xianniu-ui 0.9.14 → 2.0.2
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.
- package/lib/style/basic.css +1 -1
- package/lib/style/ellipsis.css +1 -1
- package/lib/style/fonts/element-icons.ttf +0 -0
- package/lib/style/fonts/element-icons.woff +0 -0
- package/lib/style/index.css +1 -0
- package/lib/style/index.js +1 -0
- package/lib/style/page.css +1 -0
- package/lib/style/search.css +1 -0
- package/lib/style/table.css +1 -0
- package/lib/style/tag.css +1 -0
- package/lib/style/theme/element-variables.scss +13 -11
- package/lib/style/theme/theme.scss +5 -4
- package/lib/style/tip.css +1 -0
- package/lib/style/tree.css +1 -0
- package/lib/style/upload.css +1 -0
- package/lib/xianniu-ui.common.js +19606 -69549
- package/lib/xianniu-ui.css +1 -1
- package/lib/xianniu-ui.umd.js +19611 -69554
- package/lib/xianniu-ui.umd.min.js +2 -72
- package/package.json +20 -12
- package/packages/card/main.vue +1 -1
- package/packages/page/main.vue +2 -2
- package/packages/search/main.vue +391 -293
- package/packages/style/gulpfile.js +12 -7
- package/packages/style/src/basic.scss +1 -0
- package/packages/style/src/ellipsis.scss +1 -0
- package/packages/style/src/index.scss +3 -5
- package/packages/style/src/search.scss +127 -15
- package/packages/style/src/theme/element-variables.scss +13 -11
- package/packages/style/src/theme/theme.scss +5 -4
- package/packages/style/src/upload.scss +47 -8
- package/packages/table/main.vue +77 -34
- package/packages/tag/main.vue +1 -1
- package/packages/upload/main.vue +165 -35
- package/src/area/data.js +3890 -0
- package/src/area/index.js +71 -1
- package/src/oss/index.js +93 -60
- package/src/plugins/index.js +5 -2
package/packages/search/main.vue
CHANGED
|
@@ -6,154 +6,138 @@
|
|
|
6
6
|
:model="form"
|
|
7
7
|
:label-width="labelWidth"
|
|
8
8
|
@submit.native.prevent
|
|
9
|
-
@keyup.enter.native="
|
|
9
|
+
@keyup.enter.native="handleSearch"
|
|
10
10
|
>
|
|
11
|
-
<
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
<el-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class="xn-search--row_col"
|
|
20
|
-
>
|
|
21
|
-
<xn-city
|
|
22
|
-
:key="item.prop"
|
|
23
|
-
:data-level="(item.options && item.options.dataLevel) || 2"
|
|
24
|
-
v-model="item.modelVal"
|
|
25
|
-
v-bind="item.options ? { ...item.options } : {}"
|
|
26
|
-
@on-city="handleChangeCity"
|
|
27
|
-
/>
|
|
28
|
-
</el-form-item>
|
|
29
|
-
<el-form-item
|
|
30
|
-
v-if="item.type === 'cascader'"
|
|
31
|
-
:key="idx"
|
|
32
|
-
:label="item.label"
|
|
33
|
-
:prop="item.prop"
|
|
34
|
-
class="xn-search--row_col"
|
|
35
|
-
>
|
|
36
|
-
<el-cascader
|
|
37
|
-
v-model="item.modelVal"
|
|
38
|
-
style="width: 100%"
|
|
39
|
-
:options="item.data"
|
|
40
|
-
v-bind="item.options ? { ...item.options } : {}"
|
|
41
|
-
@change="onChangeCascader($event, item)"
|
|
42
|
-
></el-cascader>
|
|
43
|
-
</el-form-item>
|
|
44
|
-
<el-form-item
|
|
45
|
-
v-if="item.type === 'input'"
|
|
46
|
-
:key="idx"
|
|
47
|
-
:label="item.label"
|
|
48
|
-
:prop="item.prop"
|
|
49
|
-
class="xn-search--row_col"
|
|
50
|
-
>
|
|
51
|
-
<el-input
|
|
52
|
-
:key="item.prop"
|
|
53
|
-
style="width: 100%"
|
|
54
|
-
v-bind="item.options ? { ...item.options } : {}"
|
|
55
|
-
v-model.trim="item.modelVal"
|
|
56
|
-
:clearable="item.clearable || true"
|
|
57
|
-
:placeholder="item.placeholder || '请填写' + item.label"
|
|
58
|
-
/>
|
|
59
|
-
</el-form-item>
|
|
60
|
-
<el-form-item
|
|
61
|
-
v-if="item.type === 'select'"
|
|
62
|
-
:key="idx"
|
|
63
|
-
:label="item.label"
|
|
64
|
-
:prop="item.prop"
|
|
65
|
-
class="xn-search--row_col"
|
|
66
|
-
>
|
|
67
|
-
<el-select
|
|
68
|
-
:key="item.prop"
|
|
69
|
-
style="width: 100%"
|
|
70
|
-
v-model="item.modelVal"
|
|
71
|
-
:placeholder="item.placeholder || '请选择' + item.label"
|
|
72
|
-
:clearable="item.clearable || true"
|
|
73
|
-
filterable
|
|
74
|
-
v-bind="item.options ? { ...item.options } : {}"
|
|
75
|
-
:remote="isRemote(item.remote)"
|
|
76
|
-
:reserve-keyword="isRemote(item.remote)"
|
|
77
|
-
:default-first-option="isRemote(item.remote)"
|
|
78
|
-
:remote-method="item.remote"
|
|
11
|
+
<div class="xn-search-flex">
|
|
12
|
+
<el-row :gutter="0" class="xn-search--row">
|
|
13
|
+
<template v-for="(item, idx) in visibleFormItems">
|
|
14
|
+
<el-col v-bind="getColumnConfig()" :key="getItemKey(item, idx)">
|
|
15
|
+
<el-form-item
|
|
16
|
+
:label="item.label"
|
|
17
|
+
:prop="item.prop"
|
|
18
|
+
class="xn-search--row_col"
|
|
79
19
|
>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"
|
|
86
|
-
|
|
87
|
-
itemData[(item.options && item.options.valueKey) || 'value']
|
|
88
|
-
"
|
|
20
|
+
<!-- 城市选择器 -->
|
|
21
|
+
<xn-city
|
|
22
|
+
v-if="item.type === 'city'"
|
|
23
|
+
v-model="item.modelVal"
|
|
24
|
+
:data-level="getCityDataLevel(item)"
|
|
25
|
+
v-bind="getItemOptions(item)"
|
|
26
|
+
@on-city="handleCityChange"
|
|
89
27
|
/>
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
item
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
28
|
+
|
|
29
|
+
<!-- 级联选择器 -->
|
|
30
|
+
<el-cascader
|
|
31
|
+
v-else-if="item.type === 'cascader'"
|
|
32
|
+
v-model="item.modelVal"
|
|
33
|
+
style="width: 100%"
|
|
34
|
+
:options="item.data"
|
|
35
|
+
v-bind="getItemOptions(item)"
|
|
36
|
+
@change="handleCascaderChange($event, item)"
|
|
37
|
+
/>
|
|
38
|
+
|
|
39
|
+
<!-- 输入框 -->
|
|
40
|
+
<el-input
|
|
41
|
+
v-else-if="item.type === 'input'"
|
|
42
|
+
v-model="item.modelVal"
|
|
43
|
+
style="width: 100%"
|
|
44
|
+
:clearable="getClearable(item)"
|
|
45
|
+
:placeholder="getPlaceholder(item)"
|
|
46
|
+
v-bind="getItemOptions(item)"
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<!-- 下拉选择器 -->
|
|
50
|
+
<el-select
|
|
51
|
+
v-else-if="item.type === 'select'"
|
|
52
|
+
v-model="item.modelVal"
|
|
53
|
+
style="width: 100%"
|
|
54
|
+
:clearable="getClearable(item)"
|
|
55
|
+
:filterable="true"
|
|
56
|
+
:placeholder="getPlaceholder(item)"
|
|
57
|
+
:remote="isRemoteSearch(item)"
|
|
58
|
+
:reserve-keyword="isRemoteSearch(item)"
|
|
59
|
+
:default-first-option="isRemoteSearch(item)"
|
|
60
|
+
:remote-method="item.remote"
|
|
61
|
+
v-bind="getItemOptions(item)"
|
|
62
|
+
@change="handleSelectChange(item)"
|
|
63
|
+
>
|
|
64
|
+
<el-option
|
|
65
|
+
v-for="(option, optionIdx) in item.data"
|
|
66
|
+
:key="optionIdx"
|
|
67
|
+
:label="getOptionLabel(option, item)"
|
|
68
|
+
:value="getOptionValue(option, item)"
|
|
69
|
+
/>
|
|
70
|
+
</el-select>
|
|
71
|
+
|
|
72
|
+
<!-- 日期选择器 -->
|
|
73
|
+
<xn-date
|
|
74
|
+
v-else-if="isDateType(item.type)"
|
|
75
|
+
v-model="item.modelVal"
|
|
76
|
+
:mode="item.mode || 'range'"
|
|
77
|
+
:type="item.type || 'daterange'"
|
|
78
|
+
:is-shortcut="showShortcut(item)"
|
|
79
|
+
:placeholder="item.placeholder"
|
|
80
|
+
:start-placeholder="(item.options && item.options.startPlaceholder) || undefined"
|
|
81
|
+
:end-placeholder="(item.options && item.options.endPlaceholder) || undefined"
|
|
82
|
+
:clearable="getClearable(item)"
|
|
83
|
+
:default-time="getDefaultTime(item)"
|
|
84
|
+
@on-change="handleDateChange"
|
|
85
|
+
@on-format="handleDateFormatChange"
|
|
86
|
+
/>
|
|
87
|
+
</el-form-item>
|
|
88
|
+
</el-col>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<!-- 展开/收起按钮 -->
|
|
92
|
+
<el-col
|
|
93
|
+
v-if="showToggleButton"
|
|
94
|
+
v-bind="toggleColumnConfig"
|
|
95
|
+
class="coll-box"
|
|
96
|
+
>
|
|
97
|
+
<el-link type="primary" :underline="false" @click="toggleCollapse">
|
|
98
|
+
<span>{{ isCollapsed ? "展开全部" : "收起" }}</span>
|
|
99
|
+
<i class="ml-5" :class="toggleIcon" />
|
|
100
|
+
</el-link>
|
|
120
101
|
</el-col>
|
|
121
|
-
</
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
102
|
+
</el-row>
|
|
103
|
+
|
|
104
|
+
<!-- 操作按钮 -->
|
|
105
|
+
<div class="xn-search-searchbtn" :class="{ 'is-horizontal': isHorizontalButtons }">
|
|
106
|
+
<slot name="prepend" />
|
|
107
|
+
<el-button type="primary" icon="el-icon-search" @click="handleSearch"
|
|
108
|
+
>查询</el-button
|
|
128
109
|
>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<el-button @click="onReset">重置</el-button>
|
|
134
|
-
<slot name="append"></slot>
|
|
135
|
-
<el-button
|
|
136
|
-
v-if="formData.length && formData.length > defaultColl"
|
|
137
|
-
type="text"
|
|
138
|
-
@click="isColl = !isColl"
|
|
139
|
-
>
|
|
140
|
-
<template v-if="_showColl">
|
|
141
|
-
<span>{{ isColl ? "收起" : "展开" }}</span
|
|
142
|
-
><i class="ml-5" :class="toggle"></i>
|
|
143
|
-
</template>
|
|
144
|
-
</el-button>
|
|
145
|
-
</el-form-item>
|
|
146
|
-
</el-col>
|
|
147
|
-
</el-row>
|
|
110
|
+
<el-button @click="handleReset">重置</el-button>
|
|
111
|
+
<slot name="append" />
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
148
114
|
</el-form>
|
|
149
115
|
</div>
|
|
150
116
|
</template>
|
|
151
117
|
|
|
152
118
|
<script>
|
|
153
|
-
import { Form } from "element-ui";
|
|
119
|
+
import { Form } from "@liuzengwei/element-ui";
|
|
120
|
+
|
|
121
|
+
// 日期类型集合
|
|
122
|
+
const DATE_TYPES = new Set([
|
|
123
|
+
"date",
|
|
124
|
+
"week",
|
|
125
|
+
"month",
|
|
126
|
+
"year",
|
|
127
|
+
"dates",
|
|
128
|
+
"datetime",
|
|
129
|
+
"datetimerange",
|
|
130
|
+
"daterange",
|
|
131
|
+
"monthrange",
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
// 范围类型集合
|
|
135
|
+
const RANGE_TYPES = new Set(["datetimerange", "daterange", "monthrange"]);
|
|
136
|
+
|
|
154
137
|
export default {
|
|
155
138
|
name: "XnSearch",
|
|
156
139
|
extends: Form,
|
|
140
|
+
|
|
157
141
|
props: {
|
|
158
142
|
formData: {
|
|
159
143
|
type: Array,
|
|
@@ -173,210 +157,324 @@ export default {
|
|
|
173
157
|
},
|
|
174
158
|
defaultColl: {
|
|
175
159
|
type: Number,
|
|
176
|
-
default:
|
|
160
|
+
default: 8,
|
|
161
|
+
validator: (value) => value > 0,
|
|
177
162
|
},
|
|
178
163
|
lastLabelWidth: {
|
|
179
164
|
type: String,
|
|
180
165
|
default: null,
|
|
181
166
|
},
|
|
182
167
|
},
|
|
168
|
+
|
|
169
|
+
data() {
|
|
170
|
+
return {
|
|
171
|
+
city: {},
|
|
172
|
+
form: {
|
|
173
|
+
value: [],
|
|
174
|
+
},
|
|
175
|
+
isCollapsed: true, // 默认收起状态
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
|
|
183
179
|
computed: {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
180
|
+
// 可见的表单项
|
|
181
|
+
visibleFormItems() {
|
|
182
|
+
if (!this.form.value.length) return [];
|
|
183
|
+
|
|
184
|
+
return this.form.value.filter((item, index) => {
|
|
185
|
+
// 如果已展开,显示所有项
|
|
186
|
+
if (!this.isCollapsed) return true;
|
|
187
|
+
|
|
188
|
+
// 如果收起,只显示前 defaultColl 项
|
|
189
|
+
return index < this.defaultColl;
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
// 是否显示展开/收起按钮
|
|
194
|
+
showToggleButton() {
|
|
195
|
+
return this.showColl && this.formData.length > this.defaultColl;
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
// 切换图标
|
|
199
|
+
toggleIcon() {
|
|
200
|
+
return this.isCollapsed ? "el-icon-arrow-down" : "el-icon-arrow-up";
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// 是否横向排列按钮(查询项<=4个时横向排列)
|
|
204
|
+
isHorizontalButtons() {
|
|
205
|
+
return this.formData.length <= 4;
|
|
194
206
|
},
|
|
195
|
-
|
|
207
|
+
|
|
208
|
+
// 列配置
|
|
209
|
+
columnConfig() {
|
|
196
210
|
const { span } = this;
|
|
197
211
|
return {
|
|
198
212
|
span,
|
|
199
|
-
xs: span
|
|
200
|
-
sm: span
|
|
201
|
-
md: span
|
|
202
|
-
lg: span
|
|
203
|
-
xl: span
|
|
213
|
+
xs: span || 24,
|
|
214
|
+
sm: span || 12,
|
|
215
|
+
md: span || 8,
|
|
216
|
+
lg: span || 6,
|
|
217
|
+
xl: span || 6,
|
|
204
218
|
offset: 0,
|
|
205
219
|
};
|
|
206
220
|
},
|
|
207
|
-
isRemote() {
|
|
208
|
-
return (val) => {
|
|
209
|
-
return val && typeof val === "function";
|
|
210
|
-
};
|
|
211
|
-
},
|
|
212
|
-
toggle() {
|
|
213
|
-
return this.isColl ? "el-icon-arrow-up" : "el-icon-arrow-down";
|
|
214
|
-
},
|
|
215
|
-
isDate() {
|
|
216
|
-
return (type) => {
|
|
217
|
-
return [
|
|
218
|
-
"date",
|
|
219
|
-
"week",
|
|
220
|
-
"month",
|
|
221
|
-
"year",
|
|
222
|
-
"dates",
|
|
223
|
-
"datetime",
|
|
224
|
-
"datetimerange",
|
|
225
|
-
"daterange",
|
|
226
|
-
"monthrange",
|
|
227
|
-
].includes(type);
|
|
228
|
-
};
|
|
229
|
-
},
|
|
230
|
-
isRange() {
|
|
231
|
-
return (type) => {
|
|
232
|
-
return ["datetimerange", "daterange", "monthrange"].includes(type);
|
|
233
|
-
};
|
|
234
|
-
},
|
|
235
|
-
showShortcut() {
|
|
236
|
-
return (item) => {
|
|
237
|
-
let flag = "";
|
|
238
|
-
if (this.isRange(item.type)) {
|
|
239
|
-
flag = item.options.isShortcut;
|
|
240
|
-
} else {
|
|
241
|
-
flag = false;
|
|
242
|
-
}
|
|
243
221
|
|
|
244
|
-
|
|
222
|
+
// 切换按钮列配置
|
|
223
|
+
toggleColumnConfig() {
|
|
224
|
+
const visibleCount = this.visibleFormItems.length;
|
|
225
|
+
const { span } = this;
|
|
226
|
+
|
|
227
|
+
// 获取每行的列数
|
|
228
|
+
const xlColumns = 24 / (span || 6);
|
|
229
|
+
const lgColumns = 24 / (span || 6);
|
|
230
|
+
const mdColumns = 24 / (span || 8);
|
|
231
|
+
const smColumns = 24 / (span || 12);
|
|
232
|
+
const xsColumns = 24 / (span || 24);
|
|
233
|
+
|
|
234
|
+
// 计算最后一行已占用的列数
|
|
235
|
+
const xlLastRowUsed = visibleCount % xlColumns || xlColumns;
|
|
236
|
+
const lgLastRowUsed = visibleCount % lgColumns || lgColumns;
|
|
237
|
+
const mdLastRowUsed = visibleCount % mdColumns || mdColumns;
|
|
238
|
+
const smLastRowUsed = visibleCount % smColumns || smColumns;
|
|
239
|
+
const xsLastRowUsed = visibleCount % xsColumns || xsColumns;
|
|
240
|
+
|
|
241
|
+
// 计算各断点下需要补齐的列数
|
|
242
|
+
const xlRemaining = xlColumns - xlLastRowUsed;
|
|
243
|
+
const lgRemaining = lgColumns - lgLastRowUsed;
|
|
244
|
+
const mdRemaining = mdColumns - mdLastRowUsed;
|
|
245
|
+
const smRemaining = smColumns - smLastRowUsed;
|
|
246
|
+
const xsRemaining = xsColumns - xsLastRowUsed;
|
|
247
|
+
|
|
248
|
+
// 如果最后一行已满,则按钮独占一行(24栅格),否则只占用剩余的栅格数
|
|
249
|
+
const xlSpan = xlRemaining === 0 ? 24 : (24 / xlColumns) * xlRemaining;
|
|
250
|
+
const lgSpan = lgRemaining === 0 ? 24 : (24 / lgColumns) * lgRemaining;
|
|
251
|
+
const mdSpan = mdRemaining === 0 ? 24 : (24 / mdColumns) * mdRemaining;
|
|
252
|
+
const smSpan = smRemaining === 0 ? 24 : (24 / smColumns) * smRemaining;
|
|
253
|
+
const xsSpan = xsRemaining === 0 ? 24 : (24 / xsColumns) * xsRemaining;
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
span: xlSpan,
|
|
257
|
+
xs: xsSpan,
|
|
258
|
+
sm: smSpan,
|
|
259
|
+
md: mdSpan,
|
|
260
|
+
lg: lgSpan,
|
|
261
|
+
xl: xlSpan,
|
|
262
|
+
offset: 0,
|
|
245
263
|
};
|
|
246
264
|
},
|
|
247
|
-
btnLabelWidth() {
|
|
248
|
-
const { lastLabelWidth, labelWidth } = this;
|
|
249
|
-
let w = labelWidth;
|
|
250
|
-
if (lastLabelWidth != null) {
|
|
251
|
-
w = lastLabelWidth;
|
|
252
|
-
} else if (this.form.value.length === 1 || !this.isColl) {
|
|
253
|
-
w = 0;
|
|
254
|
-
}
|
|
255
|
-
return w;
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
data() {
|
|
259
|
-
return {
|
|
260
|
-
city: {},
|
|
261
|
-
form: {
|
|
262
|
-
value: [],
|
|
263
|
-
},
|
|
264
|
-
formValues:{},
|
|
265
|
-
isColl: false,
|
|
266
|
-
};
|
|
267
|
-
},
|
|
268
|
-
created() {
|
|
269
|
-
// this.init();
|
|
270
265
|
},
|
|
266
|
+
|
|
271
267
|
watch: {
|
|
272
268
|
formData: {
|
|
273
|
-
handler(
|
|
274
|
-
|
|
269
|
+
handler(newFormData) {
|
|
270
|
+
if (newFormData?.length) {
|
|
271
|
+
this.initFormItems();
|
|
272
|
+
}
|
|
275
273
|
},
|
|
276
274
|
immediate: true,
|
|
277
275
|
deep: true,
|
|
278
276
|
},
|
|
279
277
|
},
|
|
278
|
+
|
|
280
279
|
methods: {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
});
|
|
291
|
-
}
|
|
280
|
+
// 初始化表单项
|
|
281
|
+
initFormItems() {
|
|
282
|
+
this.form.value = this.formData.map((item, index) => ({
|
|
283
|
+
...item,
|
|
284
|
+
// 确保每个项目都有唯一的内部标识
|
|
285
|
+
_internalId: item.prop || `field_${index}`,
|
|
286
|
+
modelVal: item.defaultValue || "",
|
|
287
|
+
isShow: index < this.defaultColl || !this.showColl,
|
|
288
|
+
}));
|
|
292
289
|
},
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
290
|
+
|
|
291
|
+
// 获取项目唯一标识
|
|
292
|
+
getItemKey(item, index) {
|
|
293
|
+
// 使用内部 ID 确保唯一性,即使没有 prop 也不会重复
|
|
294
|
+
return `${item._internalId}_${item.type}_${index}`;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// 获取列配置
|
|
298
|
+
getColumnConfig() {
|
|
299
|
+
return this.columnConfig;
|
|
300
|
+
},
|
|
301
|
+
|
|
302
|
+
// 获取项目选项
|
|
303
|
+
getItemOptions(item) {
|
|
304
|
+
return item.options || {};
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
// 获取城市数据级别
|
|
308
|
+
getCityDataLevel(item) {
|
|
309
|
+
return item.options?.dataLevel || 2;
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
// 获取清除性
|
|
313
|
+
getClearable(item) {
|
|
314
|
+
return item.clearable !== false;
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
// 获取占位符
|
|
318
|
+
getPlaceholder(item) {
|
|
319
|
+
if (item.placeholder) return item.placeholder;
|
|
320
|
+
|
|
321
|
+
const action = item.type === "select" ? "请选择" : "请填写";
|
|
322
|
+
return `${action}${item.label}`;
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
// 获取选项标签
|
|
326
|
+
getOptionLabel(option, item) {
|
|
327
|
+
const labelKey = item.options?.labelKey || "label";
|
|
328
|
+
return option[labelKey];
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
// 获取选项值
|
|
332
|
+
getOptionValue(option, item) {
|
|
333
|
+
const valueKey = item.options?.valueKey || "value";
|
|
334
|
+
return option[valueKey];
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
// 是否为远程搜索
|
|
338
|
+
isRemoteSearch(item) {
|
|
339
|
+
return item.remote && typeof item.remote === "function";
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
// 是否为日期类型
|
|
343
|
+
isDateType(type) {
|
|
344
|
+
return DATE_TYPES.has(type);
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
// 是否为范围类型
|
|
348
|
+
isRangeType(type) {
|
|
349
|
+
return RANGE_TYPES.has(type);
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// 获取默认时间
|
|
353
|
+
getDefaultTime(item) {
|
|
354
|
+
if (item.defaultTime !== undefined) return item.defaultTime;
|
|
355
|
+
return this.isRangeType(item.type) ? ["00:00:00", "23:59:59"] : undefined;
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// 显示快捷选项
|
|
359
|
+
showShortcut(item) {
|
|
360
|
+
return this.isRangeType(item.type) && item.options?.isShortcut;
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
// 切换展开/收起状态
|
|
364
|
+
toggleCollapse() {
|
|
365
|
+
this.isCollapsed = !this.isCollapsed;
|
|
318
366
|
},
|
|
319
|
-
|
|
320
|
-
|
|
367
|
+
|
|
368
|
+
// 处理搜索
|
|
369
|
+
handleSearch() {
|
|
370
|
+
const formData = this.buildFormData();
|
|
371
|
+
this.$emit("on-search", formData);
|
|
321
372
|
},
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
373
|
+
|
|
374
|
+
// 处理重置
|
|
375
|
+
handleReset() {
|
|
376
|
+
this.resetFormFields();
|
|
325
377
|
this.$emit("on-reset");
|
|
326
378
|
this.$emit("on-search", {});
|
|
327
379
|
},
|
|
328
|
-
|
|
329
|
-
|
|
380
|
+
|
|
381
|
+
// 构建表单数据
|
|
382
|
+
buildFormData() {
|
|
383
|
+
const formData = {};
|
|
384
|
+
|
|
385
|
+
this.form.value.forEach((item) => {
|
|
386
|
+
const { prop, type, modelVal, mode } = item;
|
|
387
|
+
|
|
388
|
+
if (this.isRangeType(type) || mode === "group") {
|
|
389
|
+
const { start, end } = item.options || {};
|
|
390
|
+
if (start && end) {
|
|
391
|
+
formData[start] = modelVal?.[0] || "";
|
|
392
|
+
formData[end] = modelVal?.[1] || "";
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
formData[prop] = modelVal;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return formData;
|
|
330
400
|
},
|
|
331
|
-
|
|
332
|
-
|
|
401
|
+
|
|
402
|
+
// 重置表单字段
|
|
403
|
+
resetFormFields() {
|
|
404
|
+
this.form.value.forEach((item) => {
|
|
405
|
+
item.modelVal = item.defaultValue || "";
|
|
406
|
+
});
|
|
333
407
|
},
|
|
334
|
-
|
|
408
|
+
|
|
409
|
+
// 处理城市变化
|
|
410
|
+
handleCityChange({ cityCodeLast: cityCode, cityNameLast: cityName }) {
|
|
335
411
|
this.city = { cityCode, cityName };
|
|
336
412
|
},
|
|
413
|
+
|
|
414
|
+
// 处理级联变化
|
|
415
|
+
handleCascaderChange(value, item) {
|
|
416
|
+
const flatValue = [...new Set(value.flat(Infinity))];
|
|
417
|
+
item.modelVal = flatValue;
|
|
418
|
+
|
|
419
|
+
const changeHandler = item.options?.change;
|
|
420
|
+
if (typeof changeHandler === "function") {
|
|
421
|
+
changeHandler(flatValue, value);
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
// 处理选择变化
|
|
426
|
+
handleSelectChange(item) {
|
|
427
|
+
const changeHandler = item.change;
|
|
428
|
+
if (typeof changeHandler === "function") {
|
|
429
|
+
changeHandler(item.modelVal, item.data);
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
// 处理日期变化
|
|
434
|
+
handleDateChange() {
|
|
435
|
+
// 可根据需要扩展
|
|
436
|
+
},
|
|
437
|
+
|
|
438
|
+
// 处理日期格式变化
|
|
439
|
+
handleDateFormatChange() {
|
|
440
|
+
// 可根据需要扩展
|
|
441
|
+
},
|
|
442
|
+
|
|
443
|
+
// 设置数据
|
|
337
444
|
setData(key, data) {
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
this
|
|
341
|
-
|
|
445
|
+
const item = this.findFormItem(key);
|
|
446
|
+
if (item) {
|
|
447
|
+
this.$set(item, "data", data);
|
|
448
|
+
}
|
|
342
449
|
},
|
|
450
|
+
|
|
451
|
+
// 设置值
|
|
343
452
|
setValue(key, value) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
item.modelVal = key[item.prop];
|
|
453
|
+
// 批量设置
|
|
454
|
+
if (typeof key === "object" && key !== null) {
|
|
455
|
+
Object.entries(key).forEach(([prop, val]) => {
|
|
456
|
+
const item = this.findFormItem(prop);
|
|
457
|
+
if (item) {
|
|
458
|
+
item.modelVal = val;
|
|
351
459
|
}
|
|
352
|
-
}
|
|
460
|
+
});
|
|
353
461
|
return;
|
|
354
462
|
}
|
|
355
463
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
this.$set(
|
|
360
|
-
}
|
|
361
|
-
},
|
|
362
|
-
onChangeCascader(val, item) {
|
|
363
|
-
const newArr = [...new Set(val.flat(Infinity))];
|
|
364
|
-
item.modelVal = newArr;
|
|
365
|
-
if (
|
|
366
|
-
item.options &&
|
|
367
|
-
item.options.change &&
|
|
368
|
-
typeof item.options.change === "function"
|
|
369
|
-
) {
|
|
370
|
-
item.options.change(newArr, val);
|
|
464
|
+
// 单个设置
|
|
465
|
+
const item = this.findFormItem(key);
|
|
466
|
+
if (item) {
|
|
467
|
+
this.$set(item, "modelVal", value);
|
|
371
468
|
}
|
|
372
469
|
},
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
470
|
+
|
|
471
|
+
// 查找表单项
|
|
472
|
+
findFormItem(key) {
|
|
473
|
+
return this.form.value?.find(
|
|
474
|
+
(item) =>
|
|
475
|
+
item.prop === key || item.label === key || item._internalId === key
|
|
476
|
+
);
|
|
378
477
|
},
|
|
379
478
|
},
|
|
380
479
|
};
|
|
381
480
|
</script>
|
|
382
|
-
|