fix(admin-web): 时间渲染收口到 formatUtcTime,消灭 new Date().toLocaleString
review 发现 4 处仍用 new Date(v).toLocaleString 渲染后端 UTC 口径时间戳—— 正是 lib/format.ts 头注释明令消灭的反模式(SQLite 本地/非中国浏览器会差 8h, 生产靠 +00:00 偏移侥幸正确)。统一改用 formatUtcTime 按北京显示: - admins: last_login_at - audit-logs: created_at - devices: completed_at - dashboard/HomeStatsConfig: ops_stat_config.updated_at 均为 server_default now()/datetime.now(utc) 的 UTC 口径字段。 HomeStatsConfig 的「下个更新时刻」用 epoch ms + 强制 Asia/Shanghai,正确,不动。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { Button, Form, Input, Modal, Select, Table, Tag, message } from 'antd';
|
||||
import { api, errMsg } from '@/lib/api';
|
||||
import { formatUtcTime } from '@/lib/format';
|
||||
import type { AdminInfo } from '@/lib/types';
|
||||
|
||||
const ROLES = [
|
||||
@@ -11,7 +12,8 @@ const ROLES = [
|
||||
{ value: 'finance', label: 'finance' },
|
||||
{ value: 'operator', label: 'operator' },
|
||||
];
|
||||
const dt = (v: string | null) => (v ? new Date(v).toLocaleString('zh-CN') : '从未');
|
||||
// last_login_at 为 UTC 口径(datetime.now(utc)),按北京显示(勿用 new Date().toLocaleString)
|
||||
const dt = (v: string | null) => (v ? formatUtcTime(v, 'YYYY-MM-DD HH:mm:ss') : '从未');
|
||||
|
||||
export default function AdminsPage() {
|
||||
const [admins, setAdmins] = useState<AdminInfo[]>([]);
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
import { useState } from 'react';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { Button, Input, Space, Table, Tag } from 'antd';
|
||||
import { formatUtcTime } from '@/lib/format';
|
||||
import { useCursorList } from '@/lib/useCursorList';
|
||||
import type { AuditLog } from '@/lib/types';
|
||||
|
||||
const dt = (v: string) => new Date(v).toLocaleString('zh-CN');
|
||||
// 审计 created_at 为 UTC 口径(server_default now()),按北京显示(勿用 new Date().toLocaleString)
|
||||
const dt = (v: string) => formatUtcTime(v, 'YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
export default function AuditLogsPage() {
|
||||
const [action, setAction] = useState('');
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
message,
|
||||
} from 'antd';
|
||||
import { api, errMsg } from '@/lib/api';
|
||||
import { formatUtcTime } from '@/lib/format';
|
||||
|
||||
interface StatItem {
|
||||
metric: string; // help_users / total_compares / total_saved
|
||||
@@ -601,7 +602,7 @@ export default function HomeStatsConfig() {
|
||||
</span>
|
||||
{it.updated_at && (
|
||||
<span style={{ color: '#bbb' }}>
|
||||
更新于 {new Date(it.updated_at).toLocaleString('zh-CN')}
|
||||
更新于 {formatUtcTime(it.updated_at, 'YYYY-MM-DD HH:mm:ss')}
|
||||
</span>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
@@ -4,10 +4,12 @@ import type { ColumnsType } from 'antd/es/table';
|
||||
import { Button, Modal, Popconfirm, Space, Table, message } from 'antd';
|
||||
import { api, errMsg } from '@/lib/api';
|
||||
import { canDo } from '@/lib/auth';
|
||||
import { formatUtcTime } from '@/lib/format';
|
||||
import { useCursorList } from '@/lib/useCursorList';
|
||||
import type { DeviceOnboardingItem } from '@/lib/types';
|
||||
|
||||
const dt = (v: string) => new Date(v).toLocaleString('zh-CN');
|
||||
// completed_at 为 UTC 口径(server_default now()),按北京显示(勿用 new Date().toLocaleString)
|
||||
const dt = (v: string) => formatUtcTime(v);
|
||||
const EMPTY: Record<string, unknown> = {};
|
||||
|
||||
export default function DevicesPage() {
|
||||
|
||||
Reference in New Issue
Block a user