feat: 花名册操作联动电子签署 + 修复重复创建
## 修复 - POST /contracts 不再自动创建签署记录(由前端根据signMethod决定),避免与ContractInfo重复创建 ## 新增 SignMethodChoice 通用组件 - 花名册操作成功后弹窗选择签署方式:电子签/线下手签/稍后处理 - 电子签:自动创建ESignRecord(PENDING),员工在员工端签署 - 线下手签:跳转签署页面,预填员工/场景/标题,上传扫描件登记 - 稍后处理:跳过,可后续在签署页面手动发起 ## 花名册4项操作联动签署方式选择 - 重新入职:操作成功后弹窗(scene=CONTRACT,劳动合同) - 合同续签:操作成功后弹窗(scene=CONTRACT,续签劳动合同) - 薪酬变更:操作成功后弹窗(scene=POLICY,薪酬调整确认书) - 调岗调动:操作成功后弹窗(scene=POLICY,调岗确认书) ## ESign页面支持URL参数 - 读取 ?action=paper-sign 自动打开线下手签登记Modal - 预填employeeId/scene/documentTitle Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
* - 签署详情(含证据链查看)
|
||||
* - 取消签署
|
||||
*/
|
||||
import { useState, useRef } from 'react'
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { toast } from 'sonner'
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { PenTool, Plus, RefreshCw, ExternalLink, FileText, AlertCircle, Shield, ChevronLeft, Clock, CheckCircle2, XCircle, Eye, Upload, FileCheck } from 'lucide-react'
|
||||
@@ -47,6 +48,7 @@ export default function ESign() {
|
||||
const [showCreate, setShowCreate] = useState(false)
|
||||
const [showPaperSign, setShowPaperSign] = useState(false)
|
||||
const [detailId, setDetailId] = useState<string | null>(null)
|
||||
const [searchParams] = useSearchParams()
|
||||
const [formData, setFormData] = useState({
|
||||
employeeId: '',
|
||||
scene: 'CONTRACT',
|
||||
@@ -54,6 +56,26 @@ export default function ESign() {
|
||||
remark: '',
|
||||
})
|
||||
|
||||
// 从 URL 参数读取,自动打开线下手签登记
|
||||
useEffect(() => {
|
||||
const action = searchParams.get('action')
|
||||
if (action === 'paper-sign') {
|
||||
setShowPaperSign(true)
|
||||
// 预填表单
|
||||
const employeeId = searchParams.get('employeeId')
|
||||
const scene = searchParams.get('scene') as string
|
||||
const documentTitle = searchParams.get('documentTitle') as string
|
||||
if (employeeId || scene || documentTitle) {
|
||||
setFormData({
|
||||
employeeId: employeeId || '',
|
||||
scene: scene || 'CONTRACT',
|
||||
documentTitle: documentTitle || '',
|
||||
remark: '花名册操作跳转登记',
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [searchParams])
|
||||
|
||||
const { data: records = [], isLoading } = useQuery<any[]>({
|
||||
queryKey: ['esign-records', filterStatus, filterScene],
|
||||
queryFn: async () => {
|
||||
@@ -323,10 +345,15 @@ export default function ESign() {
|
||||
{/* 线下手签登记 Modal */}
|
||||
{showPaperSign && (
|
||||
<PaperSignModal
|
||||
onClose={() => setShowPaperSign(false)}
|
||||
initialEmployeeId={formData.employeeId}
|
||||
initialScene={formData.scene as any}
|
||||
initialDocumentTitle={formData.documentTitle}
|
||||
initialRemark={formData.remark}
|
||||
onClose={() => { setShowPaperSign(false); setFormData({ employeeId: '', scene: 'CONTRACT', documentTitle: '', remark: '' }) }}
|
||||
onSuccess={() => {
|
||||
queryClient.invalidateQueries({ queryKey: ['esign-records'] })
|
||||
setShowPaperSign(false)
|
||||
setFormData({ employeeId: '', scene: 'CONTRACT', documentTitle: '', remark: '' })
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -335,17 +362,24 @@ export default function ESign() {
|
||||
}
|
||||
|
||||
// ===== 线下手签登记 Modal =====
|
||||
function PaperSignModal({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) {
|
||||
function PaperSignModal({ onClose, onSuccess, initialEmployeeId, initialScene, initialDocumentTitle, initialRemark }: {
|
||||
onClose: () => void
|
||||
onSuccess: () => void
|
||||
initialEmployeeId?: string
|
||||
initialScene?: string
|
||||
initialDocumentTitle?: string
|
||||
initialRemark?: string
|
||||
}) {
|
||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
||||
const [form, setForm] = useState({
|
||||
employeeId: '',
|
||||
scene: 'CONTRACT',
|
||||
documentTitle: '',
|
||||
employeeId: initialEmployeeId || '',
|
||||
scene: initialScene || 'CONTRACT',
|
||||
documentTitle: initialDocumentTitle || '',
|
||||
signedAt: new Date().toISOString().slice(0, 10),
|
||||
signedLocation: '',
|
||||
witnessName: '',
|
||||
witnessPhone: '',
|
||||
remark: '',
|
||||
remark: initialRemark || '',
|
||||
})
|
||||
const [scanFiles, setScanFiles] = useState<Array<{ name: string; url: string }>>([])
|
||||
const [uploading, setUploading] = useState(false)
|
||||
|
||||
Reference in New Issue
Block a user