单方协议
This commit is contained in:
@@ -37,7 +37,7 @@
|
|||||||
<div class="section-title-row counterparty-toolbar">
|
<div class="section-title-row counterparty-toolbar">
|
||||||
<div class="section-title">我方主体</div>
|
<div class="section-title">我方主体</div>
|
||||||
<a-button
|
<a-button
|
||||||
v-if="!isViewMode"
|
v-if="!isViewMode && !isSingleAgreementChecked"
|
||||||
type="link"
|
type="link"
|
||||||
class="text-action-btn"
|
class="text-action-btn"
|
||||||
@click="handleAddOurParty"
|
@click="handleAddOurParty"
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="party-empty-state" style="margin-bottom: 12px">
|
<div class="party-empty-state" style="margin-bottom: 12px">
|
||||||
当前登录主体必须包含在我方主体中
|
{{ isSingleAgreementChecked ? "单方协议默认使用当前登录主体,且不可修改" : "当前登录主体必须包含在我方主体中" }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
{{ party.displayName }}
|
{{ party.displayName }}
|
||||||
</div>
|
</div>
|
||||||
<a-button
|
<a-button
|
||||||
v-if="!isViewMode && ourParties.length > 1"
|
v-if="!isViewMode && !isSingleAgreementChecked && ourParties.length > 1"
|
||||||
type="link"
|
type="link"
|
||||||
danger
|
danger
|
||||||
class="text-action-btn"
|
class="text-action-btn"
|
||||||
@@ -73,6 +73,7 @@
|
|||||||
v-model:value="party.companyName"
|
v-model:value="party.companyName"
|
||||||
:options="getPartyOptions(party.roleCode)"
|
:options="getPartyOptions(party.roleCode)"
|
||||||
show-search
|
show-search
|
||||||
|
:disabled="isSingleAgreementChecked"
|
||||||
:placeholder="`请选择${party.displayName}`"
|
:placeholder="`请选择${party.displayName}`"
|
||||||
:filter-option="filterPartnerOption"
|
:filter-option="filterPartnerOption"
|
||||||
@change="
|
@change="
|
||||||
@@ -116,13 +117,6 @@
|
|||||||
<SearchOutlined />
|
<SearchOutlined />
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<a-button
|
|
||||||
class="invoice-btn"
|
|
||||||
@click="showInvoiceTitles(party, party.displayName)"
|
|
||||||
>
|
|
||||||
<PlusOutlined />
|
|
||||||
备选开票抬头选择
|
|
||||||
</a-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="section-title-row counterparty-toolbar">
|
<div class="section-title-row counterparty-toolbar">
|
||||||
@@ -365,7 +359,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="summary-line">
|
<div class="summary-line">
|
||||||
<span>相对方</span
|
<span>相对方</span
|
||||||
><strong>{{ counterpartySummaryText }}</strong>
|
><strong>{{ isSingleAgreementChecked ? "单方协议,无相对方" : counterpartySummaryText }}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -401,7 +395,7 @@
|
|||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="upload-block">
|
<div v-if="!isSingleAgreementChecked" class="upload-block">
|
||||||
<div class="upload-label">签订依据附件</div>
|
<div class="upload-label">签订依据附件</div>
|
||||||
<a-upload-dragger
|
<a-upload-dragger
|
||||||
:file-list="gistAttachmentList"
|
:file-list="gistAttachmentList"
|
||||||
@@ -437,7 +431,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="requiresAuthAttachment" class="upload-block">
|
<div
|
||||||
|
v-if="!isSingleAgreementChecked && requiresAuthAttachment"
|
||||||
|
class="upload-block"
|
||||||
|
>
|
||||||
<div class="upload-label">授权委托书附件</div>
|
<div class="upload-label">授权委托书附件</div>
|
||||||
<a-upload-dragger
|
<a-upload-dragger
|
||||||
:file-list="authAttachmentUploadList"
|
:file-list="authAttachmentUploadList"
|
||||||
@@ -994,86 +991,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<a-collapse class="detail-collapse">
|
|
||||||
<a-collapse-panel
|
|
||||||
v-for="party in allPartyDetails"
|
|
||||||
:key="party.localId"
|
|
||||||
:header="`${party.displayName}详细字段维护`"
|
|
||||||
>
|
|
||||||
<div class="field-grid field-grid-3">
|
|
||||||
<a-form-item class="tight-item" label="公司类型">
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.companyType"
|
|
||||||
:options="companyTypeOptions"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="公司性质">
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.companyNature"
|
|
||||||
:options="companyNatureOptions"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="组织性质">
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.organizationNature"
|
|
||||||
:options="organizationNatureOptions"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="组织性质企业二级">
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.enterpriseNatureLevel2"
|
|
||||||
:options="enterpriseNatureLevel2Options"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="统一社会信用代码">
|
|
||||||
<a-input v-model:value="party.creditCode" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="TIN号">
|
|
||||||
<a-input v-model:value="party.tinNo" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="国家/地区">
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.countryCode"
|
|
||||||
:options="countryOptions"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="法定代表人">
|
|
||||||
<a-input v-model:value="party.legalRepresentative" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item field-span-3" label="注册地址">
|
|
||||||
<a-input v-model:value="party.registeredAddress" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="注册资本">
|
|
||||||
<a-input v-model:value="party.registeredCapital" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="联系电话">
|
|
||||||
<a-input v-model:value="party.contactPhone" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="电子邮箱">
|
|
||||||
<a-input v-model:value="party.contactEmail" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item field-span-3" label="通讯地址">
|
|
||||||
<a-input v-model:value="party.contactAddress" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item" label="开户行">
|
|
||||||
<a-input v-model:value="party.bankName" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item class="tight-item field-span-2" label="银行账号">
|
|
||||||
<a-input v-model:value="party.bankAccount" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item
|
|
||||||
class="tight-item field-span-3"
|
|
||||||
label="备选开票抬头"
|
|
||||||
>
|
|
||||||
<a-select
|
|
||||||
v-model:value="party.invoiceTitleOptions"
|
|
||||||
mode="tags"
|
|
||||||
:token-separators="[',', ',']"
|
|
||||||
/>
|
|
||||||
</a-form-item>
|
|
||||||
</div>
|
|
||||||
</a-collapse-panel>
|
|
||||||
</a-collapse>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1131,11 +1048,6 @@ import {
|
|||||||
|
|
||||||
// ========== 合同方相关字典 ==========
|
// ========== 合同方相关字典 ==========
|
||||||
|
|
||||||
const partyCharacterOptions = [
|
|
||||||
{ label: "企业", value: "QY" },
|
|
||||||
{ label: "自然人", value: "ZZR" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const companyTypeOptions = [
|
const companyTypeOptions = [
|
||||||
{ label: "客户", value: "客户" },
|
{ label: "客户", value: "客户" },
|
||||||
{ label: "供应商", value: "供应商" },
|
{ label: "供应商", value: "供应商" },
|
||||||
@@ -1144,38 +1056,6 @@ const companyTypeOptions = [
|
|||||||
{ label: "其他", value: "其他" },
|
{ 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([
|
const contractCompanyOptions = ref([
|
||||||
{ label: "扬州宏富特种材料有限公司", value: "扬州宏富特种材料有限公司" },
|
{ label: "扬州宏富特种材料有限公司", value: "扬州宏富特种材料有限公司" },
|
||||||
{ label: "宁波港船务货运代理有限公司", value: "宁波港船务货运代理有限公司" },
|
{ label: "宁波港船务货运代理有限公司", value: "宁波港船务货运代理有限公司" },
|
||||||
@@ -1382,9 +1262,6 @@ function createEmptyParty(roleCode, index = 0) {
|
|||||||
companyType: "",
|
companyType: "",
|
||||||
oppositeCharacter: "",
|
oppositeCharacter: "",
|
||||||
oppCharacter: "",
|
oppCharacter: "",
|
||||||
companyNature: "",
|
|
||||||
organizationNature: "",
|
|
||||||
enterpriseNatureLevel2: "",
|
|
||||||
contactName: "",
|
contactName: "",
|
||||||
contactPhone: "",
|
contactPhone: "",
|
||||||
contactEmail: "",
|
contactEmail: "",
|
||||||
@@ -1398,7 +1275,6 @@ function createEmptyParty(roleCode, index = 0) {
|
|||||||
naturalPersonIdNumber: "",
|
naturalPersonIdNumber: "",
|
||||||
isGroupInternal: false,
|
isGroupInternal: false,
|
||||||
isHongKongMacaoTaiwan: false,
|
isHongKongMacaoTaiwan: false,
|
||||||
invoiceTitleOptions: [],
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1417,9 +1293,6 @@ function mapLaunchPartyToFormParty(item = {}) {
|
|||||||
roleCode,
|
roleCode,
|
||||||
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
|
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
|
||||||
subjectCode: item.subjectCode || "",
|
subjectCode: item.subjectCode || "",
|
||||||
companyNature: getCompanyNatureByOppositeCharacter(
|
|
||||||
item.oppositeCharacter || item.oppCharacter,
|
|
||||||
),
|
|
||||||
oppCharacter: item.oppositeCharacter || item.oppCharacter || "",
|
oppCharacter: item.oppositeCharacter || item.oppCharacter || "",
|
||||||
oppositeCharacter: item.oppositeCharacter || item.oppCharacter || "",
|
oppositeCharacter: item.oppositeCharacter || item.oppCharacter || "",
|
||||||
displayName: "",
|
displayName: "",
|
||||||
@@ -1445,16 +1318,6 @@ function buildPartyStateFromList(list = []) {
|
|||||||
return normalizePartyState(result);
|
return normalizePartyState(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCompanyNatureByOppositeCharacter(value) {
|
|
||||||
const map = {
|
|
||||||
1: "境内组织",
|
|
||||||
2: "境内个人",
|
|
||||||
3: "境外组织",
|
|
||||||
4: "境外个人",
|
|
||||||
};
|
|
||||||
return map[String(value || "")] || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPartyFilled(party = {}) {
|
function isPartyFilled(party = {}) {
|
||||||
const ignoreKeys = new Set([
|
const ignoreKeys = new Set([
|
||||||
"localId",
|
"localId",
|
||||||
@@ -1834,11 +1697,6 @@ const ourPartySummaryText = computed(() =>
|
|||||||
: "未填写",
|
: "未填写",
|
||||||
);
|
);
|
||||||
|
|
||||||
const allPartyDetails = computed(() => [
|
|
||||||
...ourParties.value,
|
|
||||||
...counterpartyParties.value,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const signingSubjectCodeText = computed(() =>
|
const signingSubjectCodeText = computed(() =>
|
||||||
ourParties.value
|
ourParties.value
|
||||||
.map((party) => String(party.subjectCode || "").trim())
|
.map((party) => String(party.subjectCode || "").trim())
|
||||||
@@ -1870,6 +1728,23 @@ const requiresAuthAttachment = computed(() =>
|
|||||||
["GZBSQRQZ", "HTZYZBSQRQZ"].includes(detailState.value.sealType),
|
["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() {
|
function syncUploadLists() {
|
||||||
otherAttachmentList.value = (detailState.value.otherAttachmentList || []).map(
|
otherAttachmentList.value = (detailState.value.otherAttachmentList || []).map(
|
||||||
(item, index) => ({
|
(item, index) => ({
|
||||||
@@ -1943,15 +1818,6 @@ function showSearchTip(title) {
|
|||||||
message.info(`${title}数据已从客户/主体库加载,可直接在下拉框搜索选择。`);
|
message.info(`${title}数据已从客户/主体库加载,可直接在下拉框搜索选择。`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showInvoiceTitles(party, roleName) {
|
|
||||||
const titles = party.invoiceTitleOptions || [];
|
|
||||||
message.info(
|
|
||||||
titles.length
|
|
||||||
? `${roleName}备选开票抬头:${titles.join(";")}`
|
|
||||||
: `${roleName}暂无备选开票抬头`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterPartnerOption(input, option) {
|
function filterPartnerOption(input, option) {
|
||||||
const keyword = String(input || "")
|
const keyword = String(input || "")
|
||||||
.trim()
|
.trim()
|
||||||
@@ -1978,27 +1844,6 @@ function getRelativeTypeLabel(value) {
|
|||||||
return map[value] || 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) {
|
function mapPartnerToParty(raw = {}, roleKey, companyName) {
|
||||||
const firstContact = raw.contacts?.[0] || {};
|
const firstContact = raw.contacts?.[0] || {};
|
||||||
const roleCode =
|
const roleCode =
|
||||||
@@ -2013,17 +1858,9 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
|
|||||||
companyType: getRelativeTypeLabel(raw.relativeType),
|
companyType: getRelativeTypeLabel(raw.relativeType),
|
||||||
oppositeCharacter: raw.oppositeCharacter || "",
|
oppositeCharacter: raw.oppositeCharacter || "",
|
||||||
oppCharacter: raw.oppositeCharacter || "",
|
oppCharacter: raw.oppositeCharacter || "",
|
||||||
companyNature: getCompanyNatureByOppositeCharacter(raw.oppositeCharacter),
|
|
||||||
organizationNature: getOrganizationNatureLabel(raw.natureOfEnterpriseOrg),
|
|
||||||
enterpriseNatureLevel2: getEnterpriseNatureLevel2Label(
|
|
||||||
raw.natureOfEnterpriseOrgLev,
|
|
||||||
),
|
|
||||||
creditCode: raw.customerTaxno || "",
|
creditCode: raw.customerTaxno || "",
|
||||||
tinNo: raw.tinCode || "",
|
|
||||||
countryCode: raw.country || "",
|
|
||||||
legalRepresentative: raw.legalPersonName || "",
|
legalRepresentative: raw.legalPersonName || "",
|
||||||
registeredAddress: raw.customerRegaddr || "",
|
registeredAddress: raw.customerRegaddr || "",
|
||||||
registeredCapital: raw.regCapital || raw.registeredCapital || "",
|
|
||||||
contactName: firstContact.contactName || "",
|
contactName: firstContact.contactName || "",
|
||||||
contactPhone: firstContact.contactPhone || raw.officephone || "",
|
contactPhone: firstContact.contactPhone || raw.officephone || "",
|
||||||
contactEmail: firstContact.email || raw.emailAddress || "",
|
contactEmail: firstContact.email || raw.emailAddress || "",
|
||||||
@@ -2034,7 +1871,6 @@ function mapPartnerToParty(raw = {}, roleKey, companyName) {
|
|||||||
naturalPersonIdNumber: raw.certificateNum || "",
|
naturalPersonIdNumber: raw.certificateNum || "",
|
||||||
isGroupInternal: raw.groupFlag === "Y" || raw.isJtn === "1",
|
isGroupInternal: raw.groupFlag === "Y" || raw.isJtn === "1",
|
||||||
isHongKongMacaoTaiwan: raw.gatFlag === "Y" || raw.isSgat === "1",
|
isHongKongMacaoTaiwan: raw.gatFlag === "Y" || raw.isSgat === "1",
|
||||||
invoiceTitleOptions: raw.customerNameC ? [raw.customerNameC] : [],
|
|
||||||
roleCode,
|
roleCode,
|
||||||
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
|
roleName: roleCode === PARTY_ROLE_OUR ? "我方" : "相对方",
|
||||||
};
|
};
|
||||||
@@ -2109,13 +1945,12 @@ function handleCompanySelect(party, companyName, option = {}) {
|
|||||||
legalRepresentative:
|
legalRepresentative:
|
||||||
party.legalRepresentative || profile.legalRepresentative,
|
party.legalRepresentative || profile.legalRepresentative,
|
||||||
creditCode: party.creditCode || profile.creditCode,
|
creditCode: party.creditCode || profile.creditCode,
|
||||||
oppCharacter:
|
oppCharacter: party.oppCharacter || "1",
|
||||||
party.oppCharacter ||
|
|
||||||
(String(party.companyNature || "").includes("个人") ? "2" : "1"),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddOurParty() {
|
function handleAddOurParty() {
|
||||||
|
if (isSingleAgreementChecked.value) return;
|
||||||
detailState.value.partyState.ourPartyList =
|
detailState.value.partyState.ourPartyList =
|
||||||
detailState.value.partyState.ourPartyList || [];
|
detailState.value.partyState.ourPartyList || [];
|
||||||
detailState.value.partyState.ourPartyList.push(
|
detailState.value.partyState.ourPartyList.push(
|
||||||
@@ -2136,6 +1971,7 @@ function handleContractTypeCodeChange(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleAddCounterparty() {
|
function handleAddCounterparty() {
|
||||||
|
if (isSingleAgreementChecked.value) return;
|
||||||
detailState.value.partyState.counterpartyList =
|
detailState.value.partyState.counterpartyList =
|
||||||
detailState.value.partyState.counterpartyList || [];
|
detailState.value.partyState.counterpartyList || [];
|
||||||
detailState.value.partyState.counterpartyList.push(
|
detailState.value.partyState.counterpartyList.push(
|
||||||
@@ -2148,6 +1984,7 @@ function handleAddCounterparty() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRemoveOurParty(localId) {
|
function handleRemoveOurParty(localId) {
|
||||||
|
if (isSingleAgreementChecked.value) return;
|
||||||
detailState.value.partyState.ourPartyList = (
|
detailState.value.partyState.ourPartyList = (
|
||||||
detailState.value.partyState.ourPartyList || []
|
detailState.value.partyState.ourPartyList || []
|
||||||
).filter((item) => item.localId !== localId);
|
).filter((item) => item.localId !== localId);
|
||||||
@@ -2160,6 +1997,7 @@ function handleRemoveOurParty(localId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleRemoveCounterparty(localId) {
|
function handleRemoveCounterparty(localId) {
|
||||||
|
if (isSingleAgreementChecked.value) return;
|
||||||
detailState.value.partyState.counterpartyList = (
|
detailState.value.partyState.counterpartyList = (
|
||||||
detailState.value.partyState.counterpartyList || []
|
detailState.value.partyState.counterpartyList || []
|
||||||
).filter((item) => item.localId !== localId);
|
).filter((item) => item.localId !== localId);
|
||||||
@@ -2247,7 +2085,7 @@ async function downloadFile(filePath, fileName = "附件") {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const resp = await downloadLaunchFile(filePath);
|
const resp = await downloadLaunchFile(filePath);
|
||||||
const arrayBuffer = resp.data;
|
const arrayBuffer = resp?.data ?? resp;
|
||||||
const blob = new Blob([arrayBuffer]);
|
const blob = new Blob([arrayBuffer]);
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
@@ -2336,6 +2174,16 @@ function validateState() {
|
|||||||
) {
|
) {
|
||||||
return "当前登录主体必须包含在我方主体中";
|
return "当前登录主体必须包含在我方主体中";
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
isSingleAgreementChecked.value &&
|
||||||
|
currentSelfSubjectCode.value &&
|
||||||
|
ourParties.value.some(
|
||||||
|
(party) =>
|
||||||
|
String(party.subjectCode || "").trim() !== currentSelfSubjectCode.value,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return "单方协议仅允许使用当前登录主体";
|
||||||
|
}
|
||||||
if (!isSingleAgreementChecked.value && !counterpartyParties.value.length)
|
if (!isSingleAgreementChecked.value && !counterpartyParties.value.length)
|
||||||
return "请至少添加一个相对方";
|
return "请至少添加一个相对方";
|
||||||
if (
|
if (
|
||||||
@@ -2405,6 +2253,7 @@ function validateState() {
|
|||||||
if (!detailState.value.contractBodyFileName?.trim())
|
if (!detailState.value.contractBodyFileName?.trim())
|
||||||
return "请先配置合同正文";
|
return "请先配置合同正文";
|
||||||
if (
|
if (
|
||||||
|
!isSingleAgreementChecked.value &&
|
||||||
requiresAuthAttachment.value &&
|
requiresAuthAttachment.value &&
|
||||||
!(detailState.value.authAttachmentList || []).length
|
!(detailState.value.authAttachmentList || []).length
|
||||||
)
|
)
|
||||||
@@ -2473,9 +2322,7 @@ function buildLaunchRecord() {
|
|||||||
oppositeId: party.oppositeId,
|
oppositeId: party.oppositeId,
|
||||||
companyName: party.companyName,
|
companyName: party.companyName,
|
||||||
companyType: party.companyType,
|
companyType: party.companyType,
|
||||||
oppositeCharacter:
|
oppositeCharacter: party.oppCharacter || "1",
|
||||||
party.oppCharacter ||
|
|
||||||
(String(party.companyNature || "").includes("个人") ? "2" : "1"),
|
|
||||||
contactName: party.contactName,
|
contactName: party.contactName,
|
||||||
contactPhone: party.contactPhone,
|
contactPhone: party.contactPhone,
|
||||||
contactEmail: party.contactEmail,
|
contactEmail: party.contactEmail,
|
||||||
@@ -2501,9 +2348,7 @@ function buildLaunchRecord() {
|
|||||||
oppositeId: party.oppositeId,
|
oppositeId: party.oppositeId,
|
||||||
companyName: party.companyName,
|
companyName: party.companyName,
|
||||||
companyType: party.companyType,
|
companyType: party.companyType,
|
||||||
oppositeCharacter:
|
oppositeCharacter: party.oppCharacter || "1",
|
||||||
party.oppCharacter ||
|
|
||||||
(String(party.companyNature || "").includes("个人") ? "2" : "1"),
|
|
||||||
contactName: party.contactName,
|
contactName: party.contactName,
|
||||||
contactPhone: party.contactPhone,
|
contactPhone: party.contactPhone,
|
||||||
contactEmail: party.contactEmail,
|
contactEmail: party.contactEmail,
|
||||||
@@ -2675,7 +2520,6 @@ function applySelfProfile(profile = {}) {
|
|||||||
bankAccount: profile.bankAccount || "",
|
bankAccount: profile.bankAccount || "",
|
||||||
legalRepresentative: profile.legalRepresentative || "",
|
legalRepresentative: profile.legalRepresentative || "",
|
||||||
creditCode: profile.creditCode || "",
|
creditCode: profile.creditCode || "",
|
||||||
invoiceTitleOptions: profile.invoiceTitleOptions || [],
|
|
||||||
};
|
};
|
||||||
const shouldHydrateFirstParty =
|
const shouldHydrateFirstParty =
|
||||||
!firstOurParty.companyName ||
|
!firstOurParty.companyName ||
|
||||||
@@ -2699,12 +2543,11 @@ function applySelfProfile(profile = {}) {
|
|||||||
legalRepresentative:
|
legalRepresentative:
|
||||||
profile.legalRepresentative || firstOurParty.legalRepresentative,
|
profile.legalRepresentative || firstOurParty.legalRepresentative,
|
||||||
creditCode: profile.creditCode || firstOurParty.creditCode,
|
creditCode: profile.creditCode || firstOurParty.creditCode,
|
||||||
invoiceTitleOptions:
|
|
||||||
profile.invoiceTitleOptions || firstOurParty.invoiceTitleOptions || [],
|
|
||||||
},
|
},
|
||||||
...(detailState.value.partyState.ourPartyList || []).slice(1),
|
...(detailState.value.partyState.ourPartyList || []).slice(1),
|
||||||
];
|
];
|
||||||
refreshPartyDisplayMeta();
|
refreshPartyDisplayMeta();
|
||||||
|
forceSingleAgreementDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showModal(context = {}, mode = "create") {
|
async function showModal(context = {}, mode = "create") {
|
||||||
@@ -2724,6 +2567,7 @@ async function showModal(context = {}, mode = "create") {
|
|||||||
detailState.value = copyContractFormData(source);
|
detailState.value = copyContractFormData(source);
|
||||||
const selfProfile = await getLaunchSelfProfile();
|
const selfProfile = await getLaunchSelfProfile();
|
||||||
applySelfProfile(selfProfile || {});
|
applySelfProfile(selfProfile || {});
|
||||||
|
forceSingleAgreementDefaults();
|
||||||
syncCounterpartyState();
|
syncCounterpartyState();
|
||||||
syncUploadLists();
|
syncUploadLists();
|
||||||
loadPartnerOptions();
|
loadPartnerOptions();
|
||||||
|
|||||||
@@ -1170,7 +1170,7 @@ async function fetchTemplateBuffer(templateFilePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resp = await downloadTemplateFile(templateFilePath);
|
const resp = await downloadTemplateFile(templateFilePath);
|
||||||
const arrayBuffer = resp.data;
|
const arrayBuffer = resp?.data ?? resp;
|
||||||
const buffer =
|
const buffer =
|
||||||
arrayBuffer instanceof ArrayBuffer ? arrayBuffer : arrayBuffer?.buffer;
|
arrayBuffer instanceof ArrayBuffer ? arrayBuffer : arrayBuffer?.buffer;
|
||||||
templateBufferCache.set(templateFilePath, buffer);
|
templateBufferCache.set(templateFilePath, buffer);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:open="visible"
|
v-model:open="visible"
|
||||||
title="上传已签署版本"
|
:title="isSingleAgreement ? '上传盖章版' : '上传已签署版本'"
|
||||||
width="560px"
|
width="560px"
|
||||||
:mask-closable="false"
|
:mask-closable="false"
|
||||||
:confirm-loading="submitting"
|
:confirm-loading="submitting"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
<a-divider style="margin: 16px 0" />
|
<a-divider style="margin: 16px 0" />
|
||||||
|
|
||||||
<a-form layout="vertical">
|
<a-form layout="vertical">
|
||||||
<a-form-item label="上传已签署合同文件" required>
|
<a-form-item :label="isSingleAgreement ? '上传已盖章文件' : '上传已签署合同文件'" required>
|
||||||
<div
|
<div
|
||||||
class="upload-dragger"
|
class="upload-dragger"
|
||||||
:class="{ 'is-dragover': dragOver }"
|
:class="{ 'is-dragover': dragOver }"
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
/>
|
/>
|
||||||
<template v-if="!uploadFile">
|
<template v-if="!uploadFile">
|
||||||
<cloud-upload-outlined :style="{ 'fontSize': '36px', 'color': '#b0b8c5' }" />
|
<cloud-upload-outlined :style="{ 'fontSize': '36px', 'color': '#b0b8c5' }" />
|
||||||
<p class="upload-text">点击或将已签署文件拖拽到这里</p>
|
<p class="upload-text">{{ isSingleAgreement ? "点击或将已盖章文件拖拽到这里" : "点击或将已签署文件拖拽到这里" }}</p>
|
||||||
<p class="upload-hint">支持 PDF、DOC、DOCX 文件,且小于 20M</p>
|
<p class="upload-hint">支持 PDF、DOC、DOCX 文件,且小于 20M</p>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -79,11 +79,11 @@
|
|||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="不在线签署的原因" required>
|
<a-form-item :label="isSingleAgreement ? '盖章说明' : '不在线签署的原因'" required>
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="offlineReason"
|
v-model:value="offlineReason"
|
||||||
:rows="4"
|
:rows="4"
|
||||||
placeholder="请填写不在线签署的原因,例如:客户无法配合在线签署、对方无数字证书等"
|
:placeholder="isSingleAgreement ? '请填写盖章说明,例如:内部审批通过后线下加盖业务章' : '请填写不在线签署的原因,例如:客户无法配合在线签署、对方无数字证书等'"
|
||||||
:maxlength="500"
|
:maxlength="500"
|
||||||
show-count
|
show-count
|
||||||
/>
|
/>
|
||||||
@@ -111,13 +111,15 @@ const activeDate = ref("");
|
|||||||
const dragOver = ref(false);
|
const dragOver = ref(false);
|
||||||
const submitting = ref(false);
|
const submitting = ref(false);
|
||||||
const fileInputRef = ref(null);
|
const fileInputRef = ref(null);
|
||||||
|
const isSingleAgreement = ref(false);
|
||||||
|
|
||||||
const emit = defineEmits(["done"]);
|
const emit = defineEmits(["done"]);
|
||||||
|
|
||||||
function showModal(record) {
|
function showModal(record) {
|
||||||
row.value = record;
|
row.value = record;
|
||||||
|
isSingleAgreement.value = String(record?.isSingleAgreement || "0") === "1";
|
||||||
uploadFile.value = null;
|
uploadFile.value = null;
|
||||||
offlineReason.value = "";
|
offlineReason.value = isSingleAgreement.value ? "内部审批通过后线下加盖业务章" : "";
|
||||||
signDate.value = sliceDateValue(record?.signDate) || todayString();
|
signDate.value = sliceDateValue(record?.signDate) || todayString();
|
||||||
sealDate.value = sliceDateValue(record?.sealDate) || signDate.value;
|
sealDate.value = sliceDateValue(record?.sealDate) || signDate.value;
|
||||||
activeDate.value = sliceDateValue(record?.activeDate) || sliceDateValue(record?.effectiveStart);
|
activeDate.value = sliceDateValue(record?.activeDate) || sliceDateValue(record?.effectiveStart);
|
||||||
@@ -201,12 +203,12 @@ function formatFileSize(bytes) {
|
|||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (!uploadFile.value) {
|
if (!uploadFile.value) {
|
||||||
message.warning("请先上传已签署文件");
|
message.warning(isSingleAgreement.value ? "请先上传已盖章文件" : "请先上传已签署文件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const reason = (offlineReason.value || "").trim();
|
const reason = (offlineReason.value || "").trim();
|
||||||
if (!reason) {
|
if (!reason) {
|
||||||
message.warning("请填写不在线签署的原因");
|
message.warning(isSingleAgreement.value ? "请填写盖章说明" : "请填写不在线签署的原因");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!signDate.value) {
|
if (!signDate.value) {
|
||||||
@@ -242,7 +244,7 @@ async function handleSubmit() {
|
|||||||
const fileSize = uploadFile.value.size;
|
const fileSize = uploadFile.value.size;
|
||||||
|
|
||||||
const finishRes = await finishLaunchSeal(row.value.id, {
|
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,
|
sealContractStatus: 2000,
|
||||||
signedFileName: fileName,
|
signedFileName: fileName,
|
||||||
signedFilePath: filePath,
|
signedFilePath: filePath,
|
||||||
@@ -260,7 +262,7 @@ async function handleSubmit() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.success("已签署版本上传成功,合同已流转到待采集");
|
message.success(isSingleAgreement.value ? "盖章版上传成功,单方协议已办结" : "已签署版本上传成功,合同已流转到待采集");
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
emit("done");
|
emit("done");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ export const currencyOptions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const sealTypeOptions = [
|
export const sealTypeOptions = [
|
||||||
|
{ label: "内部业务章", value: "YWZ" },
|
||||||
{ label: "公章", value: "GZ" },
|
{ label: "公章", value: "GZ" },
|
||||||
{ label: "合同专用章", value: "HTZYZ" },
|
{ label: "合同专用章", value: "HTZYZ" },
|
||||||
{ label: "公章+法定代表人私章", value: "GZFDDBRSZ" },
|
{ label: "公章+法定代表人私章", value: "GZFDDBRSZ" },
|
||||||
|
|||||||
+410
-131
@@ -10,17 +10,29 @@
|
|||||||
<a-row :gutter="16" style="width: 100%">
|
<a-row :gutter="16" style="width: 100%">
|
||||||
<a-col :md="6" :sm="24">
|
<a-col :md="6" :sm="24">
|
||||||
<a-form-item label="合同名称">
|
<a-form-item label="合同名称">
|
||||||
<a-input v-model:value="queryParam.contractName" allow-clear placeholder="请输入合同名称" />
|
<a-input
|
||||||
|
v-model:value="queryParam.contractName"
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入合同名称"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :sm="24">
|
<a-col :md="6" :sm="24">
|
||||||
<a-form-item label="合同编码">
|
<a-form-item label="合同编码">
|
||||||
<a-input v-model:value="queryParam.contractCode" allow-clear placeholder="请输入合同编码" />
|
<a-input
|
||||||
|
v-model:value="queryParam.contractCode"
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入合同编码"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :sm="24">
|
<a-col :md="6" :sm="24">
|
||||||
<a-form-item label="合同类型">
|
<a-form-item label="合同类型">
|
||||||
<a-input v-model:value="queryParam.contractType" allow-clear placeholder="请输入合同类型编码" />
|
<a-input
|
||||||
|
v-model:value="queryParam.contractType"
|
||||||
|
allow-clear
|
||||||
|
placeholder="请输入合同类型编码"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :md="6" :sm="24">
|
<a-col :md="6" :sm="24">
|
||||||
@@ -55,10 +67,36 @@
|
|||||||
<vxe-toolbar ref="toolbarRef" custom>
|
<vxe-toolbar ref="toolbarRef" custom>
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<a-space wrap>
|
<a-space wrap>
|
||||||
<a-button type="primary" :icon="h(SearchOutlined)" @click="handleQuery">查询</a-button>
|
<a-button
|
||||||
<a-button :icon="h(RedoOutlined)" @click="handleReset">重置</a-button>
|
type="primary"
|
||||||
<a-button type="primary" ghost :icon="h(PlusOutlined)" @click="handleCreate">发起合同</a-button>
|
:icon="h(SearchOutlined)"
|
||||||
<a-button danger :icon="h(DeleteOutlined)" :disabled="!selectedRowKeys.length" @click="handleBatchDelete">删除</a-button>
|
@click="handleQuery"
|
||||||
|
>查询</a-button
|
||||||
|
>
|
||||||
|
<a-button :icon="h(RedoOutlined)" @click="handleReset"
|
||||||
|
>重置</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
:icon="h(PlusOutlined)"
|
||||||
|
@click="handleCreate"
|
||||||
|
>发起合同</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
ghost
|
||||||
|
:icon="h(PlusOutlined)"
|
||||||
|
@click="handleCreateSingleAgreement"
|
||||||
|
>发起单方协议</a-button
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
danger
|
||||||
|
:icon="h(DeleteOutlined)"
|
||||||
|
:disabled="!selectedRowKeys.length"
|
||||||
|
@click="handleBatchDelete"
|
||||||
|
>删除</a-button
|
||||||
|
>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
</vxe-toolbar>
|
</vxe-toolbar>
|
||||||
@@ -74,33 +112,97 @@
|
|||||||
:checkbox-config="{ range: true }"
|
:checkbox-config="{ range: true }"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:loading-config="{ icon: 'vxe-icon-indicator roll', text: '正在拼命加载中...' }"
|
:loading-config="{
|
||||||
|
icon: 'vxe-icon-indicator roll',
|
||||||
|
text: '正在拼命加载中...',
|
||||||
|
}"
|
||||||
@checkbox-range-change="selectChangeEvent"
|
@checkbox-range-change="selectChangeEvent"
|
||||||
@checkbox-change="selectChangeEvent"
|
@checkbox-change="selectChangeEvent"
|
||||||
@checkbox-all="selectChangeEvent"
|
@checkbox-all="selectChangeEvent"
|
||||||
>
|
>
|
||||||
<vxe-column type="checkbox" width="56" />
|
<vxe-column type="checkbox" width="56" />
|
||||||
<vxe-column type="seq" title="序号" width="68" />
|
<vxe-column type="seq" title="序号" width="68" />
|
||||||
<vxe-column field="contractCode" title="合同编码" width="160" show-overflow="title" />
|
<vxe-column
|
||||||
<vxe-column field="lawContractCode" title="法务合同编号" width="160" show-overflow="title" />
|
field="contractCode"
|
||||||
<vxe-column field="contractName" title="合同名称" width="220" show-overflow="title" />
|
title="合同编码"
|
||||||
<vxe-column field="contractType" title="合同类型" width="160" show-overflow="title">
|
width="160"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="lawContractCode"
|
||||||
|
title="法务合同编号"
|
||||||
|
width="160"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="contractName"
|
||||||
|
title="合同名称"
|
||||||
|
width="220"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="contractType"
|
||||||
|
title="合同类型"
|
||||||
|
width="160"
|
||||||
|
show-overflow="title"
|
||||||
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ getContractTypeSimpleLabel(row.contractTypeCode || row.contractType) }}
|
{{
|
||||||
|
getContractTypeSimpleLabel(
|
||||||
|
row.contractTypeCode || row.contractType,
|
||||||
|
)
|
||||||
|
}}
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
<vxe-column field="templateName" title="所选模板" width="180" show-overflow="title" />
|
<vxe-column
|
||||||
<vxe-column field="counterpartySummary" title="合同相对方" width="260" show-overflow="title" />
|
field="templateName"
|
||||||
|
title="所选模板"
|
||||||
|
width="180"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="counterpartySummary"
|
||||||
|
title="合同相对方"
|
||||||
|
width="260"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
<vxe-column field="status" title="状态" width="120">
|
<vxe-column field="status" title="状态" width="120">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<a-tag :color="getStatusColor(row.status)">{{ getStatusLabel(row.status) }}</a-tag>
|
<a-tag :color="getStatusColor(row.status)">{{
|
||||||
|
getStatusLabelByRow(row)
|
||||||
|
}}</a-tag>
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
<vxe-column field="approveMessage" title="审批说明" width="220" show-overflow="title" />
|
<vxe-column
|
||||||
<vxe-column field="initiator" title="发起人" width="100" show-overflow="title" />
|
field="approveMessage"
|
||||||
<vxe-column field="initiatorDept" title="所属部门" width="140" show-overflow="title" />
|
title="审批说明"
|
||||||
<vxe-column field="createTime" title="发起时间" width="170" show-overflow="title" />
|
width="220"
|
||||||
<vxe-column field="updateTime" title="最后更新时间" width="170" show-overflow="title" />
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="initiator"
|
||||||
|
title="发起人"
|
||||||
|
width="100"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="initiatorDept"
|
||||||
|
title="所属部门"
|
||||||
|
width="140"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="createTime"
|
||||||
|
title="发起时间"
|
||||||
|
width="170"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
|
<vxe-column
|
||||||
|
field="updateTime"
|
||||||
|
title="最后更新时间"
|
||||||
|
width="170"
|
||||||
|
show-overflow="title"
|
||||||
|
/>
|
||||||
<vxe-column title="操作" width="720" fixed="right">
|
<vxe-column title="操作" width="720" fixed="right">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="table-actions">
|
<div class="table-actions">
|
||||||
@@ -108,17 +210,47 @@
|
|||||||
<a @click="handleCopy(row)">复制</a>
|
<a @click="handleCopy(row)">复制</a>
|
||||||
<a v-if="canChange(row)" @click="handleChange(row)">变更</a>
|
<a v-if="canChange(row)" @click="handleChange(row)">变更</a>
|
||||||
<a v-if="canEdit(row)" @click="handleEdit(row)">编辑</a>
|
<a v-if="canEdit(row)" @click="handleEdit(row)">编辑</a>
|
||||||
<a v-if="canSubmit(row)" @click="handleSubmit(row)">{{ isSingleAgreementRecord(row) ? "提交审批" : "提交法务" }}</a>
|
<a v-if="canSubmit(row)" @click="handleSubmit(row)">{{
|
||||||
<a v-if="canViewApprove(row)" @click="handleViewApprove(row)">审批记录</a>
|
isSingleAgreementRecord(row) ? "提交审批" : "提交法务"
|
||||||
<a v-if="canViewLawCallback(row)" @click="handleViewLawCallback(row)">回调data</a>
|
}}</a>
|
||||||
<a v-if="canMockApprove(row)" @click="handleMockApprove(row)">{{ isSingleAgreementRecord(row) ? "审批通过" : "测试通过" }}</a>
|
<a v-if="canViewApprove(row)" @click="handleViewApprove(row)"
|
||||||
<a v-if="canMockReject(row)" @click="handleMockReject(row)">{{ isSingleAgreementRecord(row) ? "审批驳回" : "测试驳回" }}</a>
|
>审批记录</a
|
||||||
<a v-if="canOnlineSign(row)" @click="handleOnlineSign(row)">在线签订</a>
|
>
|
||||||
<a v-if="canDownloadSigned(row)" @click="handleDownloadSigned(row)">下载签署文件</a>
|
<a
|
||||||
<a v-if="canUploadSigned(row)" @click="handleUploadSigned(row)">上传已签署版本</a>
|
v-if="canViewLawCallback(row)"
|
||||||
<a v-if="canMockFinishSign(row)" @click="handleMockFinishSign(row)">测试签署完成</a>
|
@click="handleViewLawCallback(row)"
|
||||||
<a v-if="canCollect(row)" @click="handleMockCollect(row)">测试采集</a>
|
>回调data</a
|
||||||
<a v-if="canArchive(row)" @click="handleArchive(row)">归档</a>
|
>
|
||||||
|
<a v-if="canMockApprove(row)" @click="handleMockApprove(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "审批通过" : "测试通过"
|
||||||
|
}}</a>
|
||||||
|
<a v-if="canMockReject(row)" @click="handleMockReject(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "审批驳回" : "测试驳回"
|
||||||
|
}}</a>
|
||||||
|
<a v-if="canOnlineSign(row)" @click="handleOnlineSign(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "发起盖章" : "在线签订"
|
||||||
|
}}</a>
|
||||||
|
<a
|
||||||
|
v-if="canDownloadSigned(row)"
|
||||||
|
@click="handleDownloadSigned(row)"
|
||||||
|
>下载签署文件</a
|
||||||
|
>
|
||||||
|
<a v-if="canUploadSigned(row)" @click="handleUploadSigned(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "上传盖章版" : "上传已签署版本"
|
||||||
|
}}</a>
|
||||||
|
<a
|
||||||
|
v-if="canMockFinishSign(row)"
|
||||||
|
@click="handleMockFinishSign(row)"
|
||||||
|
>{{
|
||||||
|
isSingleAgreementRecord(row) ? "测试盖章完成" : "测试签署完成"
|
||||||
|
}}</a
|
||||||
|
>
|
||||||
|
<a v-if="canCollect(row)" @click="handleMockCollect(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "测试生效" : "测试采集"
|
||||||
|
}}</a>
|
||||||
|
<a v-if="canArchive(row)" @click="handleArchive(row)">{{
|
||||||
|
isSingleAgreementRecord(row) ? "办结" : "归档"
|
||||||
|
}}</a>
|
||||||
<a v-if="canTerminate(row)" @click="handleTerminate(row)">终止</a>
|
<a v-if="canTerminate(row)" @click="handleTerminate(row)">终止</a>
|
||||||
<a v-if="canDelete(row)" @click="handleDelete(row)">删除</a>
|
<a v-if="canDelete(row)" @click="handleDelete(row)">删除</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,10 +273,22 @@
|
|||||||
/>
|
/>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<ContractPartyPlaceholderModal ref="contractModalRef" @save="handleModalSave" />
|
<ContractPartyPlaceholderModal
|
||||||
<MixedSignModal ref="mixedSignModalRef" @business-updated="handleSignBusinessUpdated" />
|
ref="contractModalRef"
|
||||||
<UploadSignedModal ref="uploadSignedModalRef" @done="handleSignBusinessUpdated" />
|
@save="handleModalSave"
|
||||||
<ContractArchiveModal ref="contractArchiveModalRef" @done="handleArchiveDone" />
|
/>
|
||||||
|
<MixedSignModal
|
||||||
|
ref="mixedSignModalRef"
|
||||||
|
@business-updated="handleSignBusinessUpdated"
|
||||||
|
/>
|
||||||
|
<UploadSignedModal
|
||||||
|
ref="uploadSignedModalRef"
|
||||||
|
@done="handleSignBusinessUpdated"
|
||||||
|
/>
|
||||||
|
<ContractArchiveModal
|
||||||
|
ref="contractArchiveModalRef"
|
||||||
|
@done="handleArchiveDone"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -302,6 +446,13 @@ function getStatusColor(status) {
|
|||||||
return statusColorMap[status] || "default";
|
return statusColorMap[status] || "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStatusLabelByRow(row) {
|
||||||
|
if (isSingleAgreementRecord(row) && row?.status === "pending_sign") {
|
||||||
|
return "待盖章";
|
||||||
|
}
|
||||||
|
return getStatusLabel(row?.status);
|
||||||
|
}
|
||||||
|
|
||||||
function canEdit(row) {
|
function canEdit(row) {
|
||||||
return ["draft", "rejected"].includes(row.status);
|
return ["draft", "rejected"].includes(row.status);
|
||||||
}
|
}
|
||||||
@@ -316,7 +467,9 @@ function canSubmit(row) {
|
|||||||
|
|
||||||
function canChange(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) {
|
function canMockApprove(row) {
|
||||||
@@ -329,11 +482,21 @@ function canMockReject(row) {
|
|||||||
|
|
||||||
function canOnlineSign(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) {
|
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) {
|
function canUploadSigned(row) {
|
||||||
@@ -341,11 +504,11 @@ function canUploadSigned(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canCollect(row) {
|
function canCollect(row) {
|
||||||
return row.status === "pending_collect";
|
return !isSingleAgreementRecord(row) && row.status === "pending_collect";
|
||||||
}
|
}
|
||||||
|
|
||||||
function canArchive(row) {
|
function canArchive(row) {
|
||||||
return row.status === "pending_archive";
|
return !isSingleAgreementRecord(row) && row.status === "pending_archive";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSingleAgreementRecord(row) {
|
function isSingleAgreementRecord(row) {
|
||||||
@@ -353,14 +516,34 @@ function isSingleAgreementRecord(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function canViewApprove(row) {
|
function canViewApprove(row) {
|
||||||
return !isSingleAgreementRecord(row)
|
return (
|
||||||
&& Boolean(row.lawContractId)
|
!isSingleAgreementRecord(row) &&
|
||||||
&& ["reviewing", "rejected", "pending_sign", "signing", "pending_collect", "pending_archive", "completed"].includes(row.status);
|
Boolean(row.lawContractId) &&
|
||||||
|
[
|
||||||
|
"reviewing",
|
||||||
|
"rejected",
|
||||||
|
"pending_sign",
|
||||||
|
"signing",
|
||||||
|
"pending_collect",
|
||||||
|
"pending_archive",
|
||||||
|
"completed",
|
||||||
|
].includes(row.status)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canViewLawCallback(row) {
|
function canViewLawCallback(row) {
|
||||||
return !isSingleAgreementRecord(row)
|
return (
|
||||||
&& ["reviewing", "rejected", "pending_sign", "signing", "pending_collect", "pending_archive", "completed"].includes(row.status);
|
!isSingleAgreementRecord(row) &&
|
||||||
|
[
|
||||||
|
"reviewing",
|
||||||
|
"rejected",
|
||||||
|
"pending_sign",
|
||||||
|
"signing",
|
||||||
|
"pending_collect",
|
||||||
|
"pending_archive",
|
||||||
|
"completed",
|
||||||
|
].includes(row.status)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function canDownloadSigned(row) {
|
function canDownloadSigned(row) {
|
||||||
@@ -441,6 +624,10 @@ function handleCreate() {
|
|||||||
contractModalRef.value?.showModal({}, "create");
|
contractModalRef.value?.showModal({}, "create");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCreateSingleAgreement() {
|
||||||
|
contractModalRef.value?.showModal({ isSingleAgreement: "1" }, "create");
|
||||||
|
}
|
||||||
|
|
||||||
function handleView(row) {
|
function handleView(row) {
|
||||||
getLaunchDetail(row.id).then((res) => {
|
getLaunchDetail(row.id).then((res) => {
|
||||||
if (!isSuccessResponse(res) || !getDataResult(res)) {
|
if (!isSuccessResponse(res) || !getDataResult(res)) {
|
||||||
@@ -511,20 +698,34 @@ function handleSubmit(row) {
|
|||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: singleAgreement ? "确认提交内部审批" : "确认提交法务审批",
|
title: singleAgreement ? "确认提交内部审批" : "确认提交法务审批",
|
||||||
content: h("div", [
|
content: h("div", [
|
||||||
h("p", singleAgreement
|
h(
|
||||||
? `确定将单方协议【${row.contractName}】提交内部审批吗?`
|
"p",
|
||||||
: `确定将合同【${row.contractName}】提交法务系统审批吗?`),
|
singleAgreement
|
||||||
h("p", { style: { color: "#999", fontSize: "12px" } }, "提交后合同进入「审批中」状态,审批完成前不可编辑。"),
|
? `确定将单方协议【${row.contractName}】提交内部审批吗?`
|
||||||
|
: `确定将合同【${row.contractName}】提交法务系统审批吗?`,
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
"p",
|
||||||
|
{ style: { color: "#999", fontSize: "12px" } },
|
||||||
|
"提交后合同进入「审批中」状态,审批完成前不可编辑。",
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
okText: "确认提交",
|
okText: "确认提交",
|
||||||
cancelText: "取消",
|
cancelText: "取消",
|
||||||
onOk: () =>
|
onOk: () =>
|
||||||
submitLaunchRecord(row.id).then((res) => {
|
submitLaunchRecord(row.id).then((res) => {
|
||||||
if (!isSuccessResponse(res)) {
|
if (!isSuccessResponse(res)) {
|
||||||
message.error(getResponseMessage(res, singleAgreement ? "提交内部审批失败" : "提交法务失败"));
|
message.error(
|
||||||
|
getResponseMessage(
|
||||||
|
res,
|
||||||
|
singleAgreement ? "提交内部审批失败" : "提交法务失败",
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.success(singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批");
|
message.success(
|
||||||
|
singleAgreement ? "已提交内部审批,等待审批" : "已提交法务,等待审批",
|
||||||
|
);
|
||||||
getList();
|
getList();
|
||||||
}),
|
}),
|
||||||
icon: null,
|
icon: null,
|
||||||
@@ -555,48 +756,84 @@ function handleViewApprove(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildLawCallbackModalContent(sample) {
|
function buildLawCallbackModalContent(sample) {
|
||||||
const approvedJson = JSON.stringify({ data: sample?.approvedData || {} }, null, 2);
|
const approvedJson = JSON.stringify(
|
||||||
const rejectedJson = JSON.stringify({ data: sample?.rejectedData || {} }, null, 2);
|
{ data: sample?.approvedData || {} },
|
||||||
return h("div", { style: { display: "flex", flexDirection: "column", gap: "12px" } }, [
|
null,
|
||||||
h("div", [
|
2,
|
||||||
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"}`),
|
const rejectedJson = JSON.stringify(
|
||||||
]),
|
{ data: sample?.rejectedData || {} },
|
||||||
h("div", [
|
null,
|
||||||
h("div", { style: { marginBottom: "6px", fontWeight: 600 } }, "审批通过 data"),
|
2,
|
||||||
h("pre", {
|
);
|
||||||
style: {
|
return h(
|
||||||
margin: 0,
|
"div",
|
||||||
maxHeight: "260px",
|
{ style: { display: "flex", flexDirection: "column", gap: "12px" } },
|
||||||
overflow: "auto",
|
[
|
||||||
padding: "12px",
|
h("div", [
|
||||||
borderRadius: "8px",
|
h(
|
||||||
background: "#f6f8fa",
|
"div",
|
||||||
fontSize: "12px",
|
{ style: { marginBottom: "6px", fontWeight: 600 } },
|
||||||
lineHeight: "1.6",
|
"回调地址",
|
||||||
whiteSpace: "pre-wrap",
|
),
|
||||||
wordBreak: "break-word",
|
h(
|
||||||
},
|
"div",
|
||||||
}, approvedJson),
|
{ 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", {
|
h("div", [
|
||||||
style: {
|
h(
|
||||||
margin: 0,
|
"div",
|
||||||
maxHeight: "220px",
|
{ style: { marginBottom: "6px", fontWeight: 600 } },
|
||||||
overflow: "auto",
|
"审批通过 data",
|
||||||
padding: "12px",
|
),
|
||||||
borderRadius: "8px",
|
h(
|
||||||
background: "#f6f8fa",
|
"pre",
|
||||||
fontSize: "12px",
|
{
|
||||||
lineHeight: "1.6",
|
style: {
|
||||||
whiteSpace: "pre-wrap",
|
margin: 0,
|
||||||
wordBreak: "break-word",
|
maxHeight: "260px",
|
||||||
},
|
overflow: "auto",
|
||||||
}, rejectedJson),
|
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) {
|
function handleViewLawCallback(row) {
|
||||||
@@ -618,7 +855,9 @@ function handleViewLawCallback(row) {
|
|||||||
function handleMockApprove(row) {
|
function handleMockApprove(row) {
|
||||||
const singleAgreement = isSingleAgreementRecord(row);
|
const singleAgreement = isSingleAgreementRecord(row);
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: singleAgreement ? "测试操作:模拟内部审批通过" : "测试操作:模拟审批通过",
|
title: singleAgreement
|
||||||
|
? "测试操作:模拟内部审批通过"
|
||||||
|
: "测试操作:模拟审批通过",
|
||||||
content: singleAgreement
|
content: singleAgreement
|
||||||
? `模拟单方协议【${row.contractName}】内部审批通过,状态将变为「待签署」。`
|
? `模拟单方协议【${row.contractName}】内部审批通过,状态将变为「待签署」。`
|
||||||
: `模拟法务审批通过合同【${row.contractName}】,状态将变为「待签署」。`,
|
: `模拟法务审批通过合同【${row.contractName}】,状态将变为「待签署」。`,
|
||||||
@@ -640,12 +879,21 @@ function handleMockApprove(row) {
|
|||||||
function handleMockReject(row) {
|
function handleMockReject(row) {
|
||||||
const singleAgreement = isSingleAgreementRecord(row);
|
const singleAgreement = isSingleAgreementRecord(row);
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: singleAgreement ? "测试操作:模拟内部审批驳回" : "测试操作:模拟审批驳回",
|
title: singleAgreement
|
||||||
|
? "测试操作:模拟内部审批驳回"
|
||||||
|
: "测试操作:模拟审批驳回",
|
||||||
content: h("div", [
|
content: h("div", [
|
||||||
h("p", singleAgreement
|
h(
|
||||||
? `模拟单方协议【${row.contractName}】内部审批驳回,状态将回到「已驳回」。`
|
"p",
|
||||||
: `模拟法务审批驳回合同【${row.contractName}】,状态将回到「已驳回」。`),
|
singleAgreement
|
||||||
h("p", { style: { color: "#999", fontSize: "12px" } }, "驳回后可重新编辑再提交。"),
|
? `模拟单方协议【${row.contractName}】内部审批驳回,状态将回到「已驳回」。`
|
||||||
|
: `模拟法务审批驳回合同【${row.contractName}】,状态将回到「已驳回」。`,
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
"p",
|
||||||
|
{ style: { color: "#999", fontSize: "12px" } },
|
||||||
|
"驳回后可重新编辑再提交。",
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
okText: "确认驳回",
|
okText: "确认驳回",
|
||||||
cancelText: "取消",
|
cancelText: "取消",
|
||||||
@@ -663,15 +911,23 @@ function handleMockReject(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleMockFinishSign(row) {
|
function handleMockFinishSign(row) {
|
||||||
|
const singleAgreement = isSingleAgreementRecord(row);
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: "测试操作:模拟签署完成",
|
title: singleAgreement
|
||||||
content: `模拟合同【${row.contractName}】签署完成,状态将变为「待采集」。`,
|
? "测试操作:模拟盖章完成"
|
||||||
|
: "测试操作:模拟签署完成",
|
||||||
|
content: singleAgreement
|
||||||
|
? `模拟单方协议【${row.contractName}】内部业务章加盖完成,状态将变为「已完成」。`
|
||||||
|
: `模拟合同【${row.contractName}】签署完成,状态将变为「待采集」。`,
|
||||||
okText: "确认模拟",
|
okText: "确认模拟",
|
||||||
cancelText: "取消",
|
cancelText: "取消",
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
const signDate = sliceDateValue(row.signDate) || todayString();
|
const signDate = sliceDateValue(row.signDate) || todayString();
|
||||||
const sealDate = sliceDateValue(row.sealDate) || signDate;
|
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, {
|
return finishLaunchSeal(row.id, {
|
||||||
sealContractId: row.sealContractId || `TEST-SEAL-${row.id}`,
|
sealContractId: row.sealContractId || `TEST-SEAL-${row.id}`,
|
||||||
sealContractStatus: 2000,
|
sealContractStatus: 2000,
|
||||||
@@ -679,16 +935,27 @@ function handleMockFinishSign(row) {
|
|||||||
signedFilePath: row.contractTextFilePath || `mock-signed/${row.id}.pdf`,
|
signedFilePath: row.contractTextFilePath || `mock-signed/${row.id}.pdf`,
|
||||||
signedFileType: "pdf",
|
signedFileType: "pdf",
|
||||||
signedFileSize: row.contractTextFileSize || null,
|
signedFileSize: row.contractTextFileSize || null,
|
||||||
signedOfflineReason: "测试按钮模拟签署完成,真实签章接入后可删除此按钮",
|
signedOfflineReason: singleAgreement
|
||||||
|
? "测试按钮模拟内部业务章加盖完成"
|
||||||
|
: "测试按钮模拟签署完成,真实签章接入后可删除此按钮",
|
||||||
signDate: formatDateTimeValue(signDate),
|
signDate: formatDateTimeValue(signDate),
|
||||||
sealDate: formatDateTimeValue(sealDate),
|
sealDate: formatDateTimeValue(sealDate),
|
||||||
activeDate: formatDateTimeValue(activeDate),
|
activeDate: formatDateTimeValue(activeDate),
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (!isSuccessResponse(res)) {
|
if (!isSuccessResponse(res)) {
|
||||||
message.error(getResponseMessage(res, "测试签署完成失败"));
|
message.error(
|
||||||
|
getResponseMessage(
|
||||||
|
res,
|
||||||
|
singleAgreement ? "测试盖章完成失败" : "测试签署完成失败",
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
message.success("测试签署完成,合同已流转到待采集");
|
message.success(
|
||||||
|
singleAgreement
|
||||||
|
? "测试盖章完成,单方协议已办结"
|
||||||
|
: "测试签署完成,合同已流转到待采集",
|
||||||
|
);
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -698,24 +965,28 @@ function handleMockFinishSign(row) {
|
|||||||
|
|
||||||
function handleDownloadSigned(row) {
|
function handleDownloadSigned(row) {
|
||||||
const filePath = row.signedFilePath;
|
const filePath = row.signedFilePath;
|
||||||
const fileName = row.signedFileName || `${row.contractName || "合同"}-已签署版.pdf`;
|
const fileName =
|
||||||
|
row.signedFileName || `${row.contractName || "合同"}-已签署版.pdf`;
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
message.warning("暂无签署文件可下载");
|
message.warning("暂无签署文件可下载");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
downloadLaunchFile(filePath).then((res) => {
|
downloadLaunchFile(filePath)
|
||||||
const blob = new Blob([res.data]);
|
.then((res) => {
|
||||||
const url = window.URL.createObjectURL(blob);
|
const arrayBuffer = res?.data ?? res;
|
||||||
const link = document.createElement("a");
|
const blob = new Blob([arrayBuffer]);
|
||||||
link.href = url;
|
const url = window.URL.createObjectURL(blob);
|
||||||
link.download = fileName;
|
const link = document.createElement("a");
|
||||||
document.body.appendChild(link);
|
link.href = url;
|
||||||
link.click();
|
link.download = fileName;
|
||||||
document.body.removeChild(link);
|
document.body.appendChild(link);
|
||||||
window.URL.revokeObjectURL(url);
|
link.click();
|
||||||
}).catch(() => {
|
document.body.removeChild(link);
|
||||||
message.error("签署文件下载失败");
|
window.URL.revokeObjectURL(url);
|
||||||
});
|
})
|
||||||
|
.catch(() => {
|
||||||
|
message.error("签署文件下载失败");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUploadSigned(row) {
|
function handleUploadSigned(row) {
|
||||||
@@ -741,7 +1012,8 @@ function handleSignBusinessUpdated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleModalSave(payload) {
|
function handleModalSave(payload) {
|
||||||
const requestFn = payload.mode === "edit" ? updateLaunchDraft : createLaunchDraft;
|
const requestFn =
|
||||||
|
payload.mode === "edit" ? updateLaunchDraft : createLaunchDraft;
|
||||||
requestFn(payload.record).then((res) => {
|
requestFn(payload.record).then((res) => {
|
||||||
if (!isSuccessResponse(res)) {
|
if (!isSuccessResponse(res)) {
|
||||||
message.error(getResponseMessage(res, "保存合同失败"));
|
message.error(getResponseMessage(res, "保存合同失败"));
|
||||||
@@ -792,16 +1064,23 @@ function handleTerminate(row) {
|
|||||||
let terminateReason = "";
|
let terminateReason = "";
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认终止合同【${row.contractName}】吗?`,
|
title: `确认终止合同【${row.contractName}】吗?`,
|
||||||
content: h("div", { style: { display: "flex", flexDirection: "column", gap: "12px" } }, [
|
content: h(
|
||||||
h("div", "除已完成外,任意环节都可终止。当前仅终止业务系统内流程,法务系统需分别操作。"),
|
"div",
|
||||||
h(Input.TextArea, {
|
{ style: { display: "flex", flexDirection: "column", gap: "12px" } },
|
||||||
rows: 4,
|
[
|
||||||
placeholder: "可选:请输入终止原因",
|
h(
|
||||||
onChange: (event) => {
|
"div",
|
||||||
terminateReason = event?.target?.value || "";
|
"除已完成外,任意环节都可终止。当前仅终止业务系统内流程,法务系统需分别操作。",
|
||||||
},
|
),
|
||||||
}),
|
h(Input.TextArea, {
|
||||||
]),
|
rows: 4,
|
||||||
|
placeholder: "可选:请输入终止原因",
|
||||||
|
onChange: (event) => {
|
||||||
|
terminateReason = event?.target?.value || "";
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
okText: "确认终止",
|
okText: "确认终止",
|
||||||
cancelText: "取消",
|
cancelText: "取消",
|
||||||
okType: "danger",
|
okType: "danger",
|
||||||
|
|||||||
@@ -371,7 +371,8 @@ function handleExportExcel() {
|
|||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10000,
|
pageSize: 10000,
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
const blob = new Blob([data], {
|
const arrayBuffer = data?.data ?? data;
|
||||||
|
const blob = new Blob([arrayBuffer], {
|
||||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
});
|
});
|
||||||
saveAs(blob, `合同日志_${Date.now()}.xlsx`);
|
saveAs(blob, `合同日志_${Date.now()}.xlsx`);
|
||||||
|
|||||||
@@ -559,8 +559,9 @@ async function handleTemplateFile(file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const downloadedBuffer = await downloadTemplateFile(uploadedFilePath)
|
const downloadedBuffer = await downloadTemplateFile(uploadedFilePath)
|
||||||
|
const downloadedArrayBuffer = downloadedBuffer?.data ?? downloadedBuffer
|
||||||
const previewBuffer =
|
const previewBuffer =
|
||||||
downloadedBuffer.data instanceof ArrayBuffer ? downloadedBuffer.data : downloadedBuffer.data?.buffer
|
downloadedArrayBuffer instanceof ArrayBuffer ? downloadedArrayBuffer : downloadedArrayBuffer?.buffer
|
||||||
|
|
||||||
if (!previewBuffer) {
|
if (!previewBuffer) {
|
||||||
message.error('模板文件已上传,但回读渲染失败')
|
message.error('模板文件已上传,但回读渲染失败')
|
||||||
@@ -798,7 +799,8 @@ async function handleSubmit(status) {
|
|||||||
async function loadTemplateBufferFromRecord(record) {
|
async function loadTemplateBufferFromRecord(record) {
|
||||||
if (record.templateFilePath) {
|
if (record.templateFilePath) {
|
||||||
const response = await downloadTemplateFile(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)
|
setUploadList(record.templateFileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -487,24 +487,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="step-card-body">
|
<div class="step-card-body">
|
||||||
<div class="complete-form-grid">
|
<div class="complete-form-grid">
|
||||||
<a-date-picker
|
<div class="complete-form-item">
|
||||||
v-model:value="completeSignDate"
|
<div class="complete-form-label">签订日期</div>
|
||||||
value-format="YYYY-MM-DD"
|
<a-date-picker
|
||||||
style="width: 100%"
|
v-model:value="completeSignDate"
|
||||||
placeholder="签订日期"
|
value-format="YYYY-MM-DD"
|
||||||
/>
|
style="width: 100%"
|
||||||
<a-date-picker
|
placeholder="请选择签订日期"
|
||||||
v-model:value="completeSealDate"
|
/>
|
||||||
value-format="YYYY-MM-DD"
|
</div>
|
||||||
style="width: 100%"
|
<div class="complete-form-item">
|
||||||
placeholder="用印时间"
|
<div class="complete-form-label">用印时间</div>
|
||||||
/>
|
<a-date-picker
|
||||||
<a-date-picker
|
v-model:value="completeSealDate"
|
||||||
v-model:value="completeActiveDate"
|
value-format="YYYY-MM-DD"
|
||||||
value-format="YYYY-MM-DD"
|
style="width: 100%"
|
||||||
style="width: 100%"
|
placeholder="请选择用印时间"
|
||||||
placeholder="合同生效日期"
|
/>
|
||||||
/>
|
</div>
|
||||||
|
<div class="complete-form-item">
|
||||||
|
<div class="complete-form-label">合同生效日期</div>
|
||||||
|
<a-date-picker
|
||||||
|
v-model:value="completeActiveDate"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
style="width: 100%"
|
||||||
|
placeholder="请选择合同生效日期"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -762,6 +771,23 @@ function formatDateTimeValue(value) {
|
|||||||
return value ? `${value} 00:00:00` : null;
|
return value ? `${value} 00:00:00` : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePdfPreviewImages(list = []) {
|
||||||
|
return (Array.isArray(list) ? list : [])
|
||||||
|
.map((item) => {
|
||||||
|
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 = {}) {
|
function syncCompletionDates(record = {}) {
|
||||||
completeSignDate.value = sliceDateValue(record?.signDate) || todayString();
|
completeSignDate.value = sliceDateValue(record?.signDate) || todayString();
|
||||||
completeSealDate.value = sliceDateValue(record?.sealDate) || completeSignDate.value;
|
completeSealDate.value = sliceDateValue(record?.sealDate) || completeSignDate.value;
|
||||||
@@ -895,7 +921,11 @@ async function buildBusinessBodyUploadFile(record = {}) {
|
|||||||
if (!bodyFile.filePath) {
|
if (!bodyFile.filePath) {
|
||||||
return null;
|
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 =
|
const type =
|
||||||
String(bodyFile.fileType || "").toLowerCase() === "pdf"
|
String(bodyFile.fileType || "").toLowerCase() === "pdf"
|
||||||
? "application/pdf"
|
? "application/pdf"
|
||||||
@@ -1108,7 +1138,7 @@ async function loadContract(cid) {
|
|||||||
contractName.value = detail?.contractName || contractName.value;
|
contractName.value = detail?.contractName || contractName.value;
|
||||||
contractStatus.value =
|
contractStatus.value =
|
||||||
detail?.contractStatus ?? detail?.status ?? contractStatus.value;
|
detail?.contractStatus ?? detail?.status ?? contractStatus.value;
|
||||||
pdfImages.value = preview?.pdfToImageList || [];
|
pdfImages.value = normalizePdfPreviewImages(preview?.pdfToImageList);
|
||||||
imageWidth.value = Number(preview?.imageWidth) || 793;
|
imageWidth.value = Number(preview?.imageWidth) || 793;
|
||||||
imageHeight.value = Number(preview?.imageHeight) || 1122;
|
imageHeight.value = Number(preview?.imageHeight) || 1122;
|
||||||
updateBusinessStatusByContractStatus(contractStatus.value);
|
updateBusinessStatusByContractStatus(contractStatus.value);
|
||||||
@@ -1144,7 +1174,7 @@ async function handleCreateContract() {
|
|||||||
|
|
||||||
const data = getResponseResult(res);
|
const data = getResponseResult(res);
|
||||||
contractId.value = data.contractId || "";
|
contractId.value = data.contractId || "";
|
||||||
pdfImages.value = data.pdfToImageList || [];
|
pdfImages.value = normalizePdfPreviewImages(data.pdfToImageList);
|
||||||
imageWidth.value = Number(data.imageWidth) || 793;
|
imageWidth.value = Number(data.imageWidth) || 793;
|
||||||
imageHeight.value = Number(data.imageHeight) || 1122;
|
imageHeight.value = Number(data.imageHeight) || 1122;
|
||||||
contractStatus.value = 10;
|
contractStatus.value = 10;
|
||||||
@@ -1676,7 +1706,7 @@ async function confirmTimestamp(item) {
|
|||||||
item.status = "signed";
|
item.status = "signed";
|
||||||
item._signTime = data.signatureTime || "";
|
item._signTime = data.signatureTime || "";
|
||||||
if (data.pdfToImageList?.length) {
|
if (data.pdfToImageList?.length) {
|
||||||
pdfImages.value = data.pdfToImageList;
|
pdfImages.value = normalizePdfPreviewImages(data.pdfToImageList);
|
||||||
}
|
}
|
||||||
if (data.contractStatus !== undefined) {
|
if (data.contractStatus !== undefined) {
|
||||||
contractStatus.value = data.contractStatus;
|
contractStatus.value = data.contractStatus;
|
||||||
@@ -1882,9 +1912,10 @@ watch(visible, (value) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: space-between;
|
grid-template-columns: 72px minmax(0, 1fr);
|
||||||
align-items: center;
|
align-items: start;
|
||||||
|
column-gap: 12px;
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
border-bottom: 1px dashed #eef2f6;
|
border-bottom: 1px dashed #eef2f6;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@@ -1896,10 +1927,16 @@ watch(visible, (value) => {
|
|||||||
|
|
||||||
.info-item span {
|
.info-item span {
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-item strong {
|
.info-item strong {
|
||||||
color: #0f172a;
|
color: #0f172a;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: break-word;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.business-tag-row {
|
.business-tag-row {
|
||||||
@@ -1933,9 +1970,10 @@ watch(visible, (value) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.business-meta-item {
|
.business-meta-item {
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: space-between;
|
grid-template-columns: 72px minmax(0, 1fr);
|
||||||
gap: 12px;
|
align-items: start;
|
||||||
|
column-gap: 12px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
@@ -1947,14 +1985,22 @@ watch(visible, (value) => {
|
|||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.business-meta-item span {
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
.business-meta-item strong {
|
.business-meta-item strong {
|
||||||
flex: 1;
|
min-width: 0;
|
||||||
text-align: right;
|
text-align: left;
|
||||||
color: #0f172a;
|
color: #0f172a;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
white-space: nowrap;
|
white-space: normal;
|
||||||
overflow: hidden;
|
overflow: visible;
|
||||||
text-overflow: ellipsis;
|
text-overflow: initial;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: break-word;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-mode-hint {
|
.upload-mode-hint {
|
||||||
|
|||||||
Reference in New Issue
Block a user