feat(ui): 自研 Celadon 组件族入库与 AntD 消费全量替换 - base(Kbd/StatusBadge/IconButton/ToolButton)+product(EmptyState/Callout/SegmentedControl/Checkbox/Select/Tooltip/Switch), composio 视觉基底, globals.css 覆盖清理 (ADR-0008)

This commit is contained in:
maomaochong-ai
2026-09-06 20:28:51 +08:00
parent 30f58aaa08
commit 5c6612c5dd
128 changed files with 2791 additions and 737 deletions

View File

@@ -1,5 +1,5 @@
import type { ColumnsType } from "antd/es/table";
import { Eye, Pencil, Power } from "lucide-react";
import { Eye, Pencil, Power, Trash2 } from "lucide-react";
import { formatCredits } from "@/constant/credits";
import { IdentityProviderBadge } from "@/components/layout/identity-provider-badge";
@@ -24,12 +24,14 @@ export function createUserColumns({
onView,
onEdit,
onToggleStatus,
onPurge,
}: {
actorId?: string;
visibleColumns: Set<UserColumnKey>;
onView: (user: AdminUser) => void;
onEdit: (user: AdminUser) => void;
onToggleStatus: (user: AdminUser) => Promise<void>;
onPurge: (user: AdminUser) => void;
}): ColumnsType<AdminUser> {
const columns: Array<ColumnsType<AdminUser>[number] & { key: UserColumnKey }> = [
{
@@ -79,6 +81,19 @@ export function createUserColumns({
},
onClick: () => onToggleStatus(user),
},
{
key: "purge",
label: "删除用户",
icon: <Trash2 className="size-3.5" />,
danger: true,
disabled: user.id === actorId,
confirm: {
title: "彻底删除这个用户?",
description: "该账号及其全部关联数据将被永久移除且不可恢复。停用可保留数据,仅当账号无资金流水和创作内容时才允许删除。",
okText: "彻底删除",
},
onClick: () => onPurge(user),
},
]}
/>
),

View File

@@ -1,4 +1,5 @@
import { App, Button, Drawer, Form, Input, Select } from "antd";
import { App, Button, Drawer, Form, Input } from "antd";
import { Select } from "@/components/ui/base/select";
import { useEffect, useState } from "react";
import { createAdminUser, updateAdminUser, type AdminUser, type LocalUser } from "@/services/api/auth";

View File

@@ -1,10 +1,11 @@
import { App, Button, Checkbox, Dropdown, Input, Select } from "antd";
import { App, Button, Dropdown, Input, Select } from "antd";
import { Checkbox } from "@/components/ui/base/checkbox";
import { Ban, Search, Settings2, UserPlus } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { PaginationBar } from "@/components/layout/workspace-page";
import { useDebouncedValue } from "@/hooks/use-debounced-value";
import { bulkDisableAdminUsers, deleteAdminUser, listAdminUsers, updateAdminUser, type AdminUser, type LocalUser } from "@/services/api/auth";
import { bulkDisableAdminUsers, deleteAdminUser, listAdminUsers, purgeAdminUser, updateAdminUser, type AdminUser, type LocalUser } from "@/services/api/auth";
import { useUserStore } from "@/stores/use-user-store";
import { AdminBatchBar, AdminDataTable, AdminTableEmpty } from "../components/admin-ui";
import { useTableUrlState } from "../lib/use-table-url-state";
@@ -101,13 +102,27 @@ export default function UsersPanel({ onUserChanged }: { onUserChanged?: (user: L
}
}, [message, replaceUser]);
const purgeUser = useCallback(async (user: AdminUser) => {
try {
await purgeAdminUser(user.id);
setUsers((items) => items.filter((item) => item.id !== user.id));
setTotal((value) => Math.max(0, value - 1));
setSelectedUserIds((ids) => ids.filter((id) => id !== user.id));
if (detailUserId === user.id) setDetailUserId(null);
message.success(`用户 ${user.displayName || user.username} 已彻底删除`);
} catch (error) {
message.error(error instanceof Error ? error.message : "删除用户失败");
}
}, [detailUserId, message]);
const columns = useMemo(() => createUserColumns({
actorId: actor?.id,
visibleColumns,
onView: (user) => setDetailUserId(user.id),
onEdit: (user) => { setCreateUserOpen(false); setEditingUser(user); },
onToggleStatus: toggleStatus,
}), [actor?.id, toggleStatus, visibleColumns]);
onPurge: purgeUser,
}), [actor?.id, purgeUser, toggleStatus, visibleColumns]);
const resetFilters = () => update({ filter: "", role: "all", status: "all", page: 1 });
@@ -182,6 +197,7 @@ export default function UsersPanel({ onUserChanged }: { onUserChanged?: (user: L
{userColumnOptions.map((option) => (
<label key={option.key} className="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-sm hover:bg-muted/60">
<Checkbox
bare
checked={visibleColumns.has(option.key)}
disabled={option.locked}
onChange={(event) => setVisibleColumns((current) => {