xianniu-ui 0.9.13 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,154 +6,138 @@
6
6
  :model="form"
7
7
  :label-width="labelWidth"
8
8
  @submit.native.prevent
9
- @keyup.enter.native="onSearch"
9
+ @keyup.enter.native="handleSearch"
10
10
  >
11
- <el-row :gutter="0" class="xn-search--row">
12
- <template v-for="(item, idx) in form.value">
13
- <el-col v-bind="{ ...col }" :key="idx" v-show="item.isShow || isColl">
14
- <el-form-item
15
- v-if="item.type === 'city'"
16
- :key="idx"
17
- :label="item.label"
18
- :prop="item.prop"
19
- class="xn-search--row_col"
20
- >
21
- <xn-city
22
- :key="item.prop"
23
- :data-level="(item.options && item.options.dataLevel) || 2"
24
- v-model="item.modelVal"
25
- v-bind="item.options ? { ...item.options } : {}"
26
- @on-city="handleChangeCity"
27
- />
28
- </el-form-item>
29
- <el-form-item
30
- v-if="item.type === 'cascader'"
31
- :key="idx"
32
- :label="item.label"
33
- :prop="item.prop"
34
- class="xn-search--row_col"
35
- >
36
- <el-cascader
37
- v-model="item.modelVal"
38
- style="width: 100%"
39
- :options="item.data"
40
- v-bind="item.options ? { ...item.options } : {}"
41
- @change="onChangeCascader($event, item)"
42
- ></el-cascader>
43
- </el-form-item>
44
- <el-form-item
45
- v-if="item.type === 'input'"
46
- :key="idx"
47
- :label="item.label"
48
- :prop="item.prop"
49
- class="xn-search--row_col"
50
- >
51
- <el-input
52
- :key="item.prop"
53
- style="width: 100%"
54
- v-bind="item.options ? { ...item.options } : {}"
55
- v-model.trim="item.modelVal"
56
- :clearable="item.clearable || true"
57
- :placeholder="item.placeholder || '请填写' + item.label"
58
- />
59
- </el-form-item>
60
- <el-form-item
61
- v-if="item.type === 'select'"
62
- :key="idx"
63
- :label="item.label"
64
- :prop="item.prop"
65
- class="xn-search--row_col"
66
- >
67
- <el-select
68
- :key="item.prop"
69
- style="width: 100%"
70
- v-model="item.modelVal"
71
- :placeholder="item.placeholder || '请选择' + item.label"
72
- :clearable="item.clearable || true"
73
- filterable
74
- v-bind="item.options ? { ...item.options } : {}"
75
- :remote="isRemote(item.remote)"
76
- :reserve-keyword="isRemote(item.remote)"
77
- :default-first-option="isRemote(item.remote)"
78
- :remote-method="item.remote"
11
+ <div class="xn-search-flex">
12
+ <el-row :gutter="0" class="xn-search--row">
13
+ <template v-for="(item, idx) in visibleFormItems">
14
+ <el-col v-bind="getColumnConfig()" :key="getItemKey(item, idx)">
15
+ <el-form-item
16
+ :label="item.label"
17
+ :prop="item.prop"
18
+ class="xn-search--row_col"
79
19
  >
80
- <el-option
81
- v-for="(itemData, idxData) in item.data"
82
- :key="idxData"
83
- :label="
84
- itemData[(item.options && item.options.labelKey) || 'label']
85
- "
86
- :value="
87
- itemData[(item.options && item.options.valueKey) || 'value']
88
- "
20
+ <!-- 城市选择器 -->
21
+ <xn-city
22
+ v-if="item.type === 'city'"
23
+ v-model="item.modelVal"
24
+ :data-level="getCityDataLevel(item)"
25
+ v-bind="getItemOptions(item)"
26
+ @on-city="handleCityChange"
89
27
  />
90
- </el-select>
91
- </el-form-item>
92
- <el-form-item
93
- v-if="isDate(item.type)"
94
- :key="idx"
95
- :label="item.label"
96
- :prop="item.prop"
97
- class="xn-search--row_col"
98
- >
99
- <xn-date
100
- :key="item.prop"
101
- v-model="item.modelVal"
102
- :mode="item.mode || 'range'"
103
- :type="item.type || 'daterange'"
104
- :is-shortcut="showShortcut(item)"
105
- :placeholder="item.placeholder"
106
- :startPlaceholder="
107
- item.options && item.options.startPlaceholder
108
- "
109
- :endPlaceholder="item.options && item.options.endPlaceholder"
110
- :clearable="item.clearable || true"
111
- :default-time="
112
- isRange(item.type) && item.defaultTime == undefined
113
- ? ['00:00:00', '23:59:59']
114
- : item.defaultTime
115
- "
116
- @on-change="item.change && item.change($event, item.prop)"
117
- @on-format="onChangeDateFormat"
118
- />
119
- </el-form-item>
28
+
29
+ <!-- 级联选择器 -->
30
+ <el-cascader
31
+ v-else-if="item.type === 'cascader'"
32
+ v-model="item.modelVal"
33
+ style="width: 100%"
34
+ :options="item.data"
35
+ v-bind="getItemOptions(item)"
36
+ @change="handleCascaderChange($event, item)"
37
+ />
38
+
39
+ <!-- 输入框 -->
40
+ <el-input
41
+ v-else-if="item.type === 'input'"
42
+ v-model="item.modelVal"
43
+ style="width: 100%"
44
+ :clearable="getClearable(item)"
45
+ :placeholder="getPlaceholder(item)"
46
+ v-bind="getItemOptions(item)"
47
+ />
48
+
49
+ <!-- 下拉选择器 -->
50
+ <el-select
51
+ v-else-if="item.type === 'select'"
52
+ v-model="item.modelVal"
53
+ style="width: 100%"
54
+ :clearable="getClearable(item)"
55
+ :filterable="true"
56
+ :placeholder="getPlaceholder(item)"
57
+ :remote="isRemoteSearch(item)"
58
+ :reserve-keyword="isRemoteSearch(item)"
59
+ :default-first-option="isRemoteSearch(item)"
60
+ :remote-method="item.remote"
61
+ v-bind="getItemOptions(item)"
62
+ @change="handleSelectChange(item)"
63
+ >
64
+ <el-option
65
+ v-for="(option, optionIdx) in item.data"
66
+ :key="optionIdx"
67
+ :label="getOptionLabel(option, item)"
68
+ :value="getOptionValue(option, item)"
69
+ />
70
+ </el-select>
71
+
72
+ <!-- 日期选择器 -->
73
+ <xn-date
74
+ v-else-if="isDateType(item.type)"
75
+ v-model="item.modelVal"
76
+ :mode="item.mode || 'range'"
77
+ :type="item.type || 'daterange'"
78
+ :is-shortcut="showShortcut(item)"
79
+ :placeholder="item.placeholder"
80
+ :start-placeholder="(item.options && item.options.startPlaceholder) || undefined"
81
+ :end-placeholder="(item.options && item.options.endPlaceholder) || undefined"
82
+ :clearable="getClearable(item)"
83
+ :default-time="getDefaultTime(item)"
84
+ @on-change="handleDateChange"
85
+ @on-format="handleDateFormatChange"
86
+ />
87
+ </el-form-item>
88
+ </el-col>
89
+ </template>
90
+
91
+ <!-- 展开/收起按钮 -->
92
+ <el-col
93
+ v-if="showToggleButton"
94
+ v-bind="toggleColumnConfig"
95
+ class="coll-box"
96
+ >
97
+ <el-link type="primary" :underline="false" @click="toggleCollapse">
98
+ <span>{{ isCollapsed ? "展开全部" : "收起" }}</span>
99
+ <i class="ml-5" :class="toggleIcon" />
100
+ </el-link>
120
101
  </el-col>
121
- </template>
122
- <el-col v-bind="{ ...col }">
123
- <el-form-item
124
- class="xn-search-searchbtn"
125
- :style="{
126
- 'padding-left': btnLabelWidth,
127
- }"
102
+ </el-row>
103
+
104
+ <!-- 操作按钮 -->
105
+ <div class="xn-search-searchbtn" :class="{ 'is-horizontal': isHorizontalButtons }">
106
+ <slot name="prepend" />
107
+ <el-button type="primary" icon="el-icon-search" @click="handleSearch"
108
+ >查询</el-button
128
109
  >
129
- <slot name="prepend"></slot>
130
- <el-button type="primary" icon="el-icon-search" @click="onSearch"
131
- >查询</el-button
132
- >
133
- <el-button @click="onReset">重置</el-button>
134
- <slot name="append"></slot>
135
- <el-button
136
- v-if="formData.length && formData.length > defaultColl"
137
- type="text"
138
- @click="isColl = !isColl"
139
- >
140
- <template v-if="_showColl">
141
- <span>{{ isColl ? "收起" : "展开" }}</span
142
- ><i class="ml-5" :class="toggle"></i>
143
- </template>
144
- </el-button>
145
- </el-form-item>
146
- </el-col>
147
- </el-row>
110
+ <el-button @click="handleReset">重置</el-button>
111
+ <slot name="append" />
112
+ </div>
113
+ </div>
148
114
  </el-form>
149
115
  </div>
150
116
  </template>
151
117
 
152
118
  <script>
153
- import { Form } from "element-ui";
119
+ import { Form } from "@liuzengwei/element-ui";
120
+
121
+ // 日期类型集合
122
+ const DATE_TYPES = new Set([
123
+ "date",
124
+ "week",
125
+ "month",
126
+ "year",
127
+ "dates",
128
+ "datetime",
129
+ "datetimerange",
130
+ "daterange",
131
+ "monthrange",
132
+ ]);
133
+
134
+ // 范围类型集合
135
+ const RANGE_TYPES = new Set(["datetimerange", "daterange", "monthrange"]);
136
+
154
137
  export default {
155
138
  name: "XnSearch",
156
139
  extends: Form,
140
+
157
141
  props: {
158
142
  formData: {
159
143
  type: Array,
@@ -173,210 +157,324 @@ export default {
173
157
  },
174
158
  defaultColl: {
175
159
  type: Number,
176
- default: 3,
160
+ default: 8,
161
+ validator: (value) => value > 0,
177
162
  },
178
163
  lastLabelWidth: {
179
164
  type: String,
180
165
  default: null,
181
166
  },
182
167
  },
168
+
169
+ data() {
170
+ return {
171
+ city: {},
172
+ form: {
173
+ value: [],
174
+ },
175
+ isCollapsed: true, // 默认收起状态
176
+ };
177
+ },
178
+
183
179
  computed: {
184
- _showColl() {
185
- const {
186
- form: { value },
187
- defaultColl,
188
- showColl,
189
- } = this;
190
- if (value.length <= defaultColl) {
191
- return false;
192
- }
193
- return showColl;
180
+ // 可见的表单项
181
+ visibleFormItems() {
182
+ if (!this.form.value.length) return [];
183
+
184
+ return this.form.value.filter((item, index) => {
185
+ // 如果已展开,显示所有项
186
+ if (!this.isCollapsed) return true;
187
+
188
+ // 如果收起,只显示前 defaultColl 项
189
+ return index < this.defaultColl;
190
+ });
191
+ },
192
+
193
+ // 是否显示展开/收起按钮
194
+ showToggleButton() {
195
+ return this.showColl && this.formData.length > this.defaultColl;
196
+ },
197
+
198
+ // 切换图标
199
+ toggleIcon() {
200
+ return this.isCollapsed ? "el-icon-arrow-down" : "el-icon-arrow-up";
201
+ },
202
+
203
+ // 是否横向排列按钮(查询项<=4个时横向排列)
204
+ isHorizontalButtons() {
205
+ return this.formData.length <= 4;
194
206
  },
195
- col() {
207
+
208
+ // 列配置
209
+ columnConfig() {
196
210
  const { span } = this;
197
211
  return {
198
212
  span,
199
- xs: span ? span : 24,
200
- sm: span ? span : 12,
201
- md: span ? span : 8,
202
- lg: span ? span : 6,
203
- xl: span ? span : 6,
213
+ xs: span || 24,
214
+ sm: span || 12,
215
+ md: span || 8,
216
+ lg: span || 6,
217
+ xl: span || 6,
204
218
  offset: 0,
205
219
  };
206
220
  },
207
- isRemote() {
208
- return (val) => {
209
- return val && typeof val === "function";
210
- };
211
- },
212
- toggle() {
213
- return this.isColl ? "el-icon-arrow-up" : "el-icon-arrow-down";
214
- },
215
- isDate() {
216
- return (type) => {
217
- return [
218
- "date",
219
- "week",
220
- "month",
221
- "year",
222
- "dates",
223
- "datetime",
224
- "datetimerange",
225
- "daterange",
226
- "monthrange",
227
- ].includes(type);
228
- };
229
- },
230
- isRange() {
231
- return (type) => {
232
- return ["datetimerange", "daterange", "monthrange"].includes(type);
233
- };
234
- },
235
- showShortcut() {
236
- return (item) => {
237
- let flag = "";
238
- if (this.isRange(item.type)) {
239
- flag = item.options.isShortcut;
240
- } else {
241
- flag = false;
242
- }
243
221
 
244
- return flag;
222
+ // 切换按钮列配置
223
+ toggleColumnConfig() {
224
+ const visibleCount = this.visibleFormItems.length;
225
+ const { span } = this;
226
+
227
+ // 获取每行的列数
228
+ const xlColumns = 24 / (span || 6);
229
+ const lgColumns = 24 / (span || 6);
230
+ const mdColumns = 24 / (span || 8);
231
+ const smColumns = 24 / (span || 12);
232
+ const xsColumns = 24 / (span || 24);
233
+
234
+ // 计算最后一行已占用的列数
235
+ const xlLastRowUsed = visibleCount % xlColumns || xlColumns;
236
+ const lgLastRowUsed = visibleCount % lgColumns || lgColumns;
237
+ const mdLastRowUsed = visibleCount % mdColumns || mdColumns;
238
+ const smLastRowUsed = visibleCount % smColumns || smColumns;
239
+ const xsLastRowUsed = visibleCount % xsColumns || xsColumns;
240
+
241
+ // 计算各断点下需要补齐的列数
242
+ const xlRemaining = xlColumns - xlLastRowUsed;
243
+ const lgRemaining = lgColumns - lgLastRowUsed;
244
+ const mdRemaining = mdColumns - mdLastRowUsed;
245
+ const smRemaining = smColumns - smLastRowUsed;
246
+ const xsRemaining = xsColumns - xsLastRowUsed;
247
+
248
+ // 如果最后一行已满,则按钮独占一行(24栅格),否则只占用剩余的栅格数
249
+ const xlSpan = xlRemaining === 0 ? 24 : (24 / xlColumns) * xlRemaining;
250
+ const lgSpan = lgRemaining === 0 ? 24 : (24 / lgColumns) * lgRemaining;
251
+ const mdSpan = mdRemaining === 0 ? 24 : (24 / mdColumns) * mdRemaining;
252
+ const smSpan = smRemaining === 0 ? 24 : (24 / smColumns) * smRemaining;
253
+ const xsSpan = xsRemaining === 0 ? 24 : (24 / xsColumns) * xsRemaining;
254
+
255
+ return {
256
+ span: xlSpan,
257
+ xs: xsSpan,
258
+ sm: smSpan,
259
+ md: mdSpan,
260
+ lg: lgSpan,
261
+ xl: xlSpan,
262
+ offset: 0,
245
263
  };
246
264
  },
247
- btnLabelWidth() {
248
- const { lastLabelWidth, labelWidth } = this;
249
- let w = labelWidth;
250
- if (lastLabelWidth != null) {
251
- w = lastLabelWidth;
252
- } else if (this.form.value.length === 1 || !this.isColl) {
253
- w = 0;
254
- }
255
- return w;
256
- },
257
- },
258
- data() {
259
- return {
260
- city: {},
261
- form: {
262
- value: [],
263
- },
264
- formValues:{},
265
- isColl: false,
266
- };
267
- },
268
- created() {
269
- // this.init();
270
265
  },
266
+
271
267
  watch: {
272
268
  formData: {
273
- handler(n) {
274
- n && n.length && this.init();
269
+ handler(newFormData) {
270
+ if (newFormData?.length) {
271
+ this.initFormItems();
272
+ }
275
273
  },
276
274
  immediate: true,
277
275
  deep: true,
278
276
  },
279
277
  },
278
+
280
279
  methods: {
281
- init() {
282
- this.form.value = [];
283
- for (let i = 0, formData = this.formData; i < formData.length; i++) {
284
- const item = formData[i];
285
- item.isShow = i >= this.defaultColl && this.showColl ? false : true;
286
- this.form.value.push({
287
- ...item,
288
- key: item.prop,
289
- modelVal: "",
290
- });
291
- }
280
+ // 初始化表单项
281
+ initFormItems() {
282
+ this.form.value = this.formData.map((item, index) => ({
283
+ ...item,
284
+ // 确保每个项目都有唯一的内部标识
285
+ _internalId: item.prop || `field_${index}`,
286
+ modelVal: item.defaultValue || "",
287
+ isShow: index < this.defaultColl || !this.showColl,
288
+ }));
292
289
  },
293
- onSearch() {
294
- const formValue = {};
295
- if (this.form.value) {
296
- for (let i = 0, formData = this.form.value; i < formData.length; i++) {
297
- const item = formData[i];
298
- const index = i;
299
- const key = item.prop;
300
- const value = this.form.value[index].modelVal;
301
- if (this.isRange(item.type) || item.mode === "group") {
302
- if (
303
- item.options &&
304
- item.options.start &&
305
- item.options &&
306
- item.options.end
307
- ) {
308
- formValue[item.options.start] = value[0] || "";
309
- formValue[item.options.end] = value[1] || "";
310
- }
311
- } else {
312
- formValue[key] = value;
313
- }
314
- }
315
- }
316
- this.formValues = formValue;
317
- this.$emit("on-search", formValue);
290
+
291
+ // 获取项目唯一标识
292
+ getItemKey(item, index) {
293
+ // 使用内部 ID 确保唯一性,即使没有 prop 也不会重复
294
+ return `${item._internalId}_${item.type}_${index}`;
295
+ },
296
+
297
+ // 获取列配置
298
+ getColumnConfig() {
299
+ return this.columnConfig;
300
+ },
301
+
302
+ // 获取项目选项
303
+ getItemOptions(item) {
304
+ return item.options || {};
305
+ },
306
+
307
+ // 获取城市数据级别
308
+ getCityDataLevel(item) {
309
+ return item.options?.dataLevel || 2;
310
+ },
311
+
312
+ // 获取清除性
313
+ getClearable(item) {
314
+ return item.clearable !== false;
315
+ },
316
+
317
+ // 获取占位符
318
+ getPlaceholder(item) {
319
+ if (item.placeholder) return item.placeholder;
320
+
321
+ const action = item.type === "select" ? "请选择" : "请填写";
322
+ return `${action}${item.label}`;
323
+ },
324
+
325
+ // 获取选项标签
326
+ getOptionLabel(option, item) {
327
+ const labelKey = item.options?.labelKey || "label";
328
+ return option[labelKey];
329
+ },
330
+
331
+ // 获取选项值
332
+ getOptionValue(option, item) {
333
+ const valueKey = item.options?.valueKey || "value";
334
+ return option[valueKey];
335
+ },
336
+
337
+ // 是否为远程搜索
338
+ isRemoteSearch(item) {
339
+ return item.remote && typeof item.remote === "function";
340
+ },
341
+
342
+ // 是否为日期类型
343
+ isDateType(type) {
344
+ return DATE_TYPES.has(type);
345
+ },
346
+
347
+ // 是否为范围类型
348
+ isRangeType(type) {
349
+ return RANGE_TYPES.has(type);
350
+ },
351
+
352
+ // 获取默认时间
353
+ getDefaultTime(item) {
354
+ if (item.defaultTime !== undefined) return item.defaultTime;
355
+ return this.isRangeType(item.type) ? ["00:00:00", "23:59:59"] : undefined;
356
+ },
357
+
358
+ // 显示快捷选项
359
+ showShortcut(item) {
360
+ return this.isRangeType(item.type) && item.options?.isShortcut;
361
+ },
362
+
363
+ // 切换展开/收起状态
364
+ toggleCollapse() {
365
+ this.isCollapsed = !this.isCollapsed;
318
366
  },
319
- getFormValue(){
320
- return this.formValues;
367
+
368
+ // 处理搜索
369
+ handleSearch() {
370
+ const formData = this.buildFormData();
371
+ this.$emit("on-search", formData);
321
372
  },
322
- onReset() {
323
- this.resetFields();
324
- this.formValues = {}
373
+
374
+ // 处理重置
375
+ handleReset() {
376
+ this.resetFormFields();
325
377
  this.$emit("on-reset");
326
378
  this.$emit("on-search", {});
327
379
  },
328
- onChangeDate(val) {
329
- console.log(val);
380
+
381
+ // 构建表单数据
382
+ buildFormData() {
383
+ const formData = {};
384
+
385
+ this.form.value.forEach((item) => {
386
+ const { prop, type, modelVal, mode } = item;
387
+
388
+ if (this.isRangeType(type) || mode === "group") {
389
+ const { start, end } = item.options || {};
390
+ if (start && end) {
391
+ formData[start] = modelVal?.[0] || "";
392
+ formData[end] = modelVal?.[1] || "";
393
+ }
394
+ } else {
395
+ formData[prop] = modelVal;
396
+ }
397
+ });
398
+
399
+ return formData;
330
400
  },
331
- onChangeDateFormat(val) {
332
- console.log(val);
401
+
402
+ // 重置表单字段
403
+ resetFormFields() {
404
+ this.form.value.forEach((item) => {
405
+ item.modelVal = item.defaultValue || "";
406
+ });
333
407
  },
334
- handleChangeCity({ cityCodeLast: cityCode, cityNameLast: cityName }) {
408
+
409
+ // 处理城市变化
410
+ handleCityChange({ cityCodeLast: cityCode, cityNameLast: cityName }) {
335
411
  this.city = { cityCode, cityName };
336
412
  },
413
+
414
+ // 处理级联变化
415
+ handleCascaderChange(value, item) {
416
+ const flatValue = [...new Set(value.flat(Infinity))];
417
+ item.modelVal = flatValue;
418
+
419
+ const changeHandler = item.options?.change;
420
+ if (typeof changeHandler === "function") {
421
+ changeHandler(flatValue, value);
422
+ }
423
+ },
424
+
425
+ // 处理选择变化
426
+ handleSelectChange(item) {
427
+ const changeHandler = item.change;
428
+ if (typeof changeHandler === "function") {
429
+ changeHandler(item.modelVal, item.data);
430
+ }
431
+ },
432
+
433
+ // 处理日期变化
434
+ handleDateChange() {
435
+ // 可根据需要扩展
436
+ },
437
+
438
+ // 处理日期格式变化
439
+ handleDateFormatChange() {
440
+ // 可根据需要扩展
441
+ },
442
+
443
+ // 设置数据
337
444
  setData(key, data) {
338
- const row =
339
- this.form.value &&
340
- this.form.value.find((item) => item.label === key || item.prop === key);
341
- this.$set(row, "data", data);
445
+ const item = this.findFormItem(key);
446
+ if (item) {
447
+ this.$set(item, "data", data);
448
+ }
342
449
  },
450
+
451
+ // 设置值
343
452
  setValue(key, value) {
344
- if (Object.prototype.toString.call(key) === "[object Object]") {
345
- const list = this.form.value;
346
- const keys = Object.keys(key);
347
- for (let i = 0; i < list.length; i++) {
348
- const item = list[i];
349
- if (keys.includes(item.prop)) {
350
- item.modelVal = key[item.prop];
453
+ // 批量设置
454
+ if (typeof key === "object" && key !== null) {
455
+ Object.entries(key).forEach(([prop, val]) => {
456
+ const item = this.findFormItem(prop);
457
+ if (item) {
458
+ item.modelVal = val;
351
459
  }
352
- }
460
+ });
353
461
  return;
354
462
  }
355
463
 
356
- const row =
357
- this.form.value && this.form.value.find((item) => item.label === key);
358
- if (row) {
359
- this.$set(row, "modelVal", value);
360
- }
361
- },
362
- onChangeCascader(val, item) {
363
- const newArr = [...new Set(val.flat(Infinity))];
364
- item.modelVal = newArr;
365
- if (
366
- item.options &&
367
- item.options.change &&
368
- typeof item.options.change === "function"
369
- ) {
370
- item.options.change(newArr, val);
464
+ // 单个设置
465
+ const item = this.findFormItem(key);
466
+ if (item) {
467
+ this.$set(item, "modelVal", value);
371
468
  }
372
469
  },
373
- resetFields() {
374
- for (let i = 0, formData = this.form.value; i < formData.length; i++) {
375
- const item = formData[i];
376
- item.modelVal = "";
377
- }
470
+
471
+ // 查找表单项
472
+ findFormItem(key) {
473
+ return this.form.value?.find(
474
+ (item) =>
475
+ item.prop === key || item.label === key || item._internalId === key
476
+ );
378
477
  },
379
478
  },
380
479
  };
381
480
  </script>
382
-