af-mobile-client-vue3 1.0.70 → 1.0.71

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,595 +1,638 @@
1
- <script setup lang="ts">
2
- import {
3
- Area as VanArea,
4
- Calendar as VanCalendar,
5
- Checkbox as VanCheckbox,
6
- DatePicker as VanDatePicker,
7
- Field as VanField,
8
- Picker as VanPicker,
9
- Popup as VanPopup,
10
- Radio as VanRadio,
11
- RadioGroup as VanRadioGroup,
12
- Rate as VanRate,
13
- Slider as VanSlider,
14
- Stepper as VanStepper,
15
- Switch as VanSwitch,
16
- TimePicker as VanTimePicker,
17
- CheckboxGroup as vanCheckboxGroup,
18
- } from 'vant'
19
- import { computed, defineEmits, defineProps, onBeforeMount, reactive, ref } from 'vue'
20
- import { areaList } from '@vant/area-data'
21
- import { runLogic } from '@af-mobile-client-vue3/services/api/common'
22
- import Uploader from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
23
- import XSelect from '@af-mobile-client-vue3/components/core/XSelect/index.vue'
24
- import XMultiSelect from '@af-mobile-client-vue3/components/core/XMultiSelect/index.vue'
25
- import XGridDropOption from '@af-mobile-client-vue3/components/core/XGridDropOption/index.vue'
26
- import type { Numeric } from 'vant/es/utils'
27
- import { getDict } from "@af-mobile-client-vue3/utils/dictUtil";
28
- import {useRoute} from "vue-router";
29
-
30
- const props = defineProps({
31
- attr: {
32
- type: Object,
33
- },
34
- datePickerFilter: {
35
- type: Function,
36
- default: () => true,
37
- },
38
- datePickerFormatter: {
39
- type: Function,
40
- default: (type, val) => val,
41
- },
42
- mode: {
43
- type: String,
44
- default: '查询',
45
- },
46
- serviceName: {
47
- type: String,
48
- default: undefined,
49
- },
50
- // 调用logic获取数据源的追加参数
51
- getDataParams: {
52
- type: Object,
53
- default: undefined,
54
- },
55
- disabled: {
56
- type: Boolean,
57
- default: false,
58
- },
59
- rules: {
60
- type: Object,
61
- default: () => {},
62
- },
63
- modelValue: {
64
- type: [String, Number, Boolean, Array, Object],
65
- default: undefined,
66
- },
67
- showLabel: {
68
- type: Boolean,
69
- default: true,
70
- },
71
- // radio/checkbox/select/mul-select 选项数据结构
72
- columnsField: {
73
- type: Object,
74
- default: () => {
75
- return { text: 'label', value: 'value' }
76
- },
77
- },
78
-
79
- })
80
-
81
- const emits = defineEmits(['update:modelValue'])
82
- const { attr, mode, serviceName, getDataParams, columnsField } = props
83
- const calendarShow = ref(false)
84
- const option = ref([])
85
- const pickerValue = ref(undefined)
86
- const datePickerValue = ref(undefined)
87
- const timePickerValue = ref(undefined)
88
- const area = ref<any>(undefined)
89
- const calendarValue = ref<any>('')
90
- const showPicker = ref(false)
91
- const showDatePicker = ref(false)
92
- const showTimePicker = ref(false)
93
- const showArea = ref(false)
94
-
95
- const localValue = computed({
96
- get() {
97
- // if (props.modelValue !== undefined) {
98
- // return props.modelValue
99
- // }
100
- switch (props.attr.type) {
101
- case 'switch':
102
- return props.modelValue != undefined ? props.modelValue:false
103
- case 'checkbox':
104
- case 'uploader':
105
- case 'file':
106
- case 'image':
107
- case 'datePicker':
108
- case 'timePicker':
109
- case 'select':
110
- return props.modelValue != undefined ? props.modelValue:[]
111
- case 'radio':
112
- case 'rate':
113
- case 'slider':
114
- case 'area':
115
- case 'citySelect':
116
- case 'calendar':
117
- case 'textarea':
118
- case 'input':
119
- return props.modelValue != undefined ? props.modelValue:''
120
- case 'stepper':
121
- return props.modelValue != undefined ? props.modelValue:1
122
- case 'rangePicker':
123
- if(props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length>1){
124
- return`${props.modelValue[0]} ~ ${props.modelValue[1]}`
125
- }else{
126
- return props.modelValue
127
- }
128
- default:
129
- return undefined
130
- }
131
- },
132
- set(newValue) {
133
- emits('update:modelValue', newValue)
134
- },
135
- })
136
-
137
- onBeforeMount(() => {
138
- init()
139
- })
140
- const labelData = computed(()=>{
141
- return props.showLabel?attr.name:null
142
- })
143
- const readonly = computed(()=>{
144
- return attr.addOrEdit === 'readonly'
145
- })
146
- const placeholder = computed(()=>{
147
- if (attr.addOrEdit === 'readonly') {
148
- return ' 暂无内容 ~ '
149
- }else{
150
- return attr.placeholder ? attr.placeholder : `请选择${attr.name}`
151
- }
152
- })
153
- const formatDate = date => `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
154
-
155
- function onCalendarConfirm(values) {
156
- localValue.value = [formatDate(values[0]),formatDate(values[1])]
157
- calendarShow.value = false
158
- }
159
-
160
- function init() {
161
- if (attr.keyName && typeof attr.keyName === 'string') {
162
- if (attr.keyName && attr.keyName.includes('logic@')) {
163
- getData({}, (res) => {
164
- option.value = res
165
- initRadioValue()
166
- })
167
- } else if (attr.keyName && attr.keyName.includes('config@')) {
168
- const configName = attr.keyName.substring(7)
169
- getDict(configName, (result) => {
170
- if (result) {
171
- option.value = result
172
- }
173
- },serviceName)
174
- } else {
175
- initRadioValue()
176
- }
177
- }
178
- }
179
-
180
- function initRadioValue() {
181
- if ((mode === '新增' || mode === '修改') && attr.type === 'radio' && !localValue.value) {
182
- if (attr.keys && attr.keys.length > 0)
183
- localValue.value = attr.keys[0].value
184
- else if (option && option.value.length > 0)
185
- localValue.value = option[0].value
186
- }
187
- }
188
-
189
- function getData(value, callback) {
190
- if (value !== '') {
191
- const logicName = attr.keyName
192
- const logic = logicName.substring(6)
193
- // 调用logic前设置参数
194
- if (getDataParams && getDataParams[attr.model])
195
- Object.assign(value, getDataParams[attr.model])
196
-
197
- runLogic(logic, value, serviceName).then((res) => {
198
- callback(res)
199
- })
200
- }
201
- }
202
-
203
- function onPickerConfirm({ selectedOptions }) {
204
- showPicker.value = false
205
- pickerValue.value = selectedOptions[0].text
206
- emits('update:modelValue', [selectedOptions[0].text])
207
- }
208
-
209
- function onDatePickerConfirm({ selectedValues }) {
210
- showDatePicker.value = false
211
- localValue.value = selectedValues.join('-')
212
- }
213
-
214
- function onTimePickerConfirm({ selectedValues }) {
215
- showTimePicker.value = false
216
- timePickerValue.value = selectedValues.join(':')
217
- emits('update:modelValue', timePickerValue.value)
218
- }
219
-
220
- function onAreaConfirm({ selectedOptions }) {
221
- area.value = `${selectedOptions[0].text}-${selectedOptions[1].text}-${selectedOptions[2].text}`
222
- showArea.value = false
223
- emits('update:modelValue', [{
224
- province: selectedOptions[0].text,
225
- city: selectedOptions[1].text,
226
- district: selectedOptions[2].text,
227
- }])
228
- }
229
-
230
- function updateFile(files, _index) {
231
- files.forEach((file) => {
232
- if (file.content)
233
- delete file.content
234
- if (file.file)
235
- delete file.file
236
- if (file.objectUrl)
237
- delete file.objectUrl
238
- })
239
- localValue.value = files
240
- emits('update:modelValue', localValue.value)
241
- }
242
- </script>
243
-
244
- <template>
245
- <div>
246
- <!-- switch开关 -->
247
- <VanField
248
- v-if="attr.type === 'switch'"
249
- name="switch"
250
- :label="labelData"
251
- :rules="[{ required: attr.rule.required === 'true', message: `未切换${attr.name}` }]"
252
- >
253
- <template #input>
254
- <VanSwitch v-model="localValue" />
255
- </template>
256
- </VanField>
257
-
258
- <!-- 复选框 -->
259
- <!-- <VanField
260
- v-if="attr.type === 'checkbox'"
261
- name="checkbox"
262
- :label="labelData"
263
- >
264
- <template #input>
265
- <VanCheckbox v-model="localValue" shape="square" />
266
- </template>
267
- </VanField>-->
268
-
269
- <!-- 多选框-checkbox-复选框组 -->
270
- <template v-if="attr.type === 'checkbox'">
271
- <!-- 勾选 -->
272
- <VanField
273
- v-if="attr.showMode === 'checkbox' && mode != '查询'"
274
- name="checkboxGroup"
275
- :label="labelData"
276
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
277
- >
278
- <template #input>
279
- <van-checkbox-group v-model="localValue as any[]" direction="horizontal" shape="square" :disabled="readonly">
280
- <VanCheckbox v-for="(item, index) in option" :key="index" style="padding: 2px" :name="item[columnsField.value]" :shape="rules?.[attr.model].shape" :value="item[columnsField.value]">
281
- {{ item[columnsField.text] }}
282
- </VanCheckbox>
283
- </van-checkbox-group>
284
- </template>
285
- </VanField>
286
- <VanField
287
- v-if="attr.showMode === 'checkbox' && mode === '查询'"
288
- name="checkboxGroup"
289
- :label="labelData"
290
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
291
- >
292
- <template #input>
293
- <XGridDropOption
294
- v-model="localValue"
295
- :multiple="true"
296
- :columns="option"
297
- />
298
- </template>
299
- </VanField>
300
- <!-- 下拉 -->
301
- <XMultiSelect
302
- v-else
303
- :label="labelData"
304
- v-model="localValue"
305
- :readonly="readonly"
306
- :placeholder="placeholder"
307
- :columns="option"
308
- :option="attr.option ? attr.option : columnsField"
309
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
310
- />
311
- </template>
312
-
313
- <!-- 单选框 -->
314
- <VanField
315
- v-if="attr.type === 'radio' && mode != '查询'"
316
- name="radio"
317
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
318
- :label="labelData"
319
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
320
- >
321
- <template #input>
322
- <VanRadioGroup v-model="localValue" direction="horizontal" :disabled="readonly">
323
- <VanRadio v-for="(item, index) in option" :key="index" style="padding: 2px" :name="item[columnsField.value]" :value="item[columnsField.value]">
324
- {{ item[columnsField.text] }}
325
- </VanRadio>
326
- </VanRadioGroup>
327
- </template>
328
- </VanField>
329
-
330
- <!-- 单选框-查询 -->
331
- <VanField
332
- v-if="attr.type === 'radio' && mode === '查询'"
333
- name="radio"
334
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
335
- :label="labelData"
336
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
337
- >
338
- <template #input>
339
- <XGridDropOption
340
- v-model="localValue"
341
- :columns="option"
342
- />
343
- </template>
344
- </VanField>
345
-
346
- <!-- 步进器 -->
347
- <VanField
348
- v-if="attr.type === 'stepper'"
349
- name="stepper"
350
- :label="labelData"
351
- :readonly="readonly"
352
- :rules="[{ required: attr.rule.required === 'true', message: `未调整${attr.name}` }]"
353
- >
354
- <template #input>
355
- <VanStepper v-model="localValue as string" />
356
- </template>
357
- </VanField>
358
-
359
- <!-- 评分 -->
360
- <VanField
361
- v-if="attr.type === 'rate'"
362
- name="rate"
363
- :label="labelData"
364
- :readonly="readonly"
365
- :rules="[{ required: attr.rule.required === 'true', message: `未进行${attr.name}评分` }]"
366
- >
367
- <template #input>
368
- <VanRate v-model="localValue as number" />
369
- </template>
370
- </VanField>
371
-
372
- <!-- 滑块 -->
373
- <VanField
374
- v-if="attr.type === 'slider'"
375
- name="slider"
376
- :label="labelData"
377
- :readonly="readonly"
378
- :rules="[{ required: attr.rule.required === 'true', message: `未移动${attr.name}滑块` }]"
379
- >
380
- <template #input>
381
- <VanSlider v-model="localValue as number" />
382
- </template>
383
- </VanField>
384
-
385
- <!-- 图片文件上传 -->
386
- <VanField
387
- v-if="attr.type === 'image' || attr.type === 'file'"
388
- name="uploader"
389
- :label="labelData"
390
- :rules="[{ required: attr.rule.required === 'true', message: `未上传${attr.name}` }]"
391
- >
392
- <template #input>
393
- <!-- <van-uploader v-model="localValue" /> -->
394
- <Uploader
395
- upload-mode="server"
396
- :image-list="localValue as any[]"
397
- authority="admin"
398
- @update-file-list="updateFile"
399
- />
400
- </template>
401
- </VanField>
402
-
403
- <!-- 选择器 -->
404
- <VanField
405
- v-if="attr.type === 'picker'"
406
- v-model="pickerValue"
407
- name="picker"
408
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
409
- :label="labelData" readonly
410
- :readonly="readonly"
411
- is-link
412
- @click="showPicker = true"
413
- :rules="[{ required: attr.rule.required === 'true', message: `未选择${attr.name}` }]"
414
- />
415
- <VanPopup v-model:show="showPicker" round position="bottom" teleport="body">
416
- <VanPicker
417
- v-model="localValue as Numeric[]"
418
- :title="attr.name"
419
- :columns="attr.selectKey"
420
- :readonly="readonly"
421
- :columns-field-names="attr.customFieldName ? attr.customFieldName : { text: 'text', value: 'value', children: 'children' }"
422
- :confirm-button-text="attr.confirmButtonText || attr.confirmButtonText === '' ? attr.confirmButtonText : '确认'"
423
- :cancel-button-text="attr.cancelButtonText || attr.cancelButtonText === '' ? attr.cancelButtonText : '取消'"
424
- @cancel="showPicker = false"
425
- @confirm="onPickerConfirm"
426
- />
427
- </VanPopup>
428
-
429
- <!-- 日历选择-查询 -->
430
- <VanField
431
- v-if="attr.type === 'rangePicker' && mode === '查询'"
432
- v-model="localValue as string | number"
433
- is-link
434
- readonly
435
- name="rangePicker"
436
- :label="labelData"
437
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
438
- @click="calendarShow = true"
439
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
440
- />
441
- <VanCalendar
442
- switch-mode="year-month"
443
- type="range"
444
- v-model:show="calendarShow"
445
- teleport="body"
446
- :show-confirm="attr.showConfirm"
447
- @confirm="onCalendarConfirm"
448
- />
449
-
450
- <!-- 日期选择-非查询 -->
451
- <VanField
452
- v-if="(attr.type === 'datePicker' || attr.type === 'rangePicker') && mode != '查询'"
453
- v-model="localValue as string | number"
454
- name="datePicker"
455
- :label="labelData"
456
- readonly
457
- :is-link="true"
458
- :placeholder="placeholder"
459
- @click="readonly ? null: showDatePicker = true"
460
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
461
- />
462
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
463
- <VanDatePicker
464
- v-model="datePickerValue"
465
- calend
466
- :title="attr.name"
467
- :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
468
- :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
469
- :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
470
- @cancel="showDatePicker = false"
471
- @confirm="onDatePickerConfirm"
472
- />
473
- </VanPopup>
474
-
475
- <!-- 日期选择-查询 -->
476
- <VanField
477
- v-if="attr.type === 'datePicker' && mode == '查询'"
478
- v-model="localValue as string | number"
479
- name="datePicker"
480
- :label="labelData"
481
- readonly
482
- :is-link="true"
483
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
484
- @click="showDatePicker = true"
485
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
486
- />
487
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
488
- <VanDatePicker
489
- v-model="datePickerValue"
490
- calend
491
- :title="attr.name"
492
- :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
493
- :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
494
- :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
495
- :readonly="attr.readonly ? attr.readonly : false"
496
- @cancel="showDatePicker = false"
497
- @confirm="onDatePickerConfirm"
498
- />
499
- </VanPopup>
500
-
501
- <!-- 时间选择 -->
502
- <VanField
503
- v-if="attr.type === 'timePicker'"
504
- v-model="timePickerValue"
505
- name="timePicker"
506
- is-link
507
- readonly
508
- :placeholder="attr.placeholder"
509
- :label="labelData"
510
- @click="showTimePicker = true"
511
- :rules="[{ required: attr.rule.required === 'true', message: '未选择时间' }]"
512
- />
513
- <VanPopup v-model:show="showTimePicker" position="bottom" teleport="body">
514
- <VanTimePicker
515
- v-model="localValue as string[]"
516
- :title="attr.name"
517
- :columns-type="attr.columnsType ? attr.columnsType : ['hour', 'minute', 'second']"
518
- :min-time="attr.minTime ? attr.minTime : '00:00:00'"
519
- :max-time="attr.maxTime ? attr.maxTime : '23:59:59'"
520
- :readonly="attr.readonly ? attr.readonly : false"
521
- @cancel="showTimePicker = false"
522
- @confirm="onTimePickerConfirm"
523
- />
524
- </VanPopup>
525
-
526
- <!-- 省市区选择 -->
527
- <VanField
528
- v-if="attr.type === 'area' || attr.type === 'citySelect'"
529
- v-model="area"
530
- name="area"
531
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
532
- is-link
533
- readonly
534
- :label="labelData"
535
- @click="readonly ? null : showArea = true"
536
- :rules="[{ required: attr.rule.required === 'true', message: '未选择地区' }]"
537
- />
538
- <VanPopup v-model:show="showArea" position="bottom" teleport="body">
539
- <VanArea
540
- v-model="localValue as string" :title="attr.name" :area-list="areaList"
541
- @confirm="onAreaConfirm"
542
- @cancel="showArea = false"
543
- />
544
- </VanPopup>
545
-
546
- <!-- 单选下拉列表 -->
547
- <XSelect
548
- v-if="attr.type === 'select'"
549
- :label="labelData"
550
- v-model="localValue"
551
- :readonly="readonly"
552
- clearable
553
- :placeholder="placeholder"
554
- :columns="option"
555
- :option="attr.option ? attr.option : columnsField"
556
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
557
- />
558
-
559
-
560
- <!-- 文本区域 -->
561
- <VanField
562
- v-if="attr.type === 'textarea'"
563
- v-model="localValue as string"
564
- rows="3"
565
- autosize
566
- :label="labelData"
567
- type="textarea"
568
- :readonly="readonly"
569
- :maxlength="attr.maxlength"
570
- :placeholder="attr.placeholder ? attr.placeholder : `请输入${attr.name}`"
571
- show-word-limit
572
- label-align="top"
573
- :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
574
- />
575
-
576
- <!-- 文本输入框 -->
577
- <VanField
578
- v-if="attr.type === 'input'"
579
- v-model="localValue as string"
580
- :label="labelData"
581
- :required="attr.required"
582
- :type="attr.type"
583
- :readonly="readonly"
584
- :disabled="attr.disabled"
585
- :placeholder="placeholder"
586
- :error-message="attr.errorMessage"
587
- :clearable="attr.clearable"
588
- :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
589
- />
590
- </div>
591
- </template>
592
-
593
- <style scoped>
594
-
595
- </style>
1
+ <script setup lang="ts">
2
+ import {
3
+ Area as VanArea,
4
+ Calendar as VanCalendar,
5
+ Checkbox as VanCheckbox,
6
+ DatePicker as VanDatePicker,
7
+ Field as VanField,
8
+ Picker as VanPicker,
9
+ Popup as VanPopup,
10
+ Radio as VanRadio,
11
+ RadioGroup as VanRadioGroup,
12
+ Rate as VanRate,
13
+ Slider as VanSlider,
14
+ Stepper as VanStepper,
15
+ Switch as VanSwitch,
16
+ TimePicker as VanTimePicker,
17
+ CheckboxGroup as vanCheckboxGroup,
18
+ } from 'vant'
19
+ import { computed, defineEmits, defineProps, getCurrentInstance, onBeforeMount, ref, watch } from 'vue'
20
+ import { areaList } from '@vant/area-data'
21
+ import { runLogic } from '@af-mobile-client-vue3/services/api/common'
22
+ import Uploader from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
23
+ import XSelect from '@af-mobile-client-vue3/components/core/XSelect/index.vue'
24
+ import XMultiSelect from '@af-mobile-client-vue3/components/core/XMultiSelect/index.vue'
25
+ import XGridDropOption from '@af-mobile-client-vue3/components/core/XGridDropOption/index.vue'
26
+ import type { Numeric } from 'vant/es/utils'
27
+ import { getDict } from '@af-mobile-client-vue3/utils/dictUtil'
28
+ import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
29
+ import { debounce } from 'lodash-es'
30
+
31
+ const props = defineProps({
32
+ attr: {
33
+ type: Object,
34
+ },
35
+ form: {
36
+ type: Object,
37
+ },
38
+ datePickerFilter: {
39
+ type: Function,
40
+ default: () => true,
41
+ },
42
+ datePickerFormatter: {
43
+ type: Function,
44
+ default: (type, val) => val,
45
+ },
46
+ mode: {
47
+ type: String,
48
+ default: '查询',
49
+ },
50
+ serviceName: {
51
+ type: String,
52
+ default: undefined,
53
+ },
54
+ // 调用logic获取数据源的追加参数
55
+ getDataParams: {
56
+ type: Object,
57
+ default: undefined,
58
+ },
59
+ disabled: {
60
+ type: Boolean,
61
+ default: false,
62
+ },
63
+ rules: {
64
+ type: Object,
65
+ default: () => {},
66
+ },
67
+ modelValue: {
68
+ type: [String, Number, Boolean, Array, Object],
69
+ default: undefined,
70
+ },
71
+ showLabel: {
72
+ type: Boolean,
73
+ default: true,
74
+ },
75
+ // radio/checkbox/select/mul-select 选项数据结构
76
+ columnsField: {
77
+ type: Object,
78
+ default: () => {
79
+ return { text: 'label', value: 'value' }
80
+ },
81
+ },
82
+
83
+ })
84
+
85
+ const emits = defineEmits(['update:modelValue'])
86
+ const { attr, form, mode, serviceName, getDataParams, columnsField } = props
87
+ const calendarShow = ref(false)
88
+ const option = ref([])
89
+ const pickerValue = ref(undefined)
90
+ const datePickerValue = ref(undefined)
91
+ const timePickerValue = ref(undefined)
92
+ const area = ref<any>(undefined)
93
+ const showPicker = ref(false)
94
+ const showDatePicker = ref(false)
95
+ const showTimePicker = ref(false)
96
+ const showArea = ref(false)
97
+ // 是否展示当前项
98
+ const showItem = ref(true)
99
+
100
+ // 当前组件实例(不推荐使用,可能会在后续的版本更迭中调整,暂时用来绑定函数的上下文)
101
+ const currInst = getCurrentInstance()
102
+
103
+ // 配置中心->表单项变更触发函数
104
+ const dataChangeFunc = debounce(async () => {
105
+ if (attr.dataChangeFunc)
106
+ await executeStrFunctionByContext(currInst, attr.dataChangeFunc, [form, attr, null, mode])
107
+ }, 500)
108
+
109
+ // 配置中心->表单项展示函数
110
+ const showFormItemFunc = debounce(async () => {
111
+ if (attr.showFormItemFunc) {
112
+ const obj = await executeStrFunctionByContext(currInst, attr.showFormItemFunc, [form, attr, null, mode])
113
+ // 判断是 bool 还是 obj 兼容
114
+ if (typeof obj === 'boolean') {
115
+ showItem.value = obj
116
+ }
117
+ else if (obj && typeof obj === 'object') {
118
+ // obj 是一个对象,并且不是数组
119
+ showItem.value = obj?.show
120
+ }
121
+ }
122
+ }, 500)
123
+
124
+ const localValue = computed({
125
+ get() {
126
+ // if (props.modelValue !== undefined) {
127
+ // return props.modelValue
128
+ // }
129
+ switch (props.attr.type) {
130
+ case 'switch':
131
+ return props.modelValue !== undefined ? props.modelValue : false
132
+ case 'checkbox':
133
+ case 'uploader':
134
+ case 'file':
135
+ case 'image':
136
+ case 'datePicker':
137
+ case 'timePicker':
138
+ case 'select':
139
+ return props.modelValue !== undefined ? props.modelValue : []
140
+ case 'radio':
141
+ case 'rate':
142
+ case 'slider':
143
+ case 'area':
144
+ case 'citySelect':
145
+ case 'calendar':
146
+ case 'textarea':
147
+ case 'input':
148
+ return props.modelValue !== undefined ? props.modelValue : ''
149
+ case 'stepper':
150
+ return props.modelValue !== undefined ? props.modelValue : 1
151
+ case 'rangePicker':
152
+ if (props.modelValue && Array.isArray(props.modelValue) && props.modelValue.length > 1)
153
+ return `${props.modelValue[0]} ~ ${props.modelValue[1]}`
154
+
155
+ else
156
+ return props.modelValue
157
+
158
+ default:
159
+ return undefined
160
+ }
161
+ },
162
+ set(newValue) {
163
+ emits('update:modelValue', newValue)
164
+ dataChangeFunc()
165
+ },
166
+ })
167
+
168
+ onBeforeMount(() => {
169
+ init()
170
+ showFormItemFunc()
171
+ dataChangeFunc()
172
+ })
173
+ // 是否展示表单左侧label文字
174
+ const labelData = computed(() => {
175
+ return props.showLabel ? attr.name : null
176
+ })
177
+ // 是否只读
178
+ const readonly = computed(() => {
179
+ return attr.addOrEdit === 'readonly'
180
+ })
181
+ // 提示内容
182
+ const placeholder = computed(() => {
183
+ if (attr.addOrEdit === 'readonly')
184
+ return ' 暂无内容 ~ '
185
+ else
186
+ return attr.placeholder ? attr.placeholder : `请选择${attr.name}`
187
+ })
188
+ // 登录信息 (可以在配置的动态函数中使用 this.setupState 获取到当前组件内的全部函数和变量 例:this.setupState.userState)
189
+
190
+ const formatDate = date => `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
191
+
192
+ function onCalendarConfirm(values) {
193
+ localValue.value = [formatDate(values[0]), formatDate(values[1])]
194
+ calendarShow.value = false
195
+ }
196
+
197
+ function init() {
198
+ if (attr.keyName && typeof attr.keyName === 'string') {
199
+ if (attr.keyName && attr.keyName.includes('logic@')) {
200
+ getData({}, (res) => {
201
+ option.value = res
202
+ initRadioValue()
203
+ })
204
+ }
205
+ else if (attr.keyName && attr.keyName.includes('config@')) {
206
+ const configName = attr.keyName.substring(7)
207
+ getDict(configName, (result) => {
208
+ if (result)
209
+ option.value = result
210
+ }, serviceName)
211
+ }
212
+ else {
213
+ initRadioValue()
214
+ }
215
+ }
216
+ }
217
+
218
+ function initRadioValue() {
219
+ if ((mode === '新增' || mode === '修改') && attr.type === 'radio' && !localValue.value) {
220
+ if (attr.keys && attr.keys.length > 0)
221
+ localValue.value = attr.keys[0].value
222
+ else if (option.value && option.value.length > 0)
223
+ localValue.value = option.value[0].value
224
+ }
225
+ }
226
+
227
+ function getData(value, callback) {
228
+ if (value !== '') {
229
+ const logicName = attr.keyName
230
+ const logic = logicName.substring(6)
231
+ // 调用logic前设置参数
232
+ if (getDataParams && getDataParams[attr.model])
233
+ Object.assign(value, getDataParams[attr.model])
234
+
235
+ runLogic(logic, value, serviceName).then((res) => {
236
+ callback(res)
237
+ })
238
+ }
239
+ }
240
+
241
+ function onPickerConfirm({ selectedOptions }) {
242
+ showPicker.value = false
243
+ pickerValue.value = selectedOptions[0].text
244
+ emits('update:modelValue', [selectedOptions[0].text])
245
+ }
246
+
247
+ function onDatePickerConfirm({ selectedValues }) {
248
+ showDatePicker.value = false
249
+ localValue.value = selectedValues.join('-')
250
+ }
251
+
252
+ function onTimePickerConfirm({ selectedValues }) {
253
+ showTimePicker.value = false
254
+ timePickerValue.value = selectedValues.join(':')
255
+ emits('update:modelValue', timePickerValue.value)
256
+ }
257
+
258
+ function onAreaConfirm({ selectedOptions }) {
259
+ area.value = `${selectedOptions[0].text}-${selectedOptions[1].text}-${selectedOptions[2].text}`
260
+ showArea.value = false
261
+ emits('update:modelValue', [{
262
+ province: selectedOptions[0].text,
263
+ city: selectedOptions[1].text,
264
+ district: selectedOptions[2].text,
265
+ }])
266
+ }
267
+
268
+ function updateFile(files, _index) {
269
+ files.forEach((file) => {
270
+ if (file.content)
271
+ delete file.content
272
+ if (file.file)
273
+ delete file.file
274
+ if (file.objectUrl)
275
+ delete file.objectUrl
276
+ })
277
+ localValue.value = files
278
+ emits('update:modelValue', localValue.value)
279
+ }
280
+ // 监听表单发生变化后触发展示函数
281
+ watch(form, (_oldVal, _newVal) => {
282
+ showFormItemFunc()
283
+ })
284
+ </script>
285
+
286
+ <template>
287
+ <div>
288
+ <!-- switch开关 -->
289
+ <VanField
290
+ v-if="attr.type === 'switch' && showItem"
291
+ name="switch"
292
+ :label="labelData"
293
+ :rules="[{ required: attr.rule.required === 'true', message: `未切换${attr.name}` }]"
294
+ >
295
+ <template #input>
296
+ <VanSwitch v-model="localValue" />
297
+ </template>
298
+ </VanField>
299
+
300
+ <!-- 复选框 -->
301
+ <!-- <VanField
302
+ v-if="attr.type === 'checkbox'"
303
+ name="checkbox"
304
+ :label="labelData"
305
+ >
306
+ <template #input>
307
+ <VanCheckbox v-model="localValue" shape="square" />
308
+ </template>
309
+ </VanField> -->
310
+
311
+ <!-- 多选框-checkbox-复选框组 -->
312
+ <template v-if="attr.type === 'checkbox' && showItem">
313
+ <!-- 勾选 -->
314
+ <VanField
315
+ v-if="attr.showMode === 'checkbox' && mode !== '查询'"
316
+ name="checkboxGroup"
317
+ :label="labelData"
318
+ :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
319
+ >
320
+ <template #input>
321
+ <van-checkbox-group v-model="localValue as any[]" direction="horizontal" shape="square" :disabled="readonly">
322
+ <VanCheckbox v-for="(item, index) in option" :key="index" style="padding: 2px" :name="item[columnsField.value]" :shape="rules?.[attr.model].shape" :value="item[columnsField.value]">
323
+ {{ item[columnsField.text] }}
324
+ </VanCheckbox>
325
+ </van-checkbox-group>
326
+ </template>
327
+ </VanField>
328
+ <VanField
329
+ v-if="attr.showMode === 'checkbox' && mode === '查询'"
330
+ name="checkboxGroup"
331
+ :label="labelData"
332
+ :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
333
+ >
334
+ <template #input>
335
+ <XGridDropOption
336
+ v-model="(localValue as string[])"
337
+ :column-num="labelData ? 3 : 4"
338
+ :multiple="true"
339
+ :columns="option"
340
+ />
341
+ </template>
342
+ </VanField>
343
+ <!-- 下拉 -->
344
+ <XMultiSelect
345
+ v-else
346
+ v-model="localValue"
347
+ :label="labelData"
348
+ :readonly="readonly"
349
+ :placeholder="placeholder"
350
+ :columns="option"
351
+ :option="attr.option ? attr.option : columnsField"
352
+ :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
353
+ />
354
+ </template>
355
+
356
+ <!-- 单选框 -->
357
+ <VanField
358
+ v-if="attr.type === 'radio' && mode !== '查询' && showItem"
359
+ name="radio"
360
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
361
+ :label="labelData"
362
+ :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
363
+ >
364
+ <template #input>
365
+ <VanRadioGroup v-model="localValue" direction="horizontal" :disabled="readonly">
366
+ <VanRadio v-for="(item, index) in option" :key="index" style="padding: 2px" :name="item[columnsField.value]" :value="item[columnsField.value]">
367
+ {{ item[columnsField.text] }}
368
+ </VanRadio>
369
+ </VanRadioGroup>
370
+ </template>
371
+ </VanField>
372
+
373
+ <!-- 单选框-查询 -->
374
+ <VanField
375
+ v-if="attr.type === 'radio' && mode === '查询' && showItem"
376
+ name="radio"
377
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
378
+ :label="labelData"
379
+ :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
380
+ >
381
+ <template #input>
382
+ <XGridDropOption
383
+ v-model="(localValue as string)"
384
+ :column-num="labelData ? 3 : 4"
385
+ :columns="option"
386
+ />
387
+ </template>
388
+ </VanField>
389
+
390
+ <!-- 步进器 -->
391
+ <VanField
392
+ v-if="attr.type === 'stepper' && showItem"
393
+ name="stepper"
394
+ :label="labelData"
395
+ :readonly="readonly"
396
+ :rules="[{ required: attr.rule.required === 'true', message: `未调整${attr.name}` }]"
397
+ >
398
+ <template #input>
399
+ <VanStepper v-model="(localValue as string)" />
400
+ </template>
401
+ </VanField>
402
+
403
+ <!-- 评分 -->
404
+ <VanField
405
+ v-if="attr.type === 'rate' && showItem"
406
+ name="rate"
407
+ :label="labelData"
408
+ :readonly="readonly"
409
+ :rules="[{ required: attr.rule.required === 'true', message: `未进行${attr.name}评分` }]"
410
+ >
411
+ <template #input>
412
+ <VanRate v-model="(localValue as number)" />
413
+ </template>
414
+ </VanField>
415
+
416
+ <!-- 滑块 -->
417
+ <VanField
418
+ v-if="attr.type === 'slider' && showItem"
419
+ name="slider"
420
+ :label="labelData"
421
+ :readonly="readonly"
422
+ :rules="[{ required: attr.rule.required === 'true', message: `未移动${attr.name}滑块` }]"
423
+ >
424
+ <template #input>
425
+ <VanSlider v-model="(localValue as number)" />
426
+ </template>
427
+ </VanField>
428
+
429
+ <!-- 图片文件上传 -->
430
+ <VanField
431
+ v-if="(attr.type === 'image' || attr.type === 'file') && showItem"
432
+ name="uploader"
433
+ :label="labelData"
434
+ :rules="[{ required: attr.rule.required === 'true', message: `未上传${attr.name}` }]"
435
+ >
436
+ <template #input>
437
+ <!-- <van-uploader v-model="localValue" /> -->
438
+ <Uploader
439
+ upload-mode="server"
440
+ :image-list="(localValue as any[])"
441
+ authority="admin"
442
+ @update-file-list="updateFile"
443
+ />
444
+ </template>
445
+ </VanField>
446
+
447
+ <!-- 选择器 -->
448
+ <VanField
449
+ v-if="attr.type === 'picker' && showItem"
450
+ v-model="pickerValue"
451
+ name="picker"
452
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
453
+ :label="labelData"
454
+ :readonly="readonly"
455
+ is-link
456
+ :rules="[{ required: attr.rule.required === 'true', message: `未选择${attr.name}` }]"
457
+ @click="showPicker = true"
458
+ />
459
+ <VanPopup v-model:show="showPicker" round position="bottom" teleport="body">
460
+ <VanPicker
461
+ v-model="(localValue as Numeric[])"
462
+ :title="attr.name"
463
+ :columns="attr.selectKey"
464
+ :readonly="readonly"
465
+ :columns-field-names="attr.customFieldName ? attr.customFieldName : { text: 'text', value: 'value', children: 'children' }"
466
+ :confirm-button-text="attr.confirmButtonText || attr.confirmButtonText === '' ? attr.confirmButtonText : '确认'"
467
+ :cancel-button-text="attr.cancelButtonText || attr.cancelButtonText === '' ? attr.cancelButtonText : '取消'"
468
+ @cancel="showPicker = false"
469
+ @confirm="onPickerConfirm"
470
+ />
471
+ </VanPopup>
472
+
473
+ <!-- 日历选择-查询 -->
474
+ <VanField
475
+ v-if="attr.type === 'rangePicker' && mode === '查询' && showItem"
476
+ v-model="(localValue as string | number)"
477
+ is-link
478
+ readonly
479
+ name="rangePicker"
480
+ :label="labelData"
481
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
482
+ :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
483
+ @click="calendarShow = true"
484
+ />
485
+ <VanCalendar
486
+ v-model:show="calendarShow"
487
+ switch-mode="year-month"
488
+ type="range"
489
+ teleport="body"
490
+ :show-confirm="attr.showConfirm"
491
+ @confirm="onCalendarConfirm"
492
+ />
493
+
494
+ <!-- 日期选择-非查询 -->
495
+ <VanField
496
+ v-if="(attr.type === 'datePicker' || attr.type === 'rangePicker') && mode !== '查询' && showItem"
497
+ v-model="(localValue as string | number)"
498
+ name="datePicker"
499
+ :label="labelData"
500
+ readonly
501
+ :is-link="true"
502
+ :placeholder="placeholder"
503
+ :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
504
+ @click="readonly ? null : showDatePicker = true"
505
+ />
506
+ <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
507
+ <VanDatePicker
508
+ v-model="datePickerValue"
509
+ calend
510
+ :title="attr.name"
511
+ :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
512
+ :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
513
+ :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
514
+ @cancel="showDatePicker = false"
515
+ @confirm="onDatePickerConfirm"
516
+ />
517
+ </VanPopup>
518
+
519
+ <!-- 日期选择-查询 -->
520
+ <VanField
521
+ v-if="attr.type === 'datePicker' && mode === '查询' && showItem"
522
+ v-model="(localValue as string | number)"
523
+ name="datePicker"
524
+ :label="labelData"
525
+ readonly
526
+ :is-link="true"
527
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
528
+ :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
529
+ @click="showDatePicker = true"
530
+ />
531
+ <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
532
+ <VanDatePicker
533
+ v-model="datePickerValue"
534
+ calend
535
+ :title="attr.name"
536
+ :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
537
+ :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
538
+ :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
539
+ :readonly="attr.readonly ? attr.readonly : false"
540
+ @cancel="showDatePicker = false"
541
+ @confirm="onDatePickerConfirm"
542
+ />
543
+ </VanPopup>
544
+
545
+ <!-- 时间选择 -->
546
+ <VanField
547
+ v-if="attr.type === 'timePicker' && showItem"
548
+ v-model="timePickerValue"
549
+ name="timePicker"
550
+ is-link
551
+ readonly
552
+ :placeholder="attr.placeholder"
553
+ :label="labelData"
554
+ :rules="[{ required: attr.rule.required === 'true', message: '未选择时间' }]"
555
+ @click="showTimePicker = true"
556
+ />
557
+ <VanPopup v-model:show="showTimePicker" position="bottom" teleport="body">
558
+ <VanTimePicker
559
+ v-model="localValue as string[]"
560
+ :title="attr.name"
561
+ :columns-type="attr.columnsType ? attr.columnsType : ['hour', 'minute', 'second']"
562
+ :min-time="attr.minTime ? attr.minTime : '00:00:00'"
563
+ :max-time="attr.maxTime ? attr.maxTime : '23:59:59'"
564
+ :readonly="attr.readonly ? attr.readonly : false"
565
+ @cancel="showTimePicker = false"
566
+ @confirm="onTimePickerConfirm"
567
+ />
568
+ </VanPopup>
569
+
570
+ <!-- 省市区选择 -->
571
+ <VanField
572
+ v-if="(attr.type === 'area' || attr.type === 'citySelect') && showItem"
573
+ v-model="area"
574
+ name="area"
575
+ :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
576
+ is-link
577
+ readonly
578
+ :label="labelData"
579
+ :rules="[{ required: attr.rule.required === 'true', message: '未选择地区' }]"
580
+ @click="readonly ? null : showArea = true"
581
+ />
582
+ <VanPopup v-model:show="showArea" position="bottom" teleport="body">
583
+ <VanArea
584
+ v-model="localValue as string" :title="attr.name" :area-list="areaList"
585
+ @confirm="onAreaConfirm"
586
+ @cancel="showArea = false"
587
+ />
588
+ </VanPopup>
589
+
590
+ <!-- 单选下拉列表 -->
591
+ <XSelect
592
+ v-if="attr.type === 'select' && showItem"
593
+ v-model="localValue"
594
+ :label="labelData"
595
+ :readonly="readonly"
596
+ clearable
597
+ :placeholder="placeholder"
598
+ :columns="option"
599
+ :option="attr.option ? attr.option : columnsField"
600
+ :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
601
+ />
602
+
603
+ <!-- 文本区域 -->
604
+ <VanField
605
+ v-if="attr.type === 'textarea' && showItem"
606
+ v-model="(localValue as string)"
607
+ rows="3"
608
+ autosize
609
+ :label="labelData"
610
+ type="textarea"
611
+ :readonly="readonly"
612
+ :maxlength="attr.maxlength"
613
+ :placeholder="attr.placeholder ? attr.placeholder : `请输入${attr.name}`"
614
+ show-word-limit
615
+ label-align="top"
616
+ :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
617
+ />
618
+
619
+ <!-- 文本输入框 -->
620
+ <VanField
621
+ v-if="attr.type === 'input' && showItem"
622
+ v-model="(localValue as string)"
623
+ :label="labelData"
624
+ :required="attr.required"
625
+ :type="attr.type"
626
+ :readonly="readonly"
627
+ :disabled="attr.disabled"
628
+ :placeholder="placeholder"
629
+ :error-message="attr.errorMessage"
630
+ :clearable="attr.clearable"
631
+ :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
632
+ />
633
+ </div>
634
+ </template>
635
+
636
+ <style scoped>
637
+
638
+ </style>