wl-design-mobile 0.7.2 → 0.7.4

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # wl-design-mobile
2
-
3
- ## Setup
4
- ```
5
- npm i wl-design-mobile
6
- ```
1
+ # wl-design-mobile
2
+
3
+ ## Setup
4
+ ```
5
+ npm i wl-design-mobile
6
+ ```
@@ -1,3 +1,3 @@
1
- .img-upload-container {
2
- padding: 0px 14px 12px 14px;
3
- }
1
+ .img-upload-container {
2
+ padding: 0px 14px 12px 14px;
3
+ }
@@ -1,39 +1,39 @@
1
- .coll-div {
2
- margin-bottom: 8px;
3
- }
4
-
5
- .indicator-title {
6
- display: flex;
7
- align-items: center;
8
- color: var(--scl-blue);
9
- font-size: 14px;
10
- font-family: 微软雅黑, serif Regular;
11
- }
12
-
13
- .indicator-title .color-line {
14
- width: 3px;
15
- height: 14px;
16
- margin-right: 8px;
17
- }
18
-
19
- .coll-title-icon {
20
- justify-content: center;
21
- align-items: center;
22
- align-content: center;
23
- }
24
-
25
- /* 覆盖折叠面板的标题的padding */
26
- /deep/ .van-cell {
27
- padding: 12px 10px;
28
- }
29
-
30
- /* 覆盖去掉折叠面板的标题下面的线 */
31
- /deep/ .van-cell::after {
32
- border: none;
33
- }
34
-
35
- /* 覆盖折叠面板的内容的padding */
36
- /deep/ .van-collapse-item__content {
37
- padding: 0px 0px 0px 0px;
38
- }
39
-
1
+ .coll-div {
2
+ margin-bottom: 8px;
3
+ }
4
+
5
+ .indicator-title {
6
+ display: flex;
7
+ align-items: center;
8
+ color: var(--scl-blue);
9
+ font-size: 14px;
10
+ font-family: 微软雅黑, serif Regular;
11
+ }
12
+
13
+ .indicator-title .color-line {
14
+ width: 3px;
15
+ height: 14px;
16
+ margin-right: 8px;
17
+ }
18
+
19
+ .coll-title-icon {
20
+ justify-content: center;
21
+ align-items: center;
22
+ align-content: center;
23
+ }
24
+
25
+ /* 覆盖折叠面板的标题的padding */
26
+ /deep/ .van-cell {
27
+ padding: 12px 10px;
28
+ }
29
+
30
+ /* 覆盖去掉折叠面板的标题下面的线 */
31
+ /deep/ .van-cell::after {
32
+ border: none;
33
+ }
34
+
35
+ /* 覆盖折叠面板的内容的padding */
36
+ /deep/ .van-collapse-item__content {
37
+ padding: 0px 0px 0px 0px;
38
+ }
39
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wl-design-mobile",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "finch",
@@ -0,0 +1,522 @@
1
+ <template>
2
+ <div class="week-date-picker" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"
3
+ @mousedown="handleMouseDown" @mousemove="handleMouseMove" @mouseup="handleMouseUp" @mouseleave="handleMouseLeave">
4
+ <div class="week-days">
5
+ <van-icon name="arrow-left" @click="goPrevWeek" />
6
+ <div v-for="day in weekDays" :key="day.date.getTime()" class="day-item"
7
+ :class="{
8
+ 'today': day.isToday,
9
+ 'active': day.isSelected,
10
+ 'has-data': day.hasData
11
+ }"
12
+ @click="selectDay(day)">
13
+ <div class="day-week">{{ day.weekDay }}</div>
14
+ <div class="day-month">{{ day.year }}-{{ day.month }}</div>
15
+ <div class="day-date">{{ day.date.getDate() }}</div>
16
+ <!-- 数据点显示 -->
17
+ <div v-if="day.hasData" class="data-dot"></div>
18
+ </div>
19
+ <van-icon name="arrow" @click="goNextWeek" />
20
+ </div>
21
+ </div>
22
+ </template>
23
+
24
+ <script>
25
+ const WEEK_DAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
26
+
27
+ export default {
28
+ name: "LamboWeekDateSelect",
29
+
30
+ data() {
31
+ return {
32
+ selectedDate_: new Date(), // 当前选中的日期(Date对象),用于判断选中状态
33
+ weekStart: null, // 当前周的开始日期(周一)
34
+ startX: 0, // 触摸/鼠标起始X坐标
35
+ endX: 0, // 触摸/鼠标结束X坐标
36
+ isDragging: false, // 是否正在拖动
37
+ swipeThreshold: 50, // 滑动阈值(像素),超过这个值才触发切换周
38
+ clickDisabled: false, // 是否禁用点击(滑动后禁用点击,避免触发日期选择)
39
+ dataDates: new Set() // 有数据的日期集合(用于显示红点)
40
+ }
41
+ },
42
+ props: {
43
+ // 选中的日期(格式:yyyyMMDD),为空时使用今天
44
+ selectedDate: {
45
+ type: String,
46
+ default: ""
47
+ },
48
+ // 有数据的日期列表
49
+ dataDatesList: {
50
+ type: Array,
51
+ default: () => []
52
+ }
53
+ },
54
+
55
+ created() {
56
+ // 初始化数据日期
57
+ this.initDataDates();
58
+
59
+ if (this.selectedDate) {
60
+ this.initWithWeekDate(this.selectedDate);
61
+ } else {
62
+ const today = new Date();
63
+ const todayStr = this.formatDateToYYYYMMDD(today);
64
+ this.initWithWeekDate(todayStr);
65
+ }
66
+ },
67
+
68
+ watch: {
69
+ // 监听数据日期列表变化
70
+ dataDatesList: {
71
+ handler(newList) {
72
+ this.initDataDates(newList);
73
+ // 重新计算weekDays以更新数据点显示
74
+ this.$forceUpdate();
75
+ },
76
+ deep: true
77
+ },
78
+ // 监听选中日期变化
79
+ selectedDate: {
80
+ handler(newDate) {
81
+ if (newDate) {
82
+ this.initWithWeekDate(newDate);
83
+ this.$forceUpdate();
84
+ }
85
+ }
86
+ }
87
+ },
88
+
89
+ computed: {
90
+ weekDays() {
91
+ if (!this.weekStart) return [];
92
+ return Array.from({ length: 7 }, (_, i) => {
93
+ const date = new Date(this.weekStart);
94
+ date.setDate(this.weekStart.getDate() + i);
95
+ const today = new Date();
96
+ const dateStr = this.formatDateToYYYYMMDD(date);
97
+
98
+ return {
99
+ date,
100
+ year: date.getFullYear(),
101
+ month: date.getMonth() + 1,
102
+ weekDay: WEEK_DAYS[date.getDay()],
103
+ isToday: this.isSameDay(date, today),
104
+ isSelected: this.isSameDay(date, this.selectedDate_),
105
+ hasData: this.dataDates.has(dateStr)
106
+ };
107
+ });
108
+ }
109
+ },
110
+
111
+ methods: {
112
+ /**
113
+ * 获取当前周的开始和结束日期
114
+ * @returns {Object} 包含 weekStart 和 weekEnd 的对象
115
+ */
116
+ getWeekRange() {
117
+ const weekStartDate = this.formatDateToYYYYMMDD(this.weekStart);
118
+ const weekEndDateObj = new Date(this.weekStart);
119
+ weekEndDateObj.setDate(this.weekStart.getDate() + 6);
120
+ const weekEndDate = this.formatDateToYYYYMMDD(weekEndDateObj);
121
+
122
+ return {
123
+ weekStart: weekStartDate,
124
+ weekEnd: weekEndDate
125
+ };
126
+ },
127
+
128
+ /**
129
+ * 初始化数据日期集合
130
+ * @param {Array} dateList - 日期字符串数组,格式:["20241205", "20241206"]
131
+ */
132
+ initDataDates(dateList = null) {
133
+ const dates = dateList || this.dataDatesList;
134
+ this.dataDates = new Set();
135
+
136
+ dates.forEach(dateStr => {
137
+ if (dateStr && typeof dateStr === 'string' && dateStr.length === 8) {
138
+ this.dataDates.add(dateStr);
139
+ }
140
+ })
141
+ },
142
+
143
+ /**
144
+ * 根据YYYYMMDD格式的字符串初始化组件
145
+ * @param {string} dateFormat- 格式如:"20251205"
146
+ */
147
+ initWithWeekDate(dateFormat) {
148
+ // 解析YYYYMMDD格式字符串为Date对象
149
+ const date = this.parseYYYYMMDD(dateFormat);
150
+
151
+ if (date) {
152
+ this.setWeekStart(date);
153
+ this.selectedDate_ = date;
154
+ } else {
155
+ const today = new Date();
156
+ this.setWeekStart(today);
157
+ this.selectedDate_ = today;
158
+ }
159
+ },
160
+
161
+ /**
162
+ * 解析YYYYMMDD格式字符串为Date对象
163
+ * @param {string} yyyymmdd - 格式如:"20251205"
164
+ * @returns {Date|null} Date对象或null
165
+ */
166
+ parseYYYYMMDD(dateFormat) {
167
+ if (!dateFormat || typeof dateFormat !== 'string' || dateFormat.length !== 8) {
168
+ return null;
169
+ }
170
+
171
+ try {
172
+ const year = parseInt(dateFormat.substring(0, 4));
173
+ const month = parseInt(dateFormat.substring(4, 6)) - 1;
174
+ const day = parseInt(dateFormat.substring(6, 8));
175
+
176
+ const date = new Date(year, month, day);
177
+
178
+ // 验证日期是否有效
179
+ if (isNaN(date.getTime()) ||
180
+ date.getFullYear() !== year ||
181
+ date.getMonth() !== month ||
182
+ date.getDate() !== day) {
183
+ return null;
184
+ }
185
+
186
+ return date;
187
+ } catch (error) {
188
+ console.error("日期解析错误:", error);
189
+ return null;
190
+ }
191
+ },
192
+
193
+ /**
194
+ * 设置周起始日期(周一)
195
+ * @param {Date} date - 任意日期
196
+ */
197
+ setWeekStart(date) {
198
+ const d = new Date(date);
199
+ const day = d.getDay();
200
+ const diff = d.getDate() - (day === 0 ? 6 : day - 1);
201
+ d.setDate(diff);
202
+ d.setHours(0, 0, 0, 0);
203
+ this.weekStart = d;
204
+ },
205
+
206
+ /**
207
+ * 判断两个日期是否是同一天
208
+ * @param {Date} d1 - 日期1
209
+ * @param {Date} d2 - 日期2
210
+ * @returns {boolean} 是否是同一天
211
+ */
212
+ isSameDay(d1, d2) {
213
+ if (!d1 || !d2) return false;
214
+ return d1.toDateString() === d2.toDateString();
215
+ },
216
+
217
+ /**
218
+ * 格式化日期为 YYYYMMDD 字符串
219
+ * @param {Date} date - 日期对象
220
+ * @returns {string} 格式化后的日期字符串
221
+ */
222
+ formatDateToYYYYMMDD(date) {
223
+ const year = date.getFullYear();
224
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
225
+ const day = date.getDate().toString().padStart(2, '0');
226
+ return `${year}${month}${day}`;
227
+ },
228
+
229
+ /**
230
+ * 选择日期
231
+ * @param {Object} day - 日期对象(包含 date 属性)
232
+ */
233
+ selectDay(day) {
234
+ if (this.clickDisabled) {
235
+ this.clickDisabled = false;
236
+ return;
237
+ }
238
+ this.selectedDate_ = new Date(day.date);
239
+ const clickDate = this.formatDateToYYYYMMDD(this.selectedDate_);
240
+ this.$emit('click', clickDate);
241
+ },
242
+
243
+ /**
244
+ * 切换到上一周
245
+ */
246
+ goPrevWeek() {
247
+ const newWeekStart = new Date(this.weekStart);
248
+ newWeekStart.setDate(this.weekStart.getDate() - 7);
249
+ this.setWeekStart(newWeekStart);
250
+ this.emitWeekChange();
251
+ },
252
+
253
+ /**
254
+ * 切换到下一周
255
+ */
256
+ goNextWeek() {
257
+ const newWeekStart = new Date(this.weekStart);
258
+ newWeekStart.setDate(this.weekStart.getDate() + 7);
259
+ this.setWeekStart(newWeekStart);
260
+ this.emitWeekChange();
261
+ },
262
+
263
+ /**
264
+ * 触发周变化事件
265
+ */
266
+ emitWeekChange() {
267
+ const weekRange = this.getWeekRange();
268
+ this.$emit('on-week-change', weekRange);
269
+ },
270
+
271
+ /**
272
+ * 触摸开始事件
273
+ * @param {TouchEvent} e - 触摸事件
274
+ */
275
+ handleTouchStart(e) {
276
+ this.startX = e.touches[0].clientX;
277
+ this.endX = this.startX;
278
+ this.isDragging = true;
279
+ this.clickDisabled = false;
280
+ },
281
+
282
+ /**
283
+ * 触摸移动事件
284
+ * @param {TouchEvent} e - 触摸事件
285
+ */
286
+ handleTouchMove(e) {
287
+ if (!this.isDragging) return;
288
+ this.endX = e.touches[0].clientX;
289
+ },
290
+
291
+ /**
292
+ * 触摸结束事件
293
+ */
294
+ handleTouchEnd() {
295
+ if (!this.isDragging) return;
296
+
297
+ const deltaX = this.endX - this.startX;
298
+ this.handleSwipe(deltaX);
299
+
300
+ this.isDragging = false;
301
+ },
302
+
303
+ /**
304
+ * 鼠标按下事件
305
+ * @param {MouseEvent} e - 鼠标事件
306
+ */
307
+ handleMouseDown(e) {
308
+ this.startX = e.clientX;
309
+ this.endX = this.startX;
310
+ this.isDragging = true;
311
+ this.clickDisabled = false;
312
+ },
313
+
314
+ /**
315
+ * 鼠标移动事件
316
+ * @param {MouseEvent} e - 鼠标事件
317
+ */
318
+ handleMouseMove(e) {
319
+ if (!this.isDragging) return;
320
+ this.endX = e.clientX;
321
+ },
322
+
323
+ /**
324
+ * 鼠标松开事件
325
+ */
326
+ handleMouseUp() {
327
+ if (!this.isDragging) return;
328
+
329
+ const deltaX = this.endX - this.startX;
330
+ this.handleSwipe(deltaX);
331
+
332
+ this.isDragging = false;
333
+ },
334
+
335
+ /**
336
+ * 鼠标离开事件
337
+ */
338
+ handleMouseLeave() {
339
+ this.isDragging = false;
340
+ },
341
+
342
+ /**
343
+ * 处理滑动操作
344
+ * @param {number} deltaX - 滑动距离(正值向左滑,负值向右滑)
345
+ */
346
+ handleSwipe(deltaX) {
347
+ if (Math.abs(deltaX) > this.swipeThreshold) {
348
+ this.clickDisabled = true;
349
+ if (deltaX > 0) {
350
+ this.goPrevWeek();
351
+ } else {
352
+ this.goNextWeek();
353
+ }
354
+ }
355
+ },
356
+
357
+ /**
358
+ * 手动添加/移除数据日期(供外部调用)
359
+ * @param {string} dateStr - YYYYMMDD格式的日期字符串
360
+ * @param {boolean} hasData - 是否有数据
361
+ */
362
+ setDateHasData(dateStr, hasData = true) {
363
+ if (hasData) {
364
+ this.dataDates.add(dateStr);
365
+ } else {
366
+ this.dataDates.delete(dateStr);
367
+ }
368
+ this.$forceUpdate();
369
+ }
370
+ }
371
+ }
372
+ </script>
373
+
374
+ <style scoped>
375
+ .week-date-picker {
376
+ width: 100%;
377
+ background: white;
378
+ padding: 10px 0;
379
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
380
+ user-select: none;
381
+ border-radius: 8px;
382
+ overflow: hidden;
383
+ cursor: grab;
384
+ }
385
+
386
+ .week-date-picker:active {
387
+ cursor: grabbing;
388
+ }
389
+
390
+ .week-days {
391
+ display: flex;
392
+ justify-content: space-around;
393
+ align-items: center;
394
+ padding: 0 8px;
395
+ }
396
+
397
+ .day-item {
398
+ display: flex;
399
+ flex-direction: column;
400
+ align-items: center;
401
+ justify-content: center;
402
+ width: 44px;
403
+ height: 64px;
404
+ border-radius: 8px;
405
+ cursor: pointer;
406
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
407
+ position: relative;
408
+ flex-shrink: 0;
409
+ }
410
+
411
+ /* 今天日期的浅蓝色背景 */
412
+ .day-item.today {
413
+ background-color: #e6efff;
414
+ }
415
+
416
+ .day-item:hover {
417
+ background-color: #f5f5f5;
418
+ transform: translateY(-2px);
419
+ }
420
+
421
+ .day-item.today:hover {
422
+ background-color: #b0d2f9;
423
+ }
424
+
425
+ .day-item.active {
426
+ background-color: #0070D2;
427
+ box-shadow: 0 4px 12px rgba(22, 119, 255, 0.3);
428
+ transform: translateY(-2px);
429
+ }
430
+
431
+ .day-item.active .day-week,
432
+ .day-item.active .day-month,
433
+ .day-item.active .day-date {
434
+ color: white;
435
+ }
436
+
437
+ .day-week {
438
+ font-size: 12px;
439
+ color: #666;
440
+ margin-bottom: 4px;
441
+ }
442
+
443
+ .day-month {
444
+ font-size: 10px;
445
+ color: #999;
446
+ margin-bottom: 2px;
447
+ }
448
+
449
+ .day-date {
450
+ font-size: 17px;
451
+ font-weight: 500;
452
+ color: #333;
453
+ }
454
+
455
+ /* 今天日期的文字颜色 */
456
+ .day-item.today .day-week,
457
+ .day-item.today .day-month,
458
+ .day-item.today .day-date {
459
+ color: #2c3e50;
460
+ font-weight: 500;
461
+ }
462
+
463
+ /* 数据点样式 - 统一大小和颜色 */
464
+ .data-dot {
465
+ position: absolute;
466
+ bottom: -4px;
467
+ width: 5px;
468
+ height: 5px;
469
+ background-color: #129456;
470
+ border-radius: 50%;
471
+ animation: fadeIn 0.3s ease;
472
+ }
473
+
474
+ /* 选中状态下的数据点 - 统一为白色 */
475
+ .day-item.active .data-dot {
476
+ background-color: white;
477
+ box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
478
+ }
479
+
480
+ /* 淡入动画 */
481
+ @keyframes fadeIn {
482
+ from {
483
+ opacity: 0;
484
+ transform: scale(0.5);
485
+ }
486
+ to {
487
+ opacity: 1;
488
+ transform: scale(1);
489
+ }
490
+ }
491
+
492
+ /* 今天且有数据时的特殊样式 */
493
+ .day-item.today.has-data {
494
+ border: 1px solid #CBE2FB;
495
+ }
496
+
497
+ /* 移动端优化 */
498
+ @media (max-width: 375px) {
499
+ .day-item {
500
+ width: 40px;
501
+ height: 60px;
502
+ }
503
+
504
+ .day-date {
505
+ font-size: 16px;
506
+ }
507
+
508
+ .day-week {
509
+ font-size: 11px;
510
+ }
511
+
512
+ .day-month {
513
+ font-size: 9px;
514
+ }
515
+
516
+ .data-dot {
517
+ width: 4px;
518
+ height: 4px;
519
+ bottom: -3px;
520
+ }
521
+ }
522
+ </style>
package/util/assist.js CHANGED
@@ -1,43 +1,43 @@
1
- // 深拷贝
2
- export function deepCopy(data) {
3
- let i;
4
- const t = typeOf(data);
5
- let o;
6
-
7
- if (t === 'array') {
8
- o = [];
9
- } else if (t === 'object') {
10
- o = {};
11
- } else {
12
- return data;
13
- }
14
-
15
- if (t === 'array') {
16
- for (i = 0; i < data.length; i++) {
17
- o.push(deepCopy(data[i]));
18
- }
19
- } else if (t === 'object') {
20
- for (i in data) {
21
- o[i] = deepCopy(data[i]);
22
- }
23
- }
24
- return o;
25
- }
26
-
27
- // 判断对象类型
28
- export function typeOf(obj) {
29
- const toString = Object.prototype.toString;
30
- const map = {
31
- '[object Boolean]': 'boolean',
32
- '[object Number]': 'number',
33
- '[object String]': 'string',
34
- '[object Function]': 'function',
35
- '[object Array]': 'array',
36
- '[object Date]': 'date',
37
- '[object RegExp]': 'regExp',
38
- '[object Undefined]': 'undefined',
39
- '[object Null]': 'null',
40
- '[object Object]': 'object'
41
- };
42
- return map[toString.call(obj)];
43
- }
1
+ // 深拷贝
2
+ export function deepCopy(data) {
3
+ let i;
4
+ const t = typeOf(data);
5
+ let o;
6
+
7
+ if (t === 'array') {
8
+ o = [];
9
+ } else if (t === 'object') {
10
+ o = {};
11
+ } else {
12
+ return data;
13
+ }
14
+
15
+ if (t === 'array') {
16
+ for (i = 0; i < data.length; i++) {
17
+ o.push(deepCopy(data[i]));
18
+ }
19
+ } else if (t === 'object') {
20
+ for (i in data) {
21
+ o[i] = deepCopy(data[i]);
22
+ }
23
+ }
24
+ return o;
25
+ }
26
+
27
+ // 判断对象类型
28
+ export function typeOf(obj) {
29
+ const toString = Object.prototype.toString;
30
+ const map = {
31
+ '[object Boolean]': 'boolean',
32
+ '[object Number]': 'number',
33
+ '[object String]': 'string',
34
+ '[object Function]': 'function',
35
+ '[object Array]': 'array',
36
+ '[object Date]': 'date',
37
+ '[object RegExp]': 'regExp',
38
+ '[object Undefined]': 'undefined',
39
+ '[object Null]': 'null',
40
+ '[object Object]': 'object'
41
+ };
42
+ return map[toString.call(obj)];
43
+ }
package/util/bus.js CHANGED
@@ -1,4 +1,4 @@
1
- import Vue from 'vue'
2
-
3
- const Bus = new Vue();
4
- export default Bus;
1
+ import Vue from 'vue'
2
+
3
+ const Bus = new Vue();
4
+ export default Bus;
@@ -1,326 +0,0 @@
1
- <template>
2
- <div
3
- class="week-date-picker"
4
- @touchstart="handleTouchStart"
5
- @touchmove="handleTouchMove"
6
- @touchend="handleTouchEnd"
7
- @mousedown="handleMouseDown"
8
- @mousemove="handleMouseMove"
9
- @mouseup="handleMouseUp"
10
- @mouseleave="handleMouseLeave"
11
- >
12
- <div class="week-days">
13
- <div
14
- v-for="day in weekDays"
15
- :key="day.date.getTime()"
16
- class="day-item"
17
- :class="{
18
- 'today': day.isToday,
19
- 'active': day.isSelected,
20
- }"
21
- @click="selectDay(day)"
22
- >
23
- <div class="day-week">{{ day.weekDay }}</div>
24
- <div class="day-month">{{ day.month }}月</div>
25
- <div class="day-date">{{ day.date.getDate() }}</div>
26
- <div v-if="day.isToday" class="today-dot"></div>
27
- </div>
28
- </div>
29
- </div>
30
- </template>
31
-
32
- <script>
33
- const WEEK_DAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
34
-
35
- export default {
36
- name: "LamboWeekSelect",
37
-
38
- data() {
39
- return {
40
- selectedDate: new Date(),
41
- weekStart: null,
42
- startX: 0,
43
- endX: 0,
44
- isDragging: false,
45
- swipeThreshold: 50,
46
- clickDisabled: false
47
- }
48
- },
49
- props: {
50
- weekDate: {
51
- type: String,
52
- default: null
53
- },
54
- },
55
-
56
- created() {
57
- if (this.weekDate) {
58
- this.initWithWeekDate(this.weekDate);
59
- } else {
60
- const today = new Date();
61
- const todayStr = this.formatDateToYYYYMMDD(today);
62
- this.initWithWeekDate(todayStr);
63
- }
64
- },
65
-
66
- computed: {
67
- weekDays() {
68
- if (!this.weekStart) return [];
69
- return Array.from({length: 7}, (_, i) => {
70
- const date = new Date(this.weekStart);
71
- date.setDate(this.weekStart.getDate() + i);
72
- const today = new Date();
73
- return {
74
- date,
75
- month: date.getMonth() + 1,
76
- weekDay: WEEK_DAYS[date.getDay()],
77
- isToday: this.isSameDay(date, today),
78
- isSelected: this.isSameDay(date, this.selectedDate)
79
- };
80
- });
81
- }
82
- },
83
-
84
- methods: {
85
- /**
86
- * 根据YYYYMMDD格式的字符串初始化组件
87
- * @param {string} dateFormat- 格式如:"20251205"
88
- */
89
- initWithWeekDate(dateFormat) {
90
- // 解析YYYYMMDD格式字符串为Date对象
91
- const date = this.parseYYYYMMDD(dateFormat);
92
-
93
- if (date) {
94
- console.log("根据传入日期初始化:", dateFormat);
95
- this.setWeekStart(date);
96
- this.selectedDate = new Date(date);
97
- } else {
98
- console.log("日期解析失败,使用今天");
99
- const today = new Date();
100
- this.setWeekStart(today);
101
- this.selectedDate = new Date(today);
102
- }
103
- },
104
-
105
- /**
106
- * 解析YYYYMMDD格式字符串为Date对象
107
- * @param {string} yyyymmdd - 格式如:"20251205"
108
- * @returns {Date|null} Date对象或null
109
- */
110
- parseYYYYMMDD(dateFormat) {
111
- if (!dateFormat || typeof dateFormat !== 'string' || dateFormat.length !== 8) {
112
- return null;
113
- }
114
-
115
- try {
116
- const year = parseInt(dateFormat.substring(0, 4));
117
- const month = parseInt(dateFormat.substring(4, 6)) - 1;
118
- const day = parseInt(dateFormat.substring(6, 8));
119
-
120
- const date = new Date(year, month, day);
121
-
122
- // 验证日期是否有效
123
- if (isNaN(date.getTime()) ||
124
- date.getFullYear() !== year ||
125
- date.getMonth() !== month ||
126
- date.getDate() !== day) {
127
- return null;
128
- }
129
-
130
- return date;
131
- } catch (error) {
132
- console.error("日期解析错误:", error);
133
- return null;
134
- }
135
- },
136
-
137
- setWeekStart(date) {
138
- const d = new Date(date);
139
- const day = d.getDay();
140
- const diff = d.getDate() - (day === 0 ? 6 : day - 1);
141
- d.setDate(diff);
142
- d.setHours(0, 0, 0, 0);
143
- this.weekStart = d;
144
- },
145
-
146
- isSameDay(d1, d2) {
147
- if (!d1 || !d2) return false;
148
- return d1.toDateString() === d2.toDateString();
149
- },
150
-
151
- formatDateToYYYYMMDD(date) {
152
- const year = date.getFullYear();
153
- const month = (date.getMonth() + 1).toString().padStart(2, '0');
154
- const day = date.getDate().toString().padStart(2, '0');
155
- return `${year}${month}${day}`;
156
- },
157
-
158
- selectDay(day) {
159
- if (this.clickDisabled) {
160
- this.clickDisabled = false;
161
- return;
162
- }
163
- this.selectedDate = new Date(day.date);
164
- const clickDate = this.formatDateToYYYYMMDD(this.selectedDate);
165
- console.log('选中的日期:', clickDate);
166
- // 触发自定义事件,传递YYYYMMDD格式的日期
167
- this.$emit('click', clickDate);
168
- },
169
-
170
- goPrevWeek() {
171
- const newWeekStart = new Date(this.weekStart);
172
- newWeekStart.setDate(this.weekStart.getDate() - 7);
173
- this.setWeekStart(newWeekStart);
174
- },
175
-
176
- goNextWeek() {
177
- const newWeekStart = new Date(this.weekStart);
178
- newWeekStart.setDate(this.weekStart.getDate() + 7);
179
- this.setWeekStart(newWeekStart);
180
- },
181
-
182
- handleTouchStart(e) {
183
- this.startX = e.touches[0].clientX;
184
- this.endX = this.startX;
185
- this.isDragging = true;
186
- this.clickDisabled = false;
187
- },
188
-
189
- handleTouchMove(e) {
190
- if (!this.isDragging) return;
191
- this.endX = e.touches[0].clientX;
192
- },
193
-
194
- handleTouchEnd() {
195
- if (!this.isDragging) return;
196
-
197
- const deltaX = this.endX - this.startX;
198
- this.handleSwipe(deltaX);
199
-
200
- this.isDragging = false;
201
- },
202
-
203
- handleMouseDown(e) {
204
- this.startX = e.clientX;
205
- this.endX = this.startX;
206
- this.isDragging = true;
207
- this.clickDisabled = false;
208
- },
209
-
210
- handleMouseMove(e) {
211
- if (!this.isDragging) return;
212
- this.endX = e.clientX;
213
- },
214
-
215
- handleMouseUp() {
216
- if (!this.isDragging) return;
217
-
218
- const deltaX = this.endX - this.startX;
219
- this.handleSwipe(deltaX);
220
-
221
- this.isDragging = false;
222
- },
223
-
224
- handleMouseLeave() {
225
- this.isDragging = false;
226
- },
227
-
228
- handleSwipe(deltaX) {
229
- if (Math.abs(deltaX) > this.swipeThreshold) {
230
- this.clickDisabled = true;
231
- if (deltaX > 0) {
232
- this.goPrevWeek();
233
- } else {
234
- this.goNextWeek();
235
- }
236
- }
237
- }
238
- }
239
- }
240
- </script>
241
-
242
- <style scoped>
243
- .week-date-picker {
244
- width: 100%;
245
- background: white;
246
- padding: 16px 0;
247
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
248
- user-select: none;
249
- border-radius: 8px;
250
- overflow: hidden;
251
- cursor: grab;
252
- }
253
-
254
- .week-date-picker:active {
255
- cursor: grabbing;
256
- }
257
-
258
- .week-days {
259
- display: flex;
260
- justify-content: space-around;
261
- align-items: center;
262
- padding: 0 8px;
263
- }
264
-
265
- .day-item {
266
- display: flex;
267
- flex-direction: column;
268
- align-items: center;
269
- justify-content: center;
270
- width: 44px;
271
- height: 64px;
272
- border-radius: 8px;
273
- cursor: pointer;
274
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
275
- position: relative;
276
- flex-shrink: 0;
277
- }
278
-
279
- .day-item:hover {
280
- background-color: #f5f5f5;
281
- transform: translateY(-2px);
282
- }
283
-
284
- .day-item.active {
285
- background-color: #1677ff;
286
- box-shadow: 0 4px 12px rgba(22, 119, 255, 0.3);
287
- transform: translateY(-2px);
288
- }
289
-
290
- .day-item.active .day-week,
291
- .day-item.active .day-month,
292
- .day-item.active .day-date {
293
- color: white;
294
- }
295
-
296
- .day-week {
297
- font-size: 12px;
298
- color: #666;
299
- margin-bottom: 4px;
300
- }
301
-
302
- .day-month {
303
- font-size: 10px;
304
- color: #999;
305
- margin-bottom: 2px;
306
- }
307
-
308
- .day-date {
309
- font-size: 20px;
310
- font-weight: 500;
311
- color: #333;
312
- }
313
-
314
- .today-dot {
315
- position: absolute;
316
- bottom: -4px;
317
- width: 4px;
318
- height: 4px;
319
- background-color: #1677ff;
320
- border-radius: 50%;
321
- }
322
-
323
- .day-item.active .today-dot {
324
- background-color: white;
325
- }
326
- </style>