xt-element-ui 2.1.21 → 2.1.61

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 (75) hide show
  1. package/docs/components/base/xt-badge.md +0 -2
  2. package/docs/components/base/xt-bar.md +0 -27
  3. package/docs/components/base/xt-button.md +0 -2
  4. package/docs/components/base/xt-card-item.md +0 -2
  5. package/docs/components/base/xt-card.md +17 -19
  6. package/docs/components/base/xt-chart.md +5 -31
  7. package/docs/components/base/xt-config-provider.md +0 -2
  8. package/docs/components/base/xt-date-picker.md +185 -28
  9. package/docs/components/base/xt-flex-box.md +25 -25
  10. package/docs/components/base/xt-form-schema.md +356 -0
  11. package/docs/components/base/xt-grid-box.md +4 -6
  12. package/docs/components/base/xt-icon.md +0 -2
  13. package/docs/components/base/xt-input.md +204 -44
  14. package/docs/components/base/xt-line.md +0 -26
  15. package/docs/components/base/xt-list.md +456 -458
  16. package/docs/components/base/xt-map-provider.md +0 -2
  17. package/docs/components/base/xt-map.md +0 -2
  18. package/docs/components/base/xt-multi.md +0 -39
  19. package/docs/components/base/xt-page.md +17 -6
  20. package/docs/components/base/xt-pie.md +0 -25
  21. package/docs/components/base/xt-progress.md +0 -2
  22. package/docs/components/base/xt-scroll-arrow.md +0 -2
  23. package/docs/components/base/xt-select-tree.md +0 -2
  24. package/docs/components/base/xt-step-price.md +3 -4
  25. package/docs/components/base/xt-table.md +2 -2
  26. package/docs/components/base/xt-tabs.md +0 -2
  27. package/docs/components/base/xt-text.md +1 -2
  28. package/docs/components/base/xt-time.md +0 -2
  29. package/docs/components/base/xt-transfer-tree.md +270 -0
  30. package/docs/components/base/xt-upload.md +11 -8
  31. package/docs/components/utils/config.md +285 -0
  32. package/docs/components/utils/format.md +445 -0
  33. package/lib/index.common.js +96183 -115717
  34. package/lib/index.css +1 -1
  35. package/lib/index.umd.js +96183 -115717
  36. package/lib/index.umd.min.js +1 -34
  37. package/package.json +7 -4
  38. package/src/components/xt-badge/style/index.scss +0 -22
  39. package/src/components/xt-button/index.vue +2 -1
  40. package/src/components/xt-button/style/index.scss +2 -2
  41. package/src/components/xt-card/style/index.scss +2 -2
  42. package/src/components/xt-card-item/style/index.scss +5 -40
  43. package/src/components/xt-chart/XtBar.vue +0 -3
  44. package/src/components/xt-date-picker/component/Picker.vue +196 -0
  45. package/src/components/xt-date-picker/component/RangeDate.vue +136 -0
  46. package/src/components/xt-date-picker/index.vue +220 -80
  47. package/src/components/xt-flex-box/index.vue +1 -1
  48. package/src/components/xt-form-schema/index.js +8 -0
  49. package/src/components/xt-form-schema/index.vue +328 -0
  50. package/src/components/xt-grid-item/index.vue +2 -2
  51. package/src/components/xt-input/index.vue +224 -28
  52. package/src/components/xt-input/style/index.scss +10 -0
  53. package/src/components/xt-layout/ExFieldset.vue +4 -4
  54. package/src/components/xt-list/index.js +7 -7
  55. package/src/components/xt-list/index.vue +885 -885
  56. package/src/components/xt-page/index.vue +148 -75
  57. package/src/components/xt-progress/style/index.scss +0 -14
  58. package/src/components/xt-step-price/style/index.scss +0 -4
  59. package/src/components/xt-step-price-item/index.vue +1 -1
  60. package/src/components/xt-table/XtTableCell.vue +2 -2
  61. package/src/components/xt-table/index.vue +17 -10
  62. package/src/components/xt-tabs/style/index.scss +0 -40
  63. package/src/components/xt-text/index.vue +16 -4
  64. package/src/components/xt-text/style/index.scss +0 -15
  65. package/src/components/xt-transfer-tree/index.js +8 -0
  66. package/src/components/xt-transfer-tree/index.vue +494 -0
  67. package/src/components/xt-upload/index.vue +12 -6
  68. package/src/index.js +8 -2
  69. package/src/styles/theme/colors.scss +0 -44
  70. package/src/styles/theme/dark-variables.scss +0 -29
  71. package/src/styles/variables-export.scss +0 -72
  72. package/src/utils/index.js +278 -1
  73. package/src/components/xt-date-picker/SearchDate.vue +0 -45
  74. package/src/components/xt-date-picker/quarter.vue +0 -154
  75. package/src/components/xt-table/index copy.vue +0 -663
@@ -1,56 +1,153 @@
1
1
  <template>
2
- <div style="display:inline-block">
3
- <XtFlexBox v-if="dateType=='quarter'" type="inline-flex" class="xt-date-picker" :class="{focus: isfocus}" :style="width?{width: `${width}`}:{}">
4
- <Quarter v-model="timeStart" :format="format" placeholder="开始时间" quarter-type="quarter-start" clearable></Quarter>
5
- <span class="separator">{{ separator }}</span>
6
- <Quarter v-model="timeEnd" :format="format" placeholder="结束时间" quarter-type="quarter-end" clearable></Quarter>
7
- </XtFlexBox>
8
- <XtFlexBox v-else type="inline-flex" class="xt-date" :class="{focus: isfocus}" :style="width?{width: `${width}px`}:{}">
9
- <el-date-picker ref="timeStart" key="startSelect" v-model="timeStart" size="small" :disabled="disabled" append-to-body :picker-options="startTimeRange" :format="format" :type="dateType" placeholder="开始时间" clearable @blur="$emit('blur')" @focus="$emit('focus')"></el-date-picker>
10
- <span class="separator">{{ separator }}</span>
11
- <el-date-picker ref="timeEnd" key="endSelect" v-model="timeEnd" size="small" :disabled="disabled" append-to-body :picker-options="endTimeRange" :format="format" :type="dateType" placeholder="结束时间" clearable @blur="$emit('blur')" @focus="$emit('focus')"></el-date-picker>
12
- </XtFlexBox>
2
+ <div class="xt-date-picker-container">
3
+ <!-- 维度切换单选:日/月/年/自定义区间 -->
4
+ <div v-if="showDimension" class="xt-date-dimension">
5
+ <el-radio-group v-model="dimension" size="small">
6
+ <el-radio-button label="date">日</el-radio-button>
7
+ <el-radio-button label="month">月</el-radio-button>
8
+ <el-radio-button label="year">年</el-radio-button>
9
+ <el-radio-button label="daterange">自定义</el-radio-button>
10
+ </el-radio-group>
11
+ </div>
12
+
13
+ <div class="xt-date-picker-wrapper">
14
+ <!-- 区间模式 -->
15
+ <RangeDate
16
+ v-if="useRangeMode"
17
+ v-model="rangeValue"
18
+ :type="rangeDateType"
19
+ :separator="separator"
20
+ :disabled="disabled"
21
+ class="xt-date"
22
+ :class="{ focus: isfocus }"
23
+ :style="width ? { width: `${width}px` } : {}"
24
+ @focus="isfocus = true; $emit('focus')"
25
+ @blur="isfocus = false; $emit('blur')"
26
+ />
27
+
28
+ <!-- 单选模式:日/月/年/周 -->
29
+ <el-date-picker
30
+ v-if="!useRangeMode && realDateType !== 'quarter'"
31
+ ref="singlePicker"
32
+ v-model="singleValue"
33
+ size="small"
34
+ :disabled="disabled"
35
+ append-to-body
36
+ :format="format"
37
+ :type="realDateType"
38
+ :placeholder="innerPlaceholder"
39
+ clearable
40
+ @focus="isfocus = true; $emit('focus')"
41
+ @blur="isfocus = false; $emit('blur')"
42
+ />
43
+ <!-- 单选模式:季度(使用自定义组件) -->
44
+ <Picker
45
+ v-else-if="!useRangeMode && realDateType === 'quarter'"
46
+ v-model="singleValue"
47
+ type="quarter"
48
+ size="small"
49
+ :disabled="disabled"
50
+ :placeholder="innerPlaceholder"
51
+ @focus="isfocus = true; $emit('focus')"
52
+ @blur="isfocus = false; $emit('blur')"
53
+ />
54
+ </div>
13
55
  </div>
14
56
  </template>
57
+
15
58
  <script>
16
- const typeFormatEnum = {
17
- datetime: "yyyy-MM-dd HH:mm", month: "yyyy-MM", year: "yyyy", date: "yyyy-MM-dd", quarter: "yyyy-Qq", week: "yyyy-WW"
59
+ // 全局常量统一维护
60
+ // 类型对应格式化规则
61
+ const DATE_FORMAT_MAP = {
62
+ datetime: 'yyyy-MM-dd HH:mm',
63
+ month: 'yyyy-MM',
64
+ year: 'yyyy',
65
+ date: 'yyyy-MM-dd',
66
+ quarter: 'yyyy-Qq',
67
+ week: 'yyyy-WW'
68
+ };
69
+ // 维度面板对应的格式化
70
+ const DIMENSION_FORMAT_MAP = {
71
+ date: 'yyyy-MM-dd',
72
+ month: 'yyyy-MM',
73
+ year: 'yyyy',
74
+ daterange: 'yyyy-MM-dd'
18
75
  };
76
+ // 维度 -> RangeDate 使用的基础类型
77
+ const DIMENSION_TO_RANGE_TYPE = {
78
+ date: 'date',
79
+ month: 'month',
80
+ year: 'year',
81
+ daterange: 'date'
82
+ };
83
+ // 普通type映射区间组件type
84
+ const NORMAL_TO_RANGE_TYPE = {
85
+ date: 'date',
86
+ month: 'month',
87
+ year: 'year',
88
+ quarter: 'quarter',
89
+ week: 'week'
90
+ };
91
+
92
+ import RangeDate from './component/RangeDate.vue';
93
+ import Picker from './component/Picker.vue';
19
94
 
20
- import XtFlexBox from '../xt-flex-box/index.vue'
21
- import Quarter from "./quarter.vue";
22
95
  export default {
23
- name: "XtDatePicker",
24
- components: {
25
- XtFlexBox,
26
- Quarter
27
- },
96
+ name: 'XtDatePicker',
97
+ components: { RangeDate, Picker },
98
+ // 标准v-model:父组件 v-model="xxx"
28
99
  model: {
29
- prop: "value",
30
- event: "change"
100
+ prop: 'value',
101
+ event: 'change'
31
102
  },
32
103
  props: {
33
- value: {},
104
+ // 绑定主值
105
+ value: {
106
+ type: [String, Array, null],
107
+ default: null
108
+ },
109
+ // 基础日期类型 date/month/year/quarter/week/datetime
34
110
  dateType: {
35
111
  type: String,
36
- default: "date"
112
+ default: 'date',
113
+ validator: val => Object.keys(DATE_FORMAT_MAP).includes(val)
37
114
  },
115
+ // 区间分隔符
38
116
  separator: {
39
117
  type: String,
40
- default: ""
118
+ default: ''
41
119
  },
42
120
  disabled: {
43
121
  type: Boolean,
44
122
  default: false
45
123
  },
46
- immediate: { // 是否直接初始化 参数
124
+ // 维度切换后是否立即触发事件
125
+ immediate: {
47
126
  type: Boolean,
48
127
  default: true
49
128
  },
50
- placeholder: {},
129
+ // 外部自定义占位
130
+ placeholder: String,
131
+ // 整体宽度
51
132
  width: {
52
- type: [String],
133
+ type: String,
53
134
  default: '100%'
135
+ },
136
+ // 是否开启区间模式(无维度切换时生效)
137
+ rangeMode: {
138
+ type: Boolean,
139
+ default: false
140
+ },
141
+ // 是否展示维度切换单选框
142
+ showDimension: {
143
+ type: Boolean,
144
+ default: false
145
+ },
146
+ // 当前选中维度 date/month/year/daterange
147
+ dimension: {
148
+ type: String,
149
+ default: 'date',
150
+ validator: val => ['date', 'month', 'year', 'daterange'].includes(val)
54
151
  }
55
152
  },
56
153
  data() {
@@ -59,73 +156,116 @@ export default {
59
156
  };
60
157
  },
61
158
  computed: {
159
+ // 真实底层日期类型(区分维度面板场景)
160
+ realDateType() {
161
+ if (this.showDimension) return this.dimension;
162
+ return this.dateType;
163
+ },
164
+
165
+ // 当前是否启用区间组件
166
+ useRangeMode() {
167
+ // 维度为自定义区间 或 全局开启rangeMode且非维度面板
168
+ return this.dimension === 'daterange' || (this.rangeMode);
169
+ },
170
+
171
+ // 区间组件使用的type
172
+ rangeDateType() {
173
+ if (this.showDimension) {
174
+ return DIMENSION_TO_RANGE_TYPE[this.dimension] || 'date';
175
+ }
176
+ return NORMAL_TO_RANGE_TYPE[this.dateType] || 'date';
177
+ },
178
+
179
+ // 日期格式化字符串
62
180
  format() {
63
- return typeFormatEnum[this.dateType] || "yyyy-MM-dd";
181
+ if (this.showDimension) {
182
+ return DIMENSION_FORMAT_MAP[this.dimension] || DATE_FORMAT_MAP[this.dateType];
183
+ }
184
+ return DATE_FORMAT_MAP[this.dateType] || 'yyyy-MM-dd';
64
185
  },
65
- timeStart: {
186
+
187
+ // 内部自动生成占位(外部placeholder优先)
188
+ innerPlaceholder() {
189
+ if (this.placeholder) return this.placeholder;
190
+ const map = {
191
+ date: '请选择日期',
192
+ month: '请选择月份',
193
+ year: '请选择年份',
194
+ quarter: '请选择季度',
195
+ week: '请选择周',
196
+ datetime: '请选择日期时间'
197
+ };
198
+ return map[this.realDateType] || '请选择';
199
+ },
200
+
201
+ // 单选模式双向绑定
202
+ singleValue: {
66
203
  get() {
67
- return this.value && this.value[0];
204
+ return this.value;
68
205
  },
69
- set(v) {
70
- this.$emit("update:value", [v, this.timeEnd]);
71
- this.$emit("change", [v, this.timeEnd]);
206
+ set(val) {
207
+ this.$emit('update:value', val);
208
+ this.$emit('change', val);
209
+ this.$emit('dimension-change', {
210
+ dimension: this.dimension,
211
+ value: val
212
+ });
72
213
  }
73
214
  },
74
- timeEnd: {
215
+
216
+ // 区间组件双向绑定中转
217
+ rangeValue: {
75
218
  get() {
76
- return this.value && this.value[1];
219
+ return this.value;
77
220
  },
78
- set(v) {
79
- this.$emit("update:value", [this.timeStart, v]);
80
- this.$emit("change", [this.timeStart, v]);
221
+ set(val) {
222
+ this.$emit('update:value', val);
223
+ this.$emit('change', val);
224
+ this.$emit('dimension-change', {
225
+ dimension: this.dimension,
226
+ value: val
227
+ });
228
+ }
229
+ }
230
+ },
231
+ watch: {
232
+ // 切换维度,关闭下拉面板并抛出事件
233
+ dimension(newVal) {
234
+ this.closePickerPanels();
235
+ if (this.immediate) {
236
+ this.$emit('dimension-change', {
237
+ dimension: newVal,
238
+ value: this.value
239
+ });
81
240
  }
82
- },
83
- startTimeRange() {
84
- if (!this.timeEnd) return {};
85
- const endTime = this.timeEnd.getTime();
86
- return {
87
- disabledDate: (time) => {
88
- return time.getTime() > (endTime);
89
- }
90
- };
91
- },
92
- endTimeRange() {
93
- if (!this.timeStart) return {};
94
- const startTime = this.timeStart.getTime();
95
- return {
96
- disabledDate: (time) => {
97
- return time.getTime() < (startTime);
98
- }
99
- };
100
241
  }
101
242
  },
102
243
  methods: {
244
+ // 关闭原生单选日期下拉面板
245
+ closePickerPanels() {
246
+ if (this.$refs.singlePicker) {
247
+ this.$refs.singlePicker.pickerVisible = false;
248
+ }
249
+ }
103
250
  }
104
251
  };
105
252
  </script>
253
+
106
254
  <style lang="scss" scoped>
107
- .xt-date-picker{
255
+ .xt-date-picker-container {
256
+ display: inline-block;
257
+ width: 100%;
258
+ }
259
+
260
+ .xt-date-dimension {
261
+ margin-bottom: 8px;
262
+ }
263
+
264
+ .xt-date-picker-wrapper {
265
+ display: inline-block;
266
+ }
267
+
268
+ .xt-date {
108
269
  width: 100%;
109
- border-radius: 4px;
110
- border: 1px solid #DCDFE6;
111
-
112
- &.focus{
113
- border-color: #1890FF;
114
- }
115
-
116
- ::v-deep .el-picker-panel{
117
- position: absolute;
118
- z-index: 401;
119
- }
120
-
121
- ::v-deep .el-input__inner{
122
- border: none;
123
- padding: 0;
124
- text-align: center;
125
- }
126
-
127
- ::v-deep .el-input__prefix{
128
- display: none;
129
- }
130
270
  }
131
- </style>
271
+ </style>
@@ -25,7 +25,7 @@ export default {
25
25
  if (this.gap) {
26
26
  result.gap = this.gap
27
27
  } else {
28
- result.gap = 'var(--xt-flex-box-gap, 8px)'
28
+ result.gap = ''
29
29
  }
30
30
  return result
31
31
  }
@@ -0,0 +1,8 @@
1
+ import XtFormSchema from './index.vue'
2
+
3
+ XtFormSchema.install = function (Vue) {
4
+ Vue.component(XtFormSchema.name, XtFormSchema)
5
+ }
6
+
7
+ export default XtFormSchema
8
+ export { XtFormSchema }
@@ -0,0 +1,328 @@
1
+ <template>
2
+ <div class="xt-form-schema">
3
+ <div v-if="showSearchTags" class="search-tags">
4
+ <span class="tags-title">已检索:</span>
5
+ <el-tag
6
+ v-for="(tag, key) in activeSearchTags"
7
+ :key="key"
8
+ closable
9
+ size="small"
10
+ @close="handleRemoveTag(key)"
11
+ >
12
+ {{ tag.label }}: {{ tag.value }}
13
+ </el-tag>
14
+ <span v-if="activeSearchTagsCount === 0" class="no-tags">暂无检索条件</span>
15
+ </div>
16
+
17
+ <el-dialog
18
+ v-if="mode === 'dialog'"
19
+ :title="title"
20
+ :visible.sync="visible"
21
+ :width="width"
22
+ :before-close="handleCancel"
23
+ class="xt-form-schema-dialog"
24
+ append-to-body
25
+ modal-append-to-body
26
+ >
27
+ <el-form :model="formData" :inline="false" label-width="120px">
28
+ <el-form-item :label="field.label" :prop="field.prop" :key="field.prop" v-for="field in schema">
29
+ <component v-if="!field.isSlot" :is="getFieldComponent(field)" v-bind="getFieldProps(field)" />
30
+ <slot v-else :name="field.prop" :field="field">
31
+ </slot>
32
+ </el-form-item>
33
+ </el-form>
34
+ <div slot="footer" class="dialog-footer">
35
+ <el-button @click="handleCancel">取消</el-button>
36
+ <el-button type="primary" @click="handleConfirm">确认</el-button>
37
+ </div>
38
+ </el-dialog>
39
+
40
+ <el-drawer
41
+ v-if="mode === 'drawer'"
42
+ :title="title"
43
+ :visible.sync="visible"
44
+ :direction="direction"
45
+ :size="width"
46
+ :before-close="handleCancel"
47
+ class="xt-form-schema-drawer"
48
+ append-to-body
49
+ modal-append-to-body
50
+ >
51
+ <el-form :model="formData" :inline="false" label-width="120px">
52
+ <el-form-item :label="field.label" :prop="field.prop" v-for="field in schema" :key="field.prop">
53
+ <component v-if="!field.isSlot" :is="getFieldComponent(field)" v-bind="getFieldProps(field)" />
54
+ <slot v-else :name="field.prop" :field="field">
55
+ </slot>
56
+ </el-form-item>
57
+ </el-form>
58
+ <div class="drawer-footer">
59
+ <el-button @click="handleCancel">取消</el-button>
60
+ <el-button type="primary" @click="handleConfirm">确认</el-button>
61
+ </div>
62
+ </el-drawer>
63
+ </div>
64
+ </template>
65
+
66
+ <script>
67
+ export default {
68
+ name: 'XtFormSchema',
69
+ props: {
70
+ visible: {
71
+ type: Boolean,
72
+ default: false
73
+ },
74
+ value: {
75
+ type: Object,
76
+ default: () => ({})
77
+ },
78
+ schema: {
79
+ type: Array,
80
+ default: () => []
81
+ },
82
+ mode: {
83
+ type: String,
84
+ default: 'dialog',
85
+ validator: (val) => ['dialog', 'drawer'].includes(val)
86
+ },
87
+ title: {
88
+ type: String,
89
+ default: '高级搜索'
90
+ },
91
+ width: {
92
+ type: [String, Number],
93
+ default: '500px'
94
+ },
95
+ direction: {
96
+ type: String,
97
+ default: 'rtl',
98
+ validator: (val) => ['ltr', 'rtl', 'ttb', 'btt'].includes(val)
99
+ },
100
+ showSearchTags: {
101
+ type: Boolean,
102
+ default: false
103
+ },
104
+ simpleFields: {
105
+ type: Array,
106
+ default: () => []
107
+ }
108
+ },
109
+ data() {
110
+ return {
111
+ formData: {}
112
+ }
113
+ },
114
+ computed: {
115
+ activeSearchTags() {
116
+ const tags = {}
117
+ this.schema.forEach(field => {
118
+ const value = this.formData[field.prop]
119
+ if (value !== null && value !== undefined && value !== '' && value !== []) {
120
+ let displayValue = value
121
+ if (field.type === 'select' && field.options) {
122
+ const option = field.options.find(opt => opt.value === value)
123
+ displayValue = option ? option.label : value
124
+ } else if (field.type === 'date' && Array.isArray(value)) {
125
+ displayValue = value.map(v => v ? this.formatDate(v) : '').join(' - ')
126
+ } else if (field.type === 'daterange' && Array.isArray(value)) {
127
+ displayValue = value.map(v => v ? this.formatDate(v) : '').join(' - ')
128
+ } else if (field.type === 'checkbox-group' && Array.isArray(value)) {
129
+ const labels = value.map(v => {
130
+ const option = (field.options || []).find(opt => opt.value === v)
131
+ return option ? option.label : v
132
+ })
133
+ displayValue = labels.join(', ')
134
+ }
135
+ tags[field.prop] = {
136
+ label: field.label,
137
+ value: displayValue
138
+ }
139
+ }
140
+ })
141
+ return tags
142
+ },
143
+ activeSearchTagsCount() {
144
+ return Object.keys(this.activeSearchTags).length
145
+ }
146
+ },
147
+ watch: {
148
+ visible: {
149
+ immediate: true,
150
+ handler(val) {
151
+ if (val) {
152
+ this.initFormData()
153
+ }
154
+ }
155
+ },
156
+ value: {
157
+ deep: true,
158
+ handler(val) {
159
+ if (val && this.visible) {
160
+ this.formData = { ...val }
161
+ }
162
+ }
163
+ }
164
+ },
165
+ methods: {
166
+ initFormData() {
167
+ const data = {}
168
+ this.schema.forEach(field => {
169
+ data[field.prop] = this.value[field.prop] !== undefined ? this.value[field.prop] : (field.defaultValue !== undefined ? field.defaultValue : '')
170
+ })
171
+ this.formData = data
172
+ },
173
+ getFieldComponent(field) {
174
+ const componentMap = {
175
+ input: 'el-input',
176
+ textarea: 'el-input',
177
+ select: 'el-select',
178
+ checkbox: 'el-checkbox',
179
+ 'checkbox-group': 'el-checkbox-group',
180
+ radio: 'el-radio',
181
+ 'radio-group': 'el-radio-group',
182
+ 'date': 'el-date-picker',
183
+ daterange: 'el-date-picker',
184
+ datetime: 'el-date-picker',
185
+ 'datetime-range': 'el-date-picker',
186
+ number: 'el-input-number',
187
+ switch: 'el-switch'
188
+ }
189
+ return componentMap[field.type] || 'el-input'
190
+ },
191
+ getFieldProps(field) {
192
+ const props = {
193
+ value: this.formData[field.prop],
194
+ placeholder: field.placeholder || `请输入${field.label}`
195
+ }
196
+
197
+ if (field.type === 'textarea') {
198
+ props.type = 'textarea'
199
+ props.rows = field.rows || 3
200
+ }
201
+
202
+ if (field.type === 'select') {
203
+ props.filterable = field.filterable || false
204
+ props.multiple = field.multiple || false
205
+ }
206
+
207
+ if (field.type === 'date') {
208
+ props.type = field.dateType || 'date'
209
+ props.format = field.format || 'yyyy-MM-dd'
210
+ props['value-format'] = field.valueFormat || 'yyyy-MM-dd'
211
+ }
212
+
213
+ if (field.type === 'daterange') {
214
+ props.type = 'daterange'
215
+ props.format = field.format || 'yyyy-MM-dd'
216
+ props['value-format'] = field.valueFormat || 'yyyy-MM-dd'
217
+ }
218
+
219
+ if (field.type === 'datetime') {
220
+ props.type = 'datetime'
221
+ props.format = field.format || 'yyyy-MM-dd HH:mm:ss'
222
+ props['value-format'] = field.valueFormat || 'yyyy-MM-dd HH:mm:ss'
223
+ }
224
+
225
+ if (field.type === 'datetime-range') {
226
+ props.type = 'datetimerange'
227
+ props.format = field.format || 'yyyy-MM-dd HH:mm:ss'
228
+ props['value-format'] = field.valueFormat || 'yyyy-MM-dd HH:mm:ss'
229
+ }
230
+
231
+ if (field.type === 'number') {
232
+ props.min = field.min
233
+ props.max = field.max
234
+ props.step = field.step || 1
235
+ }
236
+
237
+ if (field.type === 'checkbox-group' || field.type === 'radio-group') {
238
+ props.options = field.options || []
239
+ }
240
+
241
+ if (field.disabled !== undefined) {
242
+ props.disabled = field.disabled
243
+ }
244
+
245
+ if (field.size !== undefined) {
246
+ props.size = field.size
247
+ }
248
+
249
+ props['on:input'] = (val) => this.handleFieldChange(field.prop, val)
250
+ props['on:change'] = (val) => this.handleFieldChange(field.prop, val)
251
+
252
+ return props
253
+ },
254
+ handleFieldChange(prop, val) {
255
+ this.formData[prop] = val
256
+ this.$emit('input', { ...this.formData })
257
+ this.$emit('change', { prop, value: val })
258
+ },
259
+ handleRemoveTag(prop) {
260
+ this.formData[prop] = ''
261
+ this.$emit('input', { ...this.formData })
262
+ this.$emit('change', { prop, value: '' })
263
+ },
264
+ handleConfirm() {
265
+ this.$emit('confirm', { ...this.formData })
266
+ this.$emit('input', { ...this.formData })
267
+ this.$emit('update:visible', false)
268
+ },
269
+ handleCancel() {
270
+ this.$emit('cancel')
271
+ this.$emit('update:visible', false)
272
+ },
273
+ formatDate(date) {
274
+ if (!date) return ''
275
+ const d = new Date(date)
276
+ const year = d.getFullYear()
277
+ const month = String(d.getMonth() + 1).padStart(2, '0')
278
+ const day = String(d.getDate()).padStart(2, '0')
279
+ return `${year}-${month}-${day}`
280
+ },
281
+ resetFields() {
282
+ this.initFormData()
283
+ this.schema.forEach(field => {
284
+ this.formData[field.prop] = field.defaultValue !== undefined ? field.defaultValue : ''
285
+ })
286
+ this.$emit('input', { ...this.formData })
287
+ }
288
+ }
289
+ }
290
+ </script>
291
+
292
+ <style lang="scss" scoped>
293
+ .xt-form-schema {
294
+ .search-tags {
295
+ display: flex;
296
+ flex-wrap: wrap;
297
+ align-items: center;
298
+ padding: 8px 12px;
299
+ background: #f5f7fa;
300
+ border-radius: 4px;
301
+ margin-bottom: 12px;
302
+
303
+ .tags-title {
304
+ font-size: 14px;
305
+ color: #606266;
306
+ margin-right: 8px;
307
+ flex-shrink: 0;
308
+ }
309
+
310
+ .el-tag {
311
+ margin: 4px;
312
+ cursor: pointer;
313
+ }
314
+
315
+ .no-tags {
316
+ font-size: 14px;
317
+ color: #c0c4cc;
318
+ }
319
+ }
320
+
321
+ .dialog-footer,
322
+ .drawer-footer {
323
+ text-align: right;
324
+ padding-top: 16px;
325
+ border-top: 1px solid #ebeef5;
326
+ }
327
+ }
328
+ </style>