502 lines
19 KiB
TypeScript
502 lines
19 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
||
import { Button, Card, DatePicker, Divider, Form, List, message, Modal, Popover, Progress, Spin, Typography } from "antd";
|
||
import ProForm, {
|
||
ModalForm,
|
||
ProFormDateTimePicker,
|
||
} from '@ant-design/pro-form';
|
||
import ProTable from "@ant-design/pro-table";
|
||
import {
|
||
AlertOutlined,
|
||
ClockCircleOutlined,
|
||
DownloadOutlined,
|
||
ExclamationCircleOutlined,
|
||
FullscreenExitOutlined,
|
||
InfoCircleOutlined,
|
||
UnorderedListOutlined
|
||
} from "@ant-design/icons";
|
||
import {
|
||
getBiddingDocumentsDecryptList,
|
||
DownFile,
|
||
decryptFile,
|
||
decryptFileType,
|
||
getBiddingDocumentsDecryptListOther, setEndTime, endTimeUp, selectParam1, selectParam2
|
||
} from "./service"
|
||
import { getDefId, getProMethod, getRoomId, getSessionProjectData, getSessionUserData } from "@/utils/session";
|
||
import request from "umi-request";
|
||
import moment from "moment";
|
||
import "@/assets/xsy_style.less";
|
||
import { btnAuthority } from "@/utils/authority";
|
||
import { numberToChinese } from '@/utils/CommonUtils';
|
||
import { checkObjectId } from '@/utils/DownloadUtils';
|
||
|
||
interface BiddingDocumentsDecryptProps {
|
||
|
||
}
|
||
|
||
const BiddingDocumentsDecrypt: React.FC<BiddingDocumentsDecryptProps> = (props) => {
|
||
|
||
let proMsg = getSessionProjectData();
|
||
|
||
const [form] = Form.useForm();
|
||
// /*投标文件查看*/
|
||
const [pageloading, setPageloading] = useState<boolean>(false);
|
||
const [spin, spinSet] = useState<any>(false);
|
||
|
||
const [rateVis, handleRateVis] = useState<boolean>(false); //进度显隐
|
||
const [rateCount, rateCountSet] = useState<number>(0); //查询进度启动器
|
||
const [jmComplete, jmCompleteSet] = useState<number>(0);//已解密成功
|
||
const [jmFail, jmFailSet] = useState<number>(0);//解密失败
|
||
const [jmWait, jmWaitSet] = useState<number>(0);//未解密
|
||
const [jmFileCount, jmFileCountSet] = useState<number>(0);//文件总数
|
||
const [tdocId, tdocIdSet] = useState<any>('');//tdocId
|
||
const [jmTimeVis, jmTimeVisSet] = useState<boolean>(false);//解密时限显隐
|
||
const [endTime, endTimeSet] = useState<any>('');//解密时限
|
||
const [endTimeVis, endTimeVisSet] = useState<boolean>(true);//解密时限提示显隐
|
||
const [endTimeModalType, setEndTimeModalType] = useState<boolean>(false);
|
||
|
||
const [PageRefresh, setPageRefresh] = useState<any>(0);//页面刷新
|
||
|
||
const [ListData, setListData] = useState<any>();
|
||
const [downFileBodyVis, downFileBodyVisSet] = useState<boolean>(false);//下载文件 打包下载文件loading
|
||
const [spinTip, spinTipSet] = useState<string>('请稍等...');//spin tip显示文字
|
||
|
||
const MethodDict = getProMethod();
|
||
const { Title, Text } = Typography;
|
||
//应答字段类型 评标,应答
|
||
let responseType = MethodDict == "procurement_mode_1" || MethodDict == "procurement_mode_2" ? "投标" : "应答"
|
||
let supplierType = MethodDict == "procurement_mode_1" || MethodDict == "procurement_mode_2" ? "投标人" : "供应商"
|
||
useEffect(() => {
|
||
let roomId = getRoomId();
|
||
if (roomId != "" && roomId != undefined) {
|
||
if (getProMethod() == "procurement_mode_4") {
|
||
getBiddingDocumentsDecryptListOther(roomId).then(res => {
|
||
if (res?.code == 200) {
|
||
setListData(res?.data);
|
||
tdocIdSet(res?.data[0].id);
|
||
}
|
||
})
|
||
} else {
|
||
getBiddingDocumentsDecryptList(roomId).then(res => {
|
||
if (res?.code == 200) {
|
||
setListData(res?.data);
|
||
tdocIdSet(res?.data[0].id);
|
||
}
|
||
})
|
||
}
|
||
|
||
} else {
|
||
message.warn("未获取到评审室id,请您稍后再试!");
|
||
}
|
||
|
||
}, [PageRefresh])
|
||
|
||
/*查看*/
|
||
const OpenWindow = (record: any, docid: any) => {
|
||
window.open("/viewOfTenderDocuments?tdocid=" + docid + "&tendererId=" + record.id);
|
||
}
|
||
|
||
/*下载*/
|
||
const download = (filePath: any, filename: any, record: any, id: any) => {
|
||
// spinTipSet('供应商资质文件与下载链接生成中,请稍等...');
|
||
// downFileBodyVisSet(true);
|
||
// 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("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
// })
|
||
// }
|
||
// }).finally(() => {
|
||
// downFileBodyVisSet(false);
|
||
// })
|
||
window.location.href = `/api/core-service-ebtp-updownload/v1/hulk/downloadFromResp/${id}?n=${filename}&tendererId=${record.id}&tendererName=${record.companyName}`;
|
||
}
|
||
/*打包下载*/
|
||
const downloadPak = (filePath: any, filename: any, id?: any) => {
|
||
// spinTipSet('供应商资质文件与下载链接生成中,请稍等...');
|
||
// downFileBodyVisSet(true);
|
||
// 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("请求文档中心失败!请您稍后再试。")
|
||
// }
|
||
|
||
|
||
// })
|
||
// }
|
||
// }).finally(() => {
|
||
// downFileBodyVisSet(false);
|
||
// })
|
||
window.location.href = `/api/core-service-ebtp-updownload/v1/hulk/downloadFromResp/${id}?n=${filename}`;
|
||
}
|
||
/*提交解密截止时间*/
|
||
const OnFinshTime = () => {
|
||
form.validateFields().then(res => {
|
||
}).catch(res => {
|
||
message.warn("您有未填写的选项!")
|
||
|
||
})
|
||
|
||
}
|
||
|
||
/*设置解密时间*/
|
||
const setDecryptionTime = (record?: any) => {
|
||
return (
|
||
<ModalForm
|
||
title="设置解密截止时间"
|
||
width={300}
|
||
trigger={
|
||
<Button type="primary" disabled={record?.decryptStatus}>
|
||
设置解密截止时间
|
||
</Button>
|
||
}
|
||
modalProps={{
|
||
onCancel: () => { },
|
||
}}
|
||
onFinish={async (values) => {
|
||
let msg;
|
||
await setEndTime({ id: record?.id, decryptEndDate: values?.decryptEndDate }).then(res => {
|
||
if (res.code == 200) {
|
||
message.success('提交成功');
|
||
msg = true;
|
||
} else {
|
||
msg = false;
|
||
}
|
||
})
|
||
return msg;
|
||
}}
|
||
>
|
||
<ProFormDateTimePicker name="decryptEndDate" />
|
||
</ModalForm>
|
||
);
|
||
}
|
||
/*解密*/
|
||
const decrypt = (record: any) => {
|
||
spinTipSet('正在查询解密进度,请稍等...');
|
||
downFileBodyVisSet(true);
|
||
/*发起解密*/
|
||
decryptFile({ tdocId: record }).then(res => {
|
||
if (res?.code == 200) {
|
||
handleRateVis(true);
|
||
rateCountSet(rateCount + 1);
|
||
}
|
||
}).finally(() => {
|
||
downFileBodyVisSet(false);
|
||
})
|
||
}
|
||
//查询进度
|
||
useEffect(() => {
|
||
if (rateVis) {
|
||
queryRate();
|
||
setTimeout(async () => {
|
||
rateCountSet(rateCount + 1);
|
||
}, 2000);
|
||
}
|
||
}, [rateCount]);
|
||
|
||
async function queryRate() {//查询解密进度
|
||
await decryptFileType({ tdocId: tdocId }).then((res) => {
|
||
// if (data != undefined) {
|
||
if (res?.code == 200) {
|
||
let data = res.data;
|
||
let all: number, comp: number, fail: number, wait: 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;
|
||
jmCompleteSet(comp);
|
||
jmFailSet(fail);
|
||
jmFileCountSet(all);
|
||
jmWaitSet(wait);
|
||
// comp == all && setTimeout(() => {//全解密 成功自动关窗
|
||
// handleRateVis(false);
|
||
// }, 1000);
|
||
}
|
||
});
|
||
}
|
||
|
||
const queryDecrypt = async (tdocid: any) => {
|
||
let msg = true;
|
||
await decryptFileType({ tdocId: tdocid }).then(res => {
|
||
if (res?.code == 200) {
|
||
let data = res.data;
|
||
if (data != undefined) {
|
||
let quanbu = data['-1'] != undefined ? data['-1'] : 0;//6
|
||
let yijie = data['1'] != undefined ? data['1'] : 0;//6
|
||
let shibai = data['2'] != undefined ? data['2'] : 0;
|
||
let weijie = data['0'] != undefined ? data['0'] : 0;// //6
|
||
if (weijie > 0) {
|
||
msg = false;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
return msg;
|
||
}
|
||
/*===========================*/
|
||
/*===========================*/
|
||
|
||
//解密时限
|
||
function onOkJmsx(value: any) {
|
||
endTimeSet(value.format('yyyy-MM-DD HH:mm:ss'));
|
||
}
|
||
|
||
function returnJmBtn() {
|
||
if (ListData[0].decryptEndDate !== '' && ListData[0].decryptEndDate !== null) {
|
||
return <div key='jmsxTip' className='mR8 xsy-red floatLeft h32 ftSz20'
|
||
hidden={ListData[0].decryptEndDate == null}>{supplierType}解密时限: {ListData[0].decryptEndDate}</div>
|
||
} else {
|
||
return <Button key='jmsx' className='mR8' type="primary" onClick={() => {
|
||
jmTimeVisSet(true)
|
||
}}>开启解密</Button>
|
||
}
|
||
|
||
}
|
||
|
||
const jmTime = () => {
|
||
return (
|
||
<>
|
||
<Modal
|
||
title="设置解密时限"
|
||
width={'400px'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ overflowY: 'auto' }}
|
||
visible={jmTimeVis}
|
||
onCancel={() => {
|
||
jmTimeVisSet(false);
|
||
}}
|
||
okButtonProps={{ disabled: spin }}
|
||
onOk={async () => {
|
||
if (endTime != '') {
|
||
spinSet(true);
|
||
await endTimeUp({ id: tdocId, decryptEndDate: endTime }).then(res => {
|
||
if (res.success) {
|
||
message.success('设置成功');
|
||
}
|
||
});
|
||
spinSet(false);
|
||
jmTimeVisSet(false);
|
||
} else {
|
||
message.error('您未设置解密截止时间')
|
||
}
|
||
setPageRefresh(PageRefresh + 1);
|
||
}}
|
||
>
|
||
<Spin spinning={spin}>
|
||
解密截止时间:
|
||
<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');
|
||
}
|
||
/**20210330新增 公开招标 邀请招标 公开比选一阶段 不显示轮次文字*/
|
||
/**20211112修改 只有竞争性谈判和单一来源显示轮次,其他采购方式不显示 */
|
||
let headType = false;
|
||
let defId = getDefId();
|
||
if (MethodDict == "procurement_mode_5" || MethodDict == "procurement_mode_6") {
|
||
headType = true;
|
||
}
|
||
/**end*/
|
||
/**20210330新增 轮次信息 即同意轮次下可有多条信息 quoteOrOther 0-报价 1-应答文件 quoteOrOther=1 取registerInfoVOList里 decryptOtherStatus*/
|
||
const getMsg = (Code?: any) => {
|
||
let msg = ""
|
||
if (Code == "0") {
|
||
msg = ":报价";
|
||
} else if (Code == "1") {
|
||
msg = ":应答文件"
|
||
}
|
||
return msg
|
||
}
|
||
/**end*/
|
||
return (
|
||
<Card>
|
||
<Spin spinning={downFileBodyVis} tip={spinTip}>
|
||
<List
|
||
itemLayout="vertical"
|
||
dataSource={ListData}
|
||
renderItem={(item: any) => (
|
||
<ProTable
|
||
headerTitle={headType ? "第" + numberToChinese(item.turnSort) + "轮" + getMsg(item.quoteOrOther) : null}
|
||
size={"small"}
|
||
loading={pageloading}
|
||
toolBarRender={() => [
|
||
proMsg.isIPassDecode == 0 ?
|
||
// setDecryptionTime(item) :
|
||
returnJmBtn() :
|
||
(<Button hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} disabled={!item.decryptStatus} type="primary" onClick={() => {
|
||
tdocIdSet(item.id);
|
||
decrypt(item.id)
|
||
}}>解密</Button>),
|
||
<Button disabled={item?.registerInfoVOList?.findIndex((e: any) => {
|
||
if (item.quoteOrOther == "1") {
|
||
return e.decryptOtherStatus == "1"
|
||
} else {
|
||
return e.decryptStatus == "1"
|
||
}
|
||
}) != -1} onClick={() => downloadPak(item.filepath, item.filename, item.id)}> 打包下载</Button>,
|
||
// <Button> 下载说明</Button>,
|
||
]}
|
||
|
||
search={false}
|
||
options={false}
|
||
columns={[
|
||
{
|
||
title: '序号',
|
||
dataIndex: 'index',
|
||
valueType: 'index'
|
||
},
|
||
{
|
||
title: '供应商名称',
|
||
dataIndex: 'companyName',
|
||
valueType: 'text',
|
||
render: (_: any, record: any, index: any) => (
|
||
<>
|
||
{_}
|
||
<Popover
|
||
content={
|
||
<Typography style={{ width: "352px" }}>
|
||
<Text style={{ display: 'block', color: "rgb(245,156,38)" }}>温馨提示:</Text>
|
||
<Text >该供应商成立日期为<Text underline>{record?.supplierCreatetime && record?.supplierCreatetime.foundTime}</Text>,距评标时间不足一年,请结合招标文件/采购文件的投标人资格要求,仔细核对供应商应当具备的企业资质。</Text>
|
||
</Typography>
|
||
}
|
||
>
|
||
{(record?.supplierCreatetime && record?.supplierCreatetime.toOpenbidTime === 0) && <AlertOutlined style={{ color: "rgb(245,156,38)", marginLeft: 6 }} />}
|
||
</Popover>
|
||
{record?.supplierCreatetime && record?.supplierCreatetime.foundTime === null ? (
|
||
<Popover
|
||
content={
|
||
<Typography>
|
||
<Text style={{ display: 'block', color: "rgb(245,156,38)" }}>温馨提示:</Text>
|
||
<Text>未查询到成立时间</Text>
|
||
</Typography>
|
||
}
|
||
>
|
||
<InfoCircleOutlined style={{ color: "rgb(245,156,38)", marginLeft: 6 }} />
|
||
</Popover>
|
||
) : null}
|
||
</>
|
||
)
|
||
},
|
||
{
|
||
title: (
|
||
<span>
|
||
同意MAC地址检测承诺书时间
|
||
<Popover
|
||
content={
|
||
<Typography>
|
||
<Title level={5}>承诺书内容:</Title>
|
||
<Text style={{ display: 'inline-block', textIndent: '2em' }}>已阅读并承诺在采购招标过程中,不存在围标、串标行为。同意中国联通公司对参与供应商进行IP、MAC地址校验,如不同供应商的MAC地址相同,评标/评审委员会(或采购人)将按围标、串标处理。</Text>
|
||
</Typography>
|
||
}
|
||
overlayInnerStyle={{ width: 400 }}
|
||
>
|
||
<ExclamationCircleOutlined style={{ color: '#b30000', marginLeft: 4 }} />
|
||
</Popover>
|
||
</span>
|
||
),
|
||
dataIndex: 'confirmTime',
|
||
valueType: 'text'
|
||
},
|
||
{
|
||
title: '解密状态',
|
||
dataIndex: item.quoteOrOther == "1" ? 'decryptOtherStatus' : "decryptStatus",
|
||
valueType: 'text',
|
||
valueEnum: {
|
||
"1": { text: "未解密" },
|
||
"2": { text: "解密成功" },
|
||
"3": { text: "解密失败" },
|
||
}
|
||
},
|
||
{
|
||
title: '操作',
|
||
// valueType: 'option',
|
||
render: (text: any, record: any) => {
|
||
let disabled = false
|
||
if (item.quoteOrOther == "1") {
|
||
if (record.decryptOtherStatus != 2) {
|
||
disabled = true;
|
||
}
|
||
} else {
|
||
if (record.decryptStatus != 2) {
|
||
disabled = true;
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Button disabled={disabled} type="text"
|
||
onClick={() => download(record?.filePath, headType ? record?.companyName + "第" + item.turnSort + "轮" + responseType + "文件" : record?.companyName + responseType + "文件", record, item?.id)}
|
||
icon={<DownloadOutlined />}>下载</Button>
|
||
{checkObjectId(record.id) && <Button disabled={disabled} type="text" onClick={() => OpenWindow(record, item?.id)}
|
||
icon={<DownloadOutlined />}>查看</Button>}
|
||
</>
|
||
);
|
||
}
|
||
|
||
}
|
||
]}
|
||
dataSource={item.registerInfoVOList}
|
||
pagination={{
|
||
defaultPageSize: 10
|
||
}}
|
||
/>
|
||
)}
|
||
/>
|
||
</Spin>
|
||
<Modal
|
||
title="解密进度"
|
||
width={'800px'}
|
||
destroyOnClose
|
||
centered
|
||
bodyStyle={{ padding: '32px 40px 48px', overflowY: 'auto' }}
|
||
visible={rateVis}
|
||
footer={false}
|
||
onCancel={() => {
|
||
handleRateVis(false);
|
||
setPageRefresh(PageRefresh + 1)
|
||
}}
|
||
|
||
>
|
||
<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> 个, */}
|
||
尚未解密:<span style={{ fontSize: 30, color: 'rgb(0,144,255)' }}>{jmWait}</span> 个,
|
||
解密失败:<span style={{ fontSize: 30, color: 'red' }}>{jmFail}</span> 个
|
||
</div>
|
||
</Modal>
|
||
{jmTime()}
|
||
</Card>
|
||
)
|
||
}
|
||
export default BiddingDocumentsDecrypt
|