"use client"; import { useState, useCallback } from "react"; import { motion } from "motion/react"; import { Trash2, ToggleLeft, ToggleRight, Search, FileText } from "lucide-react"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; import { api } from "@/lib/api/client"; import { ENDPOINTS } from "@/lib/api/endpoints"; import { useToast } from "@/lib/hooks/useToast"; import type { CompanyRuleResponse } from "@/lib/api/types"; // 模拟数据 const mockRules: CompanyRuleResponse[] = [ { id: 1, company_id: 1, rule_type: "FIELD_MAPPING", match_condition: { source_field: "员工姓名" }, target_value: "员工姓名", priority: 0, status: "ACTIVE", description: "工资表员工姓名字段映射", match_count: 15, last_used_at: "2024-01-15T10:30:00Z", created_at: "2024-01-01T00:00:00Z", updated_at: "2024-01-15T10:30:00Z", }, { id: 2, company_id: 1, rule_type: "FIELD_MAPPING", match_condition: { source_field: "基本薪资" }, target_value: "基本工资", priority: 0, status: "ACTIVE", description: "工资表基本薪资字段映射", match_count: 12, last_used_at: "2024-01-15T10:30:00Z", created_at: "2024-01-05T00:00:00Z", updated_at: "2024-01-15T10:30:00Z", }, { id: 3, company_id: 1, rule_type: "FIELD_MAPPING", match_condition: { source_field: "实发合计" }, target_value: "实发工资", priority: 1, status: "INACTIVE", description: "工资表实发合计字段映射(已停用)", match_count: 8, last_used_at: "2024-01-10T00:00:00Z", created_at: "2024-01-08T00:00:00Z", updated_at: "2024-01-12T00:00:00Z", }, ]; const RULE_TYPE_LABELS: Record = { FIELD_MAPPING: "字段映射", ACCOUNT_MAPPING: "科目映射", DEPARTMENT_MAPPING: "部门映射", }; const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.06 }, }, }; const item = { hidden: { opacity: 0, y: 8 }, show: { opacity: 1, y: 0, transition: { duration: 0.3, ease: [0.16, 1, 0.3, 1] as const } }, }; export default function RulesPage() { const toast = useToast(); const [rules, setRules] = useState(mockRules); const [searchQuery, setSearchQuery] = useState(""); const [typeFilter, setTypeFilter] = useState(""); const [statusFilter, setStatusFilter] = useState(""); // 过滤规则 const filteredRules = rules.filter((rule) => { const matchesSearch = !searchQuery || rule.match_condition.source_field?.toLowerCase().includes(searchQuery.toLowerCase()) || rule.target_value.toLowerCase().includes(searchQuery.toLowerCase()) || rule.description?.toLowerCase().includes(searchQuery.toLowerCase()); const matchesType = !typeFilter || rule.rule_type === typeFilter; const matchesStatus = !statusFilter || rule.status === statusFilter; return matchesSearch && matchesType && matchesStatus; }); // 切换规则状态 const handleToggleStatus = useCallback( async (ruleId: number, currentStatus: string) => { const newStatus = currentStatus === "ACTIVE" ? "INACTIVE" : "ACTIVE"; try { await api.patch(ENDPOINTS.MAPPING.RULE_STATUS(ruleId), { status: newStatus, }); setRules((prev) => prev.map((rule) => rule.id === ruleId ? { ...rule, status: newStatus } : rule ) ); toast.success(`规则已${newStatus === "ACTIVE" ? "启用" : "停用"}`); } catch { toast.error("状态更新失败"); } }, [toast] ); // 删除规则 const handleDeleteRule = useCallback( async (ruleId: number) => { if (!confirm("确定要删除这条规则吗?")) return; try { await api.delete(ENDPOINTS.MAPPING.RULE_DELETE(ruleId)); setRules((prev) => prev.filter((rule) => rule.id !== ruleId)); toast.success("规则已删除"); } catch { toast.error("删除失败"); } }, [toast] ); const activeCount = rules.filter((r) => r.status === "ACTIVE").length; const inactiveCount = rules.filter((r) => r.status === "INACTIVE").length; return (
{/* 页面头部 */}

规则管理

管理企业字段映射规则,实现自动识别

{/* 统计卡片 */}

总规则数

{rules.length}

启用中

{activeCount}

已停用

{inactiveCount}

{/* 筛选栏 */}
setSearchQuery(e.target.value)} className="h-9 pl-9" />
{/* 规则列表 */}
{filteredRules.length === 0 ? ( ) : ( filteredRules.map((rule, index) => ( )) )}
规则类型 匹配条件 目标字段 匹配次数 状态 最近使用 操作

暂无规则数据

上传文件后自动创建映射规则

{RULE_TYPE_LABELS[rule.rule_type] || rule.rule_type} {rule.match_condition.source_field || JSON.stringify(rule.match_condition)} {rule.target_value} {rule.match_count} {rule.status === "ACTIVE" ? "启用" : "停用"} {rule.last_used_at ? new Date(rule.last_used_at).toLocaleDateString("zh-CN") : "-"}
{/* 说明 */}

规则说明

  • 字段映射规则会在上传同类文件时自动应用
  • 精确匹配的规则(完全相同的字段名)会优先于模糊匹配
  • 停用规则不会在自动识别中应用,但不会删除
  • 删除规则后,下次上传相同格式文件需要重新确认映射
); }