vue2-client 1.16.27 → 1.16.29

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.
@@ -1,1504 +1,1504 @@
1
- <template>
2
- <!-- 输入框 -->
3
- <x-form-col
4
- v-if="attr.type === 'input' && show"
5
- :occupyCol="attr.occupyCol"
6
- :labelCol="labelCol"
7
- :flex="attr.flex">
8
- <a-form-model-item
9
- v-bind="bindOther"
10
- :rules="rules"
11
- :ref="attr.model"
12
- :label="showLabel?attr.name:undefined"
13
- :prop="attr.prop ? attr.prop : attr.model">
14
- <!-- 如果配置了后置按钮插槽 -->
15
- <a-input-group
16
- v-if="((attr.inputOnAfterName && attr.inputOnAfterFunc) || (attr.inputOnAfterIcon && attr.inputOnAfterIconFunc)) && mode !== '查询'"
17
- style="display: flex; width: 100%; padding: 4px 0"
18
- compact>
19
- <a-input
20
- v-model="form[attr.model]"
21
- :read-only="readOnly"
22
- :disabled="disabled && !readOnly"
23
- :whitespace="true"
24
- @input="attr.dataChangeFunc && debouncedDataChangeFunc()"
25
- :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
26
- @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
27
- @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
28
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
29
- :ref="`${attr.model}input`"/>
30
- <a-button
31
- v-if="attr.inputOnAfterName && attr.inputOnAfterFunc && !attr.inputOnAfterName.includes('|')"
32
- style="width: auto; min-width: 4rem;max-width: 6rem"
33
- type="primary"
34
- @click="emitFunc(attr.inputOnAfterFunc,attr)">
35
- {{ attr.inputOnAfterName }}
36
- </a-button>
37
- <!-- 仅可以配置 一个按钮 以及 一个图标插槽 -->
38
- <a-button
39
- style="width: 2rem; flex-shrink: 0;"
40
- v-else-if="attr.inputOnAfterIcon"
41
- :type="attr.inputOnAfterIcon && attr.inputOnAfterName ? 'primary' :''"
42
- :icon="attr.inputOnAfterIcon || 'question'"
43
- @click="emitFunc(attr.inputOnAfterIconFunc,attr)">
44
- </a-button>
45
- <!-- 状态按钮 -->
46
- <x-status-button
47
- v-else
48
- :states="parseStates(attr.inputOnAfterName, attr.inputOnAfterFunc)"
49
- v-on="generateDynamicEvents(attr.inputOnAfterFunc, attr)"
50
- style="width: auto; min-width: 4rem; max-width: 6rem"
51
- />
52
- </a-input-group>
53
- <a-input-number
54
- v-else-if="attr.numberInput && !readOnly"
55
- v-model="form[attr.model]"
56
- :whitespace="true"
57
- @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
58
- :disabled="disabled && !readOnly"
59
- style="width:100%"
60
- @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
61
- @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
62
- :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
63
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
64
- :ref="`${attr.model}input`"/>
65
- <a-input
66
- v-else
67
- v-model="form[attr.model]"
68
- :whitespace="true"
69
- :read-only="readOnly"
70
- :disabled="disabled && !readOnly"
71
- @input="attr.dataChangeFunc && debouncedDataChangeFunc()"
72
- :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
73
- style="width:100%"
74
- @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
75
- @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
76
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
77
- :ref="`${attr.model}input`"/>
78
- </a-form-model-item>
79
- </x-form-col>
80
- <!-- 下拉框 -->
81
- <x-form-col
82
- v-else-if="attr.type === 'select' && show"
83
- :labelCol="labelCol"
84
- :flex="attr.flex">
85
- <a-form-model-item
86
- v-bind="bindOther"
87
- :rules="rules"
88
- v-if="!attr.showMode || mode === '查询' || attr.showMode === 'select' "
89
- :ref="attr.model"
90
- :label="showLabel?attr.name:undefined"
91
- :prop="attr.prop ? attr.prop : attr.model">
92
- <!-- <span slot="label" class="label-box">{{ showLabel?attr.name:undefined }}</span>-->
93
- <a-select
94
- v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
95
- v-model="form[attr.model]"
96
- :disabled="disabled"
97
- @change="handleSelectChange"
98
- :filter-option="filterOption"
99
- :getPopupContainer="getPopupContainer"
100
- dropdownClassName="custom-dropdown"
101
- :dropdownMatchSelectWidth="false"
102
- :dropdownStyle="{ position: 'absolute'}"
103
- :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
104
- show-search
105
- :allowClear="true"
106
- :getCalendarContainer="(triggerNode) => triggerNode.parentNode"
107
- >
108
- <a-select-option
109
- v-if="mode === '查询'"
110
- key="999999"
111
- value="">全部
112
- </a-select-option>
113
- <template v-if="attr.keys">
114
- <a-select-option
115
- v-for="(item,index) in attr.keys"
116
- :key="index.value"
117
- :value="item.value + ''">
118
- {{ item.label }}
119
- </a-select-option>
120
- </template>
121
- <template v-else>
122
- <template
123
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
124
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
125
- <a-select-option
126
- v-for="(item,index) in option"
127
- :key="index.value"
128
- :value="item.value + ''">
129
- <template v-if="attr.keyName.indexOf('config@') !== -1 && item.status">
130
- <!-- 徽标(badge) -->
131
- <a-badge v-if="item.status !== 'gary'" :color="item.status" :text="item.label"/>
132
- <a-badge v-else color="#D9D9D9" :text="item.label"/>
133
- </template>
134
- <template v-else>
135
- {{ item.label }}
136
- </template>
137
- </a-select-option>
138
- </template>
139
- <template
140
- v-else-if="attr.keyName.indexOf('async ') !== -1 || attr.keyName.indexOf('function ') !== -1">
141
- <a-select-option
142
- v-for="(item,index) in optionForFunc"
143
- :key="index.value"
144
- :value="item.value + ''">
145
- <template>
146
- {{ item.label }}
147
- </template>
148
- </a-select-option>
149
- </template>
150
- <template v-else>
151
- <a-select-option
152
- v-for="item in $appdata.getDictionaryList(attr.keyName)"
153
- :key="item.value"
154
- :value="item.value + ''">
155
- <!-- 徽标(badge) -->
156
- <x-badge
157
- :badge-key="attr.keyName"
158
- :replaceText="item.text"
159
- :value="item.value"
160
- :service-name="serviceName"
161
- :env="env"/>
162
- </a-select-option>
163
- </template>
164
- </template>
165
- </a-select>
166
- <a-select
167
- v-else
168
- v-model="form[attr.model]"
169
- :disabled="disabled"
170
- @change="handleSelectChange"
171
- :filter-option="filterOption"
172
- :getPopupContainer="getPopupContainer"
173
- dropdownClassName="custom-dropdown"
174
- :dropdownMatchSelectWidth="false"
175
- :dropdownStyle="{ position: 'absolute'}"
176
- :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
177
- show-search
178
- @search="fetchFunction"
179
- >
180
- <template #notFoundContent>
181
- <a-spin v-if="searching" size="small"/>
182
- </template>
183
- <a-select-option
184
- v-if="mode === '查询'"
185
- key="999999"
186
- value="">全部
187
- </a-select-option>
188
- <a-select-option
189
- v-for="(item,index) in option"
190
- :key="index"
191
- :value="item.value + ''">{{ item.label }}
192
- </a-select-option>
193
- </a-select>
194
- </a-form-model-item>
195
- <a-form-model-item
196
- v-bind="bindOther"
197
- :rules="rules"
198
- v-else-if="attr.showMode === 'radioGroup'"
199
- :ref="attr.model"
200
- :label="showLabel?attr.name:undefined"
201
- :prop="attr.prop ? attr.prop : attr.model">
202
- <a-radio-group v-model="form[attr.model]">
203
- <a-radio-button v-for="modeItem in option" :key="modeItem.value" :value="modeItem.value">
204
- {{ modeItem.label }}
205
- </a-radio-button>
206
- </a-radio-group>
207
- </a-form-model-item>
208
- <a-form-model-item
209
- v-bind="bindOther"
210
- v-else-if="attr.showMode === 'clickChange' && option.length > 0"
211
- :ref="attr.model"
212
- :label="showLabel?attr.name:undefined"
213
- :prop="attr.prop ? attr.prop : attr.model">
214
- <XClickChangeBtn></XClickChangeBtn>
215
- </a-form-model-item>
216
- </x-form-col>
217
- <!-- 多选框 -->
218
- <x-form-col
219
- v-else-if="attr.type === 'checkbox' && show"
220
- :labelCol="labelCol"
221
- :flex="attr.flex">
222
- <a-form-model-item
223
- v-bind="bindOther"
224
- :rules="rules"
225
- v-if="!attr.showMode || mode === '查询' || attr.showMode === 'select' "
226
- :ref="attr.model"
227
- :label="showLabel?attr.name:undefined"
228
- :prop="attr.prop ? attr.prop : attr.model">
229
- <a-select
230
- class="multiple_select"
231
- style="width:100%"
232
- v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
233
- v-model="form[attr.model]"
234
- :disabled="disabled"
235
- :filter-option="filterOption"
236
- :getPopupContainer="getPopupContainer"
237
- :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
238
- @change="handleCheckboxChange"
239
- mode="multiple"
240
- show-search
241
- allowClear
242
- >
243
- <template v-if="attr.keys">
244
- <a-select-option
245
- v-for="(item,index) in attr.keys"
246
- :key="index"
247
- :value="item.value + ''">
248
- {{ item.label }}
249
- </a-select-option>
250
- </template>
251
- <template v-else>
252
- <template
253
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
254
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
255
- <a-select-option
256
- v-for="(item,index) in option"
257
- :key="index"
258
- :value="item.value">{{ item.label }}
259
- </a-select-option>
260
- </template>
261
- <template v-else>
262
- <a-select-option
263
- v-for="item in $appdata.getDictionaryList(attr.keyName)"
264
- :key="item.value"
265
- :value="item.value + ''">{{ item.text }}
266
- </a-select-option>
267
- </template>
268
- </template>
269
- </a-select>
270
- <a-select
271
- v-else
272
- class="multiple_select"
273
- v-model="form[attr.model]"
274
- :disabled="disabled"
275
- :filter-option="filterOption"
276
- :getPopupContainer="getPopupContainer"
277
- :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
278
- mode="multiple"
279
- style="width:100%"
280
- @change="handleCheckboxChange"
281
- show-search
282
- allowClear
283
- @search="fetchFunction"
284
- >
285
- <template #notFoundContent>
286
- <a-spin v-if="searching" size="small"/>
287
- </template>
288
- <a-select-option
289
- v-for="(item,index) in option"
290
- :key="index"
291
- :value="item.value + ''">{{ item.label }}
292
- </a-select-option>
293
- </a-select>
294
- </a-form-model-item>
295
- <a-form-model-item
296
- v-bind="bindOther"
297
- :rules="rules"
298
- v-else
299
- :ref="attr.model"
300
- :label="showLabel?attr.name:undefined"
301
- :prop="attr.prop ? attr.prop : attr.model">
302
- <a-checkbox-group
303
- v-model="form[attr.model]"
304
- :options="option"
305
- @change="handleCheckboxChange"
306
- />
307
- </a-form-model-item>
308
- </x-form-col>
309
- <!-- 单选框 -->
310
- <x-form-col
311
- v-else-if="attr.type === 'radio' && show"
312
- :labelCol="labelCol"
313
- :flex="attr.flex">
314
- <a-form-model-item
315
- v-bind="bindOther"
316
- :rules="rules"
317
- v-if="!attr.showMode || attr.type === 'radio' "
318
- :ref="attr.model"
319
- :label="showLabel?attr.name:undefined"
320
- :prop="attr.prop ? attr.prop : attr.model">
321
- <a-radio-group
322
- v-model="form[attr.model]"
323
- @change="handleRadioChange"
324
- >
325
- <template v-if="attr.keys">
326
- <a-radio v-for="(item,index) in attr.keys" :key="index" :value="item.value">
327
- {{ item.label }}
328
- </a-radio>
329
- </template>
330
- <template v-else>
331
- <template
332
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
333
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
334
- <a-radio v-for="(item,index) in option" :key="index" :value="item.value">
335
- {{ item.label }}
336
- </a-radio>
337
- </template>
338
- <template v-else>
339
- <a-radio v-for="(item,index) in $appdata.getDictionaryList(attr.keyName)" :key="index" :value="item.value">
340
- {{ item.text }}
341
- </a-radio>
342
- </template>
343
- </template>
344
- </a-radio-group>
345
- </a-form-model-item>
346
- <a-form-model-item
347
- v-bind="bindOther"
348
- :rules="rules"
349
- v-else-if="attr.showMode === 'radioGroup'"
350
- :ref="attr.model"
351
- :label="showLabel?attr.name:undefined"
352
- :prop="attr.prop ? attr.prop : attr.model">
353
- <a-radio-group v-model="form[attr.model]">
354
- <a-radio-button v-for="modeItem in option" :key="modeItem.value" :value="modeItem.value">
355
- {{ modeItem.label }}
356
- </a-radio-button>
357
- </a-radio-group>
358
- </a-form-model-item>
359
- <a-form-model-item
360
- v-bind="bindOther"
361
- :rules="rules"
362
- v-else-if="attr.showMode === 'clickChange' && option.length > 0"
363
- :ref="attr.model"
364
- :label="showLabel?attr.name:undefined"
365
- :prop="attr.prop ? attr.prop : attr.model">
366
- <XClickChangeBtn></XClickChangeBtn>
367
- </a-form-model-item>
368
- </x-form-col>
369
- <!-- 时间 日期 框整合 -->
370
- <x-form-col
371
- v-else-if="['datePicker', 'rangePicker', 'yearPicker', 'monthPicker', 'yearRangePicker', 'monthRangePicker'].includes(attr.type) && show"
372
- :labelCol="labelCol"
373
- :flex="attr.flex">
374
- <a-form-model-item
375
- v-bind="bindOther"
376
- :rules="rules"
377
- :ref="attr.model"
378
- :label="showLabel?attr.name:undefined"
379
- :prop="attr.prop ? attr.prop : attr.model">
380
- <XFormDatePicker
381
- :attr="attr"
382
- :mode="mode"
383
- :disabled="disabled"
384
- :readOnly="readOnly"
385
- :showLabel="showLabel"
386
- @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
387
- v-model="form[attr.model]"/>
388
- </a-form-model-item>
389
- </x-form-col>
390
- <!-- 文本域 -->
391
- <x-form-col
392
- v-else-if="attr.type === 'textarea' && show"
393
- :labelCol="labelCol"
394
- :flex="attr.flex">
395
- <!-- :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"-->
396
- <a-form-model-item
397
- v-bind="bindOther"
398
- :rules="rules"
399
- :ref="attr.model"
400
- :label="showLabel?attr.name:undefined"
401
- :prop="attr.prop ? attr.prop : attr.model">
402
- <a-textarea
403
- v-model="form[attr.model]"
404
- style="width: 100%;"
405
- :disabled="disabled"
406
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
407
- :rows="4"/>
408
- </a-form-model-item>
409
- </x-form-col>
410
- <!-- 文件上传 -->
411
- <x-form-col
412
- v-else-if="(attr.type === 'file' || attr.type === 'image') && show"
413
- :labelCol="labelCol"
414
- :flex="attr.flex">
415
- <a-form-model-item
416
- v-bind="bindOther"
417
- :rules="rules"
418
- :ref="attr.model"
419
- :label="showLabel?attr.name:undefined"
420
- :prop="attr.prop ? attr.prop : attr.model">
421
- <upload
422
- :files="files"
423
- :read-only="readOnly"
424
- :images="images"
425
- :model="attr"
426
- v-bind="attr"
427
- :service-name="serviceName"
428
- @setFiles="setFiles"></upload>
429
- </a-form-model-item>
430
- </x-form-col>
431
- <!-- 省市区选择框 -->
432
- <x-form-col
433
- v-else-if="attr.type === 'citySelect' && show"
434
- :labelCol="labelCol"
435
- :flex="attr.flex">
436
- <a-form-model-item
437
- v-bind="bindOther"
438
- :rules="rules"
439
- :ref="attr.model"
440
- :label="showLabel?attr.name:undefined"
441
- :prop="attr.prop ? attr.prop : attr.model">
442
- <citySelect
443
- @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
444
- ref="citySelect"
445
- v-model="form[attr.model]"
446
- :contexts="attr.contexts"
447
- :value-type="attr.valueType"
448
- :default-value="form[attr.model]"></citySelect>
449
- </a-form-model-item>
450
- </x-form-col>
451
- <!-- 地点搜索框 -->
452
- <x-form-col
453
- v-else-if="(attr.type === 'addressSearch' || attr.type === 'coordinateSearch') && show"
454
- :labelCol="labelCol"
455
- :occupyCol="attr.occupyCol"
456
- :flex="attr.flex">
457
- <a-form-model-item
458
- v-bind="bindOther"
459
- :rules="rules"
460
- :ref="attr.model"
461
- :label="showLabel?attr.name:undefined"
462
- :prop="attr.prop ? attr.prop : attr.model">
463
- <address-search-combobox
464
- :emitFunc="emitFunc"
465
- :attr="attr"
466
- :read-only="readOnly"
467
- :searchResult="form[attr.model]"
468
- :address="{ address: form[attr.model], coords: form[`${attr.model}_lng_lat`] }"
469
- :resultKeys="{ address: attr.model, coords: `${attr.model}_lng_lat` }"
470
- ref="addressSearchCombobox"
471
- searchResultType="Object"
472
- @onSelect="addressSearchComboboxSelect"
473
- @onDivisionsChange="onDivisionsChange"
474
- ></address-search-combobox>
475
- </a-form-model-item>
476
- </x-form-col>
477
- <!-- 颜色选择器 -->
478
- <x-form-col
479
- v-else-if="attr.type === 'colorPicker' && show"
480
- :labelCol="labelCol"
481
- :flex="attr.flex">
482
- <a-form-model-item
483
- v-bind="bindOther"
484
- :rules="rules"
485
- :ref="attr.model"
486
- :label="showLabel?attr.name:undefined"
487
- :prop="attr.prop ? attr.prop : attr.model">
488
- <color-picker-combobox
489
- :value="form[attr.model]"
490
- :read-only="readOnly"
491
- @onSelect="colorPickerComboboxSelect"
492
- />
493
- </a-form-model-item>
494
- </x-form-col>
495
- <!-- 人员选择框 -->
496
- <x-form-col
497
- v-else-if="attr.type === 'personSetting' && show"
498
- :labelCol="labelCol"
499
- :flex="attr.flex">
500
- <a-form-model-item
501
- v-bind="bindOther"
502
- :rules="rules"
503
- :ref="attr.model"
504
- :label="showLabel?attr.name:undefined"
505
- :prop="attr.prop ? attr.prop : attr.model">
506
- <PersonSetting v-model="form[attr.model]"></PersonSetting>
507
- </a-form-model-item>
508
- </x-form-col>
509
- <!-- 树形选择框 -->
510
- <x-form-col
511
- v-else-if="attr.type === 'treeSelect' && show"
512
- :labelCol="labelCol"
513
- :flex="attr.flex">
514
- <x-tree-select
515
- :rules="rules"
516
- @onChange="handleTreeSelectChange"
517
- v-model="form[attr.model]"
518
- :attr="attr"
519
- @mounted="itemMounted"
520
- ref="xTreeSelect">
521
- </x-tree-select>
522
- </x-form-col>
523
- <!-- 列表选择框 -->
524
- <x-form-col
525
- v-else-if="attr.type === 'listSelect' && show"
526
- :labelCol="labelCol"
527
- :flex="attr.flex">
528
- <a-form-model-item
529
- v-bind="bindOther"
530
- :rules="rules"
531
- :ref="attr.model"
532
- :label="showLabel?attr.name:undefined"
533
- :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
534
- :prop="attr.prop ? attr.prop : attr.model">
535
- <a-popover
536
- ref="rowChoosePopover"
537
- :visible="rowChoosePopoverVisible"
538
- title="选择数据"
539
- placement="bottom"
540
- trigger="focus"
541
- :arrowPointAtCenter="true"
542
- :overlayStyle="{ width: '1000px', height: '30vh' }">
543
- <template #content>
544
- <x-report
545
- v-if="isCover"
546
- :use-oss-for-img="false"
547
- :config-name="queryParamsName"
548
- :service-name="serviceName"
549
- :show-img-in-cell="true"
550
- :display-only="true"
551
- :edit-mode="false"
552
- :show-save-button="true"
553
- :no-padding="true"
554
- :dont-format="true"
555
- @rowChoose="rowChoose"
556
- @cancel="closeRowChooseInput"
557
- >
558
- </x-report>
559
- <x-form-table
560
- v-else
561
- title="请选择数据"
562
- :queryParamsName="queryParamsName"
563
- :rowSelectMode="true"
564
- :allowSelectRowNum="1"
565
- :service-name="serviceName"
566
- :fixed-query-form="rowChooseFixedQueryValue"
567
- @rowChoose="rowChoose"
568
- @afterQuery="rowChooseSearchAfterQuery"
569
- ref="rowChooseTable">
570
- <template #button>
571
- <a-button @click="closeRowChooseInput">
572
- 关闭
573
- </a-button>
574
- </template>
575
- </x-form-table>
576
- </template>
577
- <a-input
578
- v-model="form[attr.model]"
579
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
580
- @change="searchRowChooseData"
581
- @focus="showCloseRowChooseInput"/>
582
- </a-popover>
583
- </a-form-model-item>
584
- </x-form-col>
585
- <!-- 评分框 -->
586
- <x-form-col
587
- v-else-if="attr.type === 'rate' && show"
588
- :labelCol="labelCol"
589
- :flex="attr.flex">
590
- <a-form-model-item
591
- v-bind="bindOther"
592
- :rules="rules"
593
- :ref="attr.model"
594
- :label="showLabel?attr.name:undefined"
595
- :prop="attr.prop ? attr.prop : attr.model">
596
- <x-rate
597
- v-model="form[attr.model]"
598
- :mode="mode"
599
- :disabled="disabled"
600
- :query-type="attr.queryType"
601
- :max-count="attr.maxCount"
602
- :allow-half="attr.allowHalf"
603
- :icon="attr.rateIcon"
604
- :placeholder="attr.placeholder ? attr.placeholder : '请选择'+attr.name.replace(/\s*/g, '')"
605
- @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
606
- />
607
- </a-form-model-item>
608
- </x-form-col>
609
- <!-- 区间选择器 -->
610
- <x-form-col
611
- v-else-if="attr.type === 'intervalPicker' && show"
612
- :labelCol="labelCol"
613
- :flex="attr.flex">
614
- <a-form-model-item
615
- v-bind="bindOther"
616
- :rules="rules"
617
- :ref="attr.model"
618
- :label="showLabel?attr.name:undefined"
619
- :prop="attr.prop ? attr.prop : attr.model">
620
- <x-interval-picker
621
- v-model="form[attr.model]"
622
- :mode="mode"
623
- :read-only="readOnly"
624
- :disabled="disabled && !readOnly"
625
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
626
- :start-placeholder="attr.startPlaceholder || '起始值'"
627
- :end-placeholder="attr.endPlaceholder || '结束值'"
628
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
629
- />
630
- </a-form-model-item>
631
- </x-form-col>
632
- <!-- 车牌号选择 -->
633
- <x-form-col
634
- v-else-if="attr.type === 'licensePlate' && show"
635
- :labelCol="labelCol"
636
- :flex="attr.flex">
637
- <a-form-model-item
638
- v-bind="bindOther"
639
- :rules="rules"
640
- :ref="attr.model"
641
- :label="showLabel?attr.name:undefined"
642
- :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
643
- :prop="attr.prop ? attr.prop : attr.model">
644
- <!-- 如果配置了后置按钮插槽 -->
645
- <a-input
646
- v-if="mode ==='查询'"
647
- v-model="form[attr.model]"
648
- :whitespace="true"
649
- :read-only="readOnly"
650
- :disabled="disabled && !readOnly"
651
- style="width:100%"
652
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
653
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
654
- :ref="`${attr.model}input`"/>
655
- <x-license-plate
656
- v-else
657
- v-model="form[attr.model]"
658
- @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
659
- ></x-license-plate>
660
- </a-form-model-item>
661
- </x-form-col>
662
- <!-- 录音 -->
663
- <x-form-col
664
- v-else-if="attr.type === 'recording' && show"
665
- :labelCol="labelCol"
666
- :flex="attr.flex">
667
- <recording
668
- ref="recording"
669
- @recordingData="recordingData"
670
- >
671
- </recording>
672
- </x-form-col>
673
- <!-- 表格录入 -->
674
- <x-form-col
675
- v-else-if="attr.type === 'rowEdit' && show"
676
- :labelCol="labelCol"
677
- :flex="attr.flex">
678
- <a-form-model-item
679
- v-bind="bindOther"
680
- :rules="rules"
681
- :ref="attr.model"
682
- :label="showLabel?attr.name:undefined"
683
- :prop="attr.prop ? attr.prop : attr.model">
684
- <x-form-table
685
- :key="'childTable_' + attr.model"
686
- :title="attr.name"
687
- :queryParamsName="attr.crud"
688
- :localEditMode="true"
689
- :fixed-query-form="childTableFixedQueryForm(attr)"
690
- :service-name="serviceName"
691
- @hook:mounted="(h)=>onComponentMounted(h, attr)"
692
- :ref="'childXFormTable_' + attr.model">
693
- </x-form-table>
694
- </a-form-model-item>
695
- </x-form-col>
696
- </template>
697
- <script>
698
- import { debounce } from 'ant-design-vue/lib/vc-table/src/utils'
699
- import XFormCol from '@vue2-client/base-client/components/common/XFormCol'
700
- import XBadge from '@vue2-client/base-client/components/common/XBadge'
701
- import CitySelect from '@vue2-client/base-client/components/common/CitySelect'
702
- import PersonSetting from '@vue2-client/base-client/components/common/PersonSetting'
703
- import AddressSearchCombobox from '@vue2-client/base-client/components/common/AddressSearchCombobox'
704
- import Upload from '@vue2-client/base-client/components/common/Upload'
705
- import moment from 'moment'
706
- import { getConfigByName, runLogic, getConfigByNameAsync } from '@vue2-client/services/api/common'
707
- import * as util from '@vue2-client/utils/util'
708
- import XTreeSelect from '@vue2-client/base-client/components/common/XForm/XTreeSelect'
709
- import { searchToListOption, searchToOption } from '@vue2-client/services/v3Api'
710
- import { mapState } from 'vuex'
711
- import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
712
- import XLicensePlate from '@vue2-client/base-client/components/common/XLicensePlate/XLicensePlate.vue'
713
- import XStatusButton from './XStatusButton.vue'
714
- import XClickChangeBtn from './itemComponent/XClickChangeBtn'
715
- import 'moment/locale/zh-cn'
716
- import XFormDatePicker from '@vue2-client/base-client/components/common/XDatePicker/index.vue'
717
- import XIntervalPicker from '@vue2-client/base-client/components/common/XIntervalPicker/XIntervalPicker.vue'
718
- import XRate from '@vue2-client/base-client/components/common/XRate/index.vue'
719
- import { post } from '@vue2-client/services/api/restTools'
720
- import ColorPickerCombobox from '@vue2-client/base-client/components/common/ColorPickerCombobox/ColorPickerCombobox.vue'
721
- import { createSelectValueTypeHandler } from '@vue2-client/base-client/plugins/selectValueTypeHelper'
722
-
723
- export default {
724
- name: 'XFormItem',
725
- components: {
726
- XFormDatePicker,
727
- XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
728
- Recording: () => import('@vue2-client/base-client/components/common/Recording/Recording.vue'),
729
- XReport: () => import('@vue2-client/base-client/components/common/XReportGrid/XReport.vue'),
730
- XLicensePlate,
731
- XTreeSelect,
732
- XFormCol,
733
- XBadge,
734
- CitySelect,
735
- PersonSetting,
736
- AddressSearchCombobox,
737
- Upload,
738
- XStatusButton,
739
- XClickChangeBtn,
740
- XIntervalPicker,
741
- XRate,
742
- ColorPickerCombobox
743
- },
744
- data () {
745
- // 检索去抖
746
- this.fetchFunction = debounce(this.fetchFunction, 800)
747
- // 初始化selectValueType处理器
748
- this.selectValueTypeHandler = createSelectValueTypeHandler(this)
749
- return {
750
- option: [],
751
- // 最后检索版本
752
- lastFetchId: 0,
753
- // 检索中
754
- searching: false,
755
- searchResult: '',
756
- optionForFunc: [],
757
- // 控制当前表单项是否展示
758
- show: true,
759
- // moment
760
- moment,
761
- // 行选择器浮层是否显示
762
- rowChoosePopoverVisible: false,
763
- // 行选择器CRUD固定查询值
764
- rowChooseFixedQueryValue: undefined,
765
- bindOther: {}
766
- }
767
- },
768
- props: {
769
- attr: {
770
- type: Object,
771
- default:
772
- () => {
773
- return {}
774
- }
775
- },
776
- form: {
777
- type: Object,
778
- required:
779
- true
780
- },
781
- disabled: {
782
- type: Boolean,
783
- default:
784
- () => {
785
- return false
786
- }
787
- },
788
- readOnly: {
789
- type: Boolean,
790
- default:
791
- () => {
792
- return false
793
- }
794
- },
795
- mode: {
796
- type: String,
797
- default:
798
- () => {
799
- return '查询'
800
- }
801
- },
802
- files: {
803
- type: Array,
804
- default:
805
- () => {
806
- return []
807
- }
808
- },
809
- images: {
810
- type: Array,
811
- default:
812
- () => {
813
- return []
814
- }
815
- },
816
- serviceName: {
817
- type: String,
818
- default:
819
- undefined
820
- },
821
- // 调用logic获取数据源的追加参数
822
- getDataParams: {
823
- type: Object,
824
- default:
825
- undefined
826
- },
827
- // 布局
828
- layout: {
829
- type: String,
830
- default:
831
- 'horizontal'
832
- },
833
- // 环境
834
- env: {
835
- type: String,
836
- default:
837
- () => {
838
- return 'prod'
839
- }
840
- },
841
- // 设置表单值
842
- setForm: {
843
- type: Function,
844
- default: (val) => {
845
- console.log(val)
846
- }
847
- },
848
- showLabel: {
849
- type: Boolean,
850
- default:
851
- () => {
852
- return true
853
- }
854
- },
855
- labelCol: {
856
- type: Object,
857
- default: () => {
858
- return { span: 8 }
859
- }
860
- },
861
- rules: {
862
- type: Array,
863
- default:
864
- () => {
865
- return undefined
866
- }
867
- }
868
- },
869
- provide () {
870
- return {
871
- FormItemContext: this
872
- }
873
- },
874
- created () {
875
- this.init()
876
- if (this.attr.keyName && (this.attr?.keyName?.toString().indexOf('async ') !== -1 || this.attr?.keyName?.toString()?.indexOf('function') !== -1)) {
877
- this.debouncedUpdateOptions = debounce(this.updateOptions, 200)
878
- }
879
- if (this.attr.dataChangeFunc) {
880
- this.debouncedDataChangeFunc = debounce(this.dataChangeFunc, 200)
881
- // 执行一次
882
- this.dataChangeFunc()
883
- }
884
- if (this.attr.showFormItemFunc) {
885
- this.debouncedShowFormItemFunc = debounce(this.showFormItemFunc, 100)
886
- // 执行一次
887
- this.showFormItemFunc()
888
- }
889
- if (this.attr.showQueryFormItemFunc) {
890
- this.debouncedShowQueryFormItemFunc = debounce(this.showQueryFormItemFunc, 100)
891
- // 执行一次
892
- this.showQueryFormItemFunc()
893
- }
894
- // 人员联动框增加监听
895
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
896
- this.debouncedUserLinkFunc = debounce(() => this.updateResOptions('人员'), 200)
897
- }
898
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
899
- this.debouncedDepLinkFunc = debounce(() => this.updateResOptions('部门'), 200)
900
- }
901
- // xTreeSelect 自己调用 mounted
902
- if (this.attr.type !== 'treeSelect') {
903
- this.$emit('mounted', this.attr)
904
- }
905
- },
906
- computed: {
907
- ...mapState('account', { currUser: 'user', curRoles: 'roles', curPermissions: 'permissions' }),
908
- queryParamsName () {
909
- if (this.attr.keyName.startsWith('function')) {
910
- // 调用异步函数获取内容
911
- const obj = executeStrFunctionByContext(this, this.attr.keyName, [this.form, runLogic, this.mode, getConfigByNameAsync])
912
- // 处理同步返回值
913
- return this.handleQueryParamsResult(obj)
914
- } else if (this.attr.keyName.startsWith('async ')) {
915
- console.warn('此处不支持异步操作')
916
- return ''
917
- } else {
918
- // 按现有方式处理
919
- return this.attr.keyName.split('@')[this.attr.keyName.split('@').length - 1]
920
- }
921
- },
922
- // 判断弹出时是否Cover,弹出只支持Cover以及CRUD
923
- isCover () {
924
- // 如果 queryParamsName 为空,返回空
925
- if (!this.queryParamsName) {
926
- return false
927
- }
928
- const result = this.queryParamsName.endsWith('Cover')
929
- return result
930
- },
931
- },
932
- watch: {
933
- attr: {
934
- handler () {
935
- this.init()
936
- },
937
- deep: true
938
- },
939
- form: {
940
- handler (newVal, oldVal) {
941
- // 如果是从函数获取 options
942
- if (this.attr.keyName && (this.attr.keyName.toString().indexOf('async ') !== -1 || this.attr.keyName.toString().indexOf('function') !== -1)) {
943
- this.debouncedUpdateOptions()
944
- }
945
- // 如果有自定义是否展示表单项函数
946
- if (this.attr.showFormItemFunc) {
947
- this.debouncedShowFormItemFunc()
948
- }
949
- // 如果有自定义是否展示查询表单项函数
950
- if (this.attr.showQueryFormItemFunc) {
951
- this.debouncedShowQueryFormItemFunc()
952
- }
953
- // 地址搜索框赋值
954
- if (this.attr.type === 'addressSearch' || this.attr.type === 'coordinateSearch') {
955
- this.$refs.addressSearchCombobox.addressInput = this.form[this.attr.model]
956
- }
957
- // 数据源来自人员联动时更新数据
958
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
959
- this.debouncedUserLinkFunc()
960
- }
961
- // 数据源来自人员联动时更新数据
962
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
963
- this.debouncedDepLinkFunc()
964
- }
965
- },
966
- deep: true
967
- }
968
- },
969
- inject: {
970
- getComponentByName: {
971
- default: () => () => {
972
- console.warn('getComponentByName is not provided')
973
- return null // 或者返回一个默认的函数
974
- },
975
- },
976
- registerComponent: {
977
- default: () => () => {
978
- console.warn('registerComponent is not provided')
979
- return null // 或者返回一个默认的函数
980
- },
981
- },
982
- getSelf: {
983
- default: () => () => {
984
- console.warn('getSelf is not provided')
985
- return null // 或者返回一个默认的函数
986
- },
987
- },
988
- XFormContext: {
989
- default: () => () => {
990
- console.warn('XFormContext is not provided')
991
- return null // 或者返回一个默认的函数
992
- },
993
- },
994
- setRequired: {
995
- default: () => () => {
996
- console.warn('setRequired is not provided')
997
- return null // 或者返回一个默认的函数
998
- },
999
- },
1000
- removeRequired: {
1001
- default: () => () => {
1002
- console.warn('removeRequired is not provided')
1003
- return null // 或者返回一个默认的函数
1004
- },
1005
- }
1006
- },
1007
- methods: {
1008
- // 处理 queryParams 结果并更新 rowChooseFixedQueryValue
1009
- handleQueryParamsResult (obj) {
1010
- let configName = ''
1011
- if (obj && typeof obj === 'object') {
1012
- // obj 是一个对象,并且不是数组
1013
- if (Object.prototype.hasOwnProperty.call(obj, 'configName')) {
1014
- configName = obj?.configName
1015
- }
1016
- if (Object.prototype.hasOwnProperty.call(obj, 'fixedQueryForm')) {
1017
- if (obj?.fixedQueryForm && typeof obj?.fixedQueryForm === 'object') {
1018
- this.rowChooseFixedQueryValue = Object.assign({}, this.rowChooseFixedQueryValue, obj.fixedQueryForm)
1019
- }
1020
- }
1021
- } else if (obj && typeof obj === 'string') {
1022
- configName = obj
1023
- }
1024
- return configName
1025
- },
1026
- // 根据selectValueType预处理options数据
1027
- processOptionsForValueType (options) {
1028
- return this.selectValueTypeHandler.processOptions(options, this.attr.selectValueType)
1029
- },
1030
-
1031
- // 处理both模式的数据,为表单添加label字段
1032
- processBothModeData () {
1033
- this.selectValueTypeHandler.processBothMode(
1034
- this.form,
1035
- this.attr.model,
1036
- this.attr.selectValueType,
1037
- this.option
1038
- )
1039
- },
1040
-
1041
- // 根据value查找对应的label(支持单选和多选)
1042
- findLabelByValue (value) {
1043
- return this.selectValueTypeHandler.findLabel(value, this.option)
1044
- },
1045
-
1046
- // 统一的表单项change处理逻辑
1047
- handleFormItemChange () {
1048
- // 处理both模式
1049
- if (this.attr.selectValueType === 'both') {
1050
- this.$nextTick(() => {
1051
- this.selectValueTypeHandler.processBothMode(
1052
- this.form,
1053
- this.attr.model,
1054
- this.form[this.attr.model],
1055
- this.option
1056
- )
1057
- })
1058
- }
1059
- // 处理label模式
1060
- if (this.attr.selectValueType === 'label') {
1061
- this.$nextTick(() => {
1062
- this.selectValueTypeHandler.processLabelMode(
1063
- this.form,
1064
- this.attr.model,
1065
- this.form[this.attr.model],
1066
- this.option
1067
- )
1068
- })
1069
- }
1070
- // 处理原有的dataChangeFunc
1071
- if (this.attr.dataChangeFunc) {
1072
- this.debouncedDataChangeFunc()
1073
- }
1074
- },
1075
-
1076
- // Select组件change处理
1077
- handleSelectChange () {
1078
- this.handleFormItemChange()
1079
- },
1080
-
1081
- // Checkbox组件change处理
1082
- handleCheckboxChange () {
1083
- this.handleFormItemChange()
1084
- },
1085
-
1086
- // Radio组件change处理
1087
- handleRadioChange () {
1088
- this.handleFormItemChange()
1089
- },
1090
-
1091
- // TreeSelect组件change处理(通过XTreeSelect组件回调)
1092
- handleTreeSelectChange () {
1093
- this.handleFormItemChange()
1094
- },
1095
-
1096
- // 把内部的crud表单录入放到表单中,以便外部可以调用
1097
- onComponentMounted (h, attr) {
1098
- console.log('crud表单', h)
1099
- if (attr.crud) {
1100
- this.registerComponent(attr.model, this.$refs['childXFormTable_' + attr.model])
1101
- }
1102
- },
1103
- childTableFixedQueryForm (item) {
1104
- console.log('传递的form', this.form)
1105
- if (this.modifyModelData?.primaryKeyData) {
1106
- const fixedForm = {}
1107
- fixedForm[item.childTableForeignKeyName] = Object.values(this.modifyModelData.primaryKeyData)[0]
1108
- return fixedForm
1109
- }
1110
- return null
1111
- },
1112
- // 动态生成事件绑定对象
1113
- generateDynamicEvents (inputOnAfterFunc, attr) {
1114
- const events = {}
1115
- const states = this.parseStates(attr.inputOnAfterName, inputOnAfterFunc)
1116
-
1117
- states.forEach((state) => {
1118
- // 动态绑定事件名到 emitFunc
1119
- events[state.event] = () => {
1120
- console.info('事件名', state.event)
1121
- this.emitFunc(state.event, attr)
1122
- }
1123
- })
1124
-
1125
- return events // 返回 { state1Event: handler, state2Event: handler, ... }
1126
- },
1127
- parseStates (input, events) {
1128
- const eventNames = events.split('|')
1129
- return input.split('|').map((label, index) => ({
1130
- label,
1131
- event: eventNames[index] // 如果没有提供事件名称,则使用默认值
1132
- }))
1133
- },
1134
- focusInput () {
1135
- if (this.attr.defaultFocus) {
1136
- this.$nextTick(h => {
1137
- const el = this.$refs[`${this.attr.model}input`]?.$el
1138
- let inputEl
1139
- if (el) {
1140
- if (el.tagName.toLowerCase() === 'input') {
1141
- inputEl = el
1142
- } else {
1143
- inputEl = el.querySelector('input')
1144
- }
1145
- }
1146
- if (inputEl) {
1147
- inputEl.focus()
1148
- if (inputEl.type === 'number') {
1149
- if (inputEl.valueAsNumber) {
1150
- inputEl.setSelectionRange(0, inputEl.valueAsNumber.toString().length)
1151
- }
1152
- } else {
1153
- if (inputEl.value) {
1154
- inputEl.setSelectionRange(0, inputEl.value.length)
1155
- }
1156
- }
1157
- }
1158
- })
1159
- }
1160
- },
1161
- // 更新人员下拉框数据
1162
- async updateResOptions (type) {
1163
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString()?.endsWith(`]联动${type}`)) {
1164
- const startIndex = this.attr.keyName.indexOf('[') + 1
1165
- const endIndex = this.attr.keyName.indexOf(']', startIndex)
1166
- const fromModel = this.attr.keyName.substring(startIndex, endIndex).replace('.', '_')
1167
- // 获取表单字段的实际值(优先使用originData中的原始值)
1168
- const rawFieldValue = this.form.originData && this.form.originData[fromModel]
1169
- ? this.form.originData[fromModel]
1170
- : this.form[fromModel]
1171
-
1172
- // 确保数据为数组格式(用于filter参数)
1173
- const filterValues = Array.isArray(rawFieldValue)
1174
- ? rawFieldValue
1175
- : [rawFieldValue]
1176
- if (fromModel?.length && filterValues?.length) {
1177
- const searchData = {
1178
- source: `获取${type}`,
1179
- userid: this.currUser.id,
1180
- filter: filterValues,
1181
- filterType: fromModel.indexOf('org') > -1 ? 'org' : 'dep'
1182
- }
1183
- const tempArray = []
1184
- await searchToListOption(searchData, res => {
1185
- this.getDataCallback(
1186
- res.filter(h => {
1187
- if (fromModel.indexOf('org') > -1) {
1188
- if (type === '部门') {
1189
- if (filterValues?.includes(h.orgid || h.f_organization_id) || filterValues?.includes(h.parentid) || tempArray.includes(h.parentid)) {
1190
- tempArray.push(h.value)
1191
- return true
1192
- }
1193
- return false
1194
- } else {
1195
- return filterValues?.includes(h.orgid || h.f_organization_id || h.parentid)
1196
- }
1197
- } else {
1198
- return filterValues?.includes(h?.parentid)
1199
- }
1200
- }
1201
- )
1202
- )
1203
- })
1204
- }
1205
- }
1206
- },
1207
- // js 函数作为数据源
1208
- async updateOptions () {
1209
- if (this.attr.keyName && (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1)) {
1210
- const rawOptions = await executeStrFunctionByContext(this, this.attr.keyName, [this.form, runLogic, this.mode, getConfigByNameAsync, post])
1211
- // 根据selectValueType预处理options数据
1212
- this.optionForFunc = this.processOptionsForValueType(rawOptions)
1213
- }
1214
- },
1215
- async dataChangeFunc () {
1216
- if (this.attr.dataChangeFunc) {
1217
- await executeStrFunctionByContext(this, this.attr.dataChangeFunc, [this.form, this.setForm, this.attr, util, this.mode, runLogic, getConfigByNameAsync])
1218
- }
1219
- },
1220
- async showFormItemFunc () {
1221
- if (this.attr.showFormItemFunc) {
1222
- const obj = executeStrFunctionByContext(this, this.attr.showFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode, this.curPermissions, this.curRoles])
1223
- // 判断是 bool 还是 obj 兼容
1224
- if (typeof obj === 'boolean') {
1225
- this.show = obj
1226
- } else if (obj && typeof obj === 'object') {
1227
- // obj 是一个对象,并且不是数组
1228
- if (Object.prototype.hasOwnProperty.call(obj, 'show')) {
1229
- this.show = obj?.show
1230
- }
1231
- if (Object.prototype.hasOwnProperty.call(obj, 'readOnly')) {
1232
- this.readOnly = obj?.readOnly
1233
- }
1234
- if (Object.prototype.hasOwnProperty.call(obj, 'disabled')) {
1235
- this.disabled = obj?.disabled
1236
- }
1237
- }
1238
- } else {
1239
- this.show = true
1240
- }
1241
- },
1242
- async showQueryFormItemFunc () {
1243
- if (this.attr.showQueryFormItemFunc) {
1244
- const obj = executeStrFunctionByContext(this, this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode, this.curPermissions, this.curRoles])
1245
- // 判断是 bool 还是 obj 兼容
1246
- if (typeof obj === 'boolean') {
1247
- this.show = obj
1248
- } else if (obj && typeof obj === 'object') {
1249
- // obj 是一个对象,并且不是数组
1250
- if (Object.prototype.hasOwnProperty.call(obj, 'show')) {
1251
- this.show = obj?.show
1252
- }
1253
- if (Object.prototype.hasOwnProperty.call(obj, 'readOnly')) {
1254
- this.readOnly = obj?.readOnly
1255
- }
1256
- if (Object.prototype.hasOwnProperty.call(obj, 'disabled')) {
1257
- this.disabled = obj?.disabled
1258
- }
1259
- }
1260
- } else {
1261
- this.show = true
1262
- }
1263
- },
1264
- init () {
1265
- if (!this.attr.flex) {
1266
- if (this.mode === '新增/修改') {
1267
- if (['horizontal', 'vertical'].includes(this.layout) || ['textarea', 'file', 'image'].includes(this.attr.type)) {
1268
- // 新增修改表单 horizontal 模式下默认为一行
1269
- this.attr.flex = {
1270
- xs: 24,
1271
- sm: 24,
1272
- md: 24,
1273
- lg: 24,
1274
- xl: 24,
1275
- xxl: 24,
1276
- fullWidth: true
1277
- }
1278
- } else {
1279
- // 新增修改表单 vertical 模式下默认为1列
1280
- this.attr.flex = {
1281
- xs: 24,
1282
- sm: 12,
1283
- md: 8,
1284
- lg: 8,
1285
- xl: 6,
1286
- xxl: 6
1287
- }
1288
- }
1289
- } else {
1290
- this.attr.flex = {
1291
- xs: 24,
1292
- sm: 24,
1293
- md: 8,
1294
- lg: 6,
1295
- xl: 6,
1296
- xxl: 6
1297
- }
1298
- }
1299
- }
1300
- if (this.attr.keyName && typeof this.attr.keyName === 'string') {
1301
- if (this.attr.keyName.indexOf('logic@') !== -1) {
1302
- this.getData({}, res => this.getDataCallback(res))
1303
- } else if (this.attr.keyName.indexOf('search@') !== -1) {
1304
- // `tool.getFullTree(this.getRights().where(row.getType()==$organization$))`
1305
- // 判断是否根据角色查询
1306
- let source = this.attr.keyName.substring(7)
1307
- const userid = this.currUser.id
1308
- let roleName = 'roleName'
1309
- if (source.startsWith('根据角色[') && source.endsWith(']获取人员')) {
1310
- const startIndex = source.indexOf('[') + 1
1311
- const endIndex = source.indexOf(']', startIndex)
1312
- roleName = source.substring(startIndex, endIndex)
1313
- source = '根据角色获取人员'
1314
- }
1315
- const searchData = { source, userid, roleName }
1316
- // 判断是否根据某个表单项联动 仅返回列表结构并筛选
1317
- if (source.startsWith('根据表单项[') && source.endsWith(']联动人员')) {
1318
- this.updateResOptions('人员')
1319
- } else if (source.startsWith('根据表单项[') && source.endsWith(']联动部门')) {
1320
- this.updateResOptions('部门')
1321
- } else if (this.attr.type === 'select' || this.attr.type === 'checkbox') {
1322
- // 仅获取最内层数据
1323
- searchToListOption(searchData, res => this.getDataCallback(res))
1324
- } else {
1325
- // 其他资源通用逻辑
1326
- searchToOption(searchData, res => this.getDataCallback(res))
1327
- }
1328
- } else if (this.attr.keyName.indexOf('config@') !== -1) {
1329
- const configName = this.attr.keyName.substring(7)
1330
- getConfigByName(configName, this.serviceName, res => {
1331
- this.getDataCallback(res.value)
1332
- }, this.env === 'dev')
1333
- } else if (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1) {
1334
- this.updateOptions()
1335
- }
1336
- } else if (this.attr.keys) {
1337
- // 对静态配置的keys也进行预处理
1338
- this.getDataCallback(this.attr.keys)
1339
- }
1340
- this.focusInput()
1341
- },
1342
- addressSearchComboboxSelect (data) {
1343
- this.form = Object.assign(this.form, JSON.parse(data))
1344
- },
1345
- onDivisionsChange (data) {
1346
- this.emitFunc('addressSearchComboboxSelect', {
1347
- key: this.attr.model,
1348
- value: data
1349
- })
1350
- },
1351
- getDataCallback (res) {
1352
- // 根据selectValueType预处理options数据
1353
- this.option = this.processOptionsForValueType(res)
1354
-
1355
- if (this.attr.type === 'treeSelect') {
1356
- this.$nextTick(() => {
1357
- this.$refs.xTreeSelect.init({
1358
- option: this.option,
1359
- form: this.form,
1360
- queryType: this.attr.queryType,
1361
- name: this.attr.name,
1362
- model: this.attr.model,
1363
- mode: this.mode,
1364
- disabled: this.disabled
1365
- })
1366
- })
1367
- } else if (this.attr.type === 'radio' || ['radioGroup', 'clickChange'].includes(this.attr.showMode)) {
1368
- this.initRadioValue()
1369
- }
1370
- },
1371
- initRadioValue () {
1372
- const model = this.attr.model
1373
- if (this.mode === '新增/修改' && (this.form[model] === undefined || this.form[model] === null) && !this.attr.prop) {
1374
- if (this.attr.keys && this.attr.keys.length > 1) {
1375
- this.form[model] = this.attr.keys[0].value
1376
- } else if (this.option.length > 1) {
1377
- this.form[model] = this.option[0].value
1378
- }
1379
- }
1380
- },
1381
- // 文件框时设置上传组件的值
1382
- setFiles (fileIds) {
1383
- if (!this.form[this.attr.model]) {
1384
- this.form[this.attr.model] = []
1385
- }
1386
- this.form[this.attr.model] = [...fileIds]
1387
- },
1388
- // 懒加载检索方法
1389
- fetchFunction (value) {
1390
- this.lastFetchId += 1
1391
- const fetchId = this.lastFetchId
1392
- this.option = []
1393
- this.searching = true
1394
- this.getData({
1395
- word: value
1396
- }, res => {
1397
- if (fetchId !== this.lastFetchId) {
1398
- return
1399
- }
1400
- this.option = res
1401
- this.searching = false
1402
- })
1403
- },
1404
- // 获取数据
1405
- getData (value, callbackFun) {
1406
- if (value !== '') {
1407
- const logicName = this.attr.keyName
1408
- const logic = logicName.substring(6)
1409
- // 调用logic前设置参数
1410
- if (this.getDataParams && this.getDataParams[this.attr.model]) {
1411
- Object.assign(value, this.getDataParams[this.attr.model])
1412
- }
1413
- runLogic(logic, Object.assign(value, {
1414
- orgId: this.currUser.orgid,
1415
- userId: this.currUser.id
1416
- }), this.serviceName, this.env === 'dev').then(res => {
1417
- callbackFun(res)
1418
- }).catch(e => {
1419
- callbackFun([])
1420
- console.error('获取数据失败:' + e)
1421
- })
1422
- }
1423
- },
1424
- filterOption (input, option) {
1425
- const child = option.componentOptions.children[0]
1426
- if (child.text) {
1427
- return child.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
1428
- } else if (child.elm.innerText) {
1429
- return child.elm.innerText.toLowerCase().indexOf(input.toLowerCase()) >= 0
1430
- } else {
1431
- return child.child.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
1432
- }
1433
- },
1434
- // 表单项变更函数中调用 控制表单组中表单项组名为 groupName 的表单是否展示
1435
- // func:x-form-show(显示)/x-form-no-show(不显示)
1436
- emitShowFormFunc (func, groupName) {
1437
- this.emitFunc(func, groupName)
1438
- },
1439
- emitFunc (func, data) {
1440
- this.$emit('x-form-item-emit-func', func, data, data?.model ? this.form[data.model] : this.form)
1441
- },
1442
- itemMounted (h) {
1443
- this.$emit('mounted', h)
1444
- },
1445
- rowChoose (rows) {
1446
- this.$emit('rowChoose', rows, this.attr, this.closeRowChooseInput)
1447
- },
1448
- searchRowChooseData () {
1449
- if (this.searching) {
1450
- return
1451
- }
1452
- this.lastFetchId += 1
1453
- const fetchId = this.lastFetchId
1454
- this.searching = true
1455
- if (fetchId !== this.lastFetchId) {
1456
- return
1457
- }
1458
- this.rowChooseFixedQueryValue = []
1459
- this.rowChooseFixedQueryValue[this.attr.model] = this.form[this.attr.model]
1460
- this.$nextTick(() => {
1461
- this.$refs.rowChooseTable.refresh(true)
1462
- })
1463
- },
1464
- showCloseRowChooseInput () {
1465
- this.rowChoosePopoverVisible = true
1466
- },
1467
- closeRowChooseInput () {
1468
- this.rowChoosePopoverVisible = false
1469
- },
1470
- rowChooseSearchAfterQuery () {
1471
- this.searching = false
1472
- },
1473
- // 获取 recording 转换后的数据
1474
- getRecodingData () {
1475
- return this.$refs.recording.getRecordingData()
1476
- },
1477
- recordingData (data) {
1478
- this.emitFunc('recordingData', data)
1479
- },
1480
- getPopupContainer (triggerNode) {
1481
- // return document.body
1482
- return triggerNode.parentNode
1483
- },
1484
- colorPickerComboboxSelect (val) {
1485
- this.form[this.attr.model] = val
1486
- },
1487
- }
1488
- }
1489
- </script>
1490
-
1491
- <style lang="less" scoped>
1492
- .custom-dropdown {
1493
- position: absolute;
1494
- z-index: 1050;
1495
- }
1496
-
1497
- .multiple_select {
1498
- :deep(.ant-select-selection) {
1499
- max-height: 32px;
1500
- overflow-y: scroll;
1501
- }
1502
- }
1503
-
1504
- </style>
1
+ <template>
2
+ <!-- 输入框 -->
3
+ <x-form-col
4
+ v-if="attr.type === 'input' && show"
5
+ :occupyCol="attr.occupyCol"
6
+ :labelCol="labelCol"
7
+ :flex="attr.flex">
8
+ <a-form-model-item
9
+ v-bind="bindOther"
10
+ :rules="rules"
11
+ :ref="attr.model"
12
+ :label="showLabel?attr.name:undefined"
13
+ :prop="attr.prop ? attr.prop : attr.model">
14
+ <!-- 如果配置了后置按钮插槽 -->
15
+ <a-input-group
16
+ v-if="((attr.inputOnAfterName && attr.inputOnAfterFunc) || (attr.inputOnAfterIcon && attr.inputOnAfterIconFunc)) && mode !== '查询'"
17
+ style="display: flex; width: 100%; padding: 4px 0"
18
+ compact>
19
+ <a-input
20
+ v-model="form[attr.model]"
21
+ :read-only="readOnly"
22
+ :disabled="disabled && !readOnly"
23
+ :whitespace="true"
24
+ @input="attr.dataChangeFunc && debouncedDataChangeFunc()"
25
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
26
+ @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
27
+ @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
28
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
29
+ :ref="`${attr.model}input`"/>
30
+ <a-button
31
+ v-if="attr.inputOnAfterName && attr.inputOnAfterFunc && !attr.inputOnAfterName.includes('|')"
32
+ style="width: auto; min-width: 4rem;max-width: 6rem"
33
+ type="primary"
34
+ @click="emitFunc(attr.inputOnAfterFunc,attr)">
35
+ {{ attr.inputOnAfterName }}
36
+ </a-button>
37
+ <!-- 仅可以配置 一个按钮 以及 一个图标插槽 -->
38
+ <a-button
39
+ style="width: 2rem; flex-shrink: 0;"
40
+ v-else-if="attr.inputOnAfterIcon"
41
+ :type="attr.inputOnAfterIcon && attr.inputOnAfterName ? 'primary' :''"
42
+ :icon="attr.inputOnAfterIcon || 'question'"
43
+ @click="emitFunc(attr.inputOnAfterIconFunc,attr)">
44
+ </a-button>
45
+ <!-- 状态按钮 -->
46
+ <x-status-button
47
+ v-else
48
+ :states="parseStates(attr.inputOnAfterName, attr.inputOnAfterFunc)"
49
+ v-on="generateDynamicEvents(attr.inputOnAfterFunc, attr)"
50
+ style="width: auto; min-width: 4rem; max-width: 6rem"
51
+ />
52
+ </a-input-group>
53
+ <a-input-number
54
+ v-else-if="attr.numberInput && !readOnly"
55
+ v-model="form[attr.model]"
56
+ :whitespace="true"
57
+ @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
58
+ :disabled="disabled && !readOnly"
59
+ style="width:100%"
60
+ @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
61
+ @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
62
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
63
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
64
+ :ref="`${attr.model}input`"/>
65
+ <a-input
66
+ v-else
67
+ v-model="form[attr.model]"
68
+ :whitespace="true"
69
+ :read-only="readOnly"
70
+ :disabled="disabled && !readOnly"
71
+ @input="attr.dataChangeFunc && debouncedDataChangeFunc()"
72
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
73
+ style="width:100%"
74
+ @blur="mode !== '查询' && attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
75
+ @keyup.enter="mode !== '查询' && attr.inputOnEnterFunc && emitFunc(attr.inputOnEnterFunc, attr)"
76
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
77
+ :ref="`${attr.model}input`"/>
78
+ </a-form-model-item>
79
+ </x-form-col>
80
+ <!-- 下拉框 -->
81
+ <x-form-col
82
+ v-else-if="attr.type === 'select' && show"
83
+ :labelCol="labelCol"
84
+ :flex="attr.flex">
85
+ <a-form-model-item
86
+ v-bind="bindOther"
87
+ :rules="rules"
88
+ v-if="!attr.showMode || mode === '查询' || attr.showMode === 'select' "
89
+ :ref="attr.model"
90
+ :label="showLabel?attr.name:undefined"
91
+ :prop="attr.prop ? attr.prop : attr.model">
92
+ <!-- <span slot="label" class="label-box">{{ showLabel?attr.name:undefined }}</span>-->
93
+ <a-select
94
+ v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
95
+ v-model="form[attr.model]"
96
+ :disabled="disabled"
97
+ @change="handleSelectChange"
98
+ :filter-option="filterOption"
99
+ :getPopupContainer="getPopupContainer"
100
+ dropdownClassName="custom-dropdown"
101
+ :dropdownMatchSelectWidth="false"
102
+ :dropdownStyle="{ position: 'absolute'}"
103
+ :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
104
+ show-search
105
+ :allowClear="true"
106
+ :getCalendarContainer="(triggerNode) => triggerNode.parentNode"
107
+ >
108
+ <a-select-option
109
+ v-if="mode === '查询'"
110
+ key="999999"
111
+ value="">全部
112
+ </a-select-option>
113
+ <template v-if="attr.keys">
114
+ <a-select-option
115
+ v-for="(item,index) in attr.keys"
116
+ :key="index.value"
117
+ :value="item.value + ''">
118
+ {{ item.label }}
119
+ </a-select-option>
120
+ </template>
121
+ <template v-else>
122
+ <template
123
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
124
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
125
+ <a-select-option
126
+ v-for="(item,index) in option"
127
+ :key="index.value"
128
+ :value="item.value + ''">
129
+ <template v-if="attr.keyName.indexOf('config@') !== -1 && item.status">
130
+ <!-- 徽标(badge) -->
131
+ <a-badge v-if="item.status !== 'gary'" :color="item.status" :text="item.label"/>
132
+ <a-badge v-else color="#D9D9D9" :text="item.label"/>
133
+ </template>
134
+ <template v-else>
135
+ {{ item.label }}
136
+ </template>
137
+ </a-select-option>
138
+ </template>
139
+ <template
140
+ v-else-if="attr.keyName.indexOf('async ') !== -1 || attr.keyName.indexOf('function ') !== -1">
141
+ <a-select-option
142
+ v-for="(item,index) in optionForFunc"
143
+ :key="index.value"
144
+ :value="item.value + ''">
145
+ <template>
146
+ {{ item.label }}
147
+ </template>
148
+ </a-select-option>
149
+ </template>
150
+ <template v-else>
151
+ <a-select-option
152
+ v-for="item in $appdata.getDictionaryList(attr.keyName)"
153
+ :key="item.value"
154
+ :value="item.value + ''">
155
+ <!-- 徽标(badge) -->
156
+ <x-badge
157
+ :badge-key="attr.keyName"
158
+ :replaceText="item.text"
159
+ :value="item.value"
160
+ :service-name="serviceName"
161
+ :env="env"/>
162
+ </a-select-option>
163
+ </template>
164
+ </template>
165
+ </a-select>
166
+ <a-select
167
+ v-else
168
+ v-model="form[attr.model]"
169
+ :disabled="disabled"
170
+ @change="handleSelectChange"
171
+ :filter-option="filterOption"
172
+ :getPopupContainer="getPopupContainer"
173
+ dropdownClassName="custom-dropdown"
174
+ :dropdownMatchSelectWidth="false"
175
+ :dropdownStyle="{ position: 'absolute'}"
176
+ :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
177
+ show-search
178
+ @search="fetchFunction"
179
+ >
180
+ <template #notFoundContent>
181
+ <a-spin v-if="searching" size="small"/>
182
+ </template>
183
+ <a-select-option
184
+ v-if="mode === '查询'"
185
+ key="999999"
186
+ value="">全部
187
+ </a-select-option>
188
+ <a-select-option
189
+ v-for="(item,index) in option"
190
+ :key="index"
191
+ :value="item.value + ''">{{ item.label }}
192
+ </a-select-option>
193
+ </a-select>
194
+ </a-form-model-item>
195
+ <a-form-model-item
196
+ v-bind="bindOther"
197
+ :rules="rules"
198
+ v-else-if="attr.showMode === 'radioGroup'"
199
+ :ref="attr.model"
200
+ :label="showLabel?attr.name:undefined"
201
+ :prop="attr.prop ? attr.prop : attr.model">
202
+ <a-radio-group v-model="form[attr.model]">
203
+ <a-radio-button v-for="modeItem in option" :key="modeItem.value" :value="modeItem.value">
204
+ {{ modeItem.label }}
205
+ </a-radio-button>
206
+ </a-radio-group>
207
+ </a-form-model-item>
208
+ <a-form-model-item
209
+ v-bind="bindOther"
210
+ v-else-if="attr.showMode === 'clickChange' && option.length > 0"
211
+ :ref="attr.model"
212
+ :label="showLabel?attr.name:undefined"
213
+ :prop="attr.prop ? attr.prop : attr.model">
214
+ <XClickChangeBtn></XClickChangeBtn>
215
+ </a-form-model-item>
216
+ </x-form-col>
217
+ <!-- 多选框 -->
218
+ <x-form-col
219
+ v-else-if="attr.type === 'checkbox' && show"
220
+ :labelCol="labelCol"
221
+ :flex="attr.flex">
222
+ <a-form-model-item
223
+ v-bind="bindOther"
224
+ :rules="rules"
225
+ v-if="!attr.showMode || mode === '查询' || attr.showMode === 'select' "
226
+ :ref="attr.model"
227
+ :label="showLabel?attr.name:undefined"
228
+ :prop="attr.prop ? attr.prop : attr.model">
229
+ <a-select
230
+ class="multiple_select"
231
+ style="width:100%"
232
+ v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
233
+ v-model="form[attr.model]"
234
+ :disabled="disabled"
235
+ :filter-option="filterOption"
236
+ :getPopupContainer="getPopupContainer"
237
+ :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
238
+ @change="handleCheckboxChange"
239
+ mode="multiple"
240
+ show-search
241
+ allowClear
242
+ >
243
+ <template v-if="attr.keys">
244
+ <a-select-option
245
+ v-for="(item,index) in attr.keys"
246
+ :key="index"
247
+ :value="item.value + ''">
248
+ {{ item.label }}
249
+ </a-select-option>
250
+ </template>
251
+ <template v-else>
252
+ <template
253
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
254
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
255
+ <a-select-option
256
+ v-for="(item,index) in option"
257
+ :key="index"
258
+ :value="item.value">{{ item.label }}
259
+ </a-select-option>
260
+ </template>
261
+ <template v-else>
262
+ <a-select-option
263
+ v-for="item in $appdata.getDictionaryList(attr.keyName)"
264
+ :key="item.value"
265
+ :value="item.value + ''">{{ item.text }}
266
+ </a-select-option>
267
+ </template>
268
+ </template>
269
+ </a-select>
270
+ <a-select
271
+ v-else
272
+ class="multiple_select"
273
+ v-model="form[attr.model]"
274
+ :disabled="disabled"
275
+ :filter-option="filterOption"
276
+ :getPopupContainer="getPopupContainer"
277
+ :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
278
+ mode="multiple"
279
+ style="width:100%"
280
+ @change="handleCheckboxChange"
281
+ show-search
282
+ allowClear
283
+ @search="fetchFunction"
284
+ >
285
+ <template #notFoundContent>
286
+ <a-spin v-if="searching" size="small"/>
287
+ </template>
288
+ <a-select-option
289
+ v-for="(item,index) in option"
290
+ :key="index"
291
+ :value="item.value + ''">{{ item.label }}
292
+ </a-select-option>
293
+ </a-select>
294
+ </a-form-model-item>
295
+ <a-form-model-item
296
+ v-bind="bindOther"
297
+ :rules="rules"
298
+ v-else
299
+ :ref="attr.model"
300
+ :label="showLabel?attr.name:undefined"
301
+ :prop="attr.prop ? attr.prop : attr.model">
302
+ <a-checkbox-group
303
+ v-model="form[attr.model]"
304
+ :options="option"
305
+ @change="handleCheckboxChange"
306
+ />
307
+ </a-form-model-item>
308
+ </x-form-col>
309
+ <!-- 单选框 -->
310
+ <x-form-col
311
+ v-else-if="attr.type === 'radio' && show"
312
+ :labelCol="labelCol"
313
+ :flex="attr.flex">
314
+ <a-form-model-item
315
+ v-bind="bindOther"
316
+ :rules="rules"
317
+ v-if="!attr.showMode || attr.type === 'radio' "
318
+ :ref="attr.model"
319
+ :label="showLabel?attr.name:undefined"
320
+ :prop="attr.prop ? attr.prop : attr.model">
321
+ <a-radio-group
322
+ v-model="form[attr.model]"
323
+ @change="handleRadioChange"
324
+ >
325
+ <template v-if="attr.keys">
326
+ <a-radio v-for="(item,index) in attr.keys" :key="index" :value="item.value">
327
+ {{ item.label }}
328
+ </a-radio>
329
+ </template>
330
+ <template v-else>
331
+ <template
332
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
333
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
334
+ <a-radio v-for="(item,index) in option" :key="index" :value="item.value">
335
+ {{ item.label }}
336
+ </a-radio>
337
+ </template>
338
+ <template v-else>
339
+ <a-radio v-for="(item,index) in $appdata.getDictionaryList(attr.keyName)" :key="index" :value="item.value">
340
+ {{ item.text }}
341
+ </a-radio>
342
+ </template>
343
+ </template>
344
+ </a-radio-group>
345
+ </a-form-model-item>
346
+ <a-form-model-item
347
+ v-bind="bindOther"
348
+ :rules="rules"
349
+ v-else-if="attr.showMode === 'radioGroup'"
350
+ :ref="attr.model"
351
+ :label="showLabel?attr.name:undefined"
352
+ :prop="attr.prop ? attr.prop : attr.model">
353
+ <a-radio-group v-model="form[attr.model]">
354
+ <a-radio-button v-for="modeItem in option" :key="modeItem.value" :value="modeItem.value">
355
+ {{ modeItem.label }}
356
+ </a-radio-button>
357
+ </a-radio-group>
358
+ </a-form-model-item>
359
+ <a-form-model-item
360
+ v-bind="bindOther"
361
+ :rules="rules"
362
+ v-else-if="attr.showMode === 'clickChange' && option.length > 0"
363
+ :ref="attr.model"
364
+ :label="showLabel?attr.name:undefined"
365
+ :prop="attr.prop ? attr.prop : attr.model">
366
+ <XClickChangeBtn></XClickChangeBtn>
367
+ </a-form-model-item>
368
+ </x-form-col>
369
+ <!-- 时间 日期 框整合 -->
370
+ <x-form-col
371
+ v-else-if="['datePicker', 'rangePicker', 'yearPicker', 'monthPicker', 'yearRangePicker', 'monthRangePicker'].includes(attr.type) && show"
372
+ :labelCol="labelCol"
373
+ :flex="attr.flex">
374
+ <a-form-model-item
375
+ v-bind="bindOther"
376
+ :rules="rules"
377
+ :ref="attr.model"
378
+ :label="showLabel?attr.name:undefined"
379
+ :prop="attr.prop ? attr.prop : attr.model">
380
+ <XFormDatePicker
381
+ :attr="attr"
382
+ :mode="mode"
383
+ :disabled="disabled"
384
+ :readOnly="readOnly"
385
+ :showLabel="showLabel"
386
+ @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
387
+ v-model="form[attr.model]"/>
388
+ </a-form-model-item>
389
+ </x-form-col>
390
+ <!-- 文本域 -->
391
+ <x-form-col
392
+ v-else-if="attr.type === 'textarea' && show"
393
+ :labelCol="labelCol"
394
+ :flex="attr.flex">
395
+ <!-- :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"-->
396
+ <a-form-model-item
397
+ v-bind="bindOther"
398
+ :rules="rules"
399
+ :ref="attr.model"
400
+ :label="showLabel?attr.name:undefined"
401
+ :prop="attr.prop ? attr.prop : attr.model">
402
+ <a-textarea
403
+ v-model="form[attr.model]"
404
+ style="width: 100%;"
405
+ :disabled="disabled"
406
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
407
+ :rows="4"/>
408
+ </a-form-model-item>
409
+ </x-form-col>
410
+ <!-- 文件上传 -->
411
+ <x-form-col
412
+ v-else-if="(attr.type === 'file' || attr.type === 'image') && show"
413
+ :labelCol="labelCol"
414
+ :flex="attr.flex">
415
+ <a-form-model-item
416
+ v-bind="bindOther"
417
+ :rules="rules"
418
+ :ref="attr.model"
419
+ :label="showLabel?attr.name:undefined"
420
+ :prop="attr.prop ? attr.prop : attr.model">
421
+ <upload
422
+ :files="files"
423
+ :read-only="readOnly"
424
+ :images="images"
425
+ :model="attr"
426
+ v-bind="attr"
427
+ :service-name="serviceName"
428
+ @setFiles="setFiles"></upload>
429
+ </a-form-model-item>
430
+ </x-form-col>
431
+ <!-- 省市区选择框 -->
432
+ <x-form-col
433
+ v-else-if="attr.type === 'citySelect' && show"
434
+ :labelCol="labelCol"
435
+ :flex="attr.flex">
436
+ <a-form-model-item
437
+ v-bind="bindOther"
438
+ :rules="rules"
439
+ :ref="attr.model"
440
+ :label="showLabel?attr.name:undefined"
441
+ :prop="attr.prop ? attr.prop : attr.model">
442
+ <citySelect
443
+ @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
444
+ ref="citySelect"
445
+ v-model="form[attr.model]"
446
+ :contexts="attr.contexts"
447
+ :value-type="attr.valueType"
448
+ :default-value="form[attr.model]"></citySelect>
449
+ </a-form-model-item>
450
+ </x-form-col>
451
+ <!-- 地点搜索框 -->
452
+ <x-form-col
453
+ v-else-if="(attr.type === 'addressSearch' || attr.type === 'coordinateSearch') && show"
454
+ :labelCol="labelCol"
455
+ :occupyCol="attr.occupyCol"
456
+ :flex="attr.flex">
457
+ <a-form-model-item
458
+ v-bind="bindOther"
459
+ :rules="rules"
460
+ :ref="attr.model"
461
+ :label="showLabel?attr.name:undefined"
462
+ :prop="attr.prop ? attr.prop : attr.model">
463
+ <address-search-combobox
464
+ :emitFunc="emitFunc"
465
+ :attr="attr"
466
+ :read-only="readOnly"
467
+ :searchResult="form[attr.model]"
468
+ :address="{ address: form[attr.model], coords: form[`${attr.model}_lng_lat`] }"
469
+ :resultKeys="{ address: attr.model, coords: `${attr.model}_lng_lat` }"
470
+ ref="addressSearchCombobox"
471
+ searchResultType="Object"
472
+ @onSelect="addressSearchComboboxSelect"
473
+ @onDivisionsChange="onDivisionsChange"
474
+ ></address-search-combobox>
475
+ </a-form-model-item>
476
+ </x-form-col>
477
+ <!-- 颜色选择器 -->
478
+ <x-form-col
479
+ v-else-if="attr.type === 'colorPicker' && show"
480
+ :labelCol="labelCol"
481
+ :flex="attr.flex">
482
+ <a-form-model-item
483
+ v-bind="bindOther"
484
+ :rules="rules"
485
+ :ref="attr.model"
486
+ :label="showLabel?attr.name:undefined"
487
+ :prop="attr.prop ? attr.prop : attr.model">
488
+ <color-picker-combobox
489
+ :value="form[attr.model]"
490
+ :read-only="readOnly"
491
+ @onSelect="colorPickerComboboxSelect"
492
+ />
493
+ </a-form-model-item>
494
+ </x-form-col>
495
+ <!-- 人员选择框 -->
496
+ <x-form-col
497
+ v-else-if="attr.type === 'personSetting' && show"
498
+ :labelCol="labelCol"
499
+ :flex="attr.flex">
500
+ <a-form-model-item
501
+ v-bind="bindOther"
502
+ :rules="rules"
503
+ :ref="attr.model"
504
+ :label="showLabel?attr.name:undefined"
505
+ :prop="attr.prop ? attr.prop : attr.model">
506
+ <PersonSetting v-model="form[attr.model]"></PersonSetting>
507
+ </a-form-model-item>
508
+ </x-form-col>
509
+ <!-- 树形选择框 -->
510
+ <x-form-col
511
+ v-else-if="attr.type === 'treeSelect' && show"
512
+ :labelCol="labelCol"
513
+ :flex="attr.flex">
514
+ <x-tree-select
515
+ :rules="rules"
516
+ @onChange="handleTreeSelectChange"
517
+ v-model="form[attr.model]"
518
+ :attr="attr"
519
+ @mounted="itemMounted"
520
+ ref="xTreeSelect">
521
+ </x-tree-select>
522
+ </x-form-col>
523
+ <!-- 列表选择框 -->
524
+ <x-form-col
525
+ v-else-if="attr.type === 'listSelect' && show"
526
+ :labelCol="labelCol"
527
+ :flex="attr.flex">
528
+ <a-form-model-item
529
+ v-bind="bindOther"
530
+ :rules="rules"
531
+ :ref="attr.model"
532
+ :label="showLabel?attr.name:undefined"
533
+ :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
534
+ :prop="attr.prop ? attr.prop : attr.model">
535
+ <a-popover
536
+ ref="rowChoosePopover"
537
+ :visible="rowChoosePopoverVisible"
538
+ title="选择数据"
539
+ placement="bottom"
540
+ trigger="focus"
541
+ :arrowPointAtCenter="true"
542
+ :overlayStyle="{ width: '1000px', height: '30vh' }">
543
+ <template #content>
544
+ <x-report
545
+ v-if="isCover"
546
+ :use-oss-for-img="false"
547
+ :config-name="queryParamsName"
548
+ :service-name="serviceName"
549
+ :show-img-in-cell="true"
550
+ :display-only="true"
551
+ :edit-mode="false"
552
+ :show-save-button="true"
553
+ :no-padding="true"
554
+ :dont-format="true"
555
+ @rowChoose="rowChoose"
556
+ @cancel="closeRowChooseInput"
557
+ >
558
+ </x-report>
559
+ <x-form-table
560
+ v-else
561
+ title="请选择数据"
562
+ :queryParamsName="queryParamsName"
563
+ :rowSelectMode="true"
564
+ :allowSelectRowNum="1"
565
+ :service-name="serviceName"
566
+ :fixed-query-form="rowChooseFixedQueryValue"
567
+ @rowChoose="rowChoose"
568
+ @afterQuery="rowChooseSearchAfterQuery"
569
+ ref="rowChooseTable">
570
+ <template #button>
571
+ <a-button @click="closeRowChooseInput">
572
+ 关闭
573
+ </a-button>
574
+ </template>
575
+ </x-form-table>
576
+ </template>
577
+ <a-input
578
+ v-model="form[attr.model]"
579
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
580
+ @change="searchRowChooseData"
581
+ @focus="showCloseRowChooseInput"/>
582
+ </a-popover>
583
+ </a-form-model-item>
584
+ </x-form-col>
585
+ <!-- 评分框 -->
586
+ <x-form-col
587
+ v-else-if="attr.type === 'rate' && show"
588
+ :labelCol="labelCol"
589
+ :flex="attr.flex">
590
+ <a-form-model-item
591
+ v-bind="bindOther"
592
+ :rules="rules"
593
+ :ref="attr.model"
594
+ :label="showLabel?attr.name:undefined"
595
+ :prop="attr.prop ? attr.prop : attr.model">
596
+ <x-rate
597
+ v-model="form[attr.model]"
598
+ :mode="mode"
599
+ :disabled="disabled"
600
+ :query-type="attr.queryType"
601
+ :max-count="attr.maxCount"
602
+ :allow-half="attr.allowHalf"
603
+ :icon="attr.rateIcon"
604
+ :placeholder="attr.placeholder ? attr.placeholder : '请选择'+attr.name.replace(/\s*/g, '')"
605
+ @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
606
+ />
607
+ </a-form-model-item>
608
+ </x-form-col>
609
+ <!-- 区间选择器 -->
610
+ <x-form-col
611
+ v-else-if="attr.type === 'intervalPicker' && show"
612
+ :labelCol="labelCol"
613
+ :flex="attr.flex">
614
+ <a-form-model-item
615
+ v-bind="bindOther"
616
+ :rules="rules"
617
+ :ref="attr.model"
618
+ :label="showLabel?attr.name:undefined"
619
+ :prop="attr.prop ? attr.prop : attr.model">
620
+ <x-interval-picker
621
+ v-model="form[attr.model]"
622
+ :mode="mode"
623
+ :read-only="readOnly"
624
+ :disabled="disabled && !readOnly"
625
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
626
+ :start-placeholder="attr.startPlaceholder || '起始值'"
627
+ :end-placeholder="attr.endPlaceholder || '结束值'"
628
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
629
+ />
630
+ </a-form-model-item>
631
+ </x-form-col>
632
+ <!-- 车牌号选择 -->
633
+ <x-form-col
634
+ v-else-if="attr.type === 'licensePlate' && show"
635
+ :labelCol="labelCol"
636
+ :flex="attr.flex">
637
+ <a-form-model-item
638
+ v-bind="bindOther"
639
+ :rules="rules"
640
+ :ref="attr.model"
641
+ :label="showLabel?attr.name:undefined"
642
+ :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
643
+ :prop="attr.prop ? attr.prop : attr.model">
644
+ <!-- 如果配置了后置按钮插槽 -->
645
+ <a-input
646
+ v-if="mode ==='查询'"
647
+ v-model="form[attr.model]"
648
+ :whitespace="true"
649
+ :read-only="readOnly"
650
+ :disabled="disabled && !readOnly"
651
+ style="width:100%"
652
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
653
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
654
+ :ref="`${attr.model}input`"/>
655
+ <x-license-plate
656
+ v-else
657
+ v-model="form[attr.model]"
658
+ @change="attr.dataChangeFunc && debouncedDataChangeFunc()"
659
+ ></x-license-plate>
660
+ </a-form-model-item>
661
+ </x-form-col>
662
+ <!-- 录音 -->
663
+ <x-form-col
664
+ v-else-if="attr.type === 'recording' && show"
665
+ :labelCol="labelCol"
666
+ :flex="attr.flex">
667
+ <recording
668
+ ref="recording"
669
+ @recordingData="recordingData"
670
+ >
671
+ </recording>
672
+ </x-form-col>
673
+ <!-- 表格录入 -->
674
+ <x-form-col
675
+ v-else-if="attr.type === 'rowEdit' && show"
676
+ :labelCol="labelCol"
677
+ :flex="attr.flex">
678
+ <a-form-model-item
679
+ v-bind="bindOther"
680
+ :rules="rules"
681
+ :ref="attr.model"
682
+ :label="showLabel?attr.name:undefined"
683
+ :prop="attr.prop ? attr.prop : attr.model">
684
+ <x-form-table
685
+ :key="'childTable_' + attr.model"
686
+ :title="attr.name"
687
+ :queryParamsName="attr.crud"
688
+ :localEditMode="true"
689
+ :fixed-query-form="childTableFixedQueryForm(attr)"
690
+ :service-name="serviceName"
691
+ @hook:mounted="(h)=>onComponentMounted(h, attr)"
692
+ :ref="'childXFormTable_' + attr.model">
693
+ </x-form-table>
694
+ </a-form-model-item>
695
+ </x-form-col>
696
+ </template>
697
+ <script>
698
+ import { debounce } from 'ant-design-vue/lib/vc-table/src/utils'
699
+ import XFormCol from '@vue2-client/base-client/components/common/XFormCol'
700
+ import XBadge from '@vue2-client/base-client/components/common/XBadge'
701
+ import CitySelect from '@vue2-client/base-client/components/common/CitySelect'
702
+ import PersonSetting from '@vue2-client/base-client/components/common/PersonSetting'
703
+ import AddressSearchCombobox from '@vue2-client/base-client/components/common/AddressSearchCombobox'
704
+ import Upload from '@vue2-client/base-client/components/common/Upload'
705
+ import moment from 'moment'
706
+ import { getConfigByName, runLogic, getConfigByNameAsync } from '@vue2-client/services/api/common'
707
+ import * as util from '@vue2-client/utils/util'
708
+ import XTreeSelect from '@vue2-client/base-client/components/common/XForm/XTreeSelect'
709
+ import { searchToListOption, searchToOption } from '@vue2-client/services/v3Api'
710
+ import { mapState } from 'vuex'
711
+ import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
712
+ import XLicensePlate from '@vue2-client/base-client/components/common/XLicensePlate/XLicensePlate.vue'
713
+ import XStatusButton from './XStatusButton.vue'
714
+ import XClickChangeBtn from './itemComponent/XClickChangeBtn'
715
+ import 'moment/locale/zh-cn'
716
+ import XFormDatePicker from '@vue2-client/base-client/components/common/XDatePicker/index.vue'
717
+ import XIntervalPicker from '@vue2-client/base-client/components/common/XIntervalPicker/XIntervalPicker.vue'
718
+ import XRate from '@vue2-client/base-client/components/common/XRate/index.vue'
719
+ import { post } from '@vue2-client/services/api/restTools'
720
+ import ColorPickerCombobox from '@vue2-client/base-client/components/common/ColorPickerCombobox/ColorPickerCombobox.vue'
721
+ import { createSelectValueTypeHandler } from '@vue2-client/base-client/plugins/selectValueTypeHelper'
722
+
723
+ export default {
724
+ name: 'XFormItem',
725
+ components: {
726
+ XFormDatePicker,
727
+ XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
728
+ Recording: () => import('@vue2-client/base-client/components/common/Recording/Recording.vue'),
729
+ XReport: () => import('@vue2-client/base-client/components/common/XReportGrid/XReport.vue'),
730
+ XLicensePlate,
731
+ XTreeSelect,
732
+ XFormCol,
733
+ XBadge,
734
+ CitySelect,
735
+ PersonSetting,
736
+ AddressSearchCombobox,
737
+ Upload,
738
+ XStatusButton,
739
+ XClickChangeBtn,
740
+ XIntervalPicker,
741
+ XRate,
742
+ ColorPickerCombobox
743
+ },
744
+ data () {
745
+ // 检索去抖
746
+ this.fetchFunction = debounce(this.fetchFunction, 800)
747
+ // 初始化selectValueType处理器
748
+ this.selectValueTypeHandler = createSelectValueTypeHandler(this)
749
+ return {
750
+ option: [],
751
+ // 最后检索版本
752
+ lastFetchId: 0,
753
+ // 检索中
754
+ searching: false,
755
+ searchResult: '',
756
+ optionForFunc: [],
757
+ // 控制当前表单项是否展示
758
+ show: true,
759
+ // moment
760
+ moment,
761
+ // 行选择器浮层是否显示
762
+ rowChoosePopoverVisible: false,
763
+ // 行选择器CRUD固定查询值
764
+ rowChooseFixedQueryValue: undefined,
765
+ bindOther: {}
766
+ }
767
+ },
768
+ props: {
769
+ attr: {
770
+ type: Object,
771
+ default:
772
+ () => {
773
+ return {}
774
+ }
775
+ },
776
+ form: {
777
+ type: Object,
778
+ required:
779
+ true
780
+ },
781
+ disabled: {
782
+ type: Boolean,
783
+ default:
784
+ () => {
785
+ return false
786
+ }
787
+ },
788
+ readOnly: {
789
+ type: Boolean,
790
+ default:
791
+ () => {
792
+ return false
793
+ }
794
+ },
795
+ mode: {
796
+ type: String,
797
+ default:
798
+ () => {
799
+ return '查询'
800
+ }
801
+ },
802
+ files: {
803
+ type: Array,
804
+ default:
805
+ () => {
806
+ return []
807
+ }
808
+ },
809
+ images: {
810
+ type: Array,
811
+ default:
812
+ () => {
813
+ return []
814
+ }
815
+ },
816
+ serviceName: {
817
+ type: String,
818
+ default:
819
+ undefined
820
+ },
821
+ // 调用logic获取数据源的追加参数
822
+ getDataParams: {
823
+ type: Object,
824
+ default:
825
+ undefined
826
+ },
827
+ // 布局
828
+ layout: {
829
+ type: String,
830
+ default:
831
+ 'horizontal'
832
+ },
833
+ // 环境
834
+ env: {
835
+ type: String,
836
+ default:
837
+ () => {
838
+ return 'prod'
839
+ }
840
+ },
841
+ // 设置表单值
842
+ setForm: {
843
+ type: Function,
844
+ default: (val) => {
845
+ console.log(val)
846
+ }
847
+ },
848
+ showLabel: {
849
+ type: Boolean,
850
+ default:
851
+ () => {
852
+ return true
853
+ }
854
+ },
855
+ labelCol: {
856
+ type: Object,
857
+ default: () => {
858
+ return { span: 8 }
859
+ }
860
+ },
861
+ rules: {
862
+ type: Array,
863
+ default:
864
+ () => {
865
+ return undefined
866
+ }
867
+ }
868
+ },
869
+ provide () {
870
+ return {
871
+ FormItemContext: this
872
+ }
873
+ },
874
+ created () {
875
+ this.init()
876
+ if (this.attr.keyName && (this.attr?.keyName?.toString().indexOf('async ') !== -1 || this.attr?.keyName?.toString()?.indexOf('function') !== -1)) {
877
+ this.debouncedUpdateOptions = debounce(this.updateOptions, 200)
878
+ }
879
+ if (this.attr.dataChangeFunc) {
880
+ this.debouncedDataChangeFunc = debounce(this.dataChangeFunc, 200)
881
+ // 执行一次
882
+ this.dataChangeFunc()
883
+ }
884
+ if (this.attr.showFormItemFunc) {
885
+ this.debouncedShowFormItemFunc = debounce(this.showFormItemFunc, 100)
886
+ // 执行一次
887
+ this.showFormItemFunc()
888
+ }
889
+ if (this.attr.showQueryFormItemFunc) {
890
+ this.debouncedShowQueryFormItemFunc = debounce(this.showQueryFormItemFunc, 100)
891
+ // 执行一次
892
+ this.showQueryFormItemFunc()
893
+ }
894
+ // 人员联动框增加监听
895
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
896
+ this.debouncedUserLinkFunc = debounce(() => this.updateResOptions('人员'), 200)
897
+ }
898
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
899
+ this.debouncedDepLinkFunc = debounce(() => this.updateResOptions('部门'), 200)
900
+ }
901
+ // xTreeSelect 自己调用 mounted
902
+ if (this.attr.type !== 'treeSelect') {
903
+ this.$emit('mounted', this.attr)
904
+ }
905
+ },
906
+ computed: {
907
+ ...mapState('account', { currUser: 'user', curRoles: 'roles', curPermissions: 'permissions' }),
908
+ queryParamsName () {
909
+ if (this.attr.keyName.startsWith('function')) {
910
+ // 调用异步函数获取内容
911
+ const obj = executeStrFunctionByContext(this, this.attr.keyName, [this.form, runLogic, this.mode, getConfigByNameAsync])
912
+ // 处理同步返回值
913
+ return this.handleQueryParamsResult(obj)
914
+ } else if (this.attr.keyName.startsWith('async ')) {
915
+ console.warn('此处不支持异步操作')
916
+ return ''
917
+ } else {
918
+ // 按现有方式处理
919
+ return this.attr.keyName.split('@')[this.attr.keyName.split('@').length - 1]
920
+ }
921
+ },
922
+ // 判断弹出时是否Cover,弹出只支持Cover以及CRUD
923
+ isCover () {
924
+ // 如果 queryParamsName 为空,返回空
925
+ if (!this.queryParamsName) {
926
+ return false
927
+ }
928
+ const result = this.queryParamsName.endsWith('Cover')
929
+ return result
930
+ },
931
+ },
932
+ watch: {
933
+ attr: {
934
+ handler () {
935
+ this.init()
936
+ },
937
+ deep: true
938
+ },
939
+ form: {
940
+ handler (newVal, oldVal) {
941
+ // 如果是从函数获取 options
942
+ if (this.attr.keyName && (this.attr.keyName.toString().indexOf('async ') !== -1 || this.attr.keyName.toString().indexOf('function') !== -1)) {
943
+ this.debouncedUpdateOptions()
944
+ }
945
+ // 如果有自定义是否展示表单项函数
946
+ if (this.attr.showFormItemFunc) {
947
+ this.debouncedShowFormItemFunc()
948
+ }
949
+ // 如果有自定义是否展示查询表单项函数
950
+ if (this.attr.showQueryFormItemFunc) {
951
+ this.debouncedShowQueryFormItemFunc()
952
+ }
953
+ // 地址搜索框赋值
954
+ if (this.attr.type === 'addressSearch' || this.attr.type === 'coordinateSearch') {
955
+ this.$refs.addressSearchCombobox.addressInput = this.form[this.attr.model]
956
+ }
957
+ // 数据源来自人员联动时更新数据
958
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
959
+ this.debouncedUserLinkFunc()
960
+ }
961
+ // 数据源来自人员联动时更新数据
962
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
963
+ this.debouncedDepLinkFunc()
964
+ }
965
+ },
966
+ deep: true
967
+ }
968
+ },
969
+ inject: {
970
+ getComponentByName: {
971
+ default: () => () => {
972
+ console.warn('getComponentByName is not provided')
973
+ return null // 或者返回一个默认的函数
974
+ },
975
+ },
976
+ registerComponent: {
977
+ default: () => () => {
978
+ console.warn('registerComponent is not provided')
979
+ return null // 或者返回一个默认的函数
980
+ },
981
+ },
982
+ getSelf: {
983
+ default: () => () => {
984
+ console.warn('getSelf is not provided')
985
+ return null // 或者返回一个默认的函数
986
+ },
987
+ },
988
+ XFormContext: {
989
+ default: () => () => {
990
+ console.warn('XFormContext is not provided')
991
+ return null // 或者返回一个默认的函数
992
+ },
993
+ },
994
+ setRequired: {
995
+ default: () => () => {
996
+ console.warn('setRequired is not provided')
997
+ return null // 或者返回一个默认的函数
998
+ },
999
+ },
1000
+ removeRequired: {
1001
+ default: () => () => {
1002
+ console.warn('removeRequired is not provided')
1003
+ return null // 或者返回一个默认的函数
1004
+ },
1005
+ }
1006
+ },
1007
+ methods: {
1008
+ // 处理 queryParams 结果并更新 rowChooseFixedQueryValue
1009
+ handleQueryParamsResult (obj) {
1010
+ let configName = ''
1011
+ if (obj && typeof obj === 'object') {
1012
+ // obj 是一个对象,并且不是数组
1013
+ if (Object.prototype.hasOwnProperty.call(obj, 'configName')) {
1014
+ configName = obj?.configName
1015
+ }
1016
+ if (Object.prototype.hasOwnProperty.call(obj, 'fixedQueryForm')) {
1017
+ if (obj?.fixedQueryForm && typeof obj?.fixedQueryForm === 'object') {
1018
+ this.rowChooseFixedQueryValue = Object.assign({}, this.rowChooseFixedQueryValue, obj.fixedQueryForm)
1019
+ }
1020
+ }
1021
+ } else if (obj && typeof obj === 'string') {
1022
+ configName = obj
1023
+ }
1024
+ return configName
1025
+ },
1026
+ // 根据selectValueType预处理options数据
1027
+ processOptionsForValueType (options) {
1028
+ return this.selectValueTypeHandler.processOptions(options, this.attr.selectValueType)
1029
+ },
1030
+
1031
+ // 处理both模式的数据,为表单添加label字段
1032
+ processBothModeData () {
1033
+ this.selectValueTypeHandler.processBothMode(
1034
+ this.form,
1035
+ this.attr.model,
1036
+ this.attr.selectValueType,
1037
+ this.option
1038
+ )
1039
+ },
1040
+
1041
+ // 根据value查找对应的label(支持单选和多选)
1042
+ findLabelByValue (value) {
1043
+ return this.selectValueTypeHandler.findLabel(value, this.option)
1044
+ },
1045
+
1046
+ // 统一的表单项change处理逻辑
1047
+ handleFormItemChange () {
1048
+ // 处理both模式
1049
+ if (this.attr.selectValueType === 'both') {
1050
+ this.$nextTick(() => {
1051
+ this.selectValueTypeHandler.processBothMode(
1052
+ this.form,
1053
+ this.attr.model,
1054
+ this.form[this.attr.model],
1055
+ this.option
1056
+ )
1057
+ })
1058
+ }
1059
+ // 处理label模式
1060
+ if (this.attr.selectValueType === 'label') {
1061
+ this.$nextTick(() => {
1062
+ this.selectValueTypeHandler.processLabelMode(
1063
+ this.form,
1064
+ this.attr.model,
1065
+ this.form[this.attr.model],
1066
+ this.option
1067
+ )
1068
+ })
1069
+ }
1070
+ // 处理原有的dataChangeFunc
1071
+ if (this.attr.dataChangeFunc) {
1072
+ this.debouncedDataChangeFunc()
1073
+ }
1074
+ },
1075
+
1076
+ // Select组件change处理
1077
+ handleSelectChange () {
1078
+ this.handleFormItemChange()
1079
+ },
1080
+
1081
+ // Checkbox组件change处理
1082
+ handleCheckboxChange () {
1083
+ this.handleFormItemChange()
1084
+ },
1085
+
1086
+ // Radio组件change处理
1087
+ handleRadioChange () {
1088
+ this.handleFormItemChange()
1089
+ },
1090
+
1091
+ // TreeSelect组件change处理(通过XTreeSelect组件回调)
1092
+ handleTreeSelectChange () {
1093
+ this.handleFormItemChange()
1094
+ },
1095
+
1096
+ // 把内部的crud表单录入放到表单中,以便外部可以调用
1097
+ onComponentMounted (h, attr) {
1098
+ console.log('crud表单', h)
1099
+ if (attr.crud) {
1100
+ this.registerComponent(attr.model, this.$refs['childXFormTable_' + attr.model])
1101
+ }
1102
+ },
1103
+ childTableFixedQueryForm (item) {
1104
+ console.log('传递的form', this.form)
1105
+ if (this.modifyModelData?.primaryKeyData) {
1106
+ const fixedForm = {}
1107
+ fixedForm[item.childTableForeignKeyName] = Object.values(this.modifyModelData.primaryKeyData)[0]
1108
+ return fixedForm
1109
+ }
1110
+ return null
1111
+ },
1112
+ // 动态生成事件绑定对象
1113
+ generateDynamicEvents (inputOnAfterFunc, attr) {
1114
+ const events = {}
1115
+ const states = this.parseStates(attr.inputOnAfterName, inputOnAfterFunc)
1116
+
1117
+ states.forEach((state) => {
1118
+ // 动态绑定事件名到 emitFunc
1119
+ events[state.event] = () => {
1120
+ console.info('事件名', state.event)
1121
+ this.emitFunc(state.event, attr)
1122
+ }
1123
+ })
1124
+
1125
+ return events // 返回 { state1Event: handler, state2Event: handler, ... }
1126
+ },
1127
+ parseStates (input, events) {
1128
+ const eventNames = events.split('|')
1129
+ return input.split('|').map((label, index) => ({
1130
+ label,
1131
+ event: eventNames[index] // 如果没有提供事件名称,则使用默认值
1132
+ }))
1133
+ },
1134
+ focusInput () {
1135
+ if (this.attr.defaultFocus) {
1136
+ this.$nextTick(h => {
1137
+ const el = this.$refs[`${this.attr.model}input`]?.$el
1138
+ let inputEl
1139
+ if (el) {
1140
+ if (el.tagName.toLowerCase() === 'input') {
1141
+ inputEl = el
1142
+ } else {
1143
+ inputEl = el.querySelector('input')
1144
+ }
1145
+ }
1146
+ if (inputEl) {
1147
+ inputEl.focus()
1148
+ if (inputEl.type === 'number') {
1149
+ if (inputEl.valueAsNumber) {
1150
+ inputEl.setSelectionRange(0, inputEl.valueAsNumber.toString().length)
1151
+ }
1152
+ } else {
1153
+ if (inputEl.value) {
1154
+ inputEl.setSelectionRange(0, inputEl.value.length)
1155
+ }
1156
+ }
1157
+ }
1158
+ })
1159
+ }
1160
+ },
1161
+ // 更新人员下拉框数据
1162
+ async updateResOptions (type) {
1163
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString()?.endsWith(`]联动${type}`)) {
1164
+ const startIndex = this.attr.keyName.indexOf('[') + 1
1165
+ const endIndex = this.attr.keyName.indexOf(']', startIndex)
1166
+ const fromModel = this.attr.keyName.substring(startIndex, endIndex).replace('.', '_')
1167
+ // 获取表单字段的实际值(优先使用originData中的原始值)
1168
+ const rawFieldValue = this.form.originData && this.form.originData[fromModel]
1169
+ ? this.form.originData[fromModel]
1170
+ : this.form[fromModel]
1171
+
1172
+ // 确保数据为数组格式(用于filter参数)
1173
+ const filterValues = Array.isArray(rawFieldValue)
1174
+ ? rawFieldValue
1175
+ : [rawFieldValue]
1176
+ if (fromModel?.length && filterValues?.length) {
1177
+ const searchData = {
1178
+ source: `获取${type}`,
1179
+ userid: this.currUser.id,
1180
+ filter: filterValues,
1181
+ filterType: fromModel.indexOf('org') > -1 ? 'org' : 'dep'
1182
+ }
1183
+ const tempArray = []
1184
+ await searchToListOption(searchData, res => {
1185
+ this.getDataCallback(
1186
+ res.filter(h => {
1187
+ if (fromModel.indexOf('org') > -1) {
1188
+ if (type === '部门') {
1189
+ if (filterValues?.includes(h.orgid || h.f_organization_id) || filterValues?.includes(h.parentid) || tempArray.includes(h.parentid)) {
1190
+ tempArray.push(h.value)
1191
+ return true
1192
+ }
1193
+ return false
1194
+ } else {
1195
+ return filterValues?.includes(h.orgid || h.f_organization_id || h.parentid)
1196
+ }
1197
+ } else {
1198
+ return filterValues?.includes(h?.parentid)
1199
+ }
1200
+ }
1201
+ )
1202
+ )
1203
+ })
1204
+ }
1205
+ }
1206
+ },
1207
+ // js 函数作为数据源
1208
+ async updateOptions () {
1209
+ if (this.attr.keyName && (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1)) {
1210
+ const rawOptions = await executeStrFunctionByContext(this, this.attr.keyName, [this.form, runLogic, this.mode, getConfigByNameAsync, post])
1211
+ // 根据selectValueType预处理options数据
1212
+ this.optionForFunc = this.processOptionsForValueType(rawOptions)
1213
+ }
1214
+ },
1215
+ async dataChangeFunc () {
1216
+ if (this.attr.dataChangeFunc) {
1217
+ await executeStrFunctionByContext(this, this.attr.dataChangeFunc, [this.form, this.setForm, this.attr, util, this.mode, runLogic, getConfigByNameAsync])
1218
+ }
1219
+ },
1220
+ async showFormItemFunc () {
1221
+ if (this.attr.showFormItemFunc) {
1222
+ const obj = executeStrFunctionByContext(this, this.attr.showFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode, this.curPermissions, this.curRoles])
1223
+ // 判断是 bool 还是 obj 兼容
1224
+ if (typeof obj === 'boolean') {
1225
+ this.show = obj
1226
+ } else if (obj && typeof obj === 'object') {
1227
+ // obj 是一个对象,并且不是数组
1228
+ if (Object.prototype.hasOwnProperty.call(obj, 'show')) {
1229
+ this.show = obj?.show
1230
+ }
1231
+ if (Object.prototype.hasOwnProperty.call(obj, 'readOnly')) {
1232
+ this.readOnly = obj?.readOnly
1233
+ }
1234
+ if (Object.prototype.hasOwnProperty.call(obj, 'disabled')) {
1235
+ this.disabled = obj?.disabled
1236
+ }
1237
+ }
1238
+ } else {
1239
+ this.show = true
1240
+ }
1241
+ },
1242
+ async showQueryFormItemFunc () {
1243
+ if (this.attr.showQueryFormItemFunc) {
1244
+ const obj = executeStrFunctionByContext(this, this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode, this.curPermissions, this.curRoles])
1245
+ // 判断是 bool 还是 obj 兼容
1246
+ if (typeof obj === 'boolean') {
1247
+ this.show = obj
1248
+ } else if (obj && typeof obj === 'object') {
1249
+ // obj 是一个对象,并且不是数组
1250
+ if (Object.prototype.hasOwnProperty.call(obj, 'show')) {
1251
+ this.show = obj?.show
1252
+ }
1253
+ if (Object.prototype.hasOwnProperty.call(obj, 'readOnly')) {
1254
+ this.readOnly = obj?.readOnly
1255
+ }
1256
+ if (Object.prototype.hasOwnProperty.call(obj, 'disabled')) {
1257
+ this.disabled = obj?.disabled
1258
+ }
1259
+ }
1260
+ } else {
1261
+ this.show = true
1262
+ }
1263
+ },
1264
+ init () {
1265
+ if (!this.attr.flex) {
1266
+ if (this.mode === '新增/修改') {
1267
+ if (['horizontal', 'vertical'].includes(this.layout) || ['textarea', 'file', 'image'].includes(this.attr.type)) {
1268
+ // 新增修改表单 horizontal 模式下默认为一行
1269
+ this.attr.flex = {
1270
+ xs: 24,
1271
+ sm: 24,
1272
+ md: 24,
1273
+ lg: 24,
1274
+ xl: 24,
1275
+ xxl: 24,
1276
+ fullWidth: true
1277
+ }
1278
+ } else {
1279
+ // 新增修改表单 vertical 模式下默认为1列
1280
+ this.attr.flex = {
1281
+ xs: 24,
1282
+ sm: 12,
1283
+ md: 8,
1284
+ lg: 8,
1285
+ xl: 6,
1286
+ xxl: 6
1287
+ }
1288
+ }
1289
+ } else {
1290
+ this.attr.flex = {
1291
+ xs: 24,
1292
+ sm: 24,
1293
+ md: 8,
1294
+ lg: 6,
1295
+ xl: 6,
1296
+ xxl: 6
1297
+ }
1298
+ }
1299
+ }
1300
+ if (this.attr.keyName && typeof this.attr.keyName === 'string') {
1301
+ if (this.attr.keyName.indexOf('logic@') !== -1) {
1302
+ this.getData({}, res => this.getDataCallback(res))
1303
+ } else if (this.attr.keyName.indexOf('search@') !== -1) {
1304
+ // `tool.getFullTree(this.getRights().where(row.getType()==$organization$))`
1305
+ // 判断是否根据角色查询
1306
+ let source = this.attr.keyName.substring(7)
1307
+ const userid = this.currUser.id
1308
+ let roleName = 'roleName'
1309
+ if (source.startsWith('根据角色[') && source.endsWith(']获取人员')) {
1310
+ const startIndex = source.indexOf('[') + 1
1311
+ const endIndex = source.indexOf(']', startIndex)
1312
+ roleName = source.substring(startIndex, endIndex)
1313
+ source = '根据角色获取人员'
1314
+ }
1315
+ const searchData = { source, userid, roleName }
1316
+ // 判断是否根据某个表单项联动 仅返回列表结构并筛选
1317
+ if (source.startsWith('根据表单项[') && source.endsWith(']联动人员')) {
1318
+ this.updateResOptions('人员')
1319
+ } else if (source.startsWith('根据表单项[') && source.endsWith(']联动部门')) {
1320
+ this.updateResOptions('部门')
1321
+ } else if (this.attr.type === 'select' || this.attr.type === 'checkbox') {
1322
+ // 仅获取最内层数据
1323
+ searchToListOption(searchData, res => this.getDataCallback(res))
1324
+ } else {
1325
+ // 其他资源通用逻辑
1326
+ searchToOption(searchData, res => this.getDataCallback(res))
1327
+ }
1328
+ } else if (this.attr.keyName.indexOf('config@') !== -1) {
1329
+ const configName = this.attr.keyName.substring(7)
1330
+ getConfigByName(configName, this.serviceName, res => {
1331
+ this.getDataCallback(res.value)
1332
+ }, this.env === 'dev')
1333
+ } else if (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1) {
1334
+ this.updateOptions()
1335
+ }
1336
+ } else if (this.attr.keys) {
1337
+ // 对静态配置的keys也进行预处理
1338
+ this.getDataCallback(this.attr.keys)
1339
+ }
1340
+ this.focusInput()
1341
+ },
1342
+ addressSearchComboboxSelect (data) {
1343
+ this.form = Object.assign(this.form, JSON.parse(data))
1344
+ },
1345
+ onDivisionsChange (data) {
1346
+ this.emitFunc('addressSearchComboboxSelect', {
1347
+ key: this.attr.model,
1348
+ value: data
1349
+ })
1350
+ },
1351
+ getDataCallback (res) {
1352
+ // 根据selectValueType预处理options数据
1353
+ this.option = this.processOptionsForValueType(res)
1354
+
1355
+ if (this.attr.type === 'treeSelect') {
1356
+ this.$nextTick(() => {
1357
+ this.$refs.xTreeSelect.init({
1358
+ option: this.option,
1359
+ form: this.form,
1360
+ queryType: this.attr.queryType,
1361
+ name: this.attr.name,
1362
+ model: this.attr.model,
1363
+ mode: this.mode,
1364
+ disabled: this.disabled
1365
+ })
1366
+ })
1367
+ } else if (this.attr.type === 'radio' || ['radioGroup', 'clickChange'].includes(this.attr.showMode)) {
1368
+ this.initRadioValue()
1369
+ }
1370
+ },
1371
+ initRadioValue () {
1372
+ const model = this.attr.model
1373
+ if (this.mode === '新增/修改' && (this.form[model] === undefined || this.form[model] === null) && !this.attr.prop) {
1374
+ if (this.attr.keys && this.attr.keys.length > 1) {
1375
+ this.form[model] = this.attr.keys[0].value
1376
+ } else if (this.option.length > 1) {
1377
+ this.form[model] = this.option[0].value
1378
+ }
1379
+ }
1380
+ },
1381
+ // 文件框时设置上传组件的值
1382
+ setFiles (fileIds) {
1383
+ if (!this.form[this.attr.model]) {
1384
+ this.form[this.attr.model] = []
1385
+ }
1386
+ this.form[this.attr.model] = [...fileIds]
1387
+ },
1388
+ // 懒加载检索方法
1389
+ fetchFunction (value) {
1390
+ this.lastFetchId += 1
1391
+ const fetchId = this.lastFetchId
1392
+ this.option = []
1393
+ this.searching = true
1394
+ this.getData({
1395
+ word: value
1396
+ }, res => {
1397
+ if (fetchId !== this.lastFetchId) {
1398
+ return
1399
+ }
1400
+ this.option = res
1401
+ this.searching = false
1402
+ })
1403
+ },
1404
+ // 获取数据
1405
+ getData (value, callbackFun) {
1406
+ if (value !== '') {
1407
+ const logicName = this.attr.keyName
1408
+ const logic = logicName.substring(6)
1409
+ // 调用logic前设置参数
1410
+ if (this.getDataParams && this.getDataParams[this.attr.model]) {
1411
+ Object.assign(value, this.getDataParams[this.attr.model])
1412
+ }
1413
+ runLogic(logic, Object.assign(value, {
1414
+ orgId: this.currUser.orgid,
1415
+ userId: this.currUser.id
1416
+ }), this.serviceName, this.env === 'dev').then(res => {
1417
+ callbackFun(res)
1418
+ }).catch(e => {
1419
+ callbackFun([])
1420
+ console.error('获取数据失败:' + e)
1421
+ })
1422
+ }
1423
+ },
1424
+ filterOption (input, option) {
1425
+ const child = option.componentOptions.children[0]
1426
+ if (child.text) {
1427
+ return child.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
1428
+ } else if (child.elm.innerText) {
1429
+ return child.elm.innerText.toLowerCase().indexOf(input.toLowerCase()) >= 0
1430
+ } else {
1431
+ return child.child.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
1432
+ }
1433
+ },
1434
+ // 表单项变更函数中调用 控制表单组中表单项组名为 groupName 的表单是否展示
1435
+ // func:x-form-show(显示)/x-form-no-show(不显示)
1436
+ emitShowFormFunc (func, groupName) {
1437
+ this.emitFunc(func, groupName)
1438
+ },
1439
+ emitFunc (func, data) {
1440
+ this.$emit('x-form-item-emit-func', func, data, data?.model ? this.form[data.model] : this.form)
1441
+ },
1442
+ itemMounted (h) {
1443
+ this.$emit('mounted', h)
1444
+ },
1445
+ rowChoose (rows) {
1446
+ this.$emit('rowChoose', rows, this.attr, this.closeRowChooseInput)
1447
+ },
1448
+ searchRowChooseData () {
1449
+ if (this.searching) {
1450
+ return
1451
+ }
1452
+ this.lastFetchId += 1
1453
+ const fetchId = this.lastFetchId
1454
+ this.searching = true
1455
+ if (fetchId !== this.lastFetchId) {
1456
+ return
1457
+ }
1458
+ this.rowChooseFixedQueryValue = []
1459
+ this.rowChooseFixedQueryValue[this.attr.model] = this.form[this.attr.model]
1460
+ this.$nextTick(() => {
1461
+ this.$refs.rowChooseTable.refresh(true)
1462
+ })
1463
+ },
1464
+ showCloseRowChooseInput () {
1465
+ this.rowChoosePopoverVisible = true
1466
+ },
1467
+ closeRowChooseInput () {
1468
+ this.rowChoosePopoverVisible = false
1469
+ },
1470
+ rowChooseSearchAfterQuery () {
1471
+ this.searching = false
1472
+ },
1473
+ // 获取 recording 转换后的数据
1474
+ getRecodingData () {
1475
+ return this.$refs.recording.getRecordingData()
1476
+ },
1477
+ recordingData (data) {
1478
+ this.emitFunc('recordingData', data)
1479
+ },
1480
+ getPopupContainer (triggerNode) {
1481
+ // return document.body
1482
+ return triggerNode.parentNode
1483
+ },
1484
+ colorPickerComboboxSelect (val) {
1485
+ this.form[this.attr.model] = val
1486
+ },
1487
+ }
1488
+ }
1489
+ </script>
1490
+
1491
+ <style lang="less" scoped>
1492
+ .custom-dropdown {
1493
+ position: absolute;
1494
+ z-index: 1050;
1495
+ }
1496
+
1497
+ .multiple_select {
1498
+ :deep(.ant-select-selection) {
1499
+ max-height: 32px;
1500
+ overflow-y: scroll;
1501
+ }
1502
+ }
1503
+
1504
+ </style>