Procházet zdrojové kódy

增加dialogForm组件

tongshangming před 3 roky
rodič
revize
44d375cf68

+ 5 - 1
src/components.d.ts

@@ -7,6 +7,9 @@ export {}
 
 declare module '@vue/runtime-core' {
   export interface GlobalComponents {
+    AdvancedForm: typeof import('./components/form/AdvancedForm.vue')['default']
+    BasicForm: typeof import('./components/form/BasicForm.vue')['default']
+    DialogForm: typeof import('./components/form/DialogForm.vue')['default']
     ElAside: typeof import('element-plus/es')['ElAside']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
@@ -39,6 +42,7 @@ declare module '@vue/runtime-core' {
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
     Exception: typeof import('./components/Exception.vue')['default']
+    FormItem: typeof import('./components/form/FormItem.vue')['default']
     GlobalFooter: typeof import('./components/GlobalFooter.vue')['default']
     GlobalHeader: typeof import('./components/GlobalHeader.vue')['default']
     GlobalMenu: typeof import('./components/GlobalMenu.vue')['default']
@@ -48,7 +52,7 @@ declare module '@vue/runtime-core' {
     IEpRefresh: typeof import('~icons/ep/refresh')['default']
     IEpSearch: typeof import('~icons/ep/search')['default']
     IEpUser: typeof import('~icons/ep/user')['default']
-    ProForm: typeof import('./components/ProForm.vue')['default']
+    ProForm: typeof import('./components/form/ProForm.vue')['default']
     ProTable: typeof import('./components/ProTable.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']

+ 0 - 1
src/components/GlobalMenu.vue

@@ -71,7 +71,6 @@ const handleSelect = (index: string) => {
   background-color: #fff;
   height: 100%;
   border: none;
-  box-shadow: 2px 0 8px #1d23290d;
 }
 .layout-menu .el-menu-item.is-active {
   background-color: var(--el-color-primary);

+ 0 - 146
src/components/ProForm.vue

@@ -1,146 +0,0 @@
-<script setup lang="ts">
-import type { PropType } from 'vue'
-import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
-import { ElMessage } from 'element-plus'
-
-const props = defineProps({
-  form: {
-    required: true,
-    type: Object as PropType<BasicForm | AdvancedForm>
-  },
-  formData: {
-    required: true,
-    type: Object
-  },
-  create: {
-    required: true,
-    type: Function
-  },
-  update: {
-    required: true,
-    type: Function
-  },
-  advanced: Boolean
-})
-
-const formProps: any = ref({
-  labelWidth: '100px',
-  labelPosition: 'top',
-  size: 'large',
-  ...props.form?.props
-})
-
-const placeholder = (item: BasicFormItem) => {
-  if (['select'].includes(item.type)) {
-    return '请选择' + item.label
-  } else {
-    return '请输入' + item.label
-  }
-}
-
-const formRef = ref()
-
-const submit = () => {
-  let message
-  formRef.value.validate(async (valid: boolean) => {
-    if (valid) {
-      try {
-        if (props.formData.id) {
-          await props.update(props.formData)
-          message = '新增成功'
-        } else {
-          await props.create(props.formData)
-          message = '修改成功'
-        }
-
-        ElMessage({
-          type: 'success',
-          message
-        })
-        return Promise.resolve()
-      } catch (error) {}
-    }
-  })
-}
-
-defineExpose({
-  submit
-})
-</script>
-
-<template>
-  <el-form :model="formData" ref="formRef" v-bind="formProps" class="form">
-    <template v-if="advanced">
-      <el-card v-for="item in (form.formItems as AdvancedFormItem[])" :title="item.label">
-        <el-row :gutter="20">
-          <el-col :span="sub.span || 12" v-for="sub in item.group">
-            <el-form-item :label="sub.label" :rules="sub.rules" :prop="sub.name">
-              <component
-                :is="'el-' + sub.type"
-                v-model="formData[sub.name]"
-                v-bind="sub.props"
-                :placeholder="sub.placeholder || placeholder(sub)"
-              >
-                <template v-if="sub.type === 'radio-group'">
-                  <el-radio :label="option.label" v-for="option in sub.options" v-bind="option.props">
-                    {{ option.value }}
-                  </el-radio>
-                </template>
-                <template v-if="sub.type === 'checkbox-group'">
-                  <el-checkbox :label="option.label" v-for="option in sub.options" v-bind="option.props">
-                    {{ option.value }}
-                  </el-checkbox>
-                </template>
-                <template v-else-if="sub.type === 'select'">
-                  <el-option
-                    :label="option.label"
-                    :value="option.value"
-                    v-for="option in sub.options"
-                    v-bind="option.props"
-                  ></el-option>
-                </template>
-              </component>
-            </el-form-item>
-          </el-col>
-        </el-row>
-      </el-card>
-    </template>
-    <el-row :gutter="20" v-else>
-      <el-col :span="item.span || 12" v-for="item in (form.formItems as BasicFormItem[])">
-        <el-form-item :label="item.label" :rules="item.rules" :prop="item.name">
-          <component
-            :is="'el-' + item.type"
-            v-model="formData[item.name]"
-            v-bind="item.props"
-            :placeholder="item.placeholder || placeholder(item)"
-          >
-            <template v-if="item.type === 'radio-group'">
-              <el-radio :label="option.label" v-for="option in item.options" v-bind="option.props">
-                {{ option.value }}
-              </el-radio>
-            </template>
-            <template v-if="item.type === 'checkbox-group'">
-              <el-checkbox :label="option.label" v-for="option in item.options" v-bind="option.props">
-                {{ option.value }}
-              </el-checkbox>
-            </template>
-            <template v-else-if="item.type === 'select'">
-              <el-option
-                :label="option.label"
-                :value="option.value"
-                v-for="option in item.options"
-                v-bind="option.props"
-              ></el-option>
-            </template>
-          </component>
-        </el-form-item>
-      </el-col>
-    </el-row>
-  </el-form>
-</template>
-
-<style lang="scss" scoped>
-.form .el-select {
-  width: 100%;
-}
-</style>

+ 28 - 43
src/components/ProTable.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { ElMessage, ElMessageBox, type FormProps } from 'element-plus'
 import type { PropType } from 'vue'
-import type { BasicForm, BasicFormItem } from '@/types/form'
+import type { AdvancedForm, BasicForm, BasicFormItem } from '@/types/form'
 import router from '@/router'
 import type { RouteLocationNormalized } from 'vue-router'
 
@@ -26,14 +26,23 @@ const props = defineProps({
     default: true
   },
   form: {
-    type: Object as PropType<BasicForm>,
+    type: Object as PropType<BasicForm | AdvancedForm>,
     required: true
   }
 })
 
 // ============== 查询部分开始 ===============
 const query = ref<any>({})
-const searchList = computed(() => props?.form.formItems.filter(item => item.search))
+// const searchList = computed(() =>
+//   props.form.formItems.filter((item: any) => {
+//     if (item.group) {
+//     } else {
+//       item.search
+//     }
+//   })
+// )
+const searchList = ref<any>([])
+
 const handleQuery = () => {
   curPage.value = 1
   getTableData()
@@ -41,6 +50,13 @@ const handleQuery = () => {
 const handleReset = () => {
   query.value = {}
 }
+const placeholder = (item: BasicFormItem) => {
+  if (['select'].includes(item.type)) {
+    return '请选择' + item.label
+  } else {
+    return '请输入' + item.label
+  }
+}
 // ============== 查询部分结束 ===============
 
 // ============== 表格部分开始 ===============
@@ -78,7 +94,7 @@ const handleCreate = () => {
   if (formRoute) {
     router.push(formRoute)
   } else {
-    dialogTitle.value = '新增'
+    formData.value = {}
     dialogVisible.value = true
   }
 }
@@ -86,8 +102,6 @@ const handleUpdate = (row: any) => {
   if (formRoute) {
     router.push(formRoute)
   } else {
-    dialogTitle.value = '编辑'
-    dialogVisible.value = true
     if (props.crud?.getRecord) {
       props.crud.getRecord({ id: row.id }).then((res: any) => {
         formData.value = res.data
@@ -95,6 +109,7 @@ const handleUpdate = (row: any) => {
     } else {
       formData.value = row
     }
+    dialogVisible.value = true
   }
 }
 const handleDelete = (id: string | number) => {
@@ -115,31 +130,8 @@ const handlePatchDelete = () => {}
 
 // ============== 表单部分开始 ===============
 const formData = ref<any>({})
-const formRef = ref()
-const dialogTitle = ref('新增')
 const dialogVisible = ref(false)
 
-props.form?.formItems.forEach(item => {
-  formData.value[item.name] = item.value
-})
-
-const placeholder = (item: BasicFormItem) => {
-  if (['select'].includes(item.type)) {
-    return '请选择' + item.label
-  } else {
-    return '请输入' + item.label
-  }
-}
-
-const closeDialog = () => {
-  dialogVisible.value = false
-  formData.value = {}
-}
-
-const submit = () => {
-  formRef.value.submit().then(() => closeDialog())
-}
-
 // ============== 表单部分结束 ===============
 </script>
 
@@ -198,21 +190,14 @@ const submit = () => {
       </div>
     </el-card>
 
-    <el-dialog
-      draggable
-      :title="dialogTitle"
+    <dialog-form
       v-model="dialogVisible"
-      width="1200px"
-      @close="closeDialog"
-      :close-on-click-modal="false"
-    >
-      <pro-form :form="form" :formData="formData" ref="formRef" :create="crud.create" :update="crud?.update"></pro-form>
-
-      <template #footer>
-        <el-button @click="dialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="submit">保存</el-button>
-      </template>
-    </el-dialog>
+      :form="form"
+      :formData="formData"
+      :create="crud.create"
+      :update="crud.update"
+      v-if="dialogVisible"
+    />
   </div>
 </template>
 

+ 34 - 0
src/components/form/AdvancedForm.vue

@@ -0,0 +1,34 @@
+<script setup lang="ts">
+import type { PropType } from 'vue'
+import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
+
+const props = defineProps({
+  form: {
+    required: true,
+    type: Object as PropType<AdvancedForm>
+  },
+  formData: {
+    required: true,
+    type: Object
+  }
+})
+
+!props.formData.id &&
+  props.form?.formItems.forEach(item => {
+    item.group.forEach(element => {
+      props.formData[element.name] = element.value
+    })
+  })
+</script>
+
+<template>
+  <el-card v-for="item in form.formItems" :title="item.label">
+    <el-row :gutter="20">
+      <el-col :span="sub.span || form.span || 12" v-for="sub in item.group">
+        <form-item :item="sub" :formData="formData"></form-item>
+      </el-col>
+    </el-row>
+  </el-card>
+</template>
+
+<style lang="scss" scoped></style>

+ 30 - 0
src/components/form/BasicForm.vue

@@ -0,0 +1,30 @@
+<script setup lang="ts">
+import type { PropType } from 'vue'
+import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
+
+const props = defineProps({
+  form: {
+    required: true,
+    type: Object as PropType<BasicForm>
+  },
+  formData: {
+    required: true,
+    type: Object
+  }
+})
+
+!props.formData.id &&
+  props.form?.formItems.forEach(item => {
+    props.formData[item.name] = item.value
+  })
+</script>
+
+<template>
+  <el-row :gutter="20">
+    <el-col :span="item.span || form.span || 12" v-for="item in form.formItems">
+      <form-item :item="item" :formData="formData"></form-item>
+    </el-col>
+  </el-row>
+</template>
+
+<style lang="scss" scoped></style>

+ 77 - 0
src/components/form/DialogForm.vue

@@ -0,0 +1,77 @@
+<script setup lang="ts">
+import type { PropType } from 'vue'
+import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
+const props = defineProps({
+  modelValue: Boolean,
+  form: {
+    required: true,
+    type: Object as PropType<BasicForm | AdvancedForm>
+  },
+  formData: {
+    required: true,
+    type: Object
+  },
+  create: {
+    required: true,
+    type: Function
+  },
+  update: {
+    required: true,
+    type: Function
+  },
+  advanced: Boolean
+})
+const emits = defineEmits(['update:modelValue'])
+
+const formInitData = ref({})
+watchEffect(() => {
+  formInitData.value = props.formData
+})
+
+const formRef = ref()
+
+const dialogTitle = computed(() => (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()
+  }
+}
+</script>
+
+<template>
+  <el-dialog
+    draggable
+    :title="dialogTitle"
+    v-model="dialogVisible"
+    width="1200px"
+    @close="closeDialog"
+    :close-on-click-modal="false"
+  >
+    <pro-form
+      ref="formRef"
+      :form="form"
+      :formData="formInitData"
+      :create="create"
+      :update="update"
+      :advanced="advanced"
+    />
+
+    <template #footer>
+      <el-button @click="closeDialog">取消</el-button>
+      <el-button type="primary" @click="submit">保存</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<style lang="scss" scoped></style>

+ 59 - 0
src/components/form/FormItem.vue

@@ -0,0 +1,59 @@
+<script setup lang="ts">
+import type { PropType } from 'vue'
+import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
+
+const props = defineProps({
+  item: {
+    required: true,
+    type: Object as PropType<BasicFormItem>
+  },
+  formData: {
+    required: true,
+    type: Object
+  }
+})
+
+const placeholder = (item: BasicFormItem) => {
+  if (['select'].includes(item.type)) {
+    return '请选择' + item.label
+  } else {
+    return '请输入' + item.label
+  }
+}
+</script>
+
+<template>
+  <el-form-item :label="item.label" :rules="item.rules" :prop="item.name">
+    <component
+      :is="'el-' + item.type"
+      v-model="formData[item.name]"
+      v-bind="item.props"
+      :placeholder="item.placeholder || placeholder(item)"
+    >
+      <template v-if="item.type === 'radio-group'">
+        <el-radio :label="option.label" v-for="option in item.options" v-bind="option.props">
+          {{ option.value }}
+        </el-radio>
+      </template>
+      <template v-if="item.type === 'checkbox-group'">
+        <el-checkbox :label="option.label" v-for="option in item.options" v-bind="option.props">
+          {{ option.value }}
+        </el-checkbox>
+      </template>
+      <template v-else-if="item.type === 'select'">
+        <el-option
+          :label="option.label"
+          :value="option.value"
+          v-for="option in item.options"
+          v-bind="option.props"
+        ></el-option>
+      </template>
+    </component>
+  </el-form-item>
+</template>
+
+<style lang="scss" scoped>
+:deep(.el-select) {
+  width: 100%;
+}
+</style>

+ 73 - 0
src/components/form/ProForm.vue

@@ -0,0 +1,73 @@
+<script setup lang="ts">
+import type { PropType } from 'vue'
+import type { BasicForm, BasicFormItem, AdvancedForm, AdvancedFormItem } from '@/types/form'
+import { ElMessage } from 'element-plus'
+
+const props = defineProps({
+  formData: {
+    required: true,
+    type: Object
+  },
+  form: {
+    required: true,
+    type: Object as PropType<BasicForm | AdvancedForm>
+  },
+  create: {
+    required: true,
+    type: Function
+  },
+  update: {
+    required: true,
+    type: Function
+  },
+  advanced: Boolean
+})
+
+const formProps: any = ref({
+  labelWidth: '100px',
+  labelPosition: 'top',
+  size: 'large',
+  ...props.form?.props
+})
+
+const formInitData = computed(() => {
+  return props.formData
+})
+const formRef = ref()
+
+const submit = async () => {
+  let message
+  return formRef.value.validate().then(async (valid: boolean) => {
+    try {
+      if (formInitData.value.id) {
+        await props.update(formInitData.value)
+        message = '编辑成功'
+      } else {
+        await props.create(formInitData.value)
+        message = '新增成功'
+      }
+
+      ElMessage({
+        type: 'success',
+        message
+      })
+      return true
+    } catch (error) {
+      return false
+    }
+  })
+}
+
+defineExpose({
+  submit
+})
+</script>
+
+<template>
+  <el-form :model="formInitData" ref="formRef" v-bind="formProps" class="form">
+    <advanced-form :form="form" :formData="formInitData" v-if="advanced" />
+    <basic-form :form="form" :formData="formInitData" v-else />
+  </el-form>
+</template>
+
+<style lang="scss" scoped></style>

+ 11 - 6
src/types/form.ts

@@ -15,18 +15,23 @@ export type BasicFormItem = {
   span?: number
   props?: object
 }
-export type BasicForm = {
-  props?: FormProps
-  route?: RouteLocationNormalized
-  formItems: BasicFormItem[]
-}
 
 export type AdvancedFormItem = {
   label: string
   group: BasicFormItem[]
 }
-export type AdvancedForm = {
+
+type Form = {
   props?: FormProps
   route?: RouteLocationNormalized
+  span?: number
+  advanced?: boolean
+}
+
+export type BasicForm = Form & {
+  formItems: BasicFormItem[]
+}
+
+export type AdvancedForm = Form & {
   formItems: AdvancedFormItem[]
 }

+ 20 - 13
src/views/system/user.vue

@@ -1,19 +1,25 @@
 <script setup lang="ts">
 import type { BasicForm } from '@/types/form'
 
-const testRequest = () => {
-  return new Promise(resolve => {
-    return resolve({
-      data: [
-        {
-          phone: '187',
-          name: 'test',
-          state: true
-        }
-      ],
-      total: 1
+const CRUD = {
+  create() {},
+  update() {},
+  getList() {
+    return new Promise(resolve => {
+      return resolve({
+        data: [
+          {
+            id: 1,
+            phone: '187',
+            name: 'test',
+            state: true,
+            gender: '1'
+          }
+        ],
+        total: 1
+      })
     })
-  })
+  }
 }
 
 const testGetRole = () => {
@@ -29,6 +35,7 @@ const testGetRole = () => {
 testGetRole()
 
 const form = reactive<BasicForm>({
+  span: 8,
   formItems: [
     {
       label: '用户名',
@@ -79,7 +86,7 @@ const form = reactive<BasicForm>({
 </script>
 
 <template>
-  <pro-table :crud="{ getList: testRequest }" :form="form">
+  <pro-table :crud="CRUD" :form="form">
     <el-table-column prop="name" label="用户名"></el-table-column>
     <el-table-column prop="phone" label="手机号"></el-table-column>
     <el-table-column prop="gender" label="性别"></el-table-column>