2722 lines
115 KiB
HTML
2722 lines
115 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>项目管理 - 招采业务</title>
|
||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
|
||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||
<style>
|
||
/* 基础样式 */
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
|
||
color: #333;
|
||
background-color: #f0f2f5;
|
||
}
|
||
|
||
.app-container {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 侧边栏样式 */
|
||
.sidebar {
|
||
width: 220px;
|
||
background-color: #304156;
|
||
color: #fff;
|
||
transition: width 0.3s;
|
||
flex-shrink: 0;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.sidebar.collapsed {
|
||
width: 64px;
|
||
}
|
||
|
||
.main-content {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
transition: margin-left 0.3s;
|
||
}
|
||
|
||
.sidebar.collapsed + .main-content {
|
||
margin-left: -156px;
|
||
}
|
||
|
||
.logo {
|
||
padding: 10px 0;
|
||
text-align: center;
|
||
position: relative;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.logo h2 {
|
||
font-size: 18px;
|
||
margin: 5px 0;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
padding: 0 10px;
|
||
}
|
||
|
||
.toggle-sidebar {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
cursor: pointer;
|
||
color: #fff;
|
||
}
|
||
|
||
/* 菜单项样式 */
|
||
.el-menu {
|
||
border-right: none;
|
||
background-color: transparent;
|
||
}
|
||
|
||
.el-menu-item, .el-submenu__title {
|
||
color: #fff;
|
||
height: 46px;
|
||
line-height: 46px;
|
||
}
|
||
|
||
.el-menu-item:hover, .el-submenu__title:hover {
|
||
background-color: rgba(0, 0, 0, 0.1) !important;
|
||
}
|
||
|
||
.el-menu-item.is-active {
|
||
background-color: rgba(0, 0, 0, 0.2) !important;
|
||
color: #409EFF !important;
|
||
}
|
||
|
||
.el-submenu .el-menu-item {
|
||
min-width: 0 !important;
|
||
padding-left: 50px !important;
|
||
background-color: #1f2d3d !important;
|
||
}
|
||
|
||
.el-submenu .el-menu-item:hover {
|
||
background-color: rgba(0, 0, 0, 0.1) !important;
|
||
}
|
||
|
||
.el-submenu__title {
|
||
padding-left: 20px !important;
|
||
}
|
||
|
||
.el-menu-item [class^=el-icon-], .el-submenu [class^=el-icon-] {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
/* 主内容区样式 */
|
||
.module-title {
|
||
margin-bottom: 20px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
}
|
||
|
||
.card-container {
|
||
background: #fff;
|
||
padding: 20px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
/* 表格操作按钮 */
|
||
.table-actions {
|
||
margin-bottom: 15px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
/* 分页样式 */
|
||
.pagination-container {
|
||
margin-top: 20px;
|
||
text-align: right;
|
||
}
|
||
|
||
/* 表单样式 */
|
||
.form-container {
|
||
max-width: 1100px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 768px) {
|
||
.sidebar {
|
||
position: fixed;
|
||
z-index: 1000;
|
||
height: 100vh;
|
||
}
|
||
|
||
.sidebar.collapsed + .main-content {
|
||
margin-left: 0;
|
||
}
|
||
|
||
.main-content {
|
||
margin-left: 220px;
|
||
}
|
||
|
||
.sidebar.collapsed {
|
||
width: 0;
|
||
overflow: hidden;
|
||
}
|
||
}
|
||
|
||
/* 新增样式 */
|
||
.file-link {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.file-link i {
|
||
margin-right: 5px;
|
||
}
|
||
.status-badge {
|
||
display: inline-block;
|
||
padding: 2px 8px;
|
||
border-radius: 10px;
|
||
font-size: 12px;
|
||
background-color: #f0f0f0;
|
||
}
|
||
.status-badge.preparing {
|
||
background-color: #fdf6ec;
|
||
color: #e6a23c;
|
||
}
|
||
.status-badge.bidding {
|
||
background-color: #ecf5ff;
|
||
color: #409eff;
|
||
}
|
||
.status-badge.won {
|
||
background-color: #f0f9eb;
|
||
color: #67c23a;
|
||
}
|
||
.status-badge.lost {
|
||
background-color: #fef0f0;
|
||
color: #f56c6c;
|
||
}
|
||
.file-actions {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
/* 进度详情样式 */
|
||
.progress-timeline {
|
||
margin-top: 20px;
|
||
}
|
||
.progress-step {
|
||
margin-bottom: 30px;
|
||
position: relative;
|
||
padding-left: 30px;
|
||
}
|
||
.progress-step:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
.progress-step::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 6px;
|
||
top: 0;
|
||
height: 100%;
|
||
width: 2px;
|
||
background-color: #e4e7ed;
|
||
}
|
||
.progress-step.active::before {
|
||
background-color: #409eff;
|
||
}
|
||
.progress-step.completed::before {
|
||
background-color: #67c23a;
|
||
}
|
||
.progress-step-icon {
|
||
position: absolute;
|
||
left: 0;
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 50%;
|
||
background-color: #e4e7ed;
|
||
z-index: 1;
|
||
}
|
||
.progress-step.active .progress-step-icon {
|
||
background-color: #409eff;
|
||
}
|
||
.progress-step.completed .progress-step-icon {
|
||
background-color: #67c23a;
|
||
}
|
||
.progress-step-title {
|
||
font-weight: bold;
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.progress-step-date {
|
||
color: #909399;
|
||
font-size: 12px;
|
||
margin-left: 10px;
|
||
}
|
||
.progress-step-content {
|
||
margin-left: 20px;
|
||
}
|
||
.progress-step-files {
|
||
margin-top: 10px;
|
||
}
|
||
.progress-step-file {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 5px;
|
||
}
|
||
.progress-step-file i {
|
||
margin-right: 5px;
|
||
color: #409eff;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="app" class="app-container">
|
||
<!-- 侧边栏导航 -->
|
||
<div class="sidebar" :class="{collapsed: isCollapse}">
|
||
<div class="logo">
|
||
<h2>项目管理</h2>
|
||
<div class="toggle-sidebar" @click="toggleSidebar">
|
||
<i :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"></i>
|
||
</div>
|
||
</div>
|
||
|
||
<el-menu
|
||
:default-active="activeModule"
|
||
class="el-menu-vertical"
|
||
:collapse="isCollapse"
|
||
:collapse-transition="false"
|
||
background-color="#304156"
|
||
text-color="#fff"
|
||
active-text-color="#409EFF"
|
||
>
|
||
<!-- 市场商务管理 -->
|
||
<el-submenu index="market">
|
||
<template slot="title">
|
||
<i class="el-icon-shopping-bag-1"></i>
|
||
<span>市场商务管理</span>
|
||
</template>
|
||
|
||
<!-- 项目来源 -->
|
||
<el-submenu index="project-source">
|
||
<template slot="title">项目来源</template>
|
||
|
||
<!-- 招采业务 -->
|
||
<el-menu-item index="bidding" @click="switchModule('bidding')">招采业务</el-menu-item>
|
||
</el-submenu>
|
||
</el-submenu>
|
||
</el-menu>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content">
|
||
<!-- 招采业务 -->
|
||
<div v-if="activeModule === 'bidding'">
|
||
<h2 class="module-title">招采业务</h2>
|
||
|
||
<div class="card-container">
|
||
<el-tabs v-model="biddingTab" type="card">
|
||
<el-tab-pane label="信息检索" name="search">
|
||
<div class="table-actions">
|
||
<el-input
|
||
placeholder="搜索招标项目"
|
||
v-model="biddingSearch.keyword"
|
||
clearable
|
||
style="width: 300px;"
|
||
@keyup.enter.native="searchBiddingInfo"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search" @click="searchBiddingInfo"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-video-play" @click="startCrawler">开始爬虫</el-button>
|
||
<el-button type="primary" icon="el-icon-refresh" @click="refreshBiddingData">刷新数据</el-button>
|
||
<el-button type="success" icon="el-icon-download" @click="exportBiddingData">导出数据</el-button>
|
||
<el-button type="warning" icon="el-icon-setting" @click="showCrawlerSettings">爬虫设置</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="biddingData" border style="width: 100%">
|
||
<el-table-column prop="title" label="招标项目" width="300"></el-table-column>
|
||
<el-table-column prop="publisher" label="招标单位" width="180"></el-table-column>
|
||
<el-table-column prop="budget" label="预算金额" width="120" align="right"></el-table-column>
|
||
<el-table-column prop="deadline" label="截止时间" width="180"></el-table-column>
|
||
<el-table-column prop="crawlTime" label="爬取时间" width="180"></el-table-column>
|
||
<el-table-column prop="source" label="来源平台" width="120">
|
||
<template slot-scope="scope">
|
||
<el-link type="primary" :href="scope.row.sourceUrl" target="_blank" v-if="scope.row.sourceUrl">{{ scope.row.source }}</el-link>
|
||
<span v-else>{{ scope.row.source }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="documents" label="招标文件" width="150">
|
||
<template slot-scope="scope">
|
||
<div v-if="scope.row.documents && scope.row.documents.length > 0" class="file-actions">
|
||
<el-tag v-for="doc in scope.row.documents" :key="doc.name" size="mini" style="margin-right: 5px;">
|
||
<el-link :href="doc.url" target="_blank">{{ doc.name }}</el-link>
|
||
</el-tag>
|
||
</div>
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="(file, fileList) => handleBiddingFileUpload(file, fileList, scope.row)"
|
||
:auto-upload="false"
|
||
:show-file-list="false"
|
||
>
|
||
<el-button size="mini" type="text">上传文件</el-button>
|
||
</el-upload>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="status" label="状态" width="120">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '待报名' ? 'warning' : 'success'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="180">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewBiddingDetail(scope.row)">详情</el-button>
|
||
<el-button size="mini" type="primary" @click="markAsRegistered(scope.row)"
|
||
:disabled="scope.row.status === '已报名'">{{ scope.row.status === '已报名' ? '已报名' : '报名' }}</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
@size-change="handleBiddingSizeChange"
|
||
@current-change="handleBiddingCurrentChange"
|
||
:current-page="biddingSearch.page"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="biddingSearch.limit"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="biddingTotal">
|
||
</el-pagination>
|
||
</div>
|
||
|
||
<!-- 招标详情对话框 -->
|
||
<el-dialog title="招标详情" :visible.sync="biddingDetailVisible" width="70%">
|
||
<div v-if="currentBidding">
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="项目名称">{{ currentBidding.title }}</el-descriptions-item>
|
||
<el-descriptions-item label="招标单位">{{ currentBidding.publisher }}</el-descriptions-item>
|
||
<el-descriptions-item label="预算金额">{{ currentBidding.budget }}</el-descriptions-item>
|
||
<el-descriptions-item label="截止时间">{{ currentBidding.deadline }}</el-descriptions-item>
|
||
<el-descriptions-item label="爬取时间">{{ currentBidding.crawlTime }}</el-descriptions-item>
|
||
<el-descriptions-item label="项目地点">{{ currentBidding.location }}</el-descriptions-item>
|
||
<el-descriptions-item label="项目周期">{{ currentBidding.duration }}</el-descriptions-item>
|
||
<el-descriptions-item label="招标范围" :span="2">{{ currentBidding.scope }}</el-descriptions-item>
|
||
<el-descriptions-item label="资质要求" :span="2">{{ currentBidding.qualification }}</el-descriptions-item>
|
||
<el-descriptions-item label="来源平台" :span="2">
|
||
<el-link type="primary" :href="currentBidding.sourceUrl" target="_blank">{{ currentBidding.source }}</el-link>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="招标文件" :span="2">
|
||
<div v-if="currentBidding.documents && currentBidding.documents.length > 0" class="file-actions">
|
||
<div v-for="doc in currentBidding.documents" :key="doc.name" class="file-link">
|
||
<i class="el-icon-document"></i>
|
||
<el-link :href="doc.url" target="_blank">{{ doc.name }}</el-link>
|
||
</div>
|
||
</div>
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="(file, fileList) => handleBiddingFileUpload(file, fileList, currentBidding)"
|
||
:auto-upload="false"
|
||
:show-file-list="false"
|
||
>
|
||
<el-button size="mini" type="primary">上传招标文件</el-button>
|
||
</el-upload>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<div style="margin-top: 20px;">
|
||
<h3>招标内容</h3>
|
||
<div v-html="currentBidding.content" style="border: 1px solid #ebeef5; padding: 10px; border-radius: 4px;"></div>
|
||
</div>
|
||
</div>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="biddingDetailVisible = false">关闭</el-button>
|
||
<el-button type="primary" @click="goToBiddingResponse">投标响应</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 爬虫设置对话框 -->
|
||
<el-dialog title="爬虫设置" :visible.sync="crawlerSettingsVisible" width="50%">
|
||
<el-form :model="crawlerSettings" label-width="120px">
|
||
<el-form-item label="爬取频率">
|
||
<el-select v-model="crawlerSettings.frequency" style="width: 200px;">
|
||
<el-option label="每小时" value="hourly"></el-option>
|
||
<el-option label="每天" value="daily"></el-option>
|
||
<el-option label="每周" value="weekly"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="关键词过滤">
|
||
<el-tag
|
||
v-for="tag in crawlerSettings.keywords"
|
||
:key="tag"
|
||
closable
|
||
@close="removeKeyword(tag)"
|
||
style="margin-right: 10px;"
|
||
>
|
||
{{ tag }}
|
||
</el-tag>
|
||
<el-input
|
||
v-model="newKeyword"
|
||
size="small"
|
||
style="width: 150px;"
|
||
@keyup.enter.native="addKeyword"
|
||
>
|
||
<el-button slot="append" icon="el-icon-plus" @click="addKeyword"></el-button>
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="来源平台">
|
||
<el-checkbox-group v-model="crawlerSettings.platforms">
|
||
<el-checkbox label="中国招标投标公共服务平台"></el-checkbox>
|
||
<el-checkbox label="各省市公共资源交易中心"></el-checkbox>
|
||
<el-checkbox label="企业自有招标平台"></el-checkbox>
|
||
<el-checkbox label="其他第三方平台"></el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="自动通知">
|
||
<el-switch v-model="crawlerSettings.autoNotify"></el-switch>
|
||
<span style="margin-left: 10px;">{{ crawlerSettings.autoNotify ? '已开启' : '已关闭' }}</span>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="通知方式" v-if="crawlerSettings.autoNotify">
|
||
<el-checkbox-group v-model="crawlerSettings.notifyMethods">
|
||
<el-checkbox label="站内消息"></el-checkbox>
|
||
<el-checkbox label="电子邮件"></el-checkbox>
|
||
<el-checkbox label="手机短信"></el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="crawlerSettingsVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="saveCrawlerSettings">保存设置</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="投标响应" name="response">
|
||
<el-tabs v-model="biddingResponseTab">
|
||
<el-tab-pane label="投标项目" name="projects">
|
||
<div class="table-actions">
|
||
<el-input
|
||
placeholder="搜索投标项目"
|
||
v-model="biddingResponseSearch.keyword"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search" @click="searchBiddingResponse"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-plus" @click="showNewBiddingDialog">新建投标</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshBiddingResponse">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="biddingResponseData" border style="width: 100%">
|
||
<el-table-column prop="projectName" label="项目名称" width="250"></el-table-column>
|
||
<el-table-column prop="publisher" label="招标单位" width="200"></el-table-column>
|
||
<el-table-column prop="budget" label="预算金额" width="200" align="right"></el-table-column>
|
||
<el-table-column prop="deadline" label="截止时间" width="200"></el-table-column>
|
||
<el-table-column prop="status" label="投标状态" width="200">
|
||
<template slot-scope="scope">
|
||
<span :class="['status-badge',
|
||
scope.row.status === '准备中' ? 'preparing' :
|
||
scope.row.status === '已投标' ? 'bidding' :
|
||
scope.row.status === '已中标' ? 'won' : 'lost']">
|
||
{{ scope.row.status }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="progress" label="进度" width="150">
|
||
<template slot-scope="scope">
|
||
<el-progress :percentage="scope.row.progress" :status="scope.row.status === '已中标' ? 'success' : ''"></el-progress>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="370">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewBiddingResponse(scope.row)">详情</el-button>
|
||
<el-button size="mini" type="primary" @click="editBiddingResponse(scope.row)"
|
||
:disabled="scope.row.status === '已中标' || scope.row.status === '已投标'">编辑</el-button>
|
||
<el-button size="mini" type="success" @click="uploadBiddingDocument(scope.row)">上传文件</el-button>
|
||
<el-button size="mini" type="warning" @click="updateBiddingStatus(scope.row)"
|
||
v-if="scope.row.status === '准备中'">提交投标</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
@size-change="handleBiddingResponseSizeChange"
|
||
@current-change="handleBiddingResponseCurrentChange"
|
||
:current-page="biddingResponseSearch.page"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="biddingResponseSearch.limit"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="biddingResponseTotal">
|
||
</el-pagination>
|
||
</div>
|
||
|
||
<!-- 投标项目详情对话框 -->
|
||
<el-dialog :title="`投标项目详情 - ${currentBiddingResponse.projectName}`" :visible.sync="biddingResponseDetailVisible" width="60%">
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="项目名称">{{ currentBiddingResponse.projectName }}</el-descriptions-item>
|
||
<el-descriptions-item label="招标单位">{{ currentBiddingResponse.publisher }}</el-descriptions-item>
|
||
<el-descriptions-item label="预算金额">{{ currentBiddingResponse.budget }}</el-descriptions-item>
|
||
<el-descriptions-item label="截止时间">{{ currentBiddingResponse.deadline }}</el-descriptions-item>
|
||
<el-descriptions-item label="项目地点">{{ currentBiddingResponse.location }}</el-descriptions-item>
|
||
<el-descriptions-item label="项目类型">{{ currentBiddingResponse.projectType }}</el-descriptions-item>
|
||
<el-descriptions-item label="投标状态">{{ currentBiddingResponse.status }}</el-descriptions-item>
|
||
<el-descriptions-item label="投标进度">
|
||
<el-progress :percentage="currentBiddingResponse.progress" :status="currentBiddingResponse.status === '已中标' ? 'success' : ''"></el-progress>
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="投标负责人">{{ currentBiddingResponse.manager }}</el-descriptions-item>
|
||
<el-descriptions-item label="联系电话">{{ currentBiddingResponse.phone }}</el-descriptions-item>
|
||
<el-descriptions-item label="项目描述" :span="2">{{ currentBiddingResponse.description }}</el-descriptions-item>
|
||
<el-descriptions-item label="招标文件" :span="2">
|
||
<div v-if="currentBiddingResponse.biddingDocuments && currentBiddingResponse.biddingDocuments.length > 0">
|
||
<div v-for="doc in currentBiddingResponse.biddingDocuments" :key="doc.name" class="file-actions">
|
||
<div class="file-link">
|
||
<i class="el-icon-document"></i>
|
||
<el-link :href="doc.url" target="_blank">{{ doc.name }}</el-link>
|
||
</div>
|
||
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="deleteBiddingResponseFile(currentBiddingResponse, doc)"></el-button>
|
||
</div>
|
||
</div>
|
||
<div v-else style="color: #909399;">暂无招标文件</div>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="biddingResponseDetailVisible = false">关闭</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 上传投标文件对话框 -->
|
||
<el-dialog title="上传投标文件" :visible.sync="uploadDocumentDialogVisible" width="50%">
|
||
<el-form :model="uploadDocumentForm" label-width="100px">
|
||
<el-form-item label="文件类型">
|
||
<el-radio-group v-model="uploadDocumentForm.type">
|
||
<el-radio label="商务标书">商务标书</el-radio>
|
||
<el-radio label="报价文件">报价文件</el-radio>
|
||
<el-radio label="其他文件">其他文件</el-radio>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleDocumentUpload"
|
||
:auto-upload="false"
|
||
:file-list="documentFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传投标相关文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="uploadDocumentDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitDocumentUpload">确定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑投标项目对话框 -->
|
||
<el-dialog title="编辑投标项目" :visible.sync="editBiddingDialogVisible" width="50%">
|
||
<el-form :model="editBiddingForm" :rules="biddingRules" ref="editBiddingForm" label-width="120px">
|
||
<el-form-item label="项目名称" prop="projectName">
|
||
<el-input v-model="editBiddingForm.projectName"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="招标单位" prop="publisher">
|
||
<el-input v-model="editBiddingForm.publisher"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="预算金额" prop="budget">
|
||
<el-input v-model="editBiddingForm.budget" style="width: 200px;">
|
||
<template slot="append">万元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="截止时间" prop="deadline">
|
||
<el-date-picker
|
||
v-model="editBiddingForm.deadline"
|
||
type="datetime"
|
||
placeholder="选择日期时间"
|
||
value-format="yyyy-MM-dd HH:mm:ss">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目地点" prop="location">
|
||
<el-cascader
|
||
v-model="editBiddingForm.location"
|
||
:options="locationOptions"
|
||
style="width: 100%;"
|
||
></el-cascader>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目类型" prop="projectType">
|
||
<el-select v-model="editBiddingForm.projectType" style="width: 100%;">
|
||
<el-option label="风电叶片检查" value="wind-power"></el-option>
|
||
<el-option label="风电运维" value="maintenance"></el-option>
|
||
<el-option label="风电安装" value="installation"></el-option>
|
||
<el-option label="其他" value="other"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="投标负责人" prop="manager">
|
||
<el-input v-model="editBiddingForm.manager"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="联系电话" prop="phone">
|
||
<el-input v-model="editBiddingForm.phone"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目描述" prop="description">
|
||
<el-input type="textarea" v-model="editBiddingForm.description" :rows="3"></el-input>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="editBiddingDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitEditBidding">保存</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="商务标书" name="documents">
|
||
<div class="table-actions">
|
||
<el-input
|
||
placeholder="搜索标书"
|
||
v-model="documentSearch.keyword"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search" @click="searchDocuments"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-plus" @click="showNewDocumentDialog">新建标书</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshDocuments">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="documentData" border style="width: 100%">
|
||
<el-table-column prop="name" label="标书名称" width="280"></el-table-column>
|
||
<el-table-column prop="project" label="关联项目" width="280"></el-table-column>
|
||
<el-table-column prop="type" label="标书类型" width="300">
|
||
<template slot-scope="scope">
|
||
<el-tag>{{ scope.row.type }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="status" label="状态" width="300">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '已完成' ? 'success' : 'warning'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="400">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewDocument(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editDocument(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteDocument(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
@size-change="handleDocumentSizeChange"
|
||
@current-change="handleDocumentCurrentChange"
|
||
:current-page="documentSearch.page"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="documentSearch.limit"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="documentTotal">
|
||
</el-pagination>
|
||
</div>
|
||
|
||
<!-- 新建商务标书对话框 -->
|
||
<el-dialog title="新建商务标书" :visible.sync="newDocumentDialogVisible" width="50%">
|
||
<el-form :model="newDocumentForm" :rules="documentRules" ref="newDocumentForm" label-width="100px">
|
||
<el-form-item label="标书名称" prop="name">
|
||
<el-input v-model="newDocumentForm.name"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="newDocumentForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="标书类型" prop="type">
|
||
<el-select v-model="newDocumentForm.type" placeholder="请选择标书类型" style="width: 100%;">
|
||
<el-option label="商务标书" value="商务标书"></el-option>
|
||
<el-option label="技术标书" value="技术标书"></el-option>
|
||
<el-option label="其他" value="其他"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleNewDocumentUpload"
|
||
:auto-upload="false"
|
||
:file-list="newDocumentFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传标书文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="newDocumentDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitNewDocument">确定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑商务标书对话框 -->
|
||
<el-dialog title="编辑商务标书" :visible.sync="editDocumentDialogVisible" width="50%">
|
||
<el-form :model="editDocumentForm" :rules="documentRules" ref="editDocumentForm" label-width="100px">
|
||
<el-form-item label="标书名称" prop="name">
|
||
<el-input v-model="editDocumentForm.name"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="editDocumentForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="标书类型" prop="type">
|
||
<el-select v-model="editDocumentForm.type" placeholder="请选择标书类型" style="width: 100%;">
|
||
<el-option label="商务标书" value="商务标书"></el-option>
|
||
<el-option label="技术标书" value="技术标书"></el-option>
|
||
<el-option label="其他" value="其他"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleEditDocumentUpload"
|
||
:auto-upload="false"
|
||
:file-list="editDocumentFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传标书文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="editDocumentDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitEditDocument">保存</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="报价文件" name="quotations">
|
||
<div class="table-actions">
|
||
<el-input
|
||
placeholder="搜索报价文件"
|
||
v-model="quotationSearch.keyword"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search" @click="searchQuotations"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-plus" @click="showNewQuotationDialog">新建报价</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshQuotations">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="quotationData" border style="width: 100%">
|
||
<el-table-column prop="name" label="报价文件" width="250"></el-table-column>
|
||
<el-table-column prop="project" label="关联项目" width="250"></el-table-column>
|
||
<el-table-column prop="totalPrice" label="总报价" width="240" align="right"></el-table-column>
|
||
<el-table-column prop="profitRate" label="利润率" width="240">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.profitRate >= 20 ? 'success' : scope.row.profitRate >= 10 ? 'warning' : 'danger'">
|
||
{{ scope.row.profitRate }}%
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="status" label="状态" width="240">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '已完成' ? 'success' : 'warning'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="360">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewQuotation(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editQuotation(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteQuotation(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
@size-change="handleQuotationSizeChange"
|
||
@current-change="handleQuotationCurrentChange"
|
||
:current-page="quotationSearch.page"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="quotationSearch.limit"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="quotationTotal">
|
||
</el-pagination>
|
||
</div>
|
||
|
||
<!-- 新建报价对话框 -->
|
||
<el-dialog title="新建报价文件" :visible.sync="newQuotationDialogVisible" width="50%">
|
||
<el-form :model="newQuotationForm" :rules="quotationRules" ref="newQuotationForm" label-width="100px">
|
||
<el-form-item label="报价名称" prop="name">
|
||
<el-input v-model="newQuotationForm.name"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="newQuotationForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="总报价" prop="totalPrice">
|
||
<el-input v-model="newQuotationForm.totalPrice" style="width: 200px;">
|
||
<template slot="append">元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="利润率" prop="profitRate">
|
||
<el-input v-model="newQuotationForm.profitRate" style="width: 200px;">
|
||
<template slot="append">%</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="报价说明" prop="description">
|
||
<el-input type="textarea" v-model="newQuotationForm.description" :rows="3"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleNewQuotationUpload"
|
||
:auto-upload="false"
|
||
:file-list="newQuotationFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传报价相关文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="newQuotationDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitNewQuotation">确定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑报价对话框 -->
|
||
<el-dialog title="编辑报价文件" :visible.sync="editQuotationDialogVisible" width="50%">
|
||
<el-form :model="editQuotationForm" :rules="quotationRules" ref="editQuotationForm" label-width="100px">
|
||
<el-form-item label="报价名称" prop="name">
|
||
<el-input v-model="editQuotationForm.name"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="editQuotationForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="总报价" prop="totalPrice">
|
||
<el-input v-model="editQuotationForm.totalPrice" style="width: 200px;">
|
||
<template slot="append">元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="利润率" prop="profitRate">
|
||
<el-input v-model="editQuotationForm.profitRate" style="width: 200px;">
|
||
<template slot="append">%</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="报价说明" prop="description">
|
||
<el-input type="textarea" v-model="editQuotationForm.description" :rows="3"></el-input>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleEditQuotationUpload"
|
||
:auto-upload="false"
|
||
:file-list="editQuotationFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传报价相关文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="editQuotationDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitEditQuotation">保存</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
|
||
<el-tab-pane label="中标通知" name="notices">
|
||
<div class="table-actions">
|
||
<el-input
|
||
placeholder="搜索中标通知"
|
||
v-model="noticeSearch.keyword"
|
||
clearable
|
||
style="width: 300px;"
|
||
>
|
||
<el-button slot="append" icon="el-icon-search" @click="searchNotices"></el-button>
|
||
</el-input>
|
||
|
||
<div>
|
||
<el-button type="primary" icon="el-icon-plus" @click="showNewNoticeDialog">新建通知</el-button>
|
||
<el-button icon="el-icon-refresh" @click="refreshNotices">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="noticeData" border style="width: 100%">
|
||
<el-table-column prop="projectName" label="项目名称" width="250"></el-table-column>
|
||
<el-table-column prop="publisher" label="招标单位" width="250"></el-table-column>
|
||
<el-table-column prop="winningPrice" label="中标金额" width="240" align="right"></el-table-column>
|
||
<el-table-column prop="noticeDate" label="通知日期" width="240"></el-table-column>
|
||
<el-table-column prop="status" label="状态" width="240">
|
||
<template slot-scope="scope">
|
||
<el-tag :type="scope.row.status === '已签约' ? 'success' :
|
||
scope.row.status === '已确认' ? 'primary' : 'warning'">
|
||
{{ scope.row.status }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="350">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" @click="viewNotice(scope.row)">查看</el-button>
|
||
<el-button size="mini" type="primary" @click="editNotice(scope.row)">编辑</el-button>
|
||
<el-button size="mini" type="danger" @click="deleteNotice(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="pagination-container">
|
||
<el-pagination
|
||
@size-change="handleNoticeSizeChange"
|
||
@current-change="handleNoticeCurrentChange"
|
||
:current-page="noticeSearch.page"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:page-size="noticeSearch.limit"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="noticeTotal">
|
||
</el-pagination>
|
||
</div>
|
||
|
||
<!-- 新建中标通知对话框 -->
|
||
<el-dialog title="新建中标通知" :visible.sync="newNoticeDialogVisible" width="50%">
|
||
<el-form :model="newNoticeForm" :rules="noticeRules" ref="newNoticeForm" label-width="100px">
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="newNoticeForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="中标金额" prop="winningPrice">
|
||
<el-input v-model="newNoticeForm.winningPrice" style="width: 200px;">
|
||
<template slot="append">元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="通知日期" prop="noticeDate">
|
||
<el-date-picker
|
||
v-model="newNoticeForm.noticeDate"
|
||
type="date"
|
||
placeholder="选择日期"
|
||
value-format="yyyy-MM-dd"
|
||
style="width: 100%;">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item label="状态" prop="status">
|
||
<el-select v-model="newNoticeForm.status" placeholder="请选择状态" style="width: 100%;">
|
||
<el-option label="已确认" value="已确认"></el-option>
|
||
<el-option label="已签约" value="已签约"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleNewNoticeUpload"
|
||
:auto-upload="false"
|
||
:file-list="newNoticeFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传中标通知书等相关文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="newNoticeDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitNewNotice">确定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
<!-- 编辑中标通知对话框 -->
|
||
<el-dialog title="编辑中标通知" :visible.sync="editNoticeDialogVisible" width="50%">
|
||
<el-form :model="editNoticeForm" :rules="noticeRules" ref="editNoticeForm" label-width="100px">
|
||
<el-form-item label="关联项目" prop="project">
|
||
<el-select v-model="editNoticeForm.project" placeholder="请选择关联项目" style="width: 100%;">
|
||
<el-option
|
||
v-for="item in biddingResponseData"
|
||
:key="item.id"
|
||
:label="item.projectName"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="中标金额" prop="winningPrice">
|
||
<el-input v-model="editNoticeForm.winningPrice" style="width: 200px;">
|
||
<template slot="append">元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="通知日期" prop="noticeDate">
|
||
<el-date-picker
|
||
v-model="editNoticeForm.noticeDate"
|
||
type="date"
|
||
placeholder="选择日期"
|
||
value-format="yyyy-MM-dd"
|
||
style="width: 100%;">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
<el-form-item label="状态" prop="status">
|
||
<el-select v-model="editNoticeForm.status" placeholder="请选择状态" style="width: 100%;">
|
||
<el-option label="已确认" value="已确认"></el-option>
|
||
<el-option label="已签约" value="已签约"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="上传文件" prop="files">
|
||
<el-upload
|
||
class="upload-demo"
|
||
action=""
|
||
:on-change="handleEditNoticeUpload"
|
||
:auto-upload="false"
|
||
:file-list="editNoticeFileList"
|
||
>
|
||
<el-button size="small" type="primary">点击上传</el-button>
|
||
<div slot="tip" class="el-upload__tip">请上传中标通知书等相关文件</div>
|
||
</el-upload>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="editNoticeDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitEditNotice">保存</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
|
||
<!-- 新建投标对话框 -->
|
||
<el-dialog title="新建投标项目" :visible.sync="newBiddingDialogVisible" width="50%">
|
||
<el-form :model="newBiddingForm" :rules="biddingRules" ref="newBiddingForm" label-width="120px">
|
||
<el-form-item label="关联招标项目" prop="biddingProject">
|
||
<el-select
|
||
v-model="newBiddingForm.biddingProject"
|
||
filterable
|
||
placeholder="请选择关注的招标项目"
|
||
style="width: 100%;"
|
||
@change="handleBiddingProjectChange"
|
||
>
|
||
<el-option
|
||
v-for="item in interestedBiddingProjects"
|
||
:key="item.id"
|
||
:label="`${item.title} - ${item.publisher}`"
|
||
:value="item.id">
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目名称" prop="projectName">
|
||
<el-input v-model="newBiddingForm.projectName"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="招标单位" prop="publisher">
|
||
<el-input v-model="newBiddingForm.publisher"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="预算金额" prop="budget">
|
||
<el-input v-model="newBiddingForm.budget" style="width: 200px;">
|
||
<template slot="append">万元</template>
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="截止时间" prop="deadline">
|
||
<el-date-picker
|
||
v-model="newBiddingForm.deadline"
|
||
type="datetime"
|
||
placeholder="选择日期时间"
|
||
value-format="yyyy-MM-dd HH:mm:ss">
|
||
</el-date-picker>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目地点" prop="location">
|
||
<el-cascader
|
||
v-model="newBiddingForm.location"
|
||
:options="locationOptions"
|
||
style="width: 100%;"
|
||
></el-cascader>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目类型" prop="projectType">
|
||
<el-select v-model="newBiddingForm.projectType" style="width: 100%;">
|
||
<el-option label="风电叶片检查" value="wind-power"></el-option>
|
||
<el-option label="风电运维" value="maintenance"></el-option>
|
||
<el-option label="风电安装" value="installation"></el-option>
|
||
<el-option label="其他" value="other"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="招标文件" prop="documents">
|
||
<div v-if="newBiddingForm.documents && newBiddingForm.documents.length > 0">
|
||
<div v-for="doc in newBiddingForm.documents" :key="doc.name" class="file-link">
|
||
<i class="el-icon-document"></i>
|
||
<el-link :href="doc.url" target="_blank">{{ doc.name }}</el-link>
|
||
</div>
|
||
</div>
|
||
<div v-else style="color: #909399;">暂无招标文件</div>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="投标负责人" prop="manager">
|
||
<el-input v-model="newBiddingForm.manager"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="联系电话" prop="phone">
|
||
<el-input v-model="newBiddingForm.phone"></el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="项目描述" prop="description">
|
||
<el-input type="textarea" v-model="newBiddingForm.description" :rows="3"></el-input>
|
||
</el-form-item>
|
||
</el-form>
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="newBiddingDialogVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="submitNewBidding">确定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
new Vue({
|
||
el: '#app',
|
||
data() {
|
||
return {
|
||
isCollapse: false,
|
||
activeModule: 'bidding',
|
||
|
||
// 招采业务
|
||
biddingTab: 'search',
|
||
biddingSearch: {
|
||
keyword: '',
|
||
page: 1,
|
||
limit: 10
|
||
},
|
||
biddingData: [
|
||
{
|
||
id: 1,
|
||
title: '某风电场2023年叶片检查服务采购项目',
|
||
publisher: '某风电有限公司',
|
||
budget: '120.00万元',
|
||
deadline: '2023-12-15 17:00',
|
||
crawlTime: '2023-11-01 09:30',
|
||
source: '中国招标投标网',
|
||
sourceUrl: 'https://www.cebpubservice.com/',
|
||
status: '待报名',
|
||
location: '内蒙古自治区',
|
||
duration: '6个月',
|
||
scope: '风电场50台机组叶片检查服务',
|
||
qualification: '具备风电叶片检查资质',
|
||
documents: [
|
||
{ name: '招标文件.pdf', url: 'https://example.com/bidding-docs/123' },
|
||
{ name: '技术规范.docx', url: 'https://example.com/bidding-docs/124' }
|
||
],
|
||
content: '<p>本项目为某风电场2023年叶片检查服务采购,包括但不限于:</p><ul><li>叶片外观检查</li><li>无损检测</li><li>缺陷记录与评估</li><li>检查报告编制</li></ul>',
|
||
interested: false
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '某风电场2023年运维服务采购项目',
|
||
publisher: '某新能源集团',
|
||
budget: '200.00万元',
|
||
deadline: '2023-12-20 17:00',
|
||
crawlTime: '2023-11-02 10:15',
|
||
source: '某省公共资源交易中心',
|
||
sourceUrl: 'https://www.example-province.gov.cn/',
|
||
status: '已报名',
|
||
location: '河北省',
|
||
duration: '1年',
|
||
scope: '风电场全年运维服务',
|
||
qualification: '具备风电运维资质',
|
||
documents: [],
|
||
content: '<p>本项目为某风电场2023年全年运维服务采购,包括但不限于:</p><ul><li>日常巡检</li><li>定期维护</li><li>故障处理</li><li>数据记录</li></ul>',
|
||
interested: true
|
||
}
|
||
],
|
||
biddingTotal: 20,
|
||
currentBidding: null,
|
||
biddingDetailVisible: false,
|
||
crawlerSettingsVisible: false,
|
||
crawlerSettings: {
|
||
frequency: 'daily',
|
||
keywords: ['风电', '叶片', '检查', '运维'],
|
||
platforms: ['中国招标投标公共服务平台', '各省市公共资源交易中心'],
|
||
autoNotify: true,
|
||
notifyMethods: ['站内消息', '电子邮件']
|
||
},
|
||
newKeyword: '',
|
||
|
||
// 投标响应
|
||
biddingResponseTab: 'projects',
|
||
biddingResponseSearch: {
|
||
keyword: '',
|
||
page: 1,
|
||
limit: 10
|
||
},
|
||
biddingResponseData: [
|
||
{
|
||
id: 1,
|
||
biddingId: 1,
|
||
projectName: '某风电场2023年叶片检查服务采购项目',
|
||
publisher: '某风电有限公司',
|
||
budget: '120.00万元',
|
||
deadline: '2023-12-15 17:00',
|
||
location: '内蒙古自治区',
|
||
projectType: '风电叶片检查',
|
||
manager: '张经理',
|
||
phone: '13800138000',
|
||
description: '为某风电场提供叶片检查服务',
|
||
status: '准备中',
|
||
progress: 30,
|
||
biddingDocuments: [
|
||
{ name: '招标文件.pdf', url: 'https://example.com/bidding-docs/123' },
|
||
{ name: '技术规范.docx', url: 'https://example.com/bidding-docs/124' }
|
||
],
|
||
documents: [
|
||
{ name: '技术标书.docx', type: '商务标书', status: '已完成', url: 'https://example.com/documents/123' },
|
||
{ name: '商务标书.docx', type: '商务标书', status: '已完成', url: 'https://example.com/documents/124' }
|
||
],
|
||
quotation: {
|
||
name: '某风电场叶片检查报价单',
|
||
totalPrice: '1,080,000.00',
|
||
profitRate: 15,
|
||
status: '已完成',
|
||
description: '基于市场价格和公司成本核算的报价',
|
||
files: [
|
||
{ name: '报价单.xlsx', url: 'https://example.com/quotations/123' }
|
||
]
|
||
},
|
||
notice: null,
|
||
progressSteps: [
|
||
{
|
||
title: '项目立项',
|
||
description: '项目立项并分配负责人',
|
||
date: '2023-11-01',
|
||
status: 'completed',
|
||
files: []
|
||
},
|
||
{
|
||
title: '招标文件分析',
|
||
description: '完成招标文件分析和技术要求评估',
|
||
date: '2023-11-05',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '招标分析报告.docx', url: 'https://example.com/progress/123' }
|
||
]
|
||
},
|
||
{
|
||
title: '技术标书编制',
|
||
description: '技术标书编制完成',
|
||
date: '2023-11-10',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '技术标书.docx', url: 'https://example.com/documents/123' }
|
||
]
|
||
},
|
||
{
|
||
title: '商务标书编制',
|
||
description: '商务标书编制完成',
|
||
date: '2023-11-15',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '商务标书.docx', url: 'https://example.com/documents/124' }
|
||
]
|
||
},
|
||
{
|
||
title: '报价文件准备',
|
||
description: '正在准备报价文件',
|
||
date: '',
|
||
status: 'active',
|
||
files: []
|
||
},
|
||
{
|
||
title: '投标文件审核',
|
||
description: '等待投标文件审核',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '提交投标',
|
||
description: '提交投标文件',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
}
|
||
]
|
||
},
|
||
{
|
||
id: 2,
|
||
biddingId: 3,
|
||
projectName: '某风电场2022年运维服务项目',
|
||
publisher: '某新能源公司',
|
||
budget: '180.00万元',
|
||
deadline: '2022-11-30 17:00',
|
||
location: '甘肃省',
|
||
projectType: '风电运维',
|
||
manager: '李经理',
|
||
phone: '13900139000',
|
||
description: '为某风电场提供全年运维服务',
|
||
status: '已中标',
|
||
progress: 100,
|
||
biddingDocuments: [
|
||
{ name: '招标文件.pdf', url: 'https://example.com/bidding-docs/125' }
|
||
],
|
||
documents: [
|
||
{ name: '技术标书.docx', type: '商务标书', status: '已完成', url: 'https://example.com/documents/125' },
|
||
{ name: '商务标书.docx', type: '商务标书', status: '已完成', url: 'https://example.com/documents/126' }
|
||
],
|
||
quotation: {
|
||
name: '某风电场运维服务报价单',
|
||
totalPrice: '1,620,000.00',
|
||
profitRate: 12,
|
||
status: '已完成',
|
||
description: '综合考虑运维成本和市场竞争的报价',
|
||
files: [
|
||
{ name: '报价单.xlsx', url: 'https://example.com/quotations/124' }
|
||
]
|
||
},
|
||
notice: {
|
||
name: '某风电场2022年运维服务中标通知',
|
||
winningPrice: '1,620,000.00',
|
||
noticeDate: '2022-12-05',
|
||
status: '已签约',
|
||
files: [
|
||
{ name: '中标通知书.pdf', url: 'https://example.com/notices/123' }
|
||
]
|
||
},
|
||
progressSteps: [
|
||
{
|
||
title: '项目立项',
|
||
description: '项目立项并分配负责人',
|
||
date: '2022-10-01',
|
||
status: 'completed',
|
||
files: []
|
||
},
|
||
{
|
||
title: '招标文件分析',
|
||
description: '完成招标文件分析和技术要求评估',
|
||
date: '2022-10-05',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '招标分析报告.docx', url: 'https://example.com/progress/125' }
|
||
]
|
||
},
|
||
{
|
||
title: '技术标书编制',
|
||
description: '技术标书编制完成',
|
||
date: '2022-10-15',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '技术标书.docx', url: 'https://example.com/documents/125' }
|
||
]
|
||
},
|
||
{
|
||
title: '商务标书编制',
|
||
description: '商务标书编制完成',
|
||
date: '2022-10-20',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '商务标书.docx', url: 'https://example.com/documents/126' }
|
||
]
|
||
},
|
||
{
|
||
title: '报价文件准备',
|
||
description: '报价文件准备完成',
|
||
date: '2022-10-25',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '报价单.xlsx', url: 'https://example.com/quotations/124' }
|
||
]
|
||
},
|
||
{
|
||
title: '投标文件审核',
|
||
description: '投标文件审核通过',
|
||
date: '2022-10-28',
|
||
status: 'completed',
|
||
files: []
|
||
},
|
||
{
|
||
title: '提交投标',
|
||
description: '投标文件已提交',
|
||
date: '2022-10-30',
|
||
status: 'completed',
|
||
files: []
|
||
},
|
||
{
|
||
title: '中标通知',
|
||
description: '收到中标通知书',
|
||
date: '2022-12-05',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '中标通知书.pdf', url: 'https://example.com/notices/123' }
|
||
]
|
||
},
|
||
{
|
||
title: '合同签订',
|
||
description: '合同已签订',
|
||
date: '2022-12-15',
|
||
status: 'completed',
|
||
files: [
|
||
{ name: '合同文件.pdf', url: 'https://example.com/contracts/123' }
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
biddingResponseTotal: 15,
|
||
currentBiddingResponse: {},
|
||
biddingResponseDetailVisible: false,
|
||
uploadDocumentDialogVisible: false,
|
||
uploadDocumentForm: {
|
||
type: '商务标书',
|
||
files: []
|
||
},
|
||
documentFileList: [],
|
||
editBiddingDialogVisible: false,
|
||
editBiddingForm: {
|
||
projectName: '',
|
||
publisher: '',
|
||
budget: '',
|
||
deadline: '',
|
||
location: [],
|
||
projectType: '',
|
||
manager: '',
|
||
phone: '',
|
||
description: ''
|
||
},
|
||
|
||
// 商务标书
|
||
documentSearch: {
|
||
keyword: '',
|
||
page: 1,
|
||
limit: 10
|
||
},
|
||
documentData: [
|
||
{
|
||
id: 1,
|
||
name: '某风电场叶片检查技术标书',
|
||
project: '某风电场2023年叶片检查',
|
||
projectId: 1,
|
||
type: '商务标书',
|
||
status: '已完成',
|
||
url: 'https://example.com/documents/123'
|
||
},
|
||
{
|
||
id: 2,
|
||
name: '某风电场叶片检查商务标书',
|
||
project: '某风电场2023年叶片检查',
|
||
projectId: 1,
|
||
type: '商务标书',
|
||
status: '已完成',
|
||
url: 'https://example.com/documents/124'
|
||
}
|
||
],
|
||
documentTotal: 8,
|
||
newDocumentDialogVisible: false,
|
||
newDocumentForm: {
|
||
name: '',
|
||
project: '',
|
||
type: '商务标书',
|
||
files: []
|
||
},
|
||
newDocumentFileList: [],
|
||
editDocumentDialogVisible: false,
|
||
editDocumentForm: {
|
||
id: '',
|
||
name: '',
|
||
project: '',
|
||
type: '商务标书',
|
||
files: []
|
||
},
|
||
editDocumentFileList: [],
|
||
documentRules: {
|
||
name: [
|
||
{ required: true, message: '请输入标书名称', trigger: 'blur' }
|
||
],
|
||
project: [
|
||
{ required: true, message: '请选择关联项目', trigger: 'change' }
|
||
],
|
||
type: [
|
||
{ required: true, message: '请选择标书类型', trigger: 'change' }
|
||
]
|
||
},
|
||
|
||
// 报价文件
|
||
quotationSearch: {
|
||
keyword: '',
|
||
page: 1,
|
||
limit: 10
|
||
},
|
||
quotationData: [
|
||
{
|
||
id: 1,
|
||
name: '某风电场叶片检查报价单',
|
||
project: '某风电场2023年叶片检查',
|
||
projectId: 1,
|
||
totalPrice: '1,080,000.00',
|
||
profitRate: 15,
|
||
status: '已完成',
|
||
description: '基于市场价格和公司成本核算的报价',
|
||
files: [
|
||
{ name: '报价单.xlsx', url: 'https://example.com/quotations/123' }
|
||
]
|
||
},
|
||
{
|
||
id: 2,
|
||
name: '某风电场运维服务报价单',
|
||
project: '某风电场2022年运维服务',
|
||
projectId: 2,
|
||
totalPrice: '1,620,000.00',
|
||
profitRate: 12,
|
||
status: '已完成',
|
||
description: '综合考虑运维成本和市场竞争的报价',
|
||
files: [
|
||
{ name: '报价单.xlsx', url: 'https://example.com/quotations/124' }
|
||
]
|
||
}
|
||
],
|
||
quotationTotal: 5,
|
||
newQuotationDialogVisible: false,
|
||
newQuotationForm: {
|
||
name: '',
|
||
project: '',
|
||
totalPrice: '',
|
||
profitRate: '',
|
||
description: '',
|
||
files: []
|
||
},
|
||
newQuotationFileList: [],
|
||
editQuotationDialogVisible: false,
|
||
editQuotationForm: {
|
||
id: '',
|
||
name: '',
|
||
project: '',
|
||
totalPrice: '',
|
||
profitRate: '',
|
||
description: '',
|
||
files: []
|
||
},
|
||
editQuotationFileList: [],
|
||
quotationRules: {
|
||
name: [
|
||
{ required: true, message: '请输入报价名称', trigger: 'blur' }
|
||
],
|
||
project: [
|
||
{ required: true, message: '请选择关联项目', trigger: 'change' }
|
||
],
|
||
totalPrice: [
|
||
{ required: true, message: '请输入总报价', trigger: 'blur' }
|
||
],
|
||
profitRate: [
|
||
{ required: true, message: '请输入利润率', trigger: 'blur' }
|
||
]
|
||
},
|
||
|
||
// 中标通知
|
||
noticeSearch: {
|
||
keyword: '',
|
||
page: 1,
|
||
limit: 10
|
||
},
|
||
noticeData: [
|
||
{
|
||
id: 1,
|
||
projectName: '某风电场2022年运维服务',
|
||
projectId: 2,
|
||
publisher: '某新能源公司',
|
||
winningPrice: '1,620,000.00',
|
||
noticeDate: '2022-12-05',
|
||
status: '已签约',
|
||
files: [
|
||
{ name: '中标通知书.pdf', url: 'https://example.com/notices/123' }
|
||
]
|
||
}
|
||
],
|
||
noticeTotal: 1,
|
||
newNoticeDialogVisible: false,
|
||
newNoticeForm: {
|
||
project: '',
|
||
winningPrice: '',
|
||
noticeDate: '',
|
||
status: '已确认',
|
||
files: []
|
||
},
|
||
newNoticeFileList: [],
|
||
editNoticeDialogVisible: false,
|
||
editNoticeForm: {
|
||
id: '',
|
||
project: '',
|
||
winningPrice: '',
|
||
noticeDate: '',
|
||
status: '已确认',
|
||
files: []
|
||
},
|
||
editNoticeFileList: [],
|
||
noticeRules: {
|
||
project: [
|
||
{ required: true, message: '请选择关联项目', trigger: 'change' }
|
||
],
|
||
winningPrice: [
|
||
{ required: true, message: '请输入中标金额', trigger: 'blur' }
|
||
],
|
||
noticeDate: [
|
||
{ required: true, message: '请选择通知日期', trigger: 'change' }
|
||
],
|
||
status: [
|
||
{ required: true, message: '请选择状态', trigger: 'change' }
|
||
]
|
||
},
|
||
|
||
// 新建投标项目
|
||
newBiddingDialogVisible: false,
|
||
newBiddingForm: {
|
||
biddingProject: '',
|
||
projectName: '',
|
||
publisher: '',
|
||
budget: '',
|
||
deadline: '',
|
||
location: [],
|
||
projectType: '',
|
||
documents: [],
|
||
manager: '',
|
||
phone: '',
|
||
description: ''
|
||
},
|
||
biddingRules: {
|
||
biddingProject: [
|
||
{ required: true, message: '请选择关联的招标项目', trigger: 'change' }
|
||
],
|
||
projectName: [
|
||
{ required: true, message: '请输入项目名称', trigger: 'blur' }
|
||
],
|
||
publisher: [
|
||
{ required: true, message: '请输入招标单位', trigger: 'blur' }
|
||
],
|
||
deadline: [
|
||
{ required: true, message: '请选择截止时间', trigger: 'change' }
|
||
]
|
||
},
|
||
locationOptions: [
|
||
{
|
||
value: '北京市',
|
||
label: '北京市',
|
||
children: [
|
||
{ value: '东城区', label: '东城区' },
|
||
{ value: '西城区', label: '西城区' }
|
||
]
|
||
},
|
||
{
|
||
value: '内蒙古自治区',
|
||
label: '内蒙古自治区',
|
||
children: [
|
||
{ value: '呼和浩特市', label: '呼和浩特市' },
|
||
{ value: '包头市', label: '包头市' }
|
||
]
|
||
}
|
||
],
|
||
biddingFileList: []
|
||
}
|
||
},
|
||
computed: {
|
||
interestedBiddingProjects() {
|
||
return this.biddingData.filter(item => item.status === '已报名');
|
||
}
|
||
},
|
||
mounted() {
|
||
// 初始化数据
|
||
},
|
||
methods: {
|
||
toggleSidebar() {
|
||
this.isCollapse = !this.isCollapse;
|
||
},
|
||
switchModule(module) {
|
||
this.activeModule = module;
|
||
},
|
||
|
||
// 招采业务 - 信息检索
|
||
startCrawler() {
|
||
this.$message.success('爬虫任务已启动');
|
||
// 实际应用中这里应该调用API启动爬虫
|
||
},
|
||
searchBiddingInfo() {
|
||
this.$message(`搜索招标信息: ${this.biddingSearch.keyword}`);
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
refreshBiddingData() {
|
||
this.$message('刷新招标数据');
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
exportBiddingData() {
|
||
this.$message('导出招标数据');
|
||
},
|
||
showCrawlerSettings() {
|
||
this.crawlerSettingsVisible = true;
|
||
},
|
||
viewBiddingDetail(row) {
|
||
this.currentBidding = row;
|
||
this.biddingDetailVisible = true;
|
||
},
|
||
markAsRegistered(row) {
|
||
this.$confirm(`确定要报名招标项目 "${row.title}" 吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
row.status = '已报名';
|
||
this.$message({
|
||
type: 'success',
|
||
message: '报名成功!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消操作'
|
||
});
|
||
});
|
||
},
|
||
goToBiddingResponse() {
|
||
this.biddingTab = 'response';
|
||
this.biddingDetailVisible = false;
|
||
},
|
||
addKeyword() {
|
||
if (this.newKeyword && !this.crawlerSettings.keywords.includes(this.newKeyword)) {
|
||
this.crawlerSettings.keywords.push(this.newKeyword);
|
||
this.newKeyword = '';
|
||
}
|
||
},
|
||
removeKeyword(tag) {
|
||
this.crawlerSettings.keywords = this.crawlerSettings.keywords.filter(item => item !== tag);
|
||
},
|
||
saveCrawlerSettings() {
|
||
this.$message.success('爬虫设置已保存');
|
||
this.crawlerSettingsVisible = false;
|
||
},
|
||
handleBiddingSizeChange(val) {
|
||
this.biddingSearch.limit = val;
|
||
this.refreshBiddingData();
|
||
},
|
||
handleBiddingCurrentChange(val) {
|
||
this.biddingSearch.page = val;
|
||
this.refreshBiddingData();
|
||
},
|
||
handleBiddingFileUpload(file, fileList, row) {
|
||
// 模拟上传文件
|
||
const newDoc = {
|
||
name: file.name,
|
||
url: URL.createObjectURL(file.raw)
|
||
};
|
||
|
||
if (!row.documents) {
|
||
row.documents = [];
|
||
}
|
||
row.documents.push(newDoc);
|
||
this.$message.success(`文件 ${file.name} 上传成功`);
|
||
},
|
||
|
||
// 招采业务 - 投标响应
|
||
searchBiddingResponse() {
|
||
this.$message(`搜索投标项目: ${this.biddingResponseSearch.keyword}`);
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
showNewBiddingDialog() {
|
||
if (this.interestedBiddingProjects.length === 0) {
|
||
this.$message.warning('请先在"信息检索"中报名招标项目');
|
||
return;
|
||
}
|
||
|
||
this.newBiddingForm = {
|
||
biddingProject: '',
|
||
projectName: '',
|
||
publisher: '',
|
||
budget: '',
|
||
deadline: '',
|
||
location: [],
|
||
projectType: '',
|
||
documents: [],
|
||
manager: '',
|
||
phone: '',
|
||
description: ''
|
||
};
|
||
|
||
this.newBiddingDialogVisible = true;
|
||
},
|
||
handleBiddingProjectChange(biddingId) {
|
||
const project = this.biddingData.find(item => item.id === biddingId);
|
||
if (project) {
|
||
this.newBiddingForm.projectName = project.title;
|
||
this.newBiddingForm.publisher = project.publisher;
|
||
this.newBiddingForm.budget = project.budget;
|
||
this.newBiddingForm.deadline = project.deadline;
|
||
this.newBiddingForm.location = project.location.split(' '); // 假设location是空格分隔的
|
||
this.newBiddingForm.documents = project.documents || [];
|
||
}
|
||
},
|
||
submitNewBidding() {
|
||
this.$refs.newBiddingForm.validate(valid => {
|
||
if (valid) {
|
||
// 生成新的投标项目
|
||
const newProject = {
|
||
id: Date.now(),
|
||
biddingId: this.newBiddingForm.biddingProject,
|
||
projectName: this.newBiddingForm.projectName,
|
||
publisher: this.newBiddingForm.publisher,
|
||
budget: this.newBiddingForm.budget,
|
||
deadline: this.newBiddingForm.deadline,
|
||
location: this.newBiddingForm.location.join(' '),
|
||
projectType: this.newBiddingForm.projectType,
|
||
manager: this.newBiddingForm.manager,
|
||
phone: this.newBiddingForm.phone,
|
||
description: this.newBiddingForm.description,
|
||
status: '准备中',
|
||
progress: 0,
|
||
biddingDocuments: this.newBiddingForm.documents || [],
|
||
documents: [],
|
||
quotation: null,
|
||
notice: null,
|
||
progressSteps: [
|
||
{
|
||
title: '项目立项',
|
||
description: '项目立项并分配负责人',
|
||
date: this.formatDate(new Date()),
|
||
status: 'completed',
|
||
files: []
|
||
},
|
||
{
|
||
title: '招标文件分析',
|
||
description: '分析招标文件和技术要求',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '技术标书编制',
|
||
description: '编制技术标书',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '商务标书编制',
|
||
description: '编制商务标书',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '报价文件准备',
|
||
description: '准备报价文件',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '投标文件审核',
|
||
description: '审核投标文件',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
},
|
||
{
|
||
title: '提交投标',
|
||
description: '提交投标文件',
|
||
date: '',
|
||
status: '',
|
||
files: []
|
||
}
|
||
]
|
||
};
|
||
|
||
this.biddingResponseData.unshift(newProject);
|
||
this.biddingResponseTotal += 1;
|
||
|
||
this.$message.success('新建投标项目成功');
|
||
this.newBiddingDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
refreshBiddingResponse() {
|
||
this.$message('刷新投标响应数据');
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
viewBiddingResponse(row) {
|
||
this.currentBiddingResponse = JSON.parse(JSON.stringify(row));
|
||
this.biddingResponseDetailVisible = true;
|
||
},
|
||
editBiddingResponse(row) {
|
||
this.editBiddingForm = {
|
||
projectName: row.projectName,
|
||
publisher: row.publisher,
|
||
budget: row.budget,
|
||
deadline: row.deadline,
|
||
location: row.location.split(' '),
|
||
projectType: row.projectType,
|
||
manager: row.manager,
|
||
phone: row.phone,
|
||
description: row.description
|
||
};
|
||
this.currentBiddingResponse = row;
|
||
this.editBiddingDialogVisible = true;
|
||
},
|
||
submitEditBidding() {
|
||
this.$refs.editBiddingForm.validate(valid => {
|
||
if (valid) {
|
||
this.currentBiddingResponse.projectName = this.editBiddingForm.projectName;
|
||
this.currentBiddingResponse.publisher = this.editBiddingForm.publisher;
|
||
this.currentBiddingResponse.budget = this.editBiddingForm.budget;
|
||
this.currentBiddingResponse.deadline = this.editBiddingForm.deadline;
|
||
this.currentBiddingResponse.location = this.editBiddingForm.location.join(' ');
|
||
this.currentBiddingResponse.projectType = this.editBiddingForm.projectType;
|
||
this.currentBiddingResponse.manager = this.editBiddingForm.manager;
|
||
this.currentBiddingResponse.phone = this.editBiddingForm.phone;
|
||
this.currentBiddingResponse.description = this.editBiddingForm.description;
|
||
|
||
this.$message.success('修改投标项目成功');
|
||
this.editBiddingDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
uploadBiddingDocument(row) {
|
||
this.currentBiddingResponse = row;
|
||
this.uploadDocumentForm = {
|
||
type: '商务标书',
|
||
files: []
|
||
};
|
||
this.documentFileList = [];
|
||
this.uploadDocumentDialogVisible = true;
|
||
},
|
||
handleDocumentUpload(file, fileList) {
|
||
this.documentFileList = fileList;
|
||
},
|
||
submitDocumentUpload() {
|
||
if (this.documentFileList.length === 0) {
|
||
this.$message.warning('请先上传文件');
|
||
return;
|
||
}
|
||
|
||
const newDoc = {
|
||
name: this.documentFileList[0].name,
|
||
type: this.uploadDocumentForm.type,
|
||
url: URL.createObjectURL(this.documentFileList[0].raw),
|
||
status: '已完成'
|
||
};
|
||
|
||
// 根据文件类型添加到不同位置
|
||
if (this.uploadDocumentForm.type === '商务标书') {
|
||
if (!this.currentBiddingResponse.documents) {
|
||
this.currentBiddingResponse.documents = [];
|
||
}
|
||
this.currentBiddingResponse.documents.push(newDoc);
|
||
|
||
// 同时添加到商务标书列表
|
||
this.documentData.unshift({
|
||
id: Date.now(),
|
||
name: newDoc.name,
|
||
project: this.currentBiddingResponse.projectName,
|
||
projectId: this.currentBiddingResponse.id,
|
||
type: newDoc.type,
|
||
status: newDoc.status,
|
||
url: newDoc.url
|
||
});
|
||
this.documentTotal += 1;
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = this.currentBiddingResponse.progressSteps.findIndex(
|
||
step => step.title.includes('商务标书')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
this.currentBiddingResponse.progressSteps[stepIndex].status = 'completed';
|
||
this.currentBiddingResponse.progressSteps[stepIndex].date = this.formatDate(new Date());
|
||
this.currentBiddingResponse.progressSteps[stepIndex].files = [newDoc];
|
||
this.updateProgressPercentage(this.currentBiddingResponse);
|
||
}
|
||
} else if (this.uploadDocumentForm.type === '报价文件') {
|
||
if (!this.currentBiddingResponse.quotation) {
|
||
this.currentBiddingResponse.quotation = {
|
||
name: `${this.currentBiddingResponse.projectName}报价单`,
|
||
totalPrice: '',
|
||
profitRate: '',
|
||
status: '已完成',
|
||
description: '',
|
||
files: []
|
||
};
|
||
}
|
||
this.currentBiddingResponse.quotation.files.push(newDoc);
|
||
|
||
// 同时添加到报价文件列表
|
||
this.quotationData.unshift({
|
||
id: Date.now(),
|
||
name: `${this.currentBiddingResponse.projectName}报价单`,
|
||
project: this.currentBiddingResponse.projectName,
|
||
projectId: this.currentBiddingResponse.id,
|
||
totalPrice: this.currentBiddingResponse.quotation.totalPrice,
|
||
profitRate: this.currentBiddingResponse.quotation.profitRate,
|
||
status: '已完成',
|
||
description: this.currentBiddingResponse.quotation.description,
|
||
files: [newDoc]
|
||
});
|
||
this.quotationTotal += 1;
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = this.currentBiddingResponse.progressSteps.findIndex(
|
||
step => step.title.includes('报价文件')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
this.currentBiddingResponse.progressSteps[stepIndex].status = 'completed';
|
||
this.currentBiddingResponse.progressSteps[stepIndex].date = this.formatDate(new Date());
|
||
this.currentBiddingResponse.progressSteps[stepIndex].files = [newDoc];
|
||
this.updateProgressPercentage(this.currentBiddingResponse);
|
||
}
|
||
}
|
||
|
||
this.$message.success('文件上传成功');
|
||
this.uploadDocumentDialogVisible = false;
|
||
},
|
||
deleteBiddingResponseFile(row, doc) {
|
||
this.$confirm('确定要删除这个文件吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
if (row.biddingDocuments) {
|
||
row.biddingDocuments = row.biddingDocuments.filter(item => item.name !== doc.name);
|
||
}
|
||
this.$message.success('文件已删除');
|
||
}).catch(() => {
|
||
this.$message.info('已取消删除');
|
||
});
|
||
},
|
||
updateBiddingStatus(row) {
|
||
this.$confirm(`确定要提交投标项目 "${row.projectName}" 吗?提交后将不能修改`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
row.status = '已投标';
|
||
row.progress = 60;
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = row.progressSteps.findIndex(
|
||
step => step.title.includes('提交投标')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
row.progressSteps[stepIndex].status = 'completed';
|
||
row.progressSteps[stepIndex].date = this.formatDate(new Date());
|
||
this.updateProgressPercentage(row);
|
||
}
|
||
|
||
this.$message({
|
||
type: 'success',
|
||
message: '投标已提交!'
|
||
});
|
||
}).catch(() => {
|
||
this.$message({
|
||
type: 'info',
|
||
message: '已取消操作'
|
||
});
|
||
});
|
||
},
|
||
updateProgressPercentage(row) {
|
||
const completedSteps = row.progressSteps.filter(step => step.status === 'completed').length;
|
||
const totalSteps = row.progressSteps.length;
|
||
row.progress = Math.round((completedSteps / totalSteps) * 100);
|
||
},
|
||
formatDate(date) {
|
||
const year = date.getFullYear();
|
||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||
const day = String(date.getDate()).padStart(2, '0');
|
||
return `${year}-${month}-${day}`;
|
||
},
|
||
handleBiddingResponseSizeChange(val) {
|
||
this.biddingResponseSearch.limit = val;
|
||
this.refreshBiddingResponse();
|
||
},
|
||
handleBiddingResponseCurrentChange(val) {
|
||
this.biddingResponseSearch.page = val;
|
||
this.refreshBiddingResponse();
|
||
},
|
||
|
||
// 商务标书
|
||
searchDocuments() {
|
||
this.$message(`搜索标书: ${this.documentSearch.keyword}`);
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
refreshDocuments() {
|
||
this.$message('刷新标书数据');
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
showNewDocumentDialog() {
|
||
this.newDocumentForm = {
|
||
name: '',
|
||
project: '',
|
||
type: '商务标书',
|
||
files: []
|
||
};
|
||
this.newDocumentFileList = [];
|
||
this.newDocumentDialogVisible = true;
|
||
},
|
||
handleNewDocumentUpload(file, fileList) {
|
||
this.newDocumentFileList = fileList;
|
||
},
|
||
submitNewDocument() {
|
||
this.$refs.newDocumentForm.validate(valid => {
|
||
if (valid) {
|
||
if (this.newDocumentFileList.length === 0) {
|
||
this.$message.warning('请先上传文件');
|
||
return;
|
||
}
|
||
|
||
const project = this.biddingResponseData.find(item => item.id === this.newDocumentForm.project);
|
||
|
||
const newDoc = {
|
||
id: Date.now(),
|
||
name: this.newDocumentForm.name,
|
||
project: project ? project.projectName : '',
|
||
projectId: this.newDocumentForm.project,
|
||
type: this.newDocumentForm.type,
|
||
status: '已完成',
|
||
url: URL.createObjectURL(this.newDocumentFileList[0].raw)
|
||
};
|
||
|
||
this.documentData.unshift(newDoc);
|
||
this.documentTotal += 1;
|
||
|
||
// 同时添加到投标项目的文档列表
|
||
if (project) {
|
||
if (!project.documents) {
|
||
project.documents = [];
|
||
}
|
||
project.documents.push({
|
||
name: newDoc.name,
|
||
type: newDoc.type,
|
||
status: newDoc.status,
|
||
url: newDoc.url
|
||
});
|
||
|
||
// 更新进度步骤
|
||
const stepTitle = newDoc.type === '商务标书' ? '商务标书编制' : '技术标书编制';
|
||
const stepIndex = project.progressSteps.findIndex(
|
||
step => step.title.includes(stepTitle)
|
||
);
|
||
if (stepIndex !== -1) {
|
||
project.progressSteps[stepIndex].status = 'completed';
|
||
project.progressSteps[stepIndex].date = this.formatDate(new Date());
|
||
project.progressSteps[stepIndex].files = [{
|
||
name: newDoc.name,
|
||
url: newDoc.url
|
||
}];
|
||
this.updateProgressPercentage(project);
|
||
}
|
||
}
|
||
|
||
this.$message.success('新建标书成功');
|
||
this.newDocumentDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
viewDocument(row) {
|
||
window.open(row.url, '_blank');
|
||
},
|
||
editDocument(row) {
|
||
this.editDocumentForm = {
|
||
id: row.id,
|
||
name: row.name,
|
||
project: row.projectId,
|
||
type: row.type,
|
||
files: []
|
||
};
|
||
this.editDocumentFileList = [];
|
||
this.currentDocument = row;
|
||
this.editDocumentDialogVisible = true;
|
||
},
|
||
handleEditDocumentUpload(file, fileList) {
|
||
this.editDocumentFileList = fileList;
|
||
},
|
||
submitEditDocument() {
|
||
this.$refs.editDocumentForm.validate(valid => {
|
||
if (valid) {
|
||
this.currentDocument.name = this.editDocumentForm.name;
|
||
this.currentDocument.project = this.biddingResponseData.find(item => item.id === this.editDocumentForm.project)?.projectName || '';
|
||
this.currentDocument.projectId = this.editDocumentForm.project;
|
||
this.currentDocument.type = this.editDocumentForm.type;
|
||
|
||
if (this.editDocumentFileList.length > 0) {
|
||
this.currentDocument.url = URL.createObjectURL(this.editDocumentFileList[0].raw);
|
||
}
|
||
|
||
this.$message.success('修改标书成功');
|
||
this.editDocumentDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
deleteDocument(row) {
|
||
this.$confirm('确定要删除这个标书吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.documentData = this.documentData.filter(item => item.id !== row.id);
|
||
this.documentTotal -= 1;
|
||
|
||
// 同时从投标项目的文档列表中删除
|
||
const project = this.biddingResponseData.find(item => item.id === row.projectId);
|
||
if (project && project.documents) {
|
||
project.documents = project.documents.filter(doc => doc.name !== row.name);
|
||
}
|
||
|
||
this.$message.success('标书已删除');
|
||
}).catch(() => {
|
||
this.$message.info('已取消删除');
|
||
});
|
||
},
|
||
handleDocumentSizeChange(val) {
|
||
this.documentSearch.limit = val;
|
||
this.refreshDocuments();
|
||
},
|
||
handleDocumentCurrentChange(val) {
|
||
this.documentSearch.page = val;
|
||
this.refreshDocuments();
|
||
},
|
||
|
||
// 报价文件
|
||
searchQuotations() {
|
||
this.$message(`搜索报价文件: ${this.quotationSearch.keyword}`);
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
refreshQuotations() {
|
||
this.$message('刷新报价数据');
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
showNewQuotationDialog() {
|
||
this.newQuotationForm = {
|
||
name: '',
|
||
project: '',
|
||
totalPrice: '',
|
||
profitRate: '',
|
||
description: '',
|
||
files: []
|
||
};
|
||
this.newQuotationFileList = [];
|
||
this.newQuotationDialogVisible = true;
|
||
},
|
||
handleNewQuotationUpload(file, fileList) {
|
||
this.newQuotationFileList = fileList;
|
||
},
|
||
submitNewQuotation() {
|
||
this.$refs.newQuotationForm.validate(valid => {
|
||
if (valid) {
|
||
if (this.newQuotationFileList.length === 0) {
|
||
this.$message.warning('请先上传文件');
|
||
return;
|
||
}
|
||
|
||
const project = this.biddingResponseData.find(item => item.id === this.newQuotationForm.project);
|
||
|
||
const newQuotation = {
|
||
id: Date.now(),
|
||
name: this.newQuotationForm.name || `${project ? project.projectName : ''}报价单`,
|
||
project: project ? project.projectName : '',
|
||
projectId: this.newQuotationForm.project,
|
||
totalPrice: this.newQuotationForm.totalPrice,
|
||
profitRate: this.newQuotationForm.profitRate,
|
||
status: '已完成',
|
||
description: this.newQuotationForm.description,
|
||
files: [
|
||
{
|
||
name: this.newQuotationFileList[0].name,
|
||
url: URL.createObjectURL(this.newQuotationFileList[0].raw)
|
||
}
|
||
]
|
||
};
|
||
|
||
this.quotationData.unshift(newQuotation);
|
||
this.quotationTotal += 1;
|
||
|
||
// 同时添加到投标项目的报价信息
|
||
if (project) {
|
||
project.quotation = {
|
||
name: newQuotation.name,
|
||
totalPrice: newQuotation.totalPrice,
|
||
profitRate: newQuotation.profitRate,
|
||
status: '已完成',
|
||
description: newQuotation.description,
|
||
files: newQuotation.files
|
||
};
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = project.progressSteps.findIndex(
|
||
step => step.title.includes('报价文件')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
project.progressSteps[stepIndex].status = 'completed';
|
||
project.progressSteps[stepIndex].date = this.formatDate(new Date());
|
||
project.progressSteps[stepIndex].files = newQuotation.files;
|
||
this.updateProgressPercentage(project);
|
||
}
|
||
}
|
||
|
||
this.$message.success('新建报价成功');
|
||
this.newQuotationDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
viewQuotation(row) {
|
||
if (row.files && row.files.length > 0) {
|
||
window.open(row.files[0].url, '_blank');
|
||
}
|
||
},
|
||
editQuotation(row) {
|
||
this.editQuotationForm = {
|
||
id: row.id,
|
||
name: row.name,
|
||
project: row.projectId,
|
||
totalPrice: row.totalPrice,
|
||
profitRate: row.profitRate,
|
||
description: row.description,
|
||
files: []
|
||
};
|
||
this.editQuotationFileList = [];
|
||
this.currentQuotation = row;
|
||
this.editQuotationDialogVisible = true;
|
||
},
|
||
handleEditQuotationUpload(file, fileList) {
|
||
this.editQuotationFileList = fileList;
|
||
},
|
||
submitEditQuotation() {
|
||
this.$refs.editQuotationForm.validate(valid => {
|
||
if (valid) {
|
||
this.currentQuotation.name = this.editQuotationForm.name;
|
||
this.currentQuotation.project = this.biddingResponseData.find(item => item.id === this.editQuotationForm.project)?.projectName || '';
|
||
this.currentQuotation.projectId = this.editQuotationForm.project;
|
||
this.currentQuotation.totalPrice = this.editQuotationForm.totalPrice;
|
||
this.currentQuotation.profitRate = this.editQuotationForm.profitRate;
|
||
this.currentQuotation.description = this.editQuotationForm.description;
|
||
|
||
if (this.editQuotationFileList.length > 0) {
|
||
this.currentQuotation.files = [{
|
||
name: this.editQuotationFileList[0].name,
|
||
url: URL.createObjectURL(this.editQuotationFileList[0].raw)
|
||
}];
|
||
}
|
||
|
||
// 更新投标项目中的报价信息
|
||
const project = this.biddingResponseData.find(item => item.id === this.editQuotationForm.project);
|
||
if (project && project.quotation) {
|
||
project.quotation.name = this.editQuotationForm.name;
|
||
project.quotation.totalPrice = this.editQuotationForm.totalPrice;
|
||
project.quotation.profitRate = this.editQuotationForm.profitRate;
|
||
project.quotation.description = this.editQuotationForm.description;
|
||
|
||
if (this.editQuotationFileList.length > 0) {
|
||
project.quotation.files = [{
|
||
name: this.editQuotationFileList[0].name,
|
||
url: URL.createObjectURL(this.editQuotationFileList[0].raw)
|
||
}];
|
||
}
|
||
}
|
||
|
||
this.$message.success('修改报价成功');
|
||
this.editQuotationDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
deleteQuotation(row) {
|
||
this.$confirm('确定要删除这个报价吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.quotationData = this.quotationData.filter(item => item.id !== row.id);
|
||
this.quotationTotal -= 1;
|
||
|
||
// 同时从投标项目的报价信息中删除
|
||
const project = this.biddingResponseData.find(item => item.id === row.projectId);
|
||
if (project) {
|
||
project.quotation = null;
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = project.progressSteps.findIndex(
|
||
step => step.title.includes('报价文件')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
project.progressSteps[stepIndex].status = '';
|
||
project.progressSteps[stepIndex].date = '';
|
||
project.progressSteps[stepIndex].files = [];
|
||
this.updateProgressPercentage(project);
|
||
}
|
||
}
|
||
|
||
this.$message.success('报价已删除');
|
||
}).catch(() => {
|
||
this.$message.info('已取消删除');
|
||
});
|
||
},
|
||
handleQuotationSizeChange(val) {
|
||
this.quotationSearch.limit = val;
|
||
this.refreshQuotations();
|
||
},
|
||
handleQuotationCurrentChange(val) {
|
||
this.quotationSearch.page = val;
|
||
this.refreshQuotations();
|
||
},
|
||
|
||
// 中标通知
|
||
searchNotices() {
|
||
this.$message(`搜索中标通知: ${this.noticeSearch.keyword}`);
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
refreshNotices() {
|
||
this.$message('刷新中标通知数据');
|
||
// 实际应用中这里应该调用API获取数据
|
||
},
|
||
showNewNoticeDialog() {
|
||
this.newNoticeForm = {
|
||
project: '',
|
||
winningPrice: '',
|
||
noticeDate: '',
|
||
status: '已确认',
|
||
files: []
|
||
};
|
||
this.newNoticeFileList = [];
|
||
this.newNoticeDialogVisible = true;
|
||
},
|
||
handleNewNoticeUpload(file, fileList) {
|
||
this.newNoticeFileList = fileList;
|
||
},
|
||
submitNewNotice() {
|
||
this.$refs.newNoticeForm.validate(valid => {
|
||
if (valid) {
|
||
if (this.newNoticeFileList.length === 0) {
|
||
this.$message.warning('请先上传文件');
|
||
return;
|
||
}
|
||
|
||
const project = this.biddingResponseData.find(item => item.id === this.newNoticeForm.project);
|
||
|
||
const newNotice = {
|
||
id: Date.now(),
|
||
projectName: project ? project.projectName : '',
|
||
projectId: this.newNoticeForm.project,
|
||
publisher: project ? project.publisher : '',
|
||
winningPrice: this.newNoticeForm.winningPrice,
|
||
noticeDate: this.newNoticeForm.noticeDate,
|
||
status: this.newNoticeForm.status,
|
||
files: [
|
||
{
|
||
name: this.newNoticeFileList[0].name,
|
||
url: URL.createObjectURL(this.newNoticeFileList[0].raw)
|
||
}
|
||
]
|
||
};
|
||
|
||
this.noticeData.unshift(newNotice);
|
||
this.noticeTotal += 1;
|
||
|
||
// 同时更新投标项目的状态和通知信息
|
||
if (project) {
|
||
project.status = '已中标';
|
||
project.progress = 100;
|
||
project.notice = {
|
||
name: `${project.projectName}中标通知`,
|
||
winningPrice: newNotice.winningPrice,
|
||
noticeDate: newNotice.noticeDate,
|
||
status: newNotice.status,
|
||
files: newNotice.files
|
||
};
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = project.progressSteps.findIndex(
|
||
step => step.title.includes('中标通知')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
project.progressSteps[stepIndex].status = 'completed';
|
||
project.progressSteps[stepIndex].date = newNotice.noticeDate;
|
||
project.progressSteps[stepIndex].files = newNotice.files;
|
||
this.updateProgressPercentage(project);
|
||
}
|
||
}
|
||
|
||
this.$message.success('新建中标通知成功');
|
||
this.newNoticeDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
viewNotice(row) {
|
||
if (row.files && row.files.length > 0) {
|
||
window.open(row.files[0].url, '_blank');
|
||
}
|
||
},
|
||
editNotice(row) {
|
||
this.editNoticeForm = {
|
||
id: row.id,
|
||
project: row.projectId,
|
||
winningPrice: row.winningPrice,
|
||
noticeDate: row.noticeDate,
|
||
status: row.status,
|
||
files: []
|
||
};
|
||
this.editNoticeFileList = [];
|
||
this.currentNotice = row;
|
||
this.editNoticeDialogVisible = true;
|
||
},
|
||
handleEditNoticeUpload(file, fileList) {
|
||
this.editNoticeFileList = fileList;
|
||
},
|
||
submitEditNotice() {
|
||
this.$refs.editNoticeForm.validate(valid => {
|
||
if (valid) {
|
||
this.currentNotice.project = this.editNoticeForm.project;
|
||
this.currentNotice.projectName = this.biddingResponseData.find(item => item.id === this.editNoticeForm.project)?.projectName || '';
|
||
this.currentNotice.winningPrice = this.editNoticeForm.winningPrice;
|
||
this.currentNotice.noticeDate = this.editNoticeForm.noticeDate;
|
||
this.currentNotice.status = this.editNoticeForm.status;
|
||
|
||
if (this.editNoticeFileList.length > 0) {
|
||
this.currentNotice.files = [{
|
||
name: this.editNoticeFileList[0].name,
|
||
url: URL.createObjectURL(this.editNoticeFileList[0].raw)
|
||
}];
|
||
}
|
||
|
||
// 更新投标项目中的通知信息
|
||
const project = this.biddingResponseData.find(item => item.id === this.editNoticeForm.project);
|
||
if (project && project.notice) {
|
||
project.notice.winningPrice = this.editNoticeForm.winningPrice;
|
||
project.notice.noticeDate = this.editNoticeForm.noticeDate;
|
||
project.notice.status = this.editNoticeForm.status;
|
||
|
||
if (this.editNoticeFileList.length > 0) {
|
||
project.notice.files = [{
|
||
name: this.editNoticeFileList[0].name,
|
||
url: URL.createObjectURL(this.editNoticeFileList[0].raw)
|
||
}];
|
||
}
|
||
}
|
||
|
||
this.$message.success('修改中标通知成功');
|
||
this.editNoticeDialogVisible = false;
|
||
} else {
|
||
return false;
|
||
}
|
||
});
|
||
},
|
||
deleteNotice(row) {
|
||
this.$confirm('确定要删除这个中标通知吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.noticeData = this.noticeData.filter(item => item.id !== row.id);
|
||
this.noticeTotal -= 1;
|
||
|
||
// 同时从投标项目的通知信息中删除
|
||
const project = this.biddingResponseData.find(item => item.id === row.projectId);
|
||
if (project) {
|
||
project.notice = null;
|
||
|
||
// 更新进度步骤
|
||
const stepIndex = project.progressSteps.findIndex(
|
||
step => step.title.includes('中标通知')
|
||
);
|
||
if (stepIndex !== -1) {
|
||
project.progressSteps[stepIndex].status = '';
|
||
project.progressSteps[stepIndex].date = '';
|
||
project.progressSteps[stepIndex].files = [];
|
||
this.updateProgressPercentage(project);
|
||
}
|
||
}
|
||
|
||
this.$message.success('通知已删除');
|
||
}).catch(() => {
|
||
this.$message.info('已取消删除');
|
||
});
|
||
},
|
||
handleNoticeSizeChange(val) {
|
||
this.noticeSearch.limit = val;
|
||
this.refreshNotices();
|
||
},
|
||
handleNoticeCurrentChange(val) {
|
||
this.noticeSearch.page = val;
|
||
this.refreshNotices();
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |