feat: 20260809 系统优化 - 全部28项问题修复(P0×6+P1×16+P2×6)

P0: 福利批量参保/离职证明下载防乱码/考勤模板合并Sheet/补卡修改/附件在线查看删除
P1: 分页pageSize修复/离职导出筛选/撤回删除草稿/加班费自动计算/考勤加班汇总/证据链异常详情/制度催办/模板导入Word/社保封顶保底/校验字段提示/职务字段/社保费用明细/弹窗防误关/身份证查重/证明员工下拉/培训批量
P2: 离职流程去重/社保基数覆盖输入/薪税入口改名/添加员工引导/绩效模板清理
This commit is contained in:
freedakgmail
2026-08-09 11:59:02 +08:00
parent c355a7d208
commit a2e9ba55c2
43 changed files with 2913 additions and 324 deletions
+33 -3
View File
@@ -2,7 +2,7 @@ import { useState } from 'react'
import { usePageSize } from '../hooks/usePageSize'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { FileText, Plus, ChevronRight, CheckCircle, Clock, X } from 'lucide-react'
import { FileText, Plus, ChevronRight, CheckCircle, Clock, X, Bell } from 'lucide-react'
import { policiesApi } from '../lib/api-services'
import Card from '../components/ui/Card'
import Button from '../components/ui/Button'
@@ -247,6 +247,8 @@ function CreatePolicyModal({ onClose, onSuccess }: { onClose: () => void; onSucc
* 阅读签收统计组件
*/
function ReadStats({ policyId }: { policyId: string }) {
const queryClient = useQueryClient()
const [showUnread, setShowUnread] = useState(false)
const { data, isLoading } = useQuery<any>({
queryKey: ['policy-read-stats', policyId],
queryFn: async () => {
@@ -254,6 +256,17 @@ function ReadStats({ policyId }: { policyId: string }) {
},
})
const remindMutation = useMutation({
mutationFn: async (employeeIds?: string[]) => {
return await policiesApi.remind(policyId, employeeIds)
},
onSuccess: (res: any) => {
toast.success(`已催办 ${res?.reminded || 0} 名未签收员工`)
queryClient.invalidateQueries({ queryKey: ['policy-read-stats', policyId] })
},
onError: () => toast.error('催办失败'),
})
if (isLoading) return <div className="text-xs text-gray-400 mt-3">...</div>
if (!data) return null
@@ -271,8 +284,25 @@ function ReadStats({ policyId }: { policyId: string }) {
</span>
</div>
{data.unreadCount > 0 && (
<div className="text-xs text-amber-600 mb-2">
{data.unreadCount}
<div className="flex items-center gap-2 mb-2">
<span className="text-xs text-amber-600">{data.unreadCount} </span>
<button onClick={() => setShowUnread(!showUnread)} className="text-xs text-primary hover:underline">
{showUnread ? '收起' : '查看明细'}
</button>
<Button size="sm" variant="secondary" className="!h-6 !px-2 !text-xs" onClick={() => remindMutation.mutate(undefined)} disabled={remindMutation.isPending}>
<Bell className="w-3 h-3 mr-1" />
</Button>
</div>
)}
{showUnread && data.unreadEmployees && data.unreadEmployees.length > 0 && (
<div className="max-h-40 overflow-y-auto space-y-1 mb-2">
{data.unreadEmployees.map((r: any) => (
<div key={r.employeeId} className="flex items-center justify-between px-2 py-1 rounded bg-amber-50 text-xs">
<span className="text-gray-700">{r.employeeName}</span>
<span className="text-gray-400">{r.department}</span>
<span className="text-amber-600"></span>
</div>
))}
</div>
)}
{data.records && data.records.length > 0 && (