feat: add Chinese labels for admin learning data pages
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 10s
All checks were successful
Deploy Admin Frontend / build-and-deploy (push) Successful in 10s
- New constants/labels.ts with all enum → Chinese mappings - DataPages.tsx: all render() functions use labels - Dashboard.tsx: eventType shows Chinese - LearningData.tsx: session status shows Chinese - Filter dropdowns also show Chinese options Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
5de0b0ecaf
commit
60b6100466
46
src/constants/labels.ts
Normal file
46
src/constants/labels.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// ── Admin learning data display labels ──
|
||||
|
||||
export const eventTypeLabels: Record<string, string> = {
|
||||
material_opened: '打开资料',
|
||||
material_closed: '关闭资料',
|
||||
position_changed: '位置变化',
|
||||
heartbeat: '心跳',
|
||||
marked_as_read: '标记已读',
|
||||
};
|
||||
|
||||
export const eventStatusLabels: Record<string, string> = {
|
||||
processed: '已处理',
|
||||
failed: '失败',
|
||||
duplicate: '重复',
|
||||
pending: '待处理',
|
||||
warning: '警告',
|
||||
};
|
||||
|
||||
export const sessionStatusLabels: Record<string, string> = {
|
||||
active: '活跃',
|
||||
interrupted: '中断',
|
||||
completed: '已完成',
|
||||
};
|
||||
|
||||
export const progressStatusLabels: Record<string, string> = {
|
||||
reading: '阅读中',
|
||||
completed: '已完成',
|
||||
not_started: '未开始',
|
||||
};
|
||||
|
||||
export const targetTypeLabels: Record<string, string> = {
|
||||
knowledge_source: '知识资料',
|
||||
temporary_file: '临时文件',
|
||||
};
|
||||
|
||||
export const recordTypeLabels: Record<string, string> = {
|
||||
reading: '阅读',
|
||||
session: '会话',
|
||||
};
|
||||
|
||||
export const parseStatusLabels: Record<string, string> = {
|
||||
pending: '待解析',
|
||||
processing: '解析中',
|
||||
completed: '已解析',
|
||||
failed: '解析失败',
|
||||
};
|
||||
@ -3,6 +3,7 @@ import { Table, Tabs, Tag, Space, Input, Typography } from 'antd'
|
||||
import { SearchOutlined } from '@ant-design/icons'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { api } from '@/services/http-client'
|
||||
import { sessionStatusLabels } from '@/constants/labels'
|
||||
|
||||
const { Title } = Typography
|
||||
|
||||
@ -47,7 +48,7 @@ export default function LearningData() {
|
||||
{ title: '用户', dataIndex: 'userId', width: 100, ellipsis: true },
|
||||
{ title: '知识库', dataIndex: 'knowledgeBaseId', width: 100, ellipsis: true },
|
||||
{ title: '模式', dataIndex: 'mode', width: 80 },
|
||||
{ title: '状态', dataIndex: 'status', width: 80, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{s}</Tag> },
|
||||
{ title: '状态', dataIndex: 'status', width: 80, render: (s: string) => <Tag color={statusColors[s] || 'default'}>{sessionStatusLabels[s] || s}</Tag> },
|
||||
{ title: '时长(分)', dataIndex: 'durationSeconds', width: 80, render: (s: number) => s ? Math.round(s / 60) : '-' },
|
||||
{ title: '开始时间', dataIndex: 'startedAt', width: 120, render: (d: string) => d ? new Date(d).toLocaleString() : '-' },
|
||||
{ title: '结束时间', dataIndex: 'endedAt', width: 120, render: (d: string) => d ? new Date(d).toLocaleString() : '-' },
|
||||
|
||||
@ -4,6 +4,7 @@ import { BookOutlined, ThunderboltOutlined, UserOutlined, WarningOutlined, Check
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
import { learningAdminAPI } from '../../services/learningAdmin';
|
||||
import { eventTypeLabels } from '../../constants/labels';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
@ -36,7 +37,7 @@ export default function DashboardPage() {
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', ellipsis: true, width: 120 },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', ellipsis: true, width: 120 },
|
||||
{ title: '类型', dataIndex: 'eventType', key: 'eventType', width: 110,
|
||||
render: (t: string) => <Tag>{t}</Tag> },
|
||||
render: (t: string) => <Tag>{eventTypeLabels[t] || t}</Tag> },
|
||||
{ title: '错误码', dataIndex: 'errorCode', key: 'errorCode', width: 140,
|
||||
render: (c?: string) => c ? <Tag color="red">{c}</Tag> : '-' },
|
||||
{ title: '时间', dataIndex: 'occurredAt', key: 'occurredAt', width: 160,
|
||||
|
||||
@ -4,6 +4,7 @@ import { Table, Input, Select, Space, Tag, Button, Tabs, Drawer, Descriptions, D
|
||||
const { Text } = Typography;
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { learningAdminAPI } from '../../services/learningAdmin';
|
||||
import { eventTypeLabels, eventStatusLabels, sessionStatusLabels, progressStatusLabels, targetTypeLabels, recordTypeLabels } from '../../constants/labels';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
@ -39,10 +40,10 @@ export function ReadingEventPage() {
|
||||
{ title: '事件ID', dataIndex: 'eventId', key: 'eventId', width: 120, ellipsis: true },
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', width: 100, ellipsis: true },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', width: 100, ellipsis: true },
|
||||
{ title: '类型', dataIndex: 'eventType', key: 'eventType', width: 120, render: (t: string) => <Tag>{t}</Tag> },
|
||||
{ title: '类型', dataIndex: 'eventType', key: 'eventType', width: 120, render: (t: string) => <Tag>{eventTypeLabels[t] || t}</Tag> },
|
||||
{ title: 'Delta(s)', dataIndex: 'activeSecondsDelta', key: 'delta', width: 70 },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 90,
|
||||
render: (s: string) => <Tag color={s === 'processed' ? 'green' : s === 'failed' ? 'red' : s === 'duplicate' ? 'orange' : 'blue'}>{s}</Tag> },
|
||||
render: (s: string) => <Tag color={s === 'processed' ? 'green' : s === 'failed' ? 'red' : s === 'duplicate' ? 'orange' : 'blue'}>{eventStatusLabels[s] || s}</Tag> },
|
||||
{ title: '时间', dataIndex: 'createdAt', key: 'createdAt', width: 160,
|
||||
render: (t: string) => t ? dayjs(t).format('MM-DD HH:mm:ss') : '-' },
|
||||
];
|
||||
@ -54,7 +55,7 @@ export function ReadingEventPage() {
|
||||
<Input placeholder="资料ID" allowClear onChange={e => setFilters(f => ({ ...f, materialId: e.target.value }))} style={{ width: 140 }} />
|
||||
<Input placeholder="Client Session ID" allowClear onChange={e => setFilters(f => ({ ...f, clientSessionId: e.target.value }))} style={{ width: 170 }} />
|
||||
<Select placeholder="事件类型" allowClear style={{ width: 130 }} onChange={v => setFilters(f => ({ ...f, eventType: v || '' }))}
|
||||
options={['material_opened','material_closed','position_changed','heartbeat','marked_as_read'].map(t => ({ value: t, label: t }))} />
|
||||
options={Object.entries(eventTypeLabels).map(([v, l]) => ({ value: v, label: l }))} />
|
||||
<Select placeholder="状态" allowClear style={{ width: 110 }} onChange={v => setFilters(f => ({ ...f, status: v || '' }))}
|
||||
options={[{ value: 'processed', label: '已处理' }, { value: 'failed', label: '失败' }, { value: 'duplicate', label: '重复' }, { value: 'pending', label: '待处理' }]} />
|
||||
<RangePicker
|
||||
@ -120,11 +121,11 @@ export function SessionPage() {
|
||||
{ title: 'Client ID', dataIndex: 'clientSessionId', key: 'clientId', width: 140, ellipsis: true, render: (v?: string) => v?.slice(0, 12) || '-' },
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', width: 90, ellipsis: true },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', width: 90, ellipsis: true },
|
||||
{ title: '类型', dataIndex: 'targetType', key: 'targetType', width: 80, render: (v?: string) => v ? <Tag>{v}</Tag> : '-' },
|
||||
{ title: '类型', dataIndex: 'targetType', key: 'targetType', width: 80, render: (v?: string) => v ? <Tag>{targetTypeLabels[v] || v}</Tag> : '-' },
|
||||
{ title: '模式', dataIndex: 'mode', key: 'mode', width: 70, render: (v?: string) => v || '-' },
|
||||
{ title: 'KB', dataIndex: 'knowledgeBaseId', key: 'kbId', width: 80, ellipsis: true, render: (v?: string) => v?.slice(0, 8) || '-' },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 90,
|
||||
render: (s: string) => <Tag color={s === 'active' ? 'green' : s === 'interrupted' ? 'red' : s === 'completed' ? 'blue' : 'orange'}>{s}</Tag> },
|
||||
render: (s: string) => <Tag color={s === 'active' ? 'green' : s === 'interrupted' ? 'red' : s === 'completed' ? 'blue' : 'orange'}>{sessionStatusLabels[s] || s}</Tag> },
|
||||
{ title: '时长(s)', dataIndex: 'totalActiveSeconds', key: 'seconds', width: 70 },
|
||||
{ title: '专注(分)', dataIndex: 'focusMinutes', key: 'focus', width: 70, render: (v?: number) => v ?? '-' },
|
||||
{ title: '开始', dataIndex: 'startedAt', key: 'startedAt', width: 150, render: (t: string) => t ? dayjs(t).format('MM-DD HH:mm') : '-' },
|
||||
@ -193,10 +194,10 @@ export function ProgressPage() {
|
||||
const columns = [
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', width: 90, ellipsis: true },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', width: 110, ellipsis: true },
|
||||
{ title: '目标类型', dataIndex: 'readingTargetType', key: 'targetType', width: 85, render: (v?: string) => v ? <Tag>{v}</Tag> : '-' },
|
||||
{ title: '目标类型', dataIndex: 'readingTargetType', key: 'targetType', width: 85, render: (v?: string) => v ? <Tag>{targetTypeLabels[v] || v}</Tag> : '-' },
|
||||
{ title: '知识库', dataIndex: 'knowledgeBaseId', key: 'kbId', width: 75, ellipsis: true, render: (v?: string) => v?.slice(0,8) || '-' },
|
||||
{ title: 'Session', dataIndex: 'lastClientSessionId', key: 'sessionId', width: 120, ellipsis: true, render: (v?: string) => v?.slice(0,16) || '-' },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 85, render: (s: string) => <Tag color={s === 'reading' ? 'blue' : s === 'completed' ? 'green' : 'orange'}>{s}</Tag> },
|
||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 85, render: (s: string) => <Tag color={s === 'reading' ? 'blue' : s === 'completed' ? 'green' : 'orange'}>{progressStatusLabels[s] || s}</Tag> },
|
||||
{ title: '进度', dataIndex: 'lastProgress', key: 'progress', width: 65, render: (v: number) => v != null ? `${Math.round(v * 100)}%` : '-' },
|
||||
{ title: '位置', dataIndex: 'lastPosition', key: 'position', width: 100, ellipsis: true, render: (v?: object) => v ? JSON.stringify(v).slice(0,20) : '-' },
|
||||
{ title: '活跃秒', dataIndex: 'totalActiveSeconds', key: 'seconds', width: 70 },
|
||||
@ -320,7 +321,7 @@ export function RecordPage() {
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', width: 90, ellipsis: true },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', width: 100, ellipsis: true, render: (v?: string) => v?.slice(0,12) || '-' },
|
||||
{ title: '标题', dataIndex: 'title', key: 'title', width: 180 },
|
||||
{ title: '类型', dataIndex: 'recordType', key: 'recordType', width: 100, render: (t: string) => <Tag>{t}</Tag> },
|
||||
{ title: '类型', dataIndex: 'recordType', key: 'recordType', width: 100, render: (t: string) => <Tag>{recordTypeLabels[t] || t}</Tag> },
|
||||
{ title: '时长', dataIndex: 'durationSeconds', key: 'duration', width: 80 },
|
||||
{ title: '时间', dataIndex: 'occurredAt', key: 'occurredAt', width: 160, render: (t: string) => t ? dayjs(t).format('MM-DD HH:mm') : '-' },
|
||||
];
|
||||
@ -377,7 +378,7 @@ export function AnomalyPage() {
|
||||
{ title: '事件ID', dataIndex: 'eventId', key: 'eventId', width: 120, ellipsis: true },
|
||||
{ title: '用户', dataIndex: 'userId', key: 'userId', width: 100, ellipsis: true },
|
||||
{ title: '资料', dataIndex: 'materialId', key: 'materialId', width: 100, ellipsis: true },
|
||||
{ title: '事件类型', dataIndex: 'eventType', key: 'eventType', width: 120, render: (t: string) => <Tag>{t}</Tag> },
|
||||
{ title: '事件类型', dataIndex: 'eventType', key: 'eventType', width: 120, render: (t: string) => <Tag>{eventTypeLabels[t] || t}</Tag> },
|
||||
{ title: '错误码', dataIndex: 'errorCode', key: 'errorCode', width: 140,
|
||||
render: (c?: string) => c ? <Tag color="red">{c}</Tag> : '-' },
|
||||
{ title: '时间', dataIndex: 'createdAt', key: 'createdAt', width: 160,
|
||||
@ -444,7 +445,7 @@ export function UserTimelinePage() {
|
||||
children: (
|
||||
<div>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>{entry.occurredAt ? dayjs(entry.occurredAt).format('YYYY-MM-DD HH:mm:ss') : '-'}</Text>
|
||||
<div><Tag style={{ marginTop: 4 }}>{entry.recordType}</Tag></div>
|
||||
<div><Tag style={{ marginTop: 4 }}>{recordTypeLabels[entry.recordType] || entry.recordType}</Tag></div>
|
||||
<Text strong>{entry.title || '-'}</Text>
|
||||
{entry.durationSeconds != null && <div><Text type="secondary">时长 {entry.durationSeconds}s</Text></div>}
|
||||
{entry.materialId && <div><Text type="secondary">资料 {entry.materialId}</Text></div>}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user