@dhccmobile/vue3-lo-form 1.1.41 → 2.0.0

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.
Files changed (165) hide show
  1. package/.env.local.bak +6 -6
  2. package/.eslintrc.js +28 -28
  3. package/README.md +70 -62
  4. package/babel.config.js +3 -3
  5. package/dist/vue3-lo-form.common.js +7700 -107778
  6. package/dist/vue3-lo-form.common.js.map +1 -1
  7. package/dist/vue3-lo-form.css +1 -1
  8. package/dist/vue3-lo-form.umd.js +7773 -107851
  9. package/dist/vue3-lo-form.umd.js.map +1 -1
  10. package/dist/vue3-lo-form.umd.min.js +1 -56
  11. package/dist/vue3-lo-form.umd.min.js.map +1 -1
  12. package/package.json +65 -61
  13. package/public/index.html +17 -17
  14. package/public/js/pinyin.ts +101 -101
  15. package/src/App.vue +741 -741
  16. package/src/components/form/DvForm.vue +642 -642
  17. package/src/components/form/DvFormLayout.vue +1569 -1569
  18. package/src/components/form/StretchText.vue +90 -90
  19. package/src/components/index.ts +3 -3
  20. package/src/constants/config/form-template.config.ts +32 -32
  21. package/src/constants/config/form.config.ts +4 -4
  22. package/src/constants/config/storage.config.ts +4 -4
  23. package/src/constants/encode-assets/svg.ts +11 -11
  24. package/src/constants/enum/builtIn-label.enum.ts +5 -5
  25. package/src/constants/enum/cache-type.enum.ts +7 -7
  26. package/src/constants/enum/control-format-type.enum.ts +9 -9
  27. package/src/constants/enum/dynamic-option-type.enum.ts +6 -6
  28. package/src/constants/enum/form-bus-attr.enum.ts +8 -8
  29. package/src/constants/enum/form-field-class.enum.ts +7 -7
  30. package/src/constants/enum/form-field-type.enum.ts +25 -25
  31. package/src/constants/enum/form-type.enum.ts +5 -5
  32. package/src/constants/enum/index.ts +19 -19
  33. package/src/constants/enum/lateral-arrangement.enum.ts +9 -9
  34. package/src/constants/enum/money-unit.enum.ts +6 -6
  35. package/src/constants/enum/option-type.enum.ts +5 -5
  36. package/src/constants/enum/submitted-type.enum.ts +32 -31
  37. package/src/constants/enum/support-upload-type.enum.ts +5 -5
  38. package/src/constants/enum/switch.enum.ts +5 -5
  39. package/src/constants/enum/upload-type.enum.ts +17 -17
  40. package/src/constants/enum/validate-rules.enum.ts +25 -25
  41. package/src/constants/enum/validate-status.enum.ts +8 -8
  42. package/src/constants/enum/vertical-arrangement.enum.ts +7 -7
  43. package/src/constants/enum/zoom-type.ts +6 -6
  44. package/src/constants/index.ts +3 -3
  45. package/src/core/FormApi.ts +1238 -1238
  46. package/src/core/index.ts +1 -1
  47. package/src/domain/AbstractControl.ts +6 -6
  48. package/src/domain/Control.ts +14 -14
  49. package/src/domain/CustomFormat.ts +6 -6
  50. package/src/domain/DesForm.ts +48 -48
  51. package/src/domain/DesFormControl.ts +241 -241
  52. package/src/domain/DesFormLayout.ts +51 -51
  53. package/src/domain/FieldChangeHistory.ts +9 -9
  54. package/src/domain/FormConfig.ts +15 -15
  55. package/src/domain/FormControl.ts +125 -125
  56. package/src/domain/FormEnum.ts +9 -9
  57. package/src/domain/FormGroup.ts +42 -42
  58. package/src/domain/FormRestfulResponse.ts +6 -6
  59. package/src/domain/ProvideInjectData.ts +10 -10
  60. package/src/domain/SysDictDetail.ts +38 -38
  61. package/src/domain/SysDictInfo.ts +40 -40
  62. package/src/domain/SysDictTreeDetail.ts +52 -52
  63. package/src/domain/index.ts +12 -12
  64. package/src/filtres/amount-capitalization.filter.ts +154 -147
  65. package/src/filtres/extract-options.filter.ts +53 -53
  66. package/src/filtres/generate-grid-column-end.filter.ts +22 -22
  67. package/src/filtres/generate-grid-template-columns.filter.ts +24 -24
  68. package/src/filtres/switch-enum-convert.filter.ts +18 -18
  69. package/src/filtres/zoom-multiple.filter.ts +32 -32
  70. package/src/index.ts +73 -73
  71. package/src/main.ts +17 -17
  72. package/src/services/api.service.ts +73 -73
  73. package/src/services/clean-local-forage.service.ts +58 -58
  74. package/src/services/date-format.service.ts +74 -74
  75. package/src/services/dict-local-forage.service.ts +58 -58
  76. package/src/services/form-bean-utils.service.ts +41 -41
  77. package/src/services/form-local-forage.service.ts +59 -59
  78. package/src/services/form-tools.service.ts +739 -659
  79. package/src/services/form-tree-node-convert.service.ts +240 -240
  80. package/src/services/form-validate.service.ts +103 -103
  81. package/src/services/index.ts +9 -9
  82. package/src/services/router.service.ts +96 -96
  83. package/src/services/validate-generator.service.ts +710 -710
  84. package/src/shims-vue.d.ts +6 -6
  85. package/src/store/dict.store.ts +63 -63
  86. package/src/store/form.store.ts +32 -32
  87. package/src/store/index.ts +2 -2
  88. package/src/styles/datePicker.scss +125 -125
  89. package/src/styles/index.scss +195 -195
  90. package/src/styles/theme1.scss +277 -277
  91. package/src/styles/theme2.scss +376 -376
  92. package/src/styles/themes.scss +9 -9
  93. package/src/types/vfForm.ts +11 -11
  94. package/tsconfig.json +40 -40
  95. package/types/components/index.d.ts +3 -3
  96. package/types/constants/config/form-template.config.d.ts +30 -30
  97. package/types/constants/config/form.config.d.ts +4 -4
  98. package/types/constants/config/storage.config.d.ts +4 -4
  99. package/types/constants/encode-assets/svg.d.ts +5 -5
  100. package/types/constants/enum/builtIn-label.enum.d.ts +7 -7
  101. package/types/constants/enum/cache-type.enum.d.ts +15 -15
  102. package/types/constants/enum/control-format-type.enum.d.ts +23 -23
  103. package/types/constants/enum/dynamic-option-type.enum.d.ts +11 -11
  104. package/types/constants/enum/form-bus-attr.enum.d.ts +19 -19
  105. package/types/constants/enum/form-field-class.enum.d.ts +18 -18
  106. package/types/constants/enum/form-field-type.enum.d.ts +111 -111
  107. package/types/constants/enum/form-type.enum.d.ts +11 -11
  108. package/types/constants/enum/index.d.ts +19 -19
  109. package/types/constants/enum/lateral-arrangement.enum.d.ts +23 -23
  110. package/types/constants/enum/money-unit.enum.d.ts +15 -15
  111. package/types/constants/enum/option-type.enum.d.ts +11 -11
  112. package/types/constants/enum/submitted-type.enum.d.ts +115 -111
  113. package/types/constants/enum/support-upload-type.enum.d.ts +11 -11
  114. package/types/constants/enum/switch.enum.d.ts +11 -11
  115. package/types/constants/enum/upload-type.enum.d.ts +59 -59
  116. package/types/constants/enum/validate-rules.enum.d.ts +2 -2
  117. package/types/constants/enum/validate-status.enum.d.ts +2 -2
  118. package/types/constants/enum/vertical-arrangement.enum.d.ts +21 -21
  119. package/types/constants/enum/zoom-type.d.ts +15 -15
  120. package/types/constants/index.d.ts +3 -3
  121. package/types/core/FormApi.d.ts +376 -376
  122. package/types/core/index.d.ts +1 -1
  123. package/types/domain/AbstractControl.d.ts +5 -5
  124. package/types/domain/Control.d.ts +13 -13
  125. package/types/domain/CustomFormat.d.ts +5 -5
  126. package/types/domain/DesForm.d.ts +32 -32
  127. package/types/domain/DesFormControl.d.ts +160 -160
  128. package/types/domain/DesFormLayout.d.ts +33 -33
  129. package/types/domain/FieldChangeHistory.d.ts +9 -9
  130. package/types/domain/FormConfig.d.ts +15 -15
  131. package/types/domain/FormControl.d.ts +60 -60
  132. package/types/domain/FormEnum.d.ts +10 -10
  133. package/types/domain/FormGroup.d.ts +27 -27
  134. package/types/domain/FormRestfulResponse.d.ts +6 -6
  135. package/types/domain/ProvideInjectData.d.ts +10 -10
  136. package/types/domain/SysDictDetail.d.ts +24 -24
  137. package/types/domain/SysDictInfo.d.ts +26 -26
  138. package/types/domain/SysDictTreeDetail.d.ts +34 -34
  139. package/types/domain/index.d.ts +12 -12
  140. package/types/filtres/amount-capitalization.filter.d.ts +7 -7
  141. package/types/filtres/extract-options.filter.d.ts +13 -13
  142. package/types/filtres/generate-grid-column-end.filter.d.ts +11 -11
  143. package/types/filtres/generate-grid-template-columns.filter.d.ts +11 -11
  144. package/types/filtres/switch-enum-convert.filter.d.ts +2 -2
  145. package/types/filtres/zoom-multiple.filter.d.ts +3 -3
  146. package/types/index.d.ts +13 -13
  147. package/types/main.d.ts +2 -2
  148. package/types/services/api.service.d.ts +25 -25
  149. package/types/services/clean-local-forage.service.d.ts +28 -28
  150. package/types/services/date-format.service.d.ts +21 -21
  151. package/types/services/dict-local-forage.service.d.ts +28 -28
  152. package/types/services/form-bean-utils.service.d.ts +23 -23
  153. package/types/services/form-local-forage.service.d.ts +28 -28
  154. package/types/services/form-tools.service.d.ts +153 -144
  155. package/types/services/form-tree-node-convert.service.d.ts +104 -104
  156. package/types/services/form-validate.service.d.ts +32 -32
  157. package/types/services/index.d.ts +9 -9
  158. package/types/services/router.service.d.ts +40 -40
  159. package/types/services/validate-generator.service.d.ts +154 -154
  160. package/types/store/dict.store.d.ts +29 -29
  161. package/types/store/form.store.d.ts +17 -17
  162. package/types/store/index.d.ts +2 -2
  163. package/types/types/vfForm.d.ts +10 -10
  164. package/vue.config.js +38 -29
  165. package/dhccmobile-vue3-lo-form-1.1.41.tgz +0 -0
@@ -1,1569 +1,1569 @@
1
- <template>
2
- <div v-if="(control.type === formFieldClass.Base.code || control.type === formFieldClass.Senior.code) && !controlAttr.isHideControl" class="lo-control-container" :style="{ width: divWidthCompatibleToIe }">
3
- <div class="lo-control-box">
4
- <a-form-item
5
- :labelCol="{
6
- style: 'min-width: ' + labelSpanWidth + ';width:' + labelSpanWidth,
7
- }"
8
- :wrapperCol="{
9
- style: 'max-width: ' + controlSpanMaxWidth + ';width: ' + controlSpanWidth,
10
- }"
11
- :colon="colon"
12
- :labelAlign="labelAlign"
13
- :required="required"
14
- :validate-status="validateResult.validateStatus"
15
- :help="provideInjectData.edit ? validateResult.errorMsg : null"
16
- :class="{
17
- ['form-model-item-' + controlAttr.boundProperty]: true,
18
- ['form-model-item-' + control.code]: true,
19
- 'lo-form-model-item-textarea-box': control.code === formFieldType.Textarea.code,
20
- }"
21
- >
22
- <template v-slot:label>
23
- <span v-if="!controlAttr.isHideTitle">
24
- <span :class="{ 'lo-fw': controlAttr.isBoldTitle }" :style="{ color: controlAttr.titleColor }">{{ controlAttr.formFieldDescribe }}</span>
25
- <a-tooltip class="lo-label-sub-type-icon" placement="right" :title="submittedTypeStr" overlayClassName="lo-form-item-tooltip" v-if="submittedType.length > 0">
26
- <img :src="submittedSvg" />
27
- </a-tooltip>
28
- <a-tooltip class="lo-label-tips-icon" placement="right" :title="controlAttr.tips" overlayClassName="lo-form-item-tooltip" v-if="controlAttr.tips">
29
- <question-circle-outlined style="font-size: 13px" />
30
- </a-tooltip>
31
- <a-popconfirm overlayClassName="lo-label-history-popconfirm" placement="right" ok-text="确定" v-if="formControl.history && formControl.history.length">
32
- <template v-slot:title>
33
- <div class="lo-history-popconfirm-title">历史修改</div>
34
- <div>
35
- <a-timeline class="lo-history-timeline">
36
- <a-timeline-item v-for="(item, index) of formControl.history" :key="index">
37
- <template v-slot:dot>
38
- <clock-circle-outlined style="font-size: 13px" />
39
- </template>
40
- <div class="lo-history-context">
41
- <div>{{ item.time }}</div>
42
- <div class="lo-important lo-mx-10">
43
- {{ item.before }}
44
- </div>
45
- 改为
46
- <div class="lo-important lo-mx-10">
47
- {{ item.after }}
48
- </div>
49
- 修改人
50
- <div class="lo-important lo-ml-10">
51
- {{ item.author }}
52
- </div>
53
- </div>
54
- </a-timeline-item>
55
- </a-timeline>
56
- </div>
57
- </template>
58
- <img class="lo-label-history-icon" :src="historySvg" />
59
- </a-popconfirm>
60
- </span>
61
- </template>
62
- <template v-if="provideInjectData.edit">
63
- <template v-if="control.code === formFieldType.Input.code">
64
- <template v-if="provideInjectData.edit">
65
- <component
66
- :is="inputShape"
67
- :class="{
68
- 'addon-before': $slots['input:addonBefore:' + formControl.key] || controlAttr.bindingPrefix || controlAttr.builtInFrontLabel,
69
- 'addon-after': $slots['input:addonAfter:' + formControl.key] || controlAttr.bindingSuffix || controlAttr.builtInPostLabel,
70
- }"
71
- v-model:value="formControl.value"
72
- :placeholder="controlAttr.placeholder"
73
- :disabled="controlAttr.isNotEdit"
74
- :data-source="controlAttr.autoCompleteOptions"
75
- @focus="onFocus(control)"
76
- @blur="onBlur(control)"
77
- @input="onChange(control)"
78
- @click="onClick(control)"
79
- >
80
- <template v-slot:prefix v-if="$slots['input:prefix:' + formControl.key]">
81
- <slot :name="'input:prefix:' + formControl.key"></slot>
82
- </template>
83
- <template v-slot:suffix v-if="$slots['input:suffix:' + formControl.key]">
84
- <slot :name="'input:suffix:' + formControl.key"></slot>
85
- </template>
86
- <template v-slot:addonBefore v-if="$slots['input:addonBefore:' + formControl.key] || controlAttr.bindingPrefix || controlAttr.builtInFrontLabel">
87
- <span class="addon-inner" @click="onAddonBeforeHandler(control)">
88
- <template v-if="$slots['input:addonBefore:' + formControl.key]">
89
- <slot :name="'input:addonBefore:' + formControl.key"> </slot>
90
- </template>
91
- <template v-else-if="controlAttr.bindingPrefix">
92
- {{ controlAttr.bindingPrefix }}
93
- </template>
94
- <template v-else-if="controlAttr.builtInFrontLabel">
95
- <search-outlined class="addon-icon" />
96
- </template>
97
- </span>
98
- </template>
99
- <template v-slot:addonAfter v-if="$slots['input:addonAfter:' + formControl.key] || controlAttr.bindingSuffix || controlAttr.builtInPostLabel">
100
- <span class="addon-inner" @click="onAddonAfterHandler(control)">
101
- <template v-if="$slots['input:addonAfter:' + formControl.key]">
102
- <slot :name="'input:addonAfter:' + formControl.key"></slot>
103
- </template>
104
- <template v-else-if="controlAttr.bindingSuffix">
105
- {{ controlAttr.bindingSuffix }}
106
- </template>
107
- <template v-else-if="controlAttr.builtInPostLabel">
108
- <search-outlined class="addon-icon" />
109
- </template>
110
- </span>
111
- </template>
112
- </component>
113
- </template>
114
- </template>
115
- <template v-else-if="control.code === formFieldType.Textarea.code">
116
- <a-textarea v-model:value="control.formControl.value" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" :rows="controlAttr.textareaRows || 3" :showCount="!!maxCharacterCount" :maxlength="maxCharacterCount" @input="onChange(control)" @focus="onFocus(control)" @blur="onBlur(control)" @click="onClick(control)" />
117
- </template>
118
- <template v-if="control.code === formFieldType.InputNumber.code">
119
- <span
120
- class="lo-input-number-box"
121
- tabindex="1"
122
- :class="{
123
- 'lo-with-unit': controlAttr.zoomType === zoomType.automatic.code && moneyUnits.length > 0,
124
- ['lo-unit-' + moneyUnitsIndentScale]: true,
125
- }"
126
- >
127
- <a-popover
128
- placement="topLeft"
129
- trigger="focus"
130
- :getPopupContainer="
131
- (triggerNode) => {
132
- return triggerNode.parentNode || document.body;
133
- }
134
- "
135
- >
136
- <template v-if="numberPopoverVisible" #content>
137
- <span class="number-format-show">
138
- {{ amountCapitalization(zoomMultiple(formControl.value, formControl)) }}
139
- </span>
140
- </template>
141
- <a-input-number
142
- :step="controlAttr.step || 1"
143
- :min="controlAttr.minValue != null ? controlAttr.minValue : undefined"
144
- :max="controlAttr.maxValue != null ? controlAttr.maxValue : undefined"
145
- :formatter="numberFormatter"
146
- :parser="numberParser"
147
- :precision="controlAttr.decimalPlaces"
148
- :placeholder="controlAttr.placeholder"
149
- :disabled="controlAttr.isNotEdit"
150
- v-model:value="formControl.value"
151
- @change="onChange(control)"
152
- @click="onClick(control)"
153
- @focus="onInputNumberFocus(control)"
154
- @blur="onInputNumberBlur(control)"
155
- >
156
- <template v-slot:addonAfter v-if="controlAttr.unit">
157
- <span class="addon-inner">{{ controlAttr.unit }}</span>
158
- </template>
159
- </a-input-number>
160
- <a-dropdown v-if="controlAttr.zoomType === zoomType.automatic.code && moneyUnits.length > 0">
161
- <template v-slot:overlay>
162
- <a-menu @click="handleMoneyUnitMenuClick">
163
- <a-menu-item v-for="unit in moneyUnits" :key="unit.code">{{ unit.name }}</a-menu-item>
164
- </a-menu>
165
- </template>
166
- <a-button>
167
- {{ defaultMoneyUnit.name }}
168
- <down-outlined v-if="moneyUnits.length > 1" />
169
- </a-button>
170
- </a-dropdown>
171
- </a-popover>
172
- </span>
173
- </template>
174
- <template v-if="control.code === formFieldType.Select.code">
175
- <a-select
176
- class="lo-select"
177
- :dropdownClassName="controlAttr.hiddenDropdown ? 'lo-select-hide-drop-down-content' : ''"
178
- :class="{
179
- 'lo-select-multiple-suffix-icon': controlAttr.isMultipleChoice && ($slots['select:suffixIcon:' + formControl.key] || controlAttr.bindingSuffix),
180
- }"
181
- showArrow
182
- v-model:value="formControl.value"
183
- :allow-clear="true"
184
- show-search
185
- :mode="controlAttr.isMultipleChoice ? 'multiple' : ''"
186
- :disabled="controlAttr.isNotEdit"
187
- :placeholder="controlAttr.placeholder"
188
- @change="onChange(control)"
189
- @click="onClick(control)"
190
- :get-popup-container="getPopupContainer"
191
- :filter-option="filterOption"
192
- >
193
- <template #dropdownRender="{ menuNode: menu }">
194
- <v-nodes :vnodes="menu" />
195
- <template v-if="controlAttr.canAddEntry">
196
- <a-divider style="margin: 4px 0" />
197
- <div style="padding: 4px 8px 6px 8px; cursor: pointer" @mousedown="(e) => e.preventDefault()" @click="selectAddItem(control)"><plus-outlined />新增</div>
198
- </template>
199
- </template>
200
- <template #default>
201
- <a-select-option v-for="item in options" :value="item.value" :key="item.value" :title="item.title" :disabled="item.disabled ? item.disabled : false">{{ item.title }}</a-select-option>
202
- </template>
203
- <template #suffixIcon v-if="$slots['select:suffixIcon:' + formControl.key] || controlAttr.bindingSuffix">
204
- <template v-if="$slots['select:suffixIcon:' + formControl.key]">
205
- <slot :name="'select:suffixIcon:' + formControl.key"></slot>
206
- </template>
207
- <template v-else>
208
- {{ controlAttr.bindingSuffix }}
209
- </template>
210
- </template>
211
- </a-select>
212
- </template>
213
- <template v-if="control.code === formFieldType.Radio.code">
214
- <a-radio-group class="w-100" v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)">
215
- <a-radio v-for="item in options" :key="item.value" :value="item.value">{{ item.title }}</a-radio>
216
- </a-radio-group>
217
- </template>
218
- <template v-if="control.code === formFieldType.Checkbox.code">
219
- <a-checkbox-group class="w-100" v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)">
220
- <a-row>
221
- <a-col>
222
- <a-checkbox v-for="item in options" :key="item.value" :value="item.value" class="ml-0 mr-5" :style="{ width: controlAttr.checkboxStyle ? 'auto' : '10rem' }">
223
- <a-tooltip>
224
- <template #title>
225
- <span>{{ item.title }}</span>
226
- </template>
227
- {{ item.title }}
228
- </a-tooltip>
229
- </a-checkbox>
230
- </a-col>
231
- </a-row>
232
- </a-checkbox-group>
233
- </template>
234
- <template v-if="control.code === formFieldType.Switch.code">
235
- <a-switch v-model:checked="formControl.value" :checked-children="controlAttr.onOpeningText" :un-checked-children="controlAttr.whenClosedText" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" />
236
- </template>
237
- <template v-if="control.code === formFieldType.TimePicker.code">
238
- <a-time-picker class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :use12-hours="is12Hours" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
239
- </template>
240
- <template v-if="control.code === formFieldType.DatePicker.code">
241
- <a-month-picker v-if="useMonthPicker" class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
242
- <a-date-picker v-else-if="controlAttr.isShowHoliday" class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :showTime="showPickerTime(controlAttr.dateFormat)" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)">
243
- <template #dateRender="{ current }">
244
- <div class="ant-picker-cell-inner calendar-control-style">
245
- <div class="date-control-style">
246
- <div class="eest-day-style"></div>
247
- <div class="date-style">{{ current.date() }}</div>
248
- <div class="eest-day-style">
249
- <div class="holidays-style" v-if="isRest(current)">休</div>
250
- <div class="weekday-style" v-else-if="isWeekday(current)">班</div>
251
- </div>
252
- </div>
253
- <div class="date-type-style">
254
- <!-- 交易日 -->
255
- <div class="trading-day-style" v-if="isRadingDay(current)"></div>
256
- </div>
257
- </div>
258
- </template>
259
- <template #renderExtraFooter>
260
- <div class="legend">
261
- <div class="day-explain-style">
262
- <div class="trading-day-icon"></div>
263
- <div class="day-explain">交易日</div>
264
- </div>
265
- </div>
266
- </template>
267
- </a-date-picker>
268
- <a-date-picker v-else class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :showTime="showPickerTime(controlAttr.dateFormat)" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
269
- </template>
270
- <template v-if="control.code === formFieldType.Slider.code">
271
- <a-slider v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" />
272
- </template>
273
- <template v-if="control.code === formFieldType.Cascader.code">
274
- <a-cascader :get-popup-container="getPopupContainer" :changeOnSelect="controlAttr.changeOnSelect" :placeholder="controlAttr.placeholder" :show-search="{ cascaderFilter }" :disabled="controlAttr.isNotEdit" :options="cascaderOptions" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
275
- </template>
276
- <template v-if="control.code === formFieldType.TreeSelect.code">
277
- <a-tree-select
278
- :get-popup-container="getPopupContainer"
279
- v-model:value="formControl.value"
280
- :show-search="true"
281
- :treeNodeFilterProp="'title'"
282
- :disabled="controlAttr.isNotEdit"
283
- :placeholder="controlAttr.placeholder"
284
- :dropdown-style="{ maxHeight: '250px', overflow: 'auto' }"
285
- :tree-data="treeSelectOptions"
286
- @change="onChange(control)"
287
- @click="onClick(control)"
288
- :treeDefaultExpandAll="controlAttr.IsTreeOpen"
289
- >
290
- </a-tree-select>
291
- </template>
292
- <template v-if="control.code === formFieldType.Rate.code">
293
- <a-rate v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" allow-half />
294
- </template>
295
- <template v-if="control.code === formFieldType.Upload.code">
296
- <a-upload :file-list="formControl.value" :accept="uploadType" :multiple="controlAttr.isMultipleChoice" @remove="handleRemove" :before-upload="beforeUpload" @change="handleUploadChange">
297
- <a-button>
298
- <upload-outlined />
299
- 选择文件
300
- </a-button>
301
- </a-upload>
302
- </template>
303
- <template v-if="control.code === formFieldType.Custom.code && controlAttr.customFieldName">
304
- <slot :control="control" :onChange="onChange" :name="controlAttr.customFieldName"></slot>
305
- </template>
306
- </template>
307
- <template v-else>
308
- <div class="lo-input-content">
309
- <slot :name="'read:' + control.formControl.key" :content="formatData">
310
- <stretch-text v-if="controlAttr.textFold" :content="formatData" :linkList="linkList" :fieldKey="control.formControl.key" @linkClick="linkClick({ key: formControl.key, value: formatData })"></stretch-text>
311
- <div class="lo-control-text" :title="formatData" v-else>
312
- <a v-if="linkList.indexOf(control.formControl.key) > -1" href="#" @click="linkClick({ key: formControl.key, value: formatData })">{{ formatData }}</a>
313
- <span v-else>{{ formatData }}</span>
314
- </div>
315
- </slot>
316
- </div>
317
- <div class="flex-grow-1"></div>
318
- <template v-if="controlAttr.unit">
319
- <span class="addon-readonly">{{ controlAttr.unit }}</span>
320
- </template>
321
- </template>
322
- </a-form-item>
323
- </div>
324
- </div>
325
- <a-form v-else-if="control.type === formFieldClass.Layout.code && control.code === formFieldType.Empty.code" :class="'w-100 lo-empty-layout-container' + (controlAttr.layoutName ? ' lo-form-layout-' + controlAttr.layoutName : '')" :layout="layout" :style="emptyLayoutContainerStyle">
326
- <dv-form-layout
327
- v-for="(item, i) in control.subControls"
328
- :key="i"
329
- :index="i"
330
- :customFormats="customFormats"
331
- :control="item"
332
- :parentControl="control"
333
- :linkList="linkList"
334
- @linkClick="linkClick"
335
- @change="onChange($event)"
336
- @click="onClick($event)"
337
- @focus="onFocus($event)"
338
- @blur="onBlur($event)"
339
- @addon-before="onAddonBeforeHandler($event)"
340
- @addon-after="onAddonAfterHandler($event)"
341
- @add-item="selectAddItem($event)"
342
- @fixFormLayout="onHideControl"
343
- >
344
- <template v-for="scopedPropName in Object.keys($slots)" v-slot:[scopedPropName]="{ content, control, onChange }">
345
- <slot v-bind:content="content" v-bind:control="control" v-bind:onChange="onChange" :name="scopedPropName"></slot>
346
- </template>
347
- </dv-form-layout>
348
- </a-form>
349
- <a-form v-else-if="control.type === formFieldClass.Layout.code && control.code !== formFieldType.Empty.code" :class="'w-100 lo-general-layout-container' + (controlAttr.layoutName ? ' lo-form-layout-' + controlAttr.layoutName : '')" :layout="layout" :style="generalLayoutContainerStyle">
350
- <dv-form-layout
351
- v-for="(item, i) in control.subControls"
352
- :key="i"
353
- :index="i"
354
- :customFormats="customFormats"
355
- :control="item"
356
- :parentControl="control"
357
- :class="controlAttr.layoutName ? 'lo-form-layout-' + controlAttr.layoutName : ''"
358
- @change="onChange($event)"
359
- @click="onClick($event)"
360
- @focus="onFocus($event)"
361
- @blur="onBlur($event)"
362
- @addon-before="onAddonBeforeHandler($event)"
363
- @addon-after="onAddonAfterHandler($event)"
364
- @add-item="selectAddItem($event)"
365
- >
366
- <template v-for="scopedPropName in Object.keys($slots)" v-slot:[scopedPropName]="{ content, control, onChange }">
367
- <slot v-bind:content="content" v-bind:control="control" v-bind:onChange="onChange" :name="scopedPropName"></slot>
368
- </template>
369
- </dv-form-layout>
370
- </a-form>
371
- </template>
372
-
373
- <script lang="ts">
374
- import { Options, Inject, Prop, Watch, Vue } from "vue-property-decorator";
375
- import { Control } from "@/domain";
376
- import { FormEnum } from "@/domain";
377
- import { FormFieldClass } from "@/constants";
378
- import { FormFieldType } from "@/constants";
379
- import generateGridTemplateColumns from "../../filtres/generate-grid-template-columns.filter";
380
- import generateGridColumnEnd from "../../filtres/generate-grid-column-end.filter";
381
- import { DesFormLayout } from "@/domain";
382
- import { DesFormControl } from "@/domain";
383
-
384
- import { AutoComplete, Cascader, Checkbox, DatePicker, Form, Input, InputNumber, Radio, Select, Switch, TimePicker, TreeSelect, Slider, Tooltip, Popover, Divider, Rate, Dropdown, Button, Menu, Upload, Popconfirm, Timeline, FormItem, RadioGroup, Textarea, CheckboxGroup, InputPassword, TimelineItem, Row, Col } from "ant-design-vue";
385
- import { VerticalArrangement } from "@/constants";
386
- import { formBeanUtilsService } from "@/services";
387
- import { ProvideInjectData } from "@/domain/ProvideInjectData";
388
-
389
- import amountCapitalization from "../../filtres/amount-capitalization.filter";
390
- import { FormControl, ValidateResult, CustomFormat } from "../../domain";
391
- import { FormBusAttr, SubmittedType, MoneyUnit, ControlFormatType, BuiltLabel, SupportUploadType } from "../../constants/enum";
392
- import { ValidateRules } from "@/constants";
393
- import { ZoomType } from "@/constants";
394
- import { extractOptions } from "@/filtres/extract-options.filter";
395
- import zoomMultiple from "../../filtres/zoom-multiple.filter";
396
- import switchEnumConvert from "../../filtres/switch-enum-convert.filter";
397
- import StretchText from "./StretchText.vue";
398
- import { SUBMITTED_SVG_XML, HISTORY_SVG_XML } from "../../constants/encode-assets/svg";
399
- import { SearchOutlined, PlusOutlined, QuestionCircleOutlined, ClockCircleOutlined, DownOutlined, UploadOutlined } from "@ant-design/icons-vue";
400
-
401
- import dayjs from "dayjs";
402
- import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
403
- import pinYin from "../../../public/js/pinyin";
404
-
405
- @Options({
406
- name: "DvFormLayout",
407
- filters: {
408
- amountCapitalization: amountCapitalization,
409
- switchEnumConvert: switchEnumConvert,
410
- zoomMultiple: zoomMultiple,
411
- },
412
- components: {
413
- StretchText,
414
- PlusOutlined,
415
- [Form.name]: Form,
416
- [FormItem.name]: FormItem,
417
- [Input.name]: Input,
418
- [Textarea.name]: Textarea,
419
- [AutoComplete.name]: AutoComplete,
420
- [InputNumber.name]: InputNumber,
421
- [Select.name]: Select,
422
- [Select.Option.displayName + ""]: Select.Option,
423
- [Select.OptGroup.displayName + ""]: Select.OptGroup,
424
- [Radio.name]: Radio,
425
- [RadioGroup.name]: RadioGroup,
426
- [Checkbox.name]: Checkbox,
427
- [CheckboxGroup.name]: CheckboxGroup,
428
- [Switch.name]: Switch,
429
- [TimePicker.name]: TimePicker,
430
- [DatePicker.name]: DatePicker,
431
- [Slider.name]: Slider,
432
- [AutoComplete.name]: AutoComplete,
433
- [Cascader.name]: Cascader,
434
- [TreeSelect.name]: TreeSelect,
435
- [Tooltip.name]: Tooltip,
436
- [InputPassword.name]: InputPassword,
437
- [Popover.name]: Popover,
438
- [Popconfirm.name]: Popconfirm,
439
- [Timeline.name]: Timeline,
440
- [TimelineItem.name]: TimelineItem,
441
- [Rate.name]: Rate,
442
- [Dropdown.name]: Dropdown,
443
- [Menu.name]: Menu,
444
- [Menu.Item.name]: Menu.Item,
445
- [Upload.name]: Upload,
446
- [Button.name]: Button,
447
- [Divider.name]: Divider,
448
- [DatePicker.MonthPicker.name]: DatePicker.MonthPicker,
449
- [StretchText.name]: StretchText,
450
- [Row.name]: Row,
451
- [Col.name]: Col,
452
- VNodes: (_, { attrs }) => {
453
- return attrs.vnodes;
454
- },
455
- QuestionCircleOutlined,
456
- ClockCircleOutlined,
457
- DownOutlined,
458
- UploadOutlined,
459
- SearchOutlined,
460
- },
461
- })
462
- export default class DvFormLayout extends Vue {
463
- locale = locale; // 国际化
464
- submittedSvg = SUBMITTED_SVG_XML; // 上报图标
465
- historySvg = HISTORY_SVG_XML; // 历史记录图标
466
-
467
- numberPopoverVisible = false; // 是否开启数字气泡弹窗
468
- validateResult: ValidateResult = {}; // 校验规则
469
- metaRefresh: any; // 刷新标识
470
- defaultMoneyUnit: any = {}; // 默认单位
471
- zoomType = ZoomType; // 缩放类型
472
- builtLabel = BuiltLabel; // 内置前/后置标签
473
- traddayList: any = localStorage.getItem("traddayList") || JSON.stringify([]); // 交易日集合
474
- weekdayList: any = localStorage.getItem("weekdayList") || JSON.stringify([]); // 节假日集合
475
- workdayList: any = localStorage.getItem("workdayList") || JSON.stringify([]); // 工作日集合
476
- amountCapitalization = amountCapitalization; // 大写转换
477
- zoomMultiple = zoomMultiple; // 缩放
478
- filterOption(value: any, item: any) {
479
- if (!item.title) {
480
- return false;
481
- }
482
- return item.title.indexOf(value) > -1 || pinYin.getCamelChars(item.title).indexOf(value) > -1 || pinYin.getFullChars(item.title).indexOf(value) > -1;
483
- }
484
-
485
- @Prop() index: number | undefined;
486
- @Prop() control: Control | undefined;
487
- @Prop() parentControl: Control | undefined;
488
- @Prop({ type: Object, default: () => ({}) }) customFormats: { [key: string]: CustomFormat } | undefined;
489
- @Prop({ type: Array, default: () => [] }) linkList: any | undefined; // 需要添加超链接点击事件数组 例:['cifNo', 'prodBaseNo']
490
- @Inject() provideInjectData: ProvideInjectData | any;
491
- readonly formFieldClass: FormEnum = FormFieldClass; // 表单字段分类
492
- readonly formFieldType: FormEnum = FormFieldType; // 表单字段类型
493
-
494
- @Watch("defaultMoneyUnit", { immediate: true })
495
- onDefaultMoneyUnitHandler(newVal: any): void {
496
- if (newVal.code != null) {
497
- switch (newVal.code) {
498
- case MoneyUnit.Yuan.code:
499
- (this.controlAttr as DesFormControl).zoomMultiple = 1;
500
- break;
501
- case MoneyUnit.TenThousandYuan.code:
502
- (this.controlAttr as DesFormControl).zoomMultiple = 10000;
503
- break;
504
- case MoneyUnit.HundredMillionYuan.code:
505
- (this.controlAttr as DesFormControl).zoomMultiple = 100000000;
506
- break;
507
- }
508
- }
509
- }
510
-
511
- /**
512
- * @description: 校验反馈
513
- * @author ChenRui
514
- * @date 2021/2/26 14:24
515
- */
516
- @Watch("provideInjectData.refreshCheckFeedbackFlag")
517
- @Watch("control.formControl.refreshValidate")
518
- onValidationFeedbackHandle(): void {
519
- this.validateResult = this.formControl.validate();
520
- }
521
-
522
- /**
523
- * @description: 表单校验
524
- * @author ChenRui
525
- * @date 2022/4/6 14:12
526
- */
527
- @Watch("provideInjectData.formValidateStateResetMark")
528
- onFormValidateStateResetMarkHandle(): void {
529
- this.validateResult = {};
530
- }
531
- /**
532
- * @Description 表单数据反显回调(data:Object { key: 元素码值, value: 元素值 })
533
- * @Author JiangTao
534
- * @Date 2023-10-07 下午 05:22
535
- */
536
- linkClick(data: any): void {
537
- this.$emit("linkClick", data);
538
- }
539
-
540
- @Watch("control.controlAttr.isHideControl")
541
- onHideControl() {
542
- this.$nextTick(() => {
543
- this.$emit("fixFormLayout");
544
- });
545
- }
546
- /**
547
- * @description: 输入框形态
548
- * @author ChenRui
549
- * @date 2022/5/7 17:48
550
- */
551
- get inputShape(): string {
552
- if ((this.controlAttr as DesFormControl).isPasswordBox) {
553
- return "a-input-password";
554
- } else if ((this.controlAttr as DesFormControl).enableAutoComplete) {
555
- return "a-auto-complete";
556
- } else {
557
- return "a-input";
558
- }
559
- }
560
-
561
- /**
562
- * @description: 获取控件对象
563
- * @author ChenRui
564
- * @date 2021/1/27 11:07
565
- */
566
- get formControl(): FormControl {
567
- if (this.control && this.control.formControl) {
568
- // 初始化部分数据
569
- this.initFormControlData();
570
- return this.control.formControl;
571
- }
572
- return new FormControl();
573
- }
574
-
575
- /**
576
- * @description: 获取控件配置参数
577
- * @author ChenRui
578
- * @date 2021/1/5 11:26
579
- */
580
- get controlAttr(): DesFormControl | DesFormLayout {
581
- return this.control?.controlAttr as any;
582
- }
583
-
584
- /**
585
- * @description: 获取控件配置参数
586
- * @author ChenRui
587
- * @date 2021/1/5 11:26
588
- */
589
- get parentControlAttr(): DesFormLayout {
590
- return this.parentControl?.controlAttr as DesFormLayout;
591
- }
592
-
593
- /**
594
- * @description: 获取布局方式
595
- * @author ChenRui
596
- * @date 2020/12/30 18:19
597
- */
598
- get layout(): string {
599
- for (const propName of Object.keys(VerticalArrangement)) {
600
- if ((VerticalArrangement as any)[propName]["code"] === (this.controlAttr as DesFormLayout).gridVerticalArrangement) {
601
- return (VerticalArrangement as any)[propName]["value"];
602
- }
603
- }
604
- return VerticalArrangement.AlignRight.value;
605
- }
606
-
607
- /**
608
- * @description: 当前输入的字符长度
609
- * @author ChenRui
610
- * @date 2021/4/20 15:55
611
- */
612
- get currentCharacterCount(): any {
613
- return this.control!.formControl && this.control!.formControl.value ? this.control!.formControl.value.length : 0;
614
- }
615
-
616
- /**
617
- * @description: 最大字数限制
618
- * @author ChenRui
619
- * @date 2021/4/20 15:38
620
- */
621
- get maxCharacterCount(): any {
622
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
623
- if (controlAttr.verificationRules && controlAttr.verificationRules.length > 0) {
624
- const verificationRule: any = controlAttr.verificationRules.find((item: any) => item.ruleType === ValidateRules.MaxTextLength.code);
625
- if (verificationRule != null && verificationRule.ruleContent) {
626
- return Number(verificationRule.ruleContent);
627
- }
628
- }
629
- return undefined;
630
- }
631
-
632
- /**
633
- * @description: 数字格式化
634
- * @author ChenRui
635
- * @date 2021/1/14 16:30
636
- */
637
- get numberFormatter(): any {
638
- const controlAttr: any = this.controlAttr as DesFormControl;
639
- const controlFormatType: string = controlAttr.formatType ? controlAttr.formatType : ControlFormatType.GENERAL.code;
640
- return (value: any) => {
641
- let val: any = value != undefined ? String(value) : "";
642
- switch (controlFormatType) {
643
- case ControlFormatType.GENERAL.code:
644
- case ControlFormatType.AMOUNT_OF_MONEY.code:
645
- if (controlFormatType === ControlFormatType.AMOUNT_OF_MONEY.code && val != null && controlAttr.thousandthPercentileFormat) {
646
- // 校验小数位不做千分位格式化处理
647
- if (val.indexOf(".") > -1) {
648
- val = `${val}`.split(".")[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "." + `${val}`.split(".")[1];
649
- } else {
650
- val = `${val}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
651
- }
652
- }
653
- if (controlAttr.zoomType !== ZoomType.automatic.code && val != null && val != "" && controlAttr.unit) {
654
- // val = `${val}${controlAttr.unit}`;
655
- val = `${val}`;
656
- }
657
- return val;
658
- case ControlFormatType.BANK_CARD_NUMBER.code:
659
- if (val != null) {
660
- val = val.replace(/[\s]/g, "").replace(/(\d{4})(?=\d)/g, "$1 ");
661
- }
662
- return val;
663
- case ControlFormatType.CELL_PHONE_NUMBER.code:
664
- if (val != null) {
665
- val = val.replace(/\D/g, "").substr(0, 11); // 不允许输入非数字字符,超过11位数字截取前11位
666
- const len = val.length;
667
- if (len > 3 && len < 8) {
668
- val = val.replace(/^(\d{3})/g, "$1 ");
669
- } else if (len >= 8) {
670
- val = val.replace(/^(\d{3})(\d{4})/g, "$1 $2 ");
671
- }
672
- }
673
- return val;
674
- case ControlFormatType.LANDLINE_NUMBER.code:
675
- return val;
676
- default: {
677
- return value;
678
- }
679
- }
680
- };
681
- }
682
-
683
- /**
684
- * @description: 数字反格式化
685
- * @author ChenRui
686
- * @date 2021/1/14 16:31
687
- */
688
- get numberParser(): any {
689
- const controlAttr: any = this.controlAttr as DesFormControl;
690
- const zoomType: string = controlAttr.formatType ? controlAttr.formatType : ControlFormatType.GENERAL.code;
691
- return (value: any) => {
692
- let val: any = value;
693
- switch (zoomType) {
694
- case ControlFormatType.GENERAL.code:
695
- case ControlFormatType.AMOUNT_OF_MONEY.code:
696
- if (zoomType === ControlFormatType.AMOUNT_OF_MONEY.code && val != null && controlAttr.thousandthPercentileFormat) {
697
- val = val.replace(/\$\s?|(,*)/g, "");
698
- }
699
- if (controlAttr.zoomType !== ZoomType.automatic.code && val != null && val != "" && controlAttr.unit) {
700
- const replaceUnit: string[] = controlAttr.unit.split("");
701
- replaceUnit.forEach((item) => {
702
- val = val.replace(item, "");
703
- });
704
- }
705
- return val;
706
- case ControlFormatType.BANK_CARD_NUMBER.code:
707
- case ControlFormatType.CELL_PHONE_NUMBER.code:
708
- if (val != null) {
709
- val = val.replace(/\s/g, "");
710
- }
711
- return val;
712
- case ControlFormatType.LANDLINE_NUMBER.code:
713
- return val;
714
- default: {
715
- return val;
716
- }
717
- }
718
- };
719
- }
720
-
721
- /**
722
- * @description: label 宽度
723
- * @author ChenRui
724
- * @date 2021/1/5 11:59
725
- */
726
- get labelSpanWidth(): any {
727
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
728
- const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
729
- if (controlAttr.titleWidth) {
730
- return controlAttr.titleWidth;
731
- } else if (parentControlAttr.labelSpan) {
732
- return parentControlAttr.labelSpan;
733
- } else {
734
- return this.provideInjectData.labelSpan;
735
- }
736
- }
737
-
738
- /**
739
- * @description: 标签后是否显示冒号
740
- * @author ZPFly
741
- * @date 2022/7/15 10:54
742
- */
743
- get colon(): boolean {
744
- return this.provideInjectData.colon;
745
- }
746
-
747
- /**
748
- * @description: 最大宽度设置
749
- * @author ChenRui
750
- * @date 2021/7/8 16:39
751
- */
752
- get controlSpanMaxWidth(): any {
753
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
754
- const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
755
- if (controlAttr.controlWidth) {
756
- return controlAttr.controlWidth;
757
- } else if (parentControlAttr.controlSpan) {
758
- return parentControlAttr.controlSpan;
759
- } else if (this.provideInjectData.controlSpan) {
760
- return this.provideInjectData.controlSpan;
761
- } else {
762
- return "none";
763
- }
764
- }
765
-
766
- /**
767
- * @description: 控件宽度
768
- * @author ChenRui
769
- * @date 2021/1/5 15:11
770
- */
771
- get controlSpanWidth(): any {
772
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
773
- const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
774
- if (controlAttr.controlWidth) {
775
- return controlAttr.controlWidth;
776
- } else if (parentControlAttr.controlSpan) {
777
- return parentControlAttr.controlSpan;
778
- } else if (this.provideInjectData.controlSpan) {
779
- return this.provideInjectData.controlSpan;
780
- } else {
781
- return 0;
782
- }
783
- }
784
-
785
- /**
786
- * @description: label 标签的文本对齐方式
787
- * @author ChenRui
788
- * @date 2021/1/5 11:59
789
- */
790
- get labelAlign(): string {
791
- for (const propName of Object.keys(VerticalArrangement)) {
792
- if ((VerticalArrangement as any)[propName]["code"] === (this.controlAttr as DesFormLayout).gridVerticalArrangement) {
793
- return (VerticalArrangement as any)[propName]["textAlign"];
794
- }
795
- }
796
- return VerticalArrangement.AlignRight.textAlign;
797
- }
798
-
799
- /**
800
- * @description: 获取金额转换单位
801
- * @author ChenRui
802
- * @date 2021/2/20 17:43
803
- */
804
- get moneyUnits(): any[] {
805
- const moneyUnits: any[] = [];
806
- const moneyUnit: any[] = formBeanUtilsService.parse((this.controlAttr as DesFormControl).moneyUnit);
807
- if ((this.controlAttr as DesFormControl).moneyUnit) {
808
- Object.values(MoneyUnit).forEach((item) => {
809
- if (moneyUnit.findIndex((it) => it === item.code) !== -1) {
810
- moneyUnits.push(item);
811
- }
812
- });
813
- }
814
-
815
- if (moneyUnits && moneyUnits.length > 0) {
816
- this.defaultMoneyUnit = moneyUnits[0];
817
- }
818
- return moneyUnits;
819
- }
820
-
821
- /**
822
- * @description: 单位缩放比例
823
- * @author ChenRui
824
- * @date 2022/5/7 10:31
825
- */
826
- get moneyUnitsIndentScale(): number {
827
- const moneyUnit: any = this.defaultMoneyUnit;
828
- if (moneyUnit != null && moneyUnit.code) {
829
- return Number(moneyUnit.code);
830
- }
831
- return 0;
832
- }
833
-
834
- /**
835
- * @description: 获取select、checkbox、radio可选项
836
- * @author ChenRui
837
- * @date 2020/12/2 14:36
838
- */
839
- get options(): any[] {
840
- return extractOptions(this.controlAttr);
841
- }
842
-
843
- /**
844
- * @description: 使用月份组件
845
- * @author ChenRui
846
- * @date 2021/5/19 16:12
847
- */
848
- get useMonthPicker(): boolean {
849
- const dateFormat: any = (this.controlAttr as DesFormControl).dateFormat;
850
- if (dateFormat && dateFormat.toLowerCase() === "yyyy-mm") {
851
- return true;
852
- }
853
- return false;
854
- }
855
-
856
- /**
857
- * @description: 级联选择框
858
- * @author ChenRui
859
- * @date 2021/1/5 16:31
860
- */
861
- get cascaderOptions(): any[] {
862
- const value: any[] = this.options;
863
- let options: any[] = [];
864
- if (value && value.length > 0) {
865
- const items = formBeanUtilsService.copy(value);
866
- options = this.cascaderRecursion(items);
867
- }
868
- return options;
869
- }
870
-
871
- /**
872
- * @description: 树形下拉选项
873
- * @author ChenRui
874
- * @date 2021/1/5 16:44
875
- */
876
- get treeSelectOptions(): any[] {
877
- const value: any[] = this.options;
878
- console.log(value);
879
- if (value && value.length > 0) {
880
- const items = formBeanUtilsService.copy(value);
881
- this.treeSelectRecursion(items);
882
- return items;
883
- }
884
- return [];
885
- }
886
-
887
- /**
888
- * @description: 是否12小时制
889
- * @author ChenRui
890
- * @date 2021/1/18 10:54
891
- */
892
- get is12Hours(): boolean {
893
- return !!(this.controlAttr as DesFormControl).timeFormat && (this.controlAttr as DesFormControl).timeFormat.indexOf(":ss") < 0;
894
- }
895
-
896
- /**
897
- * @description: 是否添加反馈
898
- * @author ChenRui
899
- * @date 2021/1/21 10:43
900
- */
901
- get hasFeedback(): boolean {
902
- return this.control!.formControl != null && this.control!.formControl!.validates && this.control!.formControl!.validates.length > 0;
903
- }
904
-
905
- /**
906
- * @description: 是否必填,仅影响样式
907
- * @author ChenRui
908
- * @date 2021/1/21 10:50
909
- */
910
- get required(): boolean {
911
- if (this.hasFeedback && this.control!.formControl!.validates.findIndex((item: any) => String(item.name) === String(ValidateRules.Required.code)) !== -1) {
912
- return true;
913
- }
914
- return false;
915
- }
916
-
917
- /**
918
- * @description: 格式化数据
919
- * @author ChenRui
920
- * @date 2021/1/8 11:30
921
- */
922
- get formatData(): string {
923
- this.metaRefresh = this.provideInjectData.metaRefresh; // 刷新标识
924
- let val = "";
925
- let data: any = this.control!.formControl!.value;
926
- let options: any[];
927
- let context: any[];
928
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
929
- switch (this.control!.code) {
930
- case FormFieldType.Input.code:
931
- if (controlAttr.bindingPrefix) {
932
- val += controlAttr.bindingPrefix;
933
- }
934
- val += data || "";
935
- if (controlAttr.bindingSuffix) {
936
- val += controlAttr.bindingSuffix;
937
- }
938
- data = val;
939
- break;
940
- case FormFieldType.InputNumber.code:
941
- if (this.numberFormatter) {
942
- data = this.numberFormatter(data);
943
- }
944
- // 自动补0
945
- if (data && controlAttr.decimalPlaces != undefined && (controlAttr.decimalPlaces as any) !== "") {
946
- let index;
947
- if (data.indexOf(".") == -1) {
948
- index = controlAttr.decimalPlaces;
949
- data += ".";
950
- } else {
951
- index = controlAttr.decimalPlaces - (data.length - 1 - data.indexOf("."));
952
- }
953
- for (let i = 0; i < index; i++) {
954
- data += "0";
955
- }
956
- }
957
- // 金额后缀不依赖于是否设置了小数位
958
- if (controlAttr.zoomType !== ZoomType.automatic.code && data != null && data != "" && controlAttr.unit) {
959
- data = data.replace(controlAttr.unit, "");
960
- // data = `${data}${controlAttr.unit}`; // 后缀在后面统一展示 2023年9月22日15:49:08
961
- }
962
- return data;
963
- case FormFieldType.Select.code:
964
- case FormFieldType.Radio.code:
965
- if (data != null && Array.isArray(data)) {
966
- const context: string[] = [];
967
- this.options.find((item) => {
968
- for (let i = 0; i < data.length; i++) {
969
- if (item.value === data[i]) {
970
- context.push(item.title);
971
- }
972
- }
973
- });
974
- return context.join(",");
975
- } else {
976
- const option = this.options.find((item) => item.value === data);
977
- return option ? option.title : "";
978
- }
979
- case FormFieldType.Checkbox.code:
980
- options = data || [];
981
- context = [];
982
- options.forEach((it) => {
983
- this.options.find((item) => {
984
- if (item.value === it) {
985
- context.push(item.title);
986
- }
987
- });
988
- });
989
- return context.join(" , ");
990
- case FormFieldType.Switch.code:
991
- if (data !== undefined) {
992
- if (data === true && controlAttr.onOpeningValue != undefined && controlAttr.onOpeningValue !== "") {
993
- return controlAttr.onOpeningValue;
994
- } else if (data === false && controlAttr.whenClosedValue != undefined && controlAttr.whenClosedValue !== "") {
995
- return controlAttr.whenClosedValue;
996
- } else {
997
- return data ? "是" : "否";
998
- }
999
- }
1000
- return "";
1001
- case FormFieldType.TimePicker.code:
1002
- if (data != null) {
1003
- return dayjs(data).format(controlAttr.timeFormat || "HH:mm:ss");
1004
- }
1005
- return "";
1006
- case FormFieldType.DatePicker.code:
1007
- if (data != null) {
1008
- return dayjs(data).format(controlAttr.dateFormat || "YYYY-MM-dd");
1009
- }
1010
- return "";
1011
- case FormFieldType.Cascader.code:
1012
- if (data != null) {
1013
- return this.cascaderContextRecursion(data, this.cascaderOptions);
1014
- }
1015
- return "";
1016
- case FormFieldType.TreeSelect.code:
1017
- if (data != null) {
1018
- return this.treeSelectContextRecursion(data, this.treeSelectOptions);
1019
- }
1020
- return "";
1021
- case FormFieldType.Custom.code:
1022
- if (this.customFormats && this.customFormats[controlAttr.customFieldName]) {
1023
- const customFormat: CustomFormat = this.customFormats[controlAttr.customFieldName];
1024
- if (customFormat && customFormat.display) {
1025
- return customFormat.display(data, controlAttr);
1026
- }
1027
- }
1028
- }
1029
- return data;
1030
- }
1031
-
1032
- /**
1033
- * @description: 支持的上传类型
1034
- * @author ChenRui
1035
- * @date 2021/4/25 11:50
1036
- */
1037
- get uploadType(): any {
1038
- const controlAttr = this.controlAttr as DesFormControl;
1039
- if (controlAttr.supportUploadType === SupportUploadType.Arbitrarily.code) {
1040
- return undefined;
1041
- } else if (controlAttr.supportUploadType === SupportUploadType.Custom.code) {
1042
- return controlAttr.customUploadType;
1043
- }
1044
- return undefined;
1045
- }
1046
-
1047
- /**
1048
- * @description: 下拉选项新增
1049
- * @author ChenRui
1050
- * @date 2021/1/14 20:05
1051
- */
1052
- selectAddItem(event: any): void {
1053
- this.$emit("add-item", event);
1054
- /*const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1055
- if (controlAttr != null) {
1056
- if (controlAttr.isOptionType === OptionType.Fixed.code) {
1057
- console.log(controlAttr.optionConfig);
1058
- } else if (controlAttr.isOptionType === OptionType.Dynamic.code) {
1059
- if (controlAttr.dynamicOptionType === DynamicOptionType.GeneralDictionary.code) {
1060
- console.log(controlAttr.generalDictionaryOptions);
1061
- }
1062
- }
1063
- }*/
1064
- }
1065
-
1066
- /**
1067
- * @description: 级联搜索
1068
- * @author ChenRui
1069
- * @date 2021/5/19 17:23
1070
- */
1071
- cascaderFilter(inputValue: any, path: any): any {
1072
- return path.some((option: any) => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
1073
- }
1074
-
1075
- /**
1076
- * @description: 递归生成树形下拉选项
1077
- * @author ChenRui
1078
- * @date 2021/1/5 16:44
1079
- */
1080
- treeSelectRecursion(items: any[]): any[] {
1081
- const options: any[] = [];
1082
- items.forEach((item) => {
1083
- item.disabled = false;
1084
- item.key = item.value;
1085
- if (item.children && item.children.length > 0) {
1086
- if ((this.controlAttr as any).disableNonLeafNodes !== "0") {
1087
- item.disabled = true; // LiuBo 2023年11月7日11:33:41 禁用非叶子节点
1088
- }
1089
- this.treeSelectRecursion(item.children);
1090
- }
1091
- });
1092
- return options;
1093
- }
1094
-
1095
- /**
1096
- * @description: 级联递归
1097
- * @author ChenRui
1098
- * @date 2021/1/5 16:35
1099
- */
1100
- cascaderRecursion(items: any[]): any[] {
1101
- const options: any[] = [];
1102
- items.forEach((item) => {
1103
- const option: any = {
1104
- value: item.value,
1105
- label: item.title,
1106
- isLeaf: false,
1107
- };
1108
- options.push(option);
1109
- if (item.children && item.children.length > 0) {
1110
- option.children = this.cascaderRecursion(item.children);
1111
- } else {
1112
- option.isLeaf = true;
1113
- }
1114
- });
1115
- return options;
1116
- }
1117
-
1118
- /**
1119
- * @description: 递归获取级联选项对应的文本
1120
- * @author ChenRui
1121
- * @date 2021/1/8 14:45
1122
- */
1123
- cascaderContextRecursion(val: any[], cascaderOptions: any[], index = 0): string {
1124
- if (val && val.length > 0 && cascaderOptions && cascaderOptions.length > 0) {
1125
- if (val.length > index) {
1126
- const currentIndex = val[index];
1127
- const cascaderOption = cascaderOptions.find((item) => item.value === currentIndex);
1128
- if (cascaderOption != null) {
1129
- let currentText = cascaderOption.label;
1130
- if (val.length > index + 1) {
1131
- const subText = this.cascaderContextRecursion(val, cascaderOption.children, index + 1);
1132
- currentText += " / " + subText;
1133
- }
1134
- return currentText;
1135
- }
1136
- }
1137
- }
1138
- return "";
1139
- }
1140
-
1141
- /**
1142
- * @description:
1143
- * @author ChenRui
1144
- * @date 2021/1/8 15:05
1145
- */
1146
-
1147
- treeSelectContextRecursion(val: string, treeSelectOptions: any[]): string {
1148
- if (val && treeSelectOptions && treeSelectOptions.length > 0) {
1149
- for (let i = 0; i < treeSelectOptions.length; i++) {
1150
- if (treeSelectOptions[i].value === val) {
1151
- return treeSelectOptions[i].title;
1152
- } else if (treeSelectOptions[i].children && treeSelectOptions[i].children.length > 0) {
1153
- const subTitle: string = this.treeSelectContextRecursion(val, treeSelectOptions[i].children);
1154
- if (subTitle) {
1155
- return subTitle;
1156
- }
1157
- }
1158
- }
1159
- }
1160
- return "";
1161
- }
1162
-
1163
- /**
1164
- * @description: 是否为ie
1165
- * @author ChenRui
1166
- * @date 2021/3/25 14:44
1167
- */
1168
- get isIe(): boolean {
1169
- return !!this.provideInjectData.widthCompatibleMode || !!window.ActiveXObject || "ActiveXObject" in window;
1170
- }
1171
-
1172
- /**
1173
- * @description: ie 兼容性宽度布局
1174
- * @author ChenRui
1175
- * @date 2021/3/25 12:53
1176
- */
1177
- get divWidthCompatibleToIe(): any {
1178
- if (this.isIe) {
1179
- const desFormLayout: DesFormLayout = this.parentControlAttr as DesFormLayout;
1180
- const configIndex: number = this.index! % desFormLayout.gridColumnConfig.length; // 索引位置
1181
- const proportion: number = desFormLayout.gridColumnConfig[configIndex].value; // 比重
1182
- let total = 0; // 总值
1183
- desFormLayout.gridColumnConfig.forEach((item: any) => {
1184
- total += Number(item.value);
1185
- });
1186
- const ratio = proportion / total; // 比值
1187
- const val = Number(ratio) * 100;
1188
- return `calc( ${val}% - 1px)`;
1189
- } else {
1190
- return "100%";
1191
- }
1192
- }
1193
-
1194
- /**
1195
- * @description: 根节点容器布局样式
1196
- * @author ChenRui
1197
- * @date 2021/3/25 14:52
1198
- */
1199
- get emptyLayoutContainerStyle(): any {
1200
- let style: any = {};
1201
- if (this.isIe) {
1202
- style = { display: "flex", "flex-wrap": "wrap" };
1203
- } else {
1204
- const gridTemplateColumns: any = generateGridTemplateColumns((this.control?.controlAttr as DesFormLayout)?.gridColumnConfig);
1205
- style = { "grid-template-columns": gridTemplateColumns };
1206
- }
1207
- return style;
1208
- }
1209
-
1210
- /**
1211
- * @description: 常规布局容器样式
1212
- * @author ChenRui
1213
- * @date 2021/3/25 14:42
1214
- */
1215
- get generalLayoutContainerStyle(): any {
1216
- let style: any = {};
1217
- if (this.isIe) {
1218
- style = { display: "flex", "flex-wrap": "wrap" };
1219
- } else {
1220
- const gridColumnEnd: any = generateGridColumnEnd((this.parentControl?.controlAttr as DesFormLayout)?.gridColumnConfig);
1221
- const gridTemplateColumns: any = generateGridTemplateColumns((this.control?.controlAttr as DesFormLayout)?.gridColumnConfig);
1222
- style = {
1223
- "grid-column-end": gridColumnEnd,
1224
- "grid-template-columns": gridTemplateColumns,
1225
- };
1226
- }
1227
- return style;
1228
- }
1229
-
1230
- /**
1231
- * @description: 初始化部分数据
1232
- * @author ChenRui
1233
- * @date 2021/1/29 15:28
1234
- */
1235
- initFormControlData(): void {
1236
- if (this.control && this.control.formControl) {
1237
- if (this.control!.code === FormFieldType.DatePicker.code || this.control!.code === FormFieldType.TimePicker.code) {
1238
- if (this.control.formControl.value) {
1239
- if (typeof this.control.formControl.value === "string") {
1240
- this.control.formControl.value = dayjs(new Date(this.control.formControl.value));
1241
- } else if (this.control.formControl.value instanceof Date) {
1242
- this.control.formControl.value = dayjs(this.control.formControl.value);
1243
- }
1244
- }
1245
- }
1246
- if (this.control.formControl.textNoticeCallback == null) {
1247
- this.control.formControl.textNoticeCallback = () => {
1248
- return this.formatData;
1249
- };
1250
- }
1251
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1252
- if (controlAttr.maxValue == null || (controlAttr.maxValue as any) === "") {
1253
- const maxValue = "9999999999999999";
1254
- if (controlAttr.decimalPlaces != undefined && (controlAttr.decimalPlaces as any) !== "" && controlAttr.decimalPlaces > 0) {
1255
- if (controlAttr.decimalPlaces > 16) {
1256
- controlAttr.decimalPlaces = 16;
1257
- }
1258
- controlAttr.maxValue = Number(maxValue.slice(0, maxValue.length - controlAttr.decimalPlaces) + "." + maxValue.slice(maxValue.length - controlAttr.decimalPlaces, maxValue.length));
1259
- } else {
1260
- controlAttr.maxValue = Number(maxValue);
1261
- }
1262
- }
1263
- }
1264
- }
1265
-
1266
- /**
1267
- * @description: 业务属性
1268
- * @author ChenRui
1269
- * @date 2021/2/1 14:38
1270
- */
1271
- get busAttr(): any {
1272
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1273
- let busAttr: any;
1274
- let attrSubmittedType: any[] = [];
1275
- if (controlAttr.busAttr) {
1276
- busAttr = formBeanUtilsService.parse(controlAttr.busAttr);
1277
- if (busAttr[FormBusAttr.SUBMITTED_TYPE.code]) {
1278
- attrSubmittedType = busAttr[FormBusAttr.SUBMITTED_TYPE.code].split(",").filter((item: any) => !!item);
1279
- }
1280
- }
1281
- const submittedType: any[] = Object.values(SubmittedType).map((val: any) => ({ label: val.name, value: val.code }));
1282
- const submittedTypeCheckedNode: any[] = [];
1283
- submittedType.forEach((item) => {
1284
- if (attrSubmittedType.findIndex((it) => it === item.value) > -1) {
1285
- submittedTypeCheckedNode.push(item);
1286
- }
1287
- });
1288
- return {
1289
- [FormBusAttr.SUBMITTED_TYPE.code]: submittedTypeCheckedNode,
1290
- [FormBusAttr.IS_SUPPLEMENT.code]: busAttr ? busAttr[FormBusAttr.IS_SUPPLEMENT.code] : false,
1291
- [FormBusAttr.IS_KEY_ELEMENTS.code]: busAttr ? busAttr[FormBusAttr.IS_KEY_ELEMENTS.code] : false,
1292
- [FormBusAttr.IS_TRACK.code]: busAttr ? busAttr[FormBusAttr.IS_TRACK.code] : false,
1293
- };
1294
- }
1295
-
1296
- /**
1297
- * @description: 报送类型
1298
- * @author ChenRui
1299
- * @date 2021/2/1 15:05
1300
- */
1301
- get submittedType(): any[] {
1302
- if (this.busAttr && this.busAttr[FormBusAttr.SUBMITTED_TYPE.code].length > 0) {
1303
- return this.busAttr[FormBusAttr.SUBMITTED_TYPE.code];
1304
- }
1305
- return [];
1306
- }
1307
-
1308
- /**
1309
- * @description: 报送类型字符串
1310
- * @author ChenRui
1311
- * @date 2021/2/1 15:08
1312
- */
1313
- get submittedTypeStr(): string {
1314
- return this.submittedType.map((item) => item.label).join("、");
1315
- }
1316
-
1317
- /**
1318
- * 根据日期时间格式决定是否显示时间选择功能
1319
- * @param format
1320
- */
1321
- showPickerTime(format?: string): any {
1322
- // format 包含时间格式
1323
- if (format && format.indexOf("HH:mm") > -1) {
1324
- return format;
1325
- }
1326
- return false;
1327
- }
1328
- /**
1329
- * @description: 清除特殊字符
1330
- * @author ChenRui
1331
- * @date 2021/6/22 15:41
1332
- */
1333
- private clearNoNum(value: any) {
1334
- if (value) {
1335
- value = value.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
1336
- value = value.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
1337
- value = value.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
1338
- // eslint-disable-next-line no-useless-escape
1339
- value = value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3"); //只能输入两个小数
1340
- if (value.indexOf(".") < 0 && value != "") {
1341
- //以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
1342
- value = parseFloat(value);
1343
- }
1344
- }
1345
- return value;
1346
- }
1347
-
1348
- /**
1349
- * @description: 校验数字是否超过16位纯编码
1350
- * @author ChenRui
1351
- * @date 2021/6/22 14:58
1352
- */
1353
- private validateNumBeyondLimit(value: any): boolean {
1354
- if (value) {
1355
- const pureNumber: string = value.replace(/[^0-9]/gi, "");
1356
- return pureNumber.length > 16;
1357
- }
1358
- return false;
1359
- }
1360
-
1361
- /**
1362
- * @description: 删除文件
1363
- * @author ChenRui
1364
- * @date 2021/4/25 11:35
1365
- */
1366
- handleRemove(file: any): void {
1367
- const index = this.formControl.value.indexOf(file);
1368
- const newFileList = this.formControl.value.slice();
1369
- newFileList.splice(index, 1);
1370
- this.formControl.value = newFileList;
1371
- }
1372
-
1373
- /**
1374
- * @description: 文件上传前回调函数
1375
- * @author ChenRui
1376
- * @date 2021/4/25 11:23
1377
- */
1378
- beforeUpload(file: any): boolean {
1379
- const fileList: any[] = [...this.formControl.value, file];
1380
- this.formControl.value = fileList;
1381
- return false;
1382
- }
1383
-
1384
- /**
1385
- * @description: 文件上传变更
1386
- * @author ChenRui
1387
- * @date 2021/4/25 11:29
1388
- */
1389
- handleUploadChange(event: any): any {
1390
- let fileList: any[] = [...this.formControl.value];
1391
- const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1392
- if (controlAttr.maxUploadNumber && controlAttr.maxUploadNumber > 0) {
1393
- fileList = fileList.slice(0 - Number(controlAttr.maxUploadNumber));
1394
- }
1395
- fileList = fileList.map((file) => {
1396
- if (file.response) {
1397
- file.url = file.response.url;
1398
- }
1399
- return file;
1400
- });
1401
- this.formControl.value = fileList;
1402
- if (event && event.file && (event.file.status === undefined || event.file.status === "removed")) {
1403
- this.onChange(this.control!);
1404
- }
1405
- }
1406
-
1407
- /**
1408
- * @description: 金额菜单单机事件
1409
- * @author ChenRui
1410
- * @date 2021/2/20 17:21
1411
- */
1412
- handleMoneyUnitMenuClick(e: any): void {
1413
- this.defaultMoneyUnit = this.moneyUnits.find((item) => item.code === e.key);
1414
- }
1415
-
1416
- /**
1417
- * @description: 将下拉弹层渲染节点固定在触发器的父元素中
1418
- * @author ZPFly
1419
- * @date 2022/8/31 11:30
1420
- */
1421
- getPopupContainer(triggerNode: any) {
1422
- return triggerNode.parentNode;
1423
- }
1424
-
1425
- /**
1426
- * @description: 输入事件处理
1427
- * @author ChenRui
1428
- * @date 2020/12/2 14:37
1429
- */
1430
- onChange(event: Control): void {
1431
- if (this.control && (this.control.type === FormFieldClass.Base.code || this.control.type === FormFieldClass.Senior.code)) {
1432
- this.validateResult = this.formControl.validate(event.formControl?.value);
1433
- }
1434
- this.$emit("change", event);
1435
- }
1436
-
1437
- /**
1438
- * @description: 点击事件
1439
- * @author ChenRui
1440
- * @date 2021/3/4 11:37
1441
- */
1442
- onClick(event: Control): void {
1443
- this.$emit("click", event);
1444
- }
1445
-
1446
- /**
1447
- * @description: 内置前置标签事件
1448
- * @author ChenRui
1449
- * @date 2021/4/23 9:42
1450
- */
1451
- onAddonBeforeHandler(event: any): void {
1452
- this.$emit("addon-before", event);
1453
- }
1454
-
1455
- /**
1456
- * @description: 内置后置标签事件
1457
- * @author ChenRui
1458
- * @date 2021/4/23 9:43
1459
- */
1460
- onAddonAfterHandler(event: any): void {
1461
- this.$emit("addon-after", event);
1462
- }
1463
-
1464
- /**
1465
- * @description: 数字框失焦点
1466
- * @author ChenRui
1467
- * @date 2021/3/4 11:51
1468
- */
1469
- onInputNumberFocus(event: Control): void {
1470
- this.onFocus(event);
1471
- if ((this.controlAttr as DesFormControl).isShowCapitalization) {
1472
- this.numberPopoverVisible = true;
1473
- }
1474
- }
1475
-
1476
- /**
1477
- * @description: 数字输入框失焦
1478
- * @author ChenRui
1479
- * @date 2021/3/4 11:43
1480
- */
1481
- onInputNumberBlur(event: Control): void {
1482
- this.onBlur(event);
1483
- if ((this.controlAttr as DesFormControl).isShowCapitalization) {
1484
- this.numberPopoverVisible = false;
1485
- }
1486
- }
1487
-
1488
- /**
1489
- * @description: 获取焦点
1490
- * @author ChenRui
1491
- * @date 2021/3/4 11:46
1492
- */
1493
- onFocus(event: Control): void {
1494
- this.$emit("focus", event);
1495
- }
1496
-
1497
- /**
1498
- * @description: 失焦事件
1499
- * @author ChenRui
1500
- * @date 2021/3/4 11:38
1501
- */
1502
- onBlur(event: Control): void {
1503
- this.$emit("blur", event);
1504
- }
1505
-
1506
- /**
1507
- * @Description 是否节假日校验
1508
- * @Author JiangTao
1509
- * @Date 2024-04-16 下午 02:33
1510
- */
1511
- isRest(current: any): boolean {
1512
- if (JSON.parse(this.weekdayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1513
- return true;
1514
- } else {
1515
- return false;
1516
- }
1517
- }
1518
-
1519
- /**
1520
- * @Description 是否工作日校验
1521
- * @Author JiangTao
1522
- * @Date 2024-04-16 下午 02:33
1523
- */
1524
- isWeekday(current: any): boolean {
1525
- if (JSON.parse(this.workdayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1526
- return true;
1527
- } else {
1528
- return false;
1529
- }
1530
- }
1531
-
1532
- /**
1533
- * @Description 是否交易日校验
1534
- * @Author JiangTao
1535
- * @Date 2024-04-16 下午 02:33
1536
- */
1537
- isRadingDay(current: any): boolean {
1538
- if (JSON.parse(this.traddayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1539
- return true;
1540
- } else {
1541
- return false;
1542
- }
1543
- }
1544
-
1545
- /**
1546
- * @Description 日期格式转换
1547
- * @Author JiangTao
1548
- * @Date 2024-04-16 下午 02:33
1549
- */
1550
- DateTime(date: any): string {
1551
- const year: any = date.getFullYear();
1552
- let month: any = date.getMonth() + 1;
1553
- let strDate: any = date.getDate();
1554
-
1555
- if (month < 10) {
1556
- month = "0" + month;
1557
- }
1558
-
1559
- if (strDate < 10) {
1560
- strDate = "0" + strDate;
1561
- }
1562
-
1563
- return "" + year + month + strDate;
1564
- }
1565
- }
1566
- </script>
1567
- <style lang="scss" scoped>
1568
- @import "../../styles/themes.scss";
1569
- </style>
1
+ <template>
2
+ <div v-if="(control.type === formFieldClass.Base.code || control.type === formFieldClass.Senior.code) && !controlAttr.isHideControl" class="lo-control-container" :style="{ width: divWidthCompatibleToIe }">
3
+ <div class="lo-control-box">
4
+ <a-form-item
5
+ :labelCol="{
6
+ style: 'min-width: ' + labelSpanWidth + ';width:' + labelSpanWidth,
7
+ }"
8
+ :wrapperCol="{
9
+ style: 'max-width: ' + controlSpanMaxWidth + ';width: ' + controlSpanWidth,
10
+ }"
11
+ :colon="colon"
12
+ :labelAlign="labelAlign"
13
+ :required="required"
14
+ :validate-status="validateResult.validateStatus"
15
+ :help="provideInjectData.edit ? validateResult.errorMsg : null"
16
+ :class="{
17
+ ['form-model-item-' + controlAttr.boundProperty]: true,
18
+ ['form-model-item-' + control.code]: true,
19
+ 'lo-form-model-item-textarea-box': control.code === formFieldType.Textarea.code,
20
+ }"
21
+ >
22
+ <template v-slot:label>
23
+ <span v-if="!controlAttr.isHideTitle">
24
+ <span :class="{ 'lo-fw': controlAttr.isBoldTitle }" :style="{ color: controlAttr.titleColor }">{{ controlAttr.formFieldDescribe }}</span>
25
+ <a-tooltip class="lo-label-sub-type-icon" placement="right" :title="submittedTypeStr" overlayClassName="lo-form-item-tooltip" v-if="submittedType.length > 0">
26
+ <img :src="submittedSvg" />
27
+ </a-tooltip>
28
+ <a-tooltip class="lo-label-tips-icon" placement="right" :title="controlAttr.tips" overlayClassName="lo-form-item-tooltip" v-if="controlAttr.tips">
29
+ <question-circle-outlined style="font-size: 13px" />
30
+ </a-tooltip>
31
+ <a-popconfirm overlayClassName="lo-label-history-popconfirm" placement="right" ok-text="确定" v-if="formControl.history && formControl.history.length">
32
+ <template v-slot:title>
33
+ <div class="lo-history-popconfirm-title">历史修改</div>
34
+ <div>
35
+ <a-timeline class="lo-history-timeline">
36
+ <a-timeline-item v-for="(item, index) of formControl.history" :key="index">
37
+ <template v-slot:dot>
38
+ <clock-circle-outlined style="font-size: 13px" />
39
+ </template>
40
+ <div class="lo-history-context">
41
+ <div>{{ item.time }}</div>
42
+ <div class="lo-important lo-mx-10">
43
+ {{ item.before }}
44
+ </div>
45
+ 改为
46
+ <div class="lo-important lo-mx-10">
47
+ {{ item.after }}
48
+ </div>
49
+ 修改人
50
+ <div class="lo-important lo-ml-10">
51
+ {{ item.author }}
52
+ </div>
53
+ </div>
54
+ </a-timeline-item>
55
+ </a-timeline>
56
+ </div>
57
+ </template>
58
+ <img class="lo-label-history-icon" :src="historySvg" />
59
+ </a-popconfirm>
60
+ </span>
61
+ </template>
62
+ <template v-if="provideInjectData.edit">
63
+ <template v-if="control.code === formFieldType.Input.code">
64
+ <template v-if="provideInjectData.edit">
65
+ <component
66
+ :is="inputShape"
67
+ :class="{
68
+ 'addon-before': $slots['input:addonBefore:' + formControl.key] || controlAttr.bindingPrefix || controlAttr.builtInFrontLabel,
69
+ 'addon-after': $slots['input:addonAfter:' + formControl.key] || controlAttr.bindingSuffix || controlAttr.builtInPostLabel,
70
+ }"
71
+ v-model:value="formControl.value"
72
+ :placeholder="controlAttr.placeholder"
73
+ :disabled="controlAttr.isNotEdit"
74
+ :data-source="controlAttr.autoCompleteOptions"
75
+ @focus="onFocus(control)"
76
+ @blur="onBlur(control)"
77
+ @input="onChange(control)"
78
+ @click="onClick(control)"
79
+ >
80
+ <template v-slot:prefix v-if="$slots['input:prefix:' + formControl.key]">
81
+ <slot :name="'input:prefix:' + formControl.key"></slot>
82
+ </template>
83
+ <template v-slot:suffix v-if="$slots['input:suffix:' + formControl.key]">
84
+ <slot :name="'input:suffix:' + formControl.key"></slot>
85
+ </template>
86
+ <template v-slot:addonBefore v-if="$slots['input:addonBefore:' + formControl.key] || controlAttr.bindingPrefix || controlAttr.builtInFrontLabel">
87
+ <span class="addon-inner" @click="onAddonBeforeHandler(control)">
88
+ <template v-if="$slots['input:addonBefore:' + formControl.key]">
89
+ <slot :name="'input:addonBefore:' + formControl.key"> </slot>
90
+ </template>
91
+ <template v-else-if="controlAttr.bindingPrefix">
92
+ {{ controlAttr.bindingPrefix }}
93
+ </template>
94
+ <template v-else-if="controlAttr.builtInFrontLabel">
95
+ <search-outlined class="addon-icon" />
96
+ </template>
97
+ </span>
98
+ </template>
99
+ <template v-slot:addonAfter v-if="$slots['input:addonAfter:' + formControl.key] || controlAttr.bindingSuffix || controlAttr.builtInPostLabel">
100
+ <span class="addon-inner" @click="onAddonAfterHandler(control)">
101
+ <template v-if="$slots['input:addonAfter:' + formControl.key]">
102
+ <slot :name="'input:addonAfter:' + formControl.key"></slot>
103
+ </template>
104
+ <template v-else-if="controlAttr.bindingSuffix">
105
+ {{ controlAttr.bindingSuffix }}
106
+ </template>
107
+ <template v-else-if="controlAttr.builtInPostLabel">
108
+ <search-outlined class="addon-icon" />
109
+ </template>
110
+ </span>
111
+ </template>
112
+ </component>
113
+ </template>
114
+ </template>
115
+ <template v-else-if="control.code === formFieldType.Textarea.code">
116
+ <a-textarea v-model:value="control.formControl.value" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" :rows="controlAttr.textareaRows || 3" :showCount="!!maxCharacterCount" :maxlength="maxCharacterCount" @input="onChange(control)" @focus="onFocus(control)" @blur="onBlur(control)" @click="onClick(control)" />
117
+ </template>
118
+ <template v-if="control.code === formFieldType.InputNumber.code">
119
+ <span
120
+ class="lo-input-number-box"
121
+ tabindex="1"
122
+ :class="{
123
+ 'lo-with-unit': controlAttr.zoomType === zoomType.automatic.code && moneyUnits.length > 0,
124
+ ['lo-unit-' + moneyUnitsIndentScale]: true,
125
+ }"
126
+ >
127
+ <a-popover
128
+ placement="topLeft"
129
+ trigger="focus"
130
+ :getPopupContainer="
131
+ (triggerNode) => {
132
+ return triggerNode.parentNode || document.body;
133
+ }
134
+ "
135
+ >
136
+ <template v-if="numberPopoverVisible" #content>
137
+ <span class="number-format-show">
138
+ {{ amountCapitalization(zoomMultiple(formControl.value, formControl)) }}
139
+ </span>
140
+ </template>
141
+ <a-input-number
142
+ :step="controlAttr.step || 1"
143
+ :min="controlAttr.minValue != null ? controlAttr.minValue : undefined"
144
+ :max="controlAttr.maxValue != null ? controlAttr.maxValue : undefined"
145
+ :formatter="numberFormatter"
146
+ :parser="numberParser"
147
+ :precision="controlAttr.decimalPlaces"
148
+ :placeholder="controlAttr.placeholder"
149
+ :disabled="controlAttr.isNotEdit"
150
+ v-model:value="formControl.value"
151
+ @change="onChange(control)"
152
+ @click="onClick(control)"
153
+ @focus="onInputNumberFocus(control)"
154
+ @blur="onInputNumberBlur(control)"
155
+ >
156
+ <template v-slot:addonAfter v-if="controlAttr.unit">
157
+ <span class="addon-inner">{{ controlAttr.unit }}</span>
158
+ </template>
159
+ </a-input-number>
160
+ <a-dropdown v-if="controlAttr.zoomType === zoomType.automatic.code && moneyUnits.length > 0">
161
+ <template v-slot:overlay>
162
+ <a-menu @click="handleMoneyUnitMenuClick">
163
+ <a-menu-item v-for="unit in moneyUnits" :key="unit.code">{{ unit.name }}</a-menu-item>
164
+ </a-menu>
165
+ </template>
166
+ <a-button>
167
+ {{ defaultMoneyUnit.name }}
168
+ <down-outlined v-if="moneyUnits.length > 1" />
169
+ </a-button>
170
+ </a-dropdown>
171
+ </a-popover>
172
+ </span>
173
+ </template>
174
+ <template v-if="control.code === formFieldType.Select.code">
175
+ <a-select
176
+ class="lo-select"
177
+ :dropdownClassName="controlAttr.hiddenDropdown ? 'lo-select-hide-drop-down-content' : ''"
178
+ :class="{
179
+ 'lo-select-multiple-suffix-icon': controlAttr.isMultipleChoice && ($slots['select:suffixIcon:' + formControl.key] || controlAttr.bindingSuffix),
180
+ }"
181
+ showArrow
182
+ v-model:value="formControl.value"
183
+ :allow-clear="true"
184
+ show-search
185
+ :mode="controlAttr.isMultipleChoice ? 'multiple' : ''"
186
+ :disabled="controlAttr.isNotEdit"
187
+ :placeholder="controlAttr.placeholder"
188
+ @change="onChange(control)"
189
+ @click="onClick(control)"
190
+ :get-popup-container="getPopupContainer"
191
+ :filter-option="filterOption"
192
+ >
193
+ <template #dropdownRender="{ menuNode: menu }">
194
+ <v-nodes :vnodes="menu" />
195
+ <template v-if="controlAttr.canAddEntry">
196
+ <a-divider style="margin: 4px 0" />
197
+ <div style="padding: 4px 8px 6px 8px; cursor: pointer" @mousedown="(e) => e.preventDefault()" @click="selectAddItem(control)"><plus-outlined />新增</div>
198
+ </template>
199
+ </template>
200
+ <template #default>
201
+ <a-select-option v-for="item in options" :value="item.value" :key="item.value" :title="item.title" :disabled="item.disabled ? item.disabled : false">{{ item.title }}</a-select-option>
202
+ </template>
203
+ <template #suffixIcon v-if="$slots['select:suffixIcon:' + formControl.key] || controlAttr.bindingSuffix">
204
+ <template v-if="$slots['select:suffixIcon:' + formControl.key]">
205
+ <slot :name="'select:suffixIcon:' + formControl.key"></slot>
206
+ </template>
207
+ <template v-else>
208
+ {{ controlAttr.bindingSuffix }}
209
+ </template>
210
+ </template>
211
+ </a-select>
212
+ </template>
213
+ <template v-if="control.code === formFieldType.Radio.code">
214
+ <a-radio-group class="w-100" v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)">
215
+ <a-radio v-for="item in options" :key="item.value" :value="item.value">{{ item.title }}</a-radio>
216
+ </a-radio-group>
217
+ </template>
218
+ <template v-if="control.code === formFieldType.Checkbox.code">
219
+ <a-checkbox-group class="w-100" v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)">
220
+ <a-row>
221
+ <a-col>
222
+ <a-checkbox v-for="item in options" :key="item.value" :value="item.value" class="ml-0 mr-5" :style="{ width: controlAttr.checkboxStyle ? 'auto' : '10rem' }">
223
+ <a-tooltip>
224
+ <template #title>
225
+ <span>{{ item.title }}</span>
226
+ </template>
227
+ {{ item.title }}
228
+ </a-tooltip>
229
+ </a-checkbox>
230
+ </a-col>
231
+ </a-row>
232
+ </a-checkbox-group>
233
+ </template>
234
+ <template v-if="control.code === formFieldType.Switch.code">
235
+ <a-switch v-model:checked="formControl.value" :checked-children="controlAttr.onOpeningText" :un-checked-children="controlAttr.whenClosedText" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" />
236
+ </template>
237
+ <template v-if="control.code === formFieldType.TimePicker.code">
238
+ <a-time-picker class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :use12-hours="is12Hours" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
239
+ </template>
240
+ <template v-if="control.code === formFieldType.DatePicker.code">
241
+ <a-month-picker v-if="useMonthPicker" class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
242
+ <a-date-picker v-else-if="controlAttr.isShowHoliday" class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :showTime="showPickerTime(controlAttr.dateFormat)" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)">
243
+ <template #dateRender="{ current }">
244
+ <div class="ant-picker-cell-inner calendar-control-style">
245
+ <div class="date-control-style">
246
+ <div class="eest-day-style"></div>
247
+ <div class="date-style">{{ current.date() }}</div>
248
+ <div class="eest-day-style">
249
+ <div class="holidays-style" v-if="isRest(current)">休</div>
250
+ <div class="weekday-style" v-else-if="isWeekday(current)">班</div>
251
+ </div>
252
+ </div>
253
+ <div class="date-type-style">
254
+ <!-- 交易日 -->
255
+ <div class="trading-day-style" v-if="isRadingDay(current)"></div>
256
+ </div>
257
+ </div>
258
+ </template>
259
+ <template #renderExtraFooter>
260
+ <div class="legend">
261
+ <div class="day-explain-style">
262
+ <div class="trading-day-icon"></div>
263
+ <div class="day-explain">交易日</div>
264
+ </div>
265
+ </div>
266
+ </template>
267
+ </a-date-picker>
268
+ <a-date-picker v-else class="w-100" :get-popup-container="getPopupContainer" :locale="locale" :showTime="showPickerTime(controlAttr.dateFormat)" :format="controlAttr.dateFormat" :placeholder="controlAttr.placeholder" :disabled="controlAttr.isNotEdit" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
269
+ </template>
270
+ <template v-if="control.code === formFieldType.Slider.code">
271
+ <a-slider v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" />
272
+ </template>
273
+ <template v-if="control.code === formFieldType.Cascader.code">
274
+ <a-cascader :get-popup-container="getPopupContainer" :changeOnSelect="controlAttr.changeOnSelect" :placeholder="controlAttr.placeholder" :show-search="{ cascaderFilter }" :disabled="controlAttr.isNotEdit" :options="cascaderOptions" v-model:value="formControl.value" @change="onChange(control)" @click="onClick(control)" />
275
+ </template>
276
+ <template v-if="control.code === formFieldType.TreeSelect.code">
277
+ <a-tree-select
278
+ :get-popup-container="getPopupContainer"
279
+ v-model:value="formControl.value"
280
+ :show-search="true"
281
+ :treeNodeFilterProp="'title'"
282
+ :disabled="controlAttr.isNotEdit"
283
+ :placeholder="controlAttr.placeholder"
284
+ :dropdown-style="{ maxHeight: '250px', overflow: 'auto' }"
285
+ :tree-data="treeSelectOptions"
286
+ @change="onChange(control)"
287
+ @click="onClick(control)"
288
+ :treeDefaultExpandAll="controlAttr.isTreeOpen"
289
+ >
290
+ </a-tree-select>
291
+ </template>
292
+ <template v-if="control.code === formFieldType.Rate.code">
293
+ <a-rate v-model:value="formControl.value" :disabled="controlAttr.isNotEdit" @change="onChange(control)" @click="onClick(control)" allow-half />
294
+ </template>
295
+ <template v-if="control.code === formFieldType.Upload.code">
296
+ <a-upload :file-list="formControl.value" :accept="uploadType" :multiple="controlAttr.isMultipleChoice" @remove="handleRemove" :before-upload="beforeUpload" @change="handleUploadChange">
297
+ <a-button>
298
+ <upload-outlined />
299
+ 选择文件
300
+ </a-button>
301
+ </a-upload>
302
+ </template>
303
+ <template v-if="control.code === formFieldType.Custom.code && controlAttr.customFieldName">
304
+ <slot :control="control" :onChange="onChange" :name="controlAttr.customFieldName"></slot>
305
+ </template>
306
+ </template>
307
+ <template v-else>
308
+ <div class="lo-input-content">
309
+ <slot :name="'read:' + control.formControl.key" :content="formatData">
310
+ <stretch-text v-if="controlAttr.textFold" :content="formatData" :linkList="linkList" :fieldKey="control.formControl.key" @linkClick="linkClick({ key: formControl.key, value: formatData })"></stretch-text>
311
+ <div class="lo-control-text" :title="formatData" v-else>
312
+ <a v-if="linkList.indexOf(control.formControl.key) > -1" href="#" @click="linkClick({ key: formControl.key, value: formatData })">{{ formatData }}</a>
313
+ <span v-else>{{ formatData }}</span>
314
+ </div>
315
+ </slot>
316
+ </div>
317
+ <div class="flex-grow-1"></div>
318
+ <template v-if="controlAttr.unit">
319
+ <span class="addon-readonly">{{ controlAttr.unit }}</span>
320
+ </template>
321
+ </template>
322
+ </a-form-item>
323
+ </div>
324
+ </div>
325
+ <a-form v-else-if="control.type === formFieldClass.Layout.code && control.code === formFieldType.Empty.code" :class="'w-100 lo-empty-layout-container' + (controlAttr.layoutName ? ' lo-form-layout-' + controlAttr.layoutName : '')" :layout="layout" :style="emptyLayoutContainerStyle">
326
+ <dv-form-layout
327
+ v-for="(item, i) in control.subControls"
328
+ :key="i"
329
+ :index="i"
330
+ :customFormats="customFormats"
331
+ :control="item"
332
+ :parentControl="control"
333
+ :linkList="linkList"
334
+ @linkClick="linkClick"
335
+ @change="onChange($event)"
336
+ @click="onClick($event)"
337
+ @focus="onFocus($event)"
338
+ @blur="onBlur($event)"
339
+ @addon-before="onAddonBeforeHandler($event)"
340
+ @addon-after="onAddonAfterHandler($event)"
341
+ @add-item="selectAddItem($event)"
342
+ @fixFormLayout="onHideControl"
343
+ >
344
+ <template v-for="scopedPropName in Object.keys($slots)" v-slot:[scopedPropName]="{ content, control, onChange }">
345
+ <slot v-bind:content="content" v-bind:control="control" v-bind:onChange="onChange" :name="scopedPropName"></slot>
346
+ </template>
347
+ </dv-form-layout>
348
+ </a-form>
349
+ <a-form v-else-if="control.type === formFieldClass.Layout.code && control.code !== formFieldType.Empty.code" :class="'w-100 lo-general-layout-container' + (controlAttr.layoutName ? ' lo-form-layout-' + controlAttr.layoutName : '')" :layout="layout" :style="generalLayoutContainerStyle">
350
+ <dv-form-layout
351
+ v-for="(item, i) in control.subControls"
352
+ :key="i"
353
+ :index="i"
354
+ :customFormats="customFormats"
355
+ :control="item"
356
+ :parentControl="control"
357
+ :class="controlAttr.layoutName ? 'lo-form-layout-' + controlAttr.layoutName : ''"
358
+ @change="onChange($event)"
359
+ @click="onClick($event)"
360
+ @focus="onFocus($event)"
361
+ @blur="onBlur($event)"
362
+ @addon-before="onAddonBeforeHandler($event)"
363
+ @addon-after="onAddonAfterHandler($event)"
364
+ @add-item="selectAddItem($event)"
365
+ >
366
+ <template v-for="scopedPropName in Object.keys($slots)" v-slot:[scopedPropName]="{ content, control, onChange }">
367
+ <slot v-bind:content="content" v-bind:control="control" v-bind:onChange="onChange" :name="scopedPropName"></slot>
368
+ </template>
369
+ </dv-form-layout>
370
+ </a-form>
371
+ </template>
372
+
373
+ <script lang="ts">
374
+ import { Options, Inject, Prop, Watch, Vue } from "vue-property-decorator";
375
+ import { Control } from "@/domain";
376
+ import { FormEnum } from "@/domain";
377
+ import { FormFieldClass } from "@/constants";
378
+ import { FormFieldType } from "@/constants";
379
+ import generateGridTemplateColumns from "../../filtres/generate-grid-template-columns.filter";
380
+ import generateGridColumnEnd from "../../filtres/generate-grid-column-end.filter";
381
+ import { DesFormLayout } from "@/domain";
382
+ import { DesFormControl } from "@/domain";
383
+
384
+ import { AutoComplete, Cascader, Checkbox, DatePicker, Form, Input, InputNumber, Radio, Select, Switch, TimePicker, TreeSelect, Slider, Tooltip, Popover, Divider, Rate, Dropdown, Button, Menu, Upload, Popconfirm, Timeline, FormItem, RadioGroup, Textarea, CheckboxGroup, InputPassword, TimelineItem, Row, Col } from "ant-design-vue";
385
+ import { VerticalArrangement } from "@/constants";
386
+ import { formBeanUtilsService } from "@/services";
387
+ import { ProvideInjectData } from "@/domain/ProvideInjectData";
388
+
389
+ import amountCapitalization from "../../filtres/amount-capitalization.filter";
390
+ import { FormControl, ValidateResult, CustomFormat } from "../../domain";
391
+ import { FormBusAttr, SubmittedType, MoneyUnit, ControlFormatType, BuiltLabel, SupportUploadType } from "../../constants/enum";
392
+ import { ValidateRules } from "@/constants";
393
+ import { ZoomType } from "@/constants";
394
+ import { extractOptions } from "@/filtres/extract-options.filter";
395
+ import zoomMultiple from "../../filtres/zoom-multiple.filter";
396
+ import switchEnumConvert from "../../filtres/switch-enum-convert.filter";
397
+ import StretchText from "./StretchText.vue";
398
+ import { SUBMITTED_SVG_XML, HISTORY_SVG_XML } from "../../constants/encode-assets/svg";
399
+ import { SearchOutlined, PlusOutlined, QuestionCircleOutlined, ClockCircleOutlined, DownOutlined, UploadOutlined } from "@ant-design/icons-vue";
400
+
401
+ import dayjs from "dayjs";
402
+ import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
403
+ import pinYin from "../../../public/js/pinyin";
404
+
405
+ @Options({
406
+ name: "DvFormLayout",
407
+ filters: {
408
+ amountCapitalization: amountCapitalization,
409
+ switchEnumConvert: switchEnumConvert,
410
+ zoomMultiple: zoomMultiple,
411
+ },
412
+ components: {
413
+ StretchText,
414
+ PlusOutlined,
415
+ [Form.name]: Form,
416
+ [FormItem.name]: FormItem,
417
+ [Input.name]: Input,
418
+ [Textarea.name]: Textarea,
419
+ [AutoComplete.name]: AutoComplete,
420
+ [InputNumber.name]: InputNumber,
421
+ [Select.name]: Select,
422
+ [Select.Option.displayName + ""]: Select.Option,
423
+ [Select.OptGroup.displayName + ""]: Select.OptGroup,
424
+ [Radio.name]: Radio,
425
+ [RadioGroup.name]: RadioGroup,
426
+ [Checkbox.name]: Checkbox,
427
+ [CheckboxGroup.name]: CheckboxGroup,
428
+ [Switch.name]: Switch,
429
+ [TimePicker.name]: TimePicker,
430
+ [DatePicker.name]: DatePicker,
431
+ [Slider.name]: Slider,
432
+ [AutoComplete.name]: AutoComplete,
433
+ [Cascader.name]: Cascader,
434
+ [TreeSelect.name]: TreeSelect,
435
+ [Tooltip.name]: Tooltip,
436
+ [InputPassword.name]: InputPassword,
437
+ [Popover.name]: Popover,
438
+ [Popconfirm.name]: Popconfirm,
439
+ [Timeline.name]: Timeline,
440
+ [TimelineItem.name]: TimelineItem,
441
+ [Rate.name]: Rate,
442
+ [Dropdown.name]: Dropdown,
443
+ [Menu.name]: Menu,
444
+ [Menu.Item.name]: Menu.Item,
445
+ [Upload.name]: Upload,
446
+ [Button.name]: Button,
447
+ [Divider.name]: Divider,
448
+ [DatePicker.MonthPicker.name]: DatePicker.MonthPicker,
449
+ [StretchText.name]: StretchText,
450
+ [Row.name]: Row,
451
+ [Col.name]: Col,
452
+ VNodes: (_, { attrs }) => {
453
+ return attrs.vnodes;
454
+ },
455
+ QuestionCircleOutlined,
456
+ ClockCircleOutlined,
457
+ DownOutlined,
458
+ UploadOutlined,
459
+ SearchOutlined,
460
+ },
461
+ })
462
+ export default class DvFormLayout extends Vue {
463
+ locale = locale; // 国际化
464
+ submittedSvg = SUBMITTED_SVG_XML; // 上报图标
465
+ historySvg = HISTORY_SVG_XML; // 历史记录图标
466
+
467
+ numberPopoverVisible = false; // 是否开启数字气泡弹窗
468
+ validateResult: ValidateResult = {}; // 校验规则
469
+ metaRefresh: any; // 刷新标识
470
+ defaultMoneyUnit: any = {}; // 默认单位
471
+ zoomType = ZoomType; // 缩放类型
472
+ builtLabel = BuiltLabel; // 内置前/后置标签
473
+ traddayList: any = localStorage.getItem("traddayList") || JSON.stringify([]); // 交易日集合
474
+ weekdayList: any = localStorage.getItem("weekdayList") || JSON.stringify([]); // 节假日集合
475
+ workdayList: any = localStorage.getItem("workdayList") || JSON.stringify([]); // 工作日集合
476
+ amountCapitalization = amountCapitalization; // 大写转换
477
+ zoomMultiple = zoomMultiple; // 缩放
478
+ filterOption(value: any, item: any) {
479
+ if (!item.title) {
480
+ return false;
481
+ }
482
+ return item.title.indexOf(value) > -1 || pinYin.getCamelChars(item.title).indexOf(value) > -1 || pinYin.getFullChars(item.title).indexOf(value) > -1;
483
+ }
484
+
485
+ @Prop() index: number | undefined;
486
+ @Prop() control: Control | undefined;
487
+ @Prop() parentControl: Control | undefined;
488
+ @Prop({ type: Object, default: () => ({}) }) customFormats: { [key: string]: CustomFormat } | undefined;
489
+ @Prop({ type: Array, default: () => [] }) linkList: any | undefined; // 需要添加超链接点击事件数组 例:['cifNo', 'prodBaseNo']
490
+ @Inject() provideInjectData: ProvideInjectData | any;
491
+ readonly formFieldClass: FormEnum = FormFieldClass; // 表单字段分类
492
+ readonly formFieldType: FormEnum = FormFieldType; // 表单字段类型
493
+
494
+ @Watch("defaultMoneyUnit", { immediate: true })
495
+ onDefaultMoneyUnitHandler(newVal: any): void {
496
+ if (newVal.code != null) {
497
+ switch (newVal.code) {
498
+ case MoneyUnit.Yuan.code:
499
+ (this.controlAttr as DesFormControl).zoomMultiple = 1;
500
+ break;
501
+ case MoneyUnit.TenThousandYuan.code:
502
+ (this.controlAttr as DesFormControl).zoomMultiple = 10000;
503
+ break;
504
+ case MoneyUnit.HundredMillionYuan.code:
505
+ (this.controlAttr as DesFormControl).zoomMultiple = 100000000;
506
+ break;
507
+ }
508
+ }
509
+ }
510
+
511
+ /**
512
+ * @description: 校验反馈
513
+ * @author ChenRui
514
+ * @date 2021/2/26 14:24
515
+ */
516
+ @Watch("provideInjectData.refreshCheckFeedbackFlag")
517
+ @Watch("control.formControl.refreshValidate")
518
+ onValidationFeedbackHandle(): void {
519
+ this.validateResult = this.formControl.validate();
520
+ }
521
+
522
+ /**
523
+ * @description: 表单校验
524
+ * @author ChenRui
525
+ * @date 2022/4/6 14:12
526
+ */
527
+ @Watch("provideInjectData.formValidateStateResetMark")
528
+ onFormValidateStateResetMarkHandle(): void {
529
+ this.validateResult = {};
530
+ }
531
+ /**
532
+ * @Description 表单数据反显回调(data:Object { key: 元素码值, value: 元素值 })
533
+ * @Author JiangTao
534
+ * @Date 2023-10-07 下午 05:22
535
+ */
536
+ linkClick(data: any): void {
537
+ this.$emit("linkClick", data);
538
+ }
539
+
540
+ @Watch("control.controlAttr.isHideControl")
541
+ onHideControl() {
542
+ this.$nextTick(() => {
543
+ this.$emit("fixFormLayout");
544
+ });
545
+ }
546
+ /**
547
+ * @description: 输入框形态
548
+ * @author ChenRui
549
+ * @date 2022/5/7 17:48
550
+ */
551
+ get inputShape(): string {
552
+ if ((this.controlAttr as DesFormControl).isPasswordBox) {
553
+ return "a-input-password";
554
+ } else if ((this.controlAttr as DesFormControl).enableAutoComplete) {
555
+ return "a-auto-complete";
556
+ } else {
557
+ return "a-input";
558
+ }
559
+ }
560
+
561
+ /**
562
+ * @description: 获取控件对象
563
+ * @author ChenRui
564
+ * @date 2021/1/27 11:07
565
+ */
566
+ get formControl(): FormControl {
567
+ if (this.control && this.control.formControl) {
568
+ // 初始化部分数据
569
+ this.initFormControlData();
570
+ return this.control.formControl;
571
+ }
572
+ return new FormControl();
573
+ }
574
+
575
+ /**
576
+ * @description: 获取控件配置参数
577
+ * @author ChenRui
578
+ * @date 2021/1/5 11:26
579
+ */
580
+ get controlAttr(): DesFormControl | DesFormLayout {
581
+ return this.control?.controlAttr as any;
582
+ }
583
+
584
+ /**
585
+ * @description: 获取控件配置参数
586
+ * @author ChenRui
587
+ * @date 2021/1/5 11:26
588
+ */
589
+ get parentControlAttr(): DesFormLayout {
590
+ return this.parentControl?.controlAttr as DesFormLayout;
591
+ }
592
+
593
+ /**
594
+ * @description: 获取布局方式
595
+ * @author ChenRui
596
+ * @date 2020/12/30 18:19
597
+ */
598
+ get layout(): string {
599
+ for (const propName of Object.keys(VerticalArrangement)) {
600
+ if ((VerticalArrangement as any)[propName]["code"] === (this.controlAttr as DesFormLayout).gridVerticalArrangement) {
601
+ return (VerticalArrangement as any)[propName]["value"];
602
+ }
603
+ }
604
+ return VerticalArrangement.AlignRight.value;
605
+ }
606
+
607
+ /**
608
+ * @description: 当前输入的字符长度
609
+ * @author ChenRui
610
+ * @date 2021/4/20 15:55
611
+ */
612
+ get currentCharacterCount(): any {
613
+ return this.control!.formControl && this.control!.formControl.value ? this.control!.formControl.value.length : 0;
614
+ }
615
+
616
+ /**
617
+ * @description: 最大字数限制
618
+ * @author ChenRui
619
+ * @date 2021/4/20 15:38
620
+ */
621
+ get maxCharacterCount(): any {
622
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
623
+ if (controlAttr.verificationRules && controlAttr.verificationRules.length > 0) {
624
+ const verificationRule: any = controlAttr.verificationRules.find((item: any) => item.ruleType === ValidateRules.MaxTextLength.code);
625
+ if (verificationRule != null && verificationRule.ruleContent) {
626
+ return Number(verificationRule.ruleContent);
627
+ }
628
+ }
629
+ return undefined;
630
+ }
631
+
632
+ /**
633
+ * @description: 数字格式化
634
+ * @author ChenRui
635
+ * @date 2021/1/14 16:30
636
+ */
637
+ get numberFormatter(): any {
638
+ const controlAttr: any = this.controlAttr as DesFormControl;
639
+ const controlFormatType: string = controlAttr.formatType ? controlAttr.formatType : ControlFormatType.GENERAL.code;
640
+ return (value: any) => {
641
+ let val: any = value != undefined ? String(value) : "";
642
+ switch (controlFormatType) {
643
+ case ControlFormatType.GENERAL.code:
644
+ case ControlFormatType.AMOUNT_OF_MONEY.code:
645
+ if (controlFormatType === ControlFormatType.AMOUNT_OF_MONEY.code && val != null && controlAttr.thousandthPercentileFormat) {
646
+ // 校验小数位不做千分位格式化处理
647
+ if (val.indexOf(".") > -1) {
648
+ val = `${val}`.split(".")[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "." + `${val}`.split(".")[1];
649
+ } else {
650
+ val = `${val}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
651
+ }
652
+ }
653
+ if (controlAttr.zoomType !== ZoomType.automatic.code && val != null && val != "" && controlAttr.unit) {
654
+ // val = `${val}${controlAttr.unit}`;
655
+ val = `${val}`;
656
+ }
657
+ return val;
658
+ case ControlFormatType.BANK_CARD_NUMBER.code:
659
+ if (val != null) {
660
+ val = val.replace(/[\s]/g, "").replace(/(\d{4})(?=\d)/g, "$1 ");
661
+ }
662
+ return val;
663
+ case ControlFormatType.CELL_PHONE_NUMBER.code:
664
+ if (val != null) {
665
+ val = val.replace(/\D/g, "").substr(0, 11); // 不允许输入非数字字符,超过11位数字截取前11位
666
+ const len = val.length;
667
+ if (len > 3 && len < 8) {
668
+ val = val.replace(/^(\d{3})/g, "$1 ");
669
+ } else if (len >= 8) {
670
+ val = val.replace(/^(\d{3})(\d{4})/g, "$1 $2 ");
671
+ }
672
+ }
673
+ return val;
674
+ case ControlFormatType.LANDLINE_NUMBER.code:
675
+ return val;
676
+ default: {
677
+ return value;
678
+ }
679
+ }
680
+ };
681
+ }
682
+
683
+ /**
684
+ * @description: 数字反格式化
685
+ * @author ChenRui
686
+ * @date 2021/1/14 16:31
687
+ */
688
+ get numberParser(): any {
689
+ const controlAttr: any = this.controlAttr as DesFormControl;
690
+ const zoomType: string = controlAttr.formatType ? controlAttr.formatType : ControlFormatType.GENERAL.code;
691
+ return (value: any) => {
692
+ let val: any = value;
693
+ switch (zoomType) {
694
+ case ControlFormatType.GENERAL.code:
695
+ case ControlFormatType.AMOUNT_OF_MONEY.code:
696
+ if (zoomType === ControlFormatType.AMOUNT_OF_MONEY.code && val != null && controlAttr.thousandthPercentileFormat) {
697
+ val = val.replace(/\$\s?|(,*)/g, "");
698
+ }
699
+ if (controlAttr.zoomType !== ZoomType.automatic.code && val != null && val != "" && controlAttr.unit) {
700
+ const replaceUnit: string[] = controlAttr.unit.split("");
701
+ replaceUnit.forEach((item) => {
702
+ val = val.replace(item, "");
703
+ });
704
+ }
705
+ return val;
706
+ case ControlFormatType.BANK_CARD_NUMBER.code:
707
+ case ControlFormatType.CELL_PHONE_NUMBER.code:
708
+ if (val != null) {
709
+ val = val.replace(/\s/g, "");
710
+ }
711
+ return val;
712
+ case ControlFormatType.LANDLINE_NUMBER.code:
713
+ return val;
714
+ default: {
715
+ return val;
716
+ }
717
+ }
718
+ };
719
+ }
720
+
721
+ /**
722
+ * @description: label 宽度
723
+ * @author ChenRui
724
+ * @date 2021/1/5 11:59
725
+ */
726
+ get labelSpanWidth(): any {
727
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
728
+ const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
729
+ if (controlAttr.titleWidth) {
730
+ return controlAttr.titleWidth;
731
+ } else if (parentControlAttr.labelSpan) {
732
+ return parentControlAttr.labelSpan;
733
+ } else {
734
+ return this.provideInjectData.labelSpan;
735
+ }
736
+ }
737
+
738
+ /**
739
+ * @description: 标签后是否显示冒号
740
+ * @author ZPFly
741
+ * @date 2022/7/15 10:54
742
+ */
743
+ get colon(): boolean {
744
+ return this.provideInjectData.colon;
745
+ }
746
+
747
+ /**
748
+ * @description: 最大宽度设置
749
+ * @author ChenRui
750
+ * @date 2021/7/8 16:39
751
+ */
752
+ get controlSpanMaxWidth(): any {
753
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
754
+ const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
755
+ if (controlAttr.controlWidth) {
756
+ return controlAttr.controlWidth;
757
+ } else if (parentControlAttr.controlSpan) {
758
+ return parentControlAttr.controlSpan;
759
+ } else if (this.provideInjectData.controlSpan) {
760
+ return this.provideInjectData.controlSpan;
761
+ } else {
762
+ return "none";
763
+ }
764
+ }
765
+
766
+ /**
767
+ * @description: 控件宽度
768
+ * @author ChenRui
769
+ * @date 2021/1/5 15:11
770
+ */
771
+ get controlSpanWidth(): any {
772
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
773
+ const parentControlAttr: DesFormLayout = this.parentControlAttr as DesFormLayout;
774
+ if (controlAttr.controlWidth) {
775
+ return controlAttr.controlWidth;
776
+ } else if (parentControlAttr.controlSpan) {
777
+ return parentControlAttr.controlSpan;
778
+ } else if (this.provideInjectData.controlSpan) {
779
+ return this.provideInjectData.controlSpan;
780
+ } else {
781
+ return 0;
782
+ }
783
+ }
784
+
785
+ /**
786
+ * @description: label 标签的文本对齐方式
787
+ * @author ChenRui
788
+ * @date 2021/1/5 11:59
789
+ */
790
+ get labelAlign(): string {
791
+ for (const propName of Object.keys(VerticalArrangement)) {
792
+ if ((VerticalArrangement as any)[propName]["code"] === (this.controlAttr as DesFormLayout).gridVerticalArrangement) {
793
+ return (VerticalArrangement as any)[propName]["textAlign"];
794
+ }
795
+ }
796
+ return VerticalArrangement.AlignRight.textAlign;
797
+ }
798
+
799
+ /**
800
+ * @description: 获取金额转换单位
801
+ * @author ChenRui
802
+ * @date 2021/2/20 17:43
803
+ */
804
+ get moneyUnits(): any[] {
805
+ const moneyUnits: any[] = [];
806
+ const moneyUnit: any[] = formBeanUtilsService.parse((this.controlAttr as DesFormControl).moneyUnit);
807
+ if ((this.controlAttr as DesFormControl).moneyUnit) {
808
+ Object.values(MoneyUnit).forEach((item) => {
809
+ if (moneyUnit.findIndex((it) => it === item.code) !== -1) {
810
+ moneyUnits.push(item);
811
+ }
812
+ });
813
+ }
814
+
815
+ if (moneyUnits && moneyUnits.length > 0) {
816
+ this.defaultMoneyUnit = moneyUnits[0];
817
+ }
818
+ return moneyUnits;
819
+ }
820
+
821
+ /**
822
+ * @description: 单位缩放比例
823
+ * @author ChenRui
824
+ * @date 2022/5/7 10:31
825
+ */
826
+ get moneyUnitsIndentScale(): number {
827
+ const moneyUnit: any = this.defaultMoneyUnit;
828
+ if (moneyUnit != null && moneyUnit.code) {
829
+ return Number(moneyUnit.code);
830
+ }
831
+ return 0;
832
+ }
833
+
834
+ /**
835
+ * @description: 获取select、checkbox、radio可选项
836
+ * @author ChenRui
837
+ * @date 2020/12/2 14:36
838
+ */
839
+ get options(): any[] {
840
+ return extractOptions(this.controlAttr);
841
+ }
842
+
843
+ /**
844
+ * @description: 使用月份组件
845
+ * @author ChenRui
846
+ * @date 2021/5/19 16:12
847
+ */
848
+ get useMonthPicker(): boolean {
849
+ const dateFormat: any = (this.controlAttr as DesFormControl).dateFormat;
850
+ if (dateFormat && dateFormat.toLowerCase() === "yyyy-mm") {
851
+ return true;
852
+ }
853
+ return false;
854
+ }
855
+
856
+ /**
857
+ * @description: 级联选择框
858
+ * @author ChenRui
859
+ * @date 2021/1/5 16:31
860
+ */
861
+ get cascaderOptions(): any[] {
862
+ const value: any[] = this.options;
863
+ let options: any[] = [];
864
+ if (value && value.length > 0) {
865
+ const items = formBeanUtilsService.copy(value);
866
+ options = this.cascaderRecursion(items);
867
+ }
868
+ return options;
869
+ }
870
+
871
+ /**
872
+ * @description: 树形下拉选项
873
+ * @author ChenRui
874
+ * @date 2021/1/5 16:44
875
+ */
876
+ get treeSelectOptions(): any[] {
877
+ const value: any[] = this.options;
878
+ console.log(value);
879
+ if (value && value.length > 0) {
880
+ const items = formBeanUtilsService.copy(value);
881
+ this.treeSelectRecursion(items);
882
+ return items;
883
+ }
884
+ return [];
885
+ }
886
+
887
+ /**
888
+ * @description: 是否12小时制
889
+ * @author ChenRui
890
+ * @date 2021/1/18 10:54
891
+ */
892
+ get is12Hours(): boolean {
893
+ return !!(this.controlAttr as DesFormControl).timeFormat && (this.controlAttr as DesFormControl).timeFormat.indexOf(":ss") < 0;
894
+ }
895
+
896
+ /**
897
+ * @description: 是否添加反馈
898
+ * @author ChenRui
899
+ * @date 2021/1/21 10:43
900
+ */
901
+ get hasFeedback(): boolean {
902
+ return this.control!.formControl != null && this.control!.formControl!.validates && this.control!.formControl!.validates.length > 0;
903
+ }
904
+
905
+ /**
906
+ * @description: 是否必填,仅影响样式
907
+ * @author ChenRui
908
+ * @date 2021/1/21 10:50
909
+ */
910
+ get required(): boolean {
911
+ if (this.hasFeedback && this.control!.formControl!.validates.findIndex((item: any) => String(item.name) === String(ValidateRules.Required.code)) !== -1) {
912
+ return true;
913
+ }
914
+ return false;
915
+ }
916
+
917
+ /**
918
+ * @description: 格式化数据
919
+ * @author ChenRui
920
+ * @date 2021/1/8 11:30
921
+ */
922
+ get formatData(): string {
923
+ this.metaRefresh = this.provideInjectData.metaRefresh; // 刷新标识
924
+ let val = "";
925
+ let data: any = this.control!.formControl!.value;
926
+ let options: any[];
927
+ let context: any[];
928
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
929
+ switch (this.control!.code) {
930
+ case FormFieldType.Input.code:
931
+ if (controlAttr.bindingPrefix) {
932
+ val += controlAttr.bindingPrefix;
933
+ }
934
+ val += data || "";
935
+ if (controlAttr.bindingSuffix) {
936
+ val += controlAttr.bindingSuffix;
937
+ }
938
+ data = val;
939
+ break;
940
+ case FormFieldType.InputNumber.code:
941
+ if (this.numberFormatter) {
942
+ data = this.numberFormatter(data);
943
+ }
944
+ // 自动补0
945
+ if (data && controlAttr.decimalPlaces != undefined && (controlAttr.decimalPlaces as any) !== "") {
946
+ let index;
947
+ if (data.indexOf(".") == -1) {
948
+ index = controlAttr.decimalPlaces;
949
+ data += ".";
950
+ } else {
951
+ index = controlAttr.decimalPlaces - (data.length - 1 - data.indexOf("."));
952
+ }
953
+ for (let i = 0; i < index; i++) {
954
+ data += "0";
955
+ }
956
+ }
957
+ // 金额后缀不依赖于是否设置了小数位
958
+ if (controlAttr.zoomType !== ZoomType.automatic.code && data != null && data != "" && controlAttr.unit) {
959
+ data = data.replace(controlAttr.unit, "");
960
+ // data = `${data}${controlAttr.unit}`; // 后缀在后面统一展示 2023年9月22日15:49:08
961
+ }
962
+ return data;
963
+ case FormFieldType.Select.code:
964
+ case FormFieldType.Radio.code:
965
+ if (data != null && Array.isArray(data)) {
966
+ const context: string[] = [];
967
+ this.options.find((item) => {
968
+ for (let i = 0; i < data.length; i++) {
969
+ if (item.value === data[i]) {
970
+ context.push(item.title);
971
+ }
972
+ }
973
+ });
974
+ return context.join(",");
975
+ } else {
976
+ const option = this.options.find((item) => item.value === data);
977
+ return option ? option.title : "";
978
+ }
979
+ case FormFieldType.Checkbox.code:
980
+ options = data || [];
981
+ context = [];
982
+ options.forEach((it) => {
983
+ this.options.find((item) => {
984
+ if (item.value === it) {
985
+ context.push(item.title);
986
+ }
987
+ });
988
+ });
989
+ return context.join(" , ");
990
+ case FormFieldType.Switch.code:
991
+ if (data !== undefined) {
992
+ if (data === true && controlAttr.onOpeningValue != undefined && controlAttr.onOpeningValue !== "") {
993
+ return controlAttr.onOpeningValue;
994
+ } else if (data === false && controlAttr.whenClosedValue != undefined && controlAttr.whenClosedValue !== "") {
995
+ return controlAttr.whenClosedValue;
996
+ } else {
997
+ return data ? "是" : "否";
998
+ }
999
+ }
1000
+ return "";
1001
+ case FormFieldType.TimePicker.code:
1002
+ if (data != null) {
1003
+ return dayjs(data).format(controlAttr.timeFormat || "HH:mm:ss");
1004
+ }
1005
+ return "";
1006
+ case FormFieldType.DatePicker.code:
1007
+ if (data != null) {
1008
+ return dayjs(data).format(controlAttr.dateFormat || "YYYY-MM-dd");
1009
+ }
1010
+ return "";
1011
+ case FormFieldType.Cascader.code:
1012
+ if (data != null) {
1013
+ return this.cascaderContextRecursion(data, this.cascaderOptions);
1014
+ }
1015
+ return "";
1016
+ case FormFieldType.TreeSelect.code:
1017
+ if (data != null) {
1018
+ return this.treeSelectContextRecursion(data, this.treeSelectOptions);
1019
+ }
1020
+ return "";
1021
+ case FormFieldType.Custom.code:
1022
+ if (this.customFormats && this.customFormats[controlAttr.customFieldName]) {
1023
+ const customFormat: CustomFormat = this.customFormats[controlAttr.customFieldName];
1024
+ if (customFormat && customFormat.display) {
1025
+ return customFormat.display(data, controlAttr);
1026
+ }
1027
+ }
1028
+ }
1029
+ return data;
1030
+ }
1031
+
1032
+ /**
1033
+ * @description: 支持的上传类型
1034
+ * @author ChenRui
1035
+ * @date 2021/4/25 11:50
1036
+ */
1037
+ get uploadType(): any {
1038
+ const controlAttr = this.controlAttr as DesFormControl;
1039
+ if (controlAttr.supportUploadType === SupportUploadType.Arbitrarily.code) {
1040
+ return undefined;
1041
+ } else if (controlAttr.supportUploadType === SupportUploadType.Custom.code) {
1042
+ return controlAttr.customUploadType;
1043
+ }
1044
+ return undefined;
1045
+ }
1046
+
1047
+ /**
1048
+ * @description: 下拉选项新增
1049
+ * @author ChenRui
1050
+ * @date 2021/1/14 20:05
1051
+ */
1052
+ selectAddItem(event: any): void {
1053
+ this.$emit("add-item", event);
1054
+ /*const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1055
+ if (controlAttr != null) {
1056
+ if (controlAttr.isOptionType === OptionType.Fixed.code) {
1057
+ console.log(controlAttr.optionConfig);
1058
+ } else if (controlAttr.isOptionType === OptionType.Dynamic.code) {
1059
+ if (controlAttr.dynamicOptionType === DynamicOptionType.GeneralDictionary.code) {
1060
+ console.log(controlAttr.generalDictionaryOptions);
1061
+ }
1062
+ }
1063
+ }*/
1064
+ }
1065
+
1066
+ /**
1067
+ * @description: 级联搜索
1068
+ * @author ChenRui
1069
+ * @date 2021/5/19 17:23
1070
+ */
1071
+ cascaderFilter(inputValue: any, path: any): any {
1072
+ return path.some((option: any) => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
1073
+ }
1074
+
1075
+ /**
1076
+ * @description: 递归生成树形下拉选项
1077
+ * @author ChenRui
1078
+ * @date 2021/1/5 16:44
1079
+ */
1080
+ treeSelectRecursion(items: any[]): any[] {
1081
+ const options: any[] = [];
1082
+ items.forEach((item) => {
1083
+ item.disabled = false;
1084
+ item.key = item.value;
1085
+ if (item.children && item.children.length > 0) {
1086
+ if ((this.controlAttr as any).disableNonLeafNodes !== "0") {
1087
+ item.disabled = true; // LiuBo 2023年11月7日11:33:41 禁用非叶子节点
1088
+ }
1089
+ this.treeSelectRecursion(item.children);
1090
+ }
1091
+ });
1092
+ return options;
1093
+ }
1094
+
1095
+ /**
1096
+ * @description: 级联递归
1097
+ * @author ChenRui
1098
+ * @date 2021/1/5 16:35
1099
+ */
1100
+ cascaderRecursion(items: any[]): any[] {
1101
+ const options: any[] = [];
1102
+ items.forEach((item) => {
1103
+ const option: any = {
1104
+ value: item.value,
1105
+ label: item.title,
1106
+ isLeaf: false,
1107
+ };
1108
+ options.push(option);
1109
+ if (item.children && item.children.length > 0) {
1110
+ option.children = this.cascaderRecursion(item.children);
1111
+ } else {
1112
+ option.isLeaf = true;
1113
+ }
1114
+ });
1115
+ return options;
1116
+ }
1117
+
1118
+ /**
1119
+ * @description: 递归获取级联选项对应的文本
1120
+ * @author ChenRui
1121
+ * @date 2021/1/8 14:45
1122
+ */
1123
+ cascaderContextRecursion(val: any[], cascaderOptions: any[], index = 0): string {
1124
+ if (val && val.length > 0 && cascaderOptions && cascaderOptions.length > 0) {
1125
+ if (val.length > index) {
1126
+ const currentIndex = val[index];
1127
+ const cascaderOption = cascaderOptions.find((item) => item.value === currentIndex);
1128
+ if (cascaderOption != null) {
1129
+ let currentText = cascaderOption.label;
1130
+ if (val.length > index + 1) {
1131
+ const subText = this.cascaderContextRecursion(val, cascaderOption.children, index + 1);
1132
+ currentText += " / " + subText;
1133
+ }
1134
+ return currentText;
1135
+ }
1136
+ }
1137
+ }
1138
+ return "";
1139
+ }
1140
+
1141
+ /**
1142
+ * @description:
1143
+ * @author ChenRui
1144
+ * @date 2021/1/8 15:05
1145
+ */
1146
+
1147
+ treeSelectContextRecursion(val: string, treeSelectOptions: any[]): string {
1148
+ if (val && treeSelectOptions && treeSelectOptions.length > 0) {
1149
+ for (let i = 0; i < treeSelectOptions.length; i++) {
1150
+ if (treeSelectOptions[i].value === val) {
1151
+ return treeSelectOptions[i].title;
1152
+ } else if (treeSelectOptions[i].children && treeSelectOptions[i].children.length > 0) {
1153
+ const subTitle: string = this.treeSelectContextRecursion(val, treeSelectOptions[i].children);
1154
+ if (subTitle) {
1155
+ return subTitle;
1156
+ }
1157
+ }
1158
+ }
1159
+ }
1160
+ return "";
1161
+ }
1162
+
1163
+ /**
1164
+ * @description: 是否为ie
1165
+ * @author ChenRui
1166
+ * @date 2021/3/25 14:44
1167
+ */
1168
+ get isIe(): boolean {
1169
+ return !!this.provideInjectData.widthCompatibleMode || !!window.ActiveXObject || "ActiveXObject" in window;
1170
+ }
1171
+
1172
+ /**
1173
+ * @description: ie 兼容性宽度布局
1174
+ * @author ChenRui
1175
+ * @date 2021/3/25 12:53
1176
+ */
1177
+ get divWidthCompatibleToIe(): any {
1178
+ if (this.isIe) {
1179
+ const desFormLayout: DesFormLayout = this.parentControlAttr as DesFormLayout;
1180
+ const configIndex: number = this.index! % desFormLayout.gridColumnConfig.length; // 索引位置
1181
+ const proportion: number = desFormLayout.gridColumnConfig[configIndex].value; // 比重
1182
+ let total = 0; // 总值
1183
+ desFormLayout.gridColumnConfig.forEach((item: any) => {
1184
+ total += Number(item.value);
1185
+ });
1186
+ const ratio = proportion / total; // 比值
1187
+ const val = Number(ratio) * 100;
1188
+ return `calc( ${val}% - 1px)`;
1189
+ } else {
1190
+ return "100%";
1191
+ }
1192
+ }
1193
+
1194
+ /**
1195
+ * @description: 根节点容器布局样式
1196
+ * @author ChenRui
1197
+ * @date 2021/3/25 14:52
1198
+ */
1199
+ get emptyLayoutContainerStyle(): any {
1200
+ let style: any = {};
1201
+ if (this.isIe) {
1202
+ style = { display: "flex", "flex-wrap": "wrap" };
1203
+ } else {
1204
+ const gridTemplateColumns: any = generateGridTemplateColumns((this.control?.controlAttr as DesFormLayout)?.gridColumnConfig);
1205
+ style = { "grid-template-columns": gridTemplateColumns };
1206
+ }
1207
+ return style;
1208
+ }
1209
+
1210
+ /**
1211
+ * @description: 常规布局容器样式
1212
+ * @author ChenRui
1213
+ * @date 2021/3/25 14:42
1214
+ */
1215
+ get generalLayoutContainerStyle(): any {
1216
+ let style: any = {};
1217
+ if (this.isIe) {
1218
+ style = { display: "flex", "flex-wrap": "wrap" };
1219
+ } else {
1220
+ const gridColumnEnd: any = generateGridColumnEnd((this.parentControl?.controlAttr as DesFormLayout)?.gridColumnConfig);
1221
+ const gridTemplateColumns: any = generateGridTemplateColumns((this.control?.controlAttr as DesFormLayout)?.gridColumnConfig);
1222
+ style = {
1223
+ "grid-column-end": gridColumnEnd,
1224
+ "grid-template-columns": gridTemplateColumns,
1225
+ };
1226
+ }
1227
+ return style;
1228
+ }
1229
+
1230
+ /**
1231
+ * @description: 初始化部分数据
1232
+ * @author ChenRui
1233
+ * @date 2021/1/29 15:28
1234
+ */
1235
+ initFormControlData(): void {
1236
+ if (this.control && this.control.formControl) {
1237
+ if (this.control!.code === FormFieldType.DatePicker.code || this.control!.code === FormFieldType.TimePicker.code) {
1238
+ if (this.control.formControl.value) {
1239
+ if (typeof this.control.formControl.value === "string") {
1240
+ this.control.formControl.value = dayjs(new Date(this.control.formControl.value));
1241
+ } else if (this.control.formControl.value instanceof Date) {
1242
+ this.control.formControl.value = dayjs(this.control.formControl.value);
1243
+ }
1244
+ }
1245
+ }
1246
+ if (this.control.formControl.textNoticeCallback == null) {
1247
+ this.control.formControl.textNoticeCallback = () => {
1248
+ return this.formatData;
1249
+ };
1250
+ }
1251
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1252
+ if (controlAttr.maxValue == null || (controlAttr.maxValue as any) === "") {
1253
+ const maxValue = "9999999999999999";
1254
+ if (controlAttr.decimalPlaces != undefined && (controlAttr.decimalPlaces as any) !== "" && controlAttr.decimalPlaces > 0) {
1255
+ if (controlAttr.decimalPlaces > 16) {
1256
+ controlAttr.decimalPlaces = 16;
1257
+ }
1258
+ controlAttr.maxValue = Number(maxValue.slice(0, maxValue.length - controlAttr.decimalPlaces) + "." + maxValue.slice(maxValue.length - controlAttr.decimalPlaces, maxValue.length));
1259
+ } else {
1260
+ controlAttr.maxValue = Number(maxValue);
1261
+ }
1262
+ }
1263
+ }
1264
+ }
1265
+
1266
+ /**
1267
+ * @description: 业务属性
1268
+ * @author ChenRui
1269
+ * @date 2021/2/1 14:38
1270
+ */
1271
+ get busAttr(): any {
1272
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1273
+ let busAttr: any;
1274
+ let attrSubmittedType: any[] = [];
1275
+ if (controlAttr.busAttr) {
1276
+ busAttr = formBeanUtilsService.parse(controlAttr.busAttr);
1277
+ if (busAttr[FormBusAttr.SUBMITTED_TYPE.code]) {
1278
+ attrSubmittedType = busAttr[FormBusAttr.SUBMITTED_TYPE.code].split(",").filter((item: any) => !!item);
1279
+ }
1280
+ }
1281
+ const submittedType: any[] = Object.values(SubmittedType).map((val: any) => ({ label: val.name, value: val.code }));
1282
+ const submittedTypeCheckedNode: any[] = [];
1283
+ submittedType.forEach((item) => {
1284
+ if (attrSubmittedType.findIndex((it) => it === item.value) > -1) {
1285
+ submittedTypeCheckedNode.push(item);
1286
+ }
1287
+ });
1288
+ return {
1289
+ [FormBusAttr.SUBMITTED_TYPE.code]: submittedTypeCheckedNode,
1290
+ [FormBusAttr.IS_SUPPLEMENT.code]: busAttr ? busAttr[FormBusAttr.IS_SUPPLEMENT.code] : false,
1291
+ [FormBusAttr.IS_KEY_ELEMENTS.code]: busAttr ? busAttr[FormBusAttr.IS_KEY_ELEMENTS.code] : false,
1292
+ [FormBusAttr.IS_TRACK.code]: busAttr ? busAttr[FormBusAttr.IS_TRACK.code] : false,
1293
+ };
1294
+ }
1295
+
1296
+ /**
1297
+ * @description: 报送类型
1298
+ * @author ChenRui
1299
+ * @date 2021/2/1 15:05
1300
+ */
1301
+ get submittedType(): any[] {
1302
+ if (this.busAttr && this.busAttr[FormBusAttr.SUBMITTED_TYPE.code].length > 0) {
1303
+ return this.busAttr[FormBusAttr.SUBMITTED_TYPE.code];
1304
+ }
1305
+ return [];
1306
+ }
1307
+
1308
+ /**
1309
+ * @description: 报送类型字符串
1310
+ * @author ChenRui
1311
+ * @date 2021/2/1 15:08
1312
+ */
1313
+ get submittedTypeStr(): string {
1314
+ return this.submittedType.map((item) => item.label).join("、");
1315
+ }
1316
+
1317
+ /**
1318
+ * 根据日期时间格式决定是否显示时间选择功能
1319
+ * @param format
1320
+ */
1321
+ showPickerTime(format?: string): any {
1322
+ // format 包含时间格式
1323
+ if (format && format.indexOf("HH:mm") > -1) {
1324
+ return format;
1325
+ }
1326
+ return false;
1327
+ }
1328
+ /**
1329
+ * @description: 清除特殊字符
1330
+ * @author ChenRui
1331
+ * @date 2021/6/22 15:41
1332
+ */
1333
+ private clearNoNum(value: any) {
1334
+ if (value) {
1335
+ value = value.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
1336
+ value = value.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
1337
+ value = value.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
1338
+ // eslint-disable-next-line no-useless-escape
1339
+ value = value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3"); //只能输入两个小数
1340
+ if (value.indexOf(".") < 0 && value != "") {
1341
+ //以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
1342
+ value = parseFloat(value);
1343
+ }
1344
+ }
1345
+ return value;
1346
+ }
1347
+
1348
+ /**
1349
+ * @description: 校验数字是否超过16位纯编码
1350
+ * @author ChenRui
1351
+ * @date 2021/6/22 14:58
1352
+ */
1353
+ private validateNumBeyondLimit(value: any): boolean {
1354
+ if (value) {
1355
+ const pureNumber: string = value.replace(/[^0-9]/gi, "");
1356
+ return pureNumber.length > 16;
1357
+ }
1358
+ return false;
1359
+ }
1360
+
1361
+ /**
1362
+ * @description: 删除文件
1363
+ * @author ChenRui
1364
+ * @date 2021/4/25 11:35
1365
+ */
1366
+ handleRemove(file: any): void {
1367
+ const index = this.formControl.value.indexOf(file);
1368
+ const newFileList = this.formControl.value.slice();
1369
+ newFileList.splice(index, 1);
1370
+ this.formControl.value = newFileList;
1371
+ }
1372
+
1373
+ /**
1374
+ * @description: 文件上传前回调函数
1375
+ * @author ChenRui
1376
+ * @date 2021/4/25 11:23
1377
+ */
1378
+ beforeUpload(file: any): boolean {
1379
+ const fileList: any[] = [...this.formControl.value, file];
1380
+ this.formControl.value = fileList;
1381
+ return false;
1382
+ }
1383
+
1384
+ /**
1385
+ * @description: 文件上传变更
1386
+ * @author ChenRui
1387
+ * @date 2021/4/25 11:29
1388
+ */
1389
+ handleUploadChange(event: any): any {
1390
+ let fileList: any[] = [...this.formControl.value];
1391
+ const controlAttr: DesFormControl = this.controlAttr as DesFormControl;
1392
+ if (controlAttr.maxUploadNumber && controlAttr.maxUploadNumber > 0) {
1393
+ fileList = fileList.slice(0 - Number(controlAttr.maxUploadNumber));
1394
+ }
1395
+ fileList = fileList.map((file) => {
1396
+ if (file.response) {
1397
+ file.url = file.response.url;
1398
+ }
1399
+ return file;
1400
+ });
1401
+ this.formControl.value = fileList;
1402
+ if (event && event.file && (event.file.status === undefined || event.file.status === "removed")) {
1403
+ this.onChange(this.control!);
1404
+ }
1405
+ }
1406
+
1407
+ /**
1408
+ * @description: 金额菜单单机事件
1409
+ * @author ChenRui
1410
+ * @date 2021/2/20 17:21
1411
+ */
1412
+ handleMoneyUnitMenuClick(e: any): void {
1413
+ this.defaultMoneyUnit = this.moneyUnits.find((item) => item.code === e.key);
1414
+ }
1415
+
1416
+ /**
1417
+ * @description: 将下拉弹层渲染节点固定在触发器的父元素中
1418
+ * @author ZPFly
1419
+ * @date 2022/8/31 11:30
1420
+ */
1421
+ getPopupContainer(triggerNode: any) {
1422
+ return triggerNode.parentNode;
1423
+ }
1424
+
1425
+ /**
1426
+ * @description: 输入事件处理
1427
+ * @author ChenRui
1428
+ * @date 2020/12/2 14:37
1429
+ */
1430
+ onChange(event: Control): void {
1431
+ if (this.control && (this.control.type === FormFieldClass.Base.code || this.control.type === FormFieldClass.Senior.code)) {
1432
+ this.validateResult = this.formControl.validate(event.formControl?.value);
1433
+ }
1434
+ this.$emit("change", event);
1435
+ }
1436
+
1437
+ /**
1438
+ * @description: 点击事件
1439
+ * @author ChenRui
1440
+ * @date 2021/3/4 11:37
1441
+ */
1442
+ onClick(event: Control): void {
1443
+ this.$emit("click", event);
1444
+ }
1445
+
1446
+ /**
1447
+ * @description: 内置前置标签事件
1448
+ * @author ChenRui
1449
+ * @date 2021/4/23 9:42
1450
+ */
1451
+ onAddonBeforeHandler(event: any): void {
1452
+ this.$emit("addon-before", event);
1453
+ }
1454
+
1455
+ /**
1456
+ * @description: 内置后置标签事件
1457
+ * @author ChenRui
1458
+ * @date 2021/4/23 9:43
1459
+ */
1460
+ onAddonAfterHandler(event: any): void {
1461
+ this.$emit("addon-after", event);
1462
+ }
1463
+
1464
+ /**
1465
+ * @description: 数字框失焦点
1466
+ * @author ChenRui
1467
+ * @date 2021/3/4 11:51
1468
+ */
1469
+ onInputNumberFocus(event: Control): void {
1470
+ this.onFocus(event);
1471
+ if ((this.controlAttr as DesFormControl).isShowCapitalization) {
1472
+ this.numberPopoverVisible = true;
1473
+ }
1474
+ }
1475
+
1476
+ /**
1477
+ * @description: 数字输入框失焦
1478
+ * @author ChenRui
1479
+ * @date 2021/3/4 11:43
1480
+ */
1481
+ onInputNumberBlur(event: Control): void {
1482
+ this.onBlur(event);
1483
+ if ((this.controlAttr as DesFormControl).isShowCapitalization) {
1484
+ this.numberPopoverVisible = false;
1485
+ }
1486
+ }
1487
+
1488
+ /**
1489
+ * @description: 获取焦点
1490
+ * @author ChenRui
1491
+ * @date 2021/3/4 11:46
1492
+ */
1493
+ onFocus(event: Control): void {
1494
+ this.$emit("focus", event);
1495
+ }
1496
+
1497
+ /**
1498
+ * @description: 失焦事件
1499
+ * @author ChenRui
1500
+ * @date 2021/3/4 11:38
1501
+ */
1502
+ onBlur(event: Control): void {
1503
+ this.$emit("blur", event);
1504
+ }
1505
+
1506
+ /**
1507
+ * @Description 是否节假日校验
1508
+ * @Author JiangTao
1509
+ * @Date 2024-04-16 下午 02:33
1510
+ */
1511
+ isRest(current: any): boolean {
1512
+ if (JSON.parse(this.weekdayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1513
+ return true;
1514
+ } else {
1515
+ return false;
1516
+ }
1517
+ }
1518
+
1519
+ /**
1520
+ * @Description 是否工作日校验
1521
+ * @Author JiangTao
1522
+ * @Date 2024-04-16 下午 02:33
1523
+ */
1524
+ isWeekday(current: any): boolean {
1525
+ if (JSON.parse(this.workdayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1526
+ return true;
1527
+ } else {
1528
+ return false;
1529
+ }
1530
+ }
1531
+
1532
+ /**
1533
+ * @Description 是否交易日校验
1534
+ * @Author JiangTao
1535
+ * @Date 2024-04-16 下午 02:33
1536
+ */
1537
+ isRadingDay(current: any): boolean {
1538
+ if (JSON.parse(this.traddayList).find((e: any) => e.calDate === this.DateTime(current.$d))) {
1539
+ return true;
1540
+ } else {
1541
+ return false;
1542
+ }
1543
+ }
1544
+
1545
+ /**
1546
+ * @Description 日期格式转换
1547
+ * @Author JiangTao
1548
+ * @Date 2024-04-16 下午 02:33
1549
+ */
1550
+ DateTime(date: any): string {
1551
+ const year: any = date.getFullYear();
1552
+ let month: any = date.getMonth() + 1;
1553
+ let strDate: any = date.getDate();
1554
+
1555
+ if (month < 10) {
1556
+ month = "0" + month;
1557
+ }
1558
+
1559
+ if (strDate < 10) {
1560
+ strDate = "0" + strDate;
1561
+ }
1562
+
1563
+ return "" + year + month + strDate;
1564
+ }
1565
+ }
1566
+ </script>
1567
+ <style lang="scss" scoped>
1568
+ @import "../../styles/themes.scss";
1569
+ </style>