feat: AI历史记录、企业信息seed、员工状态自动刷新、风险预测数据准确性优化

- 智能问答/风险预测/合同审查/案例匹配 均支持历史记录保存、加载、删除
- 后端 predict/predict-stream 补充离职记录详情和预计算工龄/天数,避免AI计算错误
- Organization 增加 contactName/contactPhone 字段,seed 企业信息
- Settings 页面修复 orgData/usersData 取值路径错误
- Roster/Termination/Contracts mutation 增加 roster cache invalidation
- 员工档案页面 tab 固定、内容区域滚动到窗口底部
- 解聘证据链显示逻辑修复(协商一致离职 vs 员工主动离职)
This commit is contained in:
freedakgmail
2026-07-25 00:33:51 +08:00
parent bb25e1731c
commit 169a0e1117
12 changed files with 828 additions and 70 deletions
+25 -3
View File
@@ -1,7 +1,7 @@
import { useState, useMemo, useEffect } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { AlertTriangle, Check, ChevronRight, ChevronLeft, Shield, Info, Calculator, FileText, Printer, Trash2, List, Download, Plus, Edit, Send, CheckCircle, XCircle, Play, Ban } from 'lucide-react'
import { AlertTriangle, Check, ChevronRight, ChevronLeft, Shield, Info, Calculator, FileText, Printer, Trash2, List, Download, Plus, Edit, Send, CheckCircle, XCircle, Play, Ban, CheckCheck } from 'lucide-react'
import jsPDF from 'jspdf'
import api from '../lib/api'
import Card from '../components/ui/Card'
@@ -229,6 +229,9 @@ export default function Termination() {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
queryClient.invalidateQueries({ queryKey: ['employees'] })
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
queryClient.invalidateQueries({ queryKey: ['evidence-chain'] })
setStep(5)
},
})
@@ -308,7 +311,9 @@ export default function Termination() {
toast.success('解聘已执行')
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
queryClient.invalidateQueries({ queryKey: ['employees'] })
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['roster-profile'] })
queryClient.invalidateQueries({ queryKey: ['evidence-chain'] })
setView('list')
resetWizard()
},
@@ -321,6 +326,8 @@ export default function Termination() {
onSuccess: () => {
toast.success('已撤销')
queryClient.invalidateQueries({ queryKey: ['termination-drafts'] })
queryClient.invalidateQueries({ queryKey: ['roster'] })
queryClient.invalidateQueries({ queryKey: ['dashboard'] })
setView('list')
},
onError: () => toast.error('撤销失败'),
@@ -410,7 +417,7 @@ export default function Termination() {
}, [selectedEmployee, terminationDate, socialAvgWage, reason])
const canProceed = () => {
if (step === 0) return !!employeeId && !selectedEmployee?.hasTermination
if (step === 0) return !!employeeId && (!!draftId || !selectedEmployee?.hasTermination)
if (step === 1) return !!reason && !!terminationDate && (!riskAssessment?.warnings.length || acknowledgeRisk)
if (step === 2) return true
if (step === 3) return true
@@ -673,6 +680,21 @@ export default function Termination() {
<Edit className="w-3.5 h-3.5" />
</button>
)}
{item.status === 'DRAFT' && (
<button
onClick={() => {
if (confirm(`确认执行「${item.employeeName}」的解聘手续?\n确认后员工状态将变更为离职,社保/公积金将停缴,此操作不可撤销。`)) {
setDraftId(item.id)
executeMutation.mutate()
}
}}
className="p-1 text-safe hover:opacity-70"
aria-label="确定"
title="确定执行"
>
<CheckCheck className="w-3.5 h-3.5" />
</button>
)}
{item.status === 'PENDING_APPROVAL' && (
<>
<button