Merge branch 'release_electronic_bid_evaluation_room' into 'release_20230102'
1.6 电子评标室 See merge request eshop/fe_service_ebtp_frontend!112
This commit is contained in:
@ -3,7 +3,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
||||
import '../style.less'
|
||||
import { authCheck, ModalList, onCell, onHeaderCell, OverviewItem, ScreenLabel, ScreenTitle, ScrollTable } from '../Home';
|
||||
import Circle3199 from '@/assets/monitor/circle-3199.png';
|
||||
import { getDecryptDataAPI, getNoOpenAssessListAPI, getNoOpenListAPI, getNoOpenNumberAPI, getThreeDayNoEndAPI, getThreeDayNoEndCountAPI, getThreeDaysUnSendAnnoCountAPI, getThreeDaysUnSendAnnoListAPI } from '../service';
|
||||
import { getDecryptDataAPI, getNoOpenAssessListAPI, getNoOpenAssessNumberAPI, getNoOpenListAPI, getNoOpenNumberAPI, getThreeDayNoEndAPI, getThreeDayNoEndCountAPI, getThreeDaysUnSendAnnoCountAPI, getThreeDaysUnSendAnnoListAPI } from '../service';
|
||||
import { isNotEmpty } from '@/utils/CommonUtils';
|
||||
|
||||
const MonitorException: React.FC<{}> = () => {
|
||||
@ -16,7 +16,9 @@ const MonitorException: React.FC<{}> = () => {
|
||||
//超过1小时未开标数量-列表
|
||||
const [noOpenListData, setNoOpenListData] = useState<any[]>([]);
|
||||
//开标后超过6小时未开启评审室-列表
|
||||
const [noOpenAssessListData, setNoOpenAssessListData] = useState<any>();
|
||||
const [noOpenAssessListData, setNoOpenAssessListData] = useState<any[]>([]);
|
||||
//开标后超过6小时未开启评审室-数量
|
||||
const [noOpenAssessNumber, setNoOpenAssessNumber] = useState<string | number>(0);
|
||||
//异常监控-解密异常、mac地址相同及相关项目列表
|
||||
const [decryptData, setDecryptData] = useState<any>();
|
||||
//评审室关闭3日内未发布公示数
|
||||
@ -29,6 +31,8 @@ const MonitorException: React.FC<{}> = () => {
|
||||
const [modalListData, setModalListData] = useState<any[]>([]);
|
||||
//ModalList Type
|
||||
const [exceptionType, setExceptionType] = useState<any>();
|
||||
//selectKey
|
||||
const [selectKey, setSelectKey] = useState<number>(-1);
|
||||
//权限校验
|
||||
const auth = useRef<boolean>(authCheck());
|
||||
//超过1小时未开标数量
|
||||
@ -57,17 +61,52 @@ const MonitorException: React.FC<{}> = () => {
|
||||
}
|
||||
//开标后超过6小时未开启评审室-列表
|
||||
const getNoOpenAssessList = () => {
|
||||
getNoOpenAssessListAPI({ pageNo: 1, pageSize: 100 }).then(res => {
|
||||
getNoOpenAssessListAPI({ "timeLimit": "6", "dayNumber": "30" }).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setNoOpenAssessListData(res?.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
//异常监控-解密异常、mac地址相同及相关项目列表
|
||||
|
||||
//开标后超过6小时未开启评审室-数量
|
||||
const getNoOpenAssessNumber = () => {
|
||||
getNoOpenAssessNumberAPI({ "timeLimit": "6", "dayNumber": "30" }).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setNoOpenAssessNumber(res?.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
//异常监控-解密异常、mac地址相同及相关项目列表jectRecord?
|
||||
const getDecryptData = () => {
|
||||
getDecryptDataAPI().then(res => {
|
||||
if (res?.code == 200) {
|
||||
setDecryptData(res?.data);
|
||||
const data = res?.data;
|
||||
if (data?.decryptExceptionList?.length > 0) {
|
||||
for (let i = 0, length = data.decryptExceptionList.length; i < length; i++) {
|
||||
data.decryptExceptionList[i]["regionDictName"] = data.decryptExceptionList[i].projectRecord?.regionDictName;
|
||||
data.decryptExceptionList[i]["projectName"] = data.decryptExceptionList[i].projectRecord?.projectName;
|
||||
data.decryptExceptionList[i]["ownerContactName"] = data.decryptExceptionList[i].projectRecord?.ownerContactName;
|
||||
data.decryptExceptionList[i]["ownerContactTel"] = data.decryptExceptionList[i].projectRecord?.ownerContactTel;
|
||||
data.decryptExceptionList[i]["tenderAgencyName"] = data.decryptExceptionList[i].projectRecord?.tenderAgencyName;
|
||||
data.decryptExceptionList[i]["appManagerTel"] = data.decryptExceptionList[i].projectRecord?.appManagerTel;
|
||||
data.decryptExceptionList[i]["recruitStartTime"] = data.decryptExceptionList[i].projectRecord?.recruitStartTime;
|
||||
data.decryptExceptionList[i]["bidMethodDict"] = data.decryptExceptionList[i].projectRecord?.bidMethodDict;
|
||||
}
|
||||
|
||||
}
|
||||
if (data?.macSameList?.length > 0) {
|
||||
for (let i = 0, length = data.macSameList.length; i < length; i++) {
|
||||
data.macSameList[i]["regionDictName"] = data.macSameList[i].projectRecord?.regionDictName;
|
||||
data.macSameList[i]["projectName"] = data.macSameList[i].projectRecord?.projectName;
|
||||
data.macSameList[i]["ownerContactName"] = data.macSameList[i].projectRecord?.ownerContactName;
|
||||
data.macSameList[i]["ownerContactTel"] = data.macSameList[i].projectRecord?.ownerContactTel;
|
||||
data.macSameList[i]["tenderAgencyName"] = data.macSameList[i].projectRecord?.tenderAgencyName;
|
||||
data.macSameList[i]["appManagerTel"] = data.macSameList[i].projectRecord?.appManagerTel;
|
||||
data.macSameList[i]["recruitStartTime"] = data.macSameList[i].projectRecord?.recruitStartTime;
|
||||
data.macSameList[i]["bidMethodDict"] = data.macSameList[i].projectRecord?.bidMethodDict;
|
||||
}
|
||||
}
|
||||
setDecryptData(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -104,12 +143,43 @@ const MonitorException: React.FC<{}> = () => {
|
||||
getThreeDayNoEnd();
|
||||
getNoOpenList();
|
||||
getNoOpenAssessList();
|
||||
getNoOpenAssessNumber();
|
||||
getDecryptData();
|
||||
getThreeDaysUnSendAnnoCount();
|
||||
getThreeDaysUnSendAnnoList();
|
||||
getThreeDayNoEndCount();
|
||||
}
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
let interval: any = null;
|
||||
let count = 0;
|
||||
let lengthMap = [noOpenListData.length, noOpenAssessListData.length, isNotEmpty(decryptData?.decryptExceptionList) ? decryptData?.decryptExceptionList.length : 0, threeDayNoEndData.length, isNotEmpty(decryptData?.macSameList) ? decryptData?.macSameList.length : 0, threeDaysUnSendAnnoList.length].sort((a, b) => b - a);
|
||||
if (lengthMap[0] > 1) {//至少2条才能滚动
|
||||
interval = setInterval(() => {
|
||||
if (count < lengthMap[0]) {
|
||||
setSelectKey(count);
|
||||
const v0 = document.getElementsByClassName("scroll-select-bg")[0];
|
||||
const v1 = document.getElementsByClassName("scroll-select-bg")[1];
|
||||
const v2 = document.getElementsByClassName("scroll-select-bg")[2];
|
||||
const v3 = document.getElementsByClassName("scroll-select-bg")[3];
|
||||
const v4 = document.getElementsByClassName("scroll-select-bg")[4];
|
||||
const v5 = document.getElementsByClassName("scroll-select-bg")[5];
|
||||
v0?.scrollIntoView(false);
|
||||
v1?.scrollIntoView(false);
|
||||
v2?.scrollIntoView(false);
|
||||
v3?.scrollIntoView(false);
|
||||
v4?.scrollIntoView(false);
|
||||
v5?.scrollIntoView(false);
|
||||
count++;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, [noOpenListData, noOpenAssessListData, decryptData?.decryptExceptionList, threeDayNoEndData, decryptData?.macSameList, threeDaysUnSendAnnoList])
|
||||
|
||||
const columns: any[] = [
|
||||
{
|
||||
@ -206,8 +276,8 @@ const MonitorException: React.FC<{}> = () => {
|
||||
},
|
||||
{
|
||||
title: '预算金额(元)',
|
||||
dataIndex: 'budgetAmount',
|
||||
key: 'budgetAmount',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: 'center',
|
||||
width: '25%',
|
||||
onCell,
|
||||
@ -248,8 +318,8 @@ const MonitorException: React.FC<{}> = () => {
|
||||
},
|
||||
{
|
||||
title: '省分',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'provinceName',
|
||||
dataIndex: 'province',
|
||||
key: 'province',
|
||||
align: 'center',
|
||||
width: '15%',
|
||||
ellipsis: true,
|
||||
@ -332,13 +402,13 @@ const MonitorException: React.FC<{}> = () => {
|
||||
},
|
||||
{
|
||||
title: '预算金额(元)',
|
||||
dataIndex: 'budgetAmount',
|
||||
key: 'budgetAmount',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: 'center',
|
||||
width: '25%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => isNotEmpty(record.budgetAmount) ? Number(record.budgetAmount).toFixed(2) : 0,
|
||||
render: (_: any, record: any) => isNotEmpty(record.bidSectContractPrice) ? Number(record.bidSectContractPrice).toFixed(2) : 0,
|
||||
},
|
||||
{
|
||||
title: '采购经理',
|
||||
@ -395,8 +465,8 @@ const MonitorException: React.FC<{}> = () => {
|
||||
},
|
||||
{
|
||||
title: '预算金额(元)',
|
||||
dataIndex: 'budgetAmount',
|
||||
key: 'budgetAmount',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: 'center',
|
||||
width: '25%',
|
||||
onCell,
|
||||
@ -432,7 +502,7 @@ const MonitorException: React.FC<{}> = () => {
|
||||
<OverviewItem icon={Circle3199} title="一小时内未开标" number={noOpenNumberData} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="解密异常" number={decryptData?.decryptExceptionCount} unit="次" />
|
||||
<OverviewItem icon={Circle3199} title="MAC地址相同" number={decryptData?.macSameCount} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="开标后6小时未开启评审" number={noOpenAssessListData?.length} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="开标后6小时未开启评审" number={noOpenAssessNumber} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="开启评审后3日未结束评标" number={threeDayNoEndCount} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="评标结束3日未公示" number={threeDaysUnSendAnnoCount} unit="个" />
|
||||
{/* <OverviewItem icon={Circle3199} title="重新评标次数" number={62520} unit="次" /> */}
|
||||
@ -443,11 +513,11 @@ const MonitorException: React.FC<{}> = () => {
|
||||
<div className="monitor-left-main">
|
||||
<ScreenLabel title="1小时未开标项目列表" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType(null); setModalListData(noOpenListData); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={noOpenListData} columns={columns} ynum={266} />
|
||||
<ScrollTable dataSource={noOpenListData} columns={columns} ynum={266} rowKey="sectionId" selectKey={selectKey} />
|
||||
</div>
|
||||
<ScreenLabel title="开标后六小时未开启评审" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType(null); setModalListData(noOpenAssessListData); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={noOpenAssessListData} columns={columns} ynum={266} />
|
||||
<ScrollTable dataSource={noOpenAssessListData} columns={columns} ynum={266} selectKey={selectKey} />
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
@ -455,11 +525,11 @@ const MonitorException: React.FC<{}> = () => {
|
||||
<div className="monitor-center-main">
|
||||
<ScreenLabel title="解密异常项目列表" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType("解密异常"); setModalListData(decryptData?.decryptExceptionList ? decryptData?.decryptExceptionList : []); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={decryptData?.decryptExceptionList} columns={columnsSecond} ynum={266} />
|
||||
<ScrollTable dataSource={decryptData?.decryptExceptionList} columns={columnsSecond} selectKey={selectKey} ynum={266} />
|
||||
</div>
|
||||
<ScreenLabel title="开启评审后3日未结束评标" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType("开启评审后3日未结束评标"); setModalListData(threeDayNoEndData); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={threeDayNoEndData} columns={columnsForth} ynum={266} />
|
||||
<ScrollTable dataSource={threeDayNoEndData} columns={columnsForth} ynum={266} selectKey={selectKey} />
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
@ -467,11 +537,11 @@ const MonitorException: React.FC<{}> = () => {
|
||||
<div className="monitor-right-main">
|
||||
<ScreenLabel title="MAC地址重复项目列表" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType("MAC地址重复"); setModalListData(decryptData?.macSameList ? decryptData?.macSameList : []); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={decryptData?.macSameList} columns={columnsFifth} ynum={266} />
|
||||
<ScrollTable dataSource={decryptData?.macSameList} columns={columnsFifth} ynum={266} selectKey={selectKey} />
|
||||
</div>
|
||||
<ScreenLabel title="评标结束后3日内未发布公示" extra={<span className='monitor-extra-pointer' onClick={() => { setExceptionType("评标结束后3日内未发布公示"); setModalListData(threeDaysUnSendAnnoList); setModalListVisible(true); }}>more</span>} />
|
||||
<div className="monitor-exception-card">
|
||||
<ScrollTable dataSource={threeDaysUnSendAnnoList} columns={columnsThird} ynum={266} />
|
||||
<ScrollTable dataSource={threeDaysUnSendAnnoList} columns={columnsThird} ynum={266} selectKey={selectKey} />
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Button, Col, Descriptions, Divider, Dropdown, Empty, Menu, message, Modal, Progress, Row, Space, Table } from 'antd';
|
||||
import { Button, Col, Descriptions, Divider, Dropdown, Empty, Input, Menu, MenuProps, message, Modal, Progress, Row, Space, Table } from 'antd';
|
||||
import { debounce } from 'lodash';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import '../style.less'
|
||||
@ -14,10 +14,10 @@ import right from '@/assets/monitor/right.png';
|
||||
import { CaretRightOutlined, DownOutlined } from '@ant-design/icons';
|
||||
import './china';
|
||||
import * as echarts from 'echarts';
|
||||
import { getActiveSupplierAPI, getAnnoCountAPI, getAnnualAndTenderAgentAPI, getExpertNumberAPI, getMonitorListAPI, getOpeningListAPI, getReviewDistributionAPI, getSupplierCountAPI, getTodayOpeningAPI } from '../service';
|
||||
import { getActiveSupplierAPI, getAnnoCountAPI, getAnnualAndTenderAgentAPI, getExpertNumberAPI, getMonitorListAPI, getOpeningListAPI, getReviewDistributionAPI, getSupplierCountAPI, getTodayInfoAPI, getTodayOpeningAPI } from '../service';
|
||||
import moment from 'moment';
|
||||
import { isEmpty, isNotEmpty } from '@/utils/CommonUtils';
|
||||
import { getSessionUserData } from '@/utils/session';
|
||||
import { getDicData, getSessionUserData } from '@/utils/session';
|
||||
import { history } from 'umi';
|
||||
|
||||
export const onCell = () => ({ className: "monitor-table-content" });
|
||||
@ -56,6 +56,15 @@ export const proviceEnum = {
|
||||
"0065": "新疆",
|
||||
"001000": "集团"
|
||||
}
|
||||
function getYearMap() {
|
||||
const year: number = moment().year();//当前年份
|
||||
const data: { label: string, value: string }[] = [];
|
||||
for (let i = 0, length = year - 2021 + 1; i < length; i++) {
|
||||
data.push({ label: (year - i) + "年", value: String(year - i) })
|
||||
}
|
||||
return data;
|
||||
}
|
||||
export const yearMap: { label: string, value: string }[] = getYearMap();
|
||||
function dealWithData(mapd: any[]) {
|
||||
let geoCoordMap = {
|
||||
吉林: [125.35, 43.88],
|
||||
@ -92,20 +101,38 @@ function dealWithData(mapd: any[]) {
|
||||
江西: [115.864528, 28.687675]
|
||||
};
|
||||
let data = [];
|
||||
for (let key in geoCoordMap) {
|
||||
for (let i = 0, length = mapd.length; i < length; i++) {
|
||||
const ele = mapd[i];
|
||||
if (ele.provincesName == key) {
|
||||
geoCoordMap[key].push(Number(ele.allNumber));
|
||||
geoCoordMap[key].push(Number(ele.opeingNumber));
|
||||
geoCoordMap[key].push(Number(ele.assessNumber));
|
||||
break;
|
||||
}
|
||||
}
|
||||
data.push({ name: key, value: geoCoordMap[key] });
|
||||
// for (let key in geoCoordMap) {
|
||||
// for (let i = 0, length = mapd.length; i < length; i++) {
|
||||
// const ele = mapd[i];
|
||||
// if (ele.provincesName == key) {
|
||||
// geoCoordMap[key].push(Number(ele.allNumber));
|
||||
// geoCoordMap[key].push(Number(ele.opeingNumber));
|
||||
// geoCoordMap[key].push(Number(ele.assessNumber));
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// data.push({ name: key, value: geoCoordMap[key] });
|
||||
// }
|
||||
for (let i = 0, length = mapd.length; i < length; i++) {
|
||||
const ele = mapd[i];
|
||||
data.push({ name: ele.provincesName, value: [...geoCoordMap[ele.provincesName], Number(ele.allNumber), Number(ele.opeingNumber), Number(ele.assessNumber)] });
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
* 字典code回显dicName
|
||||
* @param dictList[]
|
||||
* @param code
|
||||
*/
|
||||
export const changeDict = (dictList: any[], code: any) => {
|
||||
let name = '';
|
||||
dictList.forEach((ele: any) => {
|
||||
if (ele.code == code) {
|
||||
name = ele.dicName;
|
||||
}
|
||||
});
|
||||
return name;
|
||||
};
|
||||
|
||||
const columns: any[] = [
|
||||
{
|
||||
@ -332,6 +359,50 @@ export const SelectItem = (props: { onSelectChange: (value: string) => void, opt
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
|
||||
//下拉框-招标代理选择
|
||||
export const SelectRadio = (props: { onSelectChange: (value: string) => void, options: ({ label: string, value: string })[], defaultText?: string, hidden?: boolean }) => {
|
||||
const { onSelectChange, options, defaultText = "全部", hidden = false } = props;
|
||||
const [selectedItem, setSelectItem] = useState<string | number>(defaultText);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [optionsList, setOptionsList] = useState<{ label: string, value: string }[]>([]);
|
||||
|
||||
const handleOpenChange = (flag: boolean) => {
|
||||
setOpen(flag);
|
||||
};
|
||||
const handleMenuClick = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
const onChange = (e: any) => {
|
||||
const data = e.target.value;
|
||||
const list = options.filter(item => item.label.includes(data));
|
||||
setOptionsList(list);
|
||||
}
|
||||
useEffect(() => {
|
||||
options.length > 0 && setOptionsList(options);
|
||||
}, [options])
|
||||
const menu = (
|
||||
<Space size={4}>
|
||||
<div>搜索:<Input placeholder="代理机构名称" bordered={false} onChange={onChange} /></div>
|
||||
{optionsList.slice(0, 56).map(item => (
|
||||
<div key={item.value} onClick={() => { setSelectItem(item.label); onSelectChange(item.value); handleMenuClick(); }}>{item.label}</div>
|
||||
))}
|
||||
{optionsList.length > 56 && "..."}
|
||||
</Space>
|
||||
);
|
||||
return (
|
||||
<Dropdown overlay={menu} trigger={["click"]} visible={open} onVisibleChange={handleOpenChange} overlayClassName="monitor-select-radio-dropdown" placement="bottomRight">
|
||||
<div className='monitor-select-btn' hidden={hidden}>
|
||||
<span>
|
||||
<Space>
|
||||
{selectedItem}
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
</span>
|
||||
</div>
|
||||
</Dropdown>
|
||||
)
|
||||
}
|
||||
//阶段卡片
|
||||
export const StageCard = (props: { percentage: string | number, total: string | number, firstTitle: string, secondTitle: string, thirdTitle: string, firstNumber: string | number, secondNumber: string | number, thirdNumber: string | number }) => {
|
||||
const { percentage, total, firstTitle, secondTitle, thirdTitle, firstNumber, secondNumber, thirdNumber } = props;
|
||||
@ -387,20 +458,26 @@ export const StageCard = (props: { percentage: string | number, total: string |
|
||||
)
|
||||
}
|
||||
//滚动列表
|
||||
export const ScrollTable = (props: { dataSource: any[], columns: any[], rollTime?: number, rollNum?: number, ynum?: number }) => {
|
||||
const { dataSource, columns, rollTime = 50, rollNum = 5, ynum = 300 } = props;
|
||||
export const ScrollTable = (props: { dataSource: any[], columns: any[], rollTime?: number, rollNum?: number, ynum?: number, rowKey?: string, selectKey?: number }) => {
|
||||
const { dataSource, columns, rollTime = 10, rollNum = 5, ynum = 300, rowKey = "id", selectKey = -1 } = props;
|
||||
return (
|
||||
<div style={{ ["--monitor-table-height" as any]: `${ynum}px` }}>
|
||||
<Table
|
||||
pagination={false}
|
||||
className="monitor-scroll-table"
|
||||
rowKey="id"
|
||||
rowKey={rowKey}
|
||||
bordered={false}
|
||||
scroll={{
|
||||
y: ynum,
|
||||
scrollToFirstRowOnChange: true,
|
||||
// scrollToFirstRowOnChange: true,
|
||||
}}
|
||||
// dataSource={tableData}
|
||||
rowClassName={(record, index) => {
|
||||
if (index == selectKey) {
|
||||
return "scroll-select-bg"; //highlight样式需要自己定义
|
||||
}
|
||||
return "scroll-select-default";
|
||||
}}
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
onRow={record => {
|
||||
@ -413,14 +490,14 @@ export const ScrollTable = (props: { dataSource: any[], columns: any[], rollTime
|
||||
)
|
||||
}
|
||||
//统计列表
|
||||
export const StatisticTable = (props: { dataSource: any[], columns: any[], rollTime?: number, rollNum?: number, ynum?: number }) => {
|
||||
const { dataSource, columns, rollTime = 50, rollNum = 5, ynum = 300 } = props;
|
||||
export const StatisticTable = (props: { dataSource: any[], columns: any[], rollTime?: number, rollNum?: number, ynum?: number, rowKey?: string }) => {
|
||||
const { dataSource, columns, rollTime = 50, rollNum = 5, ynum = 300, rowKey = "id" } = props;
|
||||
return (
|
||||
<div style={{ ["--monitor-table-height" as any]: `${ynum}px` }}>
|
||||
<Table
|
||||
pagination={false}
|
||||
className="monitor-statistic-table"
|
||||
rowKey="id"
|
||||
rowKey={rowKey}
|
||||
size='small'
|
||||
bordered={false}
|
||||
scroll={{
|
||||
@ -510,6 +587,9 @@ export const ModalList = (props: { modalVisible: boolean, onCancel: () => void,
|
||||
const contentStyle = { color: "#fff" };
|
||||
const titleStyle = { color: "#1b7ef2", fontWeight: "bold", marginBottom: '24px' };
|
||||
const dividerStyle = { borderColor: "#999", margin: "12px 0 24px" };
|
||||
//初始化字典
|
||||
let dic: any = getDicData();
|
||||
let dicData: any = JSON.parse(dic);
|
||||
return (
|
||||
<Modal
|
||||
destroyOnClose
|
||||
@ -529,9 +609,11 @@ export const ModalList = (props: { modalVisible: boolean, onCancel: () => void,
|
||||
<Descriptions>
|
||||
<Descriptions.Item label="异常类型" labelStyle={labelStyle} contentStyle={contentStyle}>{isNotEmpty(exceptionType) ? exceptionType : item?.exType}</Descriptions.Item>
|
||||
<Descriptions.Item label="项目名称" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.projectName}</Descriptions.Item>
|
||||
<Descriptions.Item label="标段名称" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.bidSectName || item?.sectionName}</Descriptions.Item>
|
||||
<Descriptions.Item label="省分" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.provinceName || item?.regionDictName || item?.province}</Descriptions.Item>
|
||||
<Descriptions.Item label="采购经理" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.ownerContactName}</Descriptions.Item>
|
||||
<Descriptions.Item label="采购经理电话" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.ownerContactTel}</Descriptions.Item>
|
||||
<Descriptions.Item label="标段状态" labelStyle={labelStyle} contentStyle={contentStyle}>{(item?.state || item?.sectionState || item?.sectionStatus) == 9 ? "异常处理" : changeDict(item?.bidMethodDict ? dicData[`business_module=${item?.bidMethodDict}`] : [], item?.businessModule)}</Descriptions.Item>
|
||||
<Descriptions.Item label="招标代理机构" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.tenderAgencyName}</Descriptions.Item>
|
||||
<Descriptions.Item label="代理机构电话" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.appManagerTel}</Descriptions.Item>
|
||||
<Descriptions.Item label="开标时间" labelStyle={labelStyle} contentStyle={contentStyle}>{item?.openTime || item?.recruitStartTime || item?.openingTime}</Descriptions.Item>
|
||||
@ -564,8 +646,7 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
let mapData: any[] = [];
|
||||
if (type == "map") {//地图处理数据
|
||||
dataValue = dealWithData(chartData);
|
||||
// mapData = dataValue.splice(0, 3);
|
||||
mapData = dataValue;
|
||||
mapData = dataValue.splice(0, 3);
|
||||
}
|
||||
const autoTooltip = (index: number) => {
|
||||
myChart.dispatchAction({
|
||||
@ -577,6 +658,18 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
},
|
||||
});
|
||||
}
|
||||
const autoSelect = (index: number) => {
|
||||
myChart.dispatchAction({
|
||||
type: 'select',
|
||||
seriesIndex: 0,
|
||||
dataIndex: index,
|
||||
});
|
||||
myChart.dispatchAction({
|
||||
type: 'showTip',
|
||||
seriesIndex: 0,
|
||||
dataIndex: index,
|
||||
});
|
||||
}
|
||||
const colors = ['#1B7EF2', '#29F1FA', '#1B7EF2'];
|
||||
const categoryOption: EChartsOption = {
|
||||
color: colors,
|
||||
@ -740,7 +833,13 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
coordinateSystem: "geo",
|
||||
data: dataValue,
|
||||
symbolSize: function (val) {
|
||||
return val[2] == 0 ? 8 : Math.floor(val[2] / 1.2);
|
||||
if (val[2] < 9) {
|
||||
return 8;
|
||||
} else if (val[2] > 30) {
|
||||
return 30;
|
||||
} else {
|
||||
return val[2];
|
||||
}
|
||||
},
|
||||
symbol: "circle",
|
||||
// symbolSize: 8,
|
||||
@ -774,48 +873,54 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
disabled: true
|
||||
},
|
||||
},
|
||||
// {
|
||||
// name: "",
|
||||
// type: "effectScatter",
|
||||
// coordinateSystem: "geo",
|
||||
// data: mapData,
|
||||
// symbolSize: 16,
|
||||
// // symbolSize: function (val) {
|
||||
// // return Math.floor(val[1] / 4);
|
||||
// // },
|
||||
// tooltip: {
|
||||
// formatter(value) {
|
||||
// return value.data.name + "<br/>" + "今日评标总数:" + value.data.value[2] + "<br/>" + "电子招标:" + value.data.value[3] + "<br/>" + "电子评标:" + value.data.value[4];
|
||||
// },
|
||||
// backgroundColor: "#0a0c11cc",
|
||||
// textStyle: {
|
||||
// color: '#fff'
|
||||
// },
|
||||
// show: true
|
||||
// },
|
||||
// encode: {
|
||||
// value: 2
|
||||
// },
|
||||
// showEffectOn: "render",
|
||||
// rippleEffect: {
|
||||
// brushType: "stroke",
|
||||
// color: "rgb(36,203,255)",
|
||||
// period: 9,
|
||||
// scale: 5
|
||||
// },
|
||||
// label: {
|
||||
// formatter: "{b}",
|
||||
// position: "right",
|
||||
// color: "#fff",
|
||||
// show: true
|
||||
// },
|
||||
// itemStyle: {
|
||||
// color: "rgb(36,203,255)",
|
||||
// shadowBlur: 2,
|
||||
// shadowColor: "#333"
|
||||
// },
|
||||
// zlevel: 1
|
||||
// }
|
||||
{
|
||||
name: "",
|
||||
type: "effectScatter",
|
||||
coordinateSystem: "geo",
|
||||
data: mapData,
|
||||
// symbolSize: 16,
|
||||
symbolSize: function (val) {
|
||||
if (val[2] < 9) {
|
||||
return 8;
|
||||
} else if (val[2] > 30) {
|
||||
return 30;
|
||||
} else {
|
||||
return val[2];
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
formatter(value) {
|
||||
return value.data.name + "<br/>" + "今日评标总数:" + value.data.value[2] + "<br/>" + "电子招标:" + value.data.value[3] + "<br/>" + "电子评标:" + value.data.value[4];
|
||||
},
|
||||
backgroundColor: "#0a0c11cc",
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
},
|
||||
show: true
|
||||
},
|
||||
encode: {
|
||||
value: 2
|
||||
},
|
||||
showEffectOn: "render",
|
||||
rippleEffect: {
|
||||
brushType: "stroke",
|
||||
color: "rgb(36,203,255)",
|
||||
period: 9,
|
||||
scale: 5
|
||||
},
|
||||
label: {
|
||||
formatter: "{b}",
|
||||
position: "right",
|
||||
color: "#fff",
|
||||
show: true
|
||||
},
|
||||
itemStyle: {
|
||||
color: "rgb(36,203,255)",
|
||||
shadowBlur: 2,
|
||||
shadowColor: "#333"
|
||||
},
|
||||
zlevel: 1
|
||||
}
|
||||
]
|
||||
};
|
||||
const gaugeOption: EChartsOption = {
|
||||
@ -917,9 +1022,6 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
}
|
||||
const mapTwiceOption: EChartsOption = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
showDelay: 0,
|
||||
transitionDuration: 0.2,
|
||||
show: false,
|
||||
},
|
||||
geo: {
|
||||
@ -937,8 +1039,8 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
}
|
||||
},
|
||||
visualMap: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
min: 0,
|
||||
max: 100,
|
||||
inRange: {
|
||||
color: [
|
||||
'#01417f',
|
||||
@ -963,6 +1065,19 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
// label: {
|
||||
// show: false
|
||||
// },
|
||||
tooltip: {
|
||||
formatter(value) {
|
||||
if (value.data?.name) {
|
||||
return value.data.name + "<br/>" + "活跃供应商数量:" + value.data?.data.supplierCount + "<br/>" + "投标次数总量:" + value.data?.data.tenderCount;
|
||||
}
|
||||
return "";
|
||||
},
|
||||
backgroundColor: "#0a0c11cc",
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
},
|
||||
show: true
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
@ -1216,7 +1331,7 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
if (type == "mapTwice") {
|
||||
myChart.on('selectchanged', function (params: any) {
|
||||
if (params.selected.length > 0) {
|
||||
onSelect(chartData[params.selected[0].dataIndex[0]].name);
|
||||
onSelect(chartData[params.selected[0].dataIndex[0]]?.name);
|
||||
} else {
|
||||
onSelect("");
|
||||
}
|
||||
@ -1238,16 +1353,29 @@ export const GraphChart = (props: { type: string, chartData: any[], chartColor?:
|
||||
myChart && myChart.resize();
|
||||
};
|
||||
let interval: any = null;
|
||||
// if (type == "map") {//地图自动轮播tooltip
|
||||
// let index = 0;
|
||||
// interval = setInterval(() => {
|
||||
// autoTooltip(index)
|
||||
// index++;
|
||||
// if (index >= mapData.length) {
|
||||
// index = 0;
|
||||
// }
|
||||
// }, 10000)
|
||||
// }
|
||||
if (type == "map") {//地图自动轮播tooltip
|
||||
let index = 0;
|
||||
interval = setInterval(() => {
|
||||
autoTooltip(index);
|
||||
index++;
|
||||
if (index >= mapData.length) {
|
||||
index = 0;
|
||||
}
|
||||
}, 10000)
|
||||
}
|
||||
if (type == "mapTwice") {//地图自动轮播tooltip
|
||||
let index = 1;
|
||||
autoSelect(0);
|
||||
if (chartData.length > 1) {
|
||||
interval = setInterval(() => {
|
||||
autoSelect(index);
|
||||
index++;
|
||||
if (index >= chartData.length) {
|
||||
index = 0;
|
||||
}
|
||||
}, 10000)
|
||||
}
|
||||
}
|
||||
window.addEventListener("resize", debounce(() => resize(), 100));
|
||||
return () => {
|
||||
window.removeEventListener("resize", debounce(() => resize(), 100));
|
||||
@ -1289,14 +1417,17 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
const [annoCount, setAnnoCount] = useState<string | number>("");
|
||||
//评审专家数量
|
||||
const [expertNumber, setExpertNumber] = useState<string | number>("");
|
||||
//年度&月度 year-年度 month-月度
|
||||
const [ymChange, setYmChange] = useState<string>("year");
|
||||
//评标室监控
|
||||
const [monitorList, setMonitorList] = useState<any[]>([{ status: "3" }, { status: "3" }, { status: "3" }]);
|
||||
const [monitorList, setMonitorList] = useState<any[]>([]);
|
||||
//今日开标-评标阶段,评标及时率
|
||||
const [todayInfoData, setTodayInfoData] = useState<any>();
|
||||
//权限校验
|
||||
const auth = useRef<boolean>(authCheck());
|
||||
const bidStatusMap = ["准备评标", "正在评标", "评标结束", "暂无数据"];
|
||||
const statusColorMap = ["card-text-orange", "card-text-green", "card-text-purple", "card-text-white"];
|
||||
//year select
|
||||
const localYear: string = moment().month() < 2 ? String(moment().year() - 1) : String(moment().year());
|
||||
const [yearSelect, setYearSelect] = useState<string>(localYear);
|
||||
const mapChart = useMemo(() => {
|
||||
return reviewDistributionData.length > 0 && <GraphChart type="map" chartData={reviewDistributionData} />
|
||||
}, [reviewDistributionData])
|
||||
@ -1325,8 +1456,8 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
})
|
||||
}
|
||||
//上面前三个指标和招标代理实施项目统计
|
||||
const getAnnualAndTenderAgent = () => {
|
||||
getAnnualAndTenderAgentAPI().then(res => {
|
||||
const getAnnualAndTenderAgent = (ym: any) => {
|
||||
getAnnualAndTenderAgentAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
const data = res?.data;
|
||||
if (data.agencyProjectYear.length > 0) {
|
||||
@ -1335,20 +1466,13 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
data.agencyProjectYear[i]["maxNum"] = max1;
|
||||
}
|
||||
}
|
||||
if (data.agencyProjectMonth.length > 0) {
|
||||
const max2 = data.agencyProjectMonth[0].num;
|
||||
|
||||
for (let i = 0, length = data.agencyProjectMonth.length; i < length; i++) {
|
||||
data.agencyProjectMonth[i]["maxNum"] = max2;
|
||||
}
|
||||
}
|
||||
setAnnualAndTenderAgentData(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
//活跃供应商
|
||||
const getActiveSupplier = () => {
|
||||
getActiveSupplierAPI().then(res => {
|
||||
const getActiveSupplier = (ym: string) => {
|
||||
getActiveSupplierAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
const data = res?.data;
|
||||
if (data.length > 0) {
|
||||
@ -1363,7 +1487,7 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
}
|
||||
//参与供应商数
|
||||
const getSupplierCount = (ym: string) => {
|
||||
getSupplierCountAPI({ type: ym }).then(res => {
|
||||
getSupplierCountAPI({ year: Number(ym) }).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setSupplierCount(res?.data);
|
||||
}
|
||||
@ -1371,7 +1495,7 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
}
|
||||
//公告公示数量
|
||||
const getAnnoCount = (ym: string) => {
|
||||
getAnnoCountAPI({ type: ym }).then(res => {
|
||||
getAnnoCountAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setAnnoCount(res?.data);
|
||||
}
|
||||
@ -1395,11 +1519,16 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
//今日开标-评标阶段,评标及时率
|
||||
const getTodayInfo = () => {
|
||||
getTodayInfoAPI().then(res => {
|
||||
if (res?.code == 200) {
|
||||
setTodayInfoData(res?.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
//监控室点击事件
|
||||
const onCardClick = (item: any) => {
|
||||
if (item.status == "3") {
|
||||
return;
|
||||
}
|
||||
if (item.status == "0") {
|
||||
message.info("当前评标室未开启,请等待开启后查看");
|
||||
return;
|
||||
@ -1409,36 +1538,41 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
state: { monitorId: item.id },
|
||||
})
|
||||
}
|
||||
//onYearSelect
|
||||
const onYearSelect = (value: string) => {
|
||||
setYearSelect(value);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (auth.current) {
|
||||
getTodayOpening();
|
||||
getReviewDistribution();
|
||||
getOpeningList();
|
||||
getAnnualAndTenderAgent();
|
||||
getActiveSupplier();
|
||||
getMonitorList();
|
||||
getTodayInfo();
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (auth.current) {
|
||||
getSupplierCount(ymChange);
|
||||
getAnnoCount(ymChange);
|
||||
getExpertNumber(ymChange);
|
||||
getSupplierCount(yearSelect);
|
||||
getAnnoCount(yearSelect);
|
||||
getAnnualAndTenderAgent(yearSelect);
|
||||
getExpertNumber(yearSelect);
|
||||
getActiveSupplier(yearSelect);
|
||||
}
|
||||
}, [ymChange])
|
||||
}, [yearSelect])
|
||||
|
||||
return (
|
||||
<ScreenTitle title="智能招标采购室">
|
||||
<div className="top-main">
|
||||
<div className='monitor-top-exchange'>
|
||||
<span onClick={() => { setYmChange("year") }}>年度</span> | <span onClick={() => { setYmChange("month") }}>月度</span>
|
||||
<SelectItem options={yearMap} onSelectChange={onYearSelect} defaultText={localYear + "年"} />
|
||||
</div>
|
||||
<Row className="monitor-top-main-flex">
|
||||
<Col span={4}><MetricItems icon={Frame10116} title="电子招标总数" number={ymChange == "year" ? annualAndTenderAgentData?.bidProjectCountYear : annualAndTenderAgentData?.bidProjectCountMonth} unit="个" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10117} title="电子谈判总数" number={ymChange == "year" ? annualAndTenderAgentData?.negoProjectCountYear : annualAndTenderAgentData?.negoProjectCountMonth} unit="个" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10118} title="预算金额" number={ymChange == "year" ? annualAndTenderAgentData?.projectBudgetYear?.toFixed(2) : annualAndTenderAgentData?.projectBudgetMonth?.toFixed(2)} unit="亿元" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10116} title="电子招标总数" number={annualAndTenderAgentData?.bidProjectCountYear} unit="个" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10117} title="电子谈判总数" number={annualAndTenderAgentData?.negoProjectCountYear} unit="个" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10118} title="预算金额" number={annualAndTenderAgentData?.projectBudgetYear?.toFixed(2)} unit="亿元" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10119} title="公告公示数量" number={annoCount} unit="个" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10120} title="评标专家数量" number={expertNumber} unit="人次" /></Col>
|
||||
<Col span={4}><MetricItems icon={Frame10121} title="参与供应商" number={supplierCount} unit="家次" /></Col>
|
||||
@ -1448,7 +1582,7 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
<Col span={8}>
|
||||
<div className="monitor-left-main">
|
||||
<div className="monitor-label-pointer" onClick={() => { window.open("/ElecMonitor/OpenToday") }}>
|
||||
<ScreenLabel title="今日开标" extra={<span>标段总数 {isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber : 0} 已完成 {isNotEmpty(todayOpeningData?.complete) ? Number(todayOpeningData?.complete).toFixed(0) : 0} 完成率 {isNotEmpty(todayOpeningData?.rate) ? todayOpeningData?.rate : 0}</span>} />
|
||||
<ScreenLabel title="今日开标" extra={<span>标段总数 {isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber : 0} 开标完成率 {isNotEmpty(todayOpeningData?.sectionNumber) && todayOpeningData?.sectionNumber != "0" ? Number(((Number(todayOpeningData?.banner) / todayOpeningData?.sectionNumber) * 100).toFixed(0)) : 0}% 评标完成率 {(isNotEmpty(todayInfoData?.sectionNumber) && todayInfoData?.sectionNumber != "0") ? Number(((Number(todayInfoData?.resultNumber) / todayInfoData?.sectionNumber) * 100).toFixed(0)) : 0}%</span>} />
|
||||
</div>
|
||||
<div className="scroll-table">
|
||||
<ScrollTable dataSource={todayOpeningData?.todayList} columns={columns} ynum={266} />
|
||||
@ -1473,11 +1607,9 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
<ScreenLabel title="智能评标监控" />
|
||||
</div>
|
||||
<div className="bid-evaluation">
|
||||
{/* <div> */}
|
||||
<Row gutter={16}>
|
||||
{monitorList.length > 0 ? <div><Row gutter={16}>
|
||||
{monitorList.map((item, index) => (
|
||||
<Col span={8} key={index}>
|
||||
{/* <div> */}
|
||||
<div className="card-default-01" onClick={() => onCardClick(item)}>
|
||||
<img src={default_play}></img>
|
||||
<div className={statusColorMap[item.status]}>{bidStatusMap[item.status]}</div>
|
||||
@ -1485,12 +1617,9 @@ const MonitorHome: React.FC<{}> = () => {
|
||||
<div className="evaluation-text">
|
||||
<span>{item?.projectName}</span>
|
||||
</div>
|
||||
{/* </div> */}
|
||||
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
{/* </div> */}
|
||||
</Row></div> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} className="monitor-modal-empty" />}
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
|
@ -1,104 +1,13 @@
|
||||
import { Col, Row } from 'antd';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import '../style.less'
|
||||
import { authCheck, ModalList, onCell, onHeaderCell, OverviewItem, ProgressItem, proviceEnum, ScreenLabel, ScreenTitle, ScrollTable, StageCard } from '../Home';
|
||||
import { authCheck, changeDict, ModalList, onCell, onHeaderCell, OverviewItem, ProgressItem, proviceEnum, ScreenLabel, ScreenTitle, ScrollTable, StageCard } from '../Home';
|
||||
import Circle3199 from '@/assets/monitor/circle-3199.png';
|
||||
import { getDecryptSuccessRateTodayAPI, getNoOpenListAPI, getNoOpenNumberAPI, getTodayInfoAPI, getTodayOpeningAPI, getUnopenSixAPI, getUnopenTenAPI } from '../service';
|
||||
import { isNotEmpty } from '@/utils/CommonUtils';
|
||||
const statusMap = ["未开标", "开标", "唱标", "唱标结束", "取消开标", "", "", "", "", "异常处理"];
|
||||
import { getDicData } from '@/utils/session';
|
||||
// const statusMap = ["未开标", "开标", "唱标", "唱标结束", "取消开标", "", "", "", "", "异常处理"];
|
||||
|
||||
const columns: any[] = [
|
||||
{
|
||||
title: '省分',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'provinceName',
|
||||
width: '20%',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
// render: (_: any, record: any) => proviceEnum[record.provinceDictId],
|
||||
},
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'projectName',
|
||||
key: 'projectName',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
width: '30%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '采购预算',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: "center",
|
||||
width: '30%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '开标时间',
|
||||
dataIndex: 'openTime',
|
||||
key: 'openTime',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
];
|
||||
const reiColumns: any[] = [
|
||||
{
|
||||
title: '省分',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'provinceName',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
ellipsis: true,
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
// render: (_: any, record: any) => proviceEnum[record.provinceDictId],
|
||||
},
|
||||
{
|
||||
title: '项目名称',
|
||||
dataIndex: 'projectName',
|
||||
key: 'projectName',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '采购预算',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '开标时间',
|
||||
dataIndex: 'openTime',
|
||||
key: 'openTime',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => statusMap[record.state],
|
||||
},
|
||||
];
|
||||
const OpenToday: React.FC<{}> = () => {
|
||||
//今日开标-评标阶段,评标及时率
|
||||
const [todayInfoData, setTodayInfoData] = useState<any>();
|
||||
@ -124,8 +33,119 @@ const OpenToday: React.FC<{}> = () => {
|
||||
const [modalListData, setModalListData] = useState<any[]>([]);
|
||||
//ModalList Type
|
||||
const [exceptionType, setExceptionType] = useState<any>();
|
||||
//selectKey
|
||||
const [selectKey, setSelectKey] = useState<number>(-1);
|
||||
//权限校验
|
||||
const auth = useRef<boolean>(authCheck());
|
||||
//定时器描述
|
||||
const _time = 60000;
|
||||
//初始化字典
|
||||
let dic: any = getDicData();
|
||||
let dicData: any = JSON.parse(dic);
|
||||
const columns: any[] = [
|
||||
{
|
||||
title: '省分',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'provinceName',
|
||||
width: '20%',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
// render: (_: any, record: any) => proviceEnum[record.provinceDictId],
|
||||
},
|
||||
{
|
||||
title: '标段名称',
|
||||
dataIndex: 'projectName',
|
||||
key: 'projectName',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => <span><span title={record.projectName}>{record.projectName}</span><br /><span title={record.sectionName}>{record.sectionName}</span></span>,
|
||||
},
|
||||
{
|
||||
title: '采购预算',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '开标时间',
|
||||
dataIndex: 'openTime',
|
||||
key: 'openTime',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '标段状态',
|
||||
dataIndex: 'sectionState',
|
||||
key: 'sectionState',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => record?.sectionState == 9 ? "异常处理" : changeDict(record?.bidMethodDict ? dicData[`business_module=${record?.bidMethodDict}`] : [], record?.businessModule),
|
||||
},
|
||||
];
|
||||
const reiColumns: any[] = [
|
||||
{
|
||||
title: '省分',
|
||||
dataIndex: 'provinceName',
|
||||
key: 'provinceName',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
ellipsis: true,
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
// render: (_: any, record: any) => proviceEnum[record.provinceDictId],
|
||||
},
|
||||
{
|
||||
title: '标段名称',
|
||||
dataIndex: 'projectName',
|
||||
key: 'projectName',
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => <span><span title={record.projectName}>{record.projectName}</span><br /><span title={record.sectionName}>{record.sectionName}</span></span>,
|
||||
},
|
||||
{
|
||||
title: '采购预算',
|
||||
dataIndex: 'bidSectContractPrice',
|
||||
key: 'bidSectContractPrice',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '开标时间',
|
||||
dataIndex: 'openTime',
|
||||
key: 'openTime',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
},
|
||||
{
|
||||
title: '标段状态',
|
||||
dataIndex: 'sectionState',
|
||||
key: 'sectionState',
|
||||
align: "center",
|
||||
width: '20%',
|
||||
onCell,
|
||||
onHeaderCell,
|
||||
render: (_: any, record: any) => record?.sectionState == 9 ? "异常处理" : changeDict(record?.bidMethodDict ? dicData[`business_module=${record?.bidMethodDict}`] : [], record?.businessModule),
|
||||
},
|
||||
];
|
||||
//今日开标-评标阶段,评标及时率
|
||||
const getTodayInfo = () => {
|
||||
getTodayInfoAPI().then(res => {
|
||||
@ -192,27 +212,62 @@ const OpenToday: React.FC<{}> = () => {
|
||||
}
|
||||
})
|
||||
}
|
||||
//页面数据获取
|
||||
const getPageData = () => {
|
||||
getTodayInfo();
|
||||
getDecryptSuccessRateToday();
|
||||
getTodayOpening();
|
||||
getUnopenSix();
|
||||
getUnopenTen();
|
||||
getNoOpenNumber();
|
||||
getNoOpenList();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let interval: any;
|
||||
if (auth.current) {
|
||||
getTodayInfo();
|
||||
getDecryptSuccessRateToday();
|
||||
getTodayOpening();
|
||||
getUnopenSix();
|
||||
getUnopenTen();
|
||||
getNoOpenNumber();
|
||||
getNoOpenList();
|
||||
getPageData();
|
||||
interval = setInterval(() => {
|
||||
getPageData();
|
||||
}, _time);
|
||||
}
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
let interval: any = null;
|
||||
let count = 0;
|
||||
let lengthMap = [isNotEmpty(todayOpeningData?.todayList) ? todayOpeningData?.todayList.length : 0, isNotEmpty(todayOpeningData?.importantList) ? todayOpeningData?.importantList.length : 0].sort((a, b) => b - a);
|
||||
if (lengthMap[0] > 1) {//至少2条才能滚动
|
||||
interval = setInterval(() => {
|
||||
if (count < lengthMap[0]) {
|
||||
setSelectKey(count);
|
||||
const v0 = document.getElementsByClassName("scroll-select-bg")[0];
|
||||
const v1 = document.getElementsByClassName("scroll-select-bg")[1];
|
||||
v0?.scrollIntoView(false);
|
||||
v1?.scrollIntoView(false);
|
||||
count++;
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, [todayOpeningData?.todayList, todayOpeningData?.importantList])
|
||||
return (
|
||||
<ScreenTitle title="今日开标">
|
||||
<div className="top-main top-main-bottom">
|
||||
<div className='monitor-top-exchange'>
|
||||
<span onClick={() => { window.open("/ElecMonitor/Exception") }}>异常监控</span>
|
||||
<div className='monitor-exception-btn'>
|
||||
<span onClick={() => { window.open("/ElecMonitor/Exception") }}>异常监控</span>
|
||||
</div>
|
||||
</div>
|
||||
<Row gutter={30}>
|
||||
<Col span={7}>
|
||||
<div className='monitor-tender-card'>
|
||||
<div className='monitor-tender-top'>
|
||||
<ScreenLabel title="开标阶段" />
|
||||
<div className='monitor-tender-card'>
|
||||
<StageCard percentage={isNotEmpty(todayOpeningData?.sectionNumber) && todayOpeningData?.sectionNumber != "0" ? Number(((Number(todayOpeningData?.banner) / todayOpeningData?.sectionNumber) * 100).toFixed(0)) : 0} total={isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber : 0} firstTitle="已开标" firstNumber={`${isNotEmpty(todayOpeningData?.openNumber) ? Number(todayOpeningData?.openNumber).toFixed(0) : 0}个`} secondTitle="已解密" secondNumber={`${isNotEmpty(todayOpeningData?.decrypt) ? Number(todayOpeningData?.decrypt).toFixed(0) : 0}个`} thirdTitle="已唱标" thirdNumber={`${isNotEmpty(todayOpeningData?.banner) ? Number(todayOpeningData?.banner).toFixed(0) : 0}个`} />
|
||||
@ -220,19 +275,19 @@ const OpenToday: React.FC<{}> = () => {
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={10}>
|
||||
<div className="monitor-top-space-flex monitor-today-overview-width">
|
||||
<div className="monitor-top-space-flex monitor-today-overview-width monitor-top-space-top">
|
||||
<OverviewItem icon={Circle3199} title="标段总数" number={isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber : 0} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="已完成" number={isNotEmpty(todayOpeningData?.complete) ? Number(todayOpeningData?.complete).toFixed(0) : 0} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="完成率" number={isNotEmpty(todayOpeningData?.rate) ? todayOpeningData?.rate.slice(0, todayOpeningData?.rate.length - 1) : 0} unit="%" />
|
||||
<OverviewItem icon={Circle3199} title="已开标" number={isNotEmpty(todayOpeningData?.openNumber) ? Number(todayOpeningData?.openNumber).toFixed(0) : 0} unit="个" />
|
||||
<OverviewItem icon={Circle3199} title="已评标" number={isNotEmpty(todayInfoData?.openAssessNumber) ? todayInfoData?.openAssessNumber : 0} unit="个" />
|
||||
</div>
|
||||
<div className="monitor-top-space-flex">
|
||||
<ProgressItem progress={isNotEmpty(decryptSuccessRateTodayData?.successRate) ? Number(Number(decryptSuccessRateTodayData?.successRate).toFixed(0)) : 100} title="解密成功率" leftTitle='解密成功' rightTitle='解密失败' leftNumber={isNotEmpty(decryptSuccessRateTodayData?.successNum) ? Number(decryptSuccessRateTodayData?.successNum) : 0} rightNumber={isNotEmpty(decryptSuccessRateTodayData?.failNum) ? Number(decryptSuccessRateTodayData?.failNum) : 0} leftClick={() => { }} rightClick={() => { setExceptionType("解密异常"); setModalListData(isNotEmpty(decryptSuccessRateTodayData?.decryptFailProjectList) ? decryptSuccessRateTodayData?.decryptFailProjectList : []); setModalListVisible(true); }} />
|
||||
<ProgressItem progress={isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber != 0 ? Number((((todayOpeningData?.sectionNumber - Number(noOpenNumberTwo)) / Number(todayOpeningData?.sectionNumber)) * 100).toFixed(0)) : 100 : 100} title="开标及时率" leftTitle='2小时未开标' rightTitle='5小时未开标' leftNumber={noOpenNumberTwo} rightNumber={noOpenNumberFive} leftClick={() => { setExceptionType(null); setModalListData(noOpenListTwo); setModalListVisible(true); }} rightClick={() => { setExceptionType(null); setModalListData(noOpenListFive); setModalListVisible(true); }} />
|
||||
<ProgressItem progress={isNotEmpty(todayInfoData?.sectionNumber) ? todayInfoData?.sectionNumber != 0 ? Number((((todayInfoData?.sectionNumber - Number(todayInfoData?.sixTimelyRate)) / Number(todayInfoData?.sectionNumber)) * 100).toFixed(0)) : 100 : 100} title="评标及时率" leftTitle='6小时未评标' rightTitle='10小时未评标' leftNumber={todayInfoData?.sixTimelyRate} rightNumber={todayInfoData?.tenTimelyRate} leftClick={() => { setExceptionType(null); setModalListData(unopenSixData); setModalListVisible(true); }} rightClick={() => { setExceptionType(null); setModalListData(unopenTenData); setModalListVisible(true); }} />
|
||||
<ProgressItem progress={isNotEmpty(todayOpeningData?.sectionNumber) ? todayOpeningData?.sectionNumber != 0 ? Number((((todayOpeningData?.sectionNumber - Number(noOpenNumberTwo)) / Number(todayOpeningData?.sectionNumber)) * 100).toFixed(0)) : 100 : 100} title="开标及时率" leftTitle='2小时未开标' rightTitle='5小时未开标' leftNumber={noOpenNumberTwo} rightNumber={noOpenNumberFive} leftClick={() => { setExceptionType("2小时未开标"); setModalListData(noOpenListTwo); setModalListVisible(true); }} rightClick={() => { setExceptionType("5小时未开标"); setModalListData(noOpenListFive); setModalListVisible(true); }} />
|
||||
<ProgressItem progress={isNotEmpty(todayInfoData?.sectionNumber) ? todayInfoData?.sectionNumber != 0 ? Number((((todayInfoData?.sectionNumber - Number(todayInfoData?.sixTimelyRate)) / Number(todayInfoData?.sectionNumber)) * 100).toFixed(0)) : 100 : 100} title="评标及时率" leftTitle='6小时未评标' rightTitle='10小时未评标' leftNumber={todayInfoData?.sixTimelyRate} rightNumber={todayInfoData?.tenTimelyRate} leftClick={() => { setExceptionType("6小时未评标"); setModalListData(unopenSixData); setModalListVisible(true); }} rightClick={() => { setExceptionType("10小时未评标"); setModalListData(unopenTenData); setModalListVisible(true); }} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={7}>
|
||||
<div className='monitor-tender-card'>
|
||||
<div className='monitor-tender-top'>
|
||||
<ScreenLabel title="评标阶段" />
|
||||
<div className='monitor-tender-card'>
|
||||
<StageCard percentage={(isNotEmpty(todayInfoData?.sectionNumber) && todayInfoData?.sectionNumber != "0") ? Number(((Number(todayInfoData?.resultNumber) / todayInfoData?.sectionNumber) * 100).toFixed(0)) : 0} total={isNotEmpty(todayInfoData?.sectionNumber) ? todayInfoData?.sectionNumber : 0} firstTitle="开启评审" firstNumber={`${isNotEmpty(todayInfoData?.openAssessNumber) ? todayInfoData?.openAssessNumber : 0}个`} secondTitle="专家签到" secondNumber={`${isNotEmpty(todayInfoData?.signExpertNumber) ? todayInfoData?.signExpertNumber : 0}/${isNotEmpty(todayInfoData?.totalExpertNumber) ? todayInfoData?.totalExpertNumber : 0}`} thirdTitle="评审汇总" thirdNumber={`${isNotEmpty(todayInfoData?.resultNumber) ? todayInfoData?.resultNumber : 0}个`} />
|
||||
@ -245,13 +300,13 @@ const OpenToday: React.FC<{}> = () => {
|
||||
<Col span={12}>
|
||||
<ScreenLabel title="今日开标明细" />
|
||||
<div className='monitor-tender-card'>
|
||||
<ScrollTable dataSource={todayOpeningData?.todayList} columns={columns} ynum={530} />
|
||||
<ScrollTable dataSource={todayOpeningData?.todayList} columns={columns} ynum={540} selectKey={selectKey} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<ScreenLabel title="重保项目" />
|
||||
<div className='monitor-tender-card'>
|
||||
<ScrollTable dataSource={isNotEmpty(todayOpeningData?.importantList) ? todayOpeningData?.importantList : []} columns={reiColumns} ynum={530} />
|
||||
<ScrollTable dataSource={isNotEmpty(todayOpeningData?.importantList) ? todayOpeningData?.importantList : []} columns={reiColumns} ynum={540} selectKey={selectKey} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Col, Progress, Row } from 'antd';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import '../style.less'
|
||||
import { authCheck, GraphChart, MetricItems, onCell, onHeaderCell, ScreenLabel, ScreenTitle, SelectItem, StatisticTable } from '../Home';
|
||||
import { authCheck, GraphChart, MetricItems, onCell, onHeaderCell, ScreenLabel, ScreenTitle, SelectItem, StatisticTable, yearMap } from '../Home';
|
||||
import Frame10116 from '@/assets/monitor/Frame-10116.png';
|
||||
import Frame10121 from '@/assets/monitor/Frame-10121.png';
|
||||
import { getActiveSupplierRankAPI, getProvinceActiveSupplierInfoAPI, getSupplierInfoAPI } from '../service';
|
||||
import { isNotEmpty } from '@/utils/CommonUtils';
|
||||
import moment from 'moment';
|
||||
|
||||
const columns: any[] = [
|
||||
{
|
||||
@ -70,13 +71,16 @@ const Supplier: React.FC<{}> = () => {
|
||||
const monthOrYear = useRef<string>("yearData");
|
||||
//指标项 tenderCount-投标次数 selectCount-中选次数 bidCost-中选金额
|
||||
const metric = useRef<string>("tenderCount");
|
||||
const metricMap = { tenderCount: "投标次数", selectCount: "中选次数", bidCost: "中选金额" };
|
||||
const metricMap = { tenderCount: "投标次数", selectCount: "中选次数", bidCost: "中选金额(万元)" };
|
||||
//省份
|
||||
const province = useRef<string>("");
|
||||
//图表数据
|
||||
const [chartData, setChartData] = useState<any[]>([]);
|
||||
//权限校验
|
||||
const auth = useRef<boolean>(authCheck());
|
||||
//year select
|
||||
const localYear: string = moment().month() < 2 ? String(moment().year() - 1) : String(moment().year());
|
||||
const [yearSelect, setYearSelect] = useState<string>(localYear);
|
||||
const transverseBarChart = useMemo(() => {
|
||||
return chartData.length > 0 && <GraphChart type="transverseBar" chartData={chartData} />
|
||||
}, [chartData])
|
||||
@ -90,16 +94,16 @@ const Supplier: React.FC<{}> = () => {
|
||||
}, [provinceData])
|
||||
|
||||
//上面六个指标
|
||||
const getSupplierInfo = () => {
|
||||
getSupplierInfoAPI().then(res => {
|
||||
const getSupplierInfo = (ym: string) => {
|
||||
getSupplierInfoAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setSupplierInfoData(res?.data);
|
||||
}
|
||||
})
|
||||
}
|
||||
//全国活跃供应商排名
|
||||
const getActiveSupplierRank = () => {
|
||||
getActiveSupplierRankAPI().then(res => {
|
||||
const getActiveSupplierRank = (ym: string) => {
|
||||
getActiveSupplierRankAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
const data = JSON.parse(res?.data)
|
||||
rankDataRef.current = data;
|
||||
@ -108,24 +112,27 @@ const Supplier: React.FC<{}> = () => {
|
||||
})
|
||||
}
|
||||
//供应商概况-省份活跃供应商
|
||||
const getProvinceActiveSupplierInfo = () => {
|
||||
getProvinceActiveSupplierInfoAPI().then(res => {
|
||||
const getProvinceActiveSupplierInfo = (ym: string) => {
|
||||
getProvinceActiveSupplierInfoAPI(ym).then(res => {
|
||||
if (res?.code == 200) {
|
||||
provinceActiveSupplierInfoData.current = res?.data;
|
||||
setProvinceData(res?.data.map((item: any) => ({ name: item.provinceName, value: 0 })))
|
||||
const data = res?.data ? res?.data : [];
|
||||
provinceActiveSupplierInfoData.current = data;
|
||||
setProvinceData(data.map((item: any) => ({ name: item.provinceName, value: item.supplierCount, data: item })))
|
||||
}
|
||||
})
|
||||
}
|
||||
//onSelectChange select变更事件
|
||||
const onSelectChange = (value: string | number) => {
|
||||
if (rankDataRef.current) {
|
||||
const data = rankDataRef.current[value];
|
||||
const data = rankDataRef.current[value] ? rankDataRef.current[value] : [];
|
||||
if (data.length > 0) {
|
||||
const max = data[0].tenderCount;
|
||||
for (let i = 0, length = data.length; i < length; i++) {
|
||||
data[i]["maxTenderCount"] = max;
|
||||
}
|
||||
setActiveSupplierRankData(data)
|
||||
setActiveSupplierRankData(data);
|
||||
} else {
|
||||
setActiveSupplierRankData([]);
|
||||
}
|
||||
|
||||
}
|
||||
@ -157,18 +164,25 @@ const Supplier: React.FC<{}> = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
//onYearSelect
|
||||
const onYearSelect = (value: string) => {
|
||||
setYearSelect(value);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (auth.current) {
|
||||
getSupplierInfo();
|
||||
getActiveSupplierRank();
|
||||
getProvinceActiveSupplierInfo();
|
||||
getSupplierInfo(yearSelect);
|
||||
getActiveSupplierRank(yearSelect);
|
||||
getProvinceActiveSupplierInfo(yearSelect);
|
||||
}
|
||||
}, [])
|
||||
}, [yearSelect])
|
||||
return (
|
||||
<ScreenTitle title="供应商概况">
|
||||
<div className="top-main">
|
||||
<div className="monitor-top-space-flex">
|
||||
<div className='monitor-top-exchange'>
|
||||
<SelectItem options={yearMap} onSelectChange={onYearSelect} defaultText={localYear + "年"} />
|
||||
</div>
|
||||
<div className="monitor-top-space-flex monitor-top-space-top monitor-top-flex-space">
|
||||
<MetricItems icon={Frame10116} title="投标总次数" number={supplierInfoData?.totalTenderCount} unit="次" />
|
||||
<MetricItems icon={Frame10121} title="投标供应商" number={supplierInfoData?.totalSupplierCount} unit="家" />
|
||||
<MetricItems icon={Frame10116} title="年度投标次数" number={supplierInfoData?.yearlyTotalTenderCount} unit="次" />
|
||||
@ -191,7 +205,7 @@ const Supplier: React.FC<{}> = () => {
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
<div className="monitor-right-main">
|
||||
<ScreenLabel title="省分活跃供应商排名" extra={<span><span className={monthOrYear.current == "yearData" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { monthOrYear.current = "yearData"; chartDataChange(); }}>本年</span> | <span className={monthOrYear.current == "monthData" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { monthOrYear.current = "monthData"; chartDataChange(); }}>本月</span> <span className={metric.current == "tenderCount" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "tenderCount"; chartDataChange(); }}>投标次数</span> | <span className={metric.current == "selectCount" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "selectCount"; chartDataChange(); }}>中选次数</span> | <span className={metric.current == "bidCost" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "bidCost"; chartDataChange(); }}>中选金额</span> {province.current}</span>} />
|
||||
<ScreenLabel title="省分活跃供应商排名" extra={<span><span className={metric.current == "tenderCount" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "tenderCount"; chartDataChange(); }}>投标次数</span> | <span className={metric.current == "selectCount" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "selectCount"; chartDataChange(); }}>中选次数</span> | <span className={metric.current == "bidCost" ? 'monitor-extra-pointer monitor-extra-pointer-select' : 'monitor-extra-pointer'} onClick={() => { metric.current = "bidCost"; chartDataChange(); }}>中选金额</span> {province.current}</span>} />
|
||||
<Row>
|
||||
<Col span={14}>
|
||||
<div className="monitor-supplier-rank">
|
||||
|
@ -1,13 +1,14 @@
|
||||
import { Col, Radio, Row } from 'antd';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import '../style.less'
|
||||
import { authCheck, GraphChart, onCell, onHeaderCell, OverviewItem, ScreenLabel, ScreenTitle, SelectItem, StatisticTable } from '../Home';
|
||||
import { authCheck, GraphChart, onCell, onHeaderCell, OverviewItem, ScreenLabel, ScreenTitle, SelectItem, SelectRadio, StatisticTable, yearMap } from '../Home';
|
||||
import Circle3197 from '@/assets/monitor/circle-3197.png';
|
||||
import Circle3198 from '@/assets/monitor/circle-3198.png';
|
||||
import Circle3199 from '@/assets/monitor/circle-3199.png';
|
||||
import Circle3200 from '@/assets/monitor/circle-3200.png';
|
||||
import { getTenderAgentDataAPI, getProvinceByAgencyAPI } from '../service';
|
||||
import { isNotEmpty } from '@/utils/CommonUtils';
|
||||
import moment from 'moment';
|
||||
|
||||
const columns: any[] = [
|
||||
{
|
||||
@ -71,6 +72,11 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
const [provinceData, setProvinceData] = useState<any[]>([]);
|
||||
//btn select
|
||||
const [btnSelect, setBtnSelect] = useState<string>("0");
|
||||
//year select
|
||||
const localYear: string = moment().month() < 2 ? String(moment().year() - 1) : String(moment().year());
|
||||
const [yearSelect, setYearSelect] = useState<string>(localYear);
|
||||
//存一份
|
||||
const selectAgency = useRef<string>("");
|
||||
//权限校验
|
||||
const auth = useRef<boolean>(authCheck());
|
||||
// const gaugeChartData = [{ value: 20 }]
|
||||
@ -94,8 +100,8 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
}, [provinceByAgencyData])
|
||||
|
||||
//相关统计数据
|
||||
const getTenderAgentData = () => {
|
||||
getTenderAgentDataAPI().then(res => {
|
||||
const getTenderAgentData = (year: string) => {
|
||||
getTenderAgentDataAPI(year).then(res => {
|
||||
if (res?.code == 200) {
|
||||
setTenderAgentData(res?.data);
|
||||
const data = res?.data.agencyProjectMonth;//左侧条形图数据处理
|
||||
@ -113,7 +119,7 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
setMonthData(monthDataMap)
|
||||
|
||||
const selectData: any[] = res?.data.agencyList.map((item: any) => ({ label: item.agencyName, value: item.agencyId }));//右侧代理机构下拉
|
||||
selectData.unshift({ label: "请选择", value: "all" });
|
||||
// selectData.unshift({ label: "请选择", value: "all" });
|
||||
setSelectData(selectData);
|
||||
|
||||
const province = res?.data.agencyListByProvince;//招标代理省份分布数据
|
||||
@ -129,8 +135,8 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
})
|
||||
}
|
||||
//代理分布省分
|
||||
const getProvinceByAgency = (agencyId: string) => {
|
||||
getProvinceByAgencyAPI(agencyId).then(res => {
|
||||
const getProvinceByAgency = (agencyId: string, year: string) => {
|
||||
getProvinceByAgencyAPI(agencyId, year).then(res => {
|
||||
if (res?.code == 200) {
|
||||
const data = res?.data;
|
||||
const agencyData = data.map((item: any) => ({ name: item.province, value: Number(item.dlxms), data: item }));
|
||||
@ -143,20 +149,27 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
}
|
||||
//onSelectChange select变更事件
|
||||
const onSelectChange = (value: string) => {
|
||||
if (value != "all") {
|
||||
getProvinceByAgency(value);
|
||||
} else {
|
||||
setProvinceByAgencyData([]);
|
||||
}
|
||||
getProvinceByAgency(value, yearSelect);
|
||||
selectAgency.current = value;
|
||||
}
|
||||
//onYearSelect
|
||||
const onYearSelect = (value: string) => {
|
||||
setYearSelect(value);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (auth.current) {
|
||||
getTenderAgentData();
|
||||
getTenderAgentData(yearSelect);
|
||||
if (selectAgency.current != "") {
|
||||
getProvinceByAgency(selectAgency.current, yearSelect);
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
}, [yearSelect])
|
||||
return (
|
||||
<ScreenTitle title="招标代理机构概况">
|
||||
<div className="top-main top-main-bottom">
|
||||
<div className='monitor-top-exchange'>
|
||||
<SelectItem options={yearMap} onSelectChange={onYearSelect} defaultText={localYear + "年"} />
|
||||
</div>
|
||||
<Row gutter={50} className="monitor-top-space-top">
|
||||
<Col span={24}>
|
||||
<ScreenLabel title="年度概览" />
|
||||
@ -164,7 +177,7 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
<OverviewItem icon={Circle3197} title="代理机构数量" number={tenderAgentData?.agencyProjectCountYear.dljg} unit="个" />
|
||||
<OverviewItem icon={Circle3198} title="代理机构人员数量" number={tenderAgentData?.agencyProjectCountYear.dljgry} unit="人" />
|
||||
<OverviewItem icon={Circle3199} title="代理机构项目数量" number={tenderAgentData?.agencyProjectCountYear.dlxms} unit="个" />
|
||||
<OverviewItem icon={Circle3200} title="代理项目预算金额" number={tenderAgentData?.agencyProjectCountYear.dlxmys} unit="亿元" />
|
||||
<OverviewItem icon={Circle3200} title="代理项目预算金额" number={tenderAgentData?.agencyProjectCountYear.dlxmys?.toFixed(0)} unit="亿元" />
|
||||
<OverviewItem icon={Circle3199} title="代理项目完成率" number={isNotEmpty(tenderAgentData?.agencyProjectCountYear.wcl) ? (tenderAgentData?.agencyProjectCountYear.wcl * 100).toFixed(0) : 0} unit="%" />
|
||||
</div>
|
||||
</Col>
|
||||
@ -194,7 +207,7 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
{categoryChart}
|
||||
</div>
|
||||
<div>
|
||||
<StatisticTable dataSource={tenderAgentData?.agencyProjectListYear} columns={columns} ynum={266} />
|
||||
<StatisticTable dataSource={tenderAgentData?.agencyProjectListYear?.slice(0, 15)} columns={columns} ynum={266} />
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
@ -204,7 +217,7 @@ const TenderAgent: React.FC<{}> = () => {
|
||||
<Radio.Button value="0">代理分布省分</Radio.Button>
|
||||
<Radio.Button value="1">省分代理分布</Radio.Button>
|
||||
</Radio.Group>
|
||||
<SelectItem options={selectData} onSelectChange={onSelectChange} defaultText="请选择" hidden={btnSelect == "1"} />
|
||||
<SelectRadio options={selectData} onSelectChange={onSelectChange} defaultText="请选择" hidden={btnSelect == "1"} />
|
||||
</div>
|
||||
<div className="monitor-tender-map">
|
||||
{btnSelect == "0" ? agencyMapChart : mapChart}
|
||||
|
@ -35,8 +35,8 @@ export async function getOpeningListAPI(data: any) {
|
||||
* 首页-上面前三个指标和招标代理实施项目统计
|
||||
* @param data
|
||||
*/
|
||||
export async function getAnnualAndTenderAgentAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/indexMonitor/getProjectData', {
|
||||
export async function getAnnualAndTenderAgentAPI(year: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/indexMonitor/getProjectData/${year}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -45,8 +45,8 @@ export async function getAnnualAndTenderAgentAPI() {
|
||||
* 首页-活跃供应商
|
||||
* @param data
|
||||
*/
|
||||
export async function getActiveSupplierAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/indexMonitor/indexQuerySupplier', {
|
||||
export async function getActiveSupplierAPI(params: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/indexMonitor/indexQuerySupplier/${params}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -55,9 +55,9 @@ export async function getActiveSupplierAPI() {
|
||||
* 首页-参与供应商数
|
||||
*/
|
||||
export async function getSupplierCountAPI(params: any) {
|
||||
return request('/api/biz-service-ebtp-statistics/v1/tenderMonitor/supplierCount', {
|
||||
return request(`/api/biz-service-ebtp-statistics/v1/tenderMonitor/supplierCount`, {
|
||||
method: 'GET',
|
||||
params: { ...params }
|
||||
params: params
|
||||
});
|
||||
}
|
||||
|
||||
@ -65,9 +65,8 @@ export async function getSupplierCountAPI(params: any) {
|
||||
* 首页-公告公示数量
|
||||
*/
|
||||
export async function getAnnoCountAPI(params: any) {
|
||||
return request('/api/biz-service-ebtp-statistics/indexMonitor/annoCount', {
|
||||
return request(`/api/biz-service-ebtp-statistics/indexMonitor/annoCount/${params}`, {
|
||||
method: 'GET',
|
||||
params: { ...params }
|
||||
});
|
||||
}
|
||||
|
||||
@ -131,6 +130,17 @@ export async function getNoOpenAssessListAPI(data: any) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常监控-开标后超过6小时未开启评审室-数量
|
||||
* @param data
|
||||
*/
|
||||
export async function getNoOpenAssessNumberAPI(data: any) {
|
||||
return request('/api/biz-service-ebtp-statistics/opening/noOpenAssessNumber', {
|
||||
method: 'POST',
|
||||
data: { ...data },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 异常监控-解密异常、mac地址相同及相关项目列表
|
||||
*/
|
||||
@ -195,8 +205,8 @@ export async function getDecryptSuccessRateTodayAPI() {
|
||||
/**
|
||||
* 供应商概况-上面六个指标
|
||||
*/
|
||||
export async function getSupplierInfoAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/v1/tenderMonitor/supplierInfo', {
|
||||
export async function getSupplierInfoAPI(params: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/v1/tenderMonitor/supplierInfo/${params}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -204,8 +214,8 @@ export async function getSupplierInfoAPI() {
|
||||
/**
|
||||
* 供应商概况-全国活跃供应商排名
|
||||
*/
|
||||
export async function getActiveSupplierRankAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/v1/tenderMonitor/activeSupplierRank', {
|
||||
export async function getActiveSupplierRankAPI(params: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/v1/tenderMonitor/activeSupplierRank/${params}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -213,8 +223,8 @@ export async function getActiveSupplierRankAPI() {
|
||||
/**
|
||||
* 供应商概况-省份活跃供应商
|
||||
*/
|
||||
export async function getProvinceActiveSupplierInfoAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/v1/tenderMonitor/provinceActiveSupplierInfo', {
|
||||
export async function getProvinceActiveSupplierInfoAPI(params: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/v1/tenderMonitor/provinceActiveSupplierInfo/${params}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
@ -222,16 +232,16 @@ export async function getProvinceActiveSupplierInfoAPI() {
|
||||
/**
|
||||
* 招标代理机构概况-相关统计数据
|
||||
*/
|
||||
export async function getTenderAgentDataAPI() {
|
||||
return request('/api/biz-service-ebtp-statistics/tenderAgent/getTenderAgentData', {
|
||||
export async function getTenderAgentDataAPI(year: string) {
|
||||
return request('/api/biz-service-ebtp-statistics/tenderAgent/getTenderAgentData/' + year, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 招标代理机构概况-代理分布省分
|
||||
*/
|
||||
export async function getProvinceByAgencyAPI(agencyId: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/tenderAgent/getProvinceByAgency/${agencyId}`, {
|
||||
export async function getProvinceByAgencyAPI(agencyId: any, year: any) {
|
||||
return request(`/api/biz-service-ebtp-statistics/tenderAgent/getProvinceByAgency/${agencyId}/${year}`, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
@ -81,26 +81,25 @@
|
||||
|
||||
.monitor-top-main-flex {
|
||||
margin-left: 80px;
|
||||
margin-top: 20px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.monitor-top-exchange {
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
color: #FFFFFF;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
&>span {
|
||||
font-size: 14px;
|
||||
color: #FFFFFF;
|
||||
line-height: 16px;
|
||||
cursor: pointer;
|
||||
.monitor-exception-btn {
|
||||
.monitor-select-btn;
|
||||
background-color: #12304e99;
|
||||
|
||||
&:hover {
|
||||
color: #1b7ef2;
|
||||
text-decoration: underline;
|
||||
&>span {
|
||||
color: #1b7ef2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.monitor-top-space-flex {
|
||||
@ -135,7 +134,11 @@
|
||||
}
|
||||
|
||||
.monitor-top-space-top {
|
||||
margin-top: 20px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.monitor-top-flex-space {
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,13 +249,14 @@
|
||||
height: 170px;
|
||||
background-clip: border-box;
|
||||
filter: blur(0px);
|
||||
.flex-center;
|
||||
|
||||
.card-default-01 {
|
||||
background-image: url('~@/assets/screen/default_pic01.jpg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
height: 120px;
|
||||
margin-top: 14px;
|
||||
margin-top: 20px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
@ -407,6 +411,10 @@
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.monitor-tender-top {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.monitor-supplier-card {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
@ -716,6 +724,10 @@
|
||||
.ant-table-body {
|
||||
height: var(--monitor-table-height);
|
||||
}
|
||||
|
||||
.scroll-select-bg {
|
||||
background: #66666666;
|
||||
}
|
||||
}
|
||||
|
||||
.monitor-statistic-table {
|
||||
@ -1013,11 +1025,6 @@
|
||||
|
||||
.monitor-select-dropdown {
|
||||
|
||||
&>ul {
|
||||
height: 99vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu {
|
||||
background-color: #081a30;
|
||||
}
|
||||
@ -1033,6 +1040,36 @@
|
||||
}
|
||||
}
|
||||
|
||||
.monitor-select-radio-dropdown {
|
||||
|
||||
.ant-dropdown-menu {
|
||||
background-color: #081a30;
|
||||
width: 900px;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item,
|
||||
.ant-dropdown-menu-submenu-title {
|
||||
color: #FFFFFF;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item:hover,
|
||||
.ant-dropdown-menu-submenu-title:hover {
|
||||
background-color: #1b7ef2;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item:first-child,
|
||||
.ant-dropdown-menu-submenu-title:first-child {
|
||||
background-color: transparent;
|
||||
width: 900px;
|
||||
|
||||
&>div>input {
|
||||
color: #fff;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.monitor-select-btn {
|
||||
outline: none;
|
||||
position: relative;
|
||||
@ -1111,14 +1148,14 @@
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.monitor-modal-empty {
|
||||
.ant-empty-image {
|
||||
color: #fff;
|
||||
}
|
||||
.monitor-modal-empty {
|
||||
.ant-empty-image {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-empty-description {
|
||||
color: #fff;
|
||||
}
|
||||
.ant-empty-description {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user