From 1629003cdc450634dcb665837dda51b21694180a Mon Sep 17 00:00:00 2001 From: xingyu4j Date: Fri, 17 Oct 2025 16:23:43 +0800 Subject: [PATCH] feat: form create --- .../src/views/bpm/form/modules/detail.vue | 2 +- .../bpm/model/form/modules/form-design.vue | 2 +- .../processInstance/create/modules/form.vue | 2 +- .../bpm/processInstance/detail/index.vue | 3 +- .../detail/modules/operation-button.vue | 2 +- .../detail/modules/task-list.vue | 2 +- .../src/components/form-create/helpers.ts | 79 ++++++++++++++++--- .../src/components/form-create/index.ts | 2 +- apps/web-ele/src/utils/formCreate.ts | 64 --------------- apps/web-ele/src/utils/index.ts | 1 - 10 files changed, 74 insertions(+), 85 deletions(-) delete mode 100644 apps/web-ele/src/utils/formCreate.ts diff --git a/apps/web-antd/src/views/bpm/form/modules/detail.vue b/apps/web-antd/src/views/bpm/form/modules/detail.vue index 063572ecd..6d23ba279 100644 --- a/apps/web-antd/src/views/bpm/form/modules/detail.vue +++ b/apps/web-antd/src/views/bpm/form/modules/detail.vue @@ -6,7 +6,7 @@ import { useVbenModal } from '@vben/common-ui'; import FormCreate from '@form-create/ant-design-vue'; import { getFormDetail } from '#/api/bpm/form'; -import { setConfAndFields2 } from '#/utils'; +import { setConfAndFields2 } from '#/components/form-create'; /** 详情 */ const formConfig = ref({}); diff --git a/apps/web-antd/src/views/bpm/model/form/modules/form-design.vue b/apps/web-antd/src/views/bpm/model/form/modules/form-design.vue index bf7b467ee..90d80ff2d 100644 --- a/apps/web-antd/src/views/bpm/model/form/modules/form-design.vue +++ b/apps/web-antd/src/views/bpm/model/form/modules/form-design.vue @@ -22,7 +22,7 @@ import { } from 'ant-design-vue'; import { getFormDetail } from '#/api/bpm/form'; -import { setConfAndFields2 } from '#/utils'; +import { setConfAndFields2 } from '#/components/form-create'; const props = defineProps({ formList: { diff --git a/apps/web-antd/src/views/bpm/processInstance/create/modules/form.vue b/apps/web-antd/src/views/bpm/processInstance/create/modules/form.vue index 43342a1bd..d1dc973d9 100644 --- a/apps/web-antd/src/views/bpm/processInstance/create/modules/form.vue +++ b/apps/web-antd/src/views/bpm/processInstance/create/modules/form.vue @@ -22,8 +22,8 @@ import { createProcessInstance, getApprovalDetail as getApprovalDetailApi, } from '#/api/bpm/processInstance'; +import { decodeFields, setConfAndFields2 } from '#/components/form-create'; import { router } from '#/router'; -import { decodeFields, setConfAndFields2 } from '#/utils'; import ProcessInstanceSimpleViewer from '#/views/bpm/processInstance/detail/modules/simple-bpm-viewer.vue'; import ProcessInstanceTimeline from '#/views/bpm/processInstance/detail/modules/time-line.vue'; diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/index.vue b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue index 20c2e518c..5f2e11629 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/index.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/index.vue @@ -21,7 +21,8 @@ import { } from '#/api/bpm/processInstance'; import { getSimpleUserList } from '#/api/system/user'; import DictTag from '#/components/dict-tag/dict-tag.vue'; -import { registerComponent, setConfAndFields2 } from '#/utils'; +import { setConfAndFields2 } from '#/components/form-create'; +import { registerComponent } from '#/utils'; import { SvgBpmApproveIcon, SvgBpmCancelIcon, diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue b/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue index ea444d2b1..11205ce7e 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/modules/operation-button.vue @@ -43,7 +43,7 @@ import { } from '#/api/bpm/processInstance'; import * as TaskApi from '#/api/bpm/task'; import * as UserApi from '#/api/system/user'; -import { setConfAndFields2 } from '#/utils'; +import { setConfAndFields2 } from '#/components/form-create'; import Signature from './signature.vue'; import ProcessInstanceTimeline from './time-line.vue'; diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/modules/task-list.vue b/apps/web-antd/src/views/bpm/processInstance/detail/modules/task-list.vue index 312fa3788..7762b45d5 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/modules/task-list.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/modules/task-list.vue @@ -14,7 +14,7 @@ import { Button } from 'ant-design-vue'; import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { getTaskListByProcessInstanceId } from '#/api/bpm/task'; -import { setConfAndFields2 } from '#/utils'; +import { setConfAndFields2 } from '#/components/form-create'; defineOptions({ name: 'BpmProcessInstanceTaskList', diff --git a/apps/web-ele/src/components/form-create/helpers.ts b/apps/web-ele/src/components/form-create/helpers.ts index c647711c4..33b806bc3 100644 --- a/apps/web-ele/src/components/form-create/helpers.ts +++ b/apps/web-ele/src/components/form-create/helpers.ts @@ -2,7 +2,7 @@ import type { Ref } from 'vue'; import type { Menu } from '#/components/form-create/typing'; -import { nextTick, onMounted } from 'vue'; +import { isRef, nextTick, onMounted } from 'vue'; import { apiSelectRule } from '#/components/form-create/rules/data'; @@ -15,6 +15,59 @@ import { useUploadImagesRule, } from './rules'; +// 编码表单 Conf +export function encodeConf(designerRef: any) { + return JSON.stringify(designerRef.value.getOption()); +} + +// 编码表单 Fields +export function encodeFields(designerRef: any) { + const rule = JSON.parse(designerRef.value.getJson()); + const fields: string[] = []; + rule.forEach((item: unknown) => { + fields.push(JSON.stringify(item)); + }); + return fields; +} + +// 解码表单 Fields +export function decodeFields(fields: string[]) { + const rule: object[] = []; + fields.forEach((item) => { + rule.push(JSON.parse(item)); + }); + return rule; +} + +// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 +export function setConfAndFields( + designerRef: any, + conf: string, + fields: string | string[], +) { + designerRef.value.setOption(JSON.parse(conf)); + // 处理 fields 参数类型,确保传入 decodeFields 的是 string[] 类型 + const fieldsArray = Array.isArray(fields) ? fields : [fields]; + designerRef.value.setRule(decodeFields(fieldsArray)); +} + +// 设置表单的 Conf 和 Fields,适用 form-create 场景 +export function setConfAndFields2( + detailPreview: any, + conf: string, + fields: string[], + value?: any, +) { + if (isRef(detailPreview)) { + detailPreview = detailPreview.value; + } + detailPreview.option = JSON.parse(conf); + detailPreview.rule = decodeFields(fields); + if (value) { + detailPreview.value = value; + } +} + export function makeRequiredRule() { return { type: 'Required', @@ -23,11 +76,11 @@ export function makeRequiredRule() { }; } -export const localeProps = ( +export function localeProps( t: (msg: string) => any, prefix: string, rules: any[], -) => { +) { return rules.map((rule: { field: string; title: any }) => { if (rule.field === 'formCreate$required') { rule.title = t('props.required') || rule.title; @@ -36,7 +89,7 @@ export const localeProps = ( } return rule; }); -}; +} /** * 解析表单组件的 field, title 等字段(递归,如果组件包含子组件) @@ -45,11 +98,11 @@ export const localeProps = ( * @param fields 解析后表单组件字段 * @param parentTitle 如果是子表单,子表单的标题,默认为空 */ -export const parseFormFields = ( +export function parseFormFields( rule: Record, fields: Array> = [], parentTitle: string = '', -) => { +) { const { type, field, $required, title: tempTitle, children } = rule; if (field && tempTitle) { let title = tempTitle; @@ -79,7 +132,7 @@ export const parseFormFields = ( parseFormFields(rule, fields); }); } -}; +} /** * 表单设计器增强 hook @@ -92,7 +145,7 @@ export const parseFormFields = ( * - 部门选择器 * - 富文本 */ -export const useFormCreateDesigner = async (designer: Ref) => { +export async function useFormCreateDesigner(designer: Ref) { const editorRule = useEditorRule(); const uploadFileRule = useUploadFileRule(); const uploadImageRule = useUploadImageRule(); @@ -101,7 +154,7 @@ export const useFormCreateDesigner = async (designer: Ref) => { /** * 构建表单组件 */ - const buildFormComponents = () => { + function buildFormComponents() { // 移除自带的上传组件规则,使用 uploadFileRule、uploadImgRule、uploadImgsRule 替代 designer.value?.removeMenuItem('upload'); // 移除自带的富文本组件规则,使用 editorRule 替代 @@ -122,7 +175,7 @@ export const useFormCreateDesigner = async (designer: Ref) => { label: component.label, }); }); - }; + } const userSelectRule = useSelectRule({ name: 'UserSelect', @@ -146,7 +199,7 @@ export const useFormCreateDesigner = async (designer: Ref) => { /** * 构建系统字段菜单 */ - const buildSystemMenu = () => { + function buildSystemMenu() { // 移除自带的下拉选择器组件,使用 currencySelectRule 替代 // designer.value?.removeMenuItem('select') // designer.value?.removeMenuItem('radio') @@ -172,11 +225,11 @@ export const useFormCreateDesigner = async (designer: Ref) => { }), }; designer.value?.addMenu(menu); - }; + } onMounted(async () => { await nextTick(); buildFormComponents(); buildSystemMenu(); }); -}; +} diff --git a/apps/web-ele/src/components/form-create/index.ts b/apps/web-ele/src/components/form-create/index.ts index b311e79e6..2c512158d 100644 --- a/apps/web-ele/src/components/form-create/index.ts +++ b/apps/web-ele/src/components/form-create/index.ts @@ -1,3 +1,3 @@ export { useApiSelect } from './components/use-api-select'; -export { useFormCreateDesigner } from './helpers'; +export * from './helpers'; diff --git a/apps/web-ele/src/utils/formCreate.ts b/apps/web-ele/src/utils/formCreate.ts deleted file mode 100644 index 39a513d8e..000000000 --- a/apps/web-ele/src/utils/formCreate.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * 针对 https://github.com/xaboy/form-create-designer 封装的工具类 - */ - -import { isRef } from 'vue'; - -// 编码表单 Conf -export function encodeConf(designerRef: object) { - // @ts-ignore designerRef.value is dynamically added by form-create-designer - return JSON.stringify(designerRef.value.getOption()); -} - -// 编码表单 Fields -export function encodeFields(designerRef: object) { - // @ts-ignore designerRef.value is dynamically added by form-create-designer - const rule = JSON.parse(designerRef.value.getJson()); - const fields: string[] = []; - rule.forEach((item: unknown) => { - fields.push(JSON.stringify(item)); - }); - return fields; -} - -// 解码表单 Fields -export function decodeFields(fields: string[]) { - const rule: object[] = []; - fields.forEach((item) => { - rule.push(JSON.parse(item)); - }); - return rule; -} - -// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 -export function setConfAndFields( - designerRef: object, - conf: string, - fields: string, -) { - // @ts-ignore designerRef.value is dynamically added by form-create-designer - designerRef.value.setOption(JSON.parse(conf)); - // @ts-ignore designerRef.value is dynamically added by form-create-designer - designerRef.value.setRule(decodeFields(fields)); -} - -// 设置表单的 Conf 和 Fields,适用 form-create 场景 -export function setConfAndFields2( - detailPreview: object, - conf: string, - fields: string[], - value?: object, -) { - if (isRef(detailPreview)) { - // @ts-ignore detailPreview.value is dynamically added by form-create-designer - detailPreview = detailPreview.value; - } - // @ts-ignore detailPreview properties are dynamically added by form-create-designer - detailPreview.option = JSON.parse(conf); - // @ts-ignore detailPreview properties are dynamically added by form-create-designer - detailPreview.rule = decodeFields(fields); - if (value) { - // @ts-ignore detailPreview properties are dynamically added by form-create-designer - detailPreview.value = value; - } -} diff --git a/apps/web-ele/src/utils/index.ts b/apps/web-ele/src/utils/index.ts index b1d2a146e..3a066fd4a 100644 --- a/apps/web-ele/src/utils/index.ts +++ b/apps/web-ele/src/utils/index.ts @@ -1,3 +1,2 @@ -export * from './formCreate'; export * from './rangePickerProps'; export * from './routerHelper';