Selaa lähdekoodia

使用组合式函数重构上传、表单组件

tongshangming 2 vuotta sitten
vanhempi
commit
194d7575f6

+ 2 - 2
.env.development

@@ -1,4 +1,4 @@
 NODE_ENV = 'development'
 
-VITE_BASE_API = /api
-VITE_BASE_PATH = http://10.0.0.198:30701
+VITE_BASE_API = /mbwb/api
+VITE_BASE_PATH = http://10.0.0.154:30701

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "fs-admin",
-  "version": "1.8.4",
+  "version": "1.9.0",
   "type": "module",
   "scripts": {
     "dev": "vite --host",

+ 2 - 3
src/components/core/ProTable.vue

@@ -3,7 +3,7 @@ defineOptions({
   inheritAttrs: false
 })
 
-import { buildFormSlots } from '@/utils/utils'
+import { useForm } from '@/hooks/useForm'
 import { useTableQuery } from '@/hooks/useTableQuery'
 import { useTable } from '@/hooks/useTable'
 import type { DialogProps, DrawerProps } from 'element-plus'
@@ -116,8 +116,7 @@ const handleFormSuccess = () => {
 }
 
 // 构造表单插槽
-const formSlots = ref<FormSlot[]>([])
-buildFormSlots(props.formConfig.formItems, formSlots.value)
+const { formSlots } = useForm(props)
 // ============== 表单部分结束 ===============
 
 defineExpose({

+ 1 - 46
src/components/core/form/BasicForm.vue

@@ -1,8 +1,7 @@
 <script setup lang="ts">
-import type { BasicForm, BasicFormItem, FormSlot } from '@/types/form'
+import type { BasicForm, BasicFormItem } from '@/types/form'
 import { containerTypes, notFormItem } from '@/utils/constants'
 import { buildContainerSlots } from '@/utils/utils'
-import config from '@/config/defaultSetting'
 
 interface Props {
   formConfig: BasicForm
@@ -10,35 +9,8 @@ interface Props {
 }
 const props = defineProps<Props>()
 
-// 递归将上传的值改成数组
-const uploadValueChange = (formItems: Array<BasicFormItem>) => {
-  formItems.forEach(item => {
-    if (['upload', 'image-upload'].includes(item.type) && !Array.isArray(props.formData[item.name])) {
-      props.formData[item.name] = props.formData[item.name]
-        .split(',')
-        .filter((item: string) => item)
-        .map((item: string) => ({ url: item }))
-    } else if (item.type === 'file-upload' && typeof props.formData[item.name] === 'string') {
-      try {
-        props.formData[item.name] = JSON.parse(props.formData[item.name] || '[]').map((item: any) => ({
-          url: item.url,
-          name: item.name
-        }))
-      } catch (error) {
-        props.formData[item.name] = []
-      }
-    }
-    // 尾递归
-    if (item.children) {
-      uploadValueChange(item.children)
-    }
-  })
-}
-
 const formData = computed(() => {
   if (props.formData.id) {
-    // 将上传的值改成数组
-    uploadValueChange(props.formConfig.formItems)
     return props.formData
   } else {
     // 构造表单值
@@ -46,23 +18,6 @@ const formData = computed(() => {
     const buildFormData = (formItems: Array<BasicFormItem>, res: any) => {
       formItems.forEach(item => {
         if (!item.notFormItem || !notFormItem.includes(item.type)) {
-          // 将上传的值改成数组
-          if (['upload', 'image-upload'].includes(item.type) && !Array.isArray(item.value)) {
-            item.value =
-              item.value
-                ?.split(',')
-                .filter((item: string) => item)
-                .map((item: string) => ({ url: item })) || []
-          } else if (item.type === 'file-upload' && typeof item.value === 'string') {
-            try {
-              item.value = JSON.parse(item.value || '[]').map((item: any) => ({
-                url: item.url,
-                name: item.name
-              }))
-            } catch (error) {
-              item.value = []
-            }
-          }
           // 避免修改当前表单项value重置其他表单项的value
           res[item.name] = res[item.name] !== undefined && item.value !== undefined ? res[item.name] : item.value
         }

+ 6 - 42
src/components/core/form/DialogForm.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { BasicForm, FormSlot } from '@/types/form'
 import type { DialogProps } from 'element-plus'
-import { buildFormSlots } from '@/utils/utils'
+import { useForm } from '@/hooks/useForm'
 
 interface Props {
   modelValue: boolean
@@ -16,54 +16,18 @@ interface Props {
 const props = defineProps<Props>()
 const emits = defineEmits(['update:modelValue', 'success'])
 
-const formInitData = ref({})
-watchEffect(() => {
-  formInitData.value = props.formData
-})
-
-const formRef = ref()
-
-// 构造表单插槽
-const formSlots = ref<FormSlot[]>(props.formSlots || [])
-if (!props.formSlots) {
-  buildFormSlots(props.formConfig.formItems, formSlots.value)
-}
-
-const dialogTitle = computed(() => {
-  if (props.formConfig.disabled) {
-    return '查看'
-  } else {
-    return props.formData.id ? '编辑' : '新增'
-  }
-})
-const dialogVisible = computed({
-  get: () => props.modelValue,
-  set: value => emits('update:modelValue', value)
-})
-
-const closeDialog = () => {
-  dialogVisible.value = false
-  formInitData.value = {}
-}
-
-const submit = async () => {
-  const res = await formRef.value.submit()
-  if (res) {
-    closeDialog()
-    emits('success')
-  }
-}
+const { formInitData, formRef, title, visible, formSlots, close, submit } = useForm(props, emits)
 </script>
 
 <template>
   <div>
     <el-dialog
       draggable
-      :title="dialogTitle"
+      :title="title"
       align-center
       v-bind="dialogConfig"
-      v-model="dialogVisible"
-      @close="closeDialog"
+      v-model="visible"
+      @close="close"
       :close-on-click-modal="false"
     >
       <pro-form
@@ -81,7 +45,7 @@ const submit = async () => {
       </pro-form>
 
       <template #footer>
-        <el-button icon="Close" @click="closeDialog">取消</el-button>
+        <el-button icon="Close" @click="close">取消</el-button>
         <el-button icon="Check" type="primary" @click="submit" v-if="!formConfig.disabled">保存</el-button>
       </template>
     </el-dialog>

+ 4 - 46
src/components/core/form/DrawerForm.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { BasicForm, FormSlot } from '@/types/form'
 import type { DrawerProps } from 'element-plus'
-import { buildFormSlots } from '@/utils/utils'
+import { useForm } from '@/hooks/useForm'
 
 interface Props {
   modelValue: boolean
@@ -16,54 +16,12 @@ interface Props {
 const props = defineProps<Props>()
 const emits = defineEmits(['update:modelValue', 'success'])
 
-const formInitData = ref({})
-watchEffect(() => {
-  formInitData.value = props.formData
-})
-
-const formRef = ref()
-
-// 构造表单插槽
-const formSlots = ref<FormSlot[]>(props.formSlots || [])
-if (!props.formSlots) {
-  buildFormSlots(props.formConfig.formItems, formSlots.value)
-}
-
-const title = computed(() => {
-  if (props.formConfig.disabled) {
-    return '查看'
-  } else {
-    return props.formData.id ? '编辑' : '新增'
-  }
-})
-const drawerVisible = computed({
-  get: () => props.modelValue,
-  set: value => emits('update:modelValue', value)
-})
-
-const closeDrawer = () => {
-  drawerVisible.value = false
-  formInitData.value = {}
-}
-
-const submit = async () => {
-  const res = await formRef.value.submit()
-  if (res) {
-    closeDrawer()
-    emits('success')
-  }
-}
+const { formInitData, formRef, title, visible, formSlots, close, submit } = useForm(props, emits)
 </script>
 
 <template>
   <div>
-    <el-drawer
-      :title="title"
-      v-bind="drawerConfig"
-      v-model="drawerVisible"
-      @close="closeDrawer"
-      :close-on-click-modal="false"
-    >
+    <el-drawer :title="title" v-bind="drawerConfig" v-model="visible" @close="close" :close-on-click-modal="false">
       <pro-form
         class="pro-form"
         ref="formRef"
@@ -79,7 +37,7 @@ const submit = async () => {
       </pro-form>
 
       <template #footer v-if="!formConfig.disabled">
-        <el-button icon="Close" @click="closeDrawer">取消</el-button>
+        <el-button icon="Close" @click="close">取消</el-button>
         <el-button icon="Check" type="primary" @click="submit">保存</el-button>
       </template>
     </el-drawer>

+ 1 - 56
src/components/core/form/FormComp.vue

@@ -2,12 +2,6 @@
 <script setup lang="ts">
 // @ts-nocheck
 import type { BasicFormItem } from '@/types/form'
-import type { UploadProps, UploadFile } from 'element-plus'
-import { ElMessage } from 'element-plus'
-import { useUserStore } from '@/stores/user'
-import { ACCESS_TOKEN } from '@/utils/constants'
-import { isAbsolutePath, ossUpload } from '@/utils/utils'
-import config from '@/config/defaultSetting'
 
 interface Props {
   modelValue: any
@@ -16,7 +10,6 @@ interface Props {
 
 const props = defineProps<Props>()
 const emits = defineEmits(['update:modelValue'])
-const baseApi = import.meta.env.VITE_BASE_API
 
 const modelValue = computed({
   get: () => props.modelValue,
@@ -40,51 +33,6 @@ if (props.item.request) {
     }
   })
 }
-
-const user = useUserStore()
-const headers = reactive({
-  [ACCESS_TOKEN]: user.token
-})
-
-let uploadApi = baseApi + config.uploadApi
-const uploadProps = props.item.props
-const oss = uploadProps?.oss ?? config.oss
-
-if (uploadProps?.action) {
-  uploadApi = isAbsolutePath(uploadProps.action) ? uploadProps.action : baseApi + uploadProps.action
-}
-
-const fileSize = Number(uploadProps?.fileSize) || 50
-const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
-  if (rawFile.size / 1024 / 1024 > fileSize) {
-    ElMessage.error(`文件大小不能超过${fileSize}MB!`)
-    return false
-  }
-  return true
-}
-// 上传成功
-const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile) => {
-  if (response.success || response.code === 200) {
-    // 附加oss路径
-    modelValue.value.forEach((item: any) => {
-      if (item.uid === uploadFile.uid) {
-        item.extra = oss ? response.url : config.uploadSuccessCb(response)
-      }
-    })
-  } else {
-    ElMessage.error(response.msg)
-  }
-}
-
-const uploadAttrs: any = oss ? { 'http-request': ossUpload } : {}
-if (!uploadProps?.onSuccess) {
-  uploadAttrs['on-success'] = handleUploadSuccess
-}
-
-// 上传接口需要的属性
-if (props.item.type === 'upload') {
-  props.item.extra = computed(() => modelValue.value.map((item: any) => item.extra))
-}
 </script>
 
 <template>
@@ -117,10 +65,7 @@ if (props.item.type === 'upload') {
   <el-upload
     v-else-if="item.type === 'upload'"
     v-model:file-list="modelValue"
-    :action="uploadApi"
-    :before-upload="beforeUpload"
-    :headers="headers"
-    v-bind="{ ...item.props, ...uploadAttrs }"
+    v-bind="item.props"
     v-on="item.events || {}"
   >
   </el-upload>

+ 2 - 6
src/components/core/form/ProForm.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { BasicForm, BasicFormItem, FormSlot } from '@/types/form'
 import { ElMessage, ElLoading } from 'element-plus'
-import { buildFormSlots } from '@/utils/utils'
+import { useForm } from '@/hooks/useForm'
 
 interface Props {
   formConfig: BasicForm
@@ -25,11 +25,7 @@ const formInitData = computed(() => {
 })
 const formRef = ref()
 
-// 构造表单插槽
-const formSlots = ref<FormSlot[]>(props.formSlots || [])
-if (!props.formSlots) {
-  buildFormSlots(props.formConfig.formItems, formSlots.value)
-}
+const { formSlots } = useForm(props)
 
 // 递归将上传的值改成逗号隔开的字符串
 const uploadValueChange = (formItems: Array<BasicFormItem>, data: any) => {

+ 10 - 3
src/components/form/ElEditor.vue

@@ -1,6 +1,7 @@
 <script setup lang="ts">
 import '@wangeditor/editor/dist/css/style.css'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
+import type { IToolbarConfig, IEditorConfig } from '@wangeditor/editor'
 import { useUserStore } from '@/stores/user'
 import { ACCESS_TOKEN } from '@/utils/constants'
 import { isAbsolutePath } from '@/utils/utils'
@@ -12,6 +13,8 @@ interface Props {
   height?: string
   uploadApi?: string
   fieldName?: string
+  toolbarConfig?: Partial<IToolbarConfig>
+  editorConfig?: Partial<IEditorConfig>
 }
 
 const props = withDefaults(defineProps<Props>(), {
@@ -32,7 +35,6 @@ const valueHtml = computed({
 })
 
 const userStore = useUserStore()
-const toolbarConfig = {}
 const editorConfig = {
   placeholder: '请输入内容...',
   MENU_CONF: {
@@ -46,7 +48,8 @@ const editorConfig = {
         insertFn(import.meta.env.VITE_BASE_PATH + file)
       }
     }
-  }
+  },
+  ...props.editorConfig
 }
 
 // 组件销毁时,也及时销毁编辑器
@@ -63,10 +66,14 @@ const handleCreated = (editor: any) => {
 const handleChange = (editor: any) => {
   emits('change', editor.getHtml())
 }
+
+defineExpose({
+  editorRef
+})
 </script>
 
 <template>
-  <div style="border: 1px solid var(--el-border-color)" class="w-full">
+  <div style="border: 1px solid var(--el-border-color); z-index: 2" class="w-full">
     <Toolbar
       style="border-bottom: 1px solid var(--el-border-color)"
       :editor="editorRef"

+ 6 - 60
src/components/form/ElFileUpload.vue

@@ -1,87 +1,33 @@
 <script lang="ts" setup>
-import { useUserStore } from '@/stores/user'
-import { ACCESS_TOKEN } from '@/utils/constants'
-import { ElMessage } from 'element-plus'
-import { isAbsolutePath, ossUpload } from '@/utils/utils'
 import config from '@/config/defaultSetting'
-import type { UploadProps, UploadFile } from 'element-plus'
+import { useUpload } from '@/hooks/useUpload'
 import type { BasicFormItem } from '@/types/form'
 
 interface Props {
   modelValue: any
   item?: BasicFormItem
   fileSize?: number | string
-  uploadApi?: string
+  action?: string
   oss?: boolean
 }
 const props = withDefaults(defineProps<Props>(), {
-  uploadApi: config.uploadApi,
+  action: config.uploadApi,
   fileSize: 100,
   oss: config.oss
 })
 const emits = defineEmits(['update:modelValue'])
 
-const modelValue = computed({
-  get: () => props.modelValue,
-  set: value => emits('update:modelValue', value)
-})
-
-const user = useUserStore()
-const baseApi = import.meta.env.VITE_BASE_API
-const headers = reactive({
-  [ACCESS_TOKEN]: user.token
-})
-
-// 在上传之前对文件进行验证
-const fileSize = Number(props.fileSize) || 100
-const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
-  if (rawFile.size / 1024 / 1024 > fileSize) {
-    ElMessage.error(`文件大小不能超过${fileSize}MB!`)
-    return false
-  }
-  return true
-}
-
-// 上传成功
-const uploadList = ref([...props.modelValue])
-const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile, uploadFiles: UploadFile[]) => {
-  if (response.success || response.code === 200) {
-    // 附加oss路径
-    uploadList.value = uploadFiles
-  } else {
-    ElMessage.error(response.msg)
-  }
-}
-
-// 删除文件
-const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
-  uploadList.value = uploadFiles
-}
-
-// 动态属性
-const attrs: any = props.oss ? { 'http-request': ossUpload } : {}
-if (props.item) {
-  // 接口需要的属性
-  props.item.extra = computed(() =>
-    uploadList.value.map((item: any) => ({
-      name: item.name,
-      url: item.response?.url || item.url
-    }))
-  )
-  if (!props.item.props?.onSuccess) {
-    attrs['on-success'] = handleUploadSuccess
-  }
-}
+const { modelValue, headers, action, uploadAttrs, beforeUpload, handleRemove } = useUpload(props, emits, 'file')
 </script>
 
 <template>
   <el-upload
     v-model:file-list="modelValue"
-    :action="isAbsolutePath(props.uploadApi) ? props.uploadApi : baseApi + props.uploadApi"
+    :action="action"
     :headers="headers"
     :before-upload="beforeUpload"
     :on-remove="handleRemove"
-    v-bind="{ ...attrs, ...$attrs }"
+    v-bind="{ ...uploadAttrs, ...$attrs }"
   >
     <template #[slot.name]="slotProps" v-for="slot in item?.slots" :key="slot.alias">
       <slot :name="slot.alias" v-bind="slotProps">

+ 8 - 50
src/components/form/ElImageUpload.vue

@@ -1,10 +1,8 @@
 <script lang="ts" setup>
-import { useUserStore } from '@/stores/user'
-import { ACCESS_TOKEN } from '@/utils/constants'
-import { ElMessage } from 'element-plus'
-import { isAbsolutePath, ossUpload } from '@/utils/utils'
+import { isAbsolutePath } from '@/utils/utils'
 import config from '@/config/defaultSetting'
-import type { UploadProps, UploadFile } from 'element-plus'
+import { useUpload } from '@/hooks/useUpload'
+import type { UploadFile } from 'element-plus'
 import type { BasicFormItem } from '@/types/form'
 
 interface Props {
@@ -13,32 +11,22 @@ interface Props {
   size?: number | string
   iconSize?: number | string
   fileSize?: number | string
-  uploadApi?: string
+  action?: string
   oss?: boolean
   limit?: number
 }
 const props = withDefaults(defineProps<Props>(), {
   size: '148px',
   iconSize: '28px',
-  uploadApi: config.uploadApi,
+  action: config.uploadApi,
   fileSize: 10,
   oss: config.oss,
   limit: 1
 })
 const emits = defineEmits(['update:modelValue'])
 
-const baseApi = import.meta.env.VITE_BASE_API
-const modelValue = computed({
-  get: () => props.modelValue,
-  set: value => emits('update:modelValue', value)
-})
-
-const user = useUserStore()
-const headers = reactive({
-  [ACCESS_TOKEN]: user.token
-})
-
 const limit = Number(props.limit) || 1
+const { modelValue, headers, baseApi, uploadList, action, uploadAttrs, beforeUpload } = useUpload(props, emits)
 
 // 生成图片地址
 const prefix = props.oss ? config.ossHost : baseApi
@@ -51,26 +39,6 @@ const genImageUrl = (url: string) => {
 }
 
 const uploadRef = ref()
-// 在上传之前对文件进行验证
-const fileSize = Number(props.fileSize) || 10
-const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
-  if (rawFile.size / 1024 / 1024 > fileSize) {
-    ElMessage.error(`图片大小不能超过${fileSize}MB!`)
-    return false
-  }
-  return true
-}
-
-// 图片上传成功
-const uploadList = ref([...props.modelValue])
-const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile, uploadFiles: UploadFile[]) => {
-  if (response.success || response.code === 200) {
-    // 附加oss路径
-    uploadList.value = uploadFiles
-  } else {
-    ElMessage.error(response.msg)
-  }
-}
 // 删除图片
 const handleRemove = (file: UploadFile) => {
   uploadRef.value.handleRemove(file)
@@ -87,16 +55,6 @@ const handlePreview = (file: UploadFile) => {
 const closeViewer = () => {
   showViewer.value = false
 }
-
-// 动态属性
-const attrs: any = props.oss ? { 'http-request': ossUpload } : {}
-if (props.item) {
-  // 接口需要的属性
-  props.item.extra = computed(() => uploadList.value.map((item: any) => item.response?.url || item.url))
-  if (!props.item.props?.onSuccess) {
-    attrs['on-success'] = handleUploadSuccess
-  }
-}
 </script>
 
 <template>
@@ -104,13 +62,13 @@ if (props.item) {
     ref="uploadRef"
     v-model:file-list="modelValue"
     :class="{ 'is-disabled': modelValue.length >= limit }"
-    :action="isAbsolutePath(props.uploadApi) ? props.uploadApi : baseApi + props.uploadApi"
+    :action="action"
     :headers="headers"
     :before-upload="beforeUpload"
     :limit="limit"
     list-type="picture-card"
     accept="image/*"
-    v-bind="{ ...attrs, ...$attrs }"
+    v-bind="{ ...uploadAttrs, ...$attrs }"
   >
     <el-icon class="avatar-uploader-icon" :style="{ fontSize: iconSize }"><Plus /></el-icon>
     <template #file="{ file }">

+ 51 - 0
src/hooks/useForm.ts

@@ -0,0 +1,51 @@
+import { buildFormSlots } from '@/utils/utils'
+import type { BasicForm, FormSlot } from '@/types/form'
+
+export const useForm = (props: any, emits?: any) => {
+  const formInitData = ref({})
+  watchEffect(() => {
+    formInitData.value = props.formData
+  })
+
+  const title = computed(() => {
+    if (props.formConfig.disabled) {
+      return '查看'
+    } else {
+      return props.formData.id ? '编辑' : '新增'
+    }
+  })
+  const visible = computed({
+    get: () => props.modelValue,
+    set: value => emits('update:modelValue', value)
+  })
+
+  const close = () => {
+    visible.value = false
+    formInitData.value = {}
+  }
+
+  const formRef = ref()
+  const submit = async () => {
+    const res = await formRef.value.submit()
+    if (res) {
+      close()
+      emits('success')
+    }
+  }
+
+  // 构造表单插槽
+  const formSlots = ref<FormSlot[]>(props.formSlots || [])
+  if (!props.formSlots) {
+    buildFormSlots(props.formConfig.formItems, formSlots.value)
+  }
+
+  return {
+    formInitData,
+    title,
+    visible,
+    close,
+    formRef,
+    submit,
+    formSlots
+  }
+}

+ 103 - 0
src/hooks/useUpload.ts

@@ -0,0 +1,103 @@
+import { useUserStore } from '@/stores/user'
+import { ACCESS_TOKEN } from '@/utils/constants'
+import { ElMessage } from 'element-plus'
+import { isAbsolutePath, ossUpload } from '@/utils/utils'
+import config from '@/config/defaultSetting'
+import type { UploadProps, UploadFile } from 'element-plus'
+
+export const useUpload = (props: any, emits: any, type?: string) => {
+  // 将上传的值改成数组
+  const modelValue = computed({
+    get: () => {
+      if (!Array.isArray(props.modelValue)) {
+        if (type === 'file') {
+          try {
+            return JSON.parse(props.modelValue || '[]').map((item: any) => ({
+              url: item.url,
+              name: item.name
+            }))
+          } catch (error) {
+            return []
+          }
+        } else {
+          return props.modelValue
+            .split(',')
+            .filter((item: string) => item)
+            .map((item: string) => ({ url: item }))
+        }
+      } else {
+        return props.modelValue
+      }
+    },
+    set: value => emits('update:modelValue', value)
+  })
+
+  const user = useUserStore()
+  const headers = reactive({
+    [ACCESS_TOKEN]: user.token
+  })
+
+  const baseApi = import.meta.env.VITE_BASE_API
+  const action = isAbsolutePath(props.action) ? props.action : baseApi + props.action
+
+  const fileSize = Number(props.fileSize) || 50
+  const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
+    if (rawFile.size / 1024 / 1024 > fileSize) {
+      ElMessage.error(`文件大小不能超过${fileSize}MB!`)
+      return false
+    }
+    return true
+  }
+
+  const uploadList = ref([...modelValue.value])
+  const handleUploadSuccess: UploadProps['onSuccess'] = (
+    response,
+    uploadFile: UploadFile,
+    uploadFiles: UploadFile[]
+  ) => {
+    if (response.success || response.code === 200) {
+      // 附加oss路径
+      uploadList.value = uploadFiles
+    } else {
+      ElMessage.error(response.msg)
+    }
+  }
+
+  // 删除文件
+  const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
+    uploadList.value = uploadFiles
+  }
+
+  const oss = props.oss ?? config.oss
+  // 动态属性
+  const uploadAttrs: any = oss ? { 'http-request': ossUpload } : {}
+  if (props.item) {
+    if (!props.item.props?.onSuccess) {
+      uploadAttrs['on-success'] = handleUploadSuccess
+    }
+    // 接口需要的属性
+    if (type === 'file') {
+      props.item.extra = computed(() =>
+        uploadList.value.map((item: any) => ({
+          name: item.name,
+          url: item.response?.url || item.url
+        }))
+      )
+    } else {
+      props.item.extra = computed(() => uploadList.value.map((item: any) => item.response?.url || item.url))
+    }
+  }
+
+  return {
+    modelValue,
+    headers,
+    baseApi,
+    action,
+    oss,
+    uploadAttrs,
+    uploadList,
+    beforeUpload,
+    handleUploadSuccess,
+    handleRemove
+  }
+}

+ 1 - 1
src/stores/user.ts

@@ -10,7 +10,7 @@ export const useUserStore = defineStore({
     flag: false,
     token:
       localStorage.getItem('token') ||
-      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiI1NjQ0MzBmMDNhYWU0NmExODE2YmU1YmI4NDExY2RmNiIsImV4cCI6MTcwMjU0MjY0MywiaWF0IjoxNzAyNDU2MjQzfQ.xgjJxHoW-f3WPEZxKPKtMtFvWZfgLnQK-8MWhh-_3Qg'
+      'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiI1NjQ0MzBmMDNhYWU0NmExODE2YmU1YmI4NDExY2RmNiIsImV4cCI6MTcwMjcxMTcyMSwiaWF0IjoxNzAyNjI1MzIxfQ.yqs-7RBbLr7G9p1JZ4VX753fHc0etGkubylBtvZL-Ek'
   }),
   actions: {
     async getUserInfo() {

+ 3 - 2
src/views/form/Basic.vue

@@ -255,7 +255,7 @@ const formConfig = reactive<BasicForm>({
     },
     {
       label: '文件',
-      value: [],
+      value: 'erp/prod/temp/1702626281947.png',
       name: 'picture',
       type: 'image-upload',
       props: {
@@ -265,7 +265,8 @@ const formConfig = reactive<BasicForm>({
     },
     {
       label: '文件',
-      value: '',
+      value:
+        '[{"name":"4.png","url":"erp/prod/temp/1702626281947.png"},{"name":"background_image3.png","url":"erp/prod/temp/1702626287319.png"}]',
       name: 'file',
       type: 'file-upload',
       slots: [

+ 1 - 37
src/views/system/User.vue

@@ -20,37 +20,7 @@ const CRUD: ICRUD = {
     return saveUser(data)
   },
   getList(data: any) {
-    return Promise.resolve({
-      total: 100,
-      rows: [
-        {
-          id: 1,
-          name: '张三',
-          loginName: 'zhangsan',
-          phone: '13888888888',
-          file: '[]',
-          roleList: [
-            {
-              id: 1,
-              name: '管理员'
-            }
-          ]
-        },
-        {
-          id: 2,
-          name: '李四',
-          loginName: 'lisi',
-          phone: '13888888888',
-          roleList: [
-            {
-              id: 2,
-              name: '普通用户'
-            }
-          ]
-        }
-      ]
-    })
-    // return getUserList(data)
+    return getUserList(data)
   },
   delete(data: any) {
     return deleteUser({ ids: data.id })
@@ -82,12 +52,6 @@ const formConfig = reactive<BasicForm>({
       rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
       search: true
     },
-    {
-      label: 'dfd',
-      value: '',
-      name: 'file',
-      type: 'file-upload'
-    },
     {
       label: '登录名',
       value: '',