From b5c92dbd30f1f67a739eecbd146e738b9c6f1163 Mon Sep 17 00:00:00 2001
From: haoliang <821644@qq.com>
Date: Wed, 13 May 2026 13:40:18 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=9B=B8=E5=AF=B9=E6=97=B6?=
=?UTF-8?q?=E9=97=B4=E5=B7=A5=E5=85=B7=E5=87=BD=E6=95=B0=E5=92=8CRelativeT?=
=?UTF-8?q?ime=E7=BB=84=E4=BB=B6=EF=BC=88Wave3-T11=E9=81=97=E6=BC=8F?=
=?UTF-8?q?=E6=8F=90=E4=BA=A4=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend/src/components/RelativeTime.vue | 65 ++++++++++++++
frontend/src/utils/time.ts | 110 +++++++++++++++++++++++
2 files changed, 175 insertions(+)
create mode 100644 frontend/src/components/RelativeTime.vue
create mode 100644 frontend/src/utils/time.ts
diff --git a/frontend/src/components/RelativeTime.vue b/frontend/src/components/RelativeTime.vue
new file mode 100644
index 0000000..7a8411d
--- /dev/null
+++ b/frontend/src/components/RelativeTime.vue
@@ -0,0 +1,65 @@
+
+
+ {{ displayText }}
+
+
+
+
+
+
diff --git a/frontend/src/utils/time.ts b/frontend/src/utils/time.ts
new file mode 100644
index 0000000..0acf99c
--- /dev/null
+++ b/frontend/src/utils/time.ts
@@ -0,0 +1,110 @@
+/**
+ * 相对时间工具函数
+ * 将时间字符串转换为相对时间显示文本
+ */
+
+export interface RelativeTimeResult {
+ /** 相对时间显示文本 */
+ displayText: string
+ /** 完整时间字符串(hover显示) */
+ fullTime: string
+ /** 是否需要自动刷新(10分钟内) */
+ needRefresh: boolean
+}
+
+/**
+ * 格式化相对时间
+ * @param timeStr 时间字符串,支持格式:'yyyy-MM-dd HH:mm:ss' | Date | number(时间戳)
+ * @returns 相对时间结果
+ */
+export function formatRelativeTime(timeStr: string | Date | number | null | undefined): RelativeTimeResult {
+ if (!timeStr) {
+ return { displayText: '--', fullTime: '--', needRefresh: false }
+ }
+
+ let date: Date
+ if (timeStr instanceof Date) {
+ date = timeStr
+ } else if (typeof timeStr === 'number') {
+ date = new Date(timeStr)
+ } else {
+ date = new Date(timeStr.replace(/-/g, '/')) // 兼容iOS Safari的日期解析
+ }
+
+ if (isNaN(date.getTime())) {
+ return { displayText: '--', fullTime: String(timeStr), needRefresh: false }
+ }
+
+ const now = Date.now()
+ const diff = now - date.getTime()
+ const absDiff = Math.abs(diff)
+
+ // 完整时间
+ const fullTime = formatFullTime(date)
+
+ // 未来时间直接返回完整时间
+ if (diff < -60000) {
+ return { displayText: fullTime, fullTime, needRefresh: false }
+ }
+
+ // 10秒内
+ if (absDiff < 10 * 1000) {
+ return { displayText: '刚刚', fullTime, needRefresh: true }
+ }
+
+ // 1分钟内
+ if (absDiff < 60 * 1000) {
+ const seconds = Math.floor(absDiff / 1000)
+ return { displayText: `${seconds}秒前`, fullTime, needRefresh: true }
+ }
+
+ // 1小时内
+ if (absDiff < 60 * 60 * 1000) {
+ const minutes = Math.floor(absDiff / (60 * 1000))
+ return { displayText: `${minutes}分钟前`, fullTime, needRefresh: true }
+ }
+
+ // 24小时内
+ if (absDiff < 24 * 60 * 60 * 1000) {
+ const hours = Math.floor(absDiff / (60 * 60 * 1000))
+ const minutes = Math.floor((absDiff % (60 * 60 * 1000)) / (60 * 1000))
+ if (minutes > 0) {
+ return { displayText: `${hours}小时${minutes}分钟前`, fullTime, needRefresh: true }
+ }
+ return { displayText: `${hours}小时前`, fullTime, needRefresh: true }
+ }
+
+ // 2天内(昨天/前天)
+ if (absDiff < 2 * 24 * 60 * 60 * 1000) {
+ return { displayText: '1天前', fullTime, needRefresh: false }
+ }
+
+ // 7天内
+ if (absDiff < 7 * 24 * 60 * 60 * 1000) {
+ const days = Math.floor(absDiff / (24 * 60 * 60 * 1000))
+ return { displayText: `${days}天前`, fullTime, needRefresh: false }
+ }
+
+ // 超过7天:显示 MM-DD HH:mm
+ return { displayText: formatShortDate(date), fullTime, needRefresh: false }
+}
+
+/** 格式化完整时间 yyyy-MM-dd HH:mm:ss */
+function formatFullTime(date: Date): string {
+ const y = date.getFullYear()
+ const m = String(date.getMonth() + 1).padStart(2, '0')
+ const d = String(date.getDate()).padStart(2, '0')
+ const h = String(date.getHours()).padStart(2, '0')
+ const min = String(date.getMinutes()).padStart(2, '0')
+ const s = String(date.getSeconds()).padStart(2, '0')
+ return `${y}-${m}-${d} ${h}:${min}:${s}`
+}
+
+/** 格式化短日期 MM-DD HH:mm */
+function formatShortDate(date: Date): string {
+ const m = String(date.getMonth() + 1).padStart(2, '0')
+ const d = String(date.getDate()).padStart(2, '0')
+ const h = String(date.getHours()).padStart(2, '0')
+ const min = String(date.getMinutes()).padStart(2, '0')
+ return `${m}-${d} ${h}:${min}`
+}