feat: 待签合同支持登记线下签署日期

- 线下手签合同:展开后可点击「登记签署日期」选择日期并保存
  保存后合同从待签列表移除(signDate 已填写)
- 电子签合同:签署日期由电签系统自动回写,不可手动修改
- 后端新增 POST /esign/sign-date 接口
  电子签合同拒绝手动修改签署日期

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 12:13:07 +08:00
parent 79145b47b9
commit 040c5a3ab9
8 changed files with 344 additions and 50 deletions
+59 -1
View File
@@ -788,9 +788,30 @@ function PendingTab({ pendingList, loading, onRemind, remindLoading, remindData,
remindData: any
onDetail: (id: string) => void
}) {
const queryClient = useQueryClient()
const [expandedEmp, setExpandedEmp] = useState<string | null>(null)
const [remindEmpId, setRemindEmpId] = useState<string | null>(null)
const [copied, setCopied] = useState(false)
const [signDateEditing, setSignDateEditing] = useState<string | null>(null)
const [signDateValue, setSignDateValue] = useState('')
const [signDateSaving, setSignDateSaving] = useState(false)
/** 保存签署日期 */
const handleSaveSignDate = async (contractId: string) => {
if (!signDateValue) { toast.error('请选择签署日期'); return }
setSignDateSaving(true)
try {
await esignApi.signDate(contractId, signDateValue)
toast.success('签署日期已登记')
setSignDateEditing(null)
setSignDateValue('')
queryClient.invalidateQueries({ queryKey: ['esign-pending'] })
} catch (err: any) {
toast.error(err?.response?.data?.error?.message || '登记失败')
} finally {
setSignDateSaving(false)
}
}
const handleCopy = (url: string) => {
navigator.clipboard?.writeText(url)
@@ -908,7 +929,44 @@ function PendingTab({ pendingList, loading, onRemind, remindLoading, remindData,
</button>
)}
{item.type === 'contract' && (
<span className="text-gray-400 ml-auto"></span>
<div className="ml-auto flex items-center gap-2">
{signDateEditing === item.contractId ? (
<>
<input
type="date"
value={signDateValue}
onChange={(e) => setSignDateValue(e.target.value)}
className="h-7 px-2 text-xs border rounded"
/>
<button
className="text-xs text-primary hover:underline"
disabled={signDateSaving}
onClick={() => handleSaveSignDate(item.contractId)}
>
{signDateSaving ? '保存中...' : '保存'}
</button>
<button
className="text-xs text-gray-400 hover:text-gray-600"
onClick={() => { setSignDateEditing(null); setSignDateValue('') }}
>
</button>
</>
) : (
<>
<span className="text-gray-400"></span>
<button
className="text-xs text-primary hover:underline"
onClick={() => {
setSignDateEditing(item.contractId)
setSignDateValue(new Date().toISOString().slice(0, 10))
}}
>
</button>
</>
)}
</div>
)}
</div>
))}