From b9240ffe9bdec1b8235ad0cebd59a8c7a9bb9265 Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Wed, 5 Aug 2026 07:34:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=B5=E5=AD=90=E7=AD=BE=E7=BD=B2?= =?UTF-8?q?=E9=9B=86=E6=88=90=E5=88=B0=E5=90=88=E5=90=8C=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=92=8C=E7=A6=BB=E8=81=8C=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 合同管理:选择电子签署时保存后自动创建ESignRecord并关联合同ID - 离职管理:工作交接清单「离职文件签署」步骤增加「发起电子签署」按钮 - 电子签署页面:列表增加来源标识(劳动合同/离职协议) - 合同卡片:电子签署合同显示提示而非手动填写编号/链接 --- frontend/src/pages/ESign.tsx | 6 +++ frontend/src/pages/Termination.tsx | 25 +++++++++- frontend/src/pages/roster/ContractInfo.tsx | 54 ++++++++++++++-------- 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/frontend/src/pages/ESign.tsx b/frontend/src/pages/ESign.tsx index b64c847..db60a81 100644 --- a/frontend/src/pages/ESign.tsx +++ b/frontend/src/pages/ESign.tsx @@ -149,6 +149,12 @@ export default function ESign() {
{r.documentTitle} + {r.contractId && ( + 劳动合同 + )} + {!r.contractId && r.documentTitle?.includes('离职') && ( + 离职协议 + )}
{r.remark &&
{r.remark}
} diff --git a/frontend/src/pages/Termination.tsx b/frontend/src/pages/Termination.tsx index 8be73fb..d3f2731 100644 --- a/frontend/src/pages/Termination.tsx +++ b/frontend/src/pages/Termination.tsx @@ -2,12 +2,12 @@ import { useState, useMemo, useEffect } from 'react' import { usePageSize } from '../hooks/usePageSize' 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, CheckCheck } from 'lucide-react' +import { AlertTriangle, Check, ChevronRight, ChevronLeft, Shield, Info, Calculator, FileText, Printer, Trash2, List, Download, Plus, Edit, Send, CheckCircle, XCircle, Play, Ban, CheckCheck, PenTool } from 'lucide-react' import { Stepper } from '../components/ui/Stepper' import { InlineAlert } from '../components/ui/InlineAlert' import PageGuide from '../components/ui/PageGuide' import jsPDF from 'jspdf' -import { rosterApi, terminationApi } from '../lib/api-services' +import { rosterApi, terminationApi, esignApi } from '../lib/api-services' import { useAuthStore } from '../store/authStore' import Card from '../components/ui/Card' import Button from '../components/ui/Button' @@ -1549,6 +1549,27 @@ export default function Termination() { placeholder="备注说明(选填)" className="text-xs" /> + {item.key === 'docs_signed' && employeeId && ( + + )} ))}
diff --git a/frontend/src/pages/roster/ContractInfo.tsx b/frontend/src/pages/roster/ContractInfo.tsx index 44f3ad5..035c326 100644 --- a/frontend/src/pages/roster/ContractInfo.tsx +++ b/frontend/src/pages/roster/ContractInfo.tsx @@ -1,12 +1,12 @@ import { useState, useRef } from "react" import { toast } from "sonner" import { useMutation, useQueryClient } from "@tanstack/react-query" -import { employeeApi } from '../../lib/api-services' +import { employeeApi, esignApi } from '../../lib/api-services' import { useConfirm } from '../../hooks/useConfirm' import Card from "../../components/ui/Card" import Button from "../../components/ui/Button" import { Input, Label, Select } from "../../components/ui/Input" -import { FileText, AlertTriangle, X, Paperclip, Trash2, Info, Download } from "lucide-react" +import { FileText, AlertTriangle, X, Paperclip, Trash2, Info, Download, PenTool } from "lucide-react" export default function ContractInfo({ employeeId, contracts, hireDate }: { employeeId: string; contracts: any[]; hireDate: string }) { const queryClient = useQueryClient() @@ -17,8 +17,27 @@ export default function ContractInfo({ employeeId, contracts, hireDate }: { empl const [previewUrl, setPreviewUrl] = useState(null) const addContractMutation = useMutation({ - mutationFn: (data: any) => employeeApi.addContract({ ...data, employeeId }), - onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); setShowForm(false) }, + mutationFn: async (data: any) => { + const res = await employeeApi.addContract({ ...data, employeeId }) as any + const contractId = res?.data?.id + if (data.signMethod === 'ELECTRONIC' && contractId) { + try { + await esignApi.create({ + contractId, + employeeId, + documentTitle: `${data.contractType === 'UNFIXED' ? '无固定期限' : '固定期限'}劳动合同`, + remark: '合同创建时自动发起', + }) + toast.success('合同已保存,电子签署记录已创建') + } catch { + toast.success('合同已保存,电子签署记录创建失败(可稍后手动发起)') + } + } else { + toast.success('合同已保存') + } + return res + }, + onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['roster-profile'] }); queryClient.invalidateQueries({ queryKey: ['esign-records'] }); setShowForm(false) }, }) const deleteContractMutation = useMutation({ @@ -193,10 +212,12 @@ export default function ContractInfo({ employeeId, contracts, hireDate }: { empl
)} {form.signMethod === 'ELECTRONIC' && ( - <> -
setForm({ ...form, electronicContractNo: e.target.value })} placeholder="如 E-2026-001" />
-
setForm({ ...form, electronicContractUrl: e.target.value })} placeholder="https://..." />
- +
+
+ + 保存合同后将自动创建电子签署记录,对接易签宝后系统会自动生成签署链接并发送给员工。当前为框架预留阶段,签署记录创建后可在「电子签署」页面查看。 +
+
)}
)} {c.signMethod === 'ELECTRONIC' && ( - <> - {c.electronicContractNo &&
电子合同编号{c.electronicContractNo}
} - {c.electronicContractUrl && ( -
- 电子合同 - - 查看电子合同 - -
- )} - +
+ 签署方式 + + 电子签署(记录已创建,请在「电子签署」页面查看进度) + +
)}