You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.3 KiB

2 months ago
/** 东八区日历日 YYYY-MM-DD与后端活动状态一致勿对 ISO 直接 slice(0,10) */
export function ymdInShanghai(iso?: string | null): string {
if (!iso) return ''
const d = new Date(String(iso))
if (Number.isNaN(d.getTime())) return String(iso).slice(0, 10)
return new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).format(d)
}
function todayYmdShanghai(): string {
return new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Shanghai',
year: 'numeric',
month: '2-digit',
day: '2-digit',
}).format(new Date())
}
function compareYmd(a: string, b: string): number {
if (!a || !b) return 0
if (a < b) return -1
if (a > b) return 1
return 0
}
/** 与后台活动列表一致:未开始 / 进行中 / 已结束 */
export type ActivityScheduleStatus = 'not_started' | 'ongoing' | 'ended'
export function computeActivityScheduleStatus(
startAt?: string | null,
endAt?: string | null,
): ActivityScheduleStatus {
const today = todayYmdShanghai()
const startD = ymdInShanghai(startAt)
const endD = ymdInShanghai(endAt)
if (!startD && !endD) return 'ongoing'
if (startD && !endD) {
return compareYmd(today, startD) < 0 ? 'not_started' : 'ongoing'
}
if (!startD && endD) {
return compareYmd(today, endD) > 0 ? 'ended' : 'ongoing'
}
if (compareYmd(today, startD) < 0) return 'not_started'
if (compareYmd(today, endD) > 0) return 'ended'
return 'ongoing'
}
export function activityScheduleStatusLabel(s: ActivityScheduleStatus): string {
if (s === 'not_started') return '未开始'
if (s === 'ended') return '已结束'
return '进行中'
}
/** 活动是否已按「日历日」结束:结束日期早于今天则视为不可报名 */
export function isActivityEndedByCalendar(endAt?: string | null): boolean {
if (!endAt) return false
const endDay = ymdInShanghai(endAt)
if (!endDay) return false
const todayStr = todayYmdShanghai()
return endDay < todayStr
}
/** 活动日期同年为「2026年4月1日至5月3日」跨年则两年份都写 */
export function formatActivityCnRange(startAt?: string | null, endAt?: string | null) {
const parse = (raw?: string | null) => {
if (!raw) return null
const s = String(raw).trim()
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
const p = s.split('-').map(Number)
if (p.length !== 3) return null
const [y, m, d] = p
if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) return null
return { y, m, d }
}
const ymd = ymdInShanghai(s)
if (!ymd) return null
const p = ymd.split('-').map(Number)
if (p.length !== 3) return null
const [y, m, d] = p
if (!Number.isFinite(y) || !Number.isFinite(m) || !Number.isFinite(d)) return null
return { y, m, d }
}
const s = parse(startAt)
const e = parse(endAt)
if (!s && !e) return '日期待定'
if (s && !e) return `${s.y}${s.m}${s.d}`
if (!s && e) return `${e.y}${e.m}${e.d}`
if (s && e) {
if (s.y === e.y && s.m === e.m && s.d === e.d) {
return `${s.y}${s.m}${s.d}`
}
if (s.y === e.y) {
return `${s.y}${s.m}${s.d}日至${e.m}${e.d}`
}
return `${s.y}${s.m}${s.d}日至${e.y}${e.m}${e.d}`
}
return '日期待定'
}