920 lines
37 KiB
TypeScript
920 lines
37 KiB
TypeScript
import ProTable, { ActionType, ProColumns, } from "@ant-design/pro-table";
|
||
import { Button, Card, Col, DatePicker, Descriptions, Form, Input, message, Modal, Progress, Row, Spin } from "antd";
|
||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||
import styles from './index.less';
|
||
import './index.less';
|
||
import { getList, jieMi, jmRate, singBid, endTimeUp, updatePrice, queryFx, confirmOffer } from './service';
|
||
import { getSessionUserData, getSessionRoleData, getProMethod } from '@/utils/session';
|
||
import { getURLInformation } from '@/utils/CommonUtils'
|
||
import '@/assets/xsy_style.less'
|
||
import logo from '@/images/opening/logo.svg'
|
||
import moment from "moment";
|
||
import { ipassDecrypt } from "@/utils/IpassVerification";
|
||
import { btnAuthority } from "@/utils/authority";
|
||
import { AsymDecrypt } from "@/utils/zwPlugin";
|
||
import FileDown from "@/utils/Download";
|
||
import { getBiddingDocumentsDecryptList, selectParam1, selectParam2 } from "@/pages/Evaluation/BiddingDocumentsDecrypt/service";
|
||
import { DownloadOutlined } from "@ant-design/icons";
|
||
|
||
const Room: React.FC<{}> = () => {
|
||
const [spin, spinSet] = useState<any>(false);
|
||
const FormItem = Form.Item;
|
||
const { TextArea } = Input;
|
||
const formLayout = {
|
||
labelCol: { span: 8 },
|
||
wrapperCol: { span: 16 },
|
||
};
|
||
const modalHeight = window.innerHeight * 96 / 100;
|
||
const roomType = getURLInformation('roomType');//预审1 后审2
|
||
//控制字段 角色、开标状态、唱标阶段、是否需要ipass解密
|
||
// const proId = 1111111;
|
||
const juese = getSessionRoleData().roleCode//ebtp-agency-project-manager 代理 ebtp-supplier 供应商 ebtp-agency-project-manager 代理 ebtp-supplier 供应商
|
||
const userId = getSessionUserData().userId//当前登陆人id
|
||
const tendererName = getSessionUserData().organizationName//当前登陆人 公司名
|
||
const tenderId = getSessionUserData().organizationId//当前登陆人 公司id
|
||
const actionRef = useRef<ActionType>();
|
||
const [count, countSet] = useState<number>(0); //开标室启动器
|
||
// const [turnSort, turnSortSet] = useState<number>(1); //开标室启动器
|
||
const [projectName, projectNameSet] = useState<any>(''); //项目名称
|
||
const [projectNo, projectNoSet] = useState<any>(''); //项目编号
|
||
const [sectionName, sectionNameSet] = useState<any>(''); //标包名称
|
||
const [sectionNo, sectionNoSet] = useState<any>(''); //标包编号
|
||
const [openTime, openTimeSet] = useState<any>(''); //开标时间
|
||
const [openState, openStateSet] = useState<boolean>();//是否开标
|
||
const [range, rangeSet] = useState<boolean>();//是否唱标
|
||
const [jm, jmSet] = useState<boolean>();//是否解密
|
||
const [queryHaveData, queryHaveDataSet] = useState<boolean>(false);//是否解密
|
||
const [rangeOver, rangeOverSet] = useState<boolean>();//是否唱标结束
|
||
const [important, importantSet] = useState<boolean>(false);//是否重大项目
|
||
const [turnId, turnIdSet] = useState<any>('');//轮次id
|
||
const [configId, configIdSet] = useState<any>('');//唱标配置id
|
||
const [openRoom, openRoomSet] = useState<any>('');//开标室id
|
||
const [signTime, signTimeSet] = useState<any>({});//供应商签名信息
|
||
const [haveComplete, haveCompleteSet] = useState<boolean>(false);//当前供应商是否有解密成功的文件
|
||
const [repairVis, repairVisSet] = useState<boolean>(false);//补录报价显隐
|
||
const [subentryVis, handleSubentryVis] = useState<boolean>(false);//分项报价显隐
|
||
const [tdocId, tdocIdSet] = useState<any>('');//tdocId 分项报价表用
|
||
const [gysId, gysIdSet] = useState<any>('');//gysId 分项报价表导出用
|
||
const [jmTimeVis, jmTimeVisSet] = useState<boolean>(false);//解密时限显隐
|
||
const [endTime, endTimeSet] = useState<any>('');//解密时限
|
||
const [endTimeVis, endTimeVisSet] = useState<boolean>(true);//解密时限提示显隐
|
||
const [rateVis, handleRateVis] = useState<boolean>(false); //进度显隐
|
||
const [rateCount, rateCountSet] = useState<number>(0); //查询进度启动器
|
||
const [jmFileCount, jmFileCountSet] = useState<number>(0);//文件总数
|
||
const [jmComplete, jmCompleteSet] = useState<number>(0);//已解密成功
|
||
const [jmWait, jmWaitSet] = useState<number>(0);//未解密
|
||
const [jmFail, jmFailSet] = useState<number>(0);//解密失败
|
||
const [isJm, isJmSet] = useState<number>(0);//是否解密中 0-未解密 1-解密中或者解密完成
|
||
const [tFile, tFileSet] = useState<any>([]);//供应商解密存秘钥
|
||
const [dis, disSet] = useState<boolean>(false);
|
||
const [assessRoomId, assessRoomIdSet] = useState<any>('');
|
||
const [turnSort, turnSortSet] = useState<any>('');
|
||
const [jmStatus, jmStatusSet] = useState<number>(-1);//解密状态decryptButton 0-显示解密按钮(未解密,有解密失败) 1-解密中 2-不显示解密按钮(解密已全部完成)
|
||
const [jmFlag, jmFlagSet] = useState<number>(0);//当前是否触发过解密操作 0-未解密(没点过) 1-解密中(点过)
|
||
const time_ = 2000; //设置解密间隔时间
|
||
|
||
//开标室表格
|
||
const [columnsKb, columnsKbSet] = useState<any>([]);
|
||
const [columnsKbData, columnsKbDataSet] = useState<any>([]);
|
||
const method = getProMethod();//项目类型字典项
|
||
let showNameT: any = { tbdw: '', tbr: '', bd: '', kb: '', tb: '' }//投标人供应商
|
||
if (method === 'procurement_mode_1' || method === 'procurement_mode_2') {//招标
|
||
showNameT = { tbdw: '投标单位', tbr: '投标人', bd: '标段', kb: '开标', tb: '投标' };
|
||
} else {
|
||
showNameT = { tbdw: '供应商', tbr: '供应商', bd: '采购包', kb: '开启', tb: '应答' }
|
||
}
|
||
|
||
//唱标
|
||
const sing = async (fields: any) => {
|
||
try {
|
||
const success = await singBid({ ...fields }).then((res) => {
|
||
return res.success
|
||
});
|
||
if (success) {
|
||
message.success('操作成功!');
|
||
getTableData();
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
} catch (error) {
|
||
message.error('失败请重试!');
|
||
return false;
|
||
}
|
||
};
|
||
//设置解密时限
|
||
const endTimeConfig = async (fields: any) => {
|
||
try {
|
||
const success = await endTimeUp({ ...fields }).then((res) => {
|
||
return res.success
|
||
});
|
||
if (success) {
|
||
message.success('设置成功!');
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
} catch (error) {
|
||
message.error('设置失败请重试!');
|
||
return false;
|
||
}
|
||
};
|
||
//开标室表格按钮
|
||
const tools = [
|
||
endTime != '' && important && !range ?
|
||
<div key='jmsxTip' className='mR8 xsy-red floatLeft h32 ftSz20' hidden={endTimeVis}>{showNameT.tbr}解密时限: {endTime}</div> : null,
|
||
endTime === '' && important && !range ?
|
||
<div key='tips' className='mR8 xsy-red floatLeft h32 ftSz20' hidden={btnAuthority(['ebtp-supplier'])}>请等待项目经理开启解密</div> : null,
|
||
endTimeVis && important && !range ?
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} key='jmsx' className='mR8' type="primary" onClick={() => { jmTimeVisSet(true) }}>开启解密</Button> : null,
|
||
!range && !rangeOver && (jmStatus == 0 || jmStatus == 1) && !important ?//代理解密
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} key='jm' type="primary" disabled={dis} className='mR8' loading={jmStatus == 1}
|
||
onClick={async () => {
|
||
spinSet(true); disSet(true); jmStatusSet(1);
|
||
const success = await jieMi({ tdocId: tdocId, }).then((res) => {//roomType: roomType
|
||
return res.success
|
||
});
|
||
if (success) {
|
||
handleRateVis(true);
|
||
rateCountSet(rateCount + 1);
|
||
}
|
||
spinSet(false); disSet(false);
|
||
}}>{jmStatus == 1 ? '解密中' : '解密'}</Button> : null,
|
||
!range && !rangeOver && (jmStatus == 0 || jmStatus == 1) && important && endTime != '' && jm ?//供应商解密
|
||
<Button hidden={btnAuthority(['ebtp-supplier'])} key='gysjm' type="primary" disabled={dis} className='mR8' loading={jmStatus == 1}
|
||
onClick={async () => {
|
||
spinSet(true); disSet(true); jmStatusSet(1);
|
||
let secretKeyMap: any = {};
|
||
if (tFile.length > 0) {
|
||
if (ipassDecrypt(tFile[0].secretKey) != null) {
|
||
await tFile.map((item: any) => {
|
||
secretKeyMap[item.id] = AsymDecrypt(item.secretKey);
|
||
})
|
||
}
|
||
}
|
||
if (Object.keys(secretKeyMap).length > 0) {
|
||
const success = await jieMi({ tdocId: tdocId, secretKeyMap: secretKeyMap }).then((res) => {//roomType: roomType
|
||
return res.success
|
||
});
|
||
if (success) {
|
||
handleRateVis(true);
|
||
rateCountSet(rateCount + 1);
|
||
}
|
||
}
|
||
spinSet(false); disSet(false);
|
||
}}>{jmStatus == 1 ? '解密中' : '解密'}</Button> : null,
|
||
!range && (jmStatus == 0 || jmStatus == 1) && !rangeOver ?//代理解密进度
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} key='ckjd' type="primary" disabled={dis} className='mR8'
|
||
onClick={() => {
|
||
disSet(true);
|
||
handleRateVis(true);
|
||
rateCountSet(rateCount + 1);
|
||
disSet(false);
|
||
}}>查看解密进度</Button> : null,
|
||
!range && (jmStatus == 0 || jmStatus == 1) && !rangeOver && important && endTime != '' && jm ?//供应商解密进度
|
||
<Button hidden={btnAuthority(['ebtp-supplier'])} key='ckjdgys' type="primary" disabled={dis} className='mR8'
|
||
onClick={() => {
|
||
disSet(true);
|
||
handleRateVis(true);
|
||
rateCountSet(rateCount + 1);
|
||
disSet(false);
|
||
}}>查看解密进度</Button> : null,
|
||
jmFlag == 1 && jmStatus != 1 && !rangeOver && !range && roomType === '2' ?//代理唱标
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} disabled={dis} key='cb' type="primary" className='mR8' onClick={async () => {
|
||
disSet(true);
|
||
await sing({ id: configId, whetherRange: 1, tdocId: tdocId });
|
||
disSet(false);
|
||
}}>唱标</Button> : null,
|
||
range && !rangeOver ?//代理唱标结束
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} disabled={dis} key='cbjs' type="primary" className='mR8' onClick={async () => {
|
||
disSet(true);
|
||
await sing({ id: configId, whetherRangeOver: 1, tdocId: tdocId });
|
||
disSet(false);
|
||
}}>唱标结束</Button> : null,
|
||
jmFlag == 1 && jmStatus != 1 && !rangeOver && roomType === '1' ?//代理开标结束
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} disabled={dis} key='kbjs' type="primary" className='mR8' onClick={async () => {
|
||
disSet(true);
|
||
await sing({ id: configId, whetherRangeOver: 1, tdocId: tdocId });
|
||
disSet(false);
|
||
}}>开标结束</Button> : null,
|
||
range && signTime[userId] && haveComplete ?//供应商确认报价
|
||
<Button hidden={btnAuthority(['ebtp-supplier'])} key='qrbj' type="primary" disabled={dis}
|
||
onClick={async () => {
|
||
disSet(true);
|
||
await confirmOffer(turnId, tdocId).then((res: any) => {
|
||
if (res.message === 'success') {
|
||
message.success('确认成功')
|
||
}
|
||
countSet(count + 1);
|
||
})
|
||
disSet(false);
|
||
}}>确认报价</Button> : null,
|
||
jmFlag == 1 && jmStatus != 1 &&
|
||
<Button
|
||
key='downFile'
|
||
type="primary"
|
||
disabled={dis}
|
||
className='mR8'
|
||
hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])}
|
||
onClick={() => getFownFileData()}
|
||
>下载{showNameT.tb}文件</Button>,
|
||
range && (juese === 'ebtp-agency-project-manager' || juese === 'ebtp-purchase') && roomType !== '1' &&
|
||
<FileDown key='fileDown' apiUrl={`/api/biz-service-ebtp-resps/v1/tfile/exportOpenBidByTendererId?assessRoomId=${assessRoomId}&turnSort=${turnSort}`} btnName='导出报价表' />
|
||
];
|
||
//取参数
|
||
function getQueryString(name: any) {
|
||
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
|
||
let r = window.location.search.substr(1).match(reg);
|
||
return r !== null ? unescape(r[2]) : null;
|
||
}
|
||
//进页面执行
|
||
useEffect(() => {
|
||
getTableData();
|
||
}, [count]);
|
||
//查询进度
|
||
useEffect(() => {
|
||
if (rateVis) {
|
||
queryRate();
|
||
setTimeout(async () => {
|
||
rateCountSet(rateCount + 1);
|
||
}, time_);
|
||
}
|
||
}, [rateCount, rateVis]);
|
||
async function queryRate() {//查询解密进度
|
||
|
||
await jmRate({ tdocId: tdocId }).then((res) => {
|
||
if (res?.code == 200) {
|
||
let data = res.data;
|
||
let all: number, comp: number, fail: number, wait: number = 0, isJm: number = 0;
|
||
all = data['-1'] != undefined ? parseInt(data['-1']) : 0;
|
||
comp = data['1'] != undefined ? parseInt(data['1']) : 0;
|
||
fail = data['2'] != undefined ? parseInt(data['2']) : 0;
|
||
wait = data['0'] != undefined ? parseInt(data['0']) : 0;
|
||
isJm = data['-2'] != undefined ? parseInt(data['-2']) : 0;//是否解密中 0-未解密 1-解密中
|
||
jmCompleteSet(comp);
|
||
jmFailSet(fail);
|
||
jmFileCountSet(all);
|
||
jmWaitSet(wait);
|
||
isJmSet(isJm);
|
||
// comp == all && setTimeout(() => {//全解密 成功自动关窗
|
||
// handleRateVis(false);
|
||
// }, 1000);
|
||
}
|
||
});
|
||
}
|
||
//取表格数据
|
||
const getTableData = async () => {
|
||
if (count == 0) {
|
||
spinSet(true);
|
||
}
|
||
let assessRoomId: any = "";
|
||
let turnSort: any = '';
|
||
let commpanyId = getSessionUserData().organizationId;
|
||
juese == 'ebtp-agency-project-manager' ? commpanyId = '' : null;
|
||
if (getQueryString("aa") != null) {
|
||
assessRoomId = getQueryString("aa")
|
||
}
|
||
if (getQueryString("bb") != null) {
|
||
turnSort = getQueryString("bb")
|
||
}
|
||
|
||
let column: any = [];
|
||
let tFileT: any = [];
|
||
let data: any = [];
|
||
let category: any[] = [];
|
||
let projectName: any, projectNo: any, sectionName: any, sectionNo: any, openTime: any, turnId: any, configId: any, openRoomId: any, tdocId1: any = '';
|
||
let openState: any, decryptStatus: any = false;
|
||
let rangeT: any, rangeOverT: any, important: any, endTimeVisT: any = true;
|
||
let signTimeT = {};//签名信息
|
||
let decryptEndDateT = '';//解密时限
|
||
let decryptButton = -1;
|
||
let decryptFlag = 0;
|
||
|
||
await getList({ assessRoomId: assessRoomId, turnSort: turnSort, commpanyId: commpanyId, id: tdocId }).then((res) => {//roomType: roomType
|
||
//拼记录表信息
|
||
if (res?.code == 200) {
|
||
projectName = res.data.singConfig.projectName;
|
||
projectNo = res.data.singConfig.projectNo;
|
||
sectionName = res.data.singConfig.sectionName;
|
||
sectionNo = res.data.singConfig.sectionNo;
|
||
openTime = res.data.singConfig.openTime;
|
||
openState = res.data.singConfig.openState == 1 || res.data.singConfig.openState == 3 ? true : false;
|
||
|
||
rangeT = res.data.singConfig.whetherRange == 1 ? true : false;
|
||
rangeOverT = res.data.singConfig.whetherRangeOver == 1 ? true : false;
|
||
decryptStatus = res.data.tdoc.decryptStatus;//true gys可以解密
|
||
turnId = res.data.singConfig.turnId;
|
||
configId = res.data.singConfig.id;
|
||
openRoomId = res.data.singConfig.openRoomId;
|
||
important = res.data.singConfig.passDecode === '0' ? true : false;
|
||
decryptEndDateT = res.data.tdoc.decryptEndDate == null ? '' : res.data.tdoc.decryptEndDate;
|
||
endTimeVisT = res.data.tdoc.decryptEndDate == null ? true : false;
|
||
decryptButton = res.data.decryptButton;
|
||
decryptFlag = res.data.decryptFlag;
|
||
|
||
projectNameSet(projectName);
|
||
projectNoSet(projectNo);
|
||
sectionNameSet(sectionName);
|
||
sectionNoSet(sectionNo);
|
||
openTimeSet(openTime);
|
||
openStateSet(openState);
|
||
rangeSet(rangeT);
|
||
rangeOverSet(rangeOverT);
|
||
jmSet(decryptStatus);
|
||
turnIdSet(turnId);
|
||
configIdSet(configId);
|
||
openRoomSet(openRoomId);
|
||
importantSet(important);
|
||
endTimeSet(decryptEndDateT);
|
||
endTimeVisSet(endTimeVisT);
|
||
assessRoomIdSet(assessRoomId);
|
||
turnSortSet(turnSort);
|
||
jmStatusSet(decryptButton);
|
||
jmFlagSet(decryptFlag);
|
||
}
|
||
//拼表格
|
||
if (res?.code == 200) {
|
||
//取tdoc id 分项报价用
|
||
tdocId1 = res.data.tdoc.id;
|
||
column.push({ title: '序号', dataIndex: 'index', valueType: 'index', width: 80 });
|
||
column.push({ title: showNameT.tbdw, dataIndex: 'companyName', });
|
||
res.data.title.map((item: any, index: any) => {
|
||
column.push({ title: item.name, dataIndex: item.id, });
|
||
category.push(item.id);
|
||
});
|
||
column.push({ title: '签名信息', dataIndex: 'bidUserName', width: 200, hideInTable: roomType === '1' });
|
||
column.push({
|
||
title: '操作', dataIndex: 'option', width: 140, hideInTable: roomType === '1',
|
||
valueType: 'option',
|
||
render: (_: any, record: any) => {
|
||
return (
|
||
<>
|
||
{
|
||
rangeT && record.quoteId != null ? <>
|
||
<Button key='ckfxbj' onClick={() => { queryFxbj(record, tdocId1); }}>查看分项报价</Button>
|
||
</> : null
|
||
}
|
||
{
|
||
!rangeT && record.quoteDecryptStatus == 2 && record.quoteId != null ?
|
||
<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} key='blbj' type="primary" onClick={() => {
|
||
repairVisSet(true);
|
||
formBlbj.setFieldsValue({
|
||
companyName: record.companyName,
|
||
sectionName: record.sectionName,
|
||
tendererId: record.tendererId,
|
||
contentDataId: record.contentDataId,
|
||
newPrice: record.newPrice,
|
||
remark: record.newPriceRemark,
|
||
})
|
||
}} >补录报价</Button>
|
||
: null
|
||
}
|
||
</>
|
||
)
|
||
}
|
||
});
|
||
//拼data
|
||
let haveCompleteT = false;
|
||
res.data.suppliers != undefined ? res.data.suppliers.map((item1: any, index: any) => {
|
||
let oneGys = {};
|
||
signTimeT[item1.bidUserId] = item1.signTime == null ? true : false;//控制显示 确认报价按钮
|
||
item1.signTime == null ? item1.signTime = '未签名' : null;
|
||
oneGys["key"] = index;
|
||
oneGys["companyName"] = item1.companyName;
|
||
oneGys["bidUserName"] = item1.bidUserName + "\n(" + item1.signTime + ")";
|
||
oneGys["sectionName"] = sectionName;
|
||
oneGys["tendererId"] = item1.id;//投标人id,补录报价用
|
||
oneGys["contentDataId"] = item1.quoteId;//数据表id,补录报价用
|
||
oneGys["newPrice"] = item1.newPrice;//数据表id,补录报价用
|
||
oneGys["newPriceRemark"] = item1.newPriceRemark;//数据表id,补录报价用
|
||
oneGys["quoteDecryptStatus"] = item1.quoteDecryptStatus;
|
||
oneGys["quoteId"] = item1.quoteId;
|
||
if (item1.companyId == tenderId) {
|
||
category.map((item2: any, index: any) => {
|
||
oneGys[item2] = item1.dataMap[item2];
|
||
if (!haveCompleteT) {
|
||
haveCompleteT = item1.dataMap[item2] === '解密成功';
|
||
}
|
||
});
|
||
} else {
|
||
category.map((item2: any, index: any) => {
|
||
oneGys[item2] = item1.dataMap[item2];
|
||
});
|
||
}
|
||
tFileT = item1.tfileList;
|
||
data.push(oneGys);
|
||
}) : null;
|
||
|
||
columnsKbSet(column);
|
||
columnsKbDataSet(data);
|
||
tdocIdSet(tdocId1);
|
||
signTimeSet(signTimeT);
|
||
tFileSet(tFileT);
|
||
spinSet(false);
|
||
haveCompleteSet(haveCompleteT);
|
||
}
|
||
queryHaveDataSet(res?.code == 200);
|
||
});
|
||
//查询进度
|
||
// if (!rateVis) {
|
||
// await jmRate({ tdocId: tdocId }).then((res) => {
|
||
// if (res?.code == 200) {
|
||
// let data = res.data;
|
||
// let all: number, comp: number, fail: number, wait: number = 0;
|
||
// if (data != undefined) {
|
||
// all = data['-1'] != undefined ? parseInt(data['-1']) : 0;
|
||
// comp = data['1'] != undefined ? parseInt(data['1']) : 0;
|
||
// fail = data['2'] != undefined ? parseInt(data['2']) : 0;
|
||
// wait = data['0'] != undefined ? parseInt(data['0']) : 0;
|
||
// jmCompleteSet(comp);
|
||
// jmFailSet(fail);
|
||
// jmFileCountSet(all);
|
||
// jmWaitSet(wait);
|
||
// }
|
||
// }
|
||
// });
|
||
// }
|
||
//供应商未唱标结束就轮询 代理唱标结束之前轮询
|
||
if (((juese === 'ebtp-supplier' && !rangeOverT) || (juese === 'ebtp-agency-project-manager' && !rangeOverT)) && !rateVis) {
|
||
setTimeout(() => {
|
||
countSet(count + 1);
|
||
}, time_);
|
||
}
|
||
}
|
||
//开标记录表
|
||
const kbjl = () => {
|
||
return (
|
||
<>
|
||
<div className={styles.titleTop}>
|
||
<div style={{ backgroundColor: 'white' }}><span style={{ letterSpacing: "12px" }}>开标报价记录</span>表</div>
|
||
</div>
|
||
<div className="desStyle">
|
||
<Descriptions bordered column={2} size="small" >
|
||
<Descriptions.Item label="项目名称:" className={styles.desItemStyle} span={2}>{projectName}</Descriptions.Item>
|
||
<Descriptions.Item label="项目编号:" className={styles.desItemStyle}>{projectNo}</Descriptions.Item>
|
||
<Descriptions.Item label={`${showNameT.bd}名称:`} className={styles.desItemStyle}>{sectionName}</Descriptions.Item>
|
||
<Descriptions.Item label={`${showNameT.bd}编号:`} className={styles.desItemStyle}>{sectionNo}</Descriptions.Item>
|
||
<Descriptions.Item label="开标时间:" className={styles.desItemStyle}>{openTime}</Descriptions.Item>
|
||
</Descriptions>
|
||
</div>
|
||
<div className='xsy-table'>
|
||
<ProTable
|
||
actionRef={actionRef}
|
||
columns={columnsKb}//表格
|
||
dataSource={columnsKbData}
|
||
search={false}
|
||
bordered
|
||
size={'small'}
|
||
rowSelection={false}
|
||
// toolBarRender={() => tools}
|
||
pagination={false}
|
||
options={false}
|
||
rowClassName='xsy-table-header'
|
||
/>
|
||
</div>
|
||
</>
|
||
)
|
||
}
|
||
//补录报价
|
||
const [formBlbj] = Form.useForm();
|
||
function checkFive(money: any) {//检查小数点后4位 不能超4位
|
||
let pass = true
|
||
let x = String(money).indexOf('.') + 1; //小数点的位置
|
||
let y = String(money).length - x; //小数的位数
|
||
y > 4 && x != 0 ? pass = false : null;
|
||
return pass
|
||
}
|
||
function moreThan0(val: any) {
|
||
if (val != "--" && val != "++" && val !== "" && val != undefined && !(val < 0)) { return true } else { return false }
|
||
}
|
||
const blbj = () => {
|
||
return (
|
||
<Modal
|
||
title="补录报价"
|
||
width={'800px'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ padding: '32px 40px 48px', overflowY: 'auto' }}
|
||
visible={repairVis}
|
||
onCancel={() => repairVisSet(false)}
|
||
onOk={async () => {
|
||
spinSet(true);
|
||
let verify = false;
|
||
await formBlbj.validateFields().then(() => {
|
||
verify = true;
|
||
if (!checkFive(formBlbj.getFieldsValue().newPrice)) {
|
||
verify = false;
|
||
message.error('报价最多四位小数');
|
||
}
|
||
if (!moreThan0(formBlbj.getFieldsValue().newPrice)) {
|
||
verify = false;
|
||
message.error('报价应大于0');
|
||
}
|
||
})
|
||
if (verify) {
|
||
const { newPrice, contentDataId, tendererId, remark } = formBlbj.getFieldsValue();
|
||
const success = await updatePrice({
|
||
evaluatingContent: newPrice,
|
||
contTid: contentDataId,
|
||
tendererId: tendererId,
|
||
tdocId: tdocId,
|
||
remark: remark,
|
||
tendererName: tendererName,
|
||
// roomType: roomType
|
||
}).then((res) => {
|
||
return res.success
|
||
});
|
||
if (success) {
|
||
message.success('补录成功!');
|
||
repairVisSet(false);
|
||
} else {
|
||
message.error('补录失败!')
|
||
}
|
||
getTableData();
|
||
}
|
||
spinSet(false);
|
||
}}
|
||
>
|
||
<Form
|
||
{...formLayout}
|
||
form={formBlbj}
|
||
>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="companyName"
|
||
label={showNameT.tbdw}
|
||
>
|
||
<Input bordered={false} readOnly />
|
||
</FormItem></Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="sectionName"
|
||
label={showNameT.bd}
|
||
>
|
||
<Input bordered={false} readOnly />
|
||
</FormItem></Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="newPrice"
|
||
label="报价(单位:元)"
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: '当前项不可为空!'
|
||
},
|
||
]}
|
||
>
|
||
<Input type='number' style={{ width: '80%' }} />
|
||
</FormItem></Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="contentDataId"
|
||
label="数据表id"
|
||
hidden={true}
|
||
>
|
||
<Input />
|
||
</FormItem></Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="tendererId"
|
||
label={`${showNameT.tbr}id`}
|
||
hidden={true}
|
||
>
|
||
<Input />
|
||
</FormItem></Col>
|
||
</Row>
|
||
<Row>
|
||
<Col span={22}><FormItem
|
||
name="remark"
|
||
label="备注"
|
||
>
|
||
<TextArea style={{ width: '80%' }} />
|
||
</FormItem></Col>
|
||
</Row>
|
||
</Form>
|
||
</Modal>
|
||
)
|
||
}
|
||
//解密进度
|
||
const jmjd = () => {
|
||
return (
|
||
<Modal
|
||
title="解密进度"
|
||
width={'800px'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ padding: '32px 40px 48px', overflowY: 'auto' }}
|
||
visible={rateVis}
|
||
footer={false}
|
||
onCancel={() => { countSet(count + 1); handleRateVis(false); }}
|
||
>
|
||
<Card bordered={false} style={{ textAlign: 'center', fontSize: '30px', }}>
|
||
{(jmComplete + jmFail == jmFileCount && jmFileCount !== 0) ? `解 密 结 束` : `正 在 解 密...`}
|
||
</Card>
|
||
<Progress percent={Math.floor((jmComplete / jmFileCount) * 100)} status="active" />
|
||
|
||
<div style={{ textAlign: "center" }}>
|
||
文件总数:<span style={{ fontSize: 30, color: 'rgb(0,144,255)' }}>{jmFileCount}</span> 个
|
||
</div>
|
||
<div style={{ textAlign: "center" }}>
|
||
解密成功:<span style={{ fontSize: 30, color: 'rgb(61,169,92)' }}>{jmComplete}</span> 个,
|
||
{/* 排队解密中:<span style={{ fontSize: 30, color: 'red' }}>{100 - rate}</span> 个, */}
|
||
{isJm == 1 ? '正在解密' : '尚未解密'}:<span style={{ fontSize: 30, color: 'rgb(0,144,255)' }}>{jmWait}</span> 个,
|
||
解密失败:<span style={{ fontSize: 30, color: 'red' }}>{jmFail}</span> 个
|
||
</div>
|
||
</Modal>
|
||
)
|
||
}
|
||
//分项报价表
|
||
const [fxData, fxDataSet] = useState<any>([{}]);
|
||
const [columnsFx, columnsFxSet] = useState<any>([]);
|
||
async function queryFxbj(record: any, id: any) {
|
||
// const [tendererId] = record;
|
||
// queryFx({tendererId:tendererId,tdocId:tdocId,tdocCatalogId:'1319439263309234001'}).then(()=>{
|
||
|
||
let columnfx: any = [];
|
||
let fxData: any = [];
|
||
await queryFx({ tendererId: record.tendererId, tdocId: id, tdocCatalogId: record.tdocCatalogId }).then((res) => {
|
||
if (res.code == 200) {
|
||
//拼表格
|
||
columnfx.push({ title: '序号', dataIndex: 'index', valueType: 'index' });
|
||
res.data.itemPriceTitle.map((item: any, index: any) => {
|
||
columnfx.push({ title: item.name, dataIndex: item.id, key: index });
|
||
});
|
||
|
||
//拼数据
|
||
let fxIndex = 0;
|
||
const priD = res.data.itemPriceData;
|
||
for (const key in priD) {
|
||
let one = {};
|
||
one["key"] = fxIndex;
|
||
for (const key2 in priD[key]) {
|
||
one[`${key2}`] = priD[key][key2]['evaluatingContent'];
|
||
}
|
||
fxIndex = fxIndex + 1;
|
||
fxData.push(one);
|
||
}
|
||
fxDataSet(fxData);
|
||
gysIdSet(record.tendererId);
|
||
handleSubentryVis(true);
|
||
}
|
||
});
|
||
columnsFxSet(columnfx);
|
||
|
||
}
|
||
const fxbj = () => {
|
||
return (
|
||
<Modal
|
||
title="分项报价表"
|
||
width={'60%'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto', paddingTop: '0px' }}
|
||
visible={subentryVis}
|
||
footer={false}
|
||
onCancel={() => { handleSubentryVis(false); fxDataSet([]) }}
|
||
>
|
||
<ProTable
|
||
columns={columnsFx}//表格
|
||
dataSource={fxData}
|
||
search={false}
|
||
size={'small'}
|
||
rowSelection={false}
|
||
options={false}
|
||
// pagination={{ defaultPageSize: 10 }}//默认显示条数
|
||
toolBarRender={() => [
|
||
<FileDown apiUrl={`/api/biz-service-ebtp-resps/v1/tfile/exportItemPriceByTendererId?tdocId=${tdocId}&tendererId=${gysId}`} btnName='导出分项报价' />
|
||
]}
|
||
pagination={false}//默认显示条数
|
||
/>
|
||
</Modal>
|
||
)
|
||
}
|
||
|
||
//解密时限
|
||
function onOkJmsx(value: any) {
|
||
endTimeSet(value.format('yyyy-MM-DD HH:mm:ss'));
|
||
}
|
||
const [sxLoading, sxLoadingSet] = useState<boolean>(false);
|
||
const jmTime = () => {
|
||
return (
|
||
<Modal
|
||
title="设置解密时限"
|
||
width={'400px'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ overflowY: 'auto' }}
|
||
visible={jmTimeVis}
|
||
okButtonProps={{ disabled: sxLoading }}
|
||
onCancel={() => { jmTimeVisSet(false); }}
|
||
onOk={async () => {
|
||
sxLoadingSet(true);
|
||
if (endTime != '') {
|
||
await endTimeConfig({ id: tdocId, decryptEndDate: endTime });
|
||
jmTimeVisSet(false);
|
||
} else {
|
||
message.error('您未设置解密截止时间')
|
||
}
|
||
sxLoadingSet(false);
|
||
countSet(count + 1);
|
||
}}
|
||
>
|
||
<Spin spinning={sxLoading}>
|
||
解密截止时间:
|
||
<DatePicker
|
||
format="YYYY-MM-DD HH:mm:ss"
|
||
disabledDate={disabledDate}
|
||
showTime={{ defaultValue: moment('00:00:00', 'HH:mm:ss') }}
|
||
// disabled={disabled}
|
||
showNow={false}
|
||
onOk={onOkJmsx}
|
||
/>
|
||
</Spin>
|
||
</Modal>
|
||
)
|
||
}
|
||
function disabledDate(current: any) {//日期选择
|
||
// Can not select days before today and today
|
||
return current && current < moment().startOf('day');
|
||
}
|
||
//未开标
|
||
let height = document.body.clientHeight - 56;
|
||
// function notOpen() {
|
||
// return (
|
||
// <div style={{ width: '100%', height: `${height}px`, paddingTop: `${0.4 * height}px`, backgroundColor: 'white', textAlign: 'center' }}>
|
||
// <div style={{}}>暂未开标</div>
|
||
// </div>
|
||
// )
|
||
// }
|
||
//下载应答文件
|
||
const [downFileVis, downFileVisSet] = useState(false);//下载文件modal vis
|
||
const [downFileBodyVis, downFileBodyVisSet] = useState(false);//下载文件modal vis
|
||
const [downFileData, downFileDataSet] = useState<any>([]);//下载文件表格数据
|
||
const downFileColumn: ProColumns<any>[] = [
|
||
{
|
||
title: '序号',
|
||
dataIndex: 'index',
|
||
valueType: 'index'
|
||
},
|
||
{
|
||
title: '供应商名称',
|
||
dataIndex: 'companyName',
|
||
valueType: 'text'
|
||
},
|
||
{
|
||
title: '解密状态',
|
||
dataIndex: downFileData[0]?.quoteOrOther as string == '1' ? "decryptOtherStatus" : "decryptStatus",
|
||
valueEnum: {
|
||
"1": { text: "未解密" },
|
||
"2": { text: "解密成功" },
|
||
"3": { text: "解密失败" },
|
||
}
|
||
},
|
||
{
|
||
title: '操作',
|
||
valueType: 'option',
|
||
render: (text: any, record: any) => {
|
||
let btn = null;
|
||
let status = downFileData[0]?.quoteOrOther as string == '1' ? record.decryptOtherStatus : record.decryptStatus;
|
||
if (status == '2') {
|
||
btn = <Button
|
||
type="text"
|
||
onClick={() => download(record?.filePath, record?.companyName, record)}
|
||
icon={<DownloadOutlined />}
|
||
>
|
||
下载
|
||
</Button>
|
||
}
|
||
return btn;
|
||
}
|
||
|
||
}
|
||
];
|
||
/*下载*/
|
||
const download = async (filePath: any, filename: any, record: any) => {
|
||
// downFileBodyVisSet(true);
|
||
// await selectParam1({ "tdocId": tdocId, "tendererId": record.id }).then((res) => {
|
||
// if (res?.code == 200) {
|
||
// selectParam2({ "data": res?.data || [], "name": filename, "path": filePath }).then((res2) => {
|
||
// let key = res2?.key
|
||
// if (key != undefined && key != null && key.length > 0) {
|
||
// window.location.href = "/api/core-service-ebtp-updownload/v1/hulk/pull/" + res2.key;
|
||
// } else {
|
||
// message.error("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
// })
|
||
// } else {
|
||
// message.error("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
// }).finally(() => {
|
||
// setTimeout(() => {
|
||
// downFileBodyVisSet(false);
|
||
// }, 1000);
|
||
// });
|
||
window.location.href = `/api/core-service-ebtp-updownload/v1/hulk/downloadFromResp/${tdocId}?n=${filename}&tendererId=${record.id}&tendererName=${record.companyName}`;
|
||
}
|
||
/*打包下载*/
|
||
const downloadPak = async (filePath: any, filename: any, id?: any) => {
|
||
// downFileBodyVisSet(true);
|
||
// await selectParam1({ "tdocId": tdocId }).then((res) => {
|
||
// if (res?.code == 200) {
|
||
// selectParam2({ "data": res?.data || [], "name": filename, "path": filePath }).then((res2) => {
|
||
// let key = res2?.key
|
||
// if (key != undefined && key != null && key.length > 0) {
|
||
// window.location.href = "/api/core-service-ebtp-updownload/v1/hulk/pull/" + res2.key;
|
||
// } else {
|
||
// message.error("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
// })
|
||
// } else {
|
||
// message.error("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
// }).finally(() => {
|
||
// setTimeout(() => {
|
||
// downFileBodyVisSet(false)
|
||
// }, 1000);
|
||
// });
|
||
window.location.href = `/api/core-service-ebtp-updownload/v1/hulk/downloadFromResp/${tdocId}?n=${filename}`;
|
||
}
|
||
//获取下载应答文件接口数据
|
||
async function getFownFileData() {
|
||
spinSet(true);
|
||
await getBiddingDocumentsDecryptList(assessRoomId).then((res) => {
|
||
if (res.code == 200) {
|
||
downFileDataSet(res?.data);
|
||
downFileVisSet(true);
|
||
}
|
||
}).finally(() => spinSet(false));
|
||
}
|
||
const downFile = useMemo(() => {
|
||
let modal;
|
||
if (downFileVis) {
|
||
modal = <Modal
|
||
title={`下载${showNameT.tb}文件`}
|
||
width={'60%'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto', paddingTop: '0px' }}
|
||
visible={downFileVis}
|
||
footer={<Button type='primary' onClick={() => downFileVisSet(false)}>关闭</Button>}
|
||
onCancel={() => downFileVisSet(false)}
|
||
>
|
||
<Spin spinning={downFileBodyVis} tip='正在生成供应商资质类文件,请稍等...'>
|
||
<ProTable
|
||
columns={downFileColumn}//表格
|
||
dataSource={downFileData[0].registerInfoVOList}
|
||
search={false}
|
||
size={'small'}
|
||
rowSelection={false}
|
||
options={false}
|
||
pagination={false}//默认显示条数
|
||
toolBarRender={() => [
|
||
<Button type='primary' onClick={() => downloadPak(downFileData[0]?.filepath, downFileData[0]?.filename, downFileData[0]?.id)}>打包下载</Button>,
|
||
]}
|
||
/>
|
||
</Spin>
|
||
</Modal>
|
||
} else {
|
||
modal = null
|
||
}
|
||
return modal;
|
||
}, [downFileVis, downFileBodyVis]);
|
||
|
||
return (
|
||
<>
|
||
<div className={styles.header}>
|
||
<div className={styles.headerAlign}>
|
||
<img src={logo} style={{ height: '30px' }} />
|
||
<span style={{ marginLeft: '10px', height: '30px' }}>招标采购中心 | 电子开标室</span>
|
||
</div>
|
||
</div>
|
||
<Spin spinning={spin} size='large' tip='正在查询,请您耐心等待。。。'>
|
||
<div style={{ width: '100%', height: `${height}px`, backgroundColor: 'white', padding: '24px 0px 24px 0px' }}>
|
||
<div className='xsy-tools-div'><div style={{ float: 'right' }}>{queryHaveData && tools}</div></div>
|
||
{
|
||
openState &&
|
||
<div>
|
||
{/* 开标记录表 */}
|
||
{kbjl()}
|
||
{/* 补录报价 */}
|
||
{blbj()}
|
||
{/* 解密进度 */}
|
||
{jmjd()}
|
||
{/* 分项报价 */}
|
||
{fxbj()}
|
||
{/* 解密时限 */}
|
||
{jmTime()}
|
||
{/* 下载应答文件 */}
|
||
{downFile}
|
||
</div>
|
||
}
|
||
</div>
|
||
</Spin>
|
||
</>
|
||
)
|
||
};
|
||
export default Room; |