+
授权委托书附件
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1131,11 +1048,6 @@ import {
// ========== 合同方相关字典 ==========
-const partyCharacterOptions = [
- { label: "企业", value: "QY" },
- { label: "自然人", value: "ZZR" },
-];
-
const companyTypeOptions = [
{ label: "客户", value: "客户" },
{ label: "供应商", value: "供应商" },
@@ -1144,38 +1056,6 @@ const companyTypeOptions = [
{ label: "其他", value: "其他" },
];
-const companyNatureOptions = [
- { label: "境内组织", value: "境内组织" },
- { label: "境内个人", value: "境内个人" },
- { label: "境外组织", value: "境外组织" },
- { label: "境外个人", value: "境外个人" },
-];
-
-const organizationNatureOptions = [
- { label: "政府", value: "政府" },
- { label: "企业", value: "企业" },
- { label: "其他组织", value: "其他组织" },
-];
-
-const enterpriseNatureLevel2Options = [
- { label: "国有企业", value: "国有企业" },
- { label: "民营企业", value: "民营企业" },
- { label: "外资企业", value: "外资企业" },
- { label: "合资企业", value: "合资企业" },
- { label: "国有全资和控股企业", value: "国有全资和控股企业" },
-];
-
-const countryOptions = [
- { label: "中国", value: "GJ156" },
- { label: "中国香港", value: "GJ344" },
- { label: "中国澳门", value: "GJ446" },
- { label: "中国台湾", value: "GJ158" },
- { label: "新加坡", value: "GJ702" },
- { label: "美国", value: "GJ840" },
- { label: "英国", value: "GJ826" },
- { label: "日本", value: "GJ392" },
-];
-
const contractCompanyOptions = ref([
{ label: "扬州宏富特种材料有限公司", value: "扬州宏富特种材料有限公司" },
{ label: "宁波港船务货运代理有限公司", value: "宁波港船务货运代理有限公司" },
@@ -1382,9 +1262,6 @@ function createEmptyParty(roleCode, index = 0) {
companyType: "",
oppositeCharacter: "",
oppCharacter: "",
- companyNature: "",
- organizationNature: "",
- enterpriseNatureLevel2: "",
contactName: "",
contactPhone: "",
contactEmail: "",
@@ -1398,7 +1275,6 @@ function createEmptyParty(roleCode, index = 0) {
naturalPersonIdNumber: "",
isGroupInternal: false,
isHongKongMacaoTaiwan: false,
- invoiceTitleOptions: [],
};
}
@@ -1417,9 +1293,6 @@ function mapLaunchPartyToFormParty(item = {}) {
roleCode,
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
subjectCode: item.subjectCode || "",
- companyNature: getCompanyNatureByOppositeCharacter(
- item.oppositeCharacter || item.oppCharacter,
- ),
oppCharacter: item.oppositeCharacter || item.oppCharacter || "",
oppositeCharacter: item.oppositeCharacter || item.oppCharacter || "",
displayName: "",
@@ -1445,16 +1318,6 @@ function buildPartyStateFromList(list = []) {
return normalizePartyState(result);
}
-function getCompanyNatureByOppositeCharacter(value) {
- const map = {
- 1: "境内组织",
- 2: "境内个人",
- 3: "境外组织",
- 4: "境外个人",
- };
- return map[String(value || "")] || "";
-}
-
function isPartyFilled(party = {}) {
const ignoreKeys = new Set([
"localId",
@@ -1834,11 +1697,6 @@ const ourPartySummaryText = computed(() =>
: "未填写",
);
-const allPartyDetails = computed(() => [
- ...ourParties.value,
- ...counterpartyParties.value,
-]);
-
const signingSubjectCodeText = computed(() =>
ourParties.value
.map((party) => String(party.subjectCode || "").trim())
@@ -1870,6 +1728,23 @@ const requiresAuthAttachment = computed(() =>
["GZBSQRQZ", "HTZYZBSQRQZ"].includes(detailState.value.sealType),
);
+function forceSingleAgreementDefaults() {
+ if (!isSingleAgreementChecked.value || !currentSelfParty.value) return;
+ detailState.value.isElectron = "0";
+ detailState.value.sealType = "YWZ";
+ detailState.value.partyState.ourPartyList = [
+ {
+ ...createEmptyParty(PARTY_ROLE_OUR, 0),
+ ...currentSelfParty.value,
+ localId:
+ detailState.value.partyState.ourPartyList?.[0]?.localId ||
+ createLocalId("our"),
+ },
+ ];
+ detailState.value.partyState.counterpartyList = [];
+ refreshPartyDisplayMeta();
+}
+
function syncUploadLists() {
otherAttachmentList.value = (detailState.value.otherAttachmentList || []).map(
(item, index) => ({
@@ -1943,15 +1818,6 @@ function showSearchTip(title) {
message.info(`${title}数据已从客户/主体库加载,可直接在下拉框搜索选择。`);
}
-function showInvoiceTitles(party, roleName) {
- const titles = party.invoiceTitleOptions || [];
- message.info(
- titles.length
- ? `${roleName}备选开票抬头:${titles.join(";")}`
- : `${roleName}暂无备选开票抬头`,
- );
-}
-
function filterPartnerOption(input, option) {
const keyword = String(input || "")
.trim()
@@ -1978,27 +1844,6 @@ function getRelativeTypeLabel(value) {
return map[value] || value || "";
}
-function getOrganizationNatureLabel(value) {
- const map = {
- ZY: "政府",
- QY: "企业",
- QT: "其他组织",
- };
- return map[value] || value || "";
-}
-
-function getEnterpriseNatureLevel2Label(value) {
- const map = {
- GNQY: "国有企业",
- MYQY: "民营企业",
- WZQY: "外资企业",
- HZQY: "合资企业",
- GYQZHKGQY: "国有全资和控股企业",
- QT: "其他",
- };
- return map[value] || value || "";
-}
-
function mapPartnerToParty(raw = {}, roleKey, companyName) {
const firstContact = raw.contacts?.[0] || {};
const roleCode =
@@ -2013,17 +1858,9 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
companyType: getRelativeTypeLabel(raw.relativeType),
oppositeCharacter: raw.oppositeCharacter || "",
oppCharacter: raw.oppositeCharacter || "",
- companyNature: getCompanyNatureByOppositeCharacter(raw.oppositeCharacter),
- organizationNature: getOrganizationNatureLabel(raw.natureOfEnterpriseOrg),
- enterpriseNatureLevel2: getEnterpriseNatureLevel2Label(
- raw.natureOfEnterpriseOrgLev,
- ),
creditCode: raw.customerTaxno || "",
- tinNo: raw.tinCode || "",
- countryCode: raw.country || "",
legalRepresentative: raw.legalPersonName || "",
registeredAddress: raw.customerRegaddr || "",
- registeredCapital: raw.regCapital || raw.registeredCapital || "",
contactName: firstContact.contactName || "",
contactPhone: firstContact.contactPhone || raw.officephone || "",
contactEmail: firstContact.email || raw.emailAddress || "",
@@ -2034,7 +1871,6 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
naturalPersonIdNumber: raw.certificateNum || "",
isGroupInternal: raw.groupFlag === "Y" || raw.isJtn === "1",
isHongKongMacaoTaiwan: raw.gatFlag === "Y" || raw.isSgat === "1",
- invoiceTitleOptions: raw.customerNameC ? [raw.customerNameC] : [],
roleCode,
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
};
@@ -2109,13 +1945,12 @@ function handleCompanySelect(party, companyName, option = {}) {
legalRepresentative:
party.legalRepresentative || profile.legalRepresentative,
creditCode: party.creditCode || profile.creditCode,
- oppCharacter:
- party.oppCharacter ||
- (String(party.companyNature || "").includes("个人") ? "2" : "1"),
+ oppCharacter: party.oppCharacter || "1",
});
}
function handleAddOurParty() {
+ if (isSingleAgreementChecked.value) return;
detailState.value.partyState.ourPartyList =
detailState.value.partyState.ourPartyList || [];
detailState.value.partyState.ourPartyList.push(
@@ -2136,6 +1971,7 @@ function handleContractTypeCodeChange(value) {
}
function handleAddCounterparty() {
+ if (isSingleAgreementChecked.value) return;
detailState.value.partyState.counterpartyList =
detailState.value.partyState.counterpartyList || [];
detailState.value.partyState.counterpartyList.push(
@@ -2148,6 +1984,7 @@ function handleAddCounterparty() {
}
function handleRemoveOurParty(localId) {
+ if (isSingleAgreementChecked.value) return;
detailState.value.partyState.ourPartyList = (
detailState.value.partyState.ourPartyList || []
).filter((item) => item.localId !== localId);
@@ -2160,6 +1997,7 @@ function handleRemoveOurParty(localId) {
}
function handleRemoveCounterparty(localId) {
+ if (isSingleAgreementChecked.value) return;
detailState.value.partyState.counterpartyList = (
detailState.value.partyState.counterpartyList || []
).filter((item) => item.localId !== localId);
@@ -2247,7 +2085,7 @@ async function downloadFile(filePath, fileName = "附件") {
}
try {
const resp = await downloadLaunchFile(filePath);
- const arrayBuffer = resp.data;
+ const arrayBuffer = resp?.data ?? resp;
const blob = new Blob([arrayBuffer]);
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
@@ -2336,6 +2174,16 @@ function validateState() {
) {
return "当前登录主体必须包含在我方主体中";
}
+ if (
+ isSingleAgreementChecked.value &&
+ currentSelfSubjectCode.value &&
+ ourParties.value.some(
+ (party) =>
+ String(party.subjectCode || "").trim() !== currentSelfSubjectCode.value,
+ )
+ ) {
+ return "单方协议仅允许使用当前登录主体";
+ }
if (!isSingleAgreementChecked.value && !counterpartyParties.value.length)
return "请至少添加一个相对方";
if (
@@ -2405,6 +2253,7 @@ function validateState() {
if (!detailState.value.contractBodyFileName?.trim())
return "请先配置合同正文";
if (
+ !isSingleAgreementChecked.value &&
requiresAuthAttachment.value &&
!(detailState.value.authAttachmentList || []).length
)
@@ -2473,9 +2322,7 @@ function buildLaunchRecord() {
oppositeId: party.oppositeId,
companyName: party.companyName,
companyType: party.companyType,
- oppositeCharacter:
- party.oppCharacter ||
- (String(party.companyNature || "").includes("个人") ? "2" : "1"),
+ oppositeCharacter: party.oppCharacter || "1",
contactName: party.contactName,
contactPhone: party.contactPhone,
contactEmail: party.contactEmail,
@@ -2501,9 +2348,7 @@ function buildLaunchRecord() {
oppositeId: party.oppositeId,
companyName: party.companyName,
companyType: party.companyType,
- oppositeCharacter:
- party.oppCharacter ||
- (String(party.companyNature || "").includes("个人") ? "2" : "1"),
+ oppositeCharacter: party.oppCharacter || "1",
contactName: party.contactName,
contactPhone: party.contactPhone,
contactEmail: party.contactEmail,
@@ -2675,7 +2520,6 @@ function applySelfProfile(profile = {}) {
bankAccount: profile.bankAccount || "",
legalRepresentative: profile.legalRepresentative || "",
creditCode: profile.creditCode || "",
- invoiceTitleOptions: profile.invoiceTitleOptions || [],
};
const shouldHydrateFirstParty =
!firstOurParty.companyName ||
@@ -2699,12 +2543,11 @@ function applySelfProfile(profile = {}) {
legalRepresentative:
profile.legalRepresentative || firstOurParty.legalRepresentative,
creditCode: profile.creditCode || firstOurParty.creditCode,
- invoiceTitleOptions:
- profile.invoiceTitleOptions || firstOurParty.invoiceTitleOptions || [],
},
...(detailState.value.partyState.ourPartyList || []).slice(1),
];
refreshPartyDisplayMeta();
+ forceSingleAgreementDefaults();
}
async function showModal(context = {}, mode = "create") {
@@ -2724,6 +2567,7 @@ async function showModal(context = {}, mode = "create") {
detailState.value = copyContractFormData(source);
const selfProfile = await getLaunchSelfProfile();
applySelfProfile(selfProfile || {});
+ forceSingleAgreementDefaults();
syncCounterpartyState();
syncUploadLists();
loadPartnerOptions();
diff --git a/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue b/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue
index 10ba189..74b7512 100644
--- a/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue
+++ b/src/views/contract/launch/components/ContractTemplateFillDemoModal.vue
@@ -1170,7 +1170,7 @@ async function fetchTemplateBuffer(templateFilePath) {
}
const resp = await downloadTemplateFile(templateFilePath);
- const arrayBuffer = resp.data;
+ const arrayBuffer = resp?.data ?? resp;
const buffer =
arrayBuffer instanceof ArrayBuffer ? arrayBuffer : arrayBuffer?.buffer;
templateBufferCache.set(templateFilePath, buffer);
diff --git a/src/views/contract/launch/components/UploadSignedModal.vue b/src/views/contract/launch/components/UploadSignedModal.vue
index 1814cdc..4d45725 100644
--- a/src/views/contract/launch/components/UploadSignedModal.vue
+++ b/src/views/contract/launch/components/UploadSignedModal.vue
@@ -1,7 +1,7 @@
-
+
- 点击或将已签署文件拖拽到这里
+ {{ isSingleAgreement ? "点击或将已盖章文件拖拽到这里" : "点击或将已签署文件拖拽到这里" }}
支持 PDF、DOC、DOCX 文件,且小于 20M
@@ -79,11 +79,11 @@
/>
-
+
@@ -111,13 +111,15 @@ const activeDate = ref("");
const dragOver = ref(false);
const submitting = ref(false);
const fileInputRef = ref(null);
+const isSingleAgreement = ref(false);
const emit = defineEmits(["done"]);
function showModal(record) {
row.value = record;
+ isSingleAgreement.value = String(record?.isSingleAgreement || "0") === "1";
uploadFile.value = null;
- offlineReason.value = "";
+ offlineReason.value = isSingleAgreement.value ? "内部审批通过后线下加盖业务章" : "";
signDate.value = sliceDateValue(record?.signDate) || todayString();
sealDate.value = sliceDateValue(record?.sealDate) || signDate.value;
activeDate.value = sliceDateValue(record?.activeDate) || sliceDateValue(record?.effectiveStart);
@@ -201,12 +203,12 @@ function formatFileSize(bytes) {
async function handleSubmit() {
if (!uploadFile.value) {
- message.warning("请先上传已签署文件");
+ message.warning(isSingleAgreement.value ? "请先上传已盖章文件" : "请先上传已签署文件");
return;
}
const reason = (offlineReason.value || "").trim();
if (!reason) {
- message.warning("请填写不在线签署的原因");
+ message.warning(isSingleAgreement.value ? "请填写盖章说明" : "请填写不在线签署的原因");
return;
}
if (!signDate.value) {
@@ -242,7 +244,7 @@ async function handleSubmit() {
const fileSize = uploadFile.value.size;
const finishRes = await finishLaunchSeal(row.value.id, {
- sealContractId: row.value.sealContractId || `OFFLINE-SEAL-${row.value.id}`,
+ sealContractId: row.value.sealContractId || `${isSingleAgreement.value ? "OFFLINE-SINGLE" : "OFFLINE-SEAL"}-${row.value.id}`,
sealContractStatus: 2000,
signedFileName: fileName,
signedFilePath: filePath,
@@ -260,7 +262,7 @@ async function handleSubmit() {
return;
}
- message.success("已签署版本上传成功,合同已流转到待采集");
+ message.success(isSingleAgreement.value ? "盖章版上传成功,单方协议已办结" : "已签署版本上传成功,合同已流转到待采集");
visible.value = false;
emit("done");
} catch (err) {
diff --git a/src/views/contract/launch/contractLaunchOptions.js b/src/views/contract/launch/contractLaunchOptions.js
index b046043..8289c16 100644
--- a/src/views/contract/launch/contractLaunchOptions.js
+++ b/src/views/contract/launch/contractLaunchOptions.js
@@ -50,6 +50,7 @@ export const currencyOptions = [
];
export const sealTypeOptions = [
+ { label: "内部业务章", value: "YWZ" },
{ label: "公章", value: "GZ" },
{ label: "合同专用章", value: "HTZYZ" },
{ label: "公章+法定代表人私章", value: "GZFDDBRSZ" },
diff --git a/src/views/contract/launch/index.vue b/src/views/contract/launch/index.vue
index 62b094a..3fa8609 100644
--- a/src/views/contract/launch/index.vue
+++ b/src/views/contract/launch/index.vue
@@ -10,17 +10,29 @@
-
+
-
+
-
+
@@ -55,10 +67,36 @@
- 查询
- 重置
- 发起合同
- 删除
+ 查询
+ 重置
+ 发起合同
+ 发起单方协议
+ 删除
@@ -74,33 +112,97 @@
:checkbox-config="{ range: true }"
:data="tableData"
:loading="loading"
- :loading-config="{ icon: 'vxe-icon-indicator roll', text: '正在拼命加载中...' }"
+ :loading-config="{
+ icon: 'vxe-icon-indicator roll',
+ text: '正在拼命加载中...',
+ }"
@checkbox-range-change="selectChangeEvent"
@checkbox-change="selectChangeEvent"
@checkbox-all="selectChangeEvent"
>
-
-
-
-
+
+
+
+
- {{ getContractTypeSimpleLabel(row.contractTypeCode || row.contractType) }}
+ {{
+ getContractTypeSimpleLabel(
+ row.contractTypeCode || row.contractType,
+ )
+ }}
-
-
+
+
- {{ getStatusLabel(row.status) }}
+ {{
+ getStatusLabelByRow(row)
+ }}
-
-
-
-
-
+
+
+
+
+
@@ -141,10 +273,22 @@
/>
-
-
-
-
+
+
+
+
@@ -302,6 +446,13 @@ function getStatusColor(status) {
return statusColorMap[status] || "default";
}
+function getStatusLabelByRow(row) {
+ if (isSingleAgreementRecord(row) && row?.status === "pending_sign") {
+ return "待盖章";
+ }
+ return getStatusLabel(row?.status);
+}
+
function canEdit(row) {
return ["draft", "rejected"].includes(row.status);
}
@@ -316,7 +467,9 @@ function canSubmit(row) {
function canChange(row) {
// 变更/补充协议:仅已完成/待采集/待归档的合同允许基于它发起变更
- return ["completed", "pending_archive", "pending_collect"].includes(row.status);
+ return ["completed", "pending_archive", "pending_collect"].includes(
+ row.status,
+ );
}
function canMockApprove(row) {
@@ -329,11 +482,21 @@ function canMockReject(row) {
function canOnlineSign(row) {
// 在线签订只对电子合同开放;纸质/线下签署走“上传已签署版本”兜底。
- return String(row.isElectron || "1") === "1" && ["pending_sign", "signing"].includes(row.status);
+ return (
+ !isSingleAgreementRecord(row) &&
+ String(row.isElectron || "1") === "1" &&
+ ["pending_sign", "signing"].includes(row.status)
+ );
}
function canMockFinishSign(row) {
- return String(row.isElectron || "1") === "1" && ["pending_sign", "signing"].includes(row.status);
+ if (isSingleAgreementRecord(row)) {
+ return row.status === "pending_sign";
+ }
+ return (
+ String(row.isElectron || "1") === "1" &&
+ ["pending_sign", "signing"].includes(row.status)
+ );
}
function canUploadSigned(row) {
@@ -341,11 +504,11 @@ function canUploadSigned(row) {
}
function canCollect(row) {
- return row.status === "pending_collect";
+ return !isSingleAgreementRecord(row) && row.status === "pending_collect";
}
function canArchive(row) {
- return row.status === "pending_archive";
+ return !isSingleAgreementRecord(row) && row.status === "pending_archive";
}
function isSingleAgreementRecord(row) {
@@ -353,14 +516,34 @@ function isSingleAgreementRecord(row) {
}
function canViewApprove(row) {
- return !isSingleAgreementRecord(row)
- && Boolean(row.lawContractId)
- && ["reviewing", "rejected", "pending_sign", "signing", "pending_collect", "pending_archive", "completed"].includes(row.status);
+ return (
+ !isSingleAgreementRecord(row) &&
+ Boolean(row.lawContractId) &&
+ [
+ "reviewing",
+ "rejected",
+ "pending_sign",
+ "signing",
+ "pending_collect",
+ "pending_archive",
+ "completed",
+ ].includes(row.status)
+ );
}
function canViewLawCallback(row) {
- return !isSingleAgreementRecord(row)
- && ["reviewing", "rejected", "pending_sign", "signing", "pending_collect", "pending_archive", "completed"].includes(row.status);
+ return (
+ !isSingleAgreementRecord(row) &&
+ [
+ "reviewing",
+ "rejected",
+ "pending_sign",
+ "signing",
+ "pending_collect",
+ "pending_archive",
+ "completed",
+ ].includes(row.status)
+ );
}
function canDownloadSigned(row) {
@@ -441,6 +624,10 @@ function handleCreate() {
contractModalRef.value?.showModal({}, "create");
}
+function handleCreateSingleAgreement() {
+ contractModalRef.value?.showModal({ isSingleAgreement: "1" }, "create");
+}
+
function handleView(row) {
getLaunchDetail(row.id).then((res) => {
if (!isSuccessResponse(res) || !getDataResult(res)) {
@@ -511,20 +698,34 @@ function handleSubmit(row) {
Modal.confirm({
title: singleAgreement ? "确认提交内部审批" : "确认提交法务审批",
content: h("div", [
- h("p", singleAgreement
- ? `确定将单方协议【${row.contractName}】提交内部审批吗?`
- : `确定将合同【${row.contractName}】提交法务系统审批吗?`),
- h("p", { style: { color: "#999", fontSize: "12px" } }, "提交后合同进入「审批中」状态,审批完成前不可编辑。"),
+ h(
+ "p",
+ singleAgreement
+ ? `确定将单方协议【${row.contractName}】提交内部审批吗?`
+ : `确定将合同【${row.contractName}】提交法务系统审批吗?`,
+ ),
+ h(
+ "p",
+ { style: { color: "#999", fontSize: "12px" } },
+ "提交后合同进入「审批中」状态,审批完成前不可编辑。",
+ ),
]),
okText: "确认提交",
cancelText: "取消",
onOk: () =>
submitLaunchRecord(row.id).then((res) => {
if (!isSuccessResponse(res)) {
- message.error(getResponseMessage(res, singleAgreement ? "提交内部审批失败" : "提交法务失败"));
+ message.error(
+ getResponseMessage(
+ res,
+ singleAgreement ? "提交内部审批失败" : "提交法务失败",
+ ),
+ );
return;
}
- message.success(singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批");
+ message.success(
+ singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批",
+ );
getList();
}),
icon: null,
@@ -555,48 +756,84 @@ function handleViewApprove(row) {
}
function buildLawCallbackModalContent(sample) {
- const approvedJson = JSON.stringify({ data: sample?.approvedData || {} }, null, 2);
- const rejectedJson = JSON.stringify({ data: sample?.rejectedData || {} }, null, 2);
- return h("div", { style: { display: "flex", flexDirection: "column", gap: "12px" } }, [
- h("div", [
- h("div", { style: { marginBottom: "6px", fontWeight: 600 } }, "回调地址"),
- h("div", { style: { color: "#666", wordBreak: "break-all" } }, `${sample?.callbackMethod || "POST"} ${sample?.callbackUrl || "/contract/launch/callback/law/approve"}`),
- ]),
- h("div", [
- h("div", { style: { marginBottom: "6px", fontWeight: 600 } }, "审批通过 data"),
- h("pre", {
- style: {
- margin: 0,
- maxHeight: "260px",
- overflow: "auto",
- padding: "12px",
- borderRadius: "8px",
- background: "#f6f8fa",
- fontSize: "12px",
- lineHeight: "1.6",
- whiteSpace: "pre-wrap",
- wordBreak: "break-word",
- },
- }, approvedJson),
- ]),
- h("div", [
- h("div", { style: { marginBottom: "6px", fontWeight: 600 } }, "审批驳回 data"),
- h("pre", {
- style: {
- margin: 0,
- maxHeight: "220px",
- overflow: "auto",
- padding: "12px",
- borderRadius: "8px",
- background: "#f6f8fa",
- fontSize: "12px",
- lineHeight: "1.6",
- whiteSpace: "pre-wrap",
- wordBreak: "break-word",
- },
- }, rejectedJson),
- ]),
- ]);
+ const approvedJson = JSON.stringify(
+ { data: sample?.approvedData || {} },
+ null,
+ 2,
+ );
+ const rejectedJson = JSON.stringify(
+ { data: sample?.rejectedData || {} },
+ null,
+ 2,
+ );
+ return h(
+ "div",
+ { style: { display: "flex", flexDirection: "column", gap: "12px" } },
+ [
+ h("div", [
+ h(
+ "div",
+ { style: { marginBottom: "6px", fontWeight: 600 } },
+ "回调地址",
+ ),
+ h(
+ "div",
+ { style: { color: "#666", wordBreak: "break-all" } },
+ `${sample?.callbackMethod || "POST"} ${sample?.callbackUrl || "/contract/launch/callback/law/approve"}`,
+ ),
+ ]),
+ h("div", [
+ h(
+ "div",
+ { style: { marginBottom: "6px", fontWeight: 600 } },
+ "审批通过 data",
+ ),
+ h(
+ "pre",
+ {
+ style: {
+ margin: 0,
+ maxHeight: "260px",
+ overflow: "auto",
+ padding: "12px",
+ borderRadius: "8px",
+ background: "#f6f8fa",
+ fontSize: "12px",
+ lineHeight: "1.6",
+ whiteSpace: "pre-wrap",
+ wordBreak: "break-word",
+ },
+ },
+ approvedJson,
+ ),
+ ]),
+ h("div", [
+ h(
+ "div",
+ { style: { marginBottom: "6px", fontWeight: 600 } },
+ "审批驳回 data",
+ ),
+ h(
+ "pre",
+ {
+ style: {
+ margin: 0,
+ maxHeight: "220px",
+ overflow: "auto",
+ padding: "12px",
+ borderRadius: "8px",
+ background: "#f6f8fa",
+ fontSize: "12px",
+ lineHeight: "1.6",
+ whiteSpace: "pre-wrap",
+ wordBreak: "break-word",
+ },
+ },
+ rejectedJson,
+ ),
+ ]),
+ ],
+ );
}
function handleViewLawCallback(row) {
@@ -618,7 +855,9 @@ function handleViewLawCallback(row) {
function handleMockApprove(row) {
const singleAgreement = isSingleAgreementRecord(row);
Modal.confirm({
- title: singleAgreement ? "测试操作:模拟内部审批通过" : "测试操作:模拟审批通过",
+ title: singleAgreement
+ ? "测试操作:模拟内部审批通过"
+ : "测试操作:模拟审批通过",
content: singleAgreement
? `模拟单方协议【${row.contractName}】内部审批通过,状态将变为「待签署」。`
: `模拟法务审批通过合同【${row.contractName}】,状态将变为「待签署」。`,
@@ -640,12 +879,21 @@ function handleMockApprove(row) {
function handleMockReject(row) {
const singleAgreement = isSingleAgreementRecord(row);
Modal.confirm({
- title: singleAgreement ? "测试操作:模拟内部审批驳回" : "测试操作:模拟审批驳回",
+ title: singleAgreement
+ ? "测试操作:模拟内部审批驳回"
+ : "测试操作:模拟审批驳回",
content: h("div", [
- h("p", singleAgreement
- ? `模拟单方协议【${row.contractName}】内部审批驳回,状态将回到「已驳回」。`
- : `模拟法务审批驳回合同【${row.contractName}】,状态将回到「已驳回」。`),
- h("p", { style: { color: "#999", fontSize: "12px" } }, "驳回后可重新编辑再提交。"),
+ h(
+ "p",
+ singleAgreement
+ ? `模拟单方协议【${row.contractName}】内部审批驳回,状态将回到「已驳回」。`
+ : `模拟法务审批驳回合同【${row.contractName}】,状态将回到「已驳回」。`,
+ ),
+ h(
+ "p",
+ { style: { color: "#999", fontSize: "12px" } },
+ "驳回后可重新编辑再提交。",
+ ),
]),
okText: "确认驳回",
cancelText: "取消",
@@ -663,15 +911,23 @@ function handleMockReject(row) {
}
function handleMockFinishSign(row) {
+ const singleAgreement = isSingleAgreementRecord(row);
Modal.confirm({
- title: "测试操作:模拟签署完成",
- content: `模拟合同【${row.contractName}】签署完成,状态将变为「待采集」。`,
+ title: singleAgreement
+ ? "测试操作:模拟盖章完成"
+ : "测试操作:模拟签署完成",
+ content: singleAgreement
+ ? `模拟单方协议【${row.contractName}】内部业务章加盖完成,状态将变为「已完成」。`
+ : `模拟合同【${row.contractName}】签署完成,状态将变为「待采集」。`,
okText: "确认模拟",
cancelText: "取消",
onOk: () => {
const signDate = sliceDateValue(row.signDate) || todayString();
const sealDate = sliceDateValue(row.sealDate) || signDate;
- const activeDate = sliceDateValue(row.activeDate) || sliceDateValue(row.effectiveStart) || signDate;
+ const activeDate =
+ sliceDateValue(row.activeDate) ||
+ sliceDateValue(row.effectiveStart) ||
+ signDate;
return finishLaunchSeal(row.id, {
sealContractId: row.sealContractId || `TEST-SEAL-${row.id}`,
sealContractStatus: 2000,
@@ -679,16 +935,27 @@ function handleMockFinishSign(row) {
signedFilePath: row.contractTextFilePath || `mock-signed/${row.id}.pdf`,
signedFileType: "pdf",
signedFileSize: row.contractTextFileSize || null,
- signedOfflineReason: "测试按钮模拟签署完成,真实签章接入后可删除此按钮",
+ signedOfflineReason: singleAgreement
+ ? "测试按钮模拟内部业务章加盖完成"
+ : "测试按钮模拟签署完成,真实签章接入后可删除此按钮",
signDate: formatDateTimeValue(signDate),
sealDate: formatDateTimeValue(sealDate),
activeDate: formatDateTimeValue(activeDate),
}).then((res) => {
if (!isSuccessResponse(res)) {
- message.error(getResponseMessage(res, "测试签署完成失败"));
+ message.error(
+ getResponseMessage(
+ res,
+ singleAgreement ? "测试盖章完成失败" : "测试签署完成失败",
+ ),
+ );
return;
}
- message.success("测试签署完成,合同已流转到待采集");
+ message.success(
+ singleAgreement
+ ? "测试盖章完成,单方协议已办结"
+ : "测试签署完成,合同已流转到待采集",
+ );
getList();
});
},
@@ -698,24 +965,28 @@ function handleMockFinishSign(row) {
function handleDownloadSigned(row) {
const filePath = row.signedFilePath;
- const fileName = row.signedFileName || `${row.contractName || "合同"}-已签署版.pdf`;
+ const fileName =
+ row.signedFileName || `${row.contractName || "合同"}-已签署版.pdf`;
if (!filePath) {
message.warning("暂无签署文件可下载");
return;
}
- downloadLaunchFile(filePath).then((res) => {
- const blob = new Blob([res.data]);
- const url = window.URL.createObjectURL(blob);
- const link = document.createElement("a");
- link.href = url;
- link.download = fileName;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- window.URL.revokeObjectURL(url);
- }).catch(() => {
- message.error("签署文件下载失败");
- });
+ downloadLaunchFile(filePath)
+ .then((res) => {
+ const arrayBuffer = res?.data ?? res;
+ const blob = new Blob([arrayBuffer]);
+ const url = window.URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = url;
+ link.download = fileName;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ window.URL.revokeObjectURL(url);
+ })
+ .catch(() => {
+ message.error("签署文件下载失败");
+ });
}
function handleUploadSigned(row) {
@@ -741,7 +1012,8 @@ function handleSignBusinessUpdated() {
}
function handleModalSave(payload) {
- const requestFn = payload.mode === "edit" ? updateLaunchDraft : createLaunchDraft;
+ const requestFn =
+ payload.mode === "edit" ? updateLaunchDraft : createLaunchDraft;
requestFn(payload.record).then((res) => {
if (!isSuccessResponse(res)) {
message.error(getResponseMessage(res, "保存合同失败"));
@@ -792,16 +1064,23 @@ function handleTerminate(row) {
let terminateReason = "";
Modal.confirm({
title: `确认终止合同【${row.contractName}】吗?`,
- content: h("div", { style: { display: "flex", flexDirection: "column", gap: "12px" } }, [
- h("div", "除已完成外,任意环节都可终止。当前仅终止业务系统内流程,法务系统需分别操作。"),
- h(Input.TextArea, {
- rows: 4,
- placeholder: "可选:请输入终止原因",
- onChange: (event) => {
- terminateReason = event?.target?.value || "";
- },
- }),
- ]),
+ content: h(
+ "div",
+ { style: { display: "flex", flexDirection: "column", gap: "12px" } },
+ [
+ h(
+ "div",
+ "除已完成外,任意环节都可终止。当前仅终止业务系统内流程,法务系统需分别操作。",
+ ),
+ h(Input.TextArea, {
+ rows: 4,
+ placeholder: "可选:请输入终止原因",
+ onChange: (event) => {
+ terminateReason = event?.target?.value || "";
+ },
+ }),
+ ],
+ ),
okText: "确认终止",
cancelText: "取消",
okType: "danger",
diff --git a/src/views/contract/log/index.vue b/src/views/contract/log/index.vue
index 0b88a68..47143d3 100644
--- a/src/views/contract/log/index.vue
+++ b/src/views/contract/log/index.vue
@@ -371,7 +371,8 @@ function handleExportExcel() {
pageNo: 1,
pageSize: 10000,
}).then((data) => {
- const blob = new Blob([data], {
+ const arrayBuffer = data?.data ?? data;
+ const blob = new Blob([arrayBuffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
saveAs(blob, `合同日志_${Date.now()}.xlsx`);
diff --git a/src/views/contract/manifest/components/ContractTemplateManageModal.vue b/src/views/contract/manifest/components/ContractTemplateManageModal.vue
index d1aadae..b3063b7 100644
--- a/src/views/contract/manifest/components/ContractTemplateManageModal.vue
+++ b/src/views/contract/manifest/components/ContractTemplateManageModal.vue
@@ -559,8 +559,9 @@ async function handleTemplateFile(file) {
}
const downloadedBuffer = await downloadTemplateFile(uploadedFilePath)
+ const downloadedArrayBuffer = downloadedBuffer?.data ?? downloadedBuffer
const previewBuffer =
- downloadedBuffer.data instanceof ArrayBuffer ? downloadedBuffer.data : downloadedBuffer.data?.buffer
+ downloadedArrayBuffer instanceof ArrayBuffer ? downloadedArrayBuffer : downloadedArrayBuffer?.buffer
if (!previewBuffer) {
message.error('模板文件已上传,但回读渲染失败')
@@ -798,7 +799,8 @@ async function handleSubmit(status) {
async function loadTemplateBufferFromRecord(record) {
if (record.templateFilePath) {
const response = await downloadTemplateFile(record.templateFilePath)
- templateArrayBuffer.value = response.data instanceof ArrayBuffer ? response.data.slice(0) : response.data
+ const arrayBuffer = response?.data ?? response
+ templateArrayBuffer.value = arrayBuffer instanceof ArrayBuffer ? arrayBuffer.slice(0) : arrayBuffer
setUploadList(record.templateFileName)
}
}
diff --git a/src/views/seal/mixedSignModal.vue b/src/views/seal/mixedSignModal.vue
index 16fe290..09ecfa5 100644
--- a/src/views/seal/mixedSignModal.vue
+++ b/src/views/seal/mixedSignModal.vue
@@ -487,24 +487,33 @@
{
+ if (typeof item === "string") return item;
+ if (!item || typeof item !== "object") return "";
+ return (
+ item.url ||
+ item.imageUrl ||
+ item.previewUrl ||
+ item.fileUrl ||
+ item.path ||
+ ""
+ );
+ })
+ .filter(Boolean);
+}
+
function syncCompletionDates(record = {}) {
completeSignDate.value = sliceDateValue(record?.signDate) || todayString();
completeSealDate.value = sliceDateValue(record?.sealDate) || completeSignDate.value;
@@ -895,7 +921,11 @@ async function buildBusinessBodyUploadFile(record = {}) {
if (!bodyFile.filePath) {
return null;
}
- const buffer = await downloadLaunchFile(bodyFile.filePath);
+ const response = await downloadLaunchFile(bodyFile.filePath);
+ const buffer = response?.data ?? response;
+ if (!buffer) {
+ throw new Error("合同正文下载结果为空");
+ }
const type =
String(bodyFile.fileType || "").toLowerCase() === "pdf"
? "application/pdf"
@@ -1108,7 +1138,7 @@ async function loadContract(cid) {
contractName.value = detail?.contractName || contractName.value;
contractStatus.value =
detail?.contractStatus ?? detail?.status ?? contractStatus.value;
- pdfImages.value = preview?.pdfToImageList || [];
+ pdfImages.value = normalizePdfPreviewImages(preview?.pdfToImageList);
imageWidth.value = Number(preview?.imageWidth) || 793;
imageHeight.value = Number(preview?.imageHeight) || 1122;
updateBusinessStatusByContractStatus(contractStatus.value);
@@ -1144,7 +1174,7 @@ async function handleCreateContract() {
const data = getResponseResult(res);
contractId.value = data.contractId || "";
- pdfImages.value = data.pdfToImageList || [];
+ pdfImages.value = normalizePdfPreviewImages(data.pdfToImageList);
imageWidth.value = Number(data.imageWidth) || 793;
imageHeight.value = Number(data.imageHeight) || 1122;
contractStatus.value = 10;
@@ -1676,7 +1706,7 @@ async function confirmTimestamp(item) {
item.status = "signed";
item._signTime = data.signatureTime || "";
if (data.pdfToImageList?.length) {
- pdfImages.value = data.pdfToImageList;
+ pdfImages.value = normalizePdfPreviewImages(data.pdfToImageList);
}
if (data.contractStatus !== undefined) {
contractStatus.value = data.contractStatus;
@@ -1882,9 +1912,10 @@ watch(visible, (value) => {
}
.info-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
+ display: grid;
+ grid-template-columns: 72px minmax(0, 1fr);
+ align-items: start;
+ column-gap: 12px;
padding: 12px 0;
border-bottom: 1px dashed #eef2f6;
font-size: 14px;
@@ -1896,10 +1927,16 @@ watch(visible, (value) => {
.info-item span {
color: #64748b;
+ white-space: nowrap;
+ line-height: 1.6;
}
.info-item strong {
color: #0f172a;
+ min-width: 0;
+ overflow-wrap: anywhere;
+ word-break: break-word;
+ line-height: 1.6;
}
.business-tag-row {
@@ -1933,9 +1970,10 @@ watch(visible, (value) => {
}
.business-meta-item {
- display: flex;
- justify-content: space-between;
- gap: 12px;
+ display: grid;
+ grid-template-columns: 72px minmax(0, 1fr);
+ align-items: start;
+ column-gap: 12px;
font-size: 12px;
color: #64748b;
padding-bottom: 8px;
@@ -1947,14 +1985,22 @@ watch(visible, (value) => {
border-bottom: none;
}
+.business-meta-item span {
+ white-space: nowrap;
+ line-height: 1.6;
+}
+
.business-meta-item strong {
- flex: 1;
- text-align: right;
+ min-width: 0;
+ text-align: left;
color: #0f172a;
font-weight: 600;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ white-space: normal;
+ overflow: visible;
+ text-overflow: initial;
+ overflow-wrap: anywhere;
+ word-break: break-word;
+ line-height: 1.6;
}
.upload-mode-hint {