获取相对方

This commit is contained in:
2026-06-30 16:36:26 +08:00
parent fe019228b7
commit 83f5b5fcce
2 changed files with 189 additions and 26 deletions
+15
View File
@@ -129,6 +129,21 @@ export function saveContractCollectInfo(id, data) {
}); });
} }
export function getCounterpartyConfirm(id) {
return request({
url: `/contract/launch/${id}/counterparty-confirm`,
method: "get",
});
}
export function confirmCounterparty(id, data) {
return request({
url: `/contract/launch/${id}/counterparty-confirm`,
method: "post",
data,
});
}
export function archiveLaunch(id, data = {}) { export function archiveLaunch(id, data = {}) {
return request({ return request({
url: `/contract/launch/${id}/archive`, url: `/contract/launch/${id}/archive`,
@@ -532,6 +532,37 @@
</div> </div>
</div> </div>
<div v-if="counterpartyPartyNames.length" class="counterparty-confirm-section">
<div class="counterparty-confirm-title">相对方签署确认</div>
<div
v-for="name in counterpartyPartyNames"
:key="name"
class="counterparty-confirm-row"
>
<span
v-if="counterpartyConfirmMap[name]?.confirmed"
class="confirm-status status-done"
></span>
<span v-else class="confirm-status status-pending"></span>
<span class="confirm-name">{{ name }}</span>
<span
v-if="counterpartyConfirmMap[name]?.confirmed"
class="confirm-method"
>{{ counterpartyConfirmMap[name]?.method === 'manual' ? '(代确认)' : '(已确认)' }}</span>
<a-button
v-else
size="small"
type="primary"
ghost
:loading="counterpartyConfirmLoading"
@click="handleConfirmCounterparty(name)"
>我已签署完成</a-button>
</div>
<div v-if="unconfirmedPartyNames.length" class="counterparty-confirm-note">
所有相对方确认后方可正常结束未确认仍可强制结束
</div>
</div>
<div <div
class="btn btn-success" class="btn btn-success"
:class="{ :class="{
@@ -647,6 +678,7 @@ import {
toRef, toRef,
reactive, reactive,
computed, computed,
h,
nextTick, nextTick,
onMounted, onMounted,
onUnmounted, onUnmounted,
@@ -679,6 +711,8 @@ import {
finishLaunchSeal, finishLaunchSeal,
downloadLaunchFile, downloadLaunchFile,
saveLaunchSealInfo, saveLaunchSealInfo,
getCounterpartyConfirm,
confirmCounterparty,
} from "@/api/launch.js"; } from "@/api/launch.js";
const SUCCESS_CODE = "0000"; const SUCCESS_CODE = "0000";
@@ -1056,6 +1090,7 @@ async function showModal(contractIdParam, businessRecordParam) {
await loadContract(contractIdToLoad); await loadContract(contractIdToLoad);
await nextTick(); await nextTick();
calcDisplaySize(); calcDisplaySize();
await loadCounterpartyConfirm();
modalLoading.value = false; modalLoading.value = false;
return; return;
} }
@@ -1077,6 +1112,7 @@ async function showModal(contractIdParam, businessRecordParam) {
} }
} catch {} } catch {}
} }
await loadCounterpartyConfirm();
modalLoading.value = false; modalLoading.value = false;
} }
@@ -1138,6 +1174,8 @@ const pdfImages = ref([]);
const imageWidth = ref(793); const imageWidth = ref(793);
const imageHeight = ref(1122); const imageHeight = ref(1122);
const completing = ref(false); const completing = ref(false);
const counterpartyConfirmMap = ref({});
const counterpartyConfirmLoading = ref(false);
async function loadContract(cid) { async function loadContract(cid) {
try { try {
@@ -1264,6 +1302,44 @@ const fetchingSeals = ref(false);
const sealList = ref([]); const sealList = ref([]);
const sealDefaultScale = ref(1.0); const sealDefaultScale = ref(1.0);
/** 解析相对方名单(分号分隔) */
const counterpartyPartyNames = computed(() => {
const text = businessRecord.value?.counterpartySummary || '';
return text.split(/[;]/).map(s => s.trim()).filter(Boolean);
});
/** 未确认的相对方名单 */
const unconfirmedPartyNames = computed(() => {
return counterpartyPartyNames.value.filter(name => !counterpartyConfirmMap.value[name]?.confirmed);
});
async function loadCounterpartyConfirm() {
if (!businessRecord.value?.id) return;
counterpartyConfirmLoading.value = true;
try {
const res = await getCounterpartyConfirm(businessRecord.value.id);
if (isSuccessResponse(res) && res.result) {
counterpartyConfirmMap.value = res.result || {};
}
} catch { /* ignore */ }
counterpartyConfirmLoading.value = false;
}
async function handleConfirmCounterparty(companyName) {
if (!businessRecord.value?.id) return;
try {
const res = await confirmCounterparty(businessRecord.value.id, { companyName });
if (isSuccessResponse(res) && res.result) {
counterpartyConfirmMap.value = res.result || {};
message.success(`已确认:${companyName}`);
} else {
message.error(getResponseMessage(res, '确认失败'));
}
} catch {
message.error('确认失败');
}
}
queryName.value = '周小锋'; queryName.value = '周小锋';
queryIdOrMobile.value = '17681520782'; queryIdOrMobile.value = '17681520782';
@@ -1754,33 +1830,52 @@ async function handleCompleteContract() {
return; return;
} }
Modal.confirm({ // 检查相对方签署确认情况
title: "确认结束", await loadCounterpartyConfirm();
content: "确认结束合约?结束后将无法再继续添加签章。", const notConfirmed = unconfirmedPartyNames.value;
okType: "danger", if (notConfirmed.length) {
onOk: async () => { Modal.confirm({
completing.value = true; title: '以下相对方尚未确认签署完成',
try { content: h('div', [
const res = await completeContract(contractId.value); h('p', { style: { color: '#e6a23c', marginBottom: '12px' } }, `${notConfirmed.length} 个相对方未确认:`),
if (!isSuccessResponse(res)) { ...notConfirmed.map(n =>
message.error(getResponseMessage(res, "结束合约失败")); h('p', { style: { margin: '4px 0', color: '#f56c6c' } }, '⚠ ' + n)
return; ),
} h('p', { style: { color: '#999', fontSize: '12px', marginTop: '12px' } }, '仍可强制结束合约,建议各方确认后再结束。'),
]),
okText: '强制结束',
okType: 'danger',
cancelText: '暂不结束',
onOk: () => doEndContract(),
});
return;
}
contractStatus.value = 2000; // 全部已确认,正常结束
updateBusinessStatusByContractStatus(2000); doEndContract();
if (businessRecord.value?.id) { }
await writeBackLaunchSealFinished(2000);
} async function doEndContract() {
clearContractState(); completing.value = true;
message.success("合约已完成"); try {
} catch { const res = await completeContract(contractId.value);
message.error("结束合约失败"); if (!isSuccessResponse(res)) {
} finally { message.error(getResponseMessage(res, "结束合约失败"));
completing.value = false; return;
} }
},
}); contractStatus.value = 2000;
updateBusinessStatusByContractStatus(2000);
if (businessRecord.value?.id) {
await writeBackLaunchSealFinished(2000);
}
clearContractState();
message.success("合约已完成");
} catch {
message.error("结束合约失败");
} finally {
completing.value = false;
}
} }
async function handleDownloadContract() { async function handleDownloadContract() {
@@ -2718,4 +2813,57 @@ watch(visible, (value) => {
width: 320px; width: 320px;
} }
} }
/* 相对方签署确认 */
.counterparty-confirm-section {
margin: 14px 0;
padding: 10px 12px;
background: #f8fafc;
border-radius: 10px;
border: 1px solid #eef2f6;
}
.counterparty-confirm-title {
font-size: 13px;
font-weight: 600;
color: #2c3e50;
margin-bottom: 8px;
}
.counterparty-confirm-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 0;
font-size: 12px;
border-bottom: 1px dashed #eef2f6;
}
.counterparty-confirm-row:last-child {
border-bottom: none;
}
.confirm-status {
font-size: 14px;
flex-shrink: 0;
}
.confirm-status.status-done {
color: #67c23a;
}
.confirm-status.status-pending {
color: #c0c4cc;
}
.confirm-name {
flex: 1;
color: #2c3e50;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.confirm-method {
font-size: 11px;
color: #909399;
flex-shrink: 0;
}
.counterparty-confirm-note {
margin-top: 6px;
font-size: 11px;
color: #909399;
}
</style> </style>