xiongzhu 3 tahun lalu
induk
melakukan
35f5981290
3 mengubah file dengan 107 tambahan dan 186 penghapusan
  1. 82 153
      src/components/MultiUpload.vue
  2. 20 33
      src/views/GalleryView.vue
  3. 5 0
      src/views/MainView.vue

+ 82 - 153
src/components/MultiUpload.vue

@@ -2,12 +2,12 @@
     <section>
         <el-upload
             list-type="picture-card"
+            accept="image/*"
             :action="uploadUrl"
-            :headers="headers"
             :on-preview="handlePictureCardPreview"
-            :on-remove="handleRemove"
             :on-success="handleSuccess"
-            :file-list="fileList"
+            :on-remove="handleRemove"
+            v-model:file-list="fileList"
             @before-upload="beforeUpload"
             multiple
         >
@@ -20,164 +20,93 @@
                 </div>
             </template>
         </el-upload>
-        <el-dialog v-model="dialogVisible">
-            <img width="100%" :src="dialogImageUrl" alt />
-        </el-dialog>
-        <el-image
-            preview-teleported
-            style="width: 0; height: 0; position: absolute"
-            ref="preview"
-            :src="previewUrl"
-            :preview-src-list="previewList"
-        >
-        </el-image>
+        <ElImageViewer v-if="showPreview" :url-list="[previewUrl]" teleported @close="showPreview = false" />
     </section>
 </template>
-<script>
+<script setup>
 import resolveUrl from 'resolve-url'
-export default {
-    created() {
-        this.uploadUrl = resolveUrl(this.$http.baseURL, 'upload/file')
-        this.updateFileList(this.modelValue)
-    },
-    props: {
-        modelValue: Array,
-        usePrefix: {
-            type: Boolean,
-            default: true
-        },
-        url: {
-            type: String
-        },
-        maxWidth: {
-            type: Number,
-            default: -1
-        },
-        maxHeight: {
-            type: Number,
-            default: -1
-        },
-        maxSize: {
-            type: Number,
-            default: 1024 * 1024
-        }
+import { ref, watch } from 'vue'
+import { ElMessage } from 'element-plus'
+import { Plus } from '@vicons/tabler'
+import { useImageSize } from '@/utils/imageSize'
+
+const props = defineProps({
+    modelValue: Array,
+    maxWidth: {
+        type: Number,
+        default: -1
     },
-    data() {
-        return {
-            dialogImageUrl: '',
-            dialogVisible: false,
-            fileList: [],
-            uploadUrl: '',
-            realFileList: [],
-            previewUrl: '',
-            previewList: []
-        }
+    maxHeight: {
+        type: Number,
+        default: -1
     },
-    computed: {
-        headers() {
-            return {
-                Authorization: 'Bearer ' + localStorage.getItem('token')
-            }
-        }
-    },
-    methods: {
-        handleRemove(file, fileList) {
-            this.realFileList = fileList
-            this.$emit(
-                'update:modelValue',
-                fileList.map((i) => i.value)
-            )
-        },
-        handlePictureCardPreview(file) {
-            this.previewUrl = file.value
-            this.previewList = this.fileList.map((i) => i.value)
-            this.$refs.preview.showViewer = true
-        },
-        handleSuccess(res, file, fileList) {
-            if (res instanceof Array) {
-                file.value = res[0]
-            } else {
-                file.value = res
-            }
-            this.realFileList = fileList
-            this.$emit(
-                'update:modelValue',
-                fileList.map((i) => i.value)
-            )
-        },
-        updateFileList(list) {
-            if (!list) {
-                list = []
-            } else if (typeof list == 'string') {
-                list = list.split(',')
-            }
-            for (let i = 0; i < list.length; i++) {
-                if (!this.fileList[i]) {
-                    this.fileList[i] = {
-                        value: list[i],
-                        url: list[i]
-                    }
-                } else if (this.fileList[i].value !== list[i]) {
-                    this.fileList[i] = {
-                        value: list[i],
-                        url: list[i]
-                    }
-                }
-            }
-            this.fileList.splice(list.length)
-            // this.fileList = list.map(i => {
-            //     return {
-            //         value: i,
-            //         url: i,
-            //     };
-            // });
-        },
-        beforeUpload(file) {
-            if (!/^image/.test(file.type)) {
-                this.$message.error('只能上传图片格式!')
-                return false
-            }
-            if (this.maxSize > 0 && file.size > this.maxSize) {
-                this.$message.error('上传图片大小不能超过 ' + this.maxSize / 1024 + 'KB!')
-                return false
-            }
-            return new Promise((resolve, reject) => {
-                let image = document.createElement('img')
-                image.onload = () => {
-                    resolve({
-                        width: image.width,
-                        height: image.height
-                    })
-                }
-                image.onerror = () => {
-                    this.$message.error('图片加载失败!')
-                    reject()
-                }
-                image.src = URL.createObjectURL(file)
-            }).then((res) => {
-                if (this.maxWidth > 0 && res.width > this.maxWidth) {
-                    this.$message.error('上传图片宽度不能超过 ' + this.maxWidth + 'px!')
-                    return Promise.reject()
-                } else if (this.maxHeight > 0 && res.height > this.maxHeight) {
-                    this.$message.error('上传图片高度不能超过 ' + this.maxHeight + 'px!')
-                    return Promise.reject()
-                } else {
-                    return Promise.resolve()
-                }
-            })
+    maxSize: {
+        type: Number,
+        default: 1024 * 1024
+    }
+})
+const emit = defineEmits(['update:modelValue'])
+const uploadUrl = resolveUrl(import.meta.env.VITE_API_BASE_URL, '/api/file/upload')
+const fileList = ref([])
+const loading = ref(false)
+const showPreview = ref(false)
+const previewUrl = ref(null)
+watch(
+    () => props.modelValue,
+    (val) => {
+        if (val.join() === fileList.value.map((i) => i.realUrl).join()) {
+            return
         }
-    },
-    watch: {
-        modelValue: {
-            handler(val, oldVal) {
-                if (JSON.stringify(val) == JSON.stringify(oldVal)) {
-                    return
-                }
-                this.updateFileList(val)
-            },
-            deep: true
+        updateFileList(val)
+    }
+)
+updateFileList(props.modelValue || [])
+function updateFileList(list) {
+    fileList.value = list.map((i) => {
+        return {
+            url: i,
+            realUrl: i
         }
+    })
+}
+
+async function beforeUpload(file) {
+    if (!/^image/.test(file.type)) {
+        this.$message.error('只能上传图片格式!')
+        return false
+    }
+    if (this.maxSize > 0 && file.size > this.maxSize) {
+        this.$message.error('上传图片大小不能超过 ' + this.maxSize / 1024 + 'KB!')
+        return false
     }
+    const { width, height } = await useImageSize(URL.createObjectURL(file))
+    if (props.maxWidth > 0 && width > props.maxWidth) {
+        this.$message.error('上传图片宽度不能超过 ' + props.maxWidth + 'px!')
+        return false
+    } else if (props.maxHeight > 0 && height > props.maxHeight) {
+        this.$message.error('上传图片高度不能超过 ' + props.maxHeight + 'px!')
+        return false
+    } else {
+        loading.value = true
+        return true
+    }
+}
+function handlePictureCardPreview(file) {
+    previewUrl.value = file.url || file.realUrl
+    showPreview.value = true
+}
+function handleSuccess(res, file, fileList) {
+    file.realUrl = res.url
+    emit(
+        'update:modelValue',
+        fileList.map((i) => i.realUrl)
+    )
+}
+function handleRemove(file, fileList) {
+    emit(
+        'update:modelValue',
+        fileList.map((i) => i.realUrl)
+    )
 }
 </script>
 <style lang="less" scoped></style>

+ 20 - 33
src/views/GalleryView.vue

@@ -1,36 +1,34 @@
 <template>
-    <PagingTable url="/admin/users" :where="where" ref="table">
+    <PagingTable url="/gallery" :where="where" ref="table">
         <template #filter>
-            <EnumSelect :enum="UserRole" v-model="where.roles"></EnumSelect>
             <ElButton :icon="Plus" @click="onEdit()">添加</ElButton>
         </template>
         <ElTableColumn prop="id" label="#" width="80" />
-        <ElTableColumn prop="username" label="用户名" min-width="120" />
-        <ElTableColumn prop="name" label="昵称" min-width="120" />
-        <ElTableColumn prop="phone" label="手机" min-width="120" />
-        <ElTableColumn prop="createdAt" label="注册时间" :formatter="timeFormatter" width="150" />
-        <ElTableColumn prop="invitor" label="上级" />
+        <ElTableColumn prop="标题" label="用户名" min-width="120" />
         <ElTableColumn label="操作" align="center" width="120">
             <template #default="{ row }">
-                <ElButton @click="getToken(row)">Token</ElButton>
+                <ElButton @click="onEdit(row)">编辑</ElButton>
             </template>
         </ElTableColumn>
     </PagingTable>
     <EditDialog v-model="showEditDialog" :model="model" :rules="rules" :on-submit="submit" @success="table.refresh()">
-        <ElFormItem prop="username" label="用户名">
-            <ElInput v-model="model.username" placeholder="请输入用户名" />
+        <ElFormItem prop="title" label="标题">
+            <ElInput v-model="model.title" />
         </ElFormItem>
-        <ElFormItem prop="name" label="昵称">
-            <ElInput v-model="model.name" placeholder="请输入昵称" />
+        <ElFormItem prop="thumb" label="封面">
+            <SingleUpload v-model="model.thumb" />
         </ElFormItem>
-        <ElFormItem prop="phone" label="手机">
-            <ElInput v-model="model.phone" placeholder="请输入手机" />
+        <ElFormItem prop="charactor" label="角色">
+            <ElInput v-model="model.charactor" />
         </ElFormItem>
-        <ElFormItem prop="password" label="密码">
-            <ElInput v-model="model.password" placeholder="请输入密码" />
+        <ElFormItem prop="tag" label="标签">
+            <ElInput v-model="model.tag" />
         </ElFormItem>
-        <ElFormItem prop="roles" label="角色">
-            <EnumSelect v-model="model.roles" :enum="UserRole" multiple :multiple-limit="1"/>
+        <ElFormItem prop="artist" label="作者">
+            <ElInput v-model="model.artist" />
+        </ElFormItem>
+        <ElFormItem prop="details" label="详情">
+            <MultiUpload v-model="model.details"></MultiUpload>
         </ElFormItem>
     </EditDialog>
 </template>
@@ -46,28 +44,17 @@ import { UserRole } from '@/enums'
 import { http } from '@/plugins/http'
 import { ElMessage } from 'element-plus'
 import { useClipboard } from '@vueuse/core'
+import SingleUpload from '@/components/SingleUpload.vue'
+import MultiUpload from '@/components/MultiUpload.vue'
 
-const where = ref({ roles: 'user' })
+const where = ref({})
 const timeFormatter = useTimeFormatter()
 const table = ref(null)
 const model = ref({})
-const rules = {
-    username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-    name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
-    phone: [{ required: true, message: '请输入手机', trigger: 'blur' }],
-    password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-    roles: [{ required: true, message: '请选择角色', trigger: 'blur' }]
-}
+const rules = {}
 const { showEditDialog, onEdit } = setupEditDialog(model)
 async function submit() {
     await http.put('/gallery', model.value)
     ElMessage.success('保存成功')
 }
-function getToken(row) {
-    http.get(`/auth/admin/user/${row.id}/token`).then((res) => {
-        const { copy } = useClipboard({ legacy: true })
-        copy(res.access_token)
-        ElMessage.success('复制成功')
-    })
-}
 </script>

+ 5 - 0
src/views/MainView.vue

@@ -70,6 +70,11 @@ const menus = ref([
         title: '主页',
         icon: shallowRef(Home)
     },
+    {
+        name: 'gallery',
+        title: '虚拟数据',
+        icon: shallowRef(Photo)
+    },
     {
         name: 'user-parent',
         title: '用户管理',