快捷菜单
常用功能一站直达
更多功能请点顶栏「快捷菜单」

[[toc]]
[toc]
Hyde大佬自动和女友爬山回来,灵感陡增,产出干活满满。这不,我就可以马上抄作业了。🤣
次功能来自《Hyde》大佬,感谢大佬。❤️❤️❤️
Teek-one开箱即用版仓库:https://cnb.cool/onedayxyy/vitepress-theme-teek-one-public
(1)创建2个文件
docs\.vitepress\theme\components\CalendarCard.vue
docs\.vitepress\theme\components\ScheduleCard.vue
1<template>
2 <TkPageCard>
3 <div class="card-widget" id="card-widget-calendar">
4 <div class="item-headline">
5 <i class="icon-calendar"></i>
6 </div>
7 <div class="item-content">
8 <div id="calendar-area-left">
9 <div id="calendar-week">
10 第{{ weekNumber }}周 {{ weekDays[today.getDay()] }}
11 </div>
12 <div id="calendar-date">{{ today.getDate() }}</div>
13 <div id="calendar-solar">
14 {{ today.getFullYear() }}年{{ today.getMonth() + 1 }}月第{{
15 dayOfYear
16 }}天
17 </div>
18 <div id="calendar-lunar">
19 {{ lunarYear }} {{ lunarMonth }} {{ lunarDay }}
20 </div>
21 </div>
22 <div id="calendar-area-right">
23 <div id="calendar-main">
24 <!-- 星期标题行 -->
25 <div class="calendar-r0">
26 <div class="calendar-d0"><a>日</a></div>
27 <div class="calendar-d1"><a>一</a></div>
28 <div class="calendar-d2"><a>二</a></div>
29 <div class="calendar-d3"><a>三</a></div>
30 <div class="calendar-d4"><a>四</a></div>
31 <div class="calendar-d5"><a>五</a></div>
32 <div class="calendar-d6"><a>六</a></div>
33 </div>
34
35 <!-- 日期行 -->
36 <div
37 v-for="(week, weekIndex) in calendarWeeks"
38 :key="weekIndex"
39 :class="`calendar-r${weekIndex + 1}`"
40 >
41 <div
42 v-for="(day, dayIndex) in week"
43 :key="dayIndex"
44 :class="`calendar-d${dayIndex}`"
45 >
46 <a
47 :class="{ now: day.isToday, 'other-month': day.isOtherMonth }"
48 v-if="day.date"
49 >
50 {{ day.date }}
51 </a>
52 <a v-else></a>
53 </div>
54 </div>
55 </div>
56 </div>
57 </div>
58 </div>
59 </TkPageCard>
60 </template>
61
62 <script setup>
63 import { TkPageCard } from "vitepress-theme-teek";
64 import { ref, onMounted, computed } from "vue";
65
66 // 星期几中文映射
67 const weekDays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
68
69 // 当前日期
70 const today = ref(new Date());
71
72 // 生成当前月份的日历数据
73 const calendarWeeks = computed(() => {
74 const year = today.value.getFullYear();
75 const month = today.value.getMonth();
76
77 // 当月第一天
78 const firstDay = new Date(year, month, 1);
79 // 当月最后一天
80 const lastDay = new Date(year, month + 1, 0);
81
82 // 日历需要显示的第一天(可能是上月的日期)
83 const startDay = new Date(firstDay);
84 startDay.setDate(firstDay.getDate() - firstDay.getDay());
85
86 // 日历需要显示的最后一天(可能是下月的日期)
87 const endDay = new Date(lastDay);
88 if (endDay.getDay() < 6) {
89 endDay.setDate(lastDay.getDate() + (6 - endDay.getDay()));
90 }
91
92 // 生成日历数据
93 const weeks = [];
94 let currentDay = new Date(startDay);
95
96 while (currentDay <= endDay) {
97 const week = [];
98 for (let i = 0; i < 7; i++) {
99 const date = currentDay.getDate();
100 const isToday = currentDay.toDateString() === today.value.toDateString();
101 const isOtherMonth = currentDay.getMonth() !== month;
102
103 week.push({ date, isToday, isOtherMonth });
104
105 currentDay.setDate(currentDay.getDate() + 1);
106 }
107 weeks.push(week);
108 }
109
110 return weeks;
111 });
112
113 // 计算当前是今年的第几天
114 const dayOfYear = computed(() => {
115 const start = new Date(today.value.getFullYear(), 0, 0);
116 const diff = today.value - start;
117 const oneDay = 1000 * 60 * 60 * 24;
118 return Math.floor(diff / oneDay);
119 });
120
121 // 计算当前是第几周
122 const weekNumber = computed(() => {
123 const firstDay = new Date(today.value.getFullYear(), 0, 1);
124 const pastDaysOfYear = (today.value - firstDay) / 86400000;
125 return Math.ceil((pastDaysOfYear + firstDay.getDay() + 1) / 7);
126 });
127
128 // 农历转换相关
129 const lunarInfo = [
130 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0,
131 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540,
132 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50,
133 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0,
134 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,
135 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2,
136 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573,
137 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4,
138 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5,
139 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,
140 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46,
141 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58,
142 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50,
143 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0,
144 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,
145 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260,
146 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0,
147 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0,
148 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0,
149 ];
150
151 const gan = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"];
152 const zhi = [
153 "子",
154 "丑",
155 "寅",
156 "卯",
157 "辰",
158 "巳",
159 "午",
160 "未",
161 "申",
162 "酉",
163 "戌",
164 "亥",
165 ];
166 const animals = [
167 "鼠",
168 "牛",
169 "虎",
170 "兔",
171 "龙",
172 "蛇",
173 "马",
174 "羊",
175 "猴",
176 "鸡",
177 "狗",
178 "猪",
179 ];
180 const lunarMonths = [
181 "正月",
182 "二月",
183 "三月",
184 "四月",
185 "五月",
186 "六月",
187 "七月",
188 "八月",
189 "九月",
190 "十月",
191 "十一月",
192 "十二月",
193 ];
194 const lunarDays = [
195 "初一",
196 "初二",
197 "初三",
198 "初四",
199 "初五",
200 "初六",
201 "初七",
202 "初八",
203 "初九",
204 "初十",
205 "十一",
206 "十二",
207 "十三",
208 "十四",
209 "十五",
210 "十六",
211 "十七",
212 "十八",
213 "十九",
214 "二十",
215 "廿一",
216 "廿二",
217 "廿三",
218 "廿四",
219 "廿五",
220 "廿六",
221 "廿七",
222 "廿八",
223 "廿九",
224 "三十",
225 ];
226
227 // 转换为农历
228 const getLunarDate = (date) => {
229 const year = date.getFullYear();
230 const month = date.getMonth() + 1;
231 const day = date.getDate();
232
233 let springStart = new Date(2000, 1, 4); // 2000年春节是2月4日
234 if (year > 2000) {
235 // 简单计算春节日期,实际应用中可能需要更精确的算法
236 springStart = new Date(year, 1, 4 + Math.floor((year - 2000) * 0.2422));
237 }
238
239 let lunarYear = year;
240 let isLeap = false;
241 let lunarMonthIdx = 0;
242 let lunarDayIdx = 0;
243
244 // 简化的农历计算,实际应用可能需要更复杂的算法
245 const offset = Math.floor((date - new Date(year, 0, 0)) / 86400000);
246 let days = 0;
247 let i = 0;
248
249 for (; i < 12; i++) {
250 const monthDays = (lunarInfo[year - 1900] >> (12 - i)) & 0x1 ? 30 : 29;
251 if (days + monthDays >= offset) {
252 lunarDayIdx = offset - days - 1;
253 break;
254 }
255 days += monthDays;
256 }
257 lunarMonthIdx = i;
258
259 // 计算农历年的干支和生肖
260 const ganIndex = (year - 3) % 10;
261 const zhiIndex = (year - 3) % 12;
262 const lunarYearStr = `${gan[ganIndex]}${zhi[zhiIndex]}${animals[zhiIndex]}年`;
263
264 return {
265 lunarYear: lunarYearStr,
266 lunarMonth: lunarMonths[lunarMonthIdx],
267 lunarDay: lunarDays[lunarDayIdx],
268 };
269 };
270
271 // 响应式农历数据
272 const lunarDate = computed(() => getLunarDate(today.value));
273 const lunarYear = computed(() => lunarDate.value.lunarYear);
274 const lunarMonth = computed(() => lunarDate.value.lunarMonth);
275 const lunarDay = computed(() => lunarDate.value.lunarDay);
276
277 // 每天更新一次日历
278 onMounted(() => {
279 // 检查是否需要更新(跨天)
280 const checkUpdate = () => {
281 const now = new Date();
282 if (now.toDateString() !== today.value.toDateString()) {
283 today.value = now;
284 }
285 };
286
287 // 每分钟检查一次
288 setInterval(checkUpdate, 60000);
289 });
290 </script>
291
292 <style scoped>
293 /* 基础样式重置 */
294 * {
295 margin: 0;
296 padding: 0;
297 box-sizing: border-box;
298 font-family: "Microsoft YaHei", sans-serif;
299 }
300
301 body {
302 background-color: #f5f7fa;
303 padding: 20px;
304 }
305
306 :root {
307 --other-month-bg: #fa0000;
308 }
309
310 .dark {
311 --other-month-bg: #0080ff;
312 }
313
314 .tk-page-card {
315 margin-top: 10px;
316 }
317
318 .card-widget {
319 max-height: calc(100vh - 100px);
320 position: relative;
321 }
322
323 #card-widget-calendar .item-headline {
324 padding-bottom: 0;
325 margin-left: 8px;
326 font-size: 1em;
327 font-weight: 700;
328 display: flex;
329 align-items: center;
330 gap: 5px;
331 margin-bottom: 10px;
332 }
333
334 #card-widget-calendar .item-headline i {
335 font-size: 18px;
336 }
337
338 #card-widget-calendar .item-content {
339 display: flex;
340 }
341
342 #calendar-area-left,
343 #calendar-area-right {
344 height: 100%;
345 padding: 4px;
346 display: flex;
347 flex-direction: column;
348 align-items: center;
349 justify-content: center;
350 }
351
352 #calendar-area-left {
353 width: 45%;
354 }
355
356 #calendar-week {
357 height: 1.2rem;
358 font-size: 14px;
359 letter-spacing: 1px;
360 font-weight: 700;
361 align-items: center;
362 display: flex;
363 }
364
365 #calendar-date {
366 height: 3rem;
367 line-height: 1.3;
368 font-size: 36px;
369 letter-spacing: 3px;
370 color: var(--vp-c-brand-1);
371 font-weight: 700;
372 align-items: center;
373 display: flex;
374 position: absolute;
375 top: calc(50% - 2.1rem);
376 }
377
378 #calendar-solar {
379 bottom: 2.1rem;
380 }
381
382 #calendar-lunar,
383 #calendar-solar {
384 height: 1rem;
385 font-size: 11px;
386 align-items: center;
387 display: flex;
388 position: absolute;
389 }
390
391 #calendar-lunar {
392 bottom: 1rem;
393 }
394
395 #calendar-area-right {
396 width: 55%;
397 }
398
399 #calendar-main {
400 width: 100%;
401 }
402
403 .calendar-r0,
404 .calendar-r1,
405 .calendar-r2,
406 .calendar-r3,
407 .calendar-r4,
408 .calendar-r5,
409 .calendar-rh {
410 height: 1.2rem;
411 display: flex;
412 }
413
414 .calendar-d0,
415 .calendar-d1,
416 .calendar-d2,
417 .calendar-d3,
418 .calendar-d4,
419 .calendar-d5,
420 .calendar-d6 {
421 width: calc(100% / 7);
422 display: flex;
423 justify-content: center;
424 align-items: center;
425 }
426
427 #calendar-main a {
428 height: 1.2rem;
429 width: 1.5rem;
430 border-radius: 50%;
431 font-size: 12px;
432 line-height: 12px;
433 display: flex;
434 justify-content: center;
435 align-items: center;
436 text-decoration: none;
437 color: var(--calendar-main-a-clolr);
438 }
439
440 #calendar-main a.now {
441 background: var(--vp-c-brand-1);
442 color: #fff;
443 }
444
445 #calendar-main a.other-month {
446 color: var(--other-month-clolr);
447 }
448 </style>
449 1<template>
2 <TkPageCard>
3 <div class="card-widget" id="card-widget-schedule">
4 <div class="item-headline">
5 <i></i>
6 </div>
7 <div class="item-content">
8 <div id="schedule-area-right">
9 <div class="schedule-r0">
10 <!-- <div class="schedule-d0">本年</div> -->
11 <div class="schedule-d1">
12 <span id="p_span_year" class="aside-span1"
13 >{{ yearProgress }}%</span
14 >
15 <div class="progress-container">
16 <span class="aside-span2"
17 >本年还剩<a id="year_days_left">{{ yearDaysLeft }}</a
18 >天</span
19 >
20 <progress
21 max="365"
22 id="pBar_year"
23 :value="yearPassedDays"
24 ></progress>
25 </div>
26 </div>
27 </div>
28 <div class="schedule-r1">
29 <!-- <div class="schedule-d0">本月</div> -->
30 <div class="schedule-d1">
31 <span id="p_span_month" class="aside-span1"
32 >{{ monthProgress }}%</span
33 >
34 <div class="progress-container">
35 <span class="aside-span2"
36 >本月还剩<a id="month_days_left">{{ monthDaysLeft }}</a
37 >天</span
38 >
39 <progress
40 max="31"
41 id="pBar_month"
42 :value="monthPassedDays"
43 ></progress>
44 </div>
45 </div>
46 </div>
47 <div class="schedule-r2">
48 <!-- <div class="schedule-d0">本周</div> -->
49 <div class="schedule-d1">
50 <span id="p_span_week" class="aside-span1"
51 >{{ weekProgress }}%</span
52 >
53 <div class="progress-container">
54 <span class="aside-span2"
55 >本周还剩<a id="week_days_left">{{ weekDaysLeft }}</a
56 >天</span
57 >
58 <progress
59 max="7"
60 id="pBar_week"
61 :value="weekDisplayValue"
62 ></progress>
63 </div>
64 </div>
65 </div>
66 </div>
67 <div id="schedule-area-left">
68 <div id="schedule-title">距离春节</div>
69 <div id="schedule-days">{{ springFestivalDays }}</div>
70 <div id="schedule-date">{{ springFestivalDateText }}</div>
71 </div>
72 </div>
73 </div>
74 </TkPageCard>
75</template>
76
77<script setup>
78import { TkPageCard } from "vitepress-theme-teek";
79import { ref, onMounted } from "vue";
80
81// 响应式变量
82const springFestivalDays = ref("--");
83const springFestivalDateText = ref("--"); // 动态春节日期文本
84const yearProgress = ref("--");
85const yearDaysLeft = ref("--");
86const yearPassedDays = ref(0);
87const monthProgress = ref("--");
88const monthDaysLeft = ref("--");
89const monthPassedDays = ref(0);
90const weekProgress = ref("--");
91const weekDaysLeft = ref("--");
92const weekDisplayValue = ref(0);
93
94/**
95 * 计算指定年份春节(农历正月初一)的公历日期(1900-2100年适用)
96 * @param {number} lunarYear - 农历年份
97 * @returns {Date} 春节的公历日期
98 */
99const getSpringFestivalDate = (lunarYear) => {
100 // 1900-2100年春节公历日期表([月, 日]),已精准修正2026年(索引126)为[2,17]
101 const springFestivalData = [
102 [2, 19], [2, 8], [1, 28], [2, 16], [2, 5], [1, 25], [2, 13], [2, 2], [1, 22], [2, 10], // 1900-1909 (0-9)
103 [1, 30], [2, 18], [2, 7], [1, 26], [2, 14], [2, 3], [1, 23], [2, 11], [1, 31], [2, 19], // 1910-1919 (10-19)
104 [2, 8], [1, 28], [2, 16], [2, 5], [1, 24], [2, 12], [2, 1], [1, 21], [2, 9], [1, 28], // 1920-1929 (20-29)
105 [2, 16], [2, 5], [1, 24], [2, 12], [2, 1], [1, 21], [2, 9], [1, 29], [2, 17], [2, 6], // 1930-1939 (30-39)
106 [1, 26], [2, 14], [2, 2], [1, 22], [2, 10], [1, 29], [2, 17], [2, 6], [1, 26], [2, 13], // 1940-1949 (40-49)
107 [2, 2], [1, 22], [2, 10], [1, 30], [2, 17], [2, 6], [1, 25], [2, 13], [2, 1], [1, 21], // 1950-1959 (50-59)
108 [2, 8], [1, 28], [2, 15], [2, 5], [1, 24], [2, 12], [1, 31], [2, 18], [2, 7], [1, 27], // 1960-1969 (60-69)
109 [2, 15], [2, 3], [1, 23], [2, 11], [1, 31], [2, 18], [2, 6], [1, 26], [2, 14], [2, 3], // 1970-1979 (70-79)
110 [1, 23], [2, 10], [1, 29], [2, 16], [2, 5], [1, 24], [2, 12], [2, 1], [1, 22], [2, 9], // 1980-1989 (80-89)
111 [1, 28], [2, 15], [2, 4], [1, 23], [2, 10], [1, 30], [2, 17], [2, 6], [1, 26], [2, 14], // 1990-1999 (90-99)
112 [2, 2], [1, 22], [2, 10], [1, 29], [2, 17], [2, 5], [1, 24], [2, 12], [1, 31], [2, 18], // 2000-2009 (100-109)
113 [2, 7], [1, 26], [2, 14], [2, 3], [1, 23], [2, 10], [1, 31], [2, 18], [2, 7], [1, 26], // 2010-2019 (110-119)
114 [2, 12], [2, 1], [1, 22], [2, 10], [1, 29], [2, 17], [2, 17], [1, 24], [2, 12], [2, 1], // 2020-2029 (120-129)
115 // 索引126对应2026年,已明确设置为[2,17]
116 [1, 22], [2, 10], [1, 29], [2, 17], [2, 6], [1, 26], [2, 14], [2, 3], [1, 23], [2, 10], // 2030-2039 (130-139)
117 [1, 30], [2, 17], [2, 6], [1, 26], [2, 13], [2, 2], [1, 22], [2, 10], [1, 29], [2, 17], // 2040-2049 (140-149)
118 [2, 5], [1, 25], [2, 13], [2, 1], [1, 21], [2, 9], [1, 28], [2, 16], [2, 5], [1, 24], // 2050-2059 (150-159)
119 [2, 12], [2, 1], [1, 21], [2, 9], [1, 28], [2, 15], [2, 4], [1, 24], [2, 11], [1, 31], // 2060-2069 (160-169)
120 [2, 18], [2, 7], [1, 27], [2, 15], [2, 3], [1, 23], [2, 11], [1, 31], [2, 18], [2, 6], // 2070-2079 (170-179)
121 [1, 26], [2, 14], [2, 3], [1, 23], [2, 10], [1, 29], [2, 16], [2, 5], [1, 24], [2, 12], // 2080-2089 (180-189)
122 [2, 1], [1, 22], [2, 9], [1, 28], [2, 15], [2, 4], [1, 23], [2, 10], [1, 30], [2, 17], // 2090-2099 (190-199)
123 [2, 5] // 2100年 (200)
124 ];
125
126 const index = lunarYear - 1900;
127 if (index >= 0 && index < springFestivalData.length) {
128 const [month, day] = springFestivalData[index];
129 return new Date(lunarYear, month - 1, day); // 月份在Date中为0基,需减1
130 }
131 return new Date(lunarYear, 1, 1); // 超出范围默认2月1日
132};
133
134/**
135 * 动态获取目标春节日期(今年或明年)
136 * @returns {Date} 目标春节日期
137 */
138const getTargetSpringFestival = () => {
139 const today = new Date();
140 const currentYear = today.getFullYear();
141 const currentYearSpring = getSpringFestivalDate(currentYear);
142 // 若今天在今年春节前,目标为今年春节;否则为明年春节
143 return today < currentYearSpring ? currentYearSpring : getSpringFestivalDate(currentYear + 1);
144};
145
146/**
147 * 计算两个日期的天数差
148 * @param {Date} date1 - 起始日期
149 * @param {Date} date2 - 目标日期
150 * @returns {number} 天数差(向上取整)
151 */
152const getDaysDifference = (date1, date2) => {
153 const oneDay = 24 * 60 * 60 * 1000;
154 const diffTime = date2 - date1;
155 return Math.ceil(diffTime / oneDay);
156};
157
158/**
159 * 更新春节倒计时及日期显示
160 */
161const updateSpringFestivalCountdown = () => {
162 const today = new Date();
163 today.setHours(0, 0, 0, 0); // 忽略时分秒,按整天计算
164 const targetSpring = getTargetSpringFestival();
165 // 计算剩余天数
166 springFestivalDays.value = getDaysDifference(today, targetSpring);
167 // 格式化日期为YYYY-MM-DD
168 const year = targetSpring.getFullYear();
169 const month = String(targetSpring.getMonth() + 1).padStart(2, '0');
170 const day = String(targetSpring.getDate()).padStart(2, '0');
171 springFestivalDateText.value = `${year}-${month}-${day}`;
172};
173
174/**
175 * 更新年度进度
176 */
177const updateYearProgress = () => {
178 const today = new Date();
179 const year = today.getFullYear();
180 const startOfYear = new Date(year, 0, 1);
181 const endOfYear = new Date(year, 11, 31);
182 const totalDays = getDaysDifference(startOfYear, endOfYear) + 1;
183 const daysPassed = getDaysDifference(startOfYear, today);
184 const daysLeft = totalDays - daysPassed;
185 const progress = (daysPassed / totalDays) * 100;
186
187 yearDaysLeft.value = daysLeft;
188 yearProgress.value = progress.toFixed(1);
189 yearPassedDays.value = daysPassed;
190};
191
192/**
193 * 更新月度进度
194 */
195const updateMonthProgress = () => {
196 const today = new Date();
197 const year = today.getFullYear();
198 const month = today.getMonth();
199 const startOfMonth = new Date(year, month, 1);
200 const endOfMonth = new Date(year, month + 1, 0);
201 const totalDays = getDaysDifference(startOfMonth, endOfMonth) + 1;
202 const daysPassed = today.getDate() - 1; // 当月已过天数(不含今天)
203 const daysLeft = totalDays - daysPassed - 1; // 剩余天数(含今天)
204 const progress = (daysPassed / totalDays) * 100;
205
206 monthDaysLeft.value = daysLeft;
207 monthProgress.value = progress.toFixed(1);
208 monthPassedDays.value = daysPassed;
209};
210
211/**
212 * 更新本周进度(已修复0%问题)
213 */
214const updateWeekProgress = () => {
215 const today = new Date();
216 let dayOfWeek = today.getDay() || 7; // 周日转为7,周一到周六为1-6
217 const daysPassed = dayOfWeek; // 已过天数(含今天:周一=1,周日=7)
218 const daysLeft = 7 - dayOfWeek; // 剩余天数
219
220 // 避免进度条完全消失(最小0.1)
221 const displayValue = daysPassed === 0 ? 0.1 : daysPassed;
222
223 weekDaysLeft.value = daysLeft;
224 weekProgress.value = ((daysPassed / 7) * 100).toFixed(1);
225 weekDisplayValue.value = displayValue;
226};
227
228/**
229 * 统一更新所有数据
230 */
231const updateAllData = () => {
232 updateSpringFestivalCountdown();
233 updateYearProgress();
234 updateMonthProgress();
235 updateWeekProgress();
236};
237
238// 页面加载时初始化,并设置每天凌晨更新
239onMounted(() => {
240 updateAllData();
241
242 // 计算距离次日凌晨0:00:01的毫秒数,设置定时器每天更新
243 const now = new Date();
244 const tomorrow = new Date(now);
245 tomorrow.setDate(now.getDate() + 1);
246 tomorrow.setHours(0, 0, 1, 0);
247 const timeToUpdate = tomorrow - now;
248
249 setInterval(updateAllData, timeToUpdate);
250});
251</script>
252
253<style scoped>
254.tk-page-card {
255 margin-top: 10px;
256}
257
258/* 进度条样式 */
259progress {
260 width: 100%;
261 height: 10px;
262 border-radius: 5px;
263 background-color: #f0f0f0;
264 border: none;
265}
266progress::-webkit-progress-bar {
267 background-color: #f0f0f0;
268 border-radius: 5px;
269}
270progress::-webkit-progress-value {
271 background-color: var(--vp-c-brand-1);
272 border-radius: 5px;
273 transition: width 0.3s ease;
274}
275
276/* 基础样式 */
277* {
278 margin: 0;
279 padding: 0;
280 box-sizing: border-box;
281 font-family: "Microsoft YaHei", sans-serif;
282}
283
284.item-headline span {
285 font-size: 18px;
286 font-weight: 600;
287 color: #333333;
288}
289
290/* 内容区域样式 */
291.item-content {
292 display: flex;
293 flex-wrap: wrap;
294 gap: 20px;
295}
296
297/* 左侧春节倒计时样式 */
298#schedule-area-left {
299 flex: 1;
300 min-width: 200px;
301 border-radius: 8px;
302 padding: 20px;
303 text-align: center;
304 border: 1px solid var(--vp-c-brand-1);
305}
306#schedule-title {
307 font-size: 16px;
308 color: var(--vp-c-brand-1);
309 margin-bottom: 10px;
310}
311#schedule-days {
312 font-size: 48px;
313 font-weight: 700;
314 color: var(--vp-c-brand-1);
315 margin: 10px 0;
316}
317#schedule-date {
318 font-size: 14px;
319 color: #666666;
320}
321
322/* 右侧进度区域样式 */
323#schedule-area-right {
324 flex: 2;
325 display: flex;
326 flex-direction: column;
327 gap: 16px;
328}
329.schedule-r0,
330.schedule-r1,
331.schedule-r2 {
332 display: flex;
333 flex-direction: column;
334 gap: 6px;
335}
336.schedule-d0 {
337 font-size: 14px;
338 color: #333333;
339 font-weight: 500;
340}
341.schedule-d1 {
342 display: flex;
343 align-items: center;
344 gap: 12px;
345}
346.progress-container {
347 width: 100%;
348 display: flex;
349 flex-direction: column;
350 gap: 4px;
351 flex: 2;
352}
353.aside-span1 {
354 font-size: 14px;
355 color: var(--vp-c-brand-1);
356 font-weight: 600;
357 width: 60px;
358 display: inline-block;
359}
360.aside-span2 {
361 font-size: 13px;
362 color: #666666;
363 flex: 1;
364}
365.aside-span2 a {
366 color: var(--vp-c-brand-1);
367 text-decoration: none;
368 font-weight: 600;
369}
370
371/* 响应式样式 */
372@media (max-width: 480px) {
373 .item-content {
374 flex-direction: column;
375 }
376 #schedule-days {
377 font-size: 36px;
378 }
379}
380</style>(2)引入
编辑docs\.vitepress\theme\components\TeekLayoutProvider.vue文件:
1import CalendarCard from "./CalendarCard.vue"; //日历卡片
2import ScheduleCard from "./ScheduleCard.vue"; //节日倒计时卡片
3
4 <!-- 自定义公告卡片 公告-->
5 <template #teek-home-card-top-article-before>
6 <!-- <WelcomeCard /> -->
7 <NoticeCard />
8 <CalendarCard />
9 <ScheduleCard />
10 </template>具体代码可见如下源码:https://cnb.cool/onedayxyy/vitepress-theme-teek-one-public/-/blob/main/docs/.vitepress/theme/components/TeekLayoutProvider.vue
(3)验证

结束。
日历 · 精选 · 友链 · 更多
如果内容对你有帮助,欢迎请我喝杯咖啡 ☕



One的公众号
爱折腾博客的小白