This commit is contained in:
2026-06-30 09:54:17 +08:00
parent 2326752b5d
commit 0b578df215
4 changed files with 508 additions and 99 deletions
@@ -0,0 +1,348 @@
<template>
<a-modal
v-model:open="visible"
title="合同采集"
width="800px"
:mask-closable="false"
:confirm-loading="submitting"
ok-text="确认采集"
cancel-text="取消"
@ok="handleSubmit"
>
<div class="collect-body">
<a-descriptions :column="2" size="small" bordered class="contract-brief">
<a-descriptions-item label="合同名称">
{{ row?.contractName || "-" }}
</a-descriptions-item>
<a-descriptions-item label="合同编码">
{{ row?.contractCode || "-" }}
</a-descriptions-item>
</a-descriptions>
<a-divider style="margin: 16px 0" />
<a-form layout="vertical">
<div class="section-header">
<span class="section-title-icon">📜</span>
用印信息c_seal
</div>
<div class="field-row">
<a-form-item label="是否用印" required class="field-half">
<a-radio-group v-model:value="formState.sealIsSeal">
<a-radio value="1"></a-radio>
<a-radio value="0"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
label="用印类型"
class="field-half"
>
<a-input
:value="sealTypeDisplay"
readonly
placeholder="沿用合同签订方式"
/>
</a-form-item>
</div>
<div class="field-row">
<a-form-item label="审批是否一致" required class="field-half">
<a-radio-group v-model:value="formState.sealApproveSame">
<a-radio value="1"></a-radio>
<a-radio value="0"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="用印数量" class="field-half">
<a-input-number
v-model:value="formState.sealQuantity"
:min="1"
:precision="0"
:disabled="formState.sealIsSeal !== '1'"
style="width: 100%"
placeholder="默认1份"
/>
</a-form-item>
</div>
<div class="field-row">
<a-form-item label="用印时间" required class="field-half">
<a-date-picker
v-model:value="formState.sealDate"
value-format="YYYY-MM-DD"
:disabled="formState.sealIsSeal !== '1'"
style="width: 100%"
placeholder="用印日期"
/>
</a-form-item>
</div>
<div class="section-header" style="margin-top: 20px">
<span class="section-title-icon"></span>
签订信息c_sign
</div>
<div class="field-row">
<a-form-item label="签订日期" required class="field-half">
<a-date-picker
v-model:value="formState.signDate"
value-format="YYYY-MM-DD"
style="width: 100%"
placeholder="请选择签订日期"
/>
</a-form-item>
<a-form-item label="合同生效日期" required class="field-half">
<a-date-picker
v-model:value="formState.activeDate"
value-format="YYYY-MM-DD"
style="width: 100%"
placeholder="必填,且需在合同期限内"
/>
</a-form-item>
</div>
<div class="field-row">
<a-form-item label="合同履行执行人" required class="field-half">
<a-input
v-model:value="formState.executorAccount"
placeholder="履行执行人账号"
/>
</a-form-item>
</div>
<div class="section-header" style="margin-top: 20px">
<span class="section-title-icon">📎</span>
合同签署文本
</div>
<a-form-item label="签署文件" required>
<a-upload-dragger
:file-list="signedFileList"
:before-upload="handleSignedFileUpload"
:show-upload-list="{ showRemoveIcon: true }"
@remove="handleRemoveSignedFile"
>
<div class="upload-text">
点击或拖拽上传签署完成的合同文件
</div>
<div class="upload-hint">
支持 .pdf 格式当前仅本地上传到业务系统文件服务
</div>
</a-upload-dragger>
</a-form-item>
</a-form>
</div>
</a-modal>
</template>
<script setup>
import { computed, reactive, ref } from "vue";
import { message } from "ant-design-vue";
import {
getLaunchDetail,
saveContractCollectInfo,
mockCollectLaunch,
uploadLaunchFile,
} from "@/api/launch.js";
const SUCCESS_CODE = "0000";
const visible = ref(false);
const submitting = ref(false);
const row = ref(null);
const signedFileList = ref([]);
const formState = reactive({
sealIsSeal: "1",
sealApproveSame: "1",
sealQuantity: 1,
sealDate: "",
signDate: "",
activeDate: "",
executorAccount: "",
signedFileName: "",
signedFilePath: "",
signedFileType: "",
signedFileSize: null,
});
const emit = defineEmits(["done"]);
const sealTypeDisplay = computed(() => {
return row.value?.sealTypeLabel || row.value?.sealType || "公章";
});
function resetForm(record) {
formState.sealIsSeal = record.sealIsSeal || "1";
formState.sealApproveSame = record.sealApproveSame || "1";
formState.sealQuantity = record.sealQuantity || 1;
formState.sealDate = record.sealDate || "";
formState.signDate = record.signDate || "";
formState.activeDate = record.activeDate || "";
formState.executorAccount = record.executorAccount || record.initiator || "";
formState.signedFileName = record.signedFileName || "";
formState.signedFilePath = record.signedFilePath || "";
formState.signedFileType = record.signedFileType || "";
formState.signedFileSize = record.signedFileSize || null;
if (record.signedFileName) {
signedFileList.value = [
{
uid: "signed_existing",
name: record.signedFileName,
status: "done",
size: record.signedFileSize || 0,
},
];
} else {
signedFileList.value = [];
}
}
async function showModal(record) {
row.value = record || {};
resetForm(record || {});
visible.value = true;
}
function buildKey(prefix) {
return `${prefix}_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;
}
async function handleSignedFileUpload(file) {
const formData = new FormData();
formData.append("file", file);
try {
const res = await uploadLaunchFile(formData);
if (String(res?.code || "") !== SUCCESS_CODE) {
message.error(res?.message || res?.msg || "签署文件上传失败");
return false;
}
const fileItem = {
uid: buildKey("signed"),
name: file.name,
status: "done",
size: file.size,
fileName: file.name,
filePath: res?.result || "",
fileType: file.name.split(".").pop()?.toLowerCase() || "",
fileSize: file.size,
};
signedFileList.value = [fileItem];
formState.signedFileName = fileItem.fileName;
formState.signedFilePath = fileItem.filePath;
formState.signedFileType = fileItem.fileType;
formState.signedFileSize = fileItem.fileSize;
message.success(`已上传签署文件:${file.name}`);
} catch (error) {
message.error("签署文件上传失败");
}
return false;
}
function handleRemoveSignedFile() {
signedFileList.value = [];
formState.signedFileName = "";
formState.signedFilePath = "";
formState.signedFileType = "";
formState.signedFileSize = null;
}
function validateForm() {
if (!formState.sealIsSeal) return "请选择是否用印";
if (!formState.sealApproveSame) return "请选择审批是否一致";
if (formState.sealIsSeal === "1") {
if (!formState.sealDate) return "请选择用印时间";
if (!formState.sealQuantity || formState.sealQuantity < 1)
return "请填写用印数量";
}
if (!formState.signDate) return "请选择签订日期";
if (!formState.activeDate) return "请选择合同生效日期";
if (!formState.executorAccount?.trim()) return "请填写合同履行执行人";
if (!signedFileList.value.length) return "请上传签署完成的合同文件";
return "";
}
async function handleSubmit() {
const validateMessage = validateForm();
if (validateMessage) {
message.warning(validateMessage);
return;
}
submitting.value = true;
try {
// 1. 保存采集信息到合同记录
const saveRes = await saveContractCollectInfo(row.value.id, {
sealIsSeal: formState.sealIsSeal,
sealApproveSame: formState.sealApproveSame,
sealQuantity: formState.sealIsSeal === "1" ? formState.sealQuantity : null,
sealDate: formState.sealIsSeal === "1" ? formState.sealDate : null,
signDate: formState.signDate,
activeDate: formState.activeDate,
executorAccount: formState.executorAccount?.trim(),
signedFileName: formState.signedFileName,
signedFilePath: formState.signedFilePath,
signedFileType: formState.signedFileType,
signedFileSize: formState.signedFileSize,
});
if (String(saveRes?.code || "") !== SUCCESS_CODE) {
message.error(saveRes?.message || "保存采集信息失败");
return;
}
// 2. 触发采集流转(push to 法务)
const collectRes = await mockCollectLaunch(row.value.id);
if (String(collectRes?.code || "") !== SUCCESS_CODE) {
message.error(collectRes?.message || "合同采集失败");
return;
}
message.success("合同采集完成,已流转到待归档");
visible.value = false;
emit("done");
} catch (error) {
message.error("合同采集失败");
} finally {
submitting.value = false;
}
}
defineExpose({ showModal });
</script>
<style scoped>
.collect-body {
max-height: 72vh;
overflow-y: auto;
padding-right: 4px;
}
.contract-brief {
margin-bottom: 8px;
}
.field-row {
display: flex;
gap: 16px;
}
.field-half {
flex: 1;
min-width: 0;
}
.section-header {
display: flex;
align-items: center;
gap: 6px;
margin: 14px 0 12px;
font-weight: 600;
font-size: 15px;
color: #1f2937;
}
.section-title-icon {
font-size: 16px;
}
.upload-text {
color: #374151;
font-size: 14px;
}
.upload-hint {
color: #9ca3af;
font-size: 12px;
margin-top: 4px;
}
</style>