- 详情 activities 排序改为按登记时间倒序,新增 reg_at 字段 - formatDateRange 同一天合并显示,字符数减半避免被截断 - DataTable 给活动名/时间/时长列显式宽度,时间列加 pl-3 留白防切
This commit is contained in:
@@ -747,23 +747,50 @@ export default function Users() {
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold mb-2 text-gray-800">
|
||||
参与的活动({detail.activities.length} 次)
|
||||
参与的活动({detail.activities.length} 次)<span className="ml-2 text-xs font-normal muted">按登记时间倒序,最新补录/登记在最上方</span>
|
||||
</h3>
|
||||
<DataTable
|
||||
columns={[
|
||||
{ key: 'title', title: '活动名称', render: (r: any) => <span className="font-medium">{r.title}</span> },
|
||||
{ key: 'time', title: '时间', render: (r: any) => formatDateRange(r.start_time, r.end_time) },
|
||||
{
|
||||
key: 'title',
|
||||
title: '活动名称',
|
||||
width: '30%',
|
||||
render: (r: any) => (
|
||||
<div className="font-medium leading-snug break-words max-w-[280px]">{r.title}</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'time',
|
||||
title: '活动时间',
|
||||
width: '240px',
|
||||
render: (r: any) => (
|
||||
<div className="text-xs font-mono tracking-wide leading-snug whitespace-nowrap pl-3 pr-2 text-gray-700 text-left">
|
||||
{formatDateRange(r.start_time, r.end_time)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'hours',
|
||||
title: '时长',
|
||||
width: '100px',
|
||||
render: (r: any) => (
|
||||
<span className="font-semibold text-primary-600">{Number(r.hours || 0).toFixed(1)}h</span>
|
||||
<span className="font-semibold text-primary-600 text-center block w-full text-sm">
|
||||
{Number(r.hours || 0).toFixed(1)}h
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'remark',
|
||||
title: '备注',
|
||||
render: (r: any) => (
|
||||
<div className="leading-relaxed break-words text-gray-700 pr-2">
|
||||
{r.remark || <span className="muted">—</span>}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{ key: 'remark', title: '备注', render: (r: any) => r.remark || '—' },
|
||||
]}
|
||||
data={detail.activities}
|
||||
rowKey={(r: any) => r.id}
|
||||
rowKey={(r: any) => `${r.id}-${r.reg_at || r.hours}-${r.remark || ''}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -271,9 +271,12 @@ export async function exportTableToImage(el: HTMLElement, filename: string) {
|
||||
}
|
||||
|
||||
export function formatDateRange(s: string, e: string) {
|
||||
const a = s?.replace('T', ' ')?.slice(0, 16);
|
||||
const b = e?.replace('T', ' ')?.slice(0, 16);
|
||||
return `${a || ''} ~ ${b || ''}`;
|
||||
const a = s?.replace('T', ' ')?.slice(0, 16) || '';
|
||||
const b = e?.replace('T', ' ')?.slice(0, 16) || '';
|
||||
if (a && b && a.slice(0, 10) === b.slice(0, 10)) {
|
||||
return `${a} ~ ${b.slice(11)}`;
|
||||
}
|
||||
return `${a} ~ ${b}`;
|
||||
}
|
||||
|
||||
export function formatCnDateTime(s?: string | null, withSeconds = false): string {
|
||||
|
||||
@@ -76,11 +76,11 @@ router.get('/:id', (req: Request, res: Response) => {
|
||||
if (!raw) return res.status(404).json({ error: '部员不存在' });
|
||||
const user = enrichUser(raw);
|
||||
const activities = db.prepareCompat(`
|
||||
SELECT a.id, a.title, a.start_time, a.end_time, h.hours, h.remark
|
||||
SELECT a.id, a.title, a.start_time, a.end_time, h.hours, h.remark, h.created_at AS reg_at
|
||||
FROM hours h
|
||||
JOIN activities a ON h.activity_id = a.id
|
||||
WHERE h.user_id = ?
|
||||
ORDER BY a.start_time DESC
|
||||
ORDER BY h.created_at DESC, a.start_time DESC
|
||||
`).all(id);
|
||||
res.json({ ...user, activities });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user