feat(analytics): persona logging upgrade and Sentry system config
Add client-logging SDK, expanded event taxonomy, API observability, admin domain events UI, and move SENTRY_DSN to HQ system settings with @sentry/node bootstrap after config preload. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,7 +17,7 @@ import {
|
||||
message,
|
||||
} from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { USER_SOURCE_TYPE_LABELS, type UserSourceType } from '@dukang/shared-types';
|
||||
import { USER_SOURCE_TYPE_LABELS, resolveUserLogCategory, type UserSourceType } from '@dukang/shared-types';
|
||||
import { request, type AdminUserRow, type HqProfile, type Paginated } from '../lib/api';
|
||||
import { ORDER_STATUS_LABELS, fmtTime, maskPhone } from '../lib/constants';
|
||||
|
||||
@@ -30,6 +30,14 @@ type UserOrderRow = {
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
type UserBehaviorLog = {
|
||||
id: string;
|
||||
eventName: string;
|
||||
clientApp?: string | null;
|
||||
createdAt: string;
|
||||
extraJson?: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
type UserDetail = AdminUserRow & {
|
||||
wxUnionId?: string | null;
|
||||
cityPref?: Record<string, unknown> | null;
|
||||
@@ -72,6 +80,7 @@ export default function UsersPage() {
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(20);
|
||||
const [detail, setDetail] = useState<UserDetail | null>(null);
|
||||
const [behaviorLogs, setBehaviorLogs] = useState<UserBehaviorLog[]>([]);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||
const [deleteConfirm, setDeleteConfirm] = useState('');
|
||||
@@ -123,8 +132,14 @@ export default function UsersPage() {
|
||||
}, [location.state, location.pathname, navigate]);
|
||||
|
||||
async function openDetail(id: string) {
|
||||
const res = await request<UserDetail>(`/admin/users/${id}`);
|
||||
const [res, logs] = await Promise.all([
|
||||
request<UserDetail>(`/admin/users/${id}`),
|
||||
request<{ items: UserBehaviorLog[] }>(`/admin/logs/users?userId=${id}&pageSize=50`).catch(
|
||||
() => ({ items: [] as UserBehaviorLog[] }),
|
||||
),
|
||||
]);
|
||||
setDetail(res);
|
||||
setBehaviorLogs(logs.items ?? []);
|
||||
setDrawerOpen(true);
|
||||
}
|
||||
|
||||
@@ -437,6 +452,28 @@ export default function UsersPage() {
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<Typography.Title level={5} style={{ marginTop: 16 }}>
|
||||
行为时间线(最近 {behaviorLogs.length} 条)
|
||||
</Typography.Title>
|
||||
<Table
|
||||
size="small"
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
scroll={{ y: 200 }}
|
||||
dataSource={behaviorLogs}
|
||||
locale={{ emptyText: '暂无行为日志' }}
|
||||
columns={[
|
||||
{ title: '时间', dataIndex: 'createdAt', width: 160, render: (v) => fmtTime(v) },
|
||||
{
|
||||
title: '分类',
|
||||
width: 100,
|
||||
render: (_, r) => resolveUserLogCategory(r.eventName) ?? '—',
|
||||
},
|
||||
{ title: '事件', dataIndex: 'eventName' },
|
||||
{ title: '端', dataIndex: 'clientApp', width: 90 },
|
||||
]}
|
||||
/>
|
||||
|
||||
<Typography.Title level={5} style={{ marginTop: 16 }}>
|
||||
全部订单({detail.orders?.length ?? 0})
|
||||
</Typography.Title>
|
||||
|
||||
Reference in New Issue
Block a user