feat(ADMIN-INFO-015): add userName render to userId columns across 8 pages
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 9s

- Billing, ChatLogs, ContentSafety, NotificationAdmin, SecurityEvents
- ComplianceAdmin (deletions + exports)
- MemberManagement (members + deletion requests)
- ComplianceAdmin status labels also fixed

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-19 13:07:59 +08:00
parent 7ebe092f3f
commit 5dd35a1c9f
7 changed files with 13 additions and 12 deletions

View File

@ -76,7 +76,7 @@ function BillingContent() {
] ]
const topUserCols = [ const topUserCols = [
{ title: '用户', dataIndex: 'userId', width: 180, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 180, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '调用量', dataIndex: 'calls', width: 80, align: 'center' as const }, { title: '调用量', dataIndex: 'calls', width: 80, align: 'center' as const },
{ title: 'Tokens', dataIndex: 'tokens', width: 100, align: 'center' as const, render: (v: number) => v.toLocaleString() }, { title: 'Tokens', dataIndex: 'tokens', width: 100, align: 'center' as const, render: (v: number) => v.toLocaleString() },
{ title: '成本', dataIndex: 'cost', width: 100, align: 'center' as const, render: (v: string) => <Text type="danger">${v}</Text> }, { title: '成本', dataIndex: 'cost', width: 100, align: 'center' as const, render: (v: string) => <Text type="danger">${v}</Text> },

View File

@ -42,7 +42,7 @@ export default function ChatLogsPage() {
pagination={{ pageSize: 20 }} size="small" pagination={{ pageSize: 20 }} size="small"
columns={[ columns={[
{ title: '标题', dataIndex: 'title', width: 200, ellipsis: true }, { title: '标题', dataIndex: 'title', width: 200, ellipsis: true },
{ title: '用户', dataIndex: 'userId', width: 140, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 140, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '知识库', dataIndex: 'knowledgeBaseId', width: 140, ellipsis: true }, { title: '知识库', dataIndex: 'knowledgeBaseId', width: 140, ellipsis: true },
{ title: '消息数', dataIndex: ['_count','messages'], width: 70, align: 'center' }, { title: '消息数', dataIndex: ['_count','messages'], width: 70, align: 'center' },
{ title: '更新时间', dataIndex: 'updatedAt', width: 140, render: (d: string) => dayjs(d).format('MM-DD HH:mm') }, { title: '更新时间', dataIndex: 'updatedAt', width: 140, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },

View File

@ -3,6 +3,7 @@ import { Table, Button, Modal, Form, Input, Tag, Typography, Tabs, DatePicker }
import { PlusOutlined, EditOutlined, SafetyOutlined, CheckOutlined } from '@ant-design/icons' import { PlusOutlined, EditOutlined, SafetyOutlined, CheckOutlined } from '@ant-design/icons'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { api } from '@/services/http-client' import { api } from '@/services/http-client'
import { complianceStatusLabels } from '@/constants/labels'
import { message } from 'antd' import { message } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -83,14 +84,14 @@ export default function ComplianceAdmin() {
const filingColumns = [ const filingColumns = [
{ title: '类型', dataIndex: 'type', width: 100 }, { title: '类型', dataIndex: 'type', width: 100 },
{ title: '标题', dataIndex: 'title', width: 200, ellipsis: true }, { title: '标题', dataIndex: 'title', width: 200, ellipsis: true },
{ title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag> }, { title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{complianceStatusLabels[s] || s}</Tag> },
{ title: '备注', dataIndex: 'notes', width: 200, ellipsis: true, render: (n: string) => n || '-' }, { title: '备注', dataIndex: 'notes', width: 200, ellipsis: true, render: (n: string) => n || '-' },
{ title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() }, { title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() },
] ]
const deletionColumns = [ const deletionColumns = [
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 100, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag> }, { title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{complianceStatusLabels[s] || s}</Tag> },
{ title: '申请时间', dataIndex: 'requestedAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() }, { title: '申请时间', dataIndex: 'requestedAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() },
{ title: '冷却结束', dataIndex: 'coolingEndsAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() }, { title: '冷却结束', dataIndex: 'coolingEndsAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() },
{ title: '操作', width: 60, render: (_: any, r: any) => r.status === 'pending' ? <Button size="small" type="primary" icon={<CheckOutlined />} onClick={() => approveDeletion.mutate(r.id)}></Button> : null }, { title: '操作', width: 60, render: (_: any, r: any) => r.status === 'pending' ? <Button size="small" type="primary" icon={<CheckOutlined />} onClick={() => approveDeletion.mutate(r.id)}></Button> : null },
@ -109,8 +110,8 @@ export default function ComplianceAdmin() {
{ key: 'filings', label: '备案台账', children: <div><Button type="primary" icon={<PlusOutlined />} onClick={() => openCreate('filing')} style={{ marginBottom: 16 }}></Button><Table dataSource={filings || []} columns={filingColumns} rowKey="id" loading={fLoading} size="small" /></div> }, { key: 'filings', label: '备案台账', children: <div><Button type="primary" icon={<PlusOutlined />} onClick={() => openCreate('filing')} style={{ marginBottom: 16 }}></Button><Table dataSource={filings || []} columns={filingColumns} rowKey="id" loading={fLoading} size="small" /></div> },
{ key: 'deletions', label: '数据删除', children: <Table dataSource={deletions || []} columns={deletionColumns} rowKey="id" loading={dLoading} size="small" /> }, { key: 'deletions', label: '数据删除', children: <Table dataSource={deletions || []} columns={deletionColumns} rowKey="id" loading={dLoading} size="small" /> },
{ key: 'exports', label: '数据导出', children: <Table dataSource={exports_ || []} columns={[ { key: 'exports', label: '数据导出', children: <Table dataSource={exports_ || []} columns={[
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 100, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag> }, { title: '状态', dataIndex: 'status', width: 70, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{complianceStatusLabels[s] || s}</Tag> },
{ title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() }, { title: '创建时间', dataIndex: 'createdAt', width: 110, render: (d: string) => new Date(d).toLocaleDateString() },
]} rowKey="id" loading={eLoading} size="small" /> }, ]} rowKey="id" loading={eLoading} size="small" /> },
{ key: 'security', label: '安全事件', children: <Table dataSource={securityEvents || []} columns={securityColumns} rowKey="id" loading={sLoading} size="small" /> }, { key: 'security', label: '安全事件', children: <Table dataSource={securityEvents || []} columns={securityColumns} rowKey="id" loading={sLoading} size="small" /> },

View File

@ -82,7 +82,7 @@ function CSPage() {
const violationCols = [ const violationCols = [
{ title: '时间', dataIndex: 'createdAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') }, { title: '时间', dataIndex: 'createdAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },
{ title: '用户', dataIndex: 'userId', width: 140, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 140, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '类型', dataIndex: 'contentType', width: 100 }, { title: '类型', dataIndex: 'contentType', width: 100 },
{ title: '内容', dataIndex: 'content', ellipsis: true, render: (v: string) => <Text style={{ fontSize: 12 }}>{v?.slice(0, 60)}</Text> }, { title: '内容', dataIndex: 'content', ellipsis: true, render: (v: string) => <Text style={{ fontSize: 12 }}>{v?.slice(0, 60)}</Text> },
{ title: '风险', dataIndex: 'riskLevel', width: 70, render: (v: string) => <Tag color={v==='critical'?'red':v==='high'?'orange':'blue'}>{v}</Tag> }, { title: '风险', dataIndex: 'riskLevel', width: 70, render: (v: string) => <Tag color={v==='critical'?'red':v==='high'?'orange':'blue'}>{v}</Tag> },

View File

@ -45,7 +45,7 @@ export default function MemberManagement() {
] ]
const membershipCols = [ const membershipCols = [
{ title: '用户ID', dataIndex: 'userId', width: 160, ellipsis: true }, { title: '用户ID', dataIndex: 'userId', width: 160, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '计划', dataIndex: ['plan', 'name'], width: 120, render: (_: any, r: any) => r.plan?.name || '-' }, { title: '计划', dataIndex: ['plan', 'name'], width: 120, render: (_: any, r: any) => r.plan?.name || '-' },
{ title: '开始', dataIndex: 'startedAt', width: 120, render: (d: string) => d ? dayjs(d).format('YYYY-MM-DD') : '-' }, { title: '开始', dataIndex: 'startedAt', width: 120, render: (d: string) => d ? dayjs(d).format('YYYY-MM-DD') : '-' },
{ title: '到期', dataIndex: 'expiresAt', width: 120, render: (d: string) => d ? dayjs(d).format('YYYY-MM-DD') : '永久' }, { title: '到期', dataIndex: 'expiresAt', width: 120, render: (d: string) => d ? dayjs(d).format('YYYY-MM-DD') : '永久' },
@ -53,7 +53,7 @@ export default function MemberManagement() {
] ]
const deletionCols = [ const deletionCols = [
{ title: '用户ID', dataIndex: 'userId', width: 160, ellipsis: true }, { title: '用户ID', dataIndex: 'userId', width: 160, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '状态', dataIndex: 'status', width: 80, render: (v: string) => v === 'pending' ? <Tag color="gold"></Tag> : v === 'completed' ? <Tag color="red"></Tag> : <Tag></Tag> }, { title: '状态', dataIndex: 'status', width: 80, render: (v: string) => v === 'pending' ? <Tag color="gold"></Tag> : v === 'completed' ? <Tag color="red"></Tag> : <Tag></Tag> },
{ title: '申请时间', dataIndex: 'requestedAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') }, { title: '申请时间', dataIndex: 'requestedAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },
{ title: '冷静期截止', dataIndex: 'coolingEndsAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') }, { title: '冷静期截止', dataIndex: 'coolingEndsAt', width: 130, render: (d: string) => dayjs(d).format('MM-DD HH:mm') },

View File

@ -89,7 +89,7 @@ export default function NotificationAdmin() {
const logColumns = [ const logColumns = [
{ title: 'ID', dataIndex: 'id', width: 100, ellipsis: true }, { title: 'ID', dataIndex: 'id', width: 100, ellipsis: true },
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 100, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '类型', dataIndex: 'type', width: 100 }, { title: '类型', dataIndex: 'type', width: 100 },
{ title: '标题', dataIndex: 'title', width: 200, ellipsis: true }, { title: '标题', dataIndex: 'title', width: 200, ellipsis: true },
{ {

View File

@ -13,7 +13,7 @@ export default function SecurityEventsPage() {
const cols = [ const cols = [
{ title: '时间', dataIndex: 'createdAt', width: 140, render: (d: string) => dayjs(d).format('MM-DD HH:mm:ss') }, { title: '时间', dataIndex: 'createdAt', width: 140, render: (d: string) => dayjs(d).format('MM-DD HH:mm:ss') },
{ title: '类型', dataIndex: 'contentType', width: 100 }, { title: '类型', dataIndex: 'contentType', width: 100 },
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true }, { title: '用户', dataIndex: 'userId', width: 100, ellipsis: true , render: (_: any, r: any) => r.userName || r.userId },
{ title: '风险', dataIndex: 'riskLevel', width: 70, render: (v: string) => <Tag color={v==='critical'?'red':v==='high'?'orange':'default'}>{v}</Tag> }, { title: '风险', dataIndex: 'riskLevel', width: 70, render: (v: string) => <Tag color={v==='critical'?'red':v==='high'?'orange':'default'}>{v}</Tag> },
{ title: '结果', dataIndex: 'result', width: 80, render: (v: string) => <Tag color={v==='passed'?'green':v==='blocked'?'red':'gold'}>{v}</Tag> }, { title: '结果', dataIndex: 'result', width: 80, render: (v: string) => <Tag color={v==='passed'?'green':v==='blocked'?'red':'gold'}>{v}</Tag> },
{ title: '匹配词', dataIndex: 'matchedWords', ellipsis: true, width: 150, render: (v: string) => v || '-' }, { title: '匹配词', dataIndex: 'matchedWords', ellipsis: true, width: 150, render: (v: string) => v || '-' },