import { useState } from "react" import { toast } from "sonner" import { useQuery } from "@tanstack/react-query" import { rosterApi, evidenceApi } from '../../lib/api-services' import { useAuthStore } from "../../store/authStore" import Card from "../../components/ui/Card" import Button from "../../components/ui/Button" import { AlertTriangle, Scale, ShieldCheck } from "lucide-react" // ========== 仲裁证据链 ========== export default function EvidenceChain({ employeeId }: { employeeId: string }) { const [verifyResult, setVerifyResult] = useState(null) const [verifying, setVerifying] = useState(false) const { data, isLoading } = useQuery({ queryKey: ['evidence-chain', employeeId], queryFn: async () => { return await rosterApi.evidenceChain(employeeId) }, }) const handleVerify = async () => { setVerifying(true) try { const records = await evidenceApi.byEmployee(employeeId) const results: any[] = [] for (const r of records) { const result = await evidenceApi.verify(r.id) results.push({ id: r.id, category: r.category, refId: r.refId, ...result }) } setVerifyResult({ total: records.length, valid: results.filter(r => r.valid).length, invalid: results.filter(r => !r.valid).length, details: results }) toast.success(`验证完成:${results.filter(r => r.valid).length}/${results.length} 条有效`) } catch { toast.error('验证失败') } finally { setVerifying(false) } } if (isLoading) return
生成证据链中...
if (!data) return
暂无证据链数据,请确保员工已录入合同、薪酬等信息
if (!data.evidence || data.evidence.length === 0) return (

仲裁证据链

{data.employee?.name || '未知'} · {data.employee?.department || '未知'} · 入职{data.employee?.hireDate ? data.employee.hireDate.toString().slice(0, 10) : '未知'}
该员工暂无证据链记录,录入合同、薪酬、考勤等信息后将自动生成
) const categoryColor: Record = { '劳动关系': 'bg-blue-50 text-blue-700 border-blue-200', '薪酬发放': 'bg-green-50 text-green-700 border-green-200', '考勤记录': 'bg-amber-50 text-amber-700 border-amber-200', '违纪处理': 'bg-red-50 text-red-700 border-red-200', '培训签收': 'bg-purple-50 text-purple-700 border-purple-200', '绩效考核': 'bg-indigo-50 text-indigo-700 border-indigo-200', '解聘记录': 'bg-gray-100 text-gray-700 border-gray-300', } const handleExport = async () => { try { const token = useAuthStore.getState().accessToken const res = await fetch(`/api/v1/roster/${employeeId}/evidence-chain/export`, { headers: token ? { Authorization: `Bearer ${token}` } : {}, }) if (!res.ok) throw new Error('导出失败') const blob = await res.blob() const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `仲裁证据链_${data.employee.name}_${new Date().toISOString().slice(0, 10)}.xlsx` a.click() URL.revokeObjectURL(url) } catch { toast.error('导出失败') } } const riskStyle: Record = { DANGER: 'bg-red-50 border-red-300 text-red-700', HIGH: 'bg-orange-50 border-orange-300 text-orange-700', MEDIUM: 'bg-amber-50 border-amber-300 text-amber-700', } const riskIcon: Record = { DANGER: '🔴', HIGH: '🟠', MEDIUM: '🟡', } return (

仲裁证据链

{data.employee.name} · {data.employee.department} · 入职{data.employee.hireDate}
证据总数
{data.summary.total}
已签字
{data.summary.signed}
未签字
{data.summary.unsigned}
{data.summary.riskCount > 0 && (
风险项
{data.summary.riskCount}
)}
{data.risks && data.risks.length > 0 && (

风险提醒({data.risks.length}项)

{data.risks.map((r: any, i: number) => (
{riskIcon[r.level] || '⚠'} {r.title} {r.category}
{r.description}
))}
)} {verifyResult && (

证据链验证结果

总记录
{verifyResult.total}
有效
{verifyResult.valid}
{verifyResult.invalid > 0 && (
无效
{verifyResult.invalid}
)}
{verifyResult.invalid > 0 && (
{verifyResult.details.filter((r: any) => !r.valid).map((r: any, i: number) => (
{r.category} {r.refId && ID: {r.refId}}
哈希不匹配:预期 {r.expectedHash?.slice(0, 16)}...,实际 {r.actualHash?.slice(0, 16)}...
))}
)} {verifyResult.invalid === 0 && (
所有证据链哈希验证通过,数据完整无篡改
)}
)}
{data.evidence.map((e: any, i: number) => (
{e.category}
{e.title} {e.date} {e.acknowledged === true && ✓ 已签字} {e.acknowledged === false && ⚠ 未签字} {e.riskLevel === 'HIGH' && ⚠ 高风险}
{e.description}
))}
) } export function generateEvidenceText(data: any): string { const lines: string[] = [] lines.push('========================================') lines.push(' 劳动仲裁证据链') lines.push('========================================') lines.push('') lines.push(`员工姓名:${data.employee.name}`) lines.push(`部门:${data.employee.department}`) lines.push(`入职日期:${data.employee.hireDate}`) lines.push(`状态:${data.employee.status === 'ACTIVE' ? '在职' : '离职'}`) lines.push('') lines.push(`证据总数:${data.summary.total} 条`) lines.push(`已签字:${data.summary.signed} 条`) lines.push(`未签字:${data.summary.unsigned} 条`) lines.push('') lines.push('----------------------------------------') lines.push('') let currentCategory = '' data.evidence.forEach((e: any, i: number) => { if (e.category !== currentCategory) { currentCategory = e.category lines.push(`【${currentCategory}】`) lines.push('') } lines.push(`${i + 1}. ${e.title}(${e.date})`) lines.push(` ${e.description}`) if (e.acknowledged === true) lines.push(' [已签字确认]') if (e.acknowledged === false) lines.push(' [未签字]') lines.push('') }) lines.push('----------------------------------------') lines.push(`导出时间:${new Date().toLocaleString('zh-CN')}`) return lines.join('\n') }