diff --git a/client/src/pages/admin/Users.tsx b/client/src/pages/admin/Users.tsx
index 025e2d9..f0b2ea5 100644
--- a/client/src/pages/admin/Users.tsx
+++ b/client/src/pages/admin/Users.tsx
@@ -749,49 +749,61 @@ export default function Users() {
参与的活动({detail.activities.length} 次)按登记时间倒序,最新补录/登记在最上方
- (
- {r.title}
- ),
- },
- {
- key: 'time',
- title: '活动时间',
- width: '240px',
- render: (r: any) => (
-
- {formatDateRange(r.start_time, r.end_time)}
-
- ),
- },
- {
- key: 'hours',
- title: '时长',
- width: '100px',
- render: (r: any) => (
-
- {Number(r.hours || 0).toFixed(1)}h
-
- ),
- },
- {
- key: 'remark',
- title: '备注',
- render: (r: any) => (
-
- {r.remark || —}
-
- ),
- },
- ]}
- data={detail.activities}
- rowKey={(r: any) => `${r.id}-${r.reg_at || r.hours}-${r.remark || ''}`}
- />
+
+
(
+ {r.title}
+ ),
+ },
+ {
+ key: 'time',
+ title: '活动时间',
+ width: '240px',
+ render: (r: any) => (
+
+ {formatDateRange(r.start_time, r.end_time)}
+
+ ),
+ },
+ {
+ key: 'hours',
+ title: '时长',
+ width: '100px',
+ render: (r: any) => (
+
+ {Number(r.hours || 0).toFixed(1)}h
+
+ ),
+ },
+ {
+ key: 'remark',
+ title: '备注',
+ render: (r: any) => (
+
+ {r.remark || —}
+
+ ),
+ },
+ ]}
+ data={detail.activities}
+ rowKey={(r: any) => `${r.id}-${r.reg_at || r.hours}-${r.remark || ''}`}
+ />
+ {detail.activities.length > 0 && (
+
+
+ 本页列表合计 (应等于上方卡片的累计时长)
+
+
+ {detail.activities.reduce((s: number, r: any) => s + Number(r.hours || 0), 0).toFixed(1)}h
+
+
+ )}
+
)}
diff --git a/server/src/routes/users.ts b/server/src/routes/users.ts
index 551fc1b..be319ca 100644
--- a/server/src/routes/users.ts
+++ b/server/src/routes/users.ts
@@ -82,6 +82,8 @@ router.get('/:id', (req: Request, res: Response) => {
WHERE h.user_id = ?
ORDER BY h.created_at DESC, a.start_time DESC
`).all(id);
+ const listSum = activities.reduce((s, r) => s + Number(r.hours || 0), 0);
+ user.total_hours = Number(listSum.toFixed(1));
res.json({ ...user, activities });
});