[feat]:[FL-160][系统日志页面一致性优化]

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
chengkai3
2026-06-20 08:13:50 +08:00
parent c9b2b332fd
commit 495c73cc9e
3 changed files with 68 additions and 19 deletions
+21
View File
@@ -240,3 +240,24 @@
- 风险与关注点: - 风险与关注点:
- 改动仅影响角色管理页前端弹窗尺寸和分页展示逻辑,不改变接口、schema、权限或 CRUD 语义。 - 改动仅影响角色管理页前端弹窗尺寸和分页展示逻辑,不改变接口、schema、权限或 CRUD 语义。
# Work Log - 系统日志页面一致性优化(FL-160)
- 背景:
- 系统日志页面需要严格对齐用户管理页的页面外层卡片、筛选表单、表格滚动和移动端卡片规范。
- 本次处理:
- 系统日志页外层容器改为与用户管理页一致的 `min-h-0 flex-1` 页面结构,并补齐 `.admin-syslog-page-card` flex 布局样式。
- 桌面筛选表单项由 Tailwind `min-w-*` 改为固定 `style={{ width: 260 }}`,与用户管理页筛选布局口径一致。
- 表格配置补齐 `tableLayout="fixed"`、分页最小 total 处理,并移除横向滚动,仅保留动态纵向滚动。
- 移动端日志卡片补齐与用户卡片一致的卡片头、标题信息、字段网格、详情省略提示和卡片头部主题样式。
- 验证:
- 基线:`npm --workspace web exec eslint src/app/admin/users/page.tsx src/app/admin/syslog/page.tsx` 通过,仅用户页存在 1 条既有 unused eslint-disable warning。
- 基线:`npm --workspace web exec tsc --noEmit` 通过。
- 修改后:`npm --workspace web exec eslint src/app/admin/syslog/page.tsx --max-warnings=0` 通过。
- 修改后:`npm --workspace web exec tsc --noEmit` 通过。
- 修改后:`npm --workspace web exec eslint src/app/admin/users/page.tsx src/app/admin/syslog/page.tsx` 通过,仍仅用户页 1 条既有 warning。
- 风险与关注点:
- 改动仅影响 `/admin/syslog` 前端展示、筛选排布、表格滚动和移动卡片视觉,不改变 `/api/v1/admin/audit-logs` 接口路径、请求/响应字段或权限语义。
+25 -19
View File
@@ -337,6 +337,12 @@ export default function AdminSyslogPage() {
key={log.id} key={log.id}
className="admin-syslog-log-card" className="admin-syslog-log-card"
size="small" size="small"
title={
<Space className="min-w-0" size={8}>
<Typography.Text strong>{log.username ?? "-"}</Typography.Text>
<Tag>{log.action}</Tag>
</Space>
}
> >
<Space direction="vertical" size={10} style={{ width: "100%" }}> <Space direction="vertical" size={10} style={{ width: "100%" }}>
<div className="admin-syslog-log-card-field"> <div className="admin-syslog-log-card-field">
@@ -346,22 +352,17 @@ export default function AdminSyslogPage() {
</Typography.Text> </Typography.Text>
</div> </div>
<div className="admin-syslog-log-card-field"> <div className="admin-syslog-log-card-field">
<Typography.Text type="secondary"></Typography.Text> <Typography.Text type="secondary"> ID</Typography.Text>
<Space size={6}> <Typography.Text code type="secondary" ellipsis={{ tooltip: log.user_id ?? "-" }}>
<span>{log.username ?? "-"}</span> {log.user_id ?? "-"}
<Typography.Text code type="secondary"> </Typography.Text>
{log.user_id ?? "-"}
</Typography.Text>
</Space>
</div>
<div className="admin-syslog-log-card-field">
<Typography.Text type="secondary"></Typography.Text>
<Tag>{log.action}</Tag>
</div> </div>
{log.detail && ( {log.detail && (
<div className="admin-syslog-log-card-field"> <div className="admin-syslog-log-card-field">
<Typography.Text type="secondary"></Typography.Text> <Typography.Text type="secondary"></Typography.Text>
<Typography.Text type="secondary">{log.detail}</Typography.Text> <Typography.Text type="secondary" ellipsis={{ tooltip: log.detail }}>
{log.detail}
</Typography.Text>
</div> </div>
)} )}
</Space> </Space>
@@ -405,8 +406,12 @@ export default function AdminSyslogPage() {
} }
return ( return (
<div className="flex flex-1 flex-col space-y-6"> <div className="flex min-h-0 flex-1 flex-col">
<AntCard ref={pageCardRef} title="系统日志" style={{ height: '100%' }}> <AntCard
ref={pageCardRef}
className="admin-syslog-page-card"
title="系统日志"
>
{viewMode === "card" ? ( {viewMode === "card" ? (
<Form layout="vertical" style={{ marginBottom: 16 }}> <Form layout="vertical" style={{ marginBottom: 16 }}>
<Form.Item label="动作"> <Form.Item label="动作">
@@ -453,7 +458,7 @@ export default function AdminSyslogPage() {
</Form> </Form>
) : ( ) : (
<Form layout="inline" style={{ rowGap: 12 }}> <Form layout="inline" style={{ rowGap: 12 }}>
<Form.Item label="动作" className="min-w-[280px]"> <Form.Item label="动作" style={{ width: 260 }}>
<Input <Input
allowClear allowClear
placeholder="按动作筛选(如 auth.login" placeholder="按动作筛选(如 auth.login"
@@ -461,7 +466,7 @@ export default function AdminSyslogPage() {
onChange={(event) => handleActionChange(event.target.value)} onChange={(event) => handleActionChange(event.target.value)}
/> />
</Form.Item> </Form.Item>
<Form.Item label="用户ID" className="min-w-[280px]"> <Form.Item label="用户ID" style={{ width: 260 }}>
<Input <Input
allowClear allowClear
placeholder="按用户ID筛选(如 openclaw" placeholder="按用户ID筛选(如 openclaw"
@@ -508,21 +513,22 @@ export default function AdminSyslogPage() {
columns={columns} columns={columns}
dataSource={logs} dataSource={logs}
loading={logsQuery.isFetching} loading={logsQuery.isFetching}
tableLayout="fixed"
pagination={{ pagination={{
current: currentPage, current: currentPage,
pageSize: PAGE_SIZE, pageSize: PAGE_SIZE,
total, total: Math.max(total, 1),
onChange: (page) => setOffset((page - 1) * PAGE_SIZE), onChange: (page) => setOffset((page - 1) * PAGE_SIZE),
showSizeChanger: false, showSizeChanger: false,
showQuickJumper: false, showQuickJumper: false,
showTotal: (value) => `${value}`, showTotal: () => `${total}`,
hideOnSinglePage: false, hideOnSinglePage: false,
style: { marginBottom: 0 }, style: { marginBottom: 0 },
}} }}
locale={{ locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无日志数据" />, emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无日志数据" />,
}} }}
scroll={{ x: 980, y: tableScrollY }} scroll={{ y: tableScrollY }}
/> />
</div> </div>
) : ( ) : (
+22
View File
@@ -892,6 +892,22 @@ body {
min-height: var(--admin-syslog-table-body-min-height, 180px); min-height: var(--admin-syslog-table-body-min-height, 180px);
} }
.admin-syslog-page-card {
display: flex;
flex: 1;
min-height: 0;
flex-direction: column;
}
.admin-syslog-page-card > .ant-card-body {
display: flex;
min-height: 0;
flex: 1;
flex-direction: column;
overflow-x: hidden;
overflow-y: auto;
}
.admin-syslog-card-view { .admin-syslog-card-view {
display: flex; display: flex;
min-height: 0; min-height: 0;
@@ -925,6 +941,12 @@ body {
box-shadow: 0 8px 18px color-mix(in srgb, var(--fquiz-theme-text-primary) 8%, transparent); box-shadow: 0 8px 18px color-mix(in srgb, var(--fquiz-theme-text-primary) 8%, transparent);
} }
.admin-syslog-log-card > .ant-card-head {
min-height: 44px;
border-bottom-color: color-mix(in srgb, var(--fquiz-theme-primary) 18%, var(--ant-color-border-secondary));
background: color-mix(in srgb, var(--fquiz-theme-primary) 6%, transparent);
}
.admin-syslog-log-card > .ant-card-body { .admin-syslog-log-card > .ant-card-body {
padding-block: 14px; padding-block: 14px;
} }