time-select.vue
4.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<template>
<view class="time-select">
<view class="tab-container">
<view class="tab-item" :class="{ active: currentDateType === 'week' }" @click="switchDateType('week')">
周
</view>
<view class="tab-item" :class="{ active: currentDateType === 'month' }" @click="switchDateType('month')">
月
</view>
</view>
<view class="date-stepper">
<view class="arrow-icon" @click="handlePrev">
<up-icon name="arrow-left" color="#333" size="12" bold></up-icon>
</view>
<view class="date-display"> {{ dateRangeText }} </view>
<!-- 修改: 根据 isNextDisabled 判断是否隐藏下一个按钮 -->
<view class="arrow-icon" @click="handleNext" v-if="!isNextDisabled">
<up-icon name="arrow-right" color="#333" size="12" bold></up-icon>
</view>
<view v-else class="occupy"></view>
</view>
</view>
</template>
<script setup>
import dayjs from 'dayjs';
import { ref, computed, watch } from 'vue';
const emit = defineEmits(['dateTypeChange', 'dateRangeChange']);
// 当前日期类型与基准日期
const currentDateType = ref('week');
const baseDate = ref(dayjs());
// ==================== 公共日期范围计算 ====================
/** 根据当前类型计算周期起止日期(dayjs 实例) */
const periodRange = computed(() => {
const d = baseDate.value;
if (currentDateType.value === 'week') {
const dayOfWeek = d.day(); // 0=周日, 1=周一, ...
const start = d.subtract(dayOfWeek === 0 ? 6 : dayOfWeek - 1, 'day');
const end = start.add(6, 'day');
return { start, end };
}
// month
return { start: d.startOf('month'), end: d.endOf('month') };
});
// ==================== 计算属性 ====================
/** 对外暴露的日期范围(YYYY-MM-DD) */
const currentDateRange = computed(() => ({
start: periodRange.value.start.format('YYYY-MM-DD'),
end: periodRange.value.end.format('YYYY-MM-DD'),
}));
/** 显示的日期范围文本 "YYYY/MM/DD - YYYY/MM/DD" */
const dateRangeText = computed(() => {
const { start, end } = periodRange.value;
return `${start.format('YYYY/MM/DD')} - ${end.format('YYYY/MM/DD')}`;
});
/** 下一周期是否超过今天(超出则隐藏前进按钮) */
const isNextDisabled = computed(() => {
const nextBase = currentDateType.value === 'week'
? baseDate.value.add(7, 'day')
: baseDate.value.add(1, 'month');
return nextBase.startOf('day').isAfter(dayjs().startOf('day'));
});
// ==================== 事件处理 ====================
const switchDateType = (type) => {
currentDateType.value = type;
emit('dateTypeChange', type);
};
const handlePrev = () => {
baseDate.value = currentDateType.value === 'week'
? baseDate.value.subtract(7, 'day')
: baseDate.value.subtract(1, 'month');
};
const handleNext = () => {
if (isNextDisabled.value) return;
baseDate.value = currentDateType.value === 'week'
? baseDate.value.add(7, 'day')
: baseDate.value.add(1, 'month');
};
// ==================== 双向绑定 ====================
watch(
[baseDate, currentDateType],
() => {
emit('dateRangeChange', {
startDate: currentDateRange.value.start,
endDate: currentDateRange.value.end,
});
},
{ immediate: true },
);
</script>
<style scoped lang="scss">
.time-select {
flex-shrink: 0;
/* 修改: 防止顶部选择器被压缩 */
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
// 周月切换 Tab
.tab-container {
width: 100%;
height: 72rpx;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8rpx;
background-color: #eee;
border-radius: 12rpx;
padding: 6rpx;
box-sizing: border-box;
.tab-item {
display: flex;
align-items: center;
justify-content: center;
color: #8c8c8c;
font-size: 28rpx;
transition: all 0.2s ease;
&.active {
background-color: #ffffff;
color: #1a1a1a;
font-weight: 600;
border-radius: 8rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
}
}
// 日期翻页器
.date-stepper {
margin-top: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.date-display {
margin: 0 40rpx;
font-size: 28rpx;
font-weight: 500;
color: #333;
font-variant-numeric: tabular-nums; // 防止数字切换时抖动
}
.arrow-icon {
width: 56rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
border-radius: 50%;
transition: background-color 0.2s;
}
}
.occupy {
width: 56rpx;
height: 56rpx;
}
}
</style>