新增: 初始化 DevFlow 项目仓库

Tauri 2 + Vue 3 + Vite 6 桌面应用,Rust workspace 含 13 个 crate
(df-ai / df-storage / df-workflow / df-core / df-execute 等)。
核心能力:AI 聊天 agentic 循环(工具调用+人工审批)、工作流引擎、
任务/想法/项目/阶段管理、可追溯性,及配套前端组件。
This commit is contained in:
2026-06-12 01:31:05 +08:00
commit 98393b4908
178 changed files with 27859 additions and 0 deletions

52
src/utils/time.ts Normal file
View File

@@ -0,0 +1,52 @@
/**
* 统一时间戳解析与格式化 — 根治前端时间显示 NaN 问题
*
* 后端 (df-storage) 统一以「毫秒数字字符串」存储 created_at / updated_at
* (见 src-tauri now_millis`SystemTime::now().as_millis().to_string()`)。
*
* 陷阱:`new Date("1718000000000")` 返回 Invalid Date —— JS 规范只对 number 类型
* 按时间戳解析,纯数字字符串走日期字符串解析路径会失败 → getTime() = NaN
* → `"{n} 天前".format(NaN)` = "NaN 天前"。
*
* 正确做法:先转 number 再 new Date。本模块统一处理毫秒字符串 / 秒级 / ISO / number / 空。
*/
/** 解析任意时间值为毫秒时间戳;无效或空返回 null */
export function parseTs(v: string | number | null | undefined): number | null {
if (v == null) return null
if (typeof v === 'number') {
if (!Number.isFinite(v)) return null
return v > 1e12 ? v : v * 1000 // 秒级 → 毫秒
}
const s = String(v).trim()
if (!s) return null
// 纯数字字符串:> 1e12 视为毫秒,否则秒
if (/^\d+$/.test(s)) {
const n = Number(s)
return n > 1e12 ? n : n * 1000
}
// ISO / 其他日期字符串
const ms = new Date(s).getTime()
return isNaN(ms) ? null : ms
}
/** 绝对日期 'YYYY/MM/DD HH:mm';无效返回 '—' */
export function formatDate(v: string | number | null | undefined): string {
const ms = parseTs(v)
if (ms == null) return '—'
const d = new Date(ms)
return d.toLocaleDateString('zh-CN') + ' ' + d.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
}
/** 中文相对时间 '刚刚 / X 分钟前 / X 小时前 / X 天前';无效返回 '—' */
export function formatRelativeZh(v: string | number | null | undefined): string {
const ms = parseTs(v)
if (ms == null) return '—'
const diffMin = Math.floor((Date.now() - ms) / 60000)
if (diffMin < 1) return '刚刚'
if (diffMin < 60) return `${diffMin} 分钟前`
const diffH = Math.floor(diffMin / 60)
if (diffH < 24) return `${diffH} 小时前`
const diffD = Math.floor(diffH / 24)
return `${diffD} 天前`
}