af-mobile-client-vue3 1.0.69 → 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,579 +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 formatDate = date => `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
144
-
145
- function onCalendarConfirm(values) {
146
- localValue.value = [formatDate(values[0]),formatDate(values[1])]
147
- calendarShow.value = false
148
- }
149
-
150
- function init() {
151
- if (attr.keyName && typeof attr.keyName === 'string') {
152
- if (attr.keyName && attr.keyName.includes('logic@')) {
153
- getData({}, (res) => {
154
- option.value = res
155
- initRadioValue()
156
- })
157
- } else if (attr.keyName && attr.keyName.includes('config@')) {
158
- const configName = attr.keyName.substring(7)
159
- getDict(configName, (result) => {
160
- if (result) {
161
- option.value = result
162
- }
163
- },serviceName)
164
- } else {
165
- initRadioValue()
166
- }
167
- }
168
- }
169
-
170
- function initRadioValue() {
171
- if (mode === '新增/修改' && attr.type === 'radio' && !localValue.value) {
172
- if (attr.keys && attr.keys.length > 0)
173
- localValue.value = attr.keys[0].value
174
- else if (option && option.value.length > 0)
175
- localValue.value = option[0].value
176
- }
177
- }
178
-
179
- function getData(value, callback) {
180
- if (value !== '') {
181
- const logicName = attr.keyName
182
- const logic = logicName.substring(6)
183
- // 调用logic前设置参数
184
- if (getDataParams && getDataParams[attr.model])
185
- Object.assign(value, getDataParams[attr.model])
186
-
187
- runLogic(logic, value, serviceName).then((res) => {
188
- callback(res)
189
- })
190
- }
191
- }
192
-
193
- function onPickerConfirm({ selectedOptions }) {
194
- showPicker.value = false
195
- pickerValue.value = selectedOptions[0].text
196
- emits('update:modelValue', [selectedOptions[0].text])
197
- }
198
-
199
- function onDatePickerConfirm({ selectedValues }) {
200
- showDatePicker.value = false
201
- localValue.value = selectedValues.join('-')
202
- }
203
-
204
- function onTimePickerConfirm({ selectedValues }) {
205
- showTimePicker.value = false
206
- timePickerValue.value = selectedValues.join(':')
207
- emits('update:modelValue', timePickerValue.value)
208
- }
209
-
210
- function onAreaConfirm({ selectedOptions }) {
211
- area.value = `${selectedOptions[0].text}-${selectedOptions[1].text}-${selectedOptions[2].text}`
212
- showArea.value = false
213
- emits('update:modelValue', [{
214
- province: selectedOptions[0].text,
215
- city: selectedOptions[1].text,
216
- district: selectedOptions[2].text,
217
- }])
218
- }
219
-
220
- function updateFile(files, _index) {
221
- files.forEach((file) => {
222
- if (file.content)
223
- delete file.content
224
- if (file.file)
225
- delete file.file
226
- if (file.objectUrl)
227
- delete file.objectUrl
228
- })
229
- localValue.value = files
230
- emits('update:modelValue', localValue.value)
231
- }
232
- </script>
233
-
234
- <template>
235
- <div>
236
- <!-- switch开关 -->
237
- <VanField
238
- v-if="attr.type === 'switch'"
239
- name="switch"
240
- :label="labelData"
241
- :rules="[{ required: attr.rule.required === 'true', message: `未切换${attr.name}` }]"
242
- >
243
- <template #input>
244
- <VanSwitch v-model="localValue" />
245
- </template>
246
- </VanField>
247
-
248
- <!-- 复选框 -->
249
- <!-- <VanField
250
- v-if="attr.type === 'checkbox'"
251
- name="checkbox"
252
- :label="labelData"
253
- >
254
- <template #input>
255
- <VanCheckbox v-model="localValue" shape="square" />
256
- </template>
257
- </VanField>-->
258
-
259
- <!-- 多选框-checkbox-复选框组 -->
260
- <template v-if="attr.type === 'checkbox'">
261
- <!-- 勾选 -->
262
- <VanField
263
- v-if="attr.showMode === 'checkbox' && mode != '查询'"
264
- name="checkboxGroup"
265
- :label="labelData"
266
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
267
- >
268
- <template #input>
269
- <van-checkbox-group v-model="localValue as any[]" direction="horizontal" shape="square">
270
- <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]">
271
- {{ item[columnsField.text] }}
272
- </VanCheckbox>
273
- </van-checkbox-group>
274
- </template>
275
- </VanField>
276
- <VanField
277
- v-if="attr.showMode === 'checkbox' && mode === '查询'"
278
- name="checkboxGroup"
279
- :label="labelData"
280
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
281
- >
282
- <template #input>
283
- <XGridDropOption
284
- v-model="localValue"
285
- :multiple="true"
286
- :columns="option"
287
- />
288
- </template>
289
- </VanField>
290
- <!-- 下拉 -->
291
- <XMultiSelect
292
- v-else
293
- :label="labelData"
294
- v-model="localValue"
295
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
296
- :columns="option"
297
- :option="attr.option ? attr.option : columnsField"
298
- :rules="[{ required: attr.rule.required === 'true', message: '至少选择一项' }]"
299
- />
300
- </template>
301
-
302
- <!-- 单选框 -->
303
- <VanField
304
- v-if="attr.type === 'radio' && mode != '查询'"
305
- name="radio"
306
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
307
- :label="labelData"
308
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
309
- >
310
- <template #input>
311
- <VanRadioGroup v-model="localValue" direction="horizontal">
312
- <VanRadio v-for="(item, index) in option" :key="index" style="padding: 2px" :name="item[columnsField.value]" :value="item[columnsField.value]">
313
- {{ item[columnsField.text] }}
314
- </VanRadio>
315
- </VanRadioGroup>
316
- </template>
317
- </VanField>
318
-
319
- <!-- 单选框-查询 -->
320
- <VanField
321
- v-if="attr.type === 'radio' && mode === '查询'"
322
- name="radio"
323
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
324
- :label="labelData"
325
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
326
- >
327
- <template #input>
328
- <XGridDropOption
329
- v-model="localValue"
330
- :columns="option"
331
- />
332
- </template>
333
- </VanField>
334
-
335
- <!-- 步进器 -->
336
- <VanField
337
- v-if="attr.type === 'stepper'"
338
- name="stepper"
339
- :label="labelData"
340
- :rules="[{ required: attr.rule.required === 'true', message: `未调整${attr.name}` }]"
341
- >
342
- <template #input>
343
- <VanStepper v-model="localValue as string" />
344
- </template>
345
- </VanField>
346
-
347
- <!-- 评分 -->
348
- <VanField
349
- v-if="attr.type === 'rate'"
350
- name="rate"
351
- :label="labelData"
352
- :rules="[{ required: attr.rule.required === 'true', message: `未进行${attr.name}评分` }]"
353
- >
354
- <template #input>
355
- <VanRate v-model="localValue as number" />
356
- </template>
357
- </VanField>
358
-
359
- <!-- 滑块 -->
360
- <VanField
361
- v-if="attr.type === 'slider'"
362
- name="slider"
363
- :label="labelData"
364
- :rules="[{ required: attr.rule.required === 'true', message: `未移动${attr.name}滑块` }]"
365
- >
366
- <template #input>
367
- <VanSlider v-model="localValue as number" />
368
- </template>
369
- </VanField>
370
-
371
- <!-- 图片文件上传 -->
372
- <VanField
373
- v-if="attr.type === 'image' || attr.type === 'file'"
374
- name="uploader"
375
- :label="labelData"
376
- :rules="[{ required: attr.rule.required === 'true', message: `未上传${attr.name}` }]"
377
- >
378
- <template #input>
379
- <!-- <van-uploader v-model="localValue" /> -->
380
- <Uploader
381
- upload-mode="server"
382
- :image-list="localValue as any[]"
383
- authority="admin"
384
- @update-file-list="updateFile"
385
- />
386
- </template>
387
- </VanField>
388
-
389
- <!-- 选择器 -->
390
- <VanField
391
- v-if="attr.type === 'picker'"
392
- v-model="pickerValue"
393
- name="picker"
394
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
395
- :label="labelData" readonly
396
- is-link
397
- @click="showPicker = true"
398
- :rules="[{ required: attr.rule.required === 'true', message: `未选择${attr.name}` }]"
399
- />
400
- <VanPopup v-model:show="showPicker" round position="bottom" teleport="body">
401
- <VanPicker
402
- v-model="localValue as Numeric[]"
403
- :title="attr.name"
404
- :columns="attr.selectKey"
405
- :readonly="attr.readonly"
406
- :columns-field-names="attr.customFieldName ? attr.customFieldName : { text: 'text', value: 'value', children: 'children' }"
407
- :confirm-button-text="attr.confirmButtonText || attr.confirmButtonText === '' ? attr.confirmButtonText : '确认'"
408
- :cancel-button-text="attr.cancelButtonText || attr.cancelButtonText === '' ? attr.cancelButtonText : '取消'"
409
- @cancel="showPicker = false"
410
- @confirm="onPickerConfirm"
411
- />
412
- </VanPopup>
413
-
414
- <!-- 日历选择-查询 -->
415
- <VanField
416
- v-if="attr.type === 'rangePicker' && mode === '查询'"
417
- v-model="localValue as string | number"
418
- is-link
419
- readonly
420
- name="rangePicker"
421
- :label="labelData"
422
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
423
- @click="calendarShow = true"
424
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
425
- />
426
- <VanCalendar
427
- switch-mode="year-month"
428
- type="range"
429
- v-model:show="calendarShow"
430
- teleport="body"
431
- :show-confirm="attr.showConfirm"
432
- @confirm="onCalendarConfirm"
433
- />
434
-
435
- <!-- 日期选择-非查询 -->
436
- <VanField
437
- v-if="(attr.type === 'datePicker' || attr.type === 'rangePicker') && mode != '查询'"
438
- v-model="localValue as string | number"
439
- name="datePicker"
440
- :label="labelData"
441
- readonly
442
- :is-link="true"
443
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
444
- @click="showDatePicker = true"
445
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
446
- />
447
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
448
- <VanDatePicker
449
- v-model="datePickerValue"
450
- calend
451
- :title="attr.name"
452
- :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
453
- :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
454
- :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
455
- :readonly="attr.readonly ? attr.readonly : false"
456
- @cancel="showDatePicker = false"
457
- @confirm="onDatePickerConfirm"
458
- />
459
- </VanPopup>
460
-
461
- <!-- 日期选择-查询 -->
462
- <VanField
463
- v-if="attr.type === 'datePicker' && mode == '查询'"
464
- v-model="localValue as string | number"
465
- name="datePicker"
466
- :label="labelData"
467
- readonly
468
- :is-link="true"
469
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
470
- @click="showDatePicker = true"
471
- :rules="[{ required: attr.rule.required === 'true', message: '未选择日期' }]"
472
- />
473
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
474
- <VanDatePicker
475
- v-model="datePickerValue"
476
- calend
477
- :title="attr.name"
478
- :confirm-button-text="attr.confirmButtonText ? attr.confirmButtonText : '确认'"
479
- :cancel-button-text="attr.cancelButtonText ? attr.cancelButtonText : '取消'"
480
- :columns-type="attr.columnsType ? attr.columnsType : ['year', 'month', 'day']"
481
- :readonly="attr.readonly ? attr.readonly : false"
482
- @cancel="showDatePicker = false"
483
- @confirm="onDatePickerConfirm"
484
- />
485
- </VanPopup>
486
-
487
- <!-- 时间选择 -->
488
- <VanField
489
- v-if="attr.type === 'timePicker'"
490
- v-model="timePickerValue"
491
- name="timePicker"
492
- is-link
493
- readonly
494
- :placeholder="attr.placeholder"
495
- :label="labelData"
496
- @click="showTimePicker = true"
497
- :rules="[{ required: attr.rule.required === 'true', message: '未选择时间' }]"
498
- />
499
- <VanPopup v-model:show="showTimePicker" position="bottom" teleport="body">
500
- <VanTimePicker
501
- v-model="localValue as string[]"
502
- :title="attr.name"
503
- :columns-type="attr.columnsType ? attr.columnsType : ['hour', 'minute', 'second']"
504
- :min-time="attr.minTime ? attr.minTime : '00:00:00'"
505
- :max-time="attr.maxTime ? attr.maxTime : '23:59:59'"
506
- :readonly="attr.readonly ? attr.readonly : false"
507
- @cancel="showTimePicker = false"
508
- @confirm="onTimePickerConfirm"
509
- />
510
- </VanPopup>
511
-
512
- <!-- 省市区选择 -->
513
- <VanField
514
- v-if="attr.type === 'area' || attr.type === 'citySelect'"
515
- v-model="area"
516
- name="area"
517
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
518
- is-link
519
- readonly
520
- :label="labelData"
521
- @click="showArea = true"
522
- :rules="[{ required: attr.rule.required === 'true', message: '未选择地区' }]"
523
- />
524
- <VanPopup v-model:show="showArea" position="bottom" teleport="body">
525
- <VanArea
526
- v-model="localValue as string" :title="attr.name" :area-list="areaList"
527
- @confirm="onAreaConfirm"
528
- @cancel="showArea = false"
529
- />
530
- </VanPopup>
531
-
532
- <!-- 单选下拉列表 -->
533
- <XSelect
534
- v-if="attr.type === 'select'"
535
- v-model="localValue"
536
- :label="labelData"
537
- clearable
538
- :placeholder="attr.placeholder ? attr.placeholder : `请选择${attr.name}`"
539
- :columns="option"
540
- :option="attr.option ? attr.option : columnsField"
541
- :rules="[{ required: attr.rule.required === 'true', message: '必须选择一项' }]"
542
- />
543
-
544
-
545
- <!-- 文本区域 -->
546
- <VanField
547
- v-if="attr.type === 'textarea'"
548
- v-model="localValue as string"
549
- rows="3"
550
- autosize
551
- :label="labelData"
552
- type="textarea"
553
- :maxlength="attr.maxlength"
554
- :placeholder="attr.placeholder ? attr.placeholder : `请输入${attr.name}`"
555
- show-word-limit
556
- label-align="top"
557
- :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
558
- />
559
-
560
- <!-- 文本输入框 -->
561
- <VanField
562
- v-if="attr.type === 'input'"
563
- v-model="localValue as string"
564
- :label="labelData"
565
- :required="attr.required"
566
- :type="attr.type"
567
- :readonly="attr.readonly"
568
- :disabled="attr.disabled"
569
- :placeholder="attr.placeholder ? attr.placeholder : `请输入${attr.name}`"
570
- :error-message="attr.errorMessage"
571
- :clearable="attr.clearable"
572
- :rules="[{ required: attr.rule.required === 'true', message: `必须填写${attr.name}` }]"
573
- />
574
- </div>
575
- </template>
576
-
577
- <style scoped>
578
-
579
- </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>