From a3057955f855b8a266c017df00645845e7471410 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期五, 07 八月 2026 18:01:59 +0800
Subject: [PATCH] 银川 1.不合格品处理页面开发联调 2.招投标管理 - 可配置版前端联调方案
---
src/views/srm/tender/detail.vue | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 102 insertions(+), 18 deletions(-)
diff --git a/src/views/srm/tender/detail.vue b/src/views/srm/tender/detail.vue
index 4dfbeda..7b2f1de 100644
--- a/src/views/srm/tender/detail.vue
+++ b/src/views/srm/tender/detail.vue
@@ -17,6 +17,7 @@
createBidOpen, getBidOpen,
getEvaluationList, createBidEvaluation, updateBidEvaluation, calculateRanking,
createAward, deleteAward, getAward, getAwardByProject, approveAward, generatePurchaseOrder,
+ confirmTenderProject,
} from '#/api/srm/tender';
import { getSupplierSimpleList } from '#/api/srm/supplier';
import { getItemSimpleList } from '#/api/mdm/item';
@@ -31,6 +32,7 @@
AWARD_STATUS,
AWARD_STATUS_MAP,
getLabel,
+ BIDDING_MODE,
} from '../enums';
defineOptions({ name: 'SrmTenderDetail' });
@@ -318,6 +320,36 @@
loadProject();
}
+// ========== 绠�鏄撴ā寮忥細纭涓爣 ==========
+const confirmBidId = ref<number>();
+const confirmModalVisible = ref(false);
+
+async function handleConfirmBidAsWinner(bidId: number) {
+ await confirmTenderProject({ id: projectId, bidId });
+ message.success('纭涓爣鎴愬姛锛岄噰璐鍗曞凡鑷姩鐢熸垚');
+ loadProject();
+ loadBids();
+ loadAward();
+}
+
+function openSimpleConfirmModal() {
+ confirmBidId.value = undefined;
+ confirmModalVisible.value = true;
+}
+
+async function handleSimpleConfirm() {
+ if (!confirmBidId.value) {
+ message.warning('璇烽�夋嫨涓爣鐨勬姇鏍囪褰�');
+ return;
+ }
+ await confirmTenderProject({ id: projectId, bidId: confirmBidId.value });
+ message.success('纭涓爣鎴愬姛锛岄噰璐鍗曞凡鑷姩鐢熸垚');
+ confirmModalVisible.value = false;
+ loadProject();
+ loadBids();
+ loadAward();
+}
+
// ========== 鍒濆鍖� ==========
loadProject();
loadMaterials();
@@ -344,23 +376,37 @@
const canApproveAward = computed(() => award.value?.awardStatus === AWARD_STATUS.PENDING_APPROVAL);
const canGeneratePO = computed(() => award.value?.awardStatus === AWARD_STATUS.AWARDED);
-const stepItems = [
- { title: '鑽夌', status: TENDER_STATUS.DRAFT },
- { title: '鍙戝竷', status: TENDER_STATUS.PUBLISHED },
- { title: '鎶曟爣涓�', status: TENDER_STATUS.BIDDING },
- { title: '璇勬爣涓�', status: TENDER_STATUS.EVALUATING },
- { title: '宸插畾鏍�', status: TENDER_STATUS.AWARDED },
-];
+// 绠�鏄撴ā寮�
+const isSimpleMode = computed(() => project.value?.biddingMode === BIDDING_MODE.SIMPLE);
+const isPriceComparing = computed(() => project.value?.tenderStatus === TENDER_STATUS.PRICE_COMPARING);
+
+const stepItems = computed(() => {
+ if (isSimpleMode.value) {
+ return [
+ { title: '鑽夌', status: TENDER_STATUS.DRAFT },
+ { title: '姣斾环涓�', status: TENDER_STATUS.PRICE_COMPARING },
+ { title: '宸茬‘璁�', status: TENDER_STATUS.CONFIRMED },
+ ];
+ }
+ return [
+ { title: '鑽夌', status: TENDER_STATUS.DRAFT },
+ { title: '鍙戝竷', status: TENDER_STATUS.PUBLISHED },
+ { title: '鎶曟爣涓�', status: TENDER_STATUS.BIDDING },
+ { title: '璇勬爣涓�', status: TENDER_STATUS.EVALUATING },
+ { title: '宸插畾鏍�', status: TENDER_STATUS.AWARDED },
+ ];
+});
const currentStep = computed(() => {
const s = project.value?.tenderStatus ?? 0;
- if (s === TENDER_STATUS.CLOSED) return 4;
- const idx = stepItems.findIndex((item) => item.status >= s);
+ const items = stepItems.value;
+ if (s === TENDER_STATUS.CLOSED) return items.length - 1;
+ const idx = items.findIndex((item) => item.status >= s);
return idx === -1 ? 0 : idx;
});
const stepStatus = computed(() => {
const s = project.value?.tenderStatus;
if (s === TENDER_STATUS.CLOSED) return 'error';
- if (s === TENDER_STATUS.AWARDED) return 'finish';
+ if (s === TENDER_STATUS.AWARDED || s === TENDER_STATUS.CONFIRMED) return 'finish';
return 'process';
});
@@ -395,7 +441,7 @@
{ title: '鎶曟爣閲戦', dataIndex: 'bidTotalAmount', width: 120 },
{ title: '鎶曟爣鏃堕棿', dataIndex: 'bidTime', width: 160 },
{ title: '鐘舵��', dataIndex: 'bidStatus', width: 100, customRender: ({ text }: any) => BID_STATUS_MAP[text] || text },
- { title: '鎿嶄綔', key: 'actions', width: 180 },
+ { title: '鎿嶄綔', key: 'actions', width: 240 },
];
const quoteColumns = [
@@ -438,7 +484,16 @@
<span class="text-gray-400 text-xs">{{ project.tenderNo }}</span>
<a-tag :color="statusColor">{{ statusLabel }}</a-tag>
<a-tag color="blue">{{ typeLabel }}</a-tag>
+ <a-tag v-if="isSimpleMode" color="purple">绠�鏄撶増</a-tag>
<div class="flex-1" />
+ <a-button
+ v-if="isPriceComparing"
+ type="primary"
+ size="small"
+ @click="openSimpleConfirmModal"
+ >
+ 纭涓爣
+ </a-button>
<a-button size="small" @click="loadProject(); loadMaterials(); loadBids(); loadEvaluations(); loadAward();">
<template #icon><IconifyIcon icon="ant-design:reload-outlined" /></template>
鍒锋柊
@@ -539,7 +594,7 @@
</template>
<div class="flex items-center justify-between mb-3">
<span class="text-xs text-gray-400">鍏� <b class="text-gray-600">{{ bidCount }}</b> 涓姇鏍�</span>
- <a-button v-if="isPublishedOrBidding" type="primary" size="small" @click="bidForm = { tenderProjectId: projectId, supplierId: undefined!, bidNo: '' }; bidFormVisible = true">
+ <a-button v-if="isPublishedOrBidding || isDraft || isPriceComparing" type="primary" size="small" @click="bidForm = { tenderProjectId: projectId, supplierId: undefined!, bidNo: '' }; bidFormVisible = true">
<template #icon><IconifyIcon icon="ant-design:plus-outlined" /></template>
鏂板鎶曟爣
</a-button>
@@ -557,7 +612,10 @@
<template v-if="column.key === 'actions'">
<a-space>
<a-button size="small" type="link" @click="loadQuotes(record.id); activeTab = 'quote'"><IconifyIcon icon="ant-design:dollar-outlined" />鎶ヤ环</a-button>
- <a-popconfirm v-if="isPublishedOrBidding && record.bidStatus === BID_STATUS.REGISTERED" title="纭鎾ゆ爣锛�" @confirm="handleWithdrawBid(record.id)">
+ <a-popconfirm v-if="isPriceComparing && record.bidStatus !== BID_STATUS.WITHDRAWN" title="纭閫夋嫨璇ユ姇鏍囦负涓爣锛熷皢鑷姩鐢熸垚閲囪喘璁㈠崟銆�" ok-text="纭涓爣" cancel-text="鍙栨秷" @confirm="handleConfirmBidAsWinner(record.id)">
+ <a-button size="small" type="link" style="color: #52c41a;"><IconifyIcon icon="ant-design:check-circle-outlined" />纭涓爣</a-button>
+ </a-popconfirm>
+ <a-popconfirm v-if="(isPublishedOrBidding || isDraft || isPriceComparing) && record.bidStatus === BID_STATUS.REGISTERED" title="纭鎾ゆ爣锛�" @confirm="handleWithdrawBid(record.id)">
<a-button size="small" type="link" danger><IconifyIcon icon="ant-design:close-circle-outlined" />鎾ゆ爣</a-button>
</a-popconfirm>
</a-space>
@@ -580,7 +638,7 @@
<a-button size="small" type="link" class="ml-auto" @click="activeTab = 'bid'">鍒囨崲鎶曟爣</a-button>
</div>
<div class="text-right mb-3">
- <a-button v-if="isPublishedOrBidding && selectedBid.bidStatus !== BID_STATUS.WITHDRAWN" type="primary" size="small" @click="handleAddQuote">
+ <a-button v-if="(isPublishedOrBidding || isDraft || isPriceComparing) && selectedBid?.bidStatus !== BID_STATUS.WITHDRAWN" type="primary" size="small" @click="handleAddQuote">
<template #icon><IconifyIcon icon="ant-design:plus-outlined" /></template>
鏂板鎶ヤ环
</a-button>
@@ -600,7 +658,7 @@
{{ record.warrantyPeriod != null ? `${record.warrantyPeriod} 涓湀` : '-' }}
</template>
<template v-if="column.key === 'actions'">
- <a-button v-if="isPublishedOrBidding && selectedBid?.bidStatus !== BID_STATUS.WITHDRAWN" size="small" type="link" @click="handleEditQuote(record)"><IconifyIcon icon="ant-design:edit-outlined" />缂栬緫</a-button>
+ <a-button v-if="(isPublishedOrBidding || isDraft || isPriceComparing) && selectedBid?.bidStatus !== BID_STATUS.WITHDRAWN" size="small" type="link" @click="handleEditQuote(record)"><IconifyIcon icon="ant-design:edit-outlined" />缂栬緫</a-button>
</template>
</template>
</a-table>
@@ -612,7 +670,7 @@
</a-tab-pane>
<!-- Tab4: 寮�鏍� -->
- <a-tab-pane key="bidOpen">
+ <a-tab-pane v-if="!isSimpleMode" key="bidOpen">
<template #tab>
<a-space :size="4"><IconifyIcon icon="ant-design:unlock-outlined" />寮�鏍�</a-space>
</template>
@@ -639,7 +697,7 @@
</a-tab-pane>
<!-- Tab5: 璇勬爣 -->
- <a-tab-pane key="evaluation">
+ <a-tab-pane v-if="!isSimpleMode" key="evaluation">
<template #tab>
<a-space :size="4"><IconifyIcon icon="ant-design:trophy-outlined" />璇勬爣</a-space>
</template>
@@ -685,7 +743,7 @@
</a-tab-pane>
<!-- Tab6: 瀹氭爣 -->
- <a-tab-pane key="award">
+ <a-tab-pane v-if="!isSimpleMode" key="award">
<template #tab>
<a-space :size="4"><IconifyIcon icon="ant-design:check-circle-outlined" />瀹氭爣</a-space>
</template>
@@ -886,6 +944,32 @@
</a-form>
</a-modal>
+ <!-- 绠�鏄撴ā寮忥細纭涓爣寮圭獥 -->
+ <a-modal v-model:open="confirmModalVisible" title="纭涓爣" :width="460" @ok="handleSimpleConfirm">
+ <a-form layout="vertical" class="mt-4">
+ <a-form-item label="涓爣鎶曟爣璁板綍" required>
+ <a-select
+ v-model:value="confirmBidId"
+ show-search
+ placeholder="閫夋嫨涓爣鐨勬姇鏍囪褰�"
+ :filter-option="filterOption"
+ >
+ <a-select-option
+ v-for="b in bidList.filter((i) => i.bidStatus !== BID_STATUS.WITHDRAWN)"
+ :key="b.id"
+ :value="b.id"
+ :label="`${b.supplierName} - ${b.bidNo}`"
+ >
+ {{ b.supplierName }} - {{ b.bidNo }} (楼{{ b.bidTotalAmount?.toLocaleString?.() ?? b.bidTotalAmount }})
+ </a-select-option>
+ </a-select>
+ </a-form-item>
+ <div class="text-gray-400 text-xs">
+ 纭鍚庡皢鑷姩鐢熸垚閲囪喘璁㈠崟锛岃鎿嶄綔涓嶅彲鎾ら攢銆�
+ </div>
+ </a-form>
+ </a-modal>
+
<!-- 瀹氭爣琛ㄥ崟 -->
<a-modal v-model:open="awardFormVisible" title="鍒涘缓瀹氭爣" :width="500" @ok="handleCreateAward">
<a-form layout="vertical" class="mt-4">
--
Gitblit v1.9.3