Ben Lin
2025-03-18 f3122a551bf69f6aed1467a6acc24805e6b469eb
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
import { Ref, SetupContext, type EmitsOptions } from 'vue';
import { IVFormComponent, IFormConfig, AForm } from '../typings/v-form-component';
import { findFormItem, formItemsForEach } from '../utils';
import { cloneDeep, isFunction } from 'lodash-es';
import { IAnyObject } from '../typings/base-type';
 
interface IFormInstanceMethods extends AForm {
  submit: () => Promise<any>;
}
 
export interface IProps {
  formConfig: IFormConfig;
  formModel: IAnyObject;
}
 
type ISet = <T extends keyof IVFormComponent>(
  field: string,
  key: T,
  value: IVFormComponent[T],
) => void;
// 获取当前field绑定的表单项
type IGet = (field: string) => IVFormComponent | undefined;
// 获取field在formData中的值
type IGetValue = (field: string) => any;
// 设置field在formData中的值并且触发校验
type ISetValue = (field: string | IAnyObject, value?: any) => void;
// 隐藏field对应的表单项
type IHidden = (field: string) => void;
// 显示field对应的表单项
type IShow = (field: string) => void;
// 设置field对应的表单项绑定的props属性
type ISetProps = (field: string, key: string, value: any) => void;
// 获取formData中的值
type IGetData = () => Promise<IAnyObject>;
// 禁用表单,如果field为空,则禁用整个表单
type IDisable = (field?: string | boolean) => void;
// 设置表单配置方法
type ISetFormConfig = (key: string, value: any) => void;
interface ILinkOn {
  [key: string]: Set<IVFormComponent>;
}
 
export interface IVFormMethods extends Partial<IFormInstanceMethods> {
  set: ISet;
  get: IGet;
  getValue: IGetValue;
  setValue: ISetValue;
  hidden: IHidden;
  show: IShow;
  setProps: ISetProps;
  linkOn: ILinkOn;
  getData: IGetData;
  disable: IDisable;
}
export function useVFormMethods<E extends EmitsOptions = EmitsOptions>(
  props: IProps,
  _context: SetupContext<E>,
  formInstance: Ref<AForm | null>,
  formInstanceMethods: Partial<IFormInstanceMethods>,
): IVFormMethods {
  /**
   * 根据field获取表单项
   * @param {string} field
   * @return {IVFormComponent | undefined}
   */
  const get: IGet = (field) =>
    findFormItem(props.formConfig.schemas, (item) => item.field === field);
 
  /**
   * 根据表单field设置表单项字段值
   * @param {string} field
   * @param {keyof IVFormComponent} key
   * @param {never} value
   */
  const set: ISet = (field, key, value) => {
    const formItem = get(field);
    if (formItem) formItem[key] = value;
  };
 
  /**
   * 设置表单项的props
   * @param {string} field 需要设置的表单项field
   * @param {string} key 需要设置的key
   * @param value 需要设置的值
   */
  const setProps: ISetProps = (field, key, value) => {
    const formItem = get(field);
    if (formItem?.componentProps) {
      ['options', 'treeData'].includes(key) && setValue(field, undefined);
 
      formItem.componentProps[key] = value;
    }
  };
  /**
   * 设置字段的值,设置后触发校验
   * @param {string} field  需要设置的字段
   * @param value  需要设置的值
   */
  const setValue: ISetValue = (field, value) => {
    if (typeof field === 'string') {
      // props.formData[field] = value
      props.formModel[field] = value;
      formInstance.value?.validateField(field, value, []);
    } else {
      const keys = Object.keys(field);
      keys.forEach((key) => {
        props.formModel[key] = field[key];
        formInstance.value?.validateField(key, field[key], []);
      });
    }
  };
  /**
   * 设置表单配置方法
   * @param {string} key
   * @param value
   */
  const setFormConfig: ISetFormConfig = (key, value) => {
    props.formConfig[key] = value;
  };
  /**
   * 根据表单项field获取字段值,如果field为空,则
   * @param {string} field  需要设置的字段
   */
  const getValue: IGetValue = (field) => {
    const formData = cloneDeep(props.formModel);
    return formData[field];
  };
 
  /**
   * 获取formData中的值
   * @return {Promise<IAnyObject<any>>}
   */
  const getData: IGetData = async () => {
    return cloneDeep(props.formModel);
  };
  /**
   * 隐藏指定表单项
   * @param {string} field 需要隐藏的表单项的field
   */
  const hidden: IHidden = (field) => {
    set(field, 'hidden', true);
  };
 
  /**
   * 禁用表单
   * @param {string | undefined} field
   */
  const disable: IDisable = (field) => {
    typeof field === 'string'
      ? setProps(field, 'disabled', true)
      : setFormConfig('disabled', field !== false);
  };
 
  /**
   * 显示表单项
   * @param {string} field 需要显示的表单项的field
   */
  const show: IShow = (field) => {
    set(field, 'hidden', false);
  };
 
  /**
   * 监听表单字段联动时触发
   * @type {ILinkOn}
   */
  const linkOn: ILinkOn = {};
  const initLink = (schemas: IVFormComponent[]) => {
    // 首次遍历,查找需要关联字段的表单
    formItemsForEach(schemas, (formItem) => {
      // 如果需要关联,则进行第二层遍历,查找表单中关联的字段,存到Set中
      formItemsForEach(schemas, (item) => {
        if (!linkOn[item.field!]) linkOn[item.field!] = new Set<IVFormComponent>();
        if (formItem.link?.includes(item.field!) && isFunction(formItem.update)) {
          linkOn[item.field!].add(formItem);
        }
      });
      linkOn[formItem.field!].add(formItem);
    });
  };
  initLink(props.formConfig.schemas);
 
  return {
    linkOn,
    setValue,
    getValue,
    hidden,
    show,
    set,
    get,
    setProps,
    getData,
    disable,
    ...formInstanceMethods,
  };
}