diff --git a/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue b/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue index 2c42d45..6da348c 100644 --- a/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue +++ b/src/views/contract/launch/components/ContractPartyPlaceholderModal.vue @@ -602,12 +602,28 @@ placeholder="选填,用于应收账款提醒" /> + + + + + + @@ -1450,6 +1466,7 @@ function createContractFormData() { bzjAmount: 0, performancePlans: [], signDate: "", + sealDate: "", activeDate: "", sealQuantity: 1, }; @@ -1503,7 +1520,7 @@ function copyContractFormData(data = {}) { ? source.contractBodyArrayBuffer.slice(0) : null : null; - } else if (key === "signDate" || key === "invoiceDate" || key === "receiveDate" || key === "activeDate") { + } else if (key === "signDate" || key === "sealDate" || key === "invoiceDate" || key === "receiveDate" || key === "activeDate") { form[key] = source[key] ? String(source[key]).slice(0, 10) : form[key]; } else if (key === "assistDept") { form.assistDept = source.assistDept ?? source.assistDepartmentName ?? form.assistDept; @@ -2032,6 +2049,15 @@ function validateState() { !detailState.value.periodExplain?.trim() ) return "请填写期限说明"; + if (!detailState.value.activeDate) return "请选择合同生效日期"; + if ( + detailState.value.contractPeriodType === "0" && + detailState.value.effectiveStart && + detailState.value.effectiveEnd && + (detailState.value.activeDate < detailState.value.effectiveStart || + detailState.value.activeDate > detailState.value.effectiveEnd) + ) + return "合同生效日期必须在合同期限范围内"; if (!detailState.value.valuationMode) return "请选择计价方式"; // 固定总价时标的额必填 if ( @@ -2073,12 +2099,19 @@ function validateState() { !(detailState.value.authAttachmentList || []).length ) return "请上传授权委托书附件"; + if (!(detailState.value.performancePlans || []).length) + return "请至少添加一条履行计划"; for (const plan of detailState.value.performancePlans || []) { if (!plan.planMatter?.trim()) return "请填写履行计划的履行事项"; if (!plan.planWhere?.trim()) return "请填写履行计划的履约条件"; if (!plan.planTime) return "请选择履行计划的节点日期"; if (plan.planDay === null || plan.planDay === undefined || plan.planDay === "") return "请填写履行计划的提醒提前天数"; + if ( + !["0", "3"].includes(detailState.value.valuationMode) && + (plan.planMoney === null || plan.planMoney === undefined || plan.planMoney === "") + ) + return "请填写履行计划的款项金额"; } return ""; } @@ -2258,6 +2291,7 @@ function buildLaunchRecord() { contractTextFileType: detailState.value.contractBodyFileType || "docx", contractTextFileSize: detailState.value.contractBodyFileSize || null, signDate: formatDateTimeValue(detailState.value.signDate), + sealDate: formatDateTimeValue(detailState.value.sealDate), invoiceDate: formatDateTimeValue(detailState.value.invoiceDate), receiveDate: formatDateTimeValue(detailState.value.receiveDate), activeDate: formatDateTimeValue(detailState.value.activeDate), diff --git a/src/views/contract/launch/components/UploadSignedModal.vue b/src/views/contract/launch/components/UploadSignedModal.vue index 53787ea..1814cdc 100644 --- a/src/views/contract/launch/components/UploadSignedModal.vue +++ b/src/views/contract/launch/components/UploadSignedModal.vue @@ -52,6 +52,33 @@ + + + + + + + + + + + + end) return false; + return true; +} + function triggerFileInput() { fileInputRef.value?.click(); } @@ -151,6 +209,22 @@ async function handleSubmit() { message.warning("请填写不在线签署的原因"); return; } + if (!signDate.value) { + message.warning("请选择签订日期"); + return; + } + if (!sealDate.value) { + message.warning("请选择用印时间"); + return; + } + if (!activeDate.value) { + message.warning("请选择合同生效日期"); + return; + } + if (!isActiveDateWithinTerm()) { + message.warning("合同生效日期必须在合同期限范围内"); + return; + } submitting.value = true; try { @@ -175,6 +249,9 @@ async function handleSubmit() { signedFileType: fileType, signedFileSize: fileSize, signedOfflineReason: reason, + signDate: formatDateTimeValue(signDate.value), + sealDate: formatDateTimeValue(sealDate.value), + activeDate: formatDateTimeValue(activeDate.value), }); if (String(finishRes?.code || "") !== SUCCESS_CODE) { diff --git a/src/views/contract/launch/index.vue b/src/views/contract/launch/index.vue index 5019064..4ba636a 100644 --- a/src/views/contract/launch/index.vue +++ b/src/views/contract/launch/index.vue @@ -266,6 +266,21 @@ function getResponseMessage(res, fallback = "操作失败") { return res?.message || res?.msg || fallback; } +function sliceDateValue(value) { + return value ? String(value).slice(0, 10) : ""; +} + +function todayString() { + const now = new Date(); + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + return `${now.getFullYear()}-${month}-${day}`; +} + +function formatDateTimeValue(value) { + return value ? `${value} 00:00:00` : null; +} + function connectToolbar() { const table = tableRef.value; const toolbar = toolbarRef.value; @@ -563,8 +578,11 @@ function handleMockFinishSign(row) { content: `模拟合同【${row.contractName}】签署完成,状态将变为「待采集」。`, okText: "确认模拟", cancelText: "取消", - onOk: () => - finishLaunchSeal(row.id, { + onOk: () => { + const signDate = sliceDateValue(row.signDate) || todayString(); + const sealDate = sliceDateValue(row.sealDate) || signDate; + const activeDate = sliceDateValue(row.activeDate) || sliceDateValue(row.effectiveStart) || signDate; + return finishLaunchSeal(row.id, { sealContractId: row.sealContractId || `TEST-SEAL-${row.id}`, sealContractStatus: 2000, signedFileName: `${row.contractName || "合同"}-测试已签署.pdf`, @@ -572,6 +590,9 @@ function handleMockFinishSign(row) { signedFileType: "pdf", signedFileSize: row.contractTextFileSize || null, signedOfflineReason: "测试按钮模拟签署完成,真实签章接入后可删除此按钮", + signDate: formatDateTimeValue(signDate), + sealDate: formatDateTimeValue(sealDate), + activeDate: formatDateTimeValue(activeDate), }).then((res) => { if (!isSuccessResponse(res)) { message.error(getResponseMessage(res, "测试签署完成失败")); @@ -579,7 +600,8 @@ function handleMockFinishSign(row) { } message.success("测试签署完成,合同已流转到待采集"); getList(); - }), + }); + }, icon: null, }); } diff --git a/src/views/seal/mixedSignModal.vue b/src/views/seal/mixedSignModal.vue index 70166b6..16fe290 100644 --- a/src/views/seal/mixedSignModal.vue +++ b/src/views/seal/mixedSignModal.vue @@ -486,6 +486,27 @@ 结束合约
+
+ + + +
+
end) { + return "合同生效日期不能晚于合同结束日期"; + } + } + return ""; +} + function mapBusinessStatusToContractStatus(status) { if (status === "completed") return 2000; if (status === "signing") return 20; @@ -863,6 +931,9 @@ async function writeBackLaunchSealFinished(status = 2000) { const res = await finishLaunchSeal(businessRecord.value.id, { sealContractId: contractId.value, sealContractStatus: status, + signDate: formatDateTimeValue(completeSignDate.value), + sealDate: formatDateTimeValue(completeSealDate.value), + activeDate: formatDateTimeValue(completeActiveDate.value), ...signedFileInfo, }); @@ -882,6 +953,7 @@ function resetSealPlacementState() { function resetModalState(record = null) { businessRecord.value = record ? { ...record } : null; + syncCompletionDates(record || {}); contractId.value = ""; contractStatus.value = mapBusinessStatusToContractStatus(record?.status); pdfImages.value = []; @@ -1623,6 +1695,11 @@ async function handleCompleteContract() { message.warning("合约已结束"); return; } + const validateMessage = validateCompletionDates(); + if (validateMessage) { + message.warning(validateMessage); + return; + } Modal.confirm({ title: "确认结束", @@ -2454,6 +2531,13 @@ watch(visible, (value) => { font-size: 13px; } +.complete-form-grid { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + margin-bottom: 12px; +} + .tag-success { color: #4a9c5d; font-weight: 500;