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