feat: 实现20260730优化方案全部功能
- AI文件审查:.docx上传提取文本,支持多种文档类型 - 用工办理工作流:WorkProcess页面+后端API,支持入职/续签/终止等流程 - 企业自建文本库:Templates页面Tab切换,企业模板CRUD+渲染+下载Word - 考勤发布:Attendance发布/取消发布按钮,员工端MyAttendance页面 - 工资条发布:Money发布/定时发送按钮+弹窗,portal端publishStatus过滤 - 合同到期弹窗:Dashboard合同到期预警可点击打开弹窗,支持续签/终止操作 - Prisma schema新增WorkProcess/EnterpriseTemplate/AttendancePublish模型 - 前后端编译验证全部通过
This commit is contained in:
@@ -547,6 +547,27 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
onError: (err: any) => toast.error(err?.response?.data?.error?.message || '取消归档失败'),
|
||||
})
|
||||
|
||||
const publishPayslipMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/publish`),
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(`已发布 ${res.data?.published || 0} 条工资条`)
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
},
|
||||
onError: (err: any) => toast.error(err?.response?.data?.error?.message || '发布失败'),
|
||||
})
|
||||
|
||||
const [showScheduleModal, setShowScheduleModal] = useState(false)
|
||||
const [scheduleDate, setScheduleDate] = useState('')
|
||||
const schedulePayslipMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll2/batches/${batchId}/schedule`, { scheduledAt: scheduleDate }),
|
||||
onSuccess: (res: any) => {
|
||||
toast.success(`已设定定时发送 ${res.data?.scheduled || 0} 条工资条`)
|
||||
setShowScheduleModal(false)
|
||||
queryClient.invalidateQueries({ queryKey: ['batch-detail'] })
|
||||
},
|
||||
onError: (err: any) => toast.error(err?.response?.data?.error?.message || '设定失败'),
|
||||
})
|
||||
|
||||
const importOvertimeMutation = useMutation({
|
||||
mutationFn: () => api.post(`/payroll/overtime/import-to-batch/${batchId}`),
|
||||
onSuccess: (res: any) => {
|
||||
@@ -890,6 +911,24 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
>
|
||||
{unarchiveMutation.isPending ? '取消中...' : '取消归档'}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={async () => {
|
||||
if (await confirm({ title: '发布工资条', message: `确认发布 ${batch.month} 月工资条?发布后员工可在员工端查看。`, variant: 'primary' })) {
|
||||
publishPayslipMutation.mutate()
|
||||
}
|
||||
}}
|
||||
disabled={publishPayslipMutation.isPending}
|
||||
>
|
||||
{publishPayslipMutation.isPending ? '发布中...' : '发布工资条'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => setShowScheduleModal(true)}
|
||||
>
|
||||
<Clock className="w-4 h-4 mr-1" />定时发送
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -1042,6 +1081,41 @@ function BatchDetail({ batchId, onBack }: { batchId: string; onBack: () => void
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 定时发送弹窗 */}
|
||||
{showScheduleModal && (
|
||||
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50 p-4" onClick={() => setShowScheduleModal(false)}>
|
||||
<Card className="max-w-md w-full" >
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-medium">定时发送工资条</h3>
|
||||
<button onClick={() => setShowScheduleModal(false)} className="text-gray-400 hover:text-gray-600"><X className="w-4 h-4" /></button>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mb-3">设定发送时间后,工资条将在指定时间自动发布到员工端</p>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<Label>发送时间</Label>
|
||||
<Input
|
||||
type="datetime-local"
|
||||
value={scheduleDate}
|
||||
onChange={(e) => setScheduleDate(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
if (!scheduleDate) { toast.error('请选择发送时间'); return }
|
||||
schedulePayslipMutation.mutate()
|
||||
}}
|
||||
disabled={schedulePayslipMutation.isPending}
|
||||
>
|
||||
{schedulePayslipMutation.isPending ? '设定中...' : '确认定时发送'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user