Browse Source

使用 tsx 封装 form-create 通用选择组件

puhui999 10 months ago
parent
commit
1f1ac1f246

+ 2 - 2
src/components/FormCreate/index.ts

@@ -1,4 +1,4 @@
 import { useFormCreateDesigner } from './src/useFormCreateDesigner'
-import CurrencySelect from './src/CurrencySelect/index.vue'
+import { useCurrencySelect } from './src/components/useCurrencySelect'
 
-export { useFormCreateDesigner, CurrencySelect }
+export { useFormCreateDesigner, useCurrencySelect }

+ 0 - 53
src/components/FormCreate/src/CurrencySelect/index.vue

@@ -1,53 +0,0 @@
-<template>
-  <el-select class="w-1/1" v-bind="attrs">
-    <el-option
-      v-for="(item, index) in options"
-      :key="index"
-      :label="item.label"
-      :value="item.value"
-    />
-  </el-select>
-</template>
-
-<script lang="ts" setup>
-import request from '@/config/axios'
-import { isEmpty } from '@/utils/is'
-
-defineOptions({ name: 'CurrencySelect' })
-
-// 接受父组件参数
-interface Props {
-  labelField?: string // 字典类型
-  valueField?: string // 字典值类型
-  restful?: string // api 接口
-}
-
-const props = withDefaults(defineProps<Props>(), {
-  labelField: 'nickname',
-  valueField: 'id',
-  restful: '/system/user/simple-list'
-})
-
-const attrs = useAttrs()
-const options = ref<any[]>([]) // 下拉数据
-const getOptions = async () => {
-  options.value = []
-  if (isEmpty(props.restful)) {
-    return
-  }
-  // TODO 只支持 GET 查询,复杂下拉构建条件请使用业务表单
-  const data = await request.get({ url: props.restful })
-  if (Array.isArray(data)) {
-    options.value = data.map((item: any) => ({
-      label: item[props.labelField],
-      value: item[props.valueField]
-    }))
-    return
-  }
-  console.log(`接口[${props.restful}] 返回结果不是一个数组`)
-}
-
-onMounted(() => {
-  getOptions()
-})
-</script>

+ 59 - 0
src/components/FormCreate/src/components/useCurrencySelect.tsx

@@ -0,0 +1,59 @@
+import request from '@/config/axios'
+import { isEmpty } from '@/utils/is'
+import { CurrencySelectProps } from '@/components/FormCreate/src/type'
+
+export const useCurrencySelect = (option: CurrencySelectProps) => {
+  return defineComponent({
+    name: option.name,
+    props: {
+      // 字典类型
+      labelField: {
+        type: String,
+        default: () => option.labelField ?? ''
+      },
+      // 字典值类型
+      valueField: {
+        type: String,
+        default: () => option.valueField ?? ''
+      },
+      // api 接口
+      restful: {
+        type: String,
+        default: () => option.restful ?? ''
+      }
+    },
+    setup(props) {
+      const attrs = useAttrs()
+      const options = ref<any[]>([]) // 下拉数据
+      const getOptions = async () => {
+        options.value = []
+        if (isEmpty(props.restful)) {
+          return
+        }
+        // TODO 只支持 GET 查询,复杂下拉构建条件请使用业务表单
+        const data = await request.get({ url: props.restful })
+        if (Array.isArray(data)) {
+          options.value = data.map((item: any) => ({
+            label: item[props.labelField],
+            value: item[props.valueField]
+          }))
+          return
+        }
+        console.log(`接口[${props.restful}] 返回结果不是一个数组`)
+      }
+
+      onMounted(async () => {
+        await getOptions()
+      })
+      return () => (
+        <>
+          <el-select className="w-1/1" {...attrs}>
+            {options.value.map((item, index) => (
+              <el-option key={index} label={item.label} value={item.value} />
+            ))}
+          </el-select>
+        </>
+      )
+    }
+  })
+}

+ 5 - 1
src/components/FormCreate/src/config/index.ts

@@ -4,6 +4,8 @@ import { useUploadImgsRule } from './useUploadImgsRule'
 import { useDictSelectRule } from './useDictSelectRule'
 import { useCurrencySelectRule } from './useCurrencySelectRule'
 import { useEditorRule } from './useEditorRule'
+import { useUserSelectRule } from './useUserSelectRule'
+import { useDeptSelectRule } from './useDeptSelectRule'
 
 export {
   useUploadFileRule,
@@ -11,5 +13,7 @@ export {
   useUploadImgsRule,
   useDictSelectRule,
   useCurrencySelectRule,
-  useEditorRule
+  useEditorRule,
+  useUserSelectRule,
+  useDeptSelectRule
 }

+ 2 - 1
src/components/FormCreate/src/config/useCurrencySelectRule.ts

@@ -1,8 +1,9 @@
 import { generateUUID } from '@/utils'
 import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
 import selectRule from '@/components/FormCreate/src/config/selectRule'
+import { DragRule } from '@/components/FormCreate/src/type'
 
-export const useCurrencySelectRule = () => {
+export const useCurrencySelectRule = (): DragRule => {
   const label = '通用选择器'
   const name = 'CurrencySelect'
   return {

+ 26 - 0
src/components/FormCreate/src/config/useDeptSelectRule.ts

@@ -0,0 +1,26 @@
+import { generateUUID } from '@/utils'
+import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
+import selectRule from '@/components/FormCreate/src/config/selectRule'
+import { DragRule } from '@/components/FormCreate/src/type'
+
+export const useDeptSelectRule = (): DragRule => {
+  const label = '部门选择器'
+  const name = 'DeptSelect'
+  return {
+    icon: 'icon-select',
+    label,
+    name,
+    rule() {
+      return {
+        type: name,
+        field: generateUUID(),
+        title: label,
+        info: '',
+        $required: false
+      }
+    },
+    props(_, { t }) {
+      return localeProps(t, name + '.props', [makeRequiredRule(), ...selectRule])
+    }
+  }
+}

+ 26 - 0
src/components/FormCreate/src/config/useUserSelectRule.ts

@@ -0,0 +1,26 @@
+import { generateUUID } from '@/utils'
+import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils'
+import selectRule from '@/components/FormCreate/src/config/selectRule'
+import { DragRule } from '@/components/FormCreate/src/type'
+
+export const useUserSelectRule = (): DragRule => {
+  const label = '用户选择器'
+  const name = 'UserSelect'
+  return {
+    icon: 'icon-select',
+    label,
+    name,
+    rule() {
+      return {
+        type: name,
+        field: generateUUID(),
+        title: label,
+        info: '',
+        $required: false
+      }
+    },
+    props(_, { t }) {
+      return localeProps(t, name + '.props', [makeRequiredRule(), ...selectRule])
+    }
+  }
+}

+ 41 - 0
src/components/FormCreate/src/type/index.ts

@@ -0,0 +1,41 @@
+import { Rule } from '@form-create/element-ui' //左侧拖拽按钮
+
+//左侧拖拽按钮
+export interface MenuItem {
+  label: string
+  name: string
+  icon: string
+}
+
+//左侧拖拽按钮分类
+export interface Menu {
+  title: string
+  name: string
+  list: MenuItem[]
+}
+
+export interface MenuList extends Array<Menu> {}
+
+//拖拽组件的规则
+export interface DragRule {
+  icon: string
+  name: string
+  label: string
+  children?: string
+  inside?: true
+  drag?: true | String
+  dragBtn?: false
+  mask?: false
+
+  rule(): Rule
+
+  props(v: any, v1: any): Rule[]
+}
+
+// 通用下拉组件 Props 类型
+export interface CurrencySelectProps {
+  name: string // 组件名称
+  labelField?: string // 字典类型
+  valueField?: string // 字典值类型
+  restful?: string // api 接口
+}

+ 38 - 2
src/components/FormCreate/src/useFormCreateDesigner.ts

@@ -1,12 +1,15 @@
 import {
   useCurrencySelectRule,
+  useDeptSelectRule,
   useDictSelectRule,
   useEditorRule,
   useUploadFileRule,
   useUploadImgRule,
-  useUploadImgsRule
+  useUploadImgsRule,
+  useUserSelectRule
 } from './config'
 import { Ref } from 'vue'
+import { Menu } from '@/components/FormCreate/src/type'
 
 /**
  * 表单设计器增强 hook
@@ -26,7 +29,10 @@ export const useFormCreateDesigner = (designer: Ref) => {
   const dictSelectRule = useDictSelectRule()
   const currencySelectRule = useCurrencySelectRule()
 
-  onMounted(() => {
+  /**
+   * 构建表单组件
+   */
+  const buildFormComponents = () => {
     // 移除自带的上传组件规则,使用 uploadFileRule、uploadImgRule、uploadImgsRule 替代
     designer.value?.removeMenuItem('upload')
     // 移除自带的富文本组件规则,使用 editorRule 替代
@@ -51,5 +57,35 @@ export const useFormCreateDesigner = (designer: Ref) => {
         label: component.label
       })
     })
+  }
+
+  const userSelectRule = useUserSelectRule()
+  const deptSelectRule = useDeptSelectRule()
+  /**
+   * 构建系统字段菜单
+   */
+  const buildSystemMenu = () => {
+    const components = [userSelectRule, deptSelectRule]
+    const menu: Menu = {
+      name: 'system',
+      title: '系统字段',
+      list: components.map((component) => {
+        // 插入组件规则
+        designer.value?.addComponent(component)
+        // 插入拖拽按钮到 `system` 分类下
+        return {
+          icon: component.icon,
+          name: component.name,
+          label: component.label
+        }
+      })
+    }
+    designer.value?.addMenu(menu)
+  }
+
+  onMounted(async () => {
+    await nextTick()
+    buildFormComponents()
+    buildSystemMenu()
   })
 }

+ 16 - 2
src/plugins/formCreate/index.ts

@@ -20,9 +20,22 @@ import install from '@form-create/element-ui/auto-import'
 //======================= 自定义组件 =======================
 import { UploadFile, UploadImg, UploadImgs } from '@/components/UploadFile'
 import { DictSelect } from '@/components/DictSelect'
-import { CurrencySelect } from '@/components/FormCreate'
+import { useCurrencySelect } from '@/components/FormCreate'
 import { Editor } from '@/components/Editor'
 
+const UserSelect = useCurrencySelect({
+  name: 'UserSelect',
+  labelField: 'nickname',
+  valueField: 'id',
+  restful: '/system/user/simple-list'
+})
+const DeptSelect = useCurrencySelect({
+  name: 'DeptSelect',
+  labelField: 'name',
+  valueField: 'id',
+  restful: '/system/dept/simple-list'
+})
+
 const components = [
   ElAside,
   ElPopconfirm,
@@ -40,7 +53,8 @@ const components = [
   UploadImgs,
   UploadFile,
   DictSelect,
-  CurrencySelect,
+  UserSelect,
+  DeptSelect,
   Editor
 ]
 

+ 2 - 4
src/views/infra/build/index.vue

@@ -8,11 +8,9 @@
           <el-button size="small" type="danger" @click="showTemplate">生成组件</el-button>
         </div>
       </el-col>
-      <!-- 表单设计器 -->
-      <el-col>
-        <FcDesigner ref="designer" height="780px" />
-      </el-col>
     </el-row>
+    <!-- 表单设计器 -->
+    <FcDesigner ref="designer" height="780px" />
   </ContentWrap>
 
   <!-- 弹窗:表单预览 -->