fix: 项目表格列优化 — 描述列可见、标题简化、操作列自适应宽度

This commit is contained in:
2026-05-29 23:32:12 +08:00
parent 10b3928bee
commit 83cf9eab94
5 changed files with 19 additions and 17 deletions

View File

@@ -46,7 +46,7 @@ bun run dev config.yaml
- **Admin管理台**:全局管理视角,包含总览和项目管理。默认入口,访问 `/` 即可进入。
- **Workbench工作台**:项目维度视角,通过 `/workbench/:projectId` 进入指定项目的工作台。URL 可保存为浏览器书签,下次直接进入。仅 active 状态的项目可进入工作台archived 项目不可访问。
从项目管理页面的 active 项目行可点击"进入工作台"跳转到对应项目的工作台。
从项目管理页面的 active 项目行可点击"工作台"跳转到对应项目的工作台。
## 模型管理

View File

@@ -4,7 +4,7 @@ import { DeleteOutlined, EditOutlined, InboxOutlined, LoginOutlined, RedoOutline
import { App as AntApp, Button, Popconfirm, Space, Table, Tag } from "antd";
import { useNavigate } from "react-router";
import type { Project, ProjectListResponse } from "../../../../shared/api";
import type { Project, ProjectListResponse, ProjectStatus } from "../../../../shared/api";
interface ProjectTableProps {
data: ProjectListResponse | undefined;
@@ -16,11 +16,12 @@ interface ProjectTableProps {
onRestore: (id: string) => Promise<unknown>;
page: number;
pageSize: number;
status: ProjectStatus;
}
const COLUMNS: ColumnsType<Project> = [
{ dataIndex: "name", ellipsis: true, title: "项目名称", width: 160 },
{ dataIndex: "description", ellipsis: true, title: "项目描述" },
{ dataIndex: "name", ellipsis: true, title: "名称", width: 140 },
{ dataIndex: "description", ellipsis: true, title: "描述" },
{
align: "center",
dataIndex: "status",
@@ -31,21 +32,21 @@ const COLUMNS: ColumnsType<Project> = [
return <Tag color="blue"></Tag>;
},
title: "状态",
width: 100,
width: 90,
},
{
align: "center",
dataIndex: "createdAt",
render: (_value, record: Project) => formatDatetime(record.createdAt),
title: "创建时间",
width: 185,
width: 180,
},
{
align: "center",
dataIndex: "updatedAt",
render: (_value, record: Project) => formatDatetime(record.updatedAt),
title: "更新时间",
width: 185,
width: 180,
},
];
@@ -59,6 +60,7 @@ export function ProjectTable({
onRestore,
page,
pageSize,
status,
}: ProjectTableProps) {
const { message } = AntApp.useApp();
const navigate = useNavigate();
@@ -92,7 +94,6 @@ export function ProjectTable({
const operationColumn: ColumnsType<Project>[number] = {
dataIndex: "op",
fixed: "right",
render: (_value, record: Project) => {
if (record.status === "active") {
return (
@@ -103,7 +104,7 @@ export function ProjectTable({
size="small"
type="link"
>
</Button>
<Button icon={<EditOutlined />} onClick={() => onEdit(record)} size="small" type="link">
@@ -140,7 +141,7 @@ export function ProjectTable({
);
},
title: "操作",
width: 280,
width: status === "active" ? 260 : 160,
};
return (
@@ -157,7 +158,6 @@ export function ProjectTable({
total: data?.total ?? 0,
}}
rowKey="id"
scroll={{ x: 900 }}
/>
);
}

View File

@@ -41,7 +41,7 @@ export function ProjectToolbar({
onSearchClear();
}}
onSearch={(value) => onSearch(value)}
placeholder="搜索项目名称或描述"
placeholder="搜索名称或描述"
value={draftKeyword}
/>
{activeTab === "active" && (

View File

@@ -73,6 +73,7 @@ export function ProjectsPage() {
onRestore={(id) => restoreMutation.mutateAsync(id)}
page={page}
pageSize={pageSize}
status={tabValue}
/>
<ProjectFormModal

View File

@@ -125,7 +125,7 @@ describe("ProjectsPage", () => {
expect(screen.getByText("已归档")).not.toBeNull();
expect(screen.getByRole("button", { name: /新建项目/ })).not.toBeNull();
expect(screen.getByPlaceholderText("搜索项目名称或描述")).not.toBeNull();
expect(screen.getByPlaceholderText("搜索名称或描述")).not.toBeNull();
expect(calls.some((call) => call.url.includes("status=active"))).toBe(true);
});
@@ -135,7 +135,7 @@ describe("ProjectsPage", () => {
renderWithProviders(createElement(App), { initialRoute: "/projects" });
await waitFor(() => expect(screen.getByText("活跃项目")).not.toBeNull());
fireEvent.change(screen.getByPlaceholderText("搜索项目名称或描述"), { target: { value: "归档" } });
fireEvent.change(screen.getByPlaceholderText("搜索名称或描述"), { target: { value: "归档" } });
fireEvent.click(screen.getByRole("button", { name: /搜\s*索/ }));
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=%E5%BD%92%E6%A1%A3"))).toBe(true));
fireEvent.click(screen.getByText("已归档"));
@@ -152,11 +152,11 @@ describe("ProjectsPage", () => {
renderWithProviders(createElement(App), { initialRoute: "/projects" });
await waitFor(() => expect(screen.getByText("活跃项目")).not.toBeNull());
fireEvent.change(screen.getByPlaceholderText("搜索项目名称或描述"), { target: { value: "归档" } });
fireEvent.change(screen.getByPlaceholderText("搜索名称或描述"), { target: { value: "归档" } });
fireEvent.click(screen.getByRole("button", { name: /搜\s*索/ }));
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=%E5%BD%92%E6%A1%A3"))).toBe(true));
fireEvent.change(screen.getByPlaceholderText("搜索项目名称或描述"), { target: { value: "" } });
fireEvent.change(screen.getByPlaceholderText("搜索名称或描述"), { target: { value: "" } });
fireEvent.click(screen.getByRole("button", { name: /搜\s*索/ }));
await waitFor(() => expect(screen.getByText("活跃项目")).not.toBeNull());
});
@@ -255,11 +255,12 @@ describe("ProjectsPage", () => {
onRestore,
page: 1,
pageSize: 20,
status: "active",
}),
),
);
fireEvent.click(screen.getByRole("button", { name: /进入工作台/ }));
fireEvent.click(screen.getByRole("button", { name: /工作台/ }));
expect(screen.getByText("当前路径:/workbench/p1")).not.toBeNull();
fireEvent.click(screen.getByRole("button", { name: /归档/ }));