gaoluyang
2026-06-24 c0cb161bb52ce0fbdce5c66ec391d107c75e2452
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import type { Rule } from '@form-create/ant-design-vue';
 
import type { Ref } from 'vue';
 
import type { Menu } from '#/components/form-create/typing';
 
import { isRef, nextTick, onMounted } from 'vue';
 
import formCreate from '@form-create/ant-design-vue';
 
import { apiSelectRule } from '#/components/form-create/rules/data';
 
import {
  useAreaSelectRule,
  useDictSelectRule,
  useEditorRule,
  useIframeRule,
  useSelectRule,
  useUploadFileRule,
  useUploadImageRule,
  useUploadImagesRule,
} from './rules';
 
/** 编码表单 Conf */
export function encodeConf(designerRef: any) {
  // 关联案例:https://gitee.com/yudaocode/yudao-ui-admin-vue3/pulls/834/
  return formCreate.toJson(designerRef.value.getOption());
}
 
/** 解码表单 Conf */
export function decodeConf(conf: string) {
  return formCreate.parseJson(conf);
}
 
/** 编码表单 Fields */
export function encodeFields(designerRef: any) {
  const rule = designerRef.value.getRule();
  const fields: string[] = [];
  rule.forEach((item: any) => {
    fields.push(formCreate.toJson(item));
  });
  return fields;
}
 
/** 解码表单 Fields */
export function decodeFields(fields: string[]) {
  const rule: Rule[] = [];
  fields.forEach((item) => {
    rule.push(formCreate.parseJson(item));
  });
  return rule;
}
 
/** 设置表单的 Conf 和 Fields,适用 FcDesigner 场景 */
export function setConfAndFields(
  designerRef: any,
  conf: string,
  fields: string | string[],
) {
  designerRef.value.setOption(decodeConf(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 = decodeConf(conf);
  detailPreview.rule = decodeFields(fields);
  if (value) {
    detailPreview.value = value;
  }
}
 
export function makeRequiredRule() {
  return {
    type: 'Required',
    field: 'formCreate$required',
    title: '是否必填',
  };
}
 
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;
    } else if (rule.field && rule.field !== '_optionType') {
      rule.title = t(`components.${prefix}.${rule.field}`) || rule.title;
    }
    return rule;
  });
}
 
/**
 * 解析表单组件的  field, title 等字段(递归,如果组件包含子组件)
 *
 * @param rule  组件的生成规则 https://www.form-create.com/v3/guide/rule
 * @param fields 解析后表单组件字段
 * @param parentTitle  如果是子表单,子表单的标题,默认为空
 */
export function parseFormFields(
  rule: Record<string, any>,
  fields: Array<Record<string, any>> = [],
  parentTitle: string = '',
) {
  const { type, field, $required, title: tempTitle, children } = rule;
  if (field && tempTitle) {
    let title = tempTitle;
    if (parentTitle) {
      title = `${parentTitle}.${tempTitle}`;
    }
    let required = false;
    if ($required) {
      required = true;
    }
    fields.push({
      field,
      title,
      type,
      required,
    });
    // TODO 子表单 需要处理子表单字段
    // if (type === 'group' && rule.props?.rule && Array.isArray(rule.props.rule)) {
    //   // 解析子表单的字段
    //   rule.props.rule.forEach((item) => {
    //     parseFields(item, fieldsPermission, title)
    //   })
    // }
  }
  if (children && Array.isArray(children)) {
    children.forEach((rule) => {
      parseFormFields(rule, fields);
    });
  }
}
 
/**
 * 表单设计器增强 hook
 * 新增
 * - 文件上传
 * - 单图上传
 * - 多图上传
 * - 字典选择器
 * - 用户选择器
 * - 部门选择器
 * - 富文本
 */
export async function useFormCreateDesigner(designer: Ref) {
  const editorRule = useEditorRule();
  const uploadFileRule = useUploadFileRule();
  const uploadImageRule = useUploadImageRule();
  const uploadImagesRule = useUploadImagesRule();
  const iframeRule = useIframeRule();
  const areaSelectRule = useAreaSelectRule();
 
  /** 构建表单组件 */
  function buildFormComponents() {
    // 移除自带的上传组件规则,使用 uploadFileRule、uploadImgRule、uploadImgsRule 替代
    designer.value?.removeMenuItem('upload');
    // 移除自带的富文本组件规则,使用 editorRule 替代
    designer.value?.removeMenuItem('fc-editor');
    const components = [
      editorRule,
      uploadFileRule,
      uploadImageRule,
      uploadImagesRule,
      iframeRule,
      areaSelectRule,
    ];
    components.forEach((component) => {
      // 插入组件规则
      designer.value?.addComponent(component);
      // 插入拖拽按钮到 `main` 分类下
      designer.value?.appendMenuItem('main', {
        icon: component.icon,
        name: component.name,
        label: component.label,
      });
    });
  }
 
  const userSelectRule = useSelectRule({
    name: 'UserSelect',
    label: '用户选择器',
    icon: 'icon-eye',
    props: [
      {
        type: 'switch',
        field: 'defaultCurrentUser',
        title: '默认选中当前用户',
        value: false,
      },
    ],
  });
  const deptSelectRule = useSelectRule({
    name: 'DeptSelect',
    label: '部门选择器',
    icon: 'icon-tree',
    props: [
      {
        type: 'select',
        field: 'returnType',
        title: '返回值类型',
        value: 'id',
        options: [
          { label: '部门编号', value: 'id' },
          { label: '部门名称', value: 'name' },
        ],
      },
      {
        type: 'switch',
        field: 'defaultCurrentDept',
        title: '默认选中当前部门',
        value: false,
      },
    ],
  });
  const dictSelectRule = useDictSelectRule();
  const apiSelectRule0 = useSelectRule({
    name: 'ApiSelect',
    label: '接口选择器',
    icon: 'icon-json',
    props: [...apiSelectRule],
    event: ['click', 'change', 'visibleChange', 'clear', 'blur', 'focus'],
  });
 
  /** 构建系统字段菜单 */
  function buildSystemMenu() {
    // 移除自带的下拉选择器组件,使用 currencySelectRule 替代
    // designer.value?.removeMenuItem('select')
    // designer.value?.removeMenuItem('radio')
    // designer.value?.removeMenuItem('checkbox')
    const components = [
      userSelectRule,
      deptSelectRule,
      dictSelectRule,
      apiSelectRule0,
    ];
    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();
  });
}