stellar-ui-plus 1.24.20 → 1.24.22
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { watch, onMounted, computed, nextTick, onUnmounted
|
|
2
|
+
import { watch, onMounted, computed, nextTick, onUnmounted } from 'vue';
|
|
3
3
|
import { useColorStore } from '../../store/color';
|
|
4
4
|
let { getColor } = useColorStore();
|
|
5
5
|
import { formatDate, type DateType, type WeekType } from './date';
|
|
@@ -9,61 +9,22 @@ import useData from './useData';
|
|
|
9
9
|
import propsData from './props';
|
|
10
10
|
import { getCalendarData } from './date';
|
|
11
11
|
|
|
12
|
-
// 类型定义
|
|
13
|
-
interface CacheKey {
|
|
14
|
-
minDate: DateType;
|
|
15
|
-
maxDate: DateType;
|
|
16
|
-
viewDate: string;
|
|
17
|
-
monthCount: number;
|
|
18
|
-
formatter: string;
|
|
19
|
-
signs: string;
|
|
20
|
-
viewStart: DateType;
|
|
21
|
-
viewEnd: DateType;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 缓存相关
|
|
25
|
-
const cachedCalendarData = shallowRef<any>(null);
|
|
26
|
-
const lastCacheKey = ref<string>('');
|
|
27
|
-
|
|
28
|
-
// 定时器管理
|
|
29
|
-
let viewTimer: ReturnType<typeof setTimeout> | null = null;
|
|
30
|
-
let scrollTimer: ReturnType<typeof setTimeout> | null = null;
|
|
31
|
-
|
|
32
12
|
const props = defineProps(propsData);
|
|
33
13
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
monthCount: props.monthCount,
|
|
41
|
-
formatter: props.formatter,
|
|
42
|
-
signs: JSON.stringify(props.signs),
|
|
43
|
-
viewStart: props.viewStart,
|
|
44
|
-
viewEnd: props.viewEnd,
|
|
45
|
-
};
|
|
46
|
-
return JSON.stringify(cacheKey);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// 优化的计算属性 - 添加缓存机制
|
|
50
|
-
const cmpDates = computed(() => {
|
|
51
|
-
const currentKey = generateCacheKey();
|
|
52
|
-
|
|
53
|
-
if (currentKey !== lastCacheKey.value || !cachedCalendarData.value) {
|
|
54
|
-
cachedCalendarData.value = getCalendarData(props.minDate, props.maxDate, viewDate.value, props.monthCount, props.formatter, props.signs, props.viewStart, props.viewEnd);
|
|
55
|
-
lastCacheKey.value = currentKey;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return cachedCalendarData.value;
|
|
59
|
-
});
|
|
14
|
+
// 常量定义
|
|
15
|
+
const ROW_HEIGHT_WITH_SIGN = 180;
|
|
16
|
+
const ROW_HEIGHT_WITHOUT_SIGN = 126;
|
|
17
|
+
const MONTH_HEADER_HEIGHT = 80;
|
|
18
|
+
const VIEW_MONTH_DELAY = 50;
|
|
19
|
+
const SHOW_MONTH_DELAY = 100;
|
|
60
20
|
|
|
61
21
|
const cmpShowSigns = computed(() => {
|
|
62
22
|
return Object.keys(props.signs).length > 0;
|
|
63
23
|
});
|
|
24
|
+
const cmpDates = computed(() => getCalendarData(props.minDate, props.maxDate, viewDate.value, props.monthCount, props.formatter, props.signs, props.viewStart, props.viewEnd));
|
|
64
25
|
|
|
65
26
|
const cmpRootStyle = computed(() => {
|
|
66
|
-
const rowHeight = cmpShowSigns.value ? utils.formatPx(
|
|
27
|
+
const rowHeight = cmpShowSigns.value ? utils.formatPx(ROW_HEIGHT_WITH_SIGN, 'num') : utils.formatPx(ROW_HEIGHT_WITHOUT_SIGN, 'num');
|
|
67
28
|
const color = props.color ? props.color : getColor().steThemeColor;
|
|
68
29
|
return {
|
|
69
30
|
'--calendar-width': utils.formatPx(props.width),
|
|
@@ -89,7 +50,7 @@ const cmpMonthTops = computed(() => {
|
|
|
89
50
|
for (let i = 0; i < datas.length; i++) {
|
|
90
51
|
const month = datas[i];
|
|
91
52
|
tops[month.key] = { top: end };
|
|
92
|
-
end += utils.formatPx(
|
|
53
|
+
end += utils.formatPx(MONTH_HEADER_HEIGHT, 'num');
|
|
93
54
|
end += rowHeight * month.weeks.length;
|
|
94
55
|
tops[month.key].end = end;
|
|
95
56
|
}
|
|
@@ -106,49 +67,33 @@ const emits = defineEmits<{
|
|
|
106
67
|
(e: 'view-month', month: string): void;
|
|
107
68
|
}>();
|
|
108
69
|
|
|
109
|
-
|
|
110
|
-
const
|
|
70
|
+
let viewTimer: ReturnType<typeof setTimeout> | null = null;
|
|
71
|
+
const clearViewTimer = () => {
|
|
111
72
|
if (viewTimer) {
|
|
112
73
|
clearTimeout(viewTimer);
|
|
113
74
|
viewTimer = null;
|
|
114
75
|
}
|
|
115
|
-
if (scrollTimer) {
|
|
116
|
-
clearTimeout(scrollTimer);
|
|
117
|
-
scrollTimer = null;
|
|
118
|
-
}
|
|
119
76
|
};
|
|
120
77
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
setDataList([day.key]);
|
|
125
|
-
},
|
|
126
|
-
multiple: (day: WeekType) => {
|
|
127
|
-
const index = dataList.value.indexOf(day.key);
|
|
128
|
-
if (index === -1) {
|
|
129
|
-
if (props.maxCount && dataList.value.length >= (props.maxCount as number)) return;
|
|
130
|
-
dataList.value.push(day.key);
|
|
131
|
-
} else {
|
|
132
|
-
dataList.value.splice(index, 1);
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
range: (day: WeekType) => {
|
|
136
|
-
onRange(day);
|
|
137
|
-
},
|
|
138
|
-
};
|
|
78
|
+
onUnmounted(() => {
|
|
79
|
+
clearViewTimer();
|
|
80
|
+
});
|
|
139
81
|
|
|
140
82
|
const showMonth = (date?: DateType) => {
|
|
141
|
-
clearTimers();
|
|
142
83
|
const newDate: Dayjs = date ? utils.dayjs(date) : viewDate.value;
|
|
143
84
|
if (newDate.format('YYYY-MM-DD') !== viewDate.value.format('YYYY-MM-DD')) {
|
|
144
85
|
viewDate.value = newDate;
|
|
145
86
|
}
|
|
87
|
+
clearViewTimer();
|
|
146
88
|
viewTimer = setTimeout(() => {
|
|
147
|
-
// 如果显示的月份不在范围区间内,则显示范围区间的第一个月份或者最后一个月份
|
|
148
89
|
if (props.minDate && props.maxDate) {
|
|
149
|
-
|
|
90
|
+
const viewValue = utils.dayjs(viewDate.value).valueOf();
|
|
91
|
+
const minValue = utils.dayjs(props.minDate).valueOf();
|
|
92
|
+
const maxValue = utils.dayjs(props.maxDate).valueOf();
|
|
93
|
+
|
|
94
|
+
if (viewValue < minValue) {
|
|
150
95
|
viewDate.value = utils.dayjs(props.minDate);
|
|
151
|
-
} else if (
|
|
96
|
+
} else if (viewValue > maxValue) {
|
|
152
97
|
viewDate.value = utils.dayjs(props.maxDate);
|
|
153
98
|
}
|
|
154
99
|
}
|
|
@@ -157,7 +102,6 @@ const showMonth = (date?: DateType) => {
|
|
|
157
102
|
const top = tops[_viewMonth]?.top || 0;
|
|
158
103
|
if (top === undefined || scrollTop.value === top) {
|
|
159
104
|
initing.value = false;
|
|
160
|
-
viewTimer = null;
|
|
161
105
|
return;
|
|
162
106
|
}
|
|
163
107
|
contentScrollTop.value = scrollTop.value;
|
|
@@ -166,9 +110,8 @@ const showMonth = (date?: DateType) => {
|
|
|
166
110
|
scrollTop.value = top;
|
|
167
111
|
viewMonth.value = _viewMonth;
|
|
168
112
|
initing.value = false;
|
|
169
|
-
viewTimer = null;
|
|
170
113
|
});
|
|
171
|
-
},
|
|
114
|
+
}, VIEW_MONTH_DELAY);
|
|
172
115
|
};
|
|
173
116
|
|
|
174
117
|
const onMultiple = (day: WeekType) => {
|
|
@@ -186,12 +129,17 @@ const rangeDates = () => {
|
|
|
186
129
|
const start = formatDate(startDate.value);
|
|
187
130
|
const end = formatDate(endDate.value);
|
|
188
131
|
let list: (string | number)[] = [];
|
|
189
|
-
|
|
190
|
-
|
|
132
|
+
|
|
133
|
+
const startDateObj = new Date(start);
|
|
134
|
+
const endDateObj = new Date(end);
|
|
135
|
+
for (let i = startDateObj; i <= endDateObj; i.setDate(i.getDate() + 1)) {
|
|
136
|
+
list.push(formatDate(new Date(i), props.formatter));
|
|
191
137
|
}
|
|
138
|
+
|
|
192
139
|
if (list.length < 2) {
|
|
193
140
|
list = [startDate.value, endDate.value];
|
|
194
141
|
}
|
|
142
|
+
|
|
195
143
|
if (props.maxRange !== null && list.length > props.maxRange) {
|
|
196
144
|
setEndDate(null);
|
|
197
145
|
if (props.showRangePrompt) {
|
|
@@ -226,50 +174,41 @@ const onRange = (day: WeekType) => {
|
|
|
226
174
|
|
|
227
175
|
const onSelect = (day: WeekType) => {
|
|
228
176
|
if (props.readonly || !day.dayText || day.disabled) return;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
};
|
|
236
|
-
|
|
237
|
-
// 统一初始化逻辑
|
|
238
|
-
const initializeRangeMode = () => {
|
|
239
|
-
if (dataList.value.length >= 2) {
|
|
240
|
-
startDate.value = dataList.value[0];
|
|
241
|
-
endDate.value = dataList.value[dataList.value.length - 1];
|
|
242
|
-
} else if (dataList.value.length === 1) {
|
|
243
|
-
startDate.value = endDate.value = dataList.value[0];
|
|
244
|
-
} else {
|
|
245
|
-
startDate.value = endDate.value = null;
|
|
246
|
-
}
|
|
247
|
-
rangeDates();
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const initializeCalendar = () => {
|
|
251
|
-
// 初始化视图日期
|
|
252
|
-
viewDate.value = props.defaultDate ? utils.dayjs(props.defaultDate) : utils.dayjs();
|
|
253
|
-
|
|
254
|
-
// 初始化选中数据
|
|
255
|
-
dataList.value = (props.list || []).map(d => formatDate(d, props.formatter));
|
|
256
|
-
|
|
257
|
-
// 处理范围模式的特殊逻辑
|
|
258
|
-
if (props.mode === 'range') {
|
|
259
|
-
initializeRangeMode();
|
|
177
|
+
if (props.mode === 'single') {
|
|
178
|
+
setDataList([day.key]);
|
|
179
|
+
} else if (props.mode === 'multiple') {
|
|
180
|
+
onMultiple(day);
|
|
181
|
+
} else if (props.mode === 'range') {
|
|
182
|
+
onRange(day);
|
|
260
183
|
}
|
|
261
|
-
|
|
262
|
-
// 显示月份
|
|
263
|
-
nextTick(() => {
|
|
264
|
-
showMonth();
|
|
265
|
-
});
|
|
184
|
+
emits('select', dataList.value, day.key);
|
|
266
185
|
};
|
|
267
186
|
|
|
268
|
-
// 简化的watch逻辑
|
|
269
187
|
watch(
|
|
270
|
-
() =>
|
|
271
|
-
|
|
272
|
-
|
|
188
|
+
() => props.list,
|
|
189
|
+
v => {
|
|
190
|
+
dataList.value = (v || []).map(d => formatDate(d, props.formatter));
|
|
191
|
+
if (props.mode === 'range') {
|
|
192
|
+
if (dataList.value.length >= 2) {
|
|
193
|
+
startDate.value = dataList.value[0];
|
|
194
|
+
endDate.value = dataList.value[dataList.value.length - 1];
|
|
195
|
+
} else if (dataList.value.length === 1) {
|
|
196
|
+
startDate.value = dataList.value[0];
|
|
197
|
+
endDate.value = dataList.value[0];
|
|
198
|
+
} else {
|
|
199
|
+
startDate.value = null;
|
|
200
|
+
endDate.value = null;
|
|
201
|
+
}
|
|
202
|
+
rangeDates();
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
{ immediate: true }
|
|
206
|
+
);
|
|
207
|
+
watch(
|
|
208
|
+
() => props.defaultDate,
|
|
209
|
+
v => {
|
|
210
|
+
viewDate.value = v ? utils.dayjs(v) : utils.dayjs();
|
|
211
|
+
showMonth();
|
|
273
212
|
},
|
|
274
213
|
{ immediate: true }
|
|
275
214
|
);
|
|
@@ -277,43 +216,30 @@ watch(
|
|
|
277
216
|
const confirm = () => {
|
|
278
217
|
emits('confirm', dataList.value);
|
|
279
218
|
};
|
|
280
|
-
|
|
281
219
|
onMounted(() => {
|
|
282
|
-
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
// 组件销毁时清理资源
|
|
286
|
-
onUnmounted(() => {
|
|
287
|
-
clearTimers();
|
|
220
|
+
showMonth();
|
|
288
221
|
});
|
|
289
222
|
|
|
290
223
|
defineExpose({ showMonth });
|
|
291
|
-
|
|
292
224
|
const onShowMonth = (scrollTop: number) => {
|
|
293
|
-
|
|
294
|
-
|
|
225
|
+
clearViewTimer();
|
|
226
|
+
viewTimer = setTimeout(() => {
|
|
295
227
|
for (let month in cmpMonthTops.value) {
|
|
296
228
|
const { top = 0, end = 0 } = cmpMonthTops.value[month];
|
|
297
229
|
if (scrollTop >= top && scrollTop < end) {
|
|
298
|
-
if (viewMonth.value === month)
|
|
299
|
-
scrollTimer = null;
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
230
|
+
if (viewMonth.value === month) return;
|
|
302
231
|
viewMonth.value = month;
|
|
303
232
|
emits('view-month', month);
|
|
304
|
-
scrollTimer = null;
|
|
305
233
|
return;
|
|
306
234
|
}
|
|
307
235
|
}
|
|
308
|
-
},
|
|
236
|
+
}, SHOW_MONTH_DELAY);
|
|
309
237
|
};
|
|
310
|
-
|
|
311
238
|
const onScroll = (e: any) => {
|
|
312
239
|
scrollTop.value = e.detail.scrollTop;
|
|
313
240
|
onShowMonth(e.detail.scrollTop);
|
|
314
241
|
};
|
|
315
242
|
</script>
|
|
316
|
-
|
|
317
243
|
<template>
|
|
318
244
|
<view class="ste-calendar-root" :style="[cmpRootStyle, { opacity: initing ? 0 : 1 }]">
|
|
319
245
|
<view v-if="showTitle" class="calendar-title">{{ title }}</view>
|
|
@@ -92,7 +92,6 @@ const onSwitchChange = (e: SwiperOnChangeEvent) => {
|
|
|
92
92
|
setSwitchIndex(e.detail.current);
|
|
93
93
|
};
|
|
94
94
|
const onClick = () => {
|
|
95
|
-
if (props.disabled) return;
|
|
96
95
|
let searchValue = dataValue.value;
|
|
97
96
|
if (!searchValue && props.hotWords.length) {
|
|
98
97
|
searchValue = props.hotWords[switchIndex.value];
|