From 08277c3be79dbcf018d04d453dc738d6354b4b1b Mon Sep 17 00:00:00 2001
From: quxin <592870522@qq.com>
Date: 星期三, 02 九月 2026 13:28:57 +0800
Subject: [PATCH] 诉讼信息自动归集至对应项目; 中标信息自动关联至对应项目; 所有销售合同数据均按项维度归集,作为项目管理模块中销售合同汇总的数据来源。
---
src/views/projectManagement/Management/projectDetail.vue | 249 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 249 insertions(+), 0 deletions(-)
diff --git a/src/views/projectManagement/Management/projectDetail.vue b/src/views/projectManagement/Management/projectDetail.vue
index be670cb..dee5f99 100644
--- a/src/views/projectManagement/Management/projectDetail.vue
+++ b/src/views/projectManagement/Management/projectDetail.vue
@@ -160,6 +160,88 @@
</el-table-column>
</el-table>
</el-tab-pane>
+
+ <el-tab-pane label="璇夎淇℃伅" name="lawsuit">
+ <el-table :data="lawsuitRows" border v-loading="lawsuitLoading" style="margin-top: 14px;">
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column label="妗堜欢缂栧彿" prop="caseNo" width="160" show-overflow-tooltip />
+ <el-table-column label="鎵�灞為」鐩�" prop="projectName" min-width="160" show-overflow-tooltip />
+ <el-table-column label="鍚堝悓缂栧彿" prop="contractNo" width="160" show-overflow-tooltip />
+ <el-table-column label="璇夎鐘舵��" width="110" align="center">
+ <template #default="{ row }">
+ <el-tag :type="lawsuitStatusTypeMap[row.lawsuitStatus] || 'info'">{{ row.lawsuitStatus || '-' }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="绔嬫鏃堕棿" prop="filingDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="鎵垮姙寰嬪笀/娉曞姟璐熻矗浜�" prop="lawyer" width="160" show-overflow-tooltip />
+ <el-table-column label="寮�搴椂闂�" prop="hearingDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="璇夎鏍囩殑閲戦(鍏�)" prop="claimAmount" width="150" align="right" :formatter="formatAmountColumn" />
+ <el-table-column label="鍒ゅ喅缁撴灉鎽樿" prop="judgmentSummary" min-width="180" show-overflow-tooltip />
+ <el-table-column label="璇夎杩涘睍澶囨敞" prop="progressRemark" min-width="160" show-overflow-tooltip />
+ <el-table-column label="闄勪欢" min-width="160">
+ <template #default="{ row }">
+ <div v-if="getLawsuitAttachments(row).length > 0" class="attachment-list">
+ <el-button
+ v-for="att in getLawsuitAttachments(row)"
+ :key="att.id || att.url || att.name || att.fileName"
+ link
+ type="primary"
+ size="small"
+ @click="downloadAttachment(att)"
+ >{{ att.name || att.fileName || '闄勪欢' }}</el-button>
+ </div>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-tab-pane>
+
+ <el-tab-pane label="涓爣淇℃伅" name="bidding">
+ <el-table :data="biddingRows" border v-loading="biddingLoading" style="margin-top: 14px;">
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column label="鎵�灞為」鐩�" prop="projectName" min-width="160" show-overflow-tooltip />
+ <el-table-column label="鏍囦功鍚嶇О" prop="bidDocName" min-width="160" show-overflow-tooltip />
+ <el-table-column label="鎷涙爣鍗曚綅" prop="tenderUnit" width="160" show-overflow-tooltip />
+ <el-table-column label="鎶曟爣鍗曚綅" prop="bidUnit" width="160" show-overflow-tooltip />
+ <el-table-column label="鎷涙爣鏃ユ湡" prop="tenderDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="鎶曟爣鏃ユ湡" prop="bidDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="鏍囦功娆鹃噾棰�(鍏�)" prop="bidDocFee" width="130" align="right" :formatter="formatAmountColumn" />
+ <el-table-column label="鏍囦功娆剧姸鎬�" width="110" align="center">
+ <template #default="{ row }">
+ <el-tag :type="bidDocFeeStatusTypeMap[row.bidDocFeeStatus] || 'info'">{{ row.bidDocFeeStatus || '-' }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏍囦功娆剧姸鎬佸彉鏇存棩鏈�" prop="bidDocFeeStatusChangeDate" width="160" :formatter="formatDateColumn" />
+ <el-table-column label="鎶曟爣淇濊瘉閲�(鍏�)" prop="bidDeposit" width="130" align="right" :formatter="formatAmountColumn" />
+ <el-table-column label="鎷涙姇鏍囩粨鏋�" width="150" align="center">
+ <template #default="{ row }">
+ <el-tag :type="bidResultTypeMap[row.bidResult] || 'info'">{{ row.bidResult || '-' }}</el-tag>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-tab-pane>
+
+ <el-tab-pane label="閿�鍞悎鍚�" name="contract">
+ <el-table :data="contractRows" border v-loading="contractLoading" style="margin-top: 14px;">
+ <el-table-column align="center" label="搴忓彿" type="index" width="60" />
+ <el-table-column label="閿�鍞悎鍚屽彿" prop="salesContractNo" width="180" show-overflow-tooltip />
+ <el-table-column label="瀹㈡埛鍚嶇О" prop="customerName" min-width="180" show-overflow-tooltip />
+ <el-table-column label="涓氬姟鍛�" prop="salesman" width="100" show-overflow-tooltip />
+ <el-table-column label="椤圭洰鍚嶇О" prop="projectName" width="180" show-overflow-tooltip />
+ <el-table-column label="浠樻鏂瑰紡" prop="paymentMethod" width="120">
+ <template #default="{ row }">
+ <dict-tag :options="checkout_payment" :value="row.paymentMethod" />
+ </template>
+ </el-table-column>
+ <el-table-column label="鍚堝悓閲戦(鍏�)" prop="contractAmount" width="140" align="right" :formatter="formatAmountColumn" />
+ <el-table-column label="瀹為檯鍚堝悓閲戦(鍏�)" prop="netContractAmount" width="150" align="right" :formatter="formatAmountColumn" />
+ <el-table-column label="褰曞叆浜�" prop="entryPersonName" width="100" show-overflow-tooltip />
+ <el-table-column label="褰曞叆鏃ユ湡" prop="entryDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="绛捐鏃ユ湡" prop="executionDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="浜や粯鏃ユ湡" prop="deliveryDate" width="110" :formatter="formatDateColumn" />
+ <el-table-column label="澶囨敞" prop="remarks" min-width="160" show-overflow-tooltip />
+ </el-table>
+ </el-tab-pane>
</el-tabs>
</el-card>
</div>
@@ -188,6 +270,9 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { getProject, saveStage, listStage, deleteStage } from '@/api/projectManagement/project'
import { listPlan } from '@/api/projectManagement/projectType'
+import { lawsuitListPage } from '@/api/salesManagement/lawsuitManagement'
+import { biddingListPage } from '@/api/salesManagement/biddingManagement'
+import { ledgerListPage } from '@/api/salesManagement/salesLedger'
import ProgressReportDialog from '@/components/ProjectManagement/ProgressReportDialog.vue'
import DiscussProgressDialog from '@/components/ProjectManagement/DiscussProgressDialog.vue'
import useUserStore from '@/store/modules/user'
@@ -196,6 +281,7 @@
const route = useRoute()
const router = useRouter()
const { bill_status, project_management, plan_status } = proxy.useDict('bill_status', 'project_management', 'plan_status')
+const { checkout_payment } = proxy.useDict('checkout_payment')
const loading = ref(false)
const activeTab = ref('base')
@@ -214,6 +300,13 @@
const planNodeRows = ref([])
const planAttachments = ref([])
const stageNodeRows = ref([])
+
+const lawsuitRows = ref([])
+const biddingRows = ref([])
+const contractRows = ref([])
+const lawsuitLoading = ref(false)
+const biddingLoading = ref(false)
+const contractLoading = ref(false)
const estimatedDays = computed(() => {
const raw = info.value?.estimatedDays
@@ -374,6 +467,161 @@
ElMessage.warning('闄勪欢鏆傛棤涓嬭浇鍦板潃')
}
+const lawsuitStatusTypeMap = {
+ 绔嬫涓�: 'warning',
+ 瀹$悊涓�: 'primary',
+ 宸插垽鍐�: 'success',
+ 宸叉挙璇�: 'info',
+ 宸插拰瑙�: 'success'
+}
+
+const bidDocFeeStatusTypeMap = {
+ 鏈氦: 'warning',
+ 宸蹭氦: 'success',
+ 宸查��: 'info'
+}
+
+const bidResultTypeMap = {
+ 搴熸爣: 'info',
+ 娴佹爣: 'info',
+ 鏈腑鏍�: 'warning',
+ 涓爣寰呭嚭閫氱煡涔�: 'primary',
+ 宸插嚭涓爣閫氱煡涔�: 'success',
+ 宸茬鍚堝悓: 'success'
+}
+
+function formatDate(val) {
+ if (val === undefined || val === null || val === '') return '-'
+ return String(val).substring(0, 10)
+}
+
+function formatAmount(val) {
+ if (val === undefined || val === null || val === '') return '0.00'
+ const num = Number(val)
+ return Number.isNaN(num) ? '0.00' : num.toFixed(2)
+}
+
+function formatDateColumn(row, column, cellValue) {
+ return formatDate(cellValue)
+}
+
+function formatAmountColumn(row, column, cellValue) {
+ return formatAmount(cellValue)
+}
+
+function getLawsuitAttachments(row) {
+ if (Array.isArray(row?.storageBlobVOs)) return row.storageBlobVOs
+ if (Array.isArray(row?.attachmentList)) return row.attachmentList
+ return []
+}
+
+function matchProject(record, projectId, projectTitle) {
+ if (!record) return false
+ if (record.projectId !== undefined && record.projectId !== null && record.projectId !== '') {
+ if (String(record.projectId) === String(projectId)) return true
+ }
+ const name = String(record.projectName || '').trim()
+ const title = String(projectTitle || '').trim()
+ if (name && title) {
+ return name === title || name.includes(title) || title.includes(name)
+ }
+ return false
+}
+
+function filterByProject(records, projectId, projectTitle) {
+ const list = Array.isArray(records) ? records : []
+ if (list.length === 0) return []
+ const matched = list.filter(r => matchProject(r, projectId, projectTitle))
+ return matched.length > 0 ? matched : list
+}
+
+function extractRecords(res) {
+ return (
+ res?.data?.records ||
+ res?.records ||
+ res?.rows ||
+ res?.data?.rows ||
+ res?.data?.list ||
+ (Array.isArray(res?.data) ? res.data : []) ||
+ []
+ )
+}
+
+async function loadLawsuitList() {
+ const projectId = info.value?.id
+ const projectTitle = info.value?.title
+ if (!projectId) {
+ lawsuitRows.value = []
+ return
+ }
+ lawsuitLoading.value = true
+ try {
+ let res = await lawsuitListPage({ projectName: projectTitle, current: 1, size: 999 })
+ let records = extractRecords(res)
+ let matched = records.filter(r => matchProject(r, projectId, projectTitle))
+ if (matched.length === 0) {
+ res = await lawsuitListPage({ current: 1, size: 999 })
+ records = extractRecords(res)
+ matched = records.filter(r => matchProject(r, projectId, projectTitle))
+ }
+ lawsuitRows.value = matched
+ } catch {
+ lawsuitRows.value = []
+ } finally {
+ lawsuitLoading.value = false
+ }
+}
+
+async function loadBiddingList() {
+ const projectId = info.value?.id
+ const projectTitle = info.value?.title
+ if (!projectId) {
+ biddingRows.value = []
+ return
+ }
+ biddingLoading.value = true
+ try {
+ let res = await biddingListPage({ projectName: projectTitle, current: 1, size: 999 })
+ let records = extractRecords(res)
+ let matched = records.filter(r => matchProject(r, projectId, projectTitle))
+ if (matched.length === 0) {
+ res = await biddingListPage({ current: 1, size: 999 })
+ records = extractRecords(res)
+ matched = records.filter(r => matchProject(r, projectId, projectTitle))
+ }
+ biddingRows.value = matched
+ } catch {
+ biddingRows.value = []
+ } finally {
+ biddingLoading.value = false
+ }
+}
+
+async function loadContractList() {
+ const projectId = info.value?.id
+ if (!projectId) {
+ contractRows.value = []
+ return
+ }
+ contractLoading.value = true
+ try {
+ const res = await ledgerListPage({ projectId, current: 1, size: 999 })
+ const records = extractRecords(res)
+ contractRows.value = filterByProject(records, projectId, info.value?.title).sort((a, b) => {
+ const da = String(a.executionDate || '').substring(0, 10)
+ const db = String(b.executionDate || '').substring(0, 10)
+ if (!da && !db) return 0
+ if (!da) return 1
+ if (!db) return -1
+ return db.localeCompare(da)
+ })
+ } catch {
+ contractRows.value = []
+ } finally {
+ contractLoading.value = false
+ }
+}
+
async function loadProjectTypeMap() {
try {
const res = await listPlan({ current: 1, size: 999 })
@@ -471,6 +719,7 @@
onMounted(async () => {
await loadProjectTypeMap()
await loadDetail()
+ await Promise.all([loadLawsuitList(), loadBiddingList(), loadContractList()])
})
</script>
--
Gitblit v1.9.3