招标解析

This commit is contained in:
cwchen 2025-11-26 16:47:07 +08:00
parent 388c95a347
commit 3f9410c01d
4 changed files with 133 additions and 65 deletions

View File

@ -34,7 +34,7 @@
<el-col :span="12" class="detail-col">
<div class="detail-field">
<div class="field-label">招标人</div>
<div class="field-value">{{ detailData.bidder || '--' }}</div>
<div class="field-value">{{ detailData.tenderer || '--' }}</div>
</div>
</el-col>
<el-col :span="12" class="detail-col">
@ -49,13 +49,13 @@
<el-col :span="12" class="detail-col">
<div class="detail-field">
<div class="field-label">开标时间</div>
<div class="field-value">{{ detailData.openTime || '--' }}</div>
<div class="field-value">{{ detailData.bidOpeningTime || '--' }}</div>
</div>
</el-col>
<el-col :span="12" class="detail-col">
<div class="detail-field">
<div class="field-label">开标方式</div>
<div class="field-value">{{ detailData.openMethod || '--' }}</div>
<div class="field-value">{{ detailData.bidOpeningMethod || '--' }}</div>
</div>
</el-col>
</el-row>
@ -63,13 +63,12 @@
<!-- 项目简介 - 占满宽度 -->
<div class="detail-field full-width">
<div class="field-label">项目简介</div>
<div class="field-value description-value">{{ detailData.proDescription || '--' }}</div>
<div class="field-value description-value">{{ detailData.proIntroduction || '--' }}</div>
</div>
<!-- 招标文件 -->
<div class="detail-field full-width">
<div class="field-label">招标文件</div>
<div class="file-value">{{ detailData.proDescription || '--' }}</div>
<div class="detail-field full-width" v-for="item in detailData.compositions" :key="item.id">
<div class="field-label">{{ item.compositionFileName || '--' }}</div>
<div class="file-value" @click="viewFile(item)">{{ getFirstFileName(item) }}</div>
</div>
</div>
</el-card>
@ -77,7 +76,7 @@
<el-row :gutter="12">
<el-col :span="17">
<TableModel :showSearch="false" :showOperation="false" :showRightTools="false"
ref="detailTableRef" :columnsList="detailColumnsList" :request-api="listAPI"
ref="detailTableRef" :columnsList="detailColumnsList" :request-api="getBidListAPI"
:sendParams="sendParams" :handleColWidth="180" :isRadioShow="true"
@radio-change="handleRadioChange" :indexNumShow="false" :isShowtableCardStyle="false">
<template slot="tableTitle">
@ -121,17 +120,18 @@
</el-row>
</div>
</div>
<ViewFile v-if="dialogVisible" :file="fileData" @closeDialog="handleCloseDialog" />
</div>
</template>
<script>
import { decryptWithSM4 } from '@/utils/sm'
import { listAPI, delDataAPI } from '@/api/analysis/analysis'
import { getProDetailAPI, getBidListAPI } from '@/api/analysis/analysis'
import { formLabel, detailColumnsList } from '../config'
import TableModel from '@/components/TableModel2'
import request from '@/utils/request'
import BidForm from './BidForm.vue'
import UploadMoreFile from '@/views/common/UploadMoreFile.vue'
import ViewFile from '@/views/common/ViewFile.vue';
//
const defaultParams = {
fileUploadRule: {
@ -148,17 +148,18 @@ export default {
components: {
TableModel,
BidForm,
UploadMoreFile
UploadMoreFile,
ViewFile
},
data() {
return {
formLabel,
detailColumnsList,
listAPI,
getBidListAPI,
proId: '',
detailData: {},
sendParams: {
enterpriseId: 2
proId: decryptWithSM4(this.$route.query.proId),
},
defaultParams,
selectedRow: {},
@ -167,6 +168,9 @@ export default {
delFileList: []
},
rules: {},
dialogVisible:false,
fileData:{}
}
},
watch: {
@ -210,44 +214,31 @@ export default {
//
async getDetail() {
try {
// TODO: API
const res = await request({
url: '/smartBid/analysis/detail',
method: 'GET',
params: { proId: this.proId }
})
// 使 getDetailDataAPI
// const res = await getDetailDataAPI({ proId: this.proId })
const res = await getProDetailAPI({ proId: this.proId, queryType: 2 })
console.log('res:', res);
if (res.code === 200) {
this.detailData = res.data || {}
} else {
this.$message.error(res.msg || '获取详情失败')
// 使
this.detailData = {
proName: '南方电网公司2025年电网基建工程第二批次施工公开招标项目',
proCode: 'CG2700022002003411',
bidder: '中建宏业建筑工程有限公司',
agency: '南方电网供应链集团有限公司',
openTime: '2025/06/02 09:00',
openMethod: '线上开标',
proDescription: '本项目为南方电网公司2025年电网基建工程第四批次施工公开招标涵盖云南、广东及深圳地区的多个标段工期从141至487日历天不等计划总投资额约...'
}
}
} catch (error) {
console.error('获取详情失败:', error)
// 使
this.detailData = {
proName: '南方电网公司2025年电网基建工程第二批次施工公开招标项目',
proCode: 'CG2700022002003411',
bidder: '中建宏业建筑工程有限公司',
agency: '南方电网供应链集团有限公司',
openTime: '2025/06/02 09:00',
openMethod: '线上开标',
proDescription: '本项目为南方电网公司2025年电网基建工程第四批次施工公开招标涵盖云南、广东及深圳地区的多个标段工期从141至487日历天不等计划总投资额约...'
}
}
},
//
getFirstFileName(item) {
return item?.fileVoList?.[0]?.fileName || '--';
},
//
viewFile(item) {
this.fileData = item.fileVoList[0]
console.log(this.fileData);
this.dialogVisible = true
},
handleCloseDialog() {
this.dialogVisible = false
this.fileData = {}
},
//
handleClose() {
const obj = { path: "/analysis" }
@ -515,6 +506,7 @@ export default {
font-size: 14px;
line-height: 1.5;
color: #1f72ea;
cursor: pointer;
}
}
}
@ -546,4 +538,5 @@ export default {
color: red;
}
}
</style>

View File

@ -1,7 +1,8 @@
<template>
<!-- 小型弹窗用于完成删除保存等操作 -->
<el-dialog class="l-dialog" :class="[lDialog, { 'no-pointer-events': showUploadAnimation }]" :title="title" :visible.sync="dialogVisible" :showClose="true"
:closeOnClickModal="false" @close="handleClose" :append-to-body="true">
<el-dialog class="l-dialog" :class="[lDialog, { 'no-pointer-events': showUploadAnimation }]" :title="title"
:visible.sync="dialogVisible" :showClose="true" :closeOnClickModal="false" @close="handleClose"
:append-to-body="true">
<div>
<!-- 全局上传动画 -->
<GlobalUploadAnimation v-if="showUploadAnimation" :text="animationText" subtext="正在处理文件,请稍候..." />
@ -38,7 +39,7 @@ import { addDataAPI } from '@/api/analysis/analysis'
//
const defaultParams = {
fileUploadRule: {
fileUploadType: 'bidding',
fileUploadType: 'pro_composition',
fields_json: '',
suffix: 'analysis_database',
},
@ -190,14 +191,18 @@ export default {
async submitForm(formName) {
try {
const data = await this.validate(formName)
console.log('data:', data);
//
let formData = {
...data,
allFiles: [
...data.fileList.map((file) =>
JSON.parse(JSON.stringify(file)),
allFiles: Object.keys(data)
.filter(key => key.startsWith('fileList'))
.flatMap(key =>
(data[key] || []).map(file =>
JSON.parse(JSON.stringify(file))
)
),
],
delFiles: [...data.delFileList],
}
@ -211,7 +216,11 @@ export default {
})
.filter((item) => item !== null)
formData.files = allFiles
delete formData.fileList
formData.uploadType = this.uploadType;
// fileList
Object.keys(formData)
.filter(key => key.startsWith('fileList'))
.forEach(key => delete formData[key]);
delete formData.delFileList
delete formData.allFiles
//
@ -223,12 +232,12 @@ export default {
this.$el.querySelector('.el-dialog') || document.body,
})
console.log('所有表单校验通过,完整数据:', formData)
/* const res = await this.saveData(formData)
const res = await this.saveData(formData)
if (res.code === 200) {
this.handleReuslt(res)
} else {
this.$modal.msgError(res.msg)
} */
}
} catch (error) {
} finally {
if (this.loading) {
@ -240,7 +249,6 @@ export default {
//
async saveData(formData) {
return new Promise((resolve, reject) => {
if (this.isAdd === 'add') {
//
addDataAPI(formData)
.then((res) => {
@ -249,7 +257,6 @@ export default {
.catch((error) => {
reject(error)
})
}
})
},
//

View File

@ -43,7 +43,7 @@
</div>
<!-- 新建项目 -->
<AnalysisForm v-if="showAnalysisForm" :title="title" :row="row" @closeDialog="showAnalysisForm = false"
:width="600" />
:width="600" @handleQuery="handleQuery" />
</el-card>
</template>
@ -155,7 +155,7 @@ export default {
this.$router.push({
name: 'AnalysisBidDetail',
query: {
proId: encryptWithSM4('2'),
proId: encryptWithSM4(row.proId + '' || '0'),
},
})
},

View File

@ -0,0 +1,68 @@
<template>
<el-dialog :visible.sync="dialogVisible" width="50%" class="preview-dialog" title="文件预览" @close="handleClose">
<OnlyOfficeViewer :document-url="documentUrl" :document-title="documentTitle" :document-key="documentKey"
:mode="mode" :type="type" @document-ready="handleDocumentReady" @app-ready="handleAppReady"
@error="handleError" @initialized="handleInitialized" :force-save="true" :save-timeout="15000" />
</el-dialog>
</template>
<script>
import OnlyOfficeViewer from './OnlyOfficeViewer';
export default {
name: 'ViewFile',
props: {
file: {
type: Object,
default: () => null
}
},
components: {
OnlyOfficeViewer
},
data() {
return {
dialogVisible: true,
documentUrl: this.file.filePath,
documentTitle: this.file.fileName,
documentKey: this.file.sourceId + '',
mode: 'view',
type: 'desktop',
}
},
methods: {
handleDocumentReady() {
console.log('文档已准备就绪')
},
handleAppReady() {
console.log('应用已准备就绪')
},
handleError(error) {
console.log('错误:', error)
},
handleInitialized() {
console.log('初始化完成')
},
handleClose() {
this.dialogVisible = false
this.$emit('closeDialog')
}
}
}
</script>
<style scoped>
.preview-dialog ::v-deep .el-dialog {
height: 88vh;
display: flex;
flex-direction: column;
}
.preview-dialog ::v-deep .el-dialog__body {
flex: 1;
padding: 0;
height: 0;
/* 重要让flex布局生效 */
}
.preview-dialog ::v-deep .onlyoffice-container {
height: 100%;
}
</style>