130 lines
4.9 KiB
TypeScript
130 lines
4.9 KiB
TypeScript
import { useState } from 'react';
|
|
import { Button, Descriptions, Drawer, Form, Input, Select, Space, Table, Tag, Typography } from 'antd';
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
import { useAdminList } from '../lib/useAdminList';
|
|
import { request } from '../lib/api';
|
|
import { fmtTime } from '../lib/constants';
|
|
import type { WecomBotLogDto } from '@dukang/shared-types';
|
|
|
|
export default function WecomBotLogsPage() {
|
|
const [form] = Form.useForm();
|
|
const [filters, setFilters] = useState<Record<string, string>>({});
|
|
const [detail, setDetail] = useState<WecomBotLogDto | null>(null);
|
|
|
|
const { data, loading, page, pageSize, setPage, setPageSize } = useAdminList<WecomBotLogDto>(
|
|
'/admin/logs/wecom-bots',
|
|
() => {
|
|
const qs = new URLSearchParams();
|
|
if (filters.botId) qs.set('botId', filters.botId);
|
|
if (filters.wecomUserId) qs.set('wecomUserId', filters.wecomUserId);
|
|
if (filters.action) qs.set('action', filters.action);
|
|
if (filters.success) qs.set('success', filters.success);
|
|
return qs;
|
|
},
|
|
[filters],
|
|
);
|
|
|
|
const columns: ColumnsType<WecomBotLogDto> = [
|
|
{ title: '时间', dataIndex: 'createdAt', width: 160, render: fmtTime },
|
|
{ title: '机器人', dataIndex: 'botName', width: 120, ellipsis: true, render: (v, r) => v || r.botKey || '—' },
|
|
{ title: '企微用户', dataIndex: 'wecomUserId', width: 120, ellipsis: true },
|
|
{ title: '动作', dataIndex: 'action', width: 160, ellipsis: true },
|
|
{ title: '权限', dataIndex: 'permission', width: 140, ellipsis: true, render: (v) => v || '—' },
|
|
{
|
|
title: '结果',
|
|
dataIndex: 'success',
|
|
width: 80,
|
|
render: (v: boolean) => <Tag color={v ? 'green' : 'red'}>{v ? '成功' : '失败'}</Tag>,
|
|
},
|
|
{ title: '耗时(ms)', dataIndex: 'latencyMs', width: 90, render: (v) => v ?? '—' },
|
|
{ title: '输入摘要', dataIndex: 'inputSummary', ellipsis: true },
|
|
{
|
|
title: '操作',
|
|
width: 80,
|
|
render: (_, row) => (
|
|
<Button type="link" size="small" onClick={() => setDetail(row)}>
|
|
详情
|
|
</Button>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div>
|
|
<Typography.Title level={4}>企微机器人日志</Typography.Title>
|
|
<Typography.Paragraph type="secondary">
|
|
记录机器人在企微内的查询与审批操作,含权限点、耗时与成败。
|
|
</Typography.Paragraph>
|
|
|
|
<Form
|
|
form={form}
|
|
layout="inline"
|
|
style={{ marginBottom: 16 }}
|
|
onFinish={(v) => {
|
|
setFilters(v);
|
|
setPage(1);
|
|
}}
|
|
>
|
|
<Form.Item name="botId" label="机器人 ID">
|
|
<Input allowClear placeholder="wecom_bot.id" style={{ width: 140 }} />
|
|
</Form.Item>
|
|
<Form.Item name="wecomUserId" label="企微 userid">
|
|
<Input allowClear placeholder="userid" style={{ width: 140 }} />
|
|
</Form.Item>
|
|
<Form.Item name="action" label="动作">
|
|
<Input allowClear placeholder="order.read" style={{ width: 140 }} />
|
|
</Form.Item>
|
|
<Form.Item name="success" label="结果">
|
|
<Select
|
|
allowClear
|
|
style={{ width: 100 }}
|
|
options={[
|
|
{ value: 'true', label: '成功' },
|
|
{ value: 'false', label: '失败' },
|
|
]}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item>
|
|
<Button type="primary" htmlType="submit">
|
|
查询
|
|
</Button>
|
|
</Form.Item>
|
|
</Form>
|
|
|
|
<Table
|
|
rowKey="id"
|
|
loading={loading}
|
|
columns={columns}
|
|
dataSource={data?.items ?? []}
|
|
scroll={{ x: 1100 }}
|
|
pagination={{
|
|
current: page,
|
|
pageSize,
|
|
total: data?.total ?? 0,
|
|
showSizeChanger: true,
|
|
onChange: (p, ps) => {
|
|
setPage(p);
|
|
setPageSize(ps);
|
|
},
|
|
}}
|
|
/>
|
|
|
|
<Drawer title="日志详情" width={480} open={!!detail} onClose={() => setDetail(null)}>
|
|
{detail && (
|
|
<Descriptions column={1} size="small" bordered>
|
|
<Descriptions.Item label="时间">{fmtTime(detail.createdAt)}</Descriptions.Item>
|
|
<Descriptions.Item label="机器人">{detail.botName || detail.botKey || '—'}</Descriptions.Item>
|
|
<Descriptions.Item label="企微用户">{detail.wecomUserId}</Descriptions.Item>
|
|
<Descriptions.Item label="动作">{detail.action}</Descriptions.Item>
|
|
<Descriptions.Item label="权限">{detail.permission || '—'}</Descriptions.Item>
|
|
<Descriptions.Item label="输入摘要">{detail.inputSummary || '—'}</Descriptions.Item>
|
|
<Descriptions.Item label="结果">{detail.success ? '成功' : '失败'}</Descriptions.Item>
|
|
<Descriptions.Item label="错误">{detail.errorMessage || '—'}</Descriptions.Item>
|
|
<Descriptions.Item label="耗时">{detail.latencyMs != null ? `${detail.latencyMs} ms` : '—'}</Descriptions.Item>
|
|
</Descriptions>
|
|
)}
|
|
</Drawer>
|
|
</div>
|
|
);
|
|
}
|