import { useState } from 'react' import { toast } from 'sonner' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { useConfirm } from '../../hooks/useConfirm' import { Plus, Settings as SettingsIcon, X, Shield, UserPlus } from 'lucide-react' import { commercialInsuranceApi, employeeApi } from '../../lib/api-services' import Card from '../../components/ui/Card' import Button from '../../components/ui/Button' import { Input, Label } from '../../components/ui/Input' import { InlineAlert } from '../../components/ui/InlineAlert' import Modal from '../../components/ui/Modal' const fmt = (n: number) => (n || 0).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) const INSURANCE_TYPES: Record = { ACCIDENT: { label: '意外伤害险', color: 'bg-orange-50 text-orange-700 border border-orange-200' }, SUPPLEMENTARY_MEDICAL: { label: '补充医疗保险', color: 'bg-blue-50 text-blue-700 border border-blue-200' }, EMPLOYER_LIABILITY: { label: '雇主责任险', color: 'bg-purple-50 text-purple-700 border border-purple-200' }, CRITICAL_ILLNESS: { label: '重大疾病险', color: 'bg-rose-50 text-rose-700 border border-rose-200' }, GROUP_LIFE: { label: '团体寿险', color: 'bg-teal-50 text-teal-700 border border-teal-200' }, OTHER: { label: '其他', color: 'bg-gray-50 text-gray-700 border border-gray-200' }, } const DEFAULT_PLAN = { name: '', type: 'ACCIDENT', provider: '', policyNo: '', premium: 0, coverageAmount: 0, effectiveFrom: new Date().toISOString().slice(0, 10), effectiveTo: '', description: '', } /** * 商险管理 Tab — 管理商业保险(意外险、补充医疗、雇主责任险等) * 支持查看商险方案、参保人员、保单信息 */ export default function CommercialInsuranceTab() { const queryClient = useQueryClient() const confirm = useConfirm() const [showAddPlan, setShowAddPlan] = useState(false) const [editingPlan, setEditingPlan] = useState(null) const [selectedPlanId, setSelectedPlanId] = useState(null) const [newPlan, setNewPlan] = useState({ ...DEFAULT_PLAN }) const [showEnrollModal, setShowEnrollModal] = useState(false) const [enrollEmployeeIds, setEnrollEmployeeIds] = useState([]) const [enrollEffectiveFrom, setEnrollEffectiveFrom] = useState(new Date().toISOString().slice(0, 10)) const { data: plans = [], isLoading } = useQuery({ queryKey: ['commercial-insurance-plans'], queryFn: async () => { return await commercialInsuranceApi.plans() }, }) const { data: enrollments = [], isLoading: enrollLoading } = useQuery({ queryKey: ['commercial-insurance-enrollments', selectedPlanId], queryFn: async () => { if (!selectedPlanId) return [] return await commercialInsuranceApi.enrollments(selectedPlanId) }, enabled: !!selectedPlanId, }) const savePlanMutation = useMutation({ mutationFn: async (data: any) => { if (editingPlan) { return commercialInsuranceApi.savePlan(data, editingPlan.id) as any } return commercialInsuranceApi.savePlan(data) as any }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['commercial-insurance-plans'] }) setShowAddPlan(false) setEditingPlan(null) setNewPlan({ ...DEFAULT_PLAN }) toast.success(editingPlan ? '商险方案已更新' : '商险方案已创建') }, onError: () => toast.error('保存失败'), }) const deletePlanMutation = useMutation({ mutationFn: (id: string) => commercialInsuranceApi.removePlan(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['commercial-insurance-plans'] }) setSelectedPlanId(null) toast.success('商险方案已删除') }, }) const { data: rosterData } = useQuery({ queryKey: ['employees-for-commercial-insurance'], queryFn: async () => { return await employeeApi.allLite({ status: 'ACTIVE' }) }, enabled: showEnrollModal, }) const enrollMutation = useMutation({ mutationFn: async (data: { employeeIds: string[]; effectiveFrom?: string }) => commercialInsuranceApi.enroll(selectedPlanId!, data) as any, onSuccess: (res: any) => { queryClient.invalidateQueries({ queryKey: ['commercial-insurance-enrollments'] }) queryClient.invalidateQueries({ queryKey: ['commercial-insurance-employee-summary'] }) setShowEnrollModal(false) setEnrollEmployeeIds([]) toast.success(`已添加 ${res.data?.enrolled || 0} 名员工`) }, onError: () => toast.error('参保失败'), }) const handleEdit = (plan: any) => { setEditingPlan(plan) setNewPlan({ ...plan }) setShowAddPlan(true) } const handleSave = () => { if (!newPlan.name?.trim()) { toast.error('请填写方案名称'); return } if (!newPlan.provider?.trim()) { toast.error('请填写保险公司'); return } savePlanMutation.mutate(newPlan) } if (isLoading) return
加载中...
return (

商业保险管理

商业保险为社保之外的自愿性补充保障,包括意外伤害险、补充医疗、雇主责任险等。此处管理商险方案及参保人员。 {plans.length === 0 ? (
暂无商险方案,点击「新增方案」创建
) : (
{plans.map((plan: any) => { const typeCfg = INSURANCE_TYPES[plan.type] || INSURANCE_TYPES.OTHER const isSelected = selectedPlanId === plan.id return (
setSelectedPlanId(isSelected ? null : plan.id)}>
{typeCfg.label}

{plan.name}

e.stopPropagation()}>
保险公司{plan.provider}
保单号{plan.policyNo || '—'}
保费(年)¥{fmt(plan.premium)}
保额¥{fmt(plan.coverageAmount)}
保障期间{plan.effectiveFrom} ~ {plan.effectiveTo || '长期'}
{plan.description &&

{plan.description}

}
) })}
)} {selectedPlanId && (

参保人员({enrollments.length}人)

{enrollLoading ? (
加载中...
) : enrollments.length === 0 ? (
暂无参保人员
) : (
{enrollments.map((e: any) => ( ))}
姓名 部门 身份证号 保费 生效日期 状态
{e.name} {e.department} {e.idCardMasked || '—'} ¥{fmt(e.premium || 0)} {e.effectiveFrom || '—'} {e.status === 'ACTIVE' ? '有效' : '已终止'}
)}
)} {/* 批量参保 Modal */} {showEnrollModal && ( setShowEnrollModal(false)} title="批量参保" size="lg">
选择需要参保的员工,设置生效日期后点击「确认参保」。
setEnrollEffectiveFrom(e.target.value)} className="!w-40" />
{rosterData?.map((emp: any) => ( ))}
0} onChange={(e) => { if (e.target.checked) { setEnrollEmployeeIds(rosterData?.map((emp: any) => emp.id) || []) } else { setEnrollEmployeeIds([]) } }} /> 姓名 部门 状态
{ if (e.target.checked) setEnrollEmployeeIds([...enrollEmployeeIds, emp.id]) else setEnrollEmployeeIds(enrollEmployeeIds.filter((id) => id !== emp.id)) }} /> {emp.name} {emp.department} 在职
已选 {enrollEmployeeIds.length} 人
)} {showAddPlan && (
setShowAddPlan(false)}>
e.stopPropagation()}>

{editingPlan ? '编辑商险方案' : '新增商险方案'}

setNewPlan({ ...newPlan, name: e.target.value })} placeholder="如:2024年度员工意外险" />
setNewPlan({ ...newPlan, provider: e.target.value })} placeholder="如:中国人寿" />
setNewPlan({ ...newPlan, policyNo: e.target.value })} placeholder="保单编号" />
setNewPlan({ ...newPlan, premium: parseFloat(e.target.value) || 0 })} />
setNewPlan({ ...newPlan, coverageAmount: parseFloat(e.target.value) || 0 })} />
setNewPlan({ ...newPlan, effectiveTo: e.target.value })} />
setNewPlan({ ...newPlan, effectiveFrom: e.target.value })} />
setNewPlan({ ...newPlan, description: e.target.value })} placeholder="保障范围、免赔额等" />
)}
) }