UI 变更: - 移除重做按钮及 redo/canRedo/redoStack 相关逻辑 (useCalendar, HeaderBar) - 移除应用更改按钮, EventDetail 改为 watch form 自动应用 (deep watch) - 用 syncing 标志防止 syncForm 回写时触发自动应用的循环 死代码清理: - weekday.js: 移除未使用的 BYDAY_TO_INDEX 和 dowLabel - date.js: 移除未使用的 toHHMM - App.vue: 移除未使用的 .empty CSS - DropZone.vue: 移除空的 .icon 容器及 CSS - test/weekday.test.js: 移除对应死代码的 2 个测试用例 性能修复: - WeekPreview: layoutEvents 从模板内联调用改为 computed (laidOutByDate), 避免每次渲染重新计算布局 - MonthPreview: occByDate 过滤为仅网格内 42 天, 避免展开全部 occurrence 代码质量: - useCalendar: prevMonth/nextMonth 合并为 shiftMonth(delta), 消除重复 - WeekPreview/MonthPreview: 移除未使用导入 (toISODate, toDate)
87 lines
2.5 KiB
JavaScript
87 lines
2.5 KiB
JavaScript
/**
|
|
* 集中式的日期字符串工具集。
|
|
*
|
|
* 应用内所有日期值统一使用 'YYYY-MM-DD' (本地墙钟时间) 格式。
|
|
* 本模块是格式化与日期运算的唯一来源, 替代此前散落在 organize.js、
|
|
* recur.js、useCalendar.js、ical-io.js 中的重复实现。
|
|
*/
|
|
|
|
/** 将数字补零为 2 位字符串。 */
|
|
export function pad2(n) {
|
|
return String(n).padStart(2, '0')
|
|
}
|
|
|
|
/** 将 JS Date 转换为 'YYYY-MM-DD' (本地墙钟时间)。 */
|
|
export function toISODate(date) {
|
|
return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`
|
|
}
|
|
|
|
/** 将 'YYYY-MM-DD' 解析为 { year, month, day } (month 为 1 基)。 */
|
|
export function parseISODate(s) {
|
|
const [y, m, d] = s.split('-').map(Number)
|
|
return { year: y, month: m, day: d }
|
|
}
|
|
|
|
/** 由 'YYYY-MM-DD' 构造本地午夜 JS Date。 */
|
|
export function toDate(isoDate) {
|
|
return new Date(isoDate + 'T00:00:00')
|
|
}
|
|
|
|
/** 在 ISO 日期字符串上增加 `days` 天, 返回新的 ISO 字符串。 */
|
|
export function addDays(isoDate, days) {
|
|
const d = toDate(isoDate)
|
|
d.setDate(d.getDate() + days)
|
|
return toISODate(d)
|
|
}
|
|
|
|
/** 两个 ISO 日期字符串之间的整天差 (b - a)。 */
|
|
export function daysBetween(isoA, isoB) {
|
|
return Math.round((toDate(isoB) - toDate(isoA)) / (24 * 3600 * 1000))
|
|
}
|
|
|
|
/** 今天的日期, 格式为 'YYYY-MM-DD' (本地)。 */
|
|
export function todayISO() {
|
|
return toISODate(new Date())
|
|
}
|
|
|
|
/**
|
|
* 当前 UTC 时间戳, 紧凑 RFC 5545 格式 (如 '20260711T085008Z')。
|
|
* 用于新事件的 DTSTAMP。
|
|
*/
|
|
export function nowCompactTimestamp() {
|
|
return new Date().toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'
|
|
}
|
|
|
|
/**
|
|
* 返回 isoDate 所在周的周一 (ISO 周, 周一为首日)。
|
|
* @param {string} isoDate - 'YYYY-MM-DD'
|
|
* @returns {string} 周一的 'YYYY-MM-DD'
|
|
*/
|
|
export function startOfWeek(isoDate) {
|
|
const d = toDate(isoDate)
|
|
const dow = d.getDay() // 0=周日 .. 6=周六
|
|
const diff = dow === 0 ? -6 : 1 - dow // 回退到周一
|
|
d.setDate(d.getDate() + diff)
|
|
return toISODate(d)
|
|
}
|
|
|
|
/**
|
|
* 返回 isoDate 所在月的第一天。
|
|
* @param {string} isoDate - 'YYYY-MM-DD'
|
|
* @returns {string} 当月 1 号的 'YYYY-MM-DD'
|
|
*/
|
|
export function startOfMonth(isoDate) {
|
|
const { year, month } = parseISODate(isoDate)
|
|
return `${year}-${pad2(month)}-01`
|
|
}
|
|
|
|
/**
|
|
* 将 'HH:MM' 转换为当天分钟数 (0~1439)。
|
|
* @param {string} hhmm - 'HH:MM'
|
|
* @returns {number}
|
|
*/
|
|
export function hhmmToMinutes(hhmm) {
|
|
const [h, m] = hhmm.split(':').map(Number)
|
|
return h * 60 + m
|
|
}
|