vue2-client 1.8.413 → 1.8.415

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,1058 +1,1061 @@
1
- <template>
2
- <!-- 输入框 -->
3
- <x-form-col
4
- v-if="attr.type === 'input' && show"
5
- :flex="attr.flex">
6
- <a-form-model-item
7
- :ref="attr.model"
8
- :label="attr.name"
9
- :labelCol="layout === 'inline' && attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].labelCol:undefined"
10
- :wrapperCol="layout === 'inline'&& attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].wrapperCol:undefined"
11
- :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
12
- :prop="attr.prop ? attr.prop : attr.model">
13
- <!-- 如果配置了后置按钮插槽 -->
14
- <a-input-group
15
- v-if="(attr.inputOnAfterName && attr.inputOnAfterFunc) || (attr.inputOnAfterIcon && attr.inputOnAfterIconFunc)"
16
- style="display: flex; width: 100%;"
17
- compact>
18
- <a-input
19
- v-model="form[attr.model]"
20
- :read-only="readOnly"
21
- :disabled="disabled && !readOnly"
22
- :whitespace="true"
23
- style="flex: 1; width: auto; min-width: 0;"
24
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
25
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
26
- :ref="`${attr.model}input`"/>
27
- <a-button
28
- v-if="attr.inputOnAfterName && attr.inputOnAfterFunc"
29
- style="flex: 1; width: auto; min-width: 4rem;max-width: 6rem"
30
- type="primary"
31
- @click="emitFunc(attr.inputOnAfterFunc,form[attr.model])">
32
- {{ attr.inputOnAfterName }}
33
- </a-button>
34
- <!-- 仅可以配置 一个按钮 以及 一个图标插槽 -->
35
- <a-button
36
- style="width: 2rem; flex-shrink: 0;"
37
- v-if="attr.inputOnAfterIcon"
38
- :type="attr.inputOnAfterIcon && attr.inputOnAfterName ? 'primary' :''"
39
- :icon="attr.inputOnAfterIcon || 'question'"
40
- @click="emitFunc(attr.inputOnAfterIconFunc,form[attr.model])">
41
- </a-button>
42
- </a-input-group>
43
- <a-input-number
44
- v-else-if="attr.numberInput && !readOnly"
45
- v-model="form[attr.model]"
46
- :whitespace="true"
47
- :disabled="disabled && !readOnly"
48
- style="width:100%"
49
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
50
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
51
- :ref="`${attr.model}input`"/>
52
- <a-input
53
- v-else
54
- v-model="form[attr.model]"
55
- :whitespace="true"
56
- :read-only="readOnly"
57
- :disabled="disabled && !readOnly"
58
- style="width:100%"
59
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
60
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
61
- :ref="`${attr.model}input`"/>
62
-
63
- </a-form-model-item>
64
- </x-form-col>
65
- <!-- 下拉框 -->
66
- <x-form-col
67
- v-else-if="(attr.type === 'select' || (attr.type === 'rate' && mode==='查询')) && show"
68
- :flex="attr.flex">
69
- <a-form-model-item
70
- :ref="attr.model"
71
- :label="attr.name"
72
- :prop="attr.prop ? attr.prop : attr.model">
73
- <a-select
74
- v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
75
- v-model="form[attr.model]"
76
- :disabled="disabled"
77
- :filter-option="filterOption"
78
- :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
79
- :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
80
- show-search
81
- >
82
- <a-select-option
83
- v-if="mode === '查询'"
84
- key="999999"
85
- value="">全部
86
- </a-select-option>
87
- <template v-if="attr.keys">
88
- <a-select-option
89
- v-for="(item,index) in attr.keys"
90
- :key="index.value"
91
- :value="item.value">
92
- {{ item.label }}
93
- </a-select-option>
94
- </template>
95
- <template v-else>
96
- <template
97
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
98
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
99
- <a-select-option
100
- v-for="(item,index) in option"
101
- :key="index.value"
102
- :value="item.value">
103
- <template v-if="attr.keyName.indexOf('config@') !== -1 && item.status">
104
- <!-- 徽标(badge) -->
105
- <a-badge v-if="item.status !== 'gary'" :color="item.status" :text="item.label"/>
106
- <a-badge v-else color="#D9D9D9" :text="item.label"/>
107
- </template>
108
- <template v-else>
109
- {{ item.label }}
110
- </template>
111
- </a-select-option>
112
- </template>
113
- <template
114
- v-else-if="attr.keyName.indexOf('async ') !== -1 || attr.keyName.indexOf('function ') !== -1">
115
- <a-select-option
116
- v-for="(item,index) in optionForFunc"
117
- :key="index.value"
118
- :value="item.value">
119
- <template>
120
- {{ item.label }}
121
- </template>
122
- </a-select-option>
123
- </template>
124
- <template v-else>
125
- <a-select-option
126
- v-for="item in $appdata.getDictionaryList(attr.keyName)"
127
- :key="item.value"
128
- :value="item.value">
129
- <!-- 徽标(badge) -->
130
- <x-badge :badge-key="attr.keyName" :replaceText="item.text" :value="item.value"/>
131
- </a-select-option>
132
- </template>
133
- </template>
134
- </a-select>
135
- <a-select
136
- v-else
137
- v-model="form[attr.model]"
138
- :disabled="disabled"
139
- :filter-option="filterOption"
140
- :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
141
- :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
142
- show-search
143
- @search="fetchFunction"
144
- >
145
- <a-spin v-if="searching" slot="notFoundContent" size="small"/>
146
- <a-select-option
147
- v-if="mode === '查询'"
148
- key="999999"
149
- value="">全部
150
- </a-select-option>
151
- <a-select-option
152
- v-for="(item,index) in option"
153
- :key="index"
154
- :value="item.value">{{ item.label }}
155
- </a-select-option>
156
- </a-select>
157
- </a-form-model-item>
158
- </x-form-col>
159
- <!-- 多选框 -->
160
- <x-form-col
161
- v-else-if="attr.type === 'checkbox' && show"
162
- :flex="attr.flex">
163
- <a-form-model-item
164
- :ref="attr.model"
165
- :label="attr.name"
166
- :prop="attr.prop ? attr.prop : attr.model">
167
- <a-select
168
- v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
169
- v-model="form[attr.model]"
170
- :disabled="disabled"
171
- :filter-option="filterOption"
172
- :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
173
- :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
174
- mode="multiple"
175
- show-search
176
- allowClear
177
- >
178
- <template v-if="attr.keys">
179
- <a-select-option
180
- v-for="(item,index) in attr.keys"
181
- :key="index"
182
- :value="item.value">
183
- {{ item.label }}
184
- </a-select-option>
185
- </template>
186
- <template v-else>
187
- <template
188
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
189
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
190
- <a-select-option
191
- v-for="(item,index) in option"
192
- :key="index"
193
- :value="item.value">{{ item.label }}
194
- </a-select-option>
195
- </template>
196
- <template v-else>
197
- <a-select-option
198
- v-for="item in $appdata.getDictionaryList(attr.keyName)"
199
- :key="item.value"
200
- :value="item.value">{{ item.text }}
201
- </a-select-option>
202
- </template>
203
- </template>
204
- </a-select>
205
- <a-select
206
- v-else
207
- v-model="form[attr.model]"
208
- :disabled="disabled"
209
- :filter-option="filterOption"
210
- :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
211
- :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
212
- mode="multiple"
213
- show-search
214
- allowClear
215
- @search="fetchFunction"
216
- >
217
- <a-spin v-if="searching" slot="notFoundContent" size="small"/>
218
- <a-select-option
219
- v-for="(item,index) in option"
220
- :key="index"
221
- :value="item.value">{{ item.label }}
222
- </a-select-option>
223
- </a-select>
224
- </a-form-model-item>
225
- </x-form-col>
226
- <!-- 单选框 -->
227
- <x-form-col
228
- v-else-if="attr.type === 'radio' && show"
229
- :flex="attr.flex">
230
- <a-form-model-item
231
- :ref="attr.model"
232
- :label="attr.name"
233
- :prop="attr.prop ? attr.prop : attr.model">
234
- <a-radio-group v-model="form[attr.model]">
235
- <template v-if="attr.keys">
236
- <a-radio v-for="(item,index) in attr.keys" :key="index" :value="item.value">
237
- {{ item.label }}
238
- </a-radio>
239
- </template>
240
- <template v-else>
241
- <template
242
- v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
243
- ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
244
- <a-radio v-for="(item,index) in option" :key="index" :value="item.value">
245
- {{ item.label }}
246
- </a-radio>
247
- </template>
248
- <template v-else>
249
- <a-radio v-for="(item,index) in $appdata.getDictionaryList(attr.keyName)" :key="index" :value="item.value">
250
- {{ item.text }}
251
- </a-radio>
252
- </template>
253
- </template>
254
- </a-radio-group>
255
- </a-form-model-item>
256
- </x-form-col>
257
- <!-- 日期范围选择器 -->
258
- <x-form-col
259
- v-else-if="attr.type === 'rangePicker' && show"
260
- :flex="attr.flex">
261
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
262
- <a-date-picker
263
- v-if="mode === '新增/修改'"
264
- v-model="form[attr.model]"
265
- :disabled="disabled"
266
- :show-time="true"
267
- style="width: 100%;"
268
- valueFormat="YYYY-MM-DD HH:mm:ss"/>
269
- <a-range-picker
270
- v-else
271
- v-model="form[attr.model]"
272
- :disabled="disabled"
273
- :show-time="true"
274
- valueFormat="YYYY-MM-DD HH:mm:ss"
275
- style="width: 100%;"
276
- />
277
- </a-form-model-item>
278
- </x-form-col>
279
- <!-- 月份选择器 -->
280
- <x-form-col
281
- v-else-if="attr.type === 'monthPicker' && show"
282
- :flex="attr.flex">
283
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
284
- <a-month-picker
285
- v-model="form[attr.model]"
286
- :disabled="disabled"
287
- :show-time="true"
288
- valueFormat="YYYY-MM"
289
- style="width: 100%;"
290
- />
291
- </a-form-model-item>
292
- </x-form-col>
293
- <!-- 年份选择器 -->
294
- <x-form-col
295
- v-else-if="attr.type === 'yearPicker' && show"
296
- :flex="attr.flex">
297
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
298
- <a-date-picker
299
- v-model="form[attr.model]"
300
- :disabled="disabled"
301
- format="YYYY"
302
- mode="year"
303
- v-decorator="['year']"
304
- placeholder="请选择年份"
305
- :open="yearShowOne"
306
- style="width: 100%;"
307
- @openChange="openChangeOne"
308
- @panelChange="panelChangeOne"/>
309
- </a-form-model-item>
310
- </x-form-col>
311
- <!-- 单日选择器 -->
312
- <x-form-col
313
- v-else-if="attr.type === 'datePicker' && show"
314
- :flex="attr.flex">
315
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
316
- <a-range-picker
317
- v-if="mode === '查询' && attr.queryType === 'BETWEEN' "
318
- v-model="form[attr.model]"
319
- :disabled="disabled"
320
- :show-time="true"
321
- style="width: 100%;"
322
- format="YYYY-MM-DD"
323
- valueFormat="YYYY-MM-DD HH:mm:ss"/>
324
- <a-date-picker
325
- v-else-if="mode === '查询'"
326
- v-model="form[attr.model]"
327
- :disabled="disabled"
328
- style="width: 100%;"
329
- valueFormat="YYYY-MM-DD"/>
330
- <a-date-picker
331
- v-else
332
- v-model="form[attr.model]"
333
- :disabled="disabled"
334
- style="width: 100%;"
335
- :show-time="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }"
336
- valueFormat="YYYY-MM-DD HH:mm:ss"/>
337
- </a-form-model-item>
338
- </x-form-col>
339
- <!-- 文本域 -->
340
- <a-col
341
- v-else-if="attr.type === 'textarea' && show"
342
- :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"
343
- :xs="24"
344
- :sm="24"
345
- :md="24"
346
- :lg="24"
347
- :xl="24"
348
- :xxl="24">
349
- <a-form-model-item
350
- :labelCol="layout === 'inline'?{span:2}:undefined"
351
- :wrapperCol="layout === 'inline'?{span:22}:undefined"
352
- :ref="attr.model"
353
- :label="attr.name"
354
- :prop="attr.prop ? attr.prop : attr.model">
355
- <a-textarea
356
- v-model="form[attr.model]"
357
- style="width: 100%;"
358
- :disabled="disabled"
359
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
360
- :rows="4"/>
361
- </a-form-model-item>
362
- </a-col>
363
- <!-- 文件上传 -->
364
- <a-col
365
- v-else-if="(attr.type === 'file' || attr.type === 'image') && show"
366
- :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"
367
- :xs="24"
368
- :sm="24"
369
- :md="24"
370
- :lg="24"
371
- :xl="24"
372
- :xxl="24">
373
- <a-form-model-item
374
- :labelCol="layout === 'inline'?{span:2}:undefined"
375
- :wrapperCol="layout === 'inline'?{span:22}:undefined"
376
- :ref="attr.model"
377
- :label="attr.name"
378
- :prop="attr.prop ? attr.prop : attr.model">
379
- <upload
380
- :files="files"
381
- :images="images"
382
- :model="attr"
383
- :uploadStyle="attr.uploadStyle"
384
- :service-name="serviceName"
385
- @setFiles="setFiles"></upload>
386
- </a-form-model-item>
387
- </a-col>
388
- <!-- 省市区选择框 -->
389
- <x-form-col
390
- v-else-if="attr.type === 'citySelect' && show"
391
- :flex="attr.flex">
392
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
393
- <citySelect
394
- ref="citySelect"
395
- v-model="form[attr.model]"
396
- :contexts="attr.contexts"
397
- :value-type="attr.valueType"
398
- :default-value="form[attr.model]"></citySelect>
399
- </a-form-model-item>
400
- </x-form-col>
401
- <!-- 地点搜索框 -->
402
- <x-form-col
403
- v-else-if="attr.type === 'addressSearch' && show"
404
- :flex="attr.flex">
405
- <a-form-model-item
406
- :ref="attr.model"
407
- :label="attr.name"
408
- :prop="attr.prop ? attr.prop : attr.model"
409
- :labelCol="layout === 'inline' && attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].labelCol:undefined"
410
- :wrapperCol="layout === 'inline'&& attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].wrapperCol:undefined"
411
- :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}">
412
- <address-search-combobox
413
- :emitFunc="emitFunc"
414
- :attr="attr"
415
- :read-only="readOnly"
416
- v-model="searchResult"
417
- :resultKeys="{ address: attr.model, coords: `${attr.model}_lng_lat` }"
418
- ref="addressSearchCombobox"
419
- searchResultType="Object"
420
- @onSelect="addressSearchComboboxSelect"
421
- @onDivisionsChange="onDivisionsChange"
422
- ></address-search-combobox>
423
- </a-form-model-item>
424
- </x-form-col>
425
- <!-- 富文本 -->
426
- <x-form-col
427
- v-else-if="attr.type === 'richText' && show"
428
- :flex="attr.flex">
429
- <a-form-model-item :ref="attr.model" :prop="attr.prop ? attr.prop : attr.model">
430
- <RichTextModal ref="richTextModal" style="height: 500px"></RichTextModal>
431
- </a-form-model-item>
432
- </x-form-col>
433
- <!-- 人员选择框 -->
434
- <x-form-col
435
- v-else-if="attr.type === 'personSetting' && show"
436
- :flex="attr.flex">
437
- <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
438
- <PersonSetting v-model="form[attr.model]"></PersonSetting>
439
- </a-form-model-item>
440
- </x-form-col>
441
- <!-- 树形选择框 -->
442
- <x-form-col
443
- v-else-if="attr.type === 'treeSelect' && show"
444
- :flex="attr.flex">
445
- <x-tree-select
446
- v-model="form[attr.model]"
447
- :attr="attr"
448
- ref="xTreeSelect">
449
- </x-tree-select>
450
- </x-form-col>
451
- <!-- 评分框 -->
452
- <x-form-col
453
- v-else-if="attr.type === 'rate' && show"
454
- :flex="attr.flex">
455
- <a-form-model-item
456
- :ref="attr.model"
457
- :label="attr.name"
458
- :prop="attr.prop ? attr.prop : attr.model">
459
- <a-rate v-model="form[attr.model]"/>
460
- </a-form-model-item>
461
- </x-form-col>
462
- <!-- 区间选择器 -->
463
- <x-form-col
464
- v-else-if="attr.type === 'intervalPicker' && show"
465
- :flex="attr.flex">
466
- <a-form-model-item
467
- :ref="attr.model"
468
- :label="attr.name"
469
- :prop="attr.prop ? attr.prop : attr.model">
470
- <a-input
471
- v-if="mode === '新增/修改'"
472
- v-model="form[attr.model]"
473
- :whitespace="true"
474
- :read-only="readOnly"
475
- :disabled="disabled && !readOnly"
476
- style="width:100%"
477
- @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
478
- :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
479
- :ref="`${attr.model}input`"/>
480
- <a-input-group v-else compact>
481
- <a-input
482
- v-model="form[attr.model][0]"
483
- class="intervalPicker-begin"
484
- placeholder="起始值"/>
485
- <a-input
486
- class="intervalPicker-center"
487
- style="backgroundColor: #fff"
488
- placeholder="~"
489
- disabled
490
- />
491
- <a-input
492
- v-model="form[attr.model][1]"
493
- class="intervalPicker-end"
494
- placeholder="结束值"/>
495
- </a-input-group>
496
- </a-form-model-item>
497
- </x-form-col>
498
- </template>
499
- <script>
500
-
501
- import { debounce } from 'ant-design-vue/lib/vc-table/src/utils'
502
- import XFormCol from '@vue2-client/base-client/components/common/XFormCol'
503
- import XBadge from '@vue2-client/base-client/components/common/XBadge'
504
- import CitySelect from '@vue2-client/base-client/components/common/CitySelect'
505
- import PersonSetting from '@vue2-client/base-client/components/common/PersonSetting'
506
- import AddressSearchCombobox from '@vue2-client/base-client/components/common/AddressSearchCombobox'
507
- import Upload from '@vue2-client/base-client/components/common/Upload'
508
- import moment from 'moment'
509
- import { upload, getConfigByName, runLogic } from '@vue2-client/services/api/common'
510
- import util, { uuid } from '.././../../../utils/util'
511
- import XTreeSelect from '@vue2-client/base-client/components/common/XForm/XTreeSelect'
512
- import { searchToListOption, searchToOption } from '@vue2-client/services/v3Api'
513
- import { mapState } from 'vuex'
514
- import { executeStrFunction } from '@vue2-client/utils/runEvalFunction'
515
- import RichTextModal from '../richTextModal/index.vue'
516
-
517
- export default {
518
- name: 'XFormItem',
519
- components: {
520
- XTreeSelect,
521
- XFormCol,
522
- XBadge,
523
- CitySelect,
524
- PersonSetting,
525
- AddressSearchCombobox,
526
- Upload,
527
- RichTextModal
528
- },
529
- data () {
530
- // 检索去抖
531
- this.fetchFunction = debounce(this.fetchFunction, 800)
532
- return {
533
- option: [],
534
- // 最后检索版本
535
- lastFetchId: 0,
536
- // 检索中
537
- searching: false,
538
- searchResult: '',
539
- yearShowOne: false,
540
- optionForFunc: [],
541
- // 控制当前表单项是否展示
542
- show: true,
543
- labelAndWrapperCol: [{
544
- labelCol: undefined,
545
- wrapperCol: undefined
546
- },
547
- {
548
- labelCol: undefined,
549
- wrapperCol: undefined
550
- },
551
- {
552
- labelCol: { span: 3 },
553
- wrapperCol: { span: 21 }
554
- },
555
- {
556
- labelCol: { span: 2 },
557
- wrapperCol: { span: 22 }
558
- }],
559
- // moment
560
- moment
561
- }
562
- },
563
- props: {
564
- attr: {
565
- type: Object,
566
- default:
567
- () => {
568
- return {}
569
- }
570
- },
571
- form: {
572
- type: Object,
573
- required:
574
- true
575
- },
576
- disabled: {
577
- type: Boolean,
578
- default:
579
- () => {
580
- return false
581
- }
582
- },
583
- readOnly: {
584
- type: Boolean,
585
- default:
586
- () => {
587
- return false
588
- }
589
- },
590
- mode: {
591
- type: String,
592
- default:
593
- () => {
594
- return '查询'
595
- }
596
- },
597
- files: {
598
- type: Array,
599
- default:
600
- () => {
601
- return []
602
- }
603
- },
604
- images: {
605
- type: Array,
606
- default:
607
- () => {
608
- return []
609
- }
610
- },
611
- serviceName: {
612
- type: String,
613
- default:
614
- undefined
615
- },
616
- // 调用logic获取数据源的追加参数
617
- getDataParams: {
618
- type: Object,
619
- default:
620
- undefined
621
- },
622
- // 布局
623
- layout: {
624
- type: String,
625
- default:
626
- 'horizontal'
627
- },
628
- // 环境
629
- env: {
630
- type: String,
631
- default:
632
- () => {
633
- return 'prod'
634
- }
635
- },
636
- // 设置表单值
637
- setForm: {
638
- type: Function,
639
- default: (val) => {
640
- console.log(val)
641
- }
642
- }
643
- },
644
- async created () {
645
- this.init()
646
- if (this.attr.keyName && (this.attr?.keyName?.toString().indexOf('async ') !== -1 || this.attr?.keyName?.toString()?.indexOf('function') !== -1)) {
647
- this.debouncedUpdateOptions = debounce(this.updateOptions, 200)
648
- }
649
- if (this.attr.dataChangeFunc) {
650
- this.debouncedDataChangeFunc = debounce(this.dataChangeFunc, 200)
651
- }
652
- if (this.attr.showFormItemFunc) {
653
- this.debouncedShowFormItemFunc = debounce(this.showFormItemFunc, 100)
654
- // 执行一次
655
- debounce(this.showFormItemFunc, 100)()
656
- }
657
- if (this.attr.showQueryFormItemFunc) {
658
- this.debouncedShowQueryFormItemFunc = debounce(this.showQueryFormItemFunc, 100)
659
- // 执行一次
660
- debounce(this.showQueryFormItemFunc, 100)()
661
- }
662
- // 人员联动框增加监听
663
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
664
- this.debouncedUserLinkFunc = debounce(() => this.updateResOptions('人员'), 200)
665
- }
666
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
667
- this.debouncedDepLinkFunc = debounce(() => this.updateResOptions('部门'), 200)
668
- }
669
- },
670
- computed: {
671
- ...mapState('account', { currUser: 'user' })
672
- },
673
- watch: {
674
- attr: {
675
- handler () {
676
- this.init()
677
- },
678
- deep: true
679
- },
680
- form: {
681
- handler (newVal) {
682
- // 如果是从函数获取 options
683
- if (this.attr.keyName && (this.attr.keyName.toString().indexOf('async ') !== -1 || this.attr.keyName.toString().indexOf('function') !== -1)) {
684
- this.debouncedUpdateOptions()
685
- }
686
- // 如果有自定义函数变更函数
687
- if (this.attr.dataChangeFunc) {
688
- this.debouncedDataChangeFunc()
689
- }
690
- // 如果有自定义是否展示表单项函数
691
- if (this.attr.showFormItemFunc) {
692
- this.debouncedShowFormItemFunc()
693
- }
694
- // 如果有自定义是否展示查询表单项函数
695
- if (this.attr.showQueryFormItemFunc) {
696
- this.debouncedShowQueryFormItemFunc()
697
- }
698
- // 地址搜索框赋值
699
- if (this.attr.type === 'addressSearch') {
700
- this.$refs.addressSearchCombobox.addressInput = this.form[this.attr.model]
701
- }
702
- // 数据源来自人员联动时更新数据
703
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
704
- this.debouncedUserLinkFunc()
705
- }
706
- // 数据源来自人员联动时更新数据
707
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
708
- this.debouncedDepLinkFunc()
709
- }
710
- },
711
- deep: true
712
- }
713
- },
714
- methods: {
715
- focusInput () {
716
- if (this.attr.defaultFocus) {
717
- this.$nextTick(h => {
718
- const el = this.$refs[`${this.attr.model}input`]?.$el
719
- let inputEl
720
- if (el) {
721
- if (el.tagName.toLowerCase() === 'input') {
722
- inputEl = el
723
- } else {
724
- inputEl = el.querySelector('input')
725
- }
726
- }
727
- if (inputEl) {
728
- inputEl.focus()
729
- if (inputEl.type === 'number') {
730
- if (inputEl.valueAsNumber) {
731
- inputEl.setSelectionRange(0, inputEl.valueAsNumber.toString().length)
732
- }
733
- } else {
734
- if (inputEl.value) {
735
- inputEl.setSelectionRange(0, inputEl.value.length)
736
- }
737
- }
738
- }
739
- })
740
- }
741
- },
742
- // 更新人员下拉框数据
743
- async updateResOptions (type) {
744
- if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString()?.endsWith(`]联动${type}`)) {
745
- const searchData = { source: `获取${type}`, userid: this.currUser.id }
746
- const startIndex = this.attr.keyName.indexOf('[') + 1
747
- const endIndex = this.attr.keyName.indexOf(']', startIndex)
748
- const fromModel = this.attr.keyName.substring(startIndex, endIndex).replace('.', '_')
749
- const formModelData = this.form[fromModel]
750
- if (fromModel?.length && formModelData?.length) {
751
- await searchToListOption(searchData, res => {
752
- this.getDataCallback(
753
- res.filter(h => {
754
- if (fromModel.indexOf('org') > -1) {
755
- return formModelData?.includes(h.orgid || h.f_organization_id || h.parentid)
756
- } else {
757
- return formModelData?.includes(h?.parentid)
758
- }
759
- }
760
- )
761
- )
762
- })
763
- }
764
- }
765
- },
766
- // js 函数作为数据源
767
- async updateOptions () {
768
- if (this.attr.keyName && (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1)) {
769
- this.optionForFunc = await executeStrFunction(this.attr.keyName, [this.form, runLogic, this.mode])
770
- }
771
- },
772
- async dataChangeFunc () {
773
- if (this.attr.dataChangeFunc) {
774
- await executeStrFunction(this.attr.dataChangeFunc, [this.form, this.setForm, this.attr, util, this.mode])
775
- }
776
- },
777
- async showFormItemFunc () {
778
- if (this.attr.showFormItemFunc) {
779
- this.show = executeStrFunction(this.attr.showFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
780
- } else {
781
- this.show = true
782
- }
783
- },
784
- async showQueryFormItemFunc () {
785
- if (this.attr.showQueryFormItemFunc) {
786
- this.show = executeStrFunction(this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
787
- } else {
788
- this.show = true
789
- }
790
- },
791
- init () {
792
- if (this.mode === '新增/修改' && !this.attr.flex) {
793
- if (['horizontal', 'vertical'].includes(this.layout)) {
794
- // 新增修改表单 horizontal 模式下默认为一行
795
- this.attr.flex = {
796
- xs: 24,
797
- sm: 24,
798
- md: 24,
799
- lg: 24,
800
- xl: 24,
801
- xxl: 24
802
- }
803
- } else {
804
- if (['input', 'addressSearch'] && this.attr.occupyCol) {
805
- // 如果是 input 看是否配置了 占用列配置
806
- this.attr.flex = {
807
- xs: 8 * this.attr.occupyCol,
808
- sm: 8 * this.attr.occupyCol,
809
- md: 8 * this.attr.occupyCol,
810
- lg: 8 * this.attr.occupyCol,
811
- xl: 8 * this.attr.occupyCol,
812
- xxl: 8 * this.attr.occupyCol
813
- }
814
- } else {
815
- // 新增修改表单 vertical 模式下默认为1列
816
- this.attr.flex = {
817
- xs: 24,
818
- sm: 24,
819
- md: 24,
820
- lg: 12,
821
- xl: 8,
822
- xxl: 8
823
- }
824
- }
825
- }
826
- } else {
827
- this.attr.flex = {
828
- xs: 24,
829
- sm: 24,
830
- md: 24,
831
- lg: 8,
832
- xl: 6,
833
- xxl: 6
834
- }
835
- }
836
- if (this.attr.type === 'radio') {
837
- this.initRadioValue()
838
- } else if (this.attr.type === 'richText') {
839
- this.initRichText()
840
- } else if (this.attr.keyName) {
841
- if (this.attr.keyName.indexOf('logic@') !== -1) {
842
- this.getData({}, res => this.getDataCallback(res))
843
- } else if (this.attr.keyName.indexOf('search@') !== -1) {
844
- // `tool.getFullTree(this.getRights().where(row.getType()==$organization$))`
845
- // 判断是否根据角色查询
846
- let source = this.attr.keyName.substring(7)
847
- const userid = this.currUser.id
848
- let roleName = 'roleName'
849
- if (source.startsWith('根据角色[') && source.endsWith(']获取人员')) {
850
- const startIndex = source.indexOf('[') + 1
851
- const endIndex = source.indexOf(']', startIndex)
852
- roleName = source.substring(startIndex, endIndex)
853
- source = '根据角色获取人员'
854
- }
855
- const searchData = { source, userid, roleName }
856
- // 判断是否根据某个表单项联动 仅返回列表结构并筛选
857
- if (source.startsWith('根据表单项[') && source.endsWith(']联动人员')) {
858
- this.updateResOptions('人员')
859
- } else if (source.startsWith('根据表单项[') && source.endsWith(']联动部门')) {
860
- this.updateResOptions('部门')
861
- } else if (this.attr.type === 'select' || this.attr.type === 'checkbox') {
862
- // 仅获取最内层数据
863
- searchToListOption(searchData, res => this.getDataCallback(res))
864
- } else {
865
- searchToOption(searchData, res => this.getDataCallback(res))
866
- }
867
- } else if (this.attr.keyName.indexOf('config@') !== -1) {
868
- const configName = this.attr.keyName.substring(7)
869
- getConfigByName(configName, this.serviceName, res => {
870
- this.getDataCallback(res.value)
871
- }, this.env === 'dev')
872
- } else if (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1) {
873
- this.updateOptions()
874
- }
875
- }
876
- this.focusInput()
877
- },
878
- addressSearchComboboxSelect (data) {
879
- this.form = Object.assign(this.form, JSON.parse(data))
880
- },
881
- onDivisionsChange (data) {
882
- this.emitFunc('addressSearchComboboxSelect', {
883
- key: this.attr.model,
884
- value: data
885
- })
886
- },
887
- getDataCallback (res) {
888
- this.option = res
889
- if (this.attr.type === 'treeSelect') {
890
- this.$refs.xTreeSelect.init({
891
- option: this.option,
892
- form: this.form,
893
- queryType: this.attr.queryType,
894
- name: this.attr.name,
895
- model: this.attr.model,
896
- mode: this.mode,
897
- disabled: this.disabled
898
- })
899
- } else if (this.attr.type === 'radio') {
900
- this.initRadioValue()
901
- }
902
- },
903
- initRadioValue () {
904
- const model = this.attr.model
905
- if (this.mode === '新增/修改' && this.attr.type === 'radio' && !this.form[model] && !this.attr.prop) {
906
- if (this.attr.keys && this.attr.keys.length > 0) {
907
- this.form[model] = this.attr.keys[0].value
908
- } else if (this.option && this.option.length > 0) {
909
- this.form[model] = this.option[0].value
910
- } else if (this.attr.keyName) {
911
- const list = this.$appdata.getDictionaryList(this.attr.keyName)
912
- if (list.length > 0) {
913
- this.form[model] = list[0].value
914
- }
915
- }
916
- }
917
- },
918
- async initRichText () {
919
- const logicName = this.attr.keyName
920
- if (logicName) {
921
- this.getData({}, async res => {
922
- try {
923
- const response = await fetch(res.url) // 等待 fetch 完成
924
- if (response.ok) {
925
- const data = await response.text() // 等待解析为文本内容
926
- const richText = JSON.parse(data)
927
- this.$refs.richTextModal.init({
928
- richText: richText
929
- })
930
- } else {
931
- this.$message.error('富文本读取失败,请求结果:' + response.statusText)
932
- }
933
- } catch (error) {
934
- this.$message.error('富文本读取失败,请求结果:' + error)
935
- }
936
- })
937
- }
938
- },
939
- async getRichValue () {
940
- if (this.$refs.richTextModal) {
941
- const richText = this.$refs.richTextModal.getValue()
942
- console.log('>>>> richText: ', richText)
943
- const fileContent = JSON.stringify(richText)
944
- const fileName = uuid() + '.txt'
945
- // 创建一个 Blob 对象,类型为 text/plain
946
- const blob = new Blob([fileContent], { type: 'text/plain' })
947
- // 创建一个 File 对象(可选,但有助于保持一致性,因为 File 继承自 Blob)
948
- const file = new File([blob], fileName, { type: blob.type })
949
- // 组装上传数据
950
- const headers = {
951
- 'Content-Type': 'multipart/form-data',
952
- }
953
- const formData = new FormData()
954
- formData.append('avatar', file)
955
- formData.append('resUploadMode', 'server')
956
- formData.append('pathKey', 'Default')
957
- formData.append('formType', 'file')
958
- formData.append('useType', 'Default')
959
- formData.append('filename', fileName)
960
- formData.append('filesize', (blob.size / 1024 / 1024).toFixed(4))
961
- formData.append('f_operator', this.currUser ? this.currUser.username : '')
962
-
963
- // 上传文件
964
- await upload(formData, this.serviceName, { headers, timeout: 600 * 1000 }).then(res => {
965
- this.form[this.attr.model] = res.data.id
966
- this.form.t_f_path = res.data.f_downloadpath
967
- }).catch(error => {
968
- // 处理上传错误
969
- console.error(error)
970
- })
971
- }
972
- },
973
- openChangeOne (status) {
974
- if (status) {
975
- this.yearShowOne = true
976
- }
977
- },
978
- // 得到年份选择器的值
979
- panelChangeOne (value) {
980
- this.yearShowOne = false
981
- this.form[this.attr.model] = value.format('YYYY')
982
- },
983
- // 文件框时设置上传组件的值
984
- setFiles (fileIds) {
985
- if (!this.form[this.attr.model]) {
986
- this.form[this.attr.model] = []
987
- }
988
- this.form[this.attr.model] = [...fileIds]
989
- },
990
- // 懒加载检索方法
991
- fetchFunction (value) {
992
- this.lastFetchId += 1
993
- const fetchId = this.lastFetchId
994
- this.option = []
995
- this.searching = true
996
- this.getData({
997
- word: value
998
- }, res => {
999
- if (fetchId !== this.lastFetchId) {
1000
- return
1001
- }
1002
- this.option = res
1003
- this.searching = false
1004
- })
1005
- },
1006
- // 获取数据
1007
- getData (value, callbackFun) {
1008
- if (value !== '') {
1009
- const logicName = this.attr.keyName
1010
- const logic = logicName.substring(6)
1011
- // 调用logic前设置参数
1012
- if (this.getDataParams && this.getDataParams[this.attr.model]) {
1013
- Object.assign(value, this.getDataParams[this.attr.model])
1014
- }
1015
- runLogic(logic, Object.assign(value, {
1016
- orgId: this.currUser.orgid,
1017
- userId: this.currUser.id
1018
- }), this.serviceName, this.env === 'dev').then(res => {
1019
- callbackFun(res)
1020
- }).catch(e => {
1021
- callbackFun([])
1022
- console.error('获取数据失败:' + e)
1023
- })
1024
- }
1025
- },
1026
- filterOption (input, option) {
1027
- const child = option.componentOptions.children[0]
1028
- if (child.text) {
1029
- return child.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
1030
- } else if (child.elm.innerText) {
1031
- return child.elm.innerText.toLowerCase().indexOf(input.toLowerCase()) >= 0
1032
- } else {
1033
- return child.child.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
1034
- }
1035
- },
1036
- emitFunc (func, data) {
1037
- this.$emit('x-form-item-emit-func', func, data)
1038
- }
1039
- }
1040
- }
1041
- </script>
1042
-
1043
- <style lang="less" scoped>
1044
- .intervalPicker-begin {
1045
- width: calc(50% - 14px);
1046
- }
1047
-
1048
- .intervalPicker-center {
1049
- width: 30px;
1050
- border-left: 0;
1051
- pointer-events: none;
1052
- }
1053
-
1054
- .intervalPicker-end {
1055
- width: calc(50% - 14px);
1056
- border-left: 0;
1057
- }
1058
- </style>
1
+ <template>
2
+ <!-- 输入框 -->
3
+ <x-form-col
4
+ v-if="attr.type === 'input' && show"
5
+ :flex="attr.flex">
6
+ <a-form-model-item
7
+ :ref="attr.model"
8
+ :label="attr.name"
9
+ :labelCol="layout === 'inline' && attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].labelCol:undefined"
10
+ :wrapperCol="layout === 'inline'&& attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].wrapperCol:undefined"
11
+ :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}"
12
+ :prop="attr.prop ? attr.prop : attr.model">
13
+ <!-- 如果配置了后置按钮插槽 -->
14
+ <a-input-group
15
+ v-if="(attr.inputOnAfterName && attr.inputOnAfterFunc) || (attr.inputOnAfterIcon && attr.inputOnAfterIconFunc)"
16
+ style="display: flex; width: 100%;"
17
+ compact>
18
+ <a-input
19
+ v-model="form[attr.model]"
20
+ :read-only="readOnly"
21
+ :disabled="disabled && !readOnly"
22
+ :whitespace="true"
23
+ style="flex: 1; width: auto; min-width: 0;"
24
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
25
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
26
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
27
+ :ref="`${attr.model}input`"/>
28
+ <a-button
29
+ v-if="attr.inputOnAfterName && attr.inputOnAfterFunc"
30
+ style="flex: 1; width: auto; min-width: 4rem;max-width: 6rem"
31
+ type="primary"
32
+ @click="emitFunc(attr.inputOnAfterFunc,form[attr.model])">
33
+ {{ attr.inputOnAfterName }}
34
+ </a-button>
35
+ <!-- 仅可以配置 一个按钮 以及 一个图标插槽 -->
36
+ <a-button
37
+ style="width: 2rem; flex-shrink: 0;"
38
+ v-if="attr.inputOnAfterIcon"
39
+ :type="attr.inputOnAfterIcon && attr.inputOnAfterName ? 'primary' :''"
40
+ :icon="attr.inputOnAfterIcon || 'question'"
41
+ @click="emitFunc(attr.inputOnAfterIconFunc,form[attr.model])">
42
+ </a-button>
43
+ </a-input-group>
44
+ <a-input-number
45
+ v-else-if="attr.numberInput && !readOnly"
46
+ v-model="form[attr.model]"
47
+ :whitespace="true"
48
+ :disabled="disabled && !readOnly"
49
+ style="width:100%"
50
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
51
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
52
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
53
+ :ref="`${attr.model}input`"/>
54
+ <a-input
55
+ v-else
56
+ v-model="form[attr.model]"
57
+ :whitespace="true"
58
+ :read-only="readOnly"
59
+ :disabled="disabled && !readOnly"
60
+ :suffix="attr.inputSuffix && mode !== '新增' ? attr.inputSuffix : ''"
61
+ style="width:100%"
62
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
63
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
64
+ :ref="`${attr.model}input`"/>
65
+
66
+ </a-form-model-item>
67
+ </x-form-col>
68
+ <!-- 下拉框 -->
69
+ <x-form-col
70
+ v-else-if="(attr.type === 'select' || (attr.type === 'rate' && mode==='查询')) && show"
71
+ :flex="attr.flex">
72
+ <a-form-model-item
73
+ :ref="attr.model"
74
+ :label="attr.name"
75
+ :prop="attr.prop ? attr.prop : attr.model">
76
+ <a-select
77
+ v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
78
+ v-model="form[attr.model]"
79
+ :disabled="disabled"
80
+ :filter-option="filterOption"
81
+ :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
82
+ :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
83
+ show-search
84
+ >
85
+ <a-select-option
86
+ v-if="mode === '查询'"
87
+ key="999999"
88
+ value="">全部
89
+ </a-select-option>
90
+ <template v-if="attr.keys">
91
+ <a-select-option
92
+ v-for="(item,index) in attr.keys"
93
+ :key="index.value"
94
+ :value="item.value">
95
+ {{ item.label }}
96
+ </a-select-option>
97
+ </template>
98
+ <template v-else>
99
+ <template
100
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
101
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
102
+ <a-select-option
103
+ v-for="(item,index) in option"
104
+ :key="index.value"
105
+ :value="item.value">
106
+ <template v-if="attr.keyName.indexOf('config@') !== -1 && item.status">
107
+ <!-- 徽标(badge) -->
108
+ <a-badge v-if="item.status !== 'gary'" :color="item.status" :text="item.label"/>
109
+ <a-badge v-else color="#D9D9D9" :text="item.label"/>
110
+ </template>
111
+ <template v-else>
112
+ {{ item.label }}
113
+ </template>
114
+ </a-select-option>
115
+ </template>
116
+ <template
117
+ v-else-if="attr.keyName.indexOf('async ') !== -1 || attr.keyName.indexOf('function ') !== -1">
118
+ <a-select-option
119
+ v-for="(item,index) in optionForFunc"
120
+ :key="index.value"
121
+ :value="item.value">
122
+ <template>
123
+ {{ item.label }}
124
+ </template>
125
+ </a-select-option>
126
+ </template>
127
+ <template v-else>
128
+ <a-select-option
129
+ v-for="item in $appdata.getDictionaryList(attr.keyName)"
130
+ :key="item.value"
131
+ :value="item.value">
132
+ <!-- 徽标(badge) -->
133
+ <x-badge :badge-key="attr.keyName" :replaceText="item.text" :value="item.value"/>
134
+ </a-select-option>
135
+ </template>
136
+ </template>
137
+ </a-select>
138
+ <a-select
139
+ v-else
140
+ v-model="form[attr.model]"
141
+ :disabled="disabled"
142
+ :filter-option="filterOption"
143
+ :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
144
+ :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
145
+ show-search
146
+ @search="fetchFunction"
147
+ >
148
+ <a-spin v-if="searching" slot="notFoundContent" size="small"/>
149
+ <a-select-option
150
+ v-if="mode === '查询'"
151
+ key="999999"
152
+ value="">全部
153
+ </a-select-option>
154
+ <a-select-option
155
+ v-for="(item,index) in option"
156
+ :key="index"
157
+ :value="item.value">{{ item.label }}
158
+ </a-select-option>
159
+ </a-select>
160
+ </a-form-model-item>
161
+ </x-form-col>
162
+ <!-- 多选框 -->
163
+ <x-form-col
164
+ v-else-if="attr.type === 'checkbox' && show"
165
+ :flex="attr.flex">
166
+ <a-form-model-item
167
+ :ref="attr.model"
168
+ :label="attr.name"
169
+ :prop="attr.prop ? attr.prop : attr.model">
170
+ <a-select
171
+ v-if="!attr.lazyLoad || attr.lazyLoad === 'false'"
172
+ v-model="form[attr.model]"
173
+ :disabled="disabled"
174
+ :filter-option="filterOption"
175
+ :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
176
+ :placeholder="attr.placeholder ? attr.placeholder : '请选择'"
177
+ mode="multiple"
178
+ show-search
179
+ allowClear
180
+ >
181
+ <template v-if="attr.keys">
182
+ <a-select-option
183
+ v-for="(item,index) in attr.keys"
184
+ :key="index"
185
+ :value="item.value">
186
+ {{ item.label }}
187
+ </a-select-option>
188
+ </template>
189
+ <template v-else>
190
+ <template
191
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
192
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
193
+ <a-select-option
194
+ v-for="(item,index) in option"
195
+ :key="index"
196
+ :value="item.value">{{ item.label }}
197
+ </a-select-option>
198
+ </template>
199
+ <template v-else>
200
+ <a-select-option
201
+ v-for="item in $appdata.getDictionaryList(attr.keyName)"
202
+ :key="item.value"
203
+ :value="item.value">{{ item.text }}
204
+ </a-select-option>
205
+ </template>
206
+ </template>
207
+ </a-select>
208
+ <a-select
209
+ v-else
210
+ v-model="form[attr.model]"
211
+ :disabled="disabled"
212
+ :filter-option="filterOption"
213
+ :getPopupContainer=" triggerNode => { return triggerNode.parentNode } "
214
+ :placeholder="attr.placeholder ? attr.placeholder : '搜索' + attr.name"
215
+ mode="multiple"
216
+ show-search
217
+ allowClear
218
+ @search="fetchFunction"
219
+ >
220
+ <a-spin v-if="searching" slot="notFoundContent" size="small"/>
221
+ <a-select-option
222
+ v-for="(item,index) in option"
223
+ :key="index"
224
+ :value="item.value">{{ item.label }}
225
+ </a-select-option>
226
+ </a-select>
227
+ </a-form-model-item>
228
+ </x-form-col>
229
+ <!-- 单选框 -->
230
+ <x-form-col
231
+ v-else-if="attr.type === 'radio' && show"
232
+ :flex="attr.flex">
233
+ <a-form-model-item
234
+ :ref="attr.model"
235
+ :label="attr.name"
236
+ :prop="attr.prop ? attr.prop : attr.model">
237
+ <a-radio-group v-model="form[attr.model]">
238
+ <template v-if="attr.keys">
239
+ <a-radio v-for="(item,index) in attr.keys" :key="index" :value="item.value">
240
+ {{ item.label }}
241
+ </a-radio>
242
+ </template>
243
+ <template v-else>
244
+ <template
245
+ v-if="attr.keyName.indexOf('logic@') !== -1 || attr.keyName.indexOf('config@') !== -1
246
+ ||attr.keyName.indexOf('search@') !== -1 || attr.keyName.indexOf('search@') !== -1">
247
+ <a-radio v-for="(item,index) in option" :key="index" :value="item.value">
248
+ {{ item.label }}
249
+ </a-radio>
250
+ </template>
251
+ <template v-else>
252
+ <a-radio v-for="(item,index) in $appdata.getDictionaryList(attr.keyName)" :key="index" :value="item.value">
253
+ {{ item.text }}
254
+ </a-radio>
255
+ </template>
256
+ </template>
257
+ </a-radio-group>
258
+ </a-form-model-item>
259
+ </x-form-col>
260
+ <!-- 日期范围选择器 -->
261
+ <x-form-col
262
+ v-else-if="attr.type === 'rangePicker' && show"
263
+ :flex="attr.flex">
264
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
265
+ <a-date-picker
266
+ v-if="mode === '新增/修改'"
267
+ v-model="form[attr.model]"
268
+ :disabled="disabled"
269
+ :show-time="true"
270
+ style="width: 100%;"
271
+ valueFormat="YYYY-MM-DD HH:mm:ss"/>
272
+ <a-range-picker
273
+ v-else
274
+ v-model="form[attr.model]"
275
+ :disabled="disabled"
276
+ :show-time="true"
277
+ valueFormat="YYYY-MM-DD HH:mm:ss"
278
+ style="width: 100%;"
279
+ />
280
+ </a-form-model-item>
281
+ </x-form-col>
282
+ <!-- 月份选择器 -->
283
+ <x-form-col
284
+ v-else-if="attr.type === 'monthPicker' && show"
285
+ :flex="attr.flex">
286
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
287
+ <a-month-picker
288
+ v-model="form[attr.model]"
289
+ :disabled="disabled"
290
+ :show-time="true"
291
+ valueFormat="YYYY-MM"
292
+ style="width: 100%;"
293
+ />
294
+ </a-form-model-item>
295
+ </x-form-col>
296
+ <!-- 年份选择器 -->
297
+ <x-form-col
298
+ v-else-if="attr.type === 'yearPicker' && show"
299
+ :flex="attr.flex">
300
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
301
+ <a-date-picker
302
+ v-model="form[attr.model]"
303
+ :disabled="disabled"
304
+ format="YYYY"
305
+ mode="year"
306
+ v-decorator="['year']"
307
+ placeholder="请选择年份"
308
+ :open="yearShowOne"
309
+ style="width: 100%;"
310
+ @openChange="openChangeOne"
311
+ @panelChange="panelChangeOne"/>
312
+ </a-form-model-item>
313
+ </x-form-col>
314
+ <!-- 单日选择器 -->
315
+ <x-form-col
316
+ v-else-if="attr.type === 'datePicker' && show"
317
+ :flex="attr.flex">
318
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
319
+ <a-range-picker
320
+ v-if="mode === '查询' && attr.queryType === 'BETWEEN' "
321
+ v-model="form[attr.model]"
322
+ :disabled="disabled"
323
+ :show-time="true"
324
+ style="width: 100%;"
325
+ format="YYYY-MM-DD"
326
+ valueFormat="YYYY-MM-DD HH:mm:ss"/>
327
+ <a-date-picker
328
+ v-else-if="mode === '查询'"
329
+ v-model="form[attr.model]"
330
+ :disabled="disabled"
331
+ style="width: 100%;"
332
+ valueFormat="YYYY-MM-DD"/>
333
+ <a-date-picker
334
+ v-else
335
+ v-model="form[attr.model]"
336
+ :disabled="disabled"
337
+ style="width: 100%;"
338
+ :show-time="{ defaultValue: moment('00:00:00', 'HH:mm:ss') }"
339
+ valueFormat="YYYY-MM-DD HH:mm:ss"/>
340
+ </a-form-model-item>
341
+ </x-form-col>
342
+ <!-- 文本域 -->
343
+ <a-col
344
+ v-else-if="attr.type === 'textarea' && show"
345
+ :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"
346
+ :xs="24"
347
+ :sm="24"
348
+ :md="24"
349
+ :lg="24"
350
+ :xl="24"
351
+ :xxl="24">
352
+ <a-form-model-item
353
+ :labelCol="layout === 'inline'?{span:2}:undefined"
354
+ :wrapperCol="layout === 'inline'?{span:22}:undefined"
355
+ :ref="attr.model"
356
+ :label="attr.name"
357
+ :prop="attr.prop ? attr.prop : attr.model">
358
+ <a-textarea
359
+ v-model="form[attr.model]"
360
+ style="width: 100%;"
361
+ :disabled="disabled"
362
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
363
+ :rows="4"/>
364
+ </a-form-model-item>
365
+ </a-col>
366
+ <!-- 文件上传 -->
367
+ <a-col
368
+ v-else-if="(attr.type === 'file' || attr.type === 'image') && show"
369
+ :style="layout === 'inline'?{width:'calc(100% - 60px)'}:{}"
370
+ :xs="24"
371
+ :sm="24"
372
+ :md="24"
373
+ :lg="24"
374
+ :xl="24"
375
+ :xxl="24">
376
+ <a-form-model-item
377
+ :labelCol="layout === 'inline'?{span:2}:undefined"
378
+ :wrapperCol="layout === 'inline'?{span:22}:undefined"
379
+ :ref="attr.model"
380
+ :label="attr.name"
381
+ :prop="attr.prop ? attr.prop : attr.model">
382
+ <upload
383
+ :files="files"
384
+ :images="images"
385
+ :model="attr"
386
+ :uploadStyle="attr.uploadStyle"
387
+ :service-name="serviceName"
388
+ @setFiles="setFiles"></upload>
389
+ </a-form-model-item>
390
+ </a-col>
391
+ <!-- 省市区选择框 -->
392
+ <x-form-col
393
+ v-else-if="attr.type === 'citySelect' && show"
394
+ :flex="attr.flex">
395
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
396
+ <citySelect
397
+ ref="citySelect"
398
+ v-model="form[attr.model]"
399
+ :contexts="attr.contexts"
400
+ :value-type="attr.valueType"
401
+ :default-value="form[attr.model]"></citySelect>
402
+ </a-form-model-item>
403
+ </x-form-col>
404
+ <!-- 地点搜索框 -->
405
+ <x-form-col
406
+ v-else-if="attr.type === 'addressSearch' && show"
407
+ :flex="attr.flex">
408
+ <a-form-model-item
409
+ :ref="attr.model"
410
+ :label="attr.name"
411
+ :prop="attr.prop ? attr.prop : attr.model"
412
+ :labelCol="layout === 'inline' && attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].labelCol:undefined"
413
+ :wrapperCol="layout === 'inline'&& attr.occupyCol ? labelAndWrapperCol[attr.occupyCol].wrapperCol:undefined"
414
+ :style="layout === 'inline'&& attr.occupyCol && attr.occupyCol > 1? {width:`calc(100% - ${attr.occupyCol * 1.533}rem)`}:{}">
415
+ <address-search-combobox
416
+ :emitFunc="emitFunc"
417
+ :attr="attr"
418
+ :read-only="readOnly"
419
+ v-model="searchResult"
420
+ :resultKeys="{ address: attr.model, coords: `${attr.model}_lng_lat` }"
421
+ ref="addressSearchCombobox"
422
+ searchResultType="Object"
423
+ @onSelect="addressSearchComboboxSelect"
424
+ @onDivisionsChange="onDivisionsChange"
425
+ ></address-search-combobox>
426
+ </a-form-model-item>
427
+ </x-form-col>
428
+ <!-- 富文本 -->
429
+ <x-form-col
430
+ v-else-if="attr.type === 'richText' && show"
431
+ :flex="attr.flex">
432
+ <a-form-model-item :ref="attr.model" :prop="attr.prop ? attr.prop : attr.model">
433
+ <RichTextModal ref="richTextModal" style="height: 500px"></RichTextModal>
434
+ </a-form-model-item>
435
+ </x-form-col>
436
+ <!-- 人员选择框 -->
437
+ <x-form-col
438
+ v-else-if="attr.type === 'personSetting' && show"
439
+ :flex="attr.flex">
440
+ <a-form-model-item :ref="attr.model" :label="attr.name" :prop="attr.prop ? attr.prop : attr.model">
441
+ <PersonSetting v-model="form[attr.model]"></PersonSetting>
442
+ </a-form-model-item>
443
+ </x-form-col>
444
+ <!-- 树形选择框 -->
445
+ <x-form-col
446
+ v-else-if="attr.type === 'treeSelect' && show"
447
+ :flex="attr.flex">
448
+ <x-tree-select
449
+ v-model="form[attr.model]"
450
+ :attr="attr"
451
+ ref="xTreeSelect">
452
+ </x-tree-select>
453
+ </x-form-col>
454
+ <!-- 评分框 -->
455
+ <x-form-col
456
+ v-else-if="attr.type === 'rate' && show"
457
+ :flex="attr.flex">
458
+ <a-form-model-item
459
+ :ref="attr.model"
460
+ :label="attr.name"
461
+ :prop="attr.prop ? attr.prop : attr.model">
462
+ <a-rate v-model="form[attr.model]"/>
463
+ </a-form-model-item>
464
+ </x-form-col>
465
+ <!-- 区间选择器 -->
466
+ <x-form-col
467
+ v-else-if="attr.type === 'intervalPicker' && show"
468
+ :flex="attr.flex">
469
+ <a-form-model-item
470
+ :ref="attr.model"
471
+ :label="attr.name"
472
+ :prop="attr.prop ? attr.prop : attr.model">
473
+ <a-input
474
+ v-if="mode === '新增/修改'"
475
+ v-model="form[attr.model]"
476
+ :whitespace="true"
477
+ :read-only="readOnly"
478
+ :disabled="disabled && !readOnly"
479
+ style="width:100%"
480
+ @blur="attr.inputOnBlurFunc && emitFunc(attr.inputOnBlurFunc,attr)"
481
+ :placeholder="attr.placeholder ? attr.placeholder : '请输入'+attr.name.replace(/\s*/g, '')"
482
+ :ref="`${attr.model}input`"/>
483
+ <a-input-group v-else compact>
484
+ <a-input
485
+ v-model="form[attr.model][0]"
486
+ class="intervalPicker-begin"
487
+ placeholder="起始值"/>
488
+ <a-input
489
+ class="intervalPicker-center"
490
+ style="backgroundColor: #fff"
491
+ placeholder="~"
492
+ disabled
493
+ />
494
+ <a-input
495
+ v-model="form[attr.model][1]"
496
+ class="intervalPicker-end"
497
+ placeholder="结束值"/>
498
+ </a-input-group>
499
+ </a-form-model-item>
500
+ </x-form-col>
501
+ </template>
502
+ <script>
503
+
504
+ import { debounce } from 'ant-design-vue/lib/vc-table/src/utils'
505
+ import XFormCol from '@vue2-client/base-client/components/common/XFormCol'
506
+ import XBadge from '@vue2-client/base-client/components/common/XBadge'
507
+ import CitySelect from '@vue2-client/base-client/components/common/CitySelect'
508
+ import PersonSetting from '@vue2-client/base-client/components/common/PersonSetting'
509
+ import AddressSearchCombobox from '@vue2-client/base-client/components/common/AddressSearchCombobox'
510
+ import Upload from '@vue2-client/base-client/components/common/Upload'
511
+ import moment from 'moment'
512
+ import { upload, getConfigByName, runLogic } from '@vue2-client/services/api/common'
513
+ import util, { uuid } from '.././../../../utils/util'
514
+ import XTreeSelect from '@vue2-client/base-client/components/common/XForm/XTreeSelect'
515
+ import { searchToListOption, searchToOption } from '@vue2-client/services/v3Api'
516
+ import { mapState } from 'vuex'
517
+ import { executeStrFunction } from '@vue2-client/utils/runEvalFunction'
518
+ import RichTextModal from '../richTextModal/index.vue'
519
+
520
+ export default {
521
+ name: 'XFormItem',
522
+ components: {
523
+ XTreeSelect,
524
+ XFormCol,
525
+ XBadge,
526
+ CitySelect,
527
+ PersonSetting,
528
+ AddressSearchCombobox,
529
+ Upload,
530
+ RichTextModal
531
+ },
532
+ data () {
533
+ // 检索去抖
534
+ this.fetchFunction = debounce(this.fetchFunction, 800)
535
+ return {
536
+ option: [],
537
+ // 最后检索版本
538
+ lastFetchId: 0,
539
+ // 检索中
540
+ searching: false,
541
+ searchResult: '',
542
+ yearShowOne: false,
543
+ optionForFunc: [],
544
+ // 控制当前表单项是否展示
545
+ show: true,
546
+ labelAndWrapperCol: [{
547
+ labelCol: undefined,
548
+ wrapperCol: undefined
549
+ },
550
+ {
551
+ labelCol: undefined,
552
+ wrapperCol: undefined
553
+ },
554
+ {
555
+ labelCol: { span: 3 },
556
+ wrapperCol: { span: 21 }
557
+ },
558
+ {
559
+ labelCol: { span: 2 },
560
+ wrapperCol: { span: 22 }
561
+ }],
562
+ // moment
563
+ moment
564
+ }
565
+ },
566
+ props: {
567
+ attr: {
568
+ type: Object,
569
+ default:
570
+ () => {
571
+ return {}
572
+ }
573
+ },
574
+ form: {
575
+ type: Object,
576
+ required:
577
+ true
578
+ },
579
+ disabled: {
580
+ type: Boolean,
581
+ default:
582
+ () => {
583
+ return false
584
+ }
585
+ },
586
+ readOnly: {
587
+ type: Boolean,
588
+ default:
589
+ () => {
590
+ return false
591
+ }
592
+ },
593
+ mode: {
594
+ type: String,
595
+ default:
596
+ () => {
597
+ return '查询'
598
+ }
599
+ },
600
+ files: {
601
+ type: Array,
602
+ default:
603
+ () => {
604
+ return []
605
+ }
606
+ },
607
+ images: {
608
+ type: Array,
609
+ default:
610
+ () => {
611
+ return []
612
+ }
613
+ },
614
+ serviceName: {
615
+ type: String,
616
+ default:
617
+ undefined
618
+ },
619
+ // 调用logic获取数据源的追加参数
620
+ getDataParams: {
621
+ type: Object,
622
+ default:
623
+ undefined
624
+ },
625
+ // 布局
626
+ layout: {
627
+ type: String,
628
+ default:
629
+ 'horizontal'
630
+ },
631
+ // 环境
632
+ env: {
633
+ type: String,
634
+ default:
635
+ () => {
636
+ return 'prod'
637
+ }
638
+ },
639
+ // 设置表单值
640
+ setForm: {
641
+ type: Function,
642
+ default: (val) => {
643
+ console.log(val)
644
+ }
645
+ }
646
+ },
647
+ async created () {
648
+ this.init()
649
+ if (this.attr.keyName && (this.attr?.keyName?.toString().indexOf('async ') !== -1 || this.attr?.keyName?.toString()?.indexOf('function') !== -1)) {
650
+ this.debouncedUpdateOptions = debounce(this.updateOptions, 200)
651
+ }
652
+ if (this.attr.dataChangeFunc) {
653
+ this.debouncedDataChangeFunc = debounce(this.dataChangeFunc, 200)
654
+ }
655
+ if (this.attr.showFormItemFunc) {
656
+ this.debouncedShowFormItemFunc = debounce(this.showFormItemFunc, 100)
657
+ // 执行一次
658
+ debounce(this.showFormItemFunc, 100)()
659
+ }
660
+ if (this.attr.showQueryFormItemFunc) {
661
+ this.debouncedShowQueryFormItemFunc = debounce(this.showQueryFormItemFunc, 100)
662
+ // 执行一次
663
+ debounce(this.showQueryFormItemFunc, 100)()
664
+ }
665
+ // 人员联动框增加监听
666
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
667
+ this.debouncedUserLinkFunc = debounce(() => this.updateResOptions('人员'), 200)
668
+ }
669
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
670
+ this.debouncedDepLinkFunc = debounce(() => this.updateResOptions('部门'), 200)
671
+ }
672
+ },
673
+ computed: {
674
+ ...mapState('account', { currUser: 'user' })
675
+ },
676
+ watch: {
677
+ attr: {
678
+ handler () {
679
+ this.init()
680
+ },
681
+ deep: true
682
+ },
683
+ form: {
684
+ handler (newVal) {
685
+ // 如果是从函数获取 options
686
+ if (this.attr.keyName && (this.attr.keyName.toString().indexOf('async ') !== -1 || this.attr.keyName.toString().indexOf('function') !== -1)) {
687
+ this.debouncedUpdateOptions()
688
+ }
689
+ // 如果有自定义函数变更函数
690
+ if (this.attr.dataChangeFunc) {
691
+ this.debouncedDataChangeFunc()
692
+ }
693
+ // 如果有自定义是否展示表单项函数
694
+ if (this.attr.showFormItemFunc) {
695
+ this.debouncedShowFormItemFunc()
696
+ }
697
+ // 如果有自定义是否展示查询表单项函数
698
+ if (this.attr.showQueryFormItemFunc) {
699
+ this.debouncedShowQueryFormItemFunc()
700
+ }
701
+ // 地址搜索框赋值
702
+ if (this.attr.type === 'addressSearch') {
703
+ this.$refs.addressSearchCombobox.addressInput = this.form[this.attr.model]
704
+ }
705
+ // 数据源来自人员联动时更新数据
706
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动人员')) {
707
+ this.debouncedUserLinkFunc()
708
+ }
709
+ // 数据源来自人员联动时更新数据
710
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString().endsWith(']联动部门')) {
711
+ this.debouncedDepLinkFunc()
712
+ }
713
+ },
714
+ deep: true
715
+ }
716
+ },
717
+ methods: {
718
+ focusInput () {
719
+ if (this.attr.defaultFocus) {
720
+ this.$nextTick(h => {
721
+ const el = this.$refs[`${this.attr.model}input`]?.$el
722
+ let inputEl
723
+ if (el) {
724
+ if (el.tagName.toLowerCase() === 'input') {
725
+ inputEl = el
726
+ } else {
727
+ inputEl = el.querySelector('input')
728
+ }
729
+ }
730
+ if (inputEl) {
731
+ inputEl.focus()
732
+ if (inputEl.type === 'number') {
733
+ if (inputEl.valueAsNumber) {
734
+ inputEl.setSelectionRange(0, inputEl.valueAsNumber.toString().length)
735
+ }
736
+ } else {
737
+ if (inputEl.value) {
738
+ inputEl.setSelectionRange(0, inputEl.value.length)
739
+ }
740
+ }
741
+ }
742
+ })
743
+ }
744
+ },
745
+ // 更新人员下拉框数据
746
+ async updateResOptions (type) {
747
+ if (this?.attr?.keyName?.toString()?.startsWith('search@根据表单项[') && this?.attr?.keyName?.toString()?.endsWith(`]联动${type}`)) {
748
+ const searchData = { source: `获取${type}`, userid: this.currUser.id }
749
+ const startIndex = this.attr.keyName.indexOf('[') + 1
750
+ const endIndex = this.attr.keyName.indexOf(']', startIndex)
751
+ const fromModel = this.attr.keyName.substring(startIndex, endIndex).replace('.', '_')
752
+ const formModelData = this.form[fromModel]
753
+ if (fromModel?.length && formModelData?.length) {
754
+ await searchToListOption(searchData, res => {
755
+ this.getDataCallback(
756
+ res.filter(h => {
757
+ if (fromModel.indexOf('org') > -1) {
758
+ return formModelData?.includes(h.orgid || h.f_organization_id || h.parentid)
759
+ } else {
760
+ return formModelData?.includes(h?.parentid)
761
+ }
762
+ }
763
+ )
764
+ )
765
+ })
766
+ }
767
+ }
768
+ },
769
+ // js 函数作为数据源
770
+ async updateOptions () {
771
+ if (this.attr.keyName && (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1)) {
772
+ this.optionForFunc = await executeStrFunction(this.attr.keyName, [this.form, runLogic, this.mode])
773
+ }
774
+ },
775
+ async dataChangeFunc () {
776
+ if (this.attr.dataChangeFunc) {
777
+ await executeStrFunction(this.attr.dataChangeFunc, [this.form, this.setForm, this.attr, util, this.mode])
778
+ }
779
+ },
780
+ async showFormItemFunc () {
781
+ if (this.attr.showFormItemFunc) {
782
+ this.show = executeStrFunction(this.attr.showFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
783
+ } else {
784
+ this.show = true
785
+ }
786
+ },
787
+ async showQueryFormItemFunc () {
788
+ if (this.attr.showQueryFormItemFunc) {
789
+ this.show = executeStrFunction(this.attr.showQueryFormItemFunc, [this.form, this.setForm, this.attr, util, this.mode])
790
+ } else {
791
+ this.show = true
792
+ }
793
+ },
794
+ init () {
795
+ if (this.mode === '新增/修改' && !this.attr.flex) {
796
+ if (['horizontal', 'vertical'].includes(this.layout)) {
797
+ // 新增修改表单 horizontal 模式下默认为一行
798
+ this.attr.flex = {
799
+ xs: 24,
800
+ sm: 24,
801
+ md: 24,
802
+ lg: 24,
803
+ xl: 24,
804
+ xxl: 24
805
+ }
806
+ } else {
807
+ if (['input', 'addressSearch'] && this.attr.occupyCol) {
808
+ // 如果是 input 看是否配置了 占用列配置
809
+ this.attr.flex = {
810
+ xs: 8 * this.attr.occupyCol,
811
+ sm: 8 * this.attr.occupyCol,
812
+ md: 8 * this.attr.occupyCol,
813
+ lg: 8 * this.attr.occupyCol,
814
+ xl: 8 * this.attr.occupyCol,
815
+ xxl: 8 * this.attr.occupyCol
816
+ }
817
+ } else {
818
+ // 新增修改表单 vertical 模式下默认为1列
819
+ this.attr.flex = {
820
+ xs: 24,
821
+ sm: 24,
822
+ md: 24,
823
+ lg: 12,
824
+ xl: 8,
825
+ xxl: 8
826
+ }
827
+ }
828
+ }
829
+ } else {
830
+ this.attr.flex = {
831
+ xs: 24,
832
+ sm: 24,
833
+ md: 24,
834
+ lg: 8,
835
+ xl: 6,
836
+ xxl: 6
837
+ }
838
+ }
839
+ if (this.attr.type === 'radio') {
840
+ this.initRadioValue()
841
+ } else if (this.attr.type === 'richText') {
842
+ this.initRichText()
843
+ } else if (this.attr.keyName) {
844
+ if (this.attr.keyName.indexOf('logic@') !== -1) {
845
+ this.getData({}, res => this.getDataCallback(res))
846
+ } else if (this.attr.keyName.indexOf('search@') !== -1) {
847
+ // `tool.getFullTree(this.getRights().where(row.getType()==$organization$))`
848
+ // 判断是否根据角色查询
849
+ let source = this.attr.keyName.substring(7)
850
+ const userid = this.currUser.id
851
+ let roleName = 'roleName'
852
+ if (source.startsWith('根据角色[') && source.endsWith(']获取人员')) {
853
+ const startIndex = source.indexOf('[') + 1
854
+ const endIndex = source.indexOf(']', startIndex)
855
+ roleName = source.substring(startIndex, endIndex)
856
+ source = '根据角色获取人员'
857
+ }
858
+ const searchData = { source, userid, roleName }
859
+ // 判断是否根据某个表单项联动 仅返回列表结构并筛选
860
+ if (source.startsWith('根据表单项[') && source.endsWith(']联动人员')) {
861
+ this.updateResOptions('人员')
862
+ } else if (source.startsWith('根据表单项[') && source.endsWith(']联动部门')) {
863
+ this.updateResOptions('部门')
864
+ } else if (this.attr.type === 'select' || this.attr.type === 'checkbox') {
865
+ // 仅获取最内层数据
866
+ searchToListOption(searchData, res => this.getDataCallback(res))
867
+ } else {
868
+ searchToOption(searchData, res => this.getDataCallback(res))
869
+ }
870
+ } else if (this.attr.keyName.indexOf('config@') !== -1) {
871
+ const configName = this.attr.keyName.substring(7)
872
+ getConfigByName(configName, this.serviceName, res => {
873
+ this.getDataCallback(res.value)
874
+ }, this.env === 'dev')
875
+ } else if (this.attr.keyName.indexOf('async ') !== -1 || this.attr.keyName.indexOf('function ') !== -1) {
876
+ this.updateOptions()
877
+ }
878
+ }
879
+ this.focusInput()
880
+ },
881
+ addressSearchComboboxSelect (data) {
882
+ this.form = Object.assign(this.form, JSON.parse(data))
883
+ },
884
+ onDivisionsChange (data) {
885
+ this.emitFunc('addressSearchComboboxSelect', {
886
+ key: this.attr.model,
887
+ value: data
888
+ })
889
+ },
890
+ getDataCallback (res) {
891
+ this.option = res
892
+ if (this.attr.type === 'treeSelect') {
893
+ this.$refs.xTreeSelect.init({
894
+ option: this.option,
895
+ form: this.form,
896
+ queryType: this.attr.queryType,
897
+ name: this.attr.name,
898
+ model: this.attr.model,
899
+ mode: this.mode,
900
+ disabled: this.disabled
901
+ })
902
+ } else if (this.attr.type === 'radio') {
903
+ this.initRadioValue()
904
+ }
905
+ },
906
+ initRadioValue () {
907
+ const model = this.attr.model
908
+ if (this.mode === '新增/修改' && this.attr.type === 'radio' && !this.form[model] && !this.attr.prop) {
909
+ if (this.attr.keys && this.attr.keys.length > 0) {
910
+ this.form[model] = this.attr.keys[0].value
911
+ } else if (this.option && this.option.length > 0) {
912
+ this.form[model] = this.option[0].value
913
+ } else if (this.attr.keyName) {
914
+ const list = this.$appdata.getDictionaryList(this.attr.keyName)
915
+ if (list.length > 0) {
916
+ this.form[model] = list[0].value
917
+ }
918
+ }
919
+ }
920
+ },
921
+ async initRichText () {
922
+ const logicName = this.attr.keyName
923
+ if (logicName) {
924
+ this.getData({}, async res => {
925
+ try {
926
+ const response = await fetch(res.url) // 等待 fetch 完成
927
+ if (response.ok) {
928
+ const data = await response.text() // 等待解析为文本内容
929
+ const richText = JSON.parse(data)
930
+ this.$refs.richTextModal.init({
931
+ richText: richText
932
+ })
933
+ } else {
934
+ this.$message.error('富文本读取失败,请求结果:' + response.statusText)
935
+ }
936
+ } catch (error) {
937
+ this.$message.error('富文本读取失败,请求结果:' + error)
938
+ }
939
+ })
940
+ }
941
+ },
942
+ async getRichValue () {
943
+ if (this.$refs.richTextModal) {
944
+ const richText = this.$refs.richTextModal.getValue()
945
+ console.log('>>>> richText: ', richText)
946
+ const fileContent = JSON.stringify(richText)
947
+ const fileName = uuid() + '.txt'
948
+ // 创建一个 Blob 对象,类型为 text/plain
949
+ const blob = new Blob([fileContent], { type: 'text/plain' })
950
+ // 创建一个 File 对象(可选,但有助于保持一致性,因为 File 继承自 Blob)
951
+ const file = new File([blob], fileName, { type: blob.type })
952
+ // 组装上传数据
953
+ const headers = {
954
+ 'Content-Type': 'multipart/form-data',
955
+ }
956
+ const formData = new FormData()
957
+ formData.append('avatar', file)
958
+ formData.append('resUploadMode', 'server')
959
+ formData.append('pathKey', 'Default')
960
+ formData.append('formType', 'file')
961
+ formData.append('useType', 'Default')
962
+ formData.append('filename', fileName)
963
+ formData.append('filesize', (blob.size / 1024 / 1024).toFixed(4))
964
+ formData.append('f_operator', this.currUser ? this.currUser.username : '')
965
+
966
+ // 上传文件
967
+ await upload(formData, this.serviceName, { headers, timeout: 600 * 1000 }).then(res => {
968
+ this.form[this.attr.model] = res.data.id
969
+ this.form.t_f_path = res.data.f_downloadpath
970
+ }).catch(error => {
971
+ // 处理上传错误
972
+ console.error(error)
973
+ })
974
+ }
975
+ },
976
+ openChangeOne (status) {
977
+ if (status) {
978
+ this.yearShowOne = true
979
+ }
980
+ },
981
+ // 得到年份选择器的值
982
+ panelChangeOne (value) {
983
+ this.yearShowOne = false
984
+ this.form[this.attr.model] = value.format('YYYY')
985
+ },
986
+ // 文件框时设置上传组件的值
987
+ setFiles (fileIds) {
988
+ if (!this.form[this.attr.model]) {
989
+ this.form[this.attr.model] = []
990
+ }
991
+ this.form[this.attr.model] = [...fileIds]
992
+ },
993
+ // 懒加载检索方法
994
+ fetchFunction (value) {
995
+ this.lastFetchId += 1
996
+ const fetchId = this.lastFetchId
997
+ this.option = []
998
+ this.searching = true
999
+ this.getData({
1000
+ word: value
1001
+ }, res => {
1002
+ if (fetchId !== this.lastFetchId) {
1003
+ return
1004
+ }
1005
+ this.option = res
1006
+ this.searching = false
1007
+ })
1008
+ },
1009
+ // 获取数据
1010
+ getData (value, callbackFun) {
1011
+ if (value !== '') {
1012
+ const logicName = this.attr.keyName
1013
+ const logic = logicName.substring(6)
1014
+ // 调用logic前设置参数
1015
+ if (this.getDataParams && this.getDataParams[this.attr.model]) {
1016
+ Object.assign(value, this.getDataParams[this.attr.model])
1017
+ }
1018
+ runLogic(logic, Object.assign(value, {
1019
+ orgId: this.currUser.orgid,
1020
+ userId: this.currUser.id
1021
+ }), this.serviceName, this.env === 'dev').then(res => {
1022
+ callbackFun(res)
1023
+ }).catch(e => {
1024
+ callbackFun([])
1025
+ console.error('获取数据失败:' + e)
1026
+ })
1027
+ }
1028
+ },
1029
+ filterOption (input, option) {
1030
+ const child = option.componentOptions.children[0]
1031
+ if (child.text) {
1032
+ return child.text.toLowerCase().indexOf(input.toLowerCase()) >= 0
1033
+ } else if (child.elm.innerText) {
1034
+ return child.elm.innerText.toLowerCase().indexOf(input.toLowerCase()) >= 0
1035
+ } else {
1036
+ return child.child.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
1037
+ }
1038
+ },
1039
+ emitFunc (func, data) {
1040
+ this.$emit('x-form-item-emit-func', func, data)
1041
+ }
1042
+ }
1043
+ }
1044
+ </script>
1045
+
1046
+ <style lang="less" scoped>
1047
+ .intervalPicker-begin {
1048
+ width: calc(50% - 14px);
1049
+ }
1050
+
1051
+ .intervalPicker-center {
1052
+ width: 30px;
1053
+ border-left: 0;
1054
+ pointer-events: none;
1055
+ }
1056
+
1057
+ .intervalPicker-end {
1058
+ width: calc(50% - 14px);
1059
+ border-left: 0;
1060
+ }
1061
+ </style>