修改
This commit is contained in:
@@ -340,6 +340,11 @@
|
||||
{{ contractBodyHint }}
|
||||
</div>
|
||||
</div>
|
||||
<a-space v-if="detailState.contractBodyFilePath" style="margin-top: 8px">
|
||||
<a-button size="small" @click="downloadFile(detailState.contractBodyFilePath, detailState.contractBodyFileName || '合同正文.docx')">
|
||||
下载
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<div class="upload-block">
|
||||
@@ -354,6 +359,18 @@
|
||||
>
|
||||
<div class="other-upload-text">签订依据文件,对应法务 contractGistFile</div>
|
||||
</a-upload-dragger>
|
||||
<div v-if="detailState.contractGistFileList?.length" class="download-list">
|
||||
<a-space wrap>
|
||||
<a-button
|
||||
v-for="item in detailState.contractGistFileList"
|
||||
:key="item.uid || item.filePath"
|
||||
size="small"
|
||||
@click="downloadFile(item.filePath, item.name || item.fileName)"
|
||||
>
|
||||
下载 {{ item.name || item.fileName }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="upload-block">
|
||||
@@ -368,6 +385,18 @@
|
||||
>
|
||||
<div class="other-upload-text">其他附件(可上传多个文件)</div>
|
||||
</a-upload-dragger>
|
||||
<div v-if="detailState.otherAttachmentList?.length" class="download-list">
|
||||
<a-space wrap>
|
||||
<a-button
|
||||
v-for="item in detailState.otherAttachmentList"
|
||||
:key="item.uid || item.filePath"
|
||||
size="small"
|
||||
@click="downloadFile(item.filePath, item.name || item.fileName)"
|
||||
>
|
||||
下载 {{ item.name || item.fileName }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-form-item class="tight-item" label="主要内容">
|
||||
@@ -477,13 +506,13 @@
|
||||
<a-form-item class="tight-item" label="二级单位合同编码">
|
||||
<a-input
|
||||
v-model:value="detailState.selfCode"
|
||||
placeholder="选填,对应法务 selfCode"
|
||||
placeholder="选填:二级单位内部合同编码,对应法务 selfCode"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="tight-item" label="主合同编码">
|
||||
<a-input
|
||||
v-model:value="detailState.mainContractCode"
|
||||
placeholder="补录/变更合同时填写"
|
||||
placeholder="选填:补录/变更时关联主合同编码,对应法务 mainContractCode"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="tight-item" label="固定期限日期类型">
|
||||
@@ -496,7 +525,7 @@
|
||||
<a-form-item class="tight-item" label="签约主体编码">
|
||||
<a-input
|
||||
v-model:value="detailState.signingSubjectCode"
|
||||
placeholder="默认使用当前组织ID,多个用逗号分隔"
|
||||
placeholder="起草人所在主体机构编码;当前默认取登录组织ID,多个用逗号分隔"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item class="tight-item" label="开票时间">
|
||||
@@ -707,7 +736,7 @@
|
||||
|
||||
<a-collapse class="detail-collapse">
|
||||
<a-collapse-panel
|
||||
v-for="party in displayedParties"
|
||||
v-for="party in counterpartyParties"
|
||||
:key="party.roleKey"
|
||||
:header="`${party.displayName}详细字段维护`"
|
||||
>
|
||||
@@ -806,7 +835,12 @@ import { computed, ref } from "vue";
|
||||
import { message } from "ant-design-vue";
|
||||
import { PlusOutlined, SearchOutlined } from "@ant-design/icons-vue";
|
||||
import ContractTemplateFillDemoModal from "./ContractTemplateFillDemoModal.vue";
|
||||
import { queryPartnerOptions, uploadLaunchFile } from "@/api/launch.js";
|
||||
import {
|
||||
downloadLaunchFile,
|
||||
getLaunchSelfProfile,
|
||||
queryPartnerOptions,
|
||||
uploadLaunchFile,
|
||||
} from "@/api/launch.js";
|
||||
import {
|
||||
contractSourceOptions,
|
||||
contractTypeOptions,
|
||||
@@ -911,7 +945,8 @@ const paymentMethodOptions = [
|
||||
];
|
||||
|
||||
const SELF_COMPANY_NAME = "浙港物流平台有限公司";
|
||||
const MAX_COUNTERPARTY_COUNT = 2;
|
||||
const MAX_COUNTERPARTY_COUNT = 5;
|
||||
const COUNTERPARTY_ROLE_CODES = ["B", "C", "D", "E", "F"];
|
||||
|
||||
// ========== 工具函数 ==========
|
||||
|
||||
@@ -933,6 +968,40 @@ function normalizeFileItem(item = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeBooleanValue(value) {
|
||||
if (value === true || value === false) return value;
|
||||
if (value === 1 || value === "1" || value === "Y" || value === "true") return true;
|
||||
if (value === 0 || value === "0" || value === "N" || value === "false") return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
function pickBooleanSource(source = {}, key) {
|
||||
const mapping = {
|
||||
isInvolveHongKongMacaoTaiwan: [
|
||||
source.isInvolveHongKongMacaoTaiwan,
|
||||
source.isSgat,
|
||||
],
|
||||
isPublicTender: [source.isPublicTender, source.isOpenBidding],
|
||||
isForeignRelatedSubject: [
|
||||
source.isForeignRelatedSubject,
|
||||
source.contractNature,
|
||||
],
|
||||
isIncludedInCurrentYearBudget: [
|
||||
source.isIncludedInCurrentYearBudget,
|
||||
source.isYearBudget,
|
||||
],
|
||||
isShared: [source.isShared, source.isShare],
|
||||
isMajorContract: [source.isMajorContract],
|
||||
};
|
||||
const values = mapping[key] || [];
|
||||
for (const value of values) {
|
||||
if (value !== undefined && value !== null && value !== "") {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getFileNameFromDetail(source, category) {
|
||||
if (category === "body") {
|
||||
return source.contractBodyFileName || source.contractTextFileName || "";
|
||||
@@ -1021,6 +1090,12 @@ function copyPartyState(input) {
|
||||
const sourcePartyA = source.partyA || source.parties?.A || {};
|
||||
const sourcePartyB = source.partyB || source.parties?.B || {};
|
||||
const sourcePartyC = source.partyC || source.parties?.C || {};
|
||||
const sourceCounterpartyList = Array.isArray(source.counterpartyList)
|
||||
? source.counterpartyList
|
||||
: [
|
||||
String(sourcePartyB.companyName || "").trim() ? { ...sourcePartyB, roleKey: "B" } : null,
|
||||
String(sourcePartyC.companyName || "").trim() ? { ...sourcePartyC, roleKey: "C" } : null,
|
||||
].filter(Boolean);
|
||||
const state = {
|
||||
isThreePartyContract: Boolean(source.isThreePartyContract),
|
||||
partyA: {
|
||||
@@ -1044,22 +1119,33 @@ function copyPartyState(input) {
|
||||
companyName: "",
|
||||
...sourcePartyC,
|
||||
},
|
||||
counterpartyList: sourceCounterpartyList.map((item, index) => ({
|
||||
...createEmptyCounterparty(item.roleKey || COUNTERPARTY_ROLE_CODES[index]),
|
||||
...item,
|
||||
roleKey: item.roleKey || COUNTERPARTY_ROLE_CODES[index],
|
||||
displayName: `相对方${index + 1}`,
|
||||
})),
|
||||
};
|
||||
if (listState) {
|
||||
state.partyA = { ...state.partyA, ...listState.partyA };
|
||||
state.partyB = { ...state.partyB, ...listState.partyB };
|
||||
state.partyC = { ...state.partyC, ...listState.partyC };
|
||||
state.counterpartyList = listState.counterpartyList.map((item) => ({ ...item }));
|
||||
state.partyB = { ...state.partyB, ...(state.counterpartyList[0] || {}) };
|
||||
state.partyC = { ...state.partyC, ...(state.counterpartyList[1] || {}) };
|
||||
state.isThreePartyContract = listState.isThreePartyContract;
|
||||
} else {
|
||||
state.partyB = { ...state.partyB, ...(state.counterpartyList[0] || {}) };
|
||||
state.partyC = { ...state.partyC, ...(state.counterpartyList[1] || {}) };
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function mapLaunchPartyToFormParty(item = {}) {
|
||||
const roleIndex = COUNTERPARTY_ROLE_CODES.indexOf(item.roleCode || "B");
|
||||
return {
|
||||
roleKey: item.roleCode || "B",
|
||||
roleName: item.roleName || "",
|
||||
displayName:
|
||||
item.roleCode === "A" ? "我方" : item.roleCode === "C" ? "相对方2" : "相对方1",
|
||||
item.roleCode === "A" ? "我方" : `相对方${roleIndex >= 0 ? roleIndex + 1 : 1}`,
|
||||
partnerId: item.partnerId || null,
|
||||
customerSysid: item.partnerId || null,
|
||||
oppositeId: item.oppositeId || "",
|
||||
@@ -1092,14 +1178,24 @@ function buildPartyStateFromList(list = []) {
|
||||
partyA: {},
|
||||
partyB: {},
|
||||
partyC: {},
|
||||
counterpartyList: [],
|
||||
};
|
||||
list.forEach((item) => {
|
||||
if (!item?.roleCode) return;
|
||||
const targetKey =
|
||||
item.roleCode === "A" ? "partyA" : item.roleCode === "C" ? "partyC" : "partyB";
|
||||
result[targetKey] = mapLaunchPartyToFormParty(item);
|
||||
if (item.roleCode === "A") {
|
||||
result.partyA = mapLaunchPartyToFormParty(item);
|
||||
} else {
|
||||
result.counterpartyList.push(mapLaunchPartyToFormParty(item));
|
||||
}
|
||||
});
|
||||
result.isThreePartyContract = Boolean(result.partyB?.companyName && result.partyC?.companyName);
|
||||
result.counterpartyList = result.counterpartyList.map((item, index) => ({
|
||||
...item,
|
||||
roleKey: item.roleKey || COUNTERPARTY_ROLE_CODES[index],
|
||||
displayName: `相对方${index + 1}`,
|
||||
}));
|
||||
result.partyB = result.counterpartyList[0] || {};
|
||||
result.partyC = result.counterpartyList[1] || {};
|
||||
result.isThreePartyContract = result.counterpartyList.length > 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1114,8 +1210,12 @@ function getCompanyNatureByOppositeCharacter(value) {
|
||||
}
|
||||
|
||||
function createEmptyCounterparty(roleKey) {
|
||||
const blankState = copyPartyState({});
|
||||
return roleKey === "C" ? blankState.partyC : blankState.partyB;
|
||||
return {
|
||||
roleKey,
|
||||
roleName: "相对方",
|
||||
displayName: `相对方${COUNTERPARTY_ROLE_CODES.indexOf(roleKey) + 1}`,
|
||||
companyName: "",
|
||||
};
|
||||
}
|
||||
|
||||
function isPartyFilled(party = {}) {
|
||||
@@ -1129,35 +1229,37 @@ function isPartyFilled(party = {}) {
|
||||
}
|
||||
|
||||
function buildCounterpartyRoleKeys(partyState) {
|
||||
const state = copyPartyState(partyState);
|
||||
const keys = [];
|
||||
if (isPartyFilled(state.partyB)) keys.push("B");
|
||||
if (isPartyFilled(state.partyC)) keys.push("C");
|
||||
return keys;
|
||||
const state = partyState || {};
|
||||
const sourceList = Array.isArray(state.counterpartyList)
|
||||
? state.counterpartyList
|
||||
: COUNTERPARTY_ROLE_CODES.map((roleKey) => state[`party${roleKey}`]).filter(Boolean);
|
||||
return sourceList
|
||||
.filter((party) => isPartyFilled(party))
|
||||
.map((party, index) => party.roleKey || COUNTERPARTY_ROLE_CODES[index])
|
||||
.slice(0, MAX_COUNTERPARTY_COUNT);
|
||||
}
|
||||
|
||||
function normalizePartyState(partyState) {
|
||||
const state = copyPartyState(partyState);
|
||||
if (!isPartyFilled(state.partyB) && isPartyFilled(state.partyC)) {
|
||||
state.partyB = {
|
||||
...createEmptyCounterparty("B"),
|
||||
...state.partyC,
|
||||
roleKey: "B",
|
||||
roleName: "相对方",
|
||||
displayName: "相对方1",
|
||||
};
|
||||
state.partyC = createEmptyCounterparty("C");
|
||||
}
|
||||
state.partyA.companyName = state.partyA.companyName || SELF_COMPANY_NAME;
|
||||
state.isThreePartyContract =
|
||||
isPartyFilled(state.partyB) && isPartyFilled(state.partyC);
|
||||
state.counterpartyList = (Array.isArray(state.counterpartyList) ? state.counterpartyList : [])
|
||||
.filter((party) => isPartyFilled(party))
|
||||
.slice(0, MAX_COUNTERPARTY_COUNT)
|
||||
.map((party, index) => ({
|
||||
...createEmptyCounterparty(party.roleKey || COUNTERPARTY_ROLE_CODES[index]),
|
||||
...party,
|
||||
roleKey: party.roleKey || COUNTERPARTY_ROLE_CODES[index],
|
||||
displayName: `相对方${index + 1}`,
|
||||
}));
|
||||
state.partyB = state.counterpartyList[0] || createEmptyCounterparty("B");
|
||||
state.partyC = state.counterpartyList[1] || createEmptyCounterparty("C");
|
||||
state.isThreePartyContract = state.counterpartyList.length > 1;
|
||||
return state;
|
||||
}
|
||||
|
||||
function getPartyByRoleKey(partyState, roleKey) {
|
||||
if (roleKey === "A") return partyState.partyA;
|
||||
if (roleKey === "C") return partyState.partyC;
|
||||
return partyState.partyB;
|
||||
return (partyState.counterpartyList || []).find((item) => item.roleKey === roleKey);
|
||||
}
|
||||
|
||||
/** 创建一条空的履行计划 */
|
||||
@@ -1178,6 +1280,7 @@ function createPerformancePlan() {
|
||||
/** 创建空白的合同表单数据 */
|
||||
function createContractFormData() {
|
||||
return {
|
||||
id: null,
|
||||
contractName: "",
|
||||
contractCode: "",
|
||||
contractType: "",
|
||||
@@ -1217,11 +1320,14 @@ function createContractFormData() {
|
||||
contractBodyArrayBuffer: null,
|
||||
otherAttachmentList: [],
|
||||
contractGistFileList: [],
|
||||
// 正文模板字段值统一放这里,后续新增模板字段时尽量只改 templateFieldList
|
||||
templateFieldValues: {},
|
||||
partyState: {
|
||||
isThreePartyContract: false,
|
||||
partyA: { companyName: SELF_COMPANY_NAME },
|
||||
partyB: { companyName: "" },
|
||||
partyC: { companyName: "" },
|
||||
counterpartyList: [],
|
||||
},
|
||||
isInvolveHongKongMacaoTaiwan: false,
|
||||
isPublicTender: false,
|
||||
@@ -1257,6 +1363,18 @@ function copyContractFormData(data = {}) {
|
||||
Object.keys(form).forEach((key) => {
|
||||
if (key === "extraAmounts") {
|
||||
form.extraAmounts = restoreExtraAmounts(source, form.extraAmounts);
|
||||
} else if (key === "templateFieldValues") {
|
||||
if (source.templateFieldValues && typeof source.templateFieldValues === "object") {
|
||||
form.templateFieldValues = { ...source.templateFieldValues };
|
||||
} else if (source.templateFieldValuesJson) {
|
||||
try {
|
||||
form.templateFieldValues = JSON.parse(source.templateFieldValuesJson);
|
||||
} catch (error) {
|
||||
form.templateFieldValues = {};
|
||||
}
|
||||
} else {
|
||||
form.templateFieldValues = {};
|
||||
}
|
||||
} else if (key === "performancePlans") {
|
||||
form.performancePlans = (source.performancePlans || []).map((item) => ({
|
||||
...createPerformancePlan(),
|
||||
@@ -1290,6 +1408,17 @@ function copyContractFormData(data = {}) {
|
||||
} else if (key === "signingSubjectCode") {
|
||||
form.signingSubjectCode =
|
||||
source.signingSubjectCode ?? source.orgId ?? form.signingSubjectCode;
|
||||
} else if (
|
||||
[
|
||||
"isInvolveHongKongMacaoTaiwan",
|
||||
"isPublicTender",
|
||||
"isForeignRelatedSubject",
|
||||
"isIncludedInCurrentYearBudget",
|
||||
"isShared",
|
||||
"isMajorContract",
|
||||
].includes(key)
|
||||
) {
|
||||
form[key] = normalizeBooleanValue(pickBooleanSource(source, key));
|
||||
} else {
|
||||
form[key] = source[key] ?? form[key];
|
||||
}
|
||||
@@ -1358,16 +1487,11 @@ const companyProfileMap = {
|
||||
const isViewMode = computed(() => modalMode.value === "view");
|
||||
|
||||
const counterpartyParties = computed(() =>
|
||||
counterpartyRoleKeys.value.map((roleKey) =>
|
||||
getPartyByRoleKey(detailState.value.partyState, roleKey),
|
||||
(detailState.value.partyState.counterpartyList || []).filter((party) =>
|
||||
counterpartyRoleKeys.value.includes(party.roleKey),
|
||||
),
|
||||
);
|
||||
|
||||
const displayedParties = computed(() => [
|
||||
detailState.value.partyState.partyA,
|
||||
...counterpartyParties.value,
|
||||
]);
|
||||
|
||||
const counterpartySummaryText = computed(() =>
|
||||
counterpartyParties.value.length
|
||||
? counterpartyParties.value
|
||||
@@ -1412,11 +1536,10 @@ function syncUploadLists() {
|
||||
|
||||
function syncCounterpartyState() {
|
||||
detailState.value.partyState = normalizePartyState(detailState.value.partyState);
|
||||
counterpartyRoleKeys.value = buildCounterpartyRoleKeys(
|
||||
detailState.value.partyState,
|
||||
);
|
||||
detailState.value.partyState.isThreePartyContract =
|
||||
counterpartyRoleKeys.value.length > 1;
|
||||
counterpartyRoleKeys.value = buildCounterpartyRoleKeys(detailState.value.partyState);
|
||||
detailState.value.partyState.counterpartyList =
|
||||
detailState.value.partyState.counterpartyList || [];
|
||||
detailState.value.partyState.isThreePartyContract = counterpartyRoleKeys.value.length > 1;
|
||||
refreshPartyDisplayMeta();
|
||||
}
|
||||
|
||||
@@ -1425,8 +1548,8 @@ function refreshPartyDisplayMeta() {
|
||||
detailState.value.partyState.partyA.roleName = "我方";
|
||||
detailState.value.partyState.partyA.displayName = "我方";
|
||||
|
||||
counterpartyRoleKeys.value.forEach((roleKey, index) => {
|
||||
const party = getPartyByRoleKey(detailState.value.partyState, roleKey);
|
||||
(detailState.value.partyState.counterpartyList || []).forEach((party, index) => {
|
||||
const roleKey = party.roleKey || COUNTERPARTY_ROLE_CODES[index];
|
||||
party.roleKey = roleKey;
|
||||
party.roleName = "相对方";
|
||||
party.displayName = `相对方${index + 1}`;
|
||||
@@ -1443,11 +1566,19 @@ function resetCurrentState() {
|
||||
}
|
||||
|
||||
function showSearchTip(title) {
|
||||
if (title === "我方详情") {
|
||||
message.info("我方信息当前按登录组织只读带出,后续接入真实组织主数据后自动完善。");
|
||||
return;
|
||||
}
|
||||
loadPartnerOptions();
|
||||
message.info(`${title}数据已从相对方管理加载,可直接在下拉框搜索选择。`);
|
||||
}
|
||||
|
||||
function showInvoiceTitles(party, roleName) {
|
||||
if (roleName === "我方") {
|
||||
message.info("我方开票抬头当前不在发起页维护,后续建议从组织主数据自动带出。");
|
||||
return;
|
||||
}
|
||||
const titles = party.invoiceTitleOptions || [];
|
||||
message.info(
|
||||
titles.length
|
||||
@@ -1536,9 +1667,7 @@ function handleCompanySelect(roleKey, companyName, option = {}) {
|
||||
const party =
|
||||
roleKey === "A"
|
||||
? detailState.value.partyState.partyA
|
||||
: roleKey === "B"
|
||||
? detailState.value.partyState.partyB
|
||||
: detailState.value.partyState.partyC;
|
||||
: getPartyByRoleKey(detailState.value.partyState, roleKey);
|
||||
if (!party) return;
|
||||
|
||||
const rawPartner =
|
||||
@@ -1586,36 +1715,34 @@ function handleAddCounterparty() {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextRoleKey = counterpartyRoleKeys.value.includes("B") ? "C" : "B";
|
||||
detailState.value.partyState[nextRoleKey === "C" ? "partyC" : "partyB"] =
|
||||
createEmptyCounterparty(nextRoleKey);
|
||||
const nextRoleKey = COUNTERPARTY_ROLE_CODES.find(
|
||||
(roleKey) => !counterpartyRoleKeys.value.includes(roleKey),
|
||||
);
|
||||
if (!nextRoleKey) return;
|
||||
|
||||
detailState.value.partyState.counterpartyList =
|
||||
detailState.value.partyState.counterpartyList || [];
|
||||
detailState.value.partyState.counterpartyList.push(
|
||||
createEmptyCounterparty(nextRoleKey),
|
||||
);
|
||||
counterpartyRoleKeys.value = [...counterpartyRoleKeys.value, nextRoleKey];
|
||||
detailState.value.partyState.isThreePartyContract =
|
||||
counterpartyRoleKeys.value.length > 1;
|
||||
detailState.value.partyState.isThreePartyContract = counterpartyRoleKeys.value.length > 1;
|
||||
refreshPartyDisplayMeta();
|
||||
}
|
||||
|
||||
function handleRemoveCounterparty(roleKey) {
|
||||
if (roleKey === "B" && counterpartyRoleKeys.value.includes("C")) {
|
||||
detailState.value.partyState.partyB = {
|
||||
...createEmptyCounterparty("B"),
|
||||
...detailState.value.partyState.partyC,
|
||||
roleKey: "B",
|
||||
roleName: "相对方",
|
||||
displayName: "相对方1",
|
||||
};
|
||||
detailState.value.partyState.partyC = createEmptyCounterparty("C");
|
||||
counterpartyRoleKeys.value = ["B"];
|
||||
} else {
|
||||
detailState.value.partyState[roleKey === "C" ? "partyC" : "partyB"] =
|
||||
createEmptyCounterparty(roleKey);
|
||||
counterpartyRoleKeys.value = counterpartyRoleKeys.value.filter(
|
||||
(key) => key !== roleKey,
|
||||
);
|
||||
}
|
||||
|
||||
detailState.value.partyState.isThreePartyContract =
|
||||
counterpartyRoleKeys.value.length > 1;
|
||||
detailState.value.partyState.counterpartyList =
|
||||
(detailState.value.partyState.counterpartyList || [])
|
||||
.filter((item) => item.roleKey !== roleKey)
|
||||
.map((item, index) => ({
|
||||
...item,
|
||||
roleKey: COUNTERPARTY_ROLE_CODES[index],
|
||||
displayName: `相对方${index + 1}`,
|
||||
}));
|
||||
counterpartyRoleKeys.value = detailState.value.partyState.counterpartyList.map(
|
||||
(item) => item.roleKey,
|
||||
);
|
||||
detailState.value.partyState.isThreePartyContract = counterpartyRoleKeys.value.length > 1;
|
||||
refreshPartyDisplayMeta();
|
||||
}
|
||||
|
||||
@@ -1676,6 +1803,27 @@ function handleRemoveGistAttachment(file) {
|
||||
);
|
||||
}
|
||||
|
||||
async function downloadFile(filePath, fileName = "附件") {
|
||||
if (!filePath) {
|
||||
message.warning("文件路径为空,无法下载");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const arrayBuffer = await downloadLaunchFile(filePath);
|
||||
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 (error) {
|
||||
message.error("文件下载失败");
|
||||
}
|
||||
}
|
||||
|
||||
function openBodyConfigModal() {
|
||||
bodyConfigModalRef.value?.showModal(
|
||||
{
|
||||
@@ -1695,6 +1843,31 @@ function handleBodyConfigSave(payload = {}) {
|
||||
detailState.value = copyContractFormData(payload.detailState);
|
||||
syncCounterpartyState();
|
||||
syncUploadLists();
|
||||
|
||||
if (modalMode.value === "edit" && detailState.value.id) {
|
||||
const errorMessage = validateState();
|
||||
if (errorMessage) {
|
||||
message.success("合同正文配置已保存到当前页面,请继续完善主信息后再保存合同草稿。");
|
||||
return;
|
||||
}
|
||||
|
||||
syncCounterpartyState();
|
||||
detailState.value.contractAmount =
|
||||
detailState.value.contractAmount === null ||
|
||||
detailState.value.contractAmount === undefined ||
|
||||
detailState.value.contractAmount === ""
|
||||
? null
|
||||
: Number(detailState.value.contractAmount);
|
||||
|
||||
emit("save", {
|
||||
mode: modalMode.value,
|
||||
record: buildLaunchRecord(),
|
||||
successMessage: "合同正文配置已保存",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
message.success("合同正文配置已保存到当前页面,请继续点击底部“保存”提交合同草稿。");
|
||||
}
|
||||
|
||||
function addPerformancePlan() {
|
||||
@@ -1799,8 +1972,8 @@ function buildLaunchRecord() {
|
||||
|
||||
counterpartyParties.value.forEach((party, index) => {
|
||||
partyList.push({
|
||||
roleCode: index === 0 ? "B" : "C",
|
||||
roleName: index === 0 ? "乙方" : "丙方",
|
||||
roleCode: party.roleKey || COUNTERPARTY_ROLE_CODES[index],
|
||||
roleName: party.displayName || `相对方${index + 1}`,
|
||||
partnerId: party.partnerId || party.customerSysid || null,
|
||||
oppositeId: party.oppositeId,
|
||||
companyName: party.companyName,
|
||||
@@ -1869,12 +2042,8 @@ function buildLaunchRecord() {
|
||||
currencyName: detailState.value.currencyName,
|
||||
contractPeriodType: detailState.value.contractPeriodType,
|
||||
periodExplain: detailState.value.periodExplain,
|
||||
effectiveStart: detailState.value.effectiveStart
|
||||
? `${detailState.value.effectiveStart} 00:00:00`
|
||||
: null,
|
||||
effectiveEnd: detailState.value.effectiveEnd
|
||||
? `${detailState.value.effectiveEnd} 23:59:59`
|
||||
: null,
|
||||
effectiveStart: formatDateTimeValue(detailState.value.effectiveStart),
|
||||
effectiveEnd: formatDateTimeValue(detailState.value.effectiveEnd, true),
|
||||
paymentMethod: detailState.value.paymentMethod,
|
||||
primaryContent: detailState.value.primaryContent,
|
||||
amountExplain: detailState.value.amountExplain,
|
||||
@@ -1909,6 +2078,9 @@ function buildLaunchRecord() {
|
||||
signDate: formatDateTimeValue(detailState.value.signDate),
|
||||
invoiceDate: formatDateTimeValue(detailState.value.invoiceDate),
|
||||
receiveDate: formatDateTimeValue(detailState.value.receiveDate),
|
||||
templateFieldValuesJson: JSON.stringify(
|
||||
detailState.value.templateFieldValues || {},
|
||||
),
|
||||
remindDays: 3,
|
||||
signingSubjectCode: detailState.value.signingSubjectCode || "",
|
||||
extraAmounts: { ...detailState.value.extraAmounts },
|
||||
@@ -1929,17 +2101,39 @@ function buildLaunchRecord() {
|
||||
};
|
||||
}
|
||||
|
||||
function showModal(context = {}, mode = "create") {
|
||||
function applySelfProfile(profile = {}) {
|
||||
detailState.value.partyState.partyA = {
|
||||
...detailState.value.partyState.partyA,
|
||||
companyName: profile.orgName || detailState.value.partyState.partyA.companyName,
|
||||
contactPhone: profile.contactPhone || detailState.value.partyState.partyA.contactPhone,
|
||||
contactEmail: profile.contactEmail || detailState.value.partyState.partyA.contactEmail,
|
||||
contactAddress: profile.contactAddress || detailState.value.partyState.partyA.contactAddress,
|
||||
registeredAddress:
|
||||
profile.registeredAddress || detailState.value.partyState.partyA.registeredAddress,
|
||||
bankName: profile.bankName || detailState.value.partyState.partyA.bankName,
|
||||
bankAccount: profile.bankAccount || detailState.value.partyState.partyA.bankAccount,
|
||||
legalRepresentative:
|
||||
profile.legalRepresentative || detailState.value.partyState.partyA.legalRepresentative,
|
||||
creditCode: profile.creditCode || detailState.value.partyState.partyA.creditCode,
|
||||
invoiceTitleOptions:
|
||||
profile.invoiceTitleOptions || detailState.value.partyState.partyA.invoiceTitleOptions || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function showModal(context = {}, mode = "create") {
|
||||
modalMode.value = mode || "create";
|
||||
const source = context.detailState ||
|
||||
(Object.keys(context || {}).length ? context : createContractFormData());
|
||||
|
||||
creationMode.value =
|
||||
context.creationMode ||
|
||||
(source.contractBodyArrayBuffer ? "manual" : "template");
|
||||
templateKey.value = context.templateKey || "";
|
||||
templateName.value = context.templateName || "";
|
||||
source.creationMode ||
|
||||
(source.contractBodyArrayBuffer || source.contractBodyFilePath ? "manual" : "template");
|
||||
templateKey.value = context.templateKey || source.templateId || "";
|
||||
templateName.value = context.templateName || source.templateName || "";
|
||||
detailState.value = copyContractFormData(source);
|
||||
const selfProfile = await getLaunchSelfProfile();
|
||||
applySelfProfile(selfProfile || {});
|
||||
syncCounterpartyState();
|
||||
syncUploadLists();
|
||||
loadPartnerOptions();
|
||||
|
||||
Reference in New Issue
Block a user