mao-mobile 0.0.1
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/ProDataPicker/README.md +123 -0
- package/ProDataPicker/index.vue +505 -0
- package/ProGoodsList/README.md +142 -0
- package/ProGoodsList/fonts/TCloudNumber-Regular.ttf +0 -0
- package/ProGoodsList/index.vue +278 -0
- package/ProOrderCard/README.md +77 -0
- package/ProOrderCard/fonts/TCloudNumber-Regular.ttf +0 -0
- package/ProOrderCard/index.vue +165 -0
- package/ProPlateKeyboard/README.md +86 -0
- package/ProPlateKeyboard/index.vue +510 -0
- package/ProPopup/README.md +131 -0
- package/ProPopup/index.vue +392 -0
- package/package.json +14 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# ProDataPicker 级联选择
|
|
2
|
+
|
|
3
|
+
一个级联选择组件,支持本地数据和远程数据加载。
|
|
4
|
+
|
|
5
|
+
## 功能特点
|
|
6
|
+
|
|
7
|
+
- 支持多级数据选择
|
|
8
|
+
- 支持本地数据和远程数据加载
|
|
9
|
+
- 自定义主题色
|
|
10
|
+
- 本地数据支持数据回显
|
|
11
|
+
- 支持自定义数据属性映射
|
|
12
|
+
- 支持禁用选项
|
|
13
|
+
- 支持空数据状态展示
|
|
14
|
+
|
|
15
|
+
## 基础用法
|
|
16
|
+
|
|
17
|
+
```vue
|
|
18
|
+
<template>
|
|
19
|
+
<pro-data-picker
|
|
20
|
+
v-model="selectedValues"
|
|
21
|
+
:localdata="localData"
|
|
22
|
+
@change="handleChange"
|
|
23
|
+
/>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup>
|
|
27
|
+
import { ref } from "vue";
|
|
28
|
+
|
|
29
|
+
const selectedValues = ref([]);
|
|
30
|
+
const localData = ref([
|
|
31
|
+
{
|
|
32
|
+
text: "选项1",
|
|
33
|
+
value: "1",
|
|
34
|
+
children: [
|
|
35
|
+
{
|
|
36
|
+
text: "选项1-1",
|
|
37
|
+
value: "1-1",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const handleChange = (value) => {
|
|
44
|
+
console.log("选择的值:", value);
|
|
45
|
+
};
|
|
46
|
+
</script>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 远程数据加载
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<template>
|
|
53
|
+
<pro-data-picker
|
|
54
|
+
v-model="selectedValues"
|
|
55
|
+
:level="3"
|
|
56
|
+
:lazyLoad="fetchData"
|
|
57
|
+
@change="handleChange"
|
|
58
|
+
/>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup>
|
|
62
|
+
import { ref } from "vue";
|
|
63
|
+
|
|
64
|
+
const selectedValues = ref([]);
|
|
65
|
+
|
|
66
|
+
const fetchData = async (level, parent) => {
|
|
67
|
+
// 根据层级和父级数据获取下一级数据
|
|
68
|
+
const response = await fetch(
|
|
69
|
+
`/api/data?level=${level}&parent=${parent?.value}`
|
|
70
|
+
);
|
|
71
|
+
return response.data;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const handleChange = (value) => {
|
|
75
|
+
console.log("选择的值:", value);
|
|
76
|
+
};
|
|
77
|
+
</script>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API
|
|
81
|
+
|
|
82
|
+
### Props
|
|
83
|
+
|
|
84
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
85
|
+
| ---------- | ------------------------ | -------- | --------- |
|
|
86
|
+
| modelValue | 选中的值(支持 v-model) | Array | [] |
|
|
87
|
+
| title | 弹出层标题 | String | '' |
|
|
88
|
+
| themeColor | 主题色 | String | '#0BC8C8' |
|
|
89
|
+
| localdata | 本地数据源 | Array | [] |
|
|
90
|
+
| dataprops | 数据属性映射 | Object | {} |
|
|
91
|
+
| level | 远程数据层级数 | Number | 3 |
|
|
92
|
+
| lazyLoad | 远程数据加载方法 | Function | null |
|
|
93
|
+
|
|
94
|
+
### dataprops 配置项
|
|
95
|
+
|
|
96
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
97
|
+
| -------------- | --------------- | ------ | ---------- |
|
|
98
|
+
| text | 选项文本字段名 | String | 'text' |
|
|
99
|
+
| value | 选项值字段名 | String | 'value' |
|
|
100
|
+
| children | 子选项字段名 | String | 'children' |
|
|
101
|
+
| remark | 备注字段名 | String | 'remark' |
|
|
102
|
+
| emptyText | 空数据提示文本 | String | '暂无数据' |
|
|
103
|
+
| `level${n}Tab` | 第 n 级标签文本 | String | '请选择' |
|
|
104
|
+
|
|
105
|
+
### Events
|
|
106
|
+
|
|
107
|
+
| 事件名 | 说明 | 回调参数 |
|
|
108
|
+
| ----------------- | ---------------- | -------------- |
|
|
109
|
+
| update:modelValue | 选中值变化时触发 | (value: Array) |
|
|
110
|
+
| change | 选择完成时触发 | (value: Array) |
|
|
111
|
+
|
|
112
|
+
### 方法
|
|
113
|
+
|
|
114
|
+
| 方法名 | 说明 | 参数 |
|
|
115
|
+
| ------ | ---------- | ---- |
|
|
116
|
+
| open | 打开选择器 | - |
|
|
117
|
+
|
|
118
|
+
## 注意事项
|
|
119
|
+
|
|
120
|
+
1. 使用本地数据时,需要提供符合数据结构的 `localdata` 数组
|
|
121
|
+
2. 使用远程数据时,需要提供 `lazyLoad` 方法来加载数据
|
|
122
|
+
3. 可以通过 `dataprops` 配置项来自定义数据字段的映射关系
|
|
123
|
+
4. 选择器的值格式为数组,每个元素包含 `name`、`value` 和 `flag` 属性
|
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view>
|
|
3
|
+
<pro-popup
|
|
4
|
+
ref="dataPickerPopupRef"
|
|
5
|
+
position="bottom"
|
|
6
|
+
:title="title"
|
|
7
|
+
:is-show-header="true"
|
|
8
|
+
@change="handlePopupChange"
|
|
9
|
+
>
|
|
10
|
+
<view class="pro-data-picker">
|
|
11
|
+
<view class="pro-data-picker__tabs">
|
|
12
|
+
<view
|
|
13
|
+
v-for="item in tabs"
|
|
14
|
+
:key="item.flag"
|
|
15
|
+
:class="[
|
|
16
|
+
'pro-data-picker__tab',
|
|
17
|
+
flag === item.flag
|
|
18
|
+
? 'pro-data-picker__tab--active'
|
|
19
|
+
: 'pro-data-picker__tab--default',
|
|
20
|
+
]"
|
|
21
|
+
@tap="handleTabClick(item)"
|
|
22
|
+
>
|
|
23
|
+
{{ item.name }}
|
|
24
|
+
<view v-if="flag === item.flag" class="pro-data-picker__tab-line" />
|
|
25
|
+
</view>
|
|
26
|
+
</view>
|
|
27
|
+
<view class="pro-data-picker__content">
|
|
28
|
+
<view v-if="currentList.length">
|
|
29
|
+
<view
|
|
30
|
+
v-for="item in currentList"
|
|
31
|
+
:key="getItemValue(item)"
|
|
32
|
+
:class="[
|
|
33
|
+
'pro-data-picker__item',
|
|
34
|
+
isSelected(item)
|
|
35
|
+
? 'pro-data-picker__item--active'
|
|
36
|
+
: 'pro-data-picker__item--default',
|
|
37
|
+
item.disable ? 'pro-data-picker__item--disabled' : '',
|
|
38
|
+
]"
|
|
39
|
+
@tap="!item.disable && handleItemClick(item)"
|
|
40
|
+
>
|
|
41
|
+
{{ getItemText(item) }}
|
|
42
|
+
<text v-if="isSelected(item)" class="pro-data-picker__item-check"
|
|
43
|
+
>✔</text
|
|
44
|
+
>
|
|
45
|
+
<text v-else class="pro-data-picker__item-remark">{{
|
|
46
|
+
getItemRemark(item)
|
|
47
|
+
}}</text>
|
|
48
|
+
</view>
|
|
49
|
+
</view>
|
|
50
|
+
<view
|
|
51
|
+
class="pro-data-picker__item-empty"
|
|
52
|
+
v-if="!currentList.length && !loading"
|
|
53
|
+
>
|
|
54
|
+
<image
|
|
55
|
+
class="pro-data-picker__item-empty-img"
|
|
56
|
+
mode="heightFix"
|
|
57
|
+
src="https://static.wxb.com.cn/frontEnd/images/ideacome-mobile/data-picker-empty.png"
|
|
58
|
+
></image>
|
|
59
|
+
<text class="pro-data-picker__item-empty-text">{{
|
|
60
|
+
mergeddataprops.emptyText
|
|
61
|
+
}}</text>
|
|
62
|
+
</view>
|
|
63
|
+
</view>
|
|
64
|
+
</view>
|
|
65
|
+
</pro-popup>
|
|
66
|
+
</view>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<script setup>
|
|
70
|
+
import { ref, computed } from "vue";
|
|
71
|
+
import ProPopup from "../ProPopup/index.vue";
|
|
72
|
+
|
|
73
|
+
const props = defineProps({
|
|
74
|
+
// 弹出层标题
|
|
75
|
+
title: {
|
|
76
|
+
type: String,
|
|
77
|
+
default: "",
|
|
78
|
+
},
|
|
79
|
+
// 默认选中的值
|
|
80
|
+
modelValue: {
|
|
81
|
+
type: Array,
|
|
82
|
+
default: () => [],
|
|
83
|
+
},
|
|
84
|
+
// 主题色
|
|
85
|
+
themeColor: {
|
|
86
|
+
type: String,
|
|
87
|
+
default: "#0BC8C8",
|
|
88
|
+
},
|
|
89
|
+
// 本地数据源
|
|
90
|
+
localdata: {
|
|
91
|
+
type: Array,
|
|
92
|
+
default: () => [],
|
|
93
|
+
},
|
|
94
|
+
// 数据属性映射
|
|
95
|
+
dataprops: {
|
|
96
|
+
type: Object,
|
|
97
|
+
default: () => ({}),
|
|
98
|
+
},
|
|
99
|
+
// 远程数据层级数
|
|
100
|
+
level: {
|
|
101
|
+
type: Number,
|
|
102
|
+
default: 3,
|
|
103
|
+
},
|
|
104
|
+
// 远程数据加载方法
|
|
105
|
+
lazyLoad: {
|
|
106
|
+
type: Function,
|
|
107
|
+
default: null,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
112
|
+
|
|
113
|
+
// 弹窗引用
|
|
114
|
+
const dataPickerPopupRef = ref(null);
|
|
115
|
+
// 当前选中的值
|
|
116
|
+
const selectedValues = ref([]);
|
|
117
|
+
// 当前激活的标签页
|
|
118
|
+
const flag = ref(0);
|
|
119
|
+
// 标签页配置
|
|
120
|
+
const tabs = ref([]);
|
|
121
|
+
// 数据列表
|
|
122
|
+
const dataList = ref([]);
|
|
123
|
+
const levelLists = ref([]);
|
|
124
|
+
const loading = ref(false);
|
|
125
|
+
|
|
126
|
+
// 合并后的数据属性映射
|
|
127
|
+
const mergeddataprops = computed(() => ({
|
|
128
|
+
text: "text",
|
|
129
|
+
value: "value",
|
|
130
|
+
children: "children",
|
|
131
|
+
remark: "remark",
|
|
132
|
+
emptyText: "暂无数据",
|
|
133
|
+
...props.dataprops,
|
|
134
|
+
}));
|
|
135
|
+
|
|
136
|
+
// 获取选项文本
|
|
137
|
+
const getItemText = (item) => item[mergeddataprops.value.text];
|
|
138
|
+
|
|
139
|
+
// 获取选项备注
|
|
140
|
+
const getItemRemark = (item) => item[mergeddataprops.value.remark];
|
|
141
|
+
|
|
142
|
+
// 获取选项值
|
|
143
|
+
const getItemValue = (item) => item[mergeddataprops.value.value];
|
|
144
|
+
|
|
145
|
+
// 获取子选项
|
|
146
|
+
const getItemChildren = (item) => item[mergeddataprops.value.children] || [];
|
|
147
|
+
|
|
148
|
+
// 当前显示的数据列表
|
|
149
|
+
const currentList = computed(() =>
|
|
150
|
+
props.localdata.length ? dataList.value : levelLists.value[flag.value] || []
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// 判断是否选中
|
|
154
|
+
const isSelected = (item) =>
|
|
155
|
+
selectedValues.value.some(
|
|
156
|
+
(val) => val.value === getItemValue(item) && val.flag === flag.value
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// 初始化标签页
|
|
160
|
+
const initTabs = () => {
|
|
161
|
+
const tabCount = props.localdata.length
|
|
162
|
+
? getMaxLevel(props.localdata)
|
|
163
|
+
: props.level;
|
|
164
|
+
tabs.value = Array.from({ length: tabCount }, (_, index) => ({
|
|
165
|
+
flag: index,
|
|
166
|
+
name: mergeddataprops.value[`level${index + 1}Tab`] || "请选择",
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
if (!props.localdata.length) {
|
|
170
|
+
levelLists.value = Array.from({ length: tabCount }, () => []);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// 获取最大层级
|
|
175
|
+
const getMaxLevel = (data, level = 1) => {
|
|
176
|
+
return Math.max(
|
|
177
|
+
level,
|
|
178
|
+
...data.map((item) => {
|
|
179
|
+
const children = getItemChildren(item);
|
|
180
|
+
return children.length ? getMaxLevel(children, level + 1) : level;
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// 更新标签页名称
|
|
186
|
+
const updateTabNames = () => {
|
|
187
|
+
tabs.value = tabs.value.map((tab, index) => {
|
|
188
|
+
const selected = selectedValues.value.find((val) => val.flag === index);
|
|
189
|
+
return {
|
|
190
|
+
...tab,
|
|
191
|
+
name: selected
|
|
192
|
+
? selected.name
|
|
193
|
+
: mergeddataprops.value[`level${index + 1}Tab`] || "请选择",
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// 处理选项点击
|
|
199
|
+
const handleItemClick = (item) => {
|
|
200
|
+
const currentFlag = flag.value;
|
|
201
|
+
const newValue = {
|
|
202
|
+
name: getItemText(item),
|
|
203
|
+
value: getItemValue(item),
|
|
204
|
+
flag: currentFlag,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const index = selectedValues.value.findIndex(
|
|
208
|
+
(val) => val.flag === currentFlag
|
|
209
|
+
);
|
|
210
|
+
if (index > -1) {
|
|
211
|
+
selectedValues.value[index] = newValue;
|
|
212
|
+
} else {
|
|
213
|
+
selectedValues.value.push(newValue);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 清空下级选择
|
|
217
|
+
selectedValues.value = selectedValues.value.filter(
|
|
218
|
+
(val) => val.flag <= currentFlag
|
|
219
|
+
);
|
|
220
|
+
updateTabNames();
|
|
221
|
+
|
|
222
|
+
// 判断是否需要加载下一级数据
|
|
223
|
+
if (currentFlag < tabs.value.length - 1) {
|
|
224
|
+
if (props.localdata.length) {
|
|
225
|
+
const children = getItemChildren(item);
|
|
226
|
+
if (children.length) {
|
|
227
|
+
dataList.value = children;
|
|
228
|
+
flag.value++;
|
|
229
|
+
} else {
|
|
230
|
+
completeSelection();
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
fetchRegionList(item);
|
|
234
|
+
flag.value++;
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
completeSelection();
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// 完成选择
|
|
242
|
+
const completeSelection = () => {
|
|
243
|
+
emit("update:modelValue", selectedValues.value);
|
|
244
|
+
emit("change", selectedValues.value);
|
|
245
|
+
handleClose();
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const resetState = () => {
|
|
249
|
+
// 使用setTimeout等待动画结束后再重置数据
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
selectedValues.value = [];
|
|
252
|
+
dataList.value = [];
|
|
253
|
+
levelLists.value = [];
|
|
254
|
+
flag.value = 0;
|
|
255
|
+
tabs.value = [];
|
|
256
|
+
loading.value = false;
|
|
257
|
+
}, 300);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// 关闭弹窗
|
|
261
|
+
const handleClose = () => {
|
|
262
|
+
dataPickerPopupRef.value.close();
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// 打开弹窗
|
|
266
|
+
const open = () => {
|
|
267
|
+
initTabs();
|
|
268
|
+
|
|
269
|
+
if (props.localdata.length) {
|
|
270
|
+
// 使用本地数据
|
|
271
|
+
dataList.value = props.localdata;
|
|
272
|
+
|
|
273
|
+
// 如果有 modelValue,进行回显处理
|
|
274
|
+
if (props.modelValue && props.modelValue.length) {
|
|
275
|
+
selectedValues.value = [...props.modelValue];
|
|
276
|
+
|
|
277
|
+
// 更新标签页名称
|
|
278
|
+
tabs.value = tabs.value.map((tab, index) => {
|
|
279
|
+
const selected = props.modelValue.find((val) => val.flag === index);
|
|
280
|
+
return {
|
|
281
|
+
...tab,
|
|
282
|
+
name: selected
|
|
283
|
+
? selected.name
|
|
284
|
+
: mergeddataprops.value[`level${index + 1}Tab`] || "请选择",
|
|
285
|
+
};
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// 设置当前显示的数据列表和 flag
|
|
289
|
+
let currentData = props.localdata;
|
|
290
|
+
let lastFlag = 0;
|
|
291
|
+
|
|
292
|
+
// 遍历已选择的值,找到对应的数据层级
|
|
293
|
+
for (let i = 0; i < props.modelValue.length; i++) {
|
|
294
|
+
const selected = props.modelValue[i];
|
|
295
|
+
const found = currentData.find(
|
|
296
|
+
(item) => getItemValue(item) === selected.value
|
|
297
|
+
);
|
|
298
|
+
if (found) {
|
|
299
|
+
lastFlag = i;
|
|
300
|
+
if (i === props.modelValue.length - 1) {
|
|
301
|
+
// 如果是最后一级,显示当前数据
|
|
302
|
+
dataList.value = currentData;
|
|
303
|
+
} else {
|
|
304
|
+
// 否则继续查找下一级
|
|
305
|
+
currentData = getItemChildren(found);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// 设置 flag 到最后一级
|
|
311
|
+
flag.value = lastFlag;
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
// 使用接口数据
|
|
315
|
+
flag.value = 0;
|
|
316
|
+
selectedValues.value = [];
|
|
317
|
+
fetchRegionList();
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
dataPickerPopupRef.value.open();
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// 获取地区数据
|
|
324
|
+
const fetchRegionList = async (item) => {
|
|
325
|
+
if (!props.lazyLoad) {
|
|
326
|
+
console.error("未提供数据加载方法");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
try {
|
|
331
|
+
loading.value = true;
|
|
332
|
+
const list = await props.lazyLoad(flag.value, item);
|
|
333
|
+
loading.value = false;
|
|
334
|
+
levelLists.value[flag.value] = list;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error("获取数据失败:", error);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
// 处理标签页点击
|
|
341
|
+
const handleTabClick = (item) => {
|
|
342
|
+
if (item.flag === 0) {
|
|
343
|
+
flag.value = item.flag;
|
|
344
|
+
if (props.localdata.length) {
|
|
345
|
+
dataList.value = props.localdata;
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const prevSelected = selectedValues.value.find(
|
|
351
|
+
(val) => val.flag === item.flag - 1
|
|
352
|
+
);
|
|
353
|
+
if (prevSelected) {
|
|
354
|
+
if (props.localdata.length) {
|
|
355
|
+
// 获取上一级选中项的children作为当前列表
|
|
356
|
+
const prevItem = findItemByValue(prevSelected.value);
|
|
357
|
+
if (prevItem?.child.length) {
|
|
358
|
+
flag.value = item.flag;
|
|
359
|
+
dataList.value = getItemChildren(prevItem);
|
|
360
|
+
} else {
|
|
361
|
+
uni.showToast({
|
|
362
|
+
title: "当前项没有下级",
|
|
363
|
+
icon: "none",
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
flag.value = item.flag;
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
uni.showToast({
|
|
371
|
+
title: "请先选择上一级",
|
|
372
|
+
icon: "none",
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// 根据值查找选项
|
|
378
|
+
const findItemByValue = (value, list = props.localdata) => {
|
|
379
|
+
for (const item of list) {
|
|
380
|
+
if (getItemValue(item) === value) {
|
|
381
|
+
return item;
|
|
382
|
+
}
|
|
383
|
+
const children = getItemChildren(item);
|
|
384
|
+
if (children.length) {
|
|
385
|
+
const found = findItemByValue(value, children);
|
|
386
|
+
if (found) return found;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return null;
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// 处理弹窗状态变化
|
|
393
|
+
const handlePopupChange = (e) => {
|
|
394
|
+
if (!e.show) {
|
|
395
|
+
resetState();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
defineExpose({
|
|
400
|
+
open,
|
|
401
|
+
});
|
|
402
|
+
</script>
|
|
403
|
+
|
|
404
|
+
<style lang="scss" scoped>
|
|
405
|
+
.pro-data-picker {
|
|
406
|
+
font-family: PingFang SC, sans-serif;
|
|
407
|
+
height: calc(100vh * 0.618 - 174rpx);
|
|
408
|
+
display: flex;
|
|
409
|
+
flex-direction: column;
|
|
410
|
+
box-sizing: border-box;
|
|
411
|
+
overflow: hidden;
|
|
412
|
+
|
|
413
|
+
&__tabs {
|
|
414
|
+
flex-shrink: 0;
|
|
415
|
+
padding: 0 8rpx;
|
|
416
|
+
height: 60rpx;
|
|
417
|
+
display: flex;
|
|
418
|
+
align-items: center;
|
|
419
|
+
justify-content: space-between;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
&__tab {
|
|
423
|
+
flex: 1;
|
|
424
|
+
position: relative;
|
|
425
|
+
padding: 0 4rpx 24rpx 4rpx;
|
|
426
|
+
font-size: 26rpx;
|
|
427
|
+
line-height: 36rpx;
|
|
428
|
+
text-align: center;
|
|
429
|
+
text-overflow: ellipsis;
|
|
430
|
+
white-space: nowrap;
|
|
431
|
+
overflow: hidden;
|
|
432
|
+
|
|
433
|
+
&--active {
|
|
434
|
+
font-weight: 500;
|
|
435
|
+
color: v-bind("themeColor");
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
&--default {
|
|
439
|
+
color: #666;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
&__tab-line {
|
|
444
|
+
position: absolute;
|
|
445
|
+
bottom: 0;
|
|
446
|
+
left: 50%;
|
|
447
|
+
transform: translateX(-50%);
|
|
448
|
+
width: 116rpx;
|
|
449
|
+
height: 6rpx;
|
|
450
|
+
background: v-bind("themeColor");
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
&__content {
|
|
454
|
+
flex: 1;
|
|
455
|
+
margin-top: 32rpx;
|
|
456
|
+
padding: 0 12rpx;
|
|
457
|
+
overflow-y: auto;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
&__item {
|
|
461
|
+
display: flex;
|
|
462
|
+
justify-content: space-between;
|
|
463
|
+
align-items: center;
|
|
464
|
+
padding: 24rpx 0;
|
|
465
|
+
font-size: 28rpx;
|
|
466
|
+
line-height: 40rpx;
|
|
467
|
+
|
|
468
|
+
&--active {
|
|
469
|
+
color: v-bind("themeColor");
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
&--default {
|
|
473
|
+
color: #212121;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
&--disabled {
|
|
477
|
+
color: #888;
|
|
478
|
+
cursor: not-allowed;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
&-check {
|
|
482
|
+
color: v-bind("themeColor");
|
|
483
|
+
}
|
|
484
|
+
&-empty {
|
|
485
|
+
padding-top: 114rpx;
|
|
486
|
+
display: flex;
|
|
487
|
+
flex-direction: column;
|
|
488
|
+
align-items: center;
|
|
489
|
+
&-img {
|
|
490
|
+
height: 180rpx;
|
|
491
|
+
}
|
|
492
|
+
&-text {
|
|
493
|
+
margin-top: 18rpx;
|
|
494
|
+
font-size: 32rpx;
|
|
495
|
+
color: #666666;
|
|
496
|
+
line-height: 44rpx;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
&__item-remark {
|
|
502
|
+
color: #888888;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
</style>
|