af-mobile-client-vue3 1.0.70 → 1.0.72

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