diff --git a/app/components/ui/index.ts b/app/components/ui/index.ts index 853101a..919bddd 100644 --- a/app/components/ui/index.ts +++ b/app/components/ui/index.ts @@ -15,6 +15,7 @@ export { FileTag } from './FileTag'; export { FileTypeTag } from './FileTypeTag'; export { StatusBadge } from './StatusBadge'; export { StatusDot } from './StatusDot'; +export { Switch } from './Switch'; export { FileIcon } from './FileIcon'; // 数据输入组件 diff --git a/app/routes/rules.list.tsx b/app/routes/rules.list.tsx index 6f23c71..790e604 100644 --- a/app/routes/rules.list.tsx +++ b/app/routes/rules.list.tsx @@ -5,6 +5,7 @@ import { Button } from '~/components/ui/Button'; import { Card } from '~/components/ui/Card'; import { Tag } from '~/components/ui/Tag'; import { StatusDot } from '~/components/ui/StatusDot'; +import { Switch } from '~/components/ui/Switch'; import { TableRowSkeleton, LoadingIndicator, NumberSkeleton } from '~/components/ui/SkeletonScreen'; import rulesStyles from "~/styles/pages/rules_index.css?url"; import type { Rule, RuleType, RulePriority } from '~/models/rule'; @@ -23,6 +24,7 @@ import { getRuleGroupsByType, batchUpdateRuleStatus, batchDeleteRules, + updateEvaluationPoint, type RuleType as ApiRuleType, type RuleGroup } from '~/api/evaluation_points/rules'; @@ -225,6 +227,9 @@ export default function RulesIndex() { // 批量选择状态 const [selectedIds, setSelectedIds] = useState([]); + // 跟踪单个评查点状态更新时的加载状态 + const [updatingStatusIds, setUpdatingStatusIds] = useState>(new Set()); + // 使用 ref 跟踪是否正在加载数据,避免重复加载 const isLoadingRef = useRef(false); @@ -654,7 +659,62 @@ export default function RulesIndex() { const newParams = new URLSearchParams(); setSearchParams(newParams); }; - + + // 处理单个评查点状态切换 + const handleStatusChange = (rule: Rule) => { + // ✅ 检查更新权限 + if (!canUpdateRule) { + toastService.warning('您没有更新权限'); + return; + } + + // 如果正在更新,不处理 + if (updatingStatusIds.has(rule.id)) { + return; + } + + const newStatus = !rule.isActive; + const statusText = newStatus ? '启用' : '禁用'; + + messageService.show({ + title: "确认操作", + message: `确认要${statusText}评查点【${rule.name}】吗?`, + type: "warning", + confirmText: "确定", + cancelText: "取消", + onConfirm: async () => { + try { + // 添加到更新中的ID集合 + setUpdatingStatusIds(prev => new Set(prev).add(rule.id)); + + const response = await updateEvaluationPoint( + rule.id, + { is_enabled: newStatus }, + loaderData.frontendJWT + ); + + if (response.error) { + toastService.error(`${statusText}失败:${response.error}`); + } else { + toastService.success(`评查点已${statusText}`); + // 刷新列表数据 + fetchData(); + } + } catch (error) { + console.error('更新评查点状态失败:', error); + toastService.error(`更新失败:${error instanceof Error ? error.message : '未知错误'}`); + } finally { + // 从更新中的ID集合移除 + setUpdatingStatusIds(prev => { + const newSet = new Set(prev); + newSet.delete(rule.id); + return newSet; + }); + } + } + }); + }; + // 定义表格列配置 const columns = [ // ✅ 添加复选框列(有批量操作权限时可见) @@ -754,7 +814,12 @@ export default function RulesIndex() { align: "left" as const, width: "5%", render: (_: unknown, record: Rule) => ( - + handleStatusChange(record)} + disabled={!canUpdateRule} + loading={updatingStatusIds.has(record.id)} + /> ) }, { diff --git a/app/styles/main.css b/app/styles/main.css index 93bb120..29b4fc1 100644 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -18,6 +18,7 @@ @import './components/status-badge.css'; @import './components/file-type-tag.css'; @import './components/status-dot.css'; +@import './components/switch.css'; @import './components/tag.css'; @import './components/file-progress.css'; @import './components/processing-steps.css';