From 7adf08f3edb0e85735378f7b7357751bfb450b62 Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Fri, 13 Jun 2025 14:54:07 +0800 Subject: [PATCH 01/21] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=B7=AF=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/router.config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/router.config.ts b/config/router.config.ts index 6cbe387..50da76f 100644 --- a/config/router.config.ts +++ b/config/router.config.ts @@ -134,6 +134,11 @@ export default [ path: '/ProjectFiles/file', component: './ProjectFiles/file', }, + { + name: 'BidReOffer', + path: '/biddingAnnouncement/BiddingAnnoStructureForm', + component: './Bid/BiddingAnnouncement/structure/BiddingAnnoStructureForm', + }, //==============================================================引入的业务路由 ...approvalForm,//审批单 ...juryRoom,//评标室内所有路由 From 94f3e5c3f0cd4b72be9370f90f1cb0669acbce1d Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Fri, 13 Jun 2025 15:26:03 +0800 Subject: [PATCH 02/21] =?UTF-8?q?=E5=85=AC=E5=91=8A=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Bid/BiddingAnnouncement/service.ts | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/pages/Bid/BiddingAnnouncement/service.ts b/src/pages/Bid/BiddingAnnouncement/service.ts index ba3929d..e7515a4 100644 --- a/src/pages/Bid/BiddingAnnouncement/service.ts +++ b/src/pages/Bid/BiddingAnnouncement/service.ts @@ -240,4 +240,41 @@ export async function saveAnno(params?: any) { ...params }, }) +} + + +/** + * 公告结构化-根据项目id获取结构化信息 + * @param projectId + * @returns + */ +export async function getAnnoStructuralValue(params?: any) { + return request('/api/biz-service-ebtp-bid/v1/bizannostructural/getStructuralValue/', { + method: "post", + data: { + ...params + }, + }) +} + +/** + * 公告结构化-保存数据 + * @param data + * @returns + */ +export async function saveAnnoStructuralFormData(data: any) { + return request('/api/biz-service-ebtp-bid/v1/bizannostructural/saveStructural', { + method: 'POST', + data: { ...data }, + }) +} + +/*招标文件-招标文件维护增加相关招标公告预览及备注信息*/ +export async function findAnnoByBsIds(params: any) { + return request('/api/biz-service-ebtp-bid/v1/bizannostructural/selectListByBsIds', { + method: "post", + data: [ + ...params + ] + }) } \ No newline at end of file From eb7edbf807c55e87c2774f330bced3b2eb2d42a2 Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Fri, 13 Jun 2025 15:27:44 +0800 Subject: [PATCH 03/21] =?UTF-8?q?=E8=AF=84=E5=A7=94=E4=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Bid/ReviewConfig/List/index.tsx | 3 +- .../JudgingPanel/List/index.tsx | 76 +++++++------------ 2 files changed, 29 insertions(+), 50 deletions(-) diff --git a/src/pages/Bid/ReviewConfig/List/index.tsx b/src/pages/Bid/ReviewConfig/List/index.tsx index a73267b..5483b5b 100644 --- a/src/pages/Bid/ReviewConfig/List/index.tsx +++ b/src/pages/Bid/ReviewConfig/List/index.tsx @@ -205,8 +205,7 @@ const List: React.FC<{}> = () => { } useEffect(() => { //取项目id - //proIdSet(getProId());//TODO zyx-假数据 - proIdSet("1920644626460389376"); + proIdSet(getProId()); // getHaveConfigSections(); }, []); return ( diff --git a/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx b/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx index e0bcc5b..74008d9 100644 --- a/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx +++ b/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx @@ -1,9 +1,9 @@ import React, { useEffect, useRef, useState } from 'react'; import { Button, Checkbox, Col, Collapse, DatePicker, Drawer, Form, Input, message, Modal, Popconfirm, Row, Select, Spin, Upload, Image, InputNumber } from 'antd' import ProTable, { ActionType, EditableProTable, ProColumns } from '@ant-design/pro-table'; -import { getList, saveGroup, delOne, saveMember, changeEx, queryVoList, changeMember, applyFor, roomStatus, juryTem, rePassWord, getUserPhoto, unlockAccount, getCrotchListUsingGET } from './service'; +import { getList, saveGroup, delOne, saveMember, changeEx, queryVoList, changeMember, applyFor, roomStatus, juryTem, rePassWord, getUserPhoto, unlockAccount, getCrotchListUsingGET, getSecs } from './service'; import moment from 'moment'; -import { getDefId, getProId, getProMethod, getSessionUserData } from '@/utils/session'; +import { getDefId, getProId, getProMethod, getProOpenTenderForm, getSessionUserData } from '@/utils/session'; import { getURLInformation, isEmpty } from '@/utils/CommonUtils'; import './judgList.less'; import '@/assets/xsy_style.less'; @@ -17,7 +17,7 @@ import ExpertSchemeProfessionalInfo from './ExpertSchemeProfessionalInfo'; const JudgingPanel: React.FC<{}> = () => { const modalHeight = window.innerHeight * 96 / 100; - const proId = "1513327631627579392";//getProId();//TODO zyx-假数据 + const proId = getProId(); const roomType = getURLInformation('roomType'); // const tailLayout = { wrapperCol: { offset: 8, span: 20 }, }; const formLayout = { labelCol: { span: 8 }, wrapperCol: { span: 16 }, }; @@ -53,7 +53,7 @@ const JudgingPanel: React.FC<{}> = () => { const [editableKeys, setEditableRowKeys] = useState([]); const [tableData, setTableData] = useState([]); function getShouName() { - const method = 'procurement_mode_1';//getProMethod();//TODO zyx-假数据 + const method = getProMethod(); let showNameT: any = { zbr: '', bb: '', pb: '', }//相关标段 标书费 保证金 服务费 // let num = 3; if (method === 'procurement_mode_1' || method === 'procurement_mode_2') {//招标 @@ -328,34 +328,19 @@ const JudgingPanel: React.FC<{}> = () => { params['juryId'] = ''; } getShouName();//根据采购类型变名字 - // TODO zyx假数据 - // modalVis == true ? getSecs({ ...params }).then((res) => { - let data = []; - let secVals = []; - // TODO zyx假数据 - // if (res.success) { - let res = { - "code": 200, "success": true, "message": "success", - "data": [{ - "id": "1905086119331868672", "tpId": "1905086117686558720", "sectionId": "1905086117879496704", - "sectionNum": "ZX00852409000329", "sectionName": "0926", "roomType": 2, "status": 1, - "openTime": "2025-04-27 14:42:00", "juryNumber": "5" - }, - { - "id": "1905086119331868671", "tpId": "1905086117686558720", "sectionId": "1905086117879496701", - "sectionNum": "ZX00852409000321", "sectionName": "0926-2", "roomType": 2, - "status": 1, "openTime": "2025-04-25 12:42:00", "juryNumber": "7" - }] - }; - secVals = res.data.map((item: any) => { return item.sectionId }) - data = res.data; - // } - setSections(data); - setSectionsVal(secVals); - setIndeterminate(!!checked.length && checked.length < secVals.length); - setCheckAll(checked.length === secVals.length); - updateData && String(updateData?.reserveStatus) == "1" && getEarliestTime(data, checked);//初始化赋值数据 - // }) : null; + modalVis == true ? getSecs({ ...params }).then((res) => { + let data = []; + let secVals = []; + if (res.success) { + secVals = res.data.map((item: any) => { return item.sectionId }) + data = res.data; + } + setSections(data); + setSectionsVal(secVals); + setIndeterminate(!!checked.length && checked.length < secVals.length); + setCheckAll(checked.length === secVals.length); + updateData && String(updateData?.reserveStatus) == "1" && getEarliestTime(data, checked);//初始化赋值数据 + }) : null; }, [sectionCount]); @@ -402,10 +387,7 @@ const JudgingPanel: React.FC<{}> = () => { let res = true; const defId = getDefId();//16 const method = getProMethod();//9 - //TODO zyx--假数据--start - const yushenType = "open_tender_form_1"; - // const yushenType = getSessionProjectData().openTenderForm; - //TODO zyx--假数据--end + const yushenType = getProOpenTenderForm(); let manNumT = 5; if (method === 'procurement_mode_1' || method === 'procurement_mode_2') { @@ -487,8 +469,10 @@ const JudgingPanel: React.FC<{}> = () => { // 在 useEffect 中监听依赖项 useEffect(() => { - calculateExpertNumber(); - }, [form.getFieldValue('representativeNumber'), checkedList]); + if (Array.isArray(sections) && sections.length > 0) { + calculateExpertNumber(); + } + }, [form.getFieldValue('representativeNumber'), checkedList, sections]); const tab1 = () => {//cqtab1 return ( <> @@ -1042,16 +1026,12 @@ const JudgingPanel: React.FC<{}> = () => { }); }, [memberCount]); async function queryOpenStatus(id: any) {//查是否开启评标 id:评委会id - //TODO ZYX假数据-start - openSet(false); - allEndSet(false); - // await roomStatus(id).then((res) => { - // if (res.data) { - // openSet(res.data.anyOpenRoom); - // allEndSet(res.data.allEndRoom); - // } - // }) - //TODO ZYX假数据-end + await roomStatus(id).then((res) => { + if (res.data) { + openSet(res.data.anyOpenRoom); + allEndSet(res.data.allEndRoom); + } + }) } const returnPanel = () => {//返回手风琴 return ( From eb90574c7472dcaa67de97712717c1528f18d19d Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Sat, 14 Jun 2025 10:31:48 +0800 Subject: [PATCH 04/21] =?UTF-8?q?=E8=AF=84=E5=A7=94=E4=BC=9A=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../JudgingPanel/List/index.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx b/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx index 74008d9..3792955 100644 --- a/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx +++ b/src/pages/Tender/ProjectManager/JudgingPanel/List/index.tsx @@ -1037,7 +1037,7 @@ const JudgingPanel: React.FC<{}> = () => { return ( <> {daibiao.juryMemberList != undefined ? - + = () => { : null} {qita.juryMemberList != undefined ? - + = () => { search={false} pagination={false} toolBarRender={() => [ - + // ]} /> From a31cf954cfd3e13fd2ce33987f48e3f3d1cfa1fd Mon Sep 17 00:00:00 2001 From: lix Date: Thu, 12 Jun 2025 17:19:52 +0800 Subject: [PATCH 05/21] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.ts | 8 +- config/defaultSettings.ts | 2 +- config/theme.js | 24 ++++++ src/assets/home.svg | 1 + src/assets/shutdown.svg | 1 + src/assets/user.svg | 1 + src/baseStyle.less | 39 ++++++++-- src/components/GlobalHeader/RightContent.tsx | 81 +++++++++++++------- src/components/GlobalHeader/index.less | 6 +- src/global.less | 2 +- src/pages/MainPage/ProjectManager/index.less | 6 +- 11 files changed, 124 insertions(+), 47 deletions(-) create mode 100644 config/theme.js create mode 100644 src/assets/home.svg create mode 100644 src/assets/shutdown.svg create mode 100644 src/assets/user.svg diff --git a/config/config.ts b/config/config.ts index c3955ff..e708dfb 100644 --- a/config/config.ts +++ b/config/config.ts @@ -2,7 +2,10 @@ import { defineConfig } from 'umi'; import defaultSettings from './defaultSettings'; // import proxy from './proxy'; import PageRoutes from './router.config' +import theme from './theme'; + const { REACT_APP_ENV } = process.env; + export default defineConfig({ hash: true, antd: {}, @@ -25,10 +28,7 @@ export default defineConfig({ // umi routes: https://umijs.org/docs/routing routes: PageRoutes, // Theme for antd: https://ant.design/docs/react/customize-theme-cn - theme: { - // ...darkTheme, - 'primary-color': defaultSettings.primaryColor, - }, + theme, // @ts-ignore title: false, ignoreMomentLocale: true, diff --git a/config/defaultSettings.ts b/config/defaultSettings.ts index d281703..ca8c2e9 100644 --- a/config/defaultSettings.ts +++ b/config/defaultSettings.ts @@ -6,7 +6,7 @@ type DefaultSettings = ProSettings & { const proSettings: DefaultSettings = { navTheme: 'light', - primaryColor: '#b30000', + primaryColor: '#014F8F', layout: 'side', contentWidth: 'Fluid', fixedHeader: false, diff --git a/config/theme.js b/config/theme.js new file mode 100644 index 0000000..3fdf767 --- /dev/null +++ b/config/theme.js @@ -0,0 +1,24 @@ +export default { + // 主题色 + 'primary-color': '#014F8F', + // 按钮圆角 + 'border-radius-base': '4px', + // layout background + 'layout-background': '#F5F7FA', + // 链接色 + 'link-color': '#014F8F', + // layout-header-background + 'layout-header-background': '#ffffff', + // error + 'error-color': '#D7000F', + // menu background + 'menu-list-bg': '#F2F6FC', + // menu item selected background + 'menu-item-selected-bg': '#D9ECFF', + // table header + 'table-header-bg': '#F2F6FC', + // table header text color + 'table-header-color': '#8F9298', + // table select row background + 'table-selected-row-bg': '#F2F6FC', +} \ No newline at end of file diff --git a/src/assets/home.svg b/src/assets/home.svg new file mode 100644 index 0000000..8405c6c --- /dev/null +++ b/src/assets/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/shutdown.svg b/src/assets/shutdown.svg new file mode 100644 index 0000000..917c660 --- /dev/null +++ b/src/assets/shutdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/user.svg b/src/assets/user.svg new file mode 100644 index 0000000..44c668d --- /dev/null +++ b/src/assets/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/baseStyle.less b/src/baseStyle.less index 3165e50..2dec159 100644 --- a/src/baseStyle.less +++ b/src/baseStyle.less @@ -3,12 +3,17 @@ top: 0; left: 0; .ant-pro-global-header{ - background-color: #b30000; + background-color: @layout-header-background; height: 56px; - color: #fff; + color: @primary-color; } } +// 通用页面布局样式 +.layout-container { + background-color: @layout-background; + min-height: 100vh; +} .ant-pro-sider-logo { background-color: #b30000; @@ -160,11 +165,11 @@ } -.ant-pro-table{ - .ant-card-body{ - padding: 0px; - } -} +// .ant-pro-table{ +// .ant-card-body{ +// padding: 0px; +// } +// } .ant-pro-table-search { padding: 10px 24px 6px 24px; @@ -308,3 +313,23 @@ input::-webkit-outer-spin-button, padding: 6px 24px; border-bottom: 1px solid #ddd; } + +#root { + .ant-table-tbody > tr.ant-table-row:hover > td, + .ant-table-tbody > tr > td.ant-table-cell-row-hover { + background-color: @table-selected-row-bg; + } +} + +// 控制左侧菜单背景色 +.ant-menu.ant-menu-sub.ant-menu-inline { + background-color: @menu-list-bg; + + .ant-menu-item-selected { + background-color: @menu-item-selected-bg; + } + .ant-menu-item-selected a { + color: @primary-color; + font-weight: bold; + } +} diff --git a/src/components/GlobalHeader/RightContent.tsx b/src/components/GlobalHeader/RightContent.tsx index ad7dc52..aad3ee8 100644 --- a/src/components/GlobalHeader/RightContent.tsx +++ b/src/components/GlobalHeader/RightContent.tsx @@ -9,27 +9,32 @@ import './index.less'; import { getMenu, getLogout } from './services' import { getSessionUserData } from "@/utils/session"; import { getToSecondUrl } from '@/pages/LoadingPage/service'; +import userIcon from '@/assets/user.svg'; +import homeIcon from '@/assets/home.svg'; +import shutdownIcon from '@/assets/shutdown.svg'; +import { logout } from './services'; +import cookie from 'react-cookies'; const GlobalHeaderRight: React.FC<{}> = (props) => { // let className = styles.right; - let data = getSessionUserData(); + const data = getSessionUserData(); const [dataMenu, setDataMenu] = React.useState([]); const urlRef = useRef(null); const handelRole = (item: any) => { sessionStorage.setItem('roleData', JSON.stringify(item)); sessionStorage.setItem('roleAuthority', JSON.stringify([item.roleCode])); - let params = { + const params = { roleIdList: [item.roleId] } history.push('/Dashboard') window.location.reload() - getMenu(params).then(res => { - if (res?.code == 1) { - setDataMenu(res?.data) - } else { - message.error("数据错误请联系管理员") - } - }) + // getMenu(params).then(res => { + // if (res?.code == 1) { + // setDataMenu(res?.data) + // } else { + // message.error("数据错误请联系管理员") + // } + // }) } //角色退出登录 const toLogout = () => { @@ -40,15 +45,21 @@ const GlobalHeaderRight: React.FC<{}> = (props) => { title: '请确认是否退出?', content: false, onOk() { - getLogout().then((res) => { + logout().then((res) => { if (res?.success) { - if (data?.userType == "0") {//联通智慧门户 - window.close(); - } else if (data?.userType == "1") {//合作方 - window.close(); - } else if (data?.userType == "2") {//专家 - window.location.href = "/userformal/login" - } + // if (data?.userType == "0") {//联通智慧门户 + // window.close(); + // } else if (data?.userType == "1") {//合作方 + // window.close(); + // } else if (data?.userType == "2") {//专家 + // window.location.href = "/userformal/login" + // } + message.success('退出登录成功'); + sessionStorage.clear(); + cookie.remove('mall3_token'); + setTimeout(() => { + history.push('/internal-login'); + }, 1000); } }) }, @@ -62,17 +73,17 @@ const GlobalHeaderRight: React.FC<{}> = (props) => { const droMenu = ( {data?.authorityList != undefined ? - data?.authorityList?.map((item: any, index: any) => ( - + data?.authorityList?.map((item: any) => ( + handelRole(item)}>{item.roleName} )) : null} - <> + {/* <> toLogout()}>退出登录 - + */} ); @@ -89,21 +100,35 @@ const GlobalHeaderRight: React.FC<{}> = (props) => { return (
- 中国联通智慧供应链平台 | 招标采购中心 +
+
+ +
+
+ 采购平台供应商统一管理系统 + CHINA COSCO SHIPPING CORPORATION LIMITED +
+
diff --git a/src/components/GlobalHeader/index.less b/src/components/GlobalHeader/index.less index 72eeb15..f3dfeec 100644 --- a/src/components/GlobalHeader/index.less +++ b/src/components/GlobalHeader/index.less @@ -25,8 +25,8 @@ float: left; line-height: 56px; font-size: 14px; - color: #fff; - padding: 0 14px; + color: inherit; + padding: 0 12px; list-style: none; span { @@ -35,7 +35,7 @@ } a { - color: #fff; + color: #131414 !important; } } } diff --git a/src/global.less b/src/global.less index c85eb4b..af3d51a 100644 --- a/src/global.less +++ b/src/global.less @@ -51,7 +51,7 @@ ol { } // 兼容IE11 -@media screen and(-ms-high-contrast: active), (-ms-high-contrast: none) { +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { body .ant-design-pro > .ant-layout { min-height: 100vh; } diff --git a/src/pages/MainPage/ProjectManager/index.less b/src/pages/MainPage/ProjectManager/index.less index 2a0db0f..5964d3e 100644 --- a/src/pages/MainPage/ProjectManager/index.less +++ b/src/pages/MainPage/ProjectManager/index.less @@ -14,7 +14,7 @@ border-radius: 5px; overflow-y:hidden; .moret{ - color:#b30000; + color:@primary-color; font-size:12px; cursor: pointer; } @@ -101,7 +101,7 @@ // background:#FFFFFF; border-radius: 5px; .moret{ - color:#b30000; + color:@primary-color; font-size:12px; cursor: pointer; } @@ -270,7 +270,7 @@ border-top-left-radius: 10px; border-bottom-left-radius: 10px; padding: 10px 6px 0; - background: #b30000; + background: @primary-color; z-index: 100; color: #fff; text-align: center; From f2ef1e81c8c5a4192a44c6f6f01d8134baaf3ed4 Mon Sep 17 00:00:00 2001 From: lix Date: Fri, 20 Jun 2025 14:55:00 +0800 Subject: [PATCH 06/21] login --- config/config.UAT.ts | 2 +- config/config.dev.ts | 2 +- config/config.prod.ts | 2 +- config/config.sim.ts | 2 +- config/proxy.ts | 14 +- config/router_transfer.ts | 4 + package.json | 1 + src/components/CaptchaInput/index.less | 48 +++ src/components/CaptchaInput/index.tsx | 72 ++++ src/components/GlobalHeader/services.ts | 6 + src/pages/LoadingPage/index.tsx | 358 +++++++++--------- src/pages/LoadingPage/service.ts | 2 +- src/pages/Login/internal.less | 100 +++++ src/pages/Login/internal.tsx | 151 ++++++++ .../components/ProjectDocumentation.tsx | 2 +- .../components/InvitationLetter.tsx | 2 +- src/services/login.ts | 39 +- src/utils/encrypt.ts | 9 + src/utils/request.ts | 1 + src/utils/session.ts | 2 +- 20 files changed, 624 insertions(+), 195 deletions(-) create mode 100644 src/components/CaptchaInput/index.less create mode 100644 src/components/CaptchaInput/index.tsx create mode 100644 src/pages/Login/internal.less create mode 100644 src/pages/Login/internal.tsx create mode 100644 src/utils/encrypt.ts diff --git a/config/config.UAT.ts b/config/config.UAT.ts index a022290..6e23f3e 100644 --- a/config/config.UAT.ts +++ b/config/config.UAT.ts @@ -12,7 +12,7 @@ export default defineConfig({ //密码加密参数 REACT_APP_PASSWORD_CIPHERMODE:'1', - REACT_APP_PASSWORD_PUBLICKEY:'0428D625CEEB71CE823BD7D78DFEE7B122F2DA5C4D21E32253AD684D0FE21810394A799639C0CDFBFEB535A1DFD6A366A637E582CE0B1466A5FE7858841135DE6B', + REACT_APP_PASSWORD_PUBLICKEY:'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvLBkALIYR/x9Rv5TiXQGWAXTzraN/He80r9gQovSQ5oTP8qllL9+Oc1LdTijPFRsddHWg37umvFliwhmukU1NT+o2loGcKpyMHFkc/UPNjQLvd+YFR4nYhgP8l+dmRNOtQWawOt5dbksRKTghMjA+FKT2+itMsawSs1+Ic+zoIwIDAQAB', //当前环境 START_ENV:'UAT', diff --git a/config/config.dev.ts b/config/config.dev.ts index d7f0893..06c4372 100644 --- a/config/config.dev.ts +++ b/config/config.dev.ts @@ -12,7 +12,7 @@ export default defineConfig({ //密码加密参数 REACT_APP_PASSWORD_CIPHERMODE: '1', - REACT_APP_PASSWORD_PUBLICKEY: '0428D625CEEB71CE823BD7D78DFEE7B122F2DA5C4D21E32253AD684D0FE21810394A799639C0CDFBFEB535A1DFD6A366A637E582CE0B1466A5FE7858841135DE6B', + REACT_APP_PASSWORD_PUBLICKEY: 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvLBkALIYR/x9Rv5TiXQGWAXTzraN/He80r9gQovSQ5oTP8qllL9+Oc1LdTijPFRsddHWg37umvFliwhmukU1NT+o2loGcKpyMHFkc/UPNjQLvd+YFR4nYhgP8l+dmRNOtQWawOt5dbksRKTghMjA+FKT2+itMsawSs1+Ic+zoIwIDAQAB', //当前环境 START_ENV: 'DEV', diff --git a/config/config.prod.ts b/config/config.prod.ts index 61ff507..5fbd4a6 100644 --- a/config/config.prod.ts +++ b/config/config.prod.ts @@ -12,7 +12,7 @@ export default defineConfig({ //密码加密参数 REACT_APP_PASSWORD_CIPHERMODE:'1', - REACT_APP_PASSWORD_PUBLICKEY:'04819CF427F9150FEEBD91E8D2346F203FC47312D212022A967D8372EA30B9581CCEEFCE2670BDDAF2E8DA1620EA73948126078ED9FF9773AA3A94EE6C80035A18', + REACT_APP_PASSWORD_PUBLICKEY:'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvLBkALIYR/x9Rv5TiXQGWAXTzraN/He80r9gQovSQ5oTP8qllL9+Oc1LdTijPFRsddHWg37umvFliwhmukU1NT+o2loGcKpyMHFkc/UPNjQLvd+YFR4nYhgP8l+dmRNOtQWawOt5dbksRKTghMjA+FKT2+itMsawSs1+Ic+zoIwIDAQAB', //当前环境 START_ENV:'PROD', diff --git a/config/config.sim.ts b/config/config.sim.ts index 43156ec..ebda6bf 100644 --- a/config/config.sim.ts +++ b/config/config.sim.ts @@ -12,7 +12,7 @@ export default defineConfig({ //密码加密参数 REACT_APP_PASSWORD_CIPHERMODE: '1', - REACT_APP_PASSWORD_PUBLICKEY: '0428D625CEEB71CE823BD7D78DFEE7B122F2DA5C4D21E32253AD684D0FE21810394A799639C0CDFBFEB535A1DFD6A366A637E582CE0B1466A5FE7858841135DE6B', + REACT_APP_PASSWORD_PUBLICKEY: 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvLBkALIYR/x9Rv5TiXQGWAXTzraN/He80r9gQovSQ5oTP8qllL9+Oc1LdTijPFRsddHWg37umvFliwhmukU1NT+o2loGcKpyMHFkc/UPNjQLvd+YFR4nYhgP8l+dmRNOtQWawOt5dbksRKTghMjA+FKT2+itMsawSs1+Ic+zoIwIDAQAB', //当前环境 START_ENV: 'sim', diff --git a/config/proxy.ts b/config/proxy.ts index 83636d7..ab6d58e 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -7,9 +7,9 @@ export default { // }, '/api/*': { // target: 'http://10.242.37.148:18022',//连接天宫的ng - target: 'http://localhost:3000',//连接天宫的ng + target: 'http://10.60.161.52:18030/',//连接天宫的ng changeOrigin: true, - pathRewrite: { '^': '' }, + pathRewrite: { '^/api': '' }, }, }, UAT: { @@ -38,11 +38,11 @@ export default { changeOrigin: true, pathRewrite: { '/api/biz-service-ebtp-process': '' }, }, - '/api/sys-manager-ebtp-project': { - target: 'http://localhost:18030', - changeOrigin: true, - pathRewrite: { '/api/sys-manager-ebtp-project': '' }, - }, + // '/api/sys-manager-ebtp-project': { + // target: 'http://localhost:18030', + // changeOrigin: true, + // pathRewrite: { '/api/sys-manager-ebtp-project': '' }, + // }, '/api/biz-service-ebtp-rsms': { target: 'http://localhost:18014', changeOrigin: true, diff --git a/config/router_transfer.ts b/config/router_transfer.ts index 81d12df..b6adc34 100644 --- a/config/router_transfer.ts +++ b/config/router_transfer.ts @@ -1,5 +1,9 @@ const { LOGIN_PATH } = process.env; export default [ + { + path: '/internal-login', + component: './Login/internal', + }, // {//内部人员便捷登陆页 // path: '/loginFake', // component: './Login/index', diff --git a/package.json b/package.json index 9fc119f..76d72f3 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "dva": "2.4.1", "echarts": "^5.2.2", "echarts-for-react": "^3.0.2", + "jsencrypt": "^3.3.2", "lodash": "4.17.21", "moment": "^2.29.4", "omit.js": "2.0.2", diff --git a/src/components/CaptchaInput/index.less b/src/components/CaptchaInput/index.less new file mode 100644 index 0000000..fa599b1 --- /dev/null +++ b/src/components/CaptchaInput/index.less @@ -0,0 +1,48 @@ +.captchaContainer { + width: 100%; + + :global { + .ant-input-affix-wrapper { + padding-right: 4px; + } + } + + .captchaWrapper { + display: flex; + justify-content: end; + align-items: center; + gap: 8px; + height: 40px; + width: 120px; + } + + .captchaImage { + height: 40px; + width: 100%; + cursor: pointer; + border-radius: 4px; + border: 1px solid #d9d9d9; + object-fit: contain; + background: #fff; + + &:hover { + border-color: #40a9ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + + .refreshIcon { + font-size: 16px; + color: #1890ff; + cursor: pointer; + transition: all 0.3s; + padding: 4px; + + &:hover { + color: #40a9ff; + transform: rotate(180deg); + background: rgba(24, 144, 255, 0.1); + border-radius: 4px; + } + } +} \ No newline at end of file diff --git a/src/components/CaptchaInput/index.tsx b/src/components/CaptchaInput/index.tsx new file mode 100644 index 0000000..02752ca --- /dev/null +++ b/src/components/CaptchaInput/index.tsx @@ -0,0 +1,72 @@ +import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react'; +import { Input, Spin } from 'antd'; +import { SafetyOutlined } from '@ant-design/icons'; +import styles from './index.less'; +import { getCaptcha } from '@/services/login'; + +interface CaptchaInputProps { + value?: { + captcha: string; + captchaToken: string; + }; + onChange?: (value: { captcha: string; captchaToken: string }) => void; + placeholder?: string; +} + +export interface CaptchaInputRef { + refresh: () => void; +} + +const CaptchaInput = forwardRef((props: CaptchaInputProps, ref) => { + const { value, onChange, placeholder = '请输入验证码' } = props; + const [imgUrl, setImgUrl] = useState(''); + const [captchaToken, setCaptchaToken] = useState(''); + const [loading, setLoading] = useState(false); + + // 获取验证码 + const fetchCaptcha = async () => { + setLoading(true); + try { + const res = await getCaptcha(); + if (res?.success) { + setImgUrl('data:image/png;base64,' + res.data.base64Image); + setCaptchaToken(res.data.code); + } + } catch (error) { + console.error('获取验证码失败:', error); + } finally { + setLoading(false); + } + }; + + // 组件挂载时获取验证码 + useEffect(() => { + fetchCaptcha(); + }, []); + + useImperativeHandle(ref, () => ({ + refresh: fetchCaptcha, + })); + + return ( +
+ onChange?.({ captcha: e.target.value, captchaToken: captchaToken })} + placeholder={placeholder} + maxLength={4} + prefix={} + suffix={ +
+ {loading ? : 验证码} +
+ } + /> +
+ ); +}); + +CaptchaInput.displayName = 'CaptchaInput'; + +export default CaptchaInput; \ No newline at end of file diff --git a/src/components/GlobalHeader/services.ts b/src/components/GlobalHeader/services.ts index 750f8a5..a6ba67f 100644 --- a/src/components/GlobalHeader/services.ts +++ b/src/components/GlobalHeader/services.ts @@ -22,3 +22,9 @@ export async function getLogout() { // 退出登录,注销 // params }); } + +export async function logout() { + return request('/api/v1/login/logout', { + method: 'post', + }); +} \ No newline at end of file diff --git a/src/pages/LoadingPage/index.tsx b/src/pages/LoadingPage/index.tsx index deee6f5..b1aa6c7 100644 --- a/src/pages/LoadingPage/index.tsx +++ b/src/pages/LoadingPage/index.tsx @@ -76,7 +76,7 @@ const Loading: React.FC<{}> = () => { // } else { setUserData(userData, userData.authorityList[0].roleCode, userData.authorityList[0]); // } - await setDict();//存字典 + // await setDict();//存字典 setTimeout(() => { history.push({ pathname: `/${url}`, @@ -89,185 +89,185 @@ const Loading: React.FC<{}> = () => { //获取用户信息 async function getUserData(token: string, url: string, extra: any, status: number) { -const res = { - "userId": "ex-linjp29", - "lastName": null, - "firstName": null, - "fullName": "林剑萍", - "emailAddress": null, - "loginName": "ex-linjp29", - "mobilePhone": null, - "officePhone": null, - "sex": null, - "employeeCategory": null, - "userType": "1", - "dateOfBirth": null, - "age": null, - "employeeNumber": "1743164896", - "nationalityId": null, - "nationality": null, - "nationalIdentifier": null, - "supervisorId": null, - "organizationId": "101058278", - "organizationName": "湖北信通通信有限公司", - "orgCategory": null, - "deptId": "101058278", - "deptName": "湖北信通通信有限公司", - "roleIds": null, - "bussiGroupId": null, - "positionId": null, - "currentRoleCode": "undefined", - "province": null, - "authorityList": [ - { - "roleId": "000009", - "roleName": "代理机构业务经理", - "roleCode": "ebtp-agency-project-manager", - "roleScope": "EBTP", - "authorities": [ - "ebtp-agency-project-manager", - null, - "ebtp-agency-project-manager", - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", - "ebtp-agency-project-manager", - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", - "ebtp-agency-project-manager", - "ebtp-agency-project-manager", - null, - "ebtp-agency-project-manager", - null, - "ebtp-agency-project-manager", - "ebtp-agency-project-manager", - null, - "ebtp-agency-project-manager,ebtp-expert,ebtp-agency-admin", - null, - null, - "ebtp-agency-admin", - null, - null, - null, - null, - null, - null, - null, - "ebtp-agency-project-manager", - "ebtp-agency-project-manager,ebtp-purchase", - "ebtp-agency-project-manager,ebtp-purchase", - "ebtp-agency-project-manager,ebtp-purchase", - "ebtp-agency-project-manager,ebtp-purchase", - "ebtp-agency-project-manager,ebtp-purchase", - null, - null, - null, - null, - null, - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier", - "ebtp-agency-project-manager,ebtp-supplier", - "ebtp-agency-project-manager", - "ebtp-agency-project-manager", - null - ] - }, - { - "roleId": "000006", - "roleName": "供应商", - "roleCode": "ebtp-supplier", - "roleScope": "EBTP", - "authorities": [ - "system:user:test", - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", - "system:user:test", - "ebtp-agency-project-manager", - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", - "ebtp-supplier", - "ebtp-supplier", - "system:user:test", - "system:user:test", - "ebtp-agency-project-manager,ebtp-expert,ebtp-agency-admin", - "ebtp-supplier", - "system:user:test", - "ebtp-supplier", - "system:user:test", - "ebtp-supplier", - "ebtp-supplier", - "ebtp-supplier", - "ebtp-supplier", - "ebtp-supplier", - "ebtp-supplier", - "ebtp-supplier", - null, - null, - null, - "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier", - "ebtp-agency-project-manager,ebtp-supplier", - "ebtp-supplier", - "system:user:test", - "system:user:test", - "system:user:test", - "ebtp-agency-project-manager", - "system:user:test" - ] - } - ] -} - if (res?.authorityList == null || res?.authorityList?.length == 0) { - if (url == 'ExamineAndApprove/Announcement' || - url == 'ExamineAndApprove/ChangeTheAnnouncement' || - url == 'ExamineAndApprove/Publicity' || - url == 'ExamineAndApprove/InvitationLetter' || - url == 'ExamineAndApprove/ExternalReference' || - url == 'ExamineAndApprove/FailureAnnouncement') { - let newAuthority: any[] = [] - newAuthority.push({ - authorities: [null, "system:user:test", "system:user:test", "system:user:test", "system:user:test", null, null], - roleCode: "ebtp-unicom-default", - roleId: "20004", - roleName: "联通普通用户", - roleScope: "EBTP" - }) - res.authorityList = [...newAuthority]; - await redirect(res, url, extra); +// const res = { +// "userId": "ex-linjp29", +// "lastName": null, +// "firstName": null, +// "fullName": "林剑萍", +// "emailAddress": null, +// "loginName": "ex-linjp29", +// "mobilePhone": null, +// "officePhone": null, +// "sex": null, +// "employeeCategory": null, +// "userType": "1", +// "dateOfBirth": null, +// "age": null, +// "employeeNumber": "1743164896", +// "nationalityId": null, +// "nationality": null, +// "nationalIdentifier": null, +// "supervisorId": null, +// "organizationId": "101058278", +// "organizationName": "湖北信通通信有限公司", +// "orgCategory": null, +// "deptId": "101058278", +// "deptName": "湖北信通通信有限公司", +// "roleIds": null, +// "bussiGroupId": null, +// "positionId": null, +// "currentRoleCode": "undefined", +// "province": null, +// "authorityList": [ +// { +// "roleId": "000009", +// "roleName": "代理机构业务经理", +// "roleCode": "ebtp-agency-project-manager", +// "roleScope": "EBTP", +// "authorities": [ +// "ebtp-agency-project-manager", +// null, +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager", +// null, +// "ebtp-agency-project-manager", +// null, +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager", +// null, +// "ebtp-agency-project-manager,ebtp-expert,ebtp-agency-admin", +// null, +// null, +// "ebtp-agency-admin", +// null, +// null, +// null, +// null, +// null, +// null, +// null, +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager,ebtp-purchase", +// "ebtp-agency-project-manager,ebtp-purchase", +// "ebtp-agency-project-manager,ebtp-purchase", +// "ebtp-agency-project-manager,ebtp-purchase", +// "ebtp-agency-project-manager,ebtp-purchase", +// null, +// null, +// null, +// null, +// null, +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier", +// "ebtp-agency-project-manager,ebtp-supplier", +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager", +// null +// ] +// }, +// { +// "roleId": "000006", +// "roleName": "供应商", +// "roleCode": "ebtp-supplier", +// "roleScope": "EBTP", +// "authorities": [ +// "system:user:test", +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", +// "system:user:test", +// "ebtp-agency-project-manager", +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier,ebtp-agency-admin", +// "ebtp-supplier", +// "ebtp-supplier", +// "system:user:test", +// "system:user:test", +// "ebtp-agency-project-manager,ebtp-expert,ebtp-agency-admin", +// "ebtp-supplier", +// "system:user:test", +// "ebtp-supplier", +// "system:user:test", +// "ebtp-supplier", +// "ebtp-supplier", +// "ebtp-supplier", +// "ebtp-supplier", +// "ebtp-supplier", +// "ebtp-supplier", +// "ebtp-supplier", +// null, +// null, +// null, +// "ebtp-agency-project-manager,ebtp-expert,ebtp-supplier", +// "ebtp-agency-project-manager,ebtp-supplier", +// "ebtp-supplier", +// "system:user:test", +// "system:user:test", +// "system:user:test", +// "ebtp-agency-project-manager", +// "system:user:test" +// ] +// } +// ] +// } +// if (res?.authorityList == null || res?.authorityList?.length == 0) { +// if (url == 'ExamineAndApprove/Announcement' || +// url == 'ExamineAndApprove/ChangeTheAnnouncement' || +// url == 'ExamineAndApprove/Publicity' || +// url == 'ExamineAndApprove/InvitationLetter' || +// url == 'ExamineAndApprove/ExternalReference' || +// url == 'ExamineAndApprove/FailureAnnouncement') { +// let newAuthority: any[] = [] +// newAuthority.push({ +// authorities: [null, "system:user:test", "system:user:test", "system:user:test", "system:user:test", null, null], +// roleCode: "ebtp-unicom-default", +// roleId: "20004", +// roleName: "联通普通用户", +// roleScope: "EBTP" +// }) +// res.authorityList = [...newAuthority]; +// await redirect(res, url, extra); +// } +// }else { +// await redirect(res, url, extra); +// } + fgetUserMsg(token).then(async res => { + if (res) { + if (res?.userType == null) { + error('401'); + } else { + if (res?.authorityList == null || res?.authorityList?.length == 0) { + if (url == 'ExamineAndApprove/Announcement' || + url == 'ExamineAndApprove/ChangeTheAnnouncement' || + url == 'ExamineAndApprove/Publicity' || + url == 'ExamineAndApprove/InvitationLetter' || + url == 'ExamineAndApprove/ExternalReference' || + url == 'ExamineAndApprove/FailureAnnouncement') { + const newAuthority: any[] = [] + newAuthority.push({ + authorities: [null, "system:user:test", "system:user:test", "system:user:test", "system:user:test", null, null], + roleCode: "ebtp-cosco-default", + roleId: "20004", + roleName: "普通用户", + roleScope: "EBTP" + }) + res.authorityList = [...newAuthority]; + await redirect(res, url, extra); + } else { + if (status == 0) { + await refreshUserData(res?.userType, token, url, extra); + } else { + error('401'); + } + } + } else { + await redirect(res, url, extra); + } + } + } else { + message.error("登录信息有误,请重新登录") } - }else { - await redirect(res, url, extra); - } - // await fgetUserMsg(token).then(async res => { - // if (res) { - // if (res?.userType == null) { - // error('401'); - // } else { - // if (res?.authorityList == null || res?.authorityList?.length == 0) { - // if (url == 'ExamineAndApprove/Announcement' || - // url == 'ExamineAndApprove/ChangeTheAnnouncement' || - // url == 'ExamineAndApprove/Publicity' || - // url == 'ExamineAndApprove/InvitationLetter' || - // url == 'ExamineAndApprove/ExternalReference' || - // url == 'ExamineAndApprove/FailureAnnouncement') { - // let newAuthority: any[] = [] - // newAuthority.push({ - // authorities: [null, "system:user:test", "system:user:test", "system:user:test", "system:user:test", null, null], - // roleCode: "ebtp-unicom-default", - // roleId: "20004", - // roleName: "联通普通用户", - // roleScope: "EBTP" - // }) - // res.authorityList = [...newAuthority]; - // await redirect(res, url, extra); - // } else { - // if (status == 0) { - // await refreshUserData(res?.userType, token, url, extra); - // } else { - // error('401'); - // } - // } - // } else { - // await redirect(res, url, extra); - // } - // } - // } else { - // message.error("登录信息有误,请重新登录") - // } - // }) + }) } //通过code取token async function getToken(code: string, data: any) { diff --git a/src/pages/LoadingPage/service.ts b/src/pages/LoadingPage/service.ts index 1a8ec45..dc5401e 100644 --- a/src/pages/LoadingPage/service.ts +++ b/src/pages/LoadingPage/service.ts @@ -6,7 +6,7 @@ import request from '@/utils/request'; * @returns */ export async function fgetUserMsg(params: any) { - return request('/api/sys-manager-ebtp-project/v1/userinfo/get', { + return request('/api/v1/userinfo/get', { method: 'GET', headers: { 'Authorization': params }, data: params, diff --git a/src/pages/Login/internal.less b/src/pages/Login/internal.less new file mode 100644 index 0000000..5ba938b --- /dev/null +++ b/src/pages/Login/internal.less @@ -0,0 +1,100 @@ +.loginContainer { + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + background-color: #f5f7fa; + padding: 20px; +} + +.loginCard { + width: 100%; + max-width: 480px; + box-shadow: 0 4px 24px rgba(0, 0, 0, 0.1); + border-radius: 8px; + + :global { + .ant-card-body { + padding: 40px 48px; + } + } +} + +.loginTabs { + :global { + // 自定义标签页样式 + .ant-tabs-tab { + font-size: 16px; + padding: 12px 24px; + margin: 0 8px !important; + + &:hover { + color: #1890ff; + } + } + + .ant-tabs-tab-active { + background-color: #1890ff; + color: #fff !important; + border-radius: 4px; + + .ant-tabs-tab-btn { + color: #fff !important; + } + } + + // 移除底部边框 + .ant-tabs-nav::before { + border: none; + } + + .ant-tabs-ink-bar { + display: none; + } + + // 表单样式 + .ant-form-item { + margin-bottom: 24px; + } + + // 登录按钮样式 + .ant-btn-primary { + height: 48px; + font-size: 16px; + border-radius: 4px; + + &:hover { + background-color: #40a9ff; + border-color: #40a9ff; + } + } + + // 输入框样式 + .ant-input-affix-wrapper { + border-radius: 4px; + + &:hover { + border-color: #40a9ff; + } + + &:focus, + &-focused { + border-color: #1890ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + + .ant-input { + border-radius: 4px; + + &:hover { + border-color: #40a9ff; + } + + &:focus { + border-color: #1890ff; + box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); + } + } + } +} \ No newline at end of file diff --git a/src/pages/Login/internal.tsx b/src/pages/Login/internal.tsx new file mode 100644 index 0000000..1411700 --- /dev/null +++ b/src/pages/Login/internal.tsx @@ -0,0 +1,151 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Form, Input, Button, Checkbox, Card, Typography } from 'antd'; +import { UserOutlined, LockOutlined, EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons'; +import { history } from 'umi'; +import cookie from 'react-cookies'; +import CaptchaInput from '@/components/CaptchaInput'; +import styles from './internal.less'; +import { internalUserLogin } from '@/services/login'; + +const { Title, Link } = Typography; + +interface LoginFormValues { + username: string; + password: string; + captcha: { + captcha: string; + captchaToken: string; + }; + remember: boolean; +} + +const InternalLogin: React.FC = () => { + const [form] = Form.useForm(); + const [loading, setLoading] = useState(false); + const captchaRef = useRef(null); + + const onFinish = async (values: LoginFormValues) => { + const params = { + account: values.username, + password: values.password, + captcha: values.captcha, + remember: values.remember, + } + try { + setLoading(true); + const res = await internalUserLogin(params); + if (res?.code === 200) { + sessionStorage.setItem('Authorization', res?.data?.token || ''); + history.push('/redirect'); + } else { + captchaRef.current?.refresh(); + form.setFieldsValue({ + captcha: { + captcha: '', + captchaToken: '', + }, + }); + } + } catch (error) { + console.error('登录失败:', error); + } finally { + setLoading(false); + } + }; + + + // 组件挂载时,检查是否有记住的用户名 + useEffect(() => { + const savedUser = localStorage.getItem('remember_user'); + if (savedUser) { + const user = JSON.parse(savedUser); + form.setFieldsValue({ + username: user.username, + password: user.password, + remember: true, + }); + } + }, [form]); + + useEffect(() => { + cookie.remove('mall3_token'); + sessionStorage.clear(); + }, []); + + const renderLoginForm = () => ( +
+ + } + placeholder={'请输入用户名'} + /> + + + + } + placeholder="请输入密码" + iconRender={(visible) => (visible ? : )} + /> + + + + + + + +
+ + 记住密码 + + 忘记密码? +
+
+ + + + + +
+ 还没有账号? + 立即注册 +
+
+ ); + + return ( +
+ + + 电子招投标平台 + + + {renderLoginForm()} + +
+ ); +}; + +export default InternalLogin; \ No newline at end of file diff --git a/src/pages/Project/ProjectManage/ProjectManager/ProjectDocumentation/components/ProjectDocumentation.tsx b/src/pages/Project/ProjectManage/ProjectManager/ProjectDocumentation/components/ProjectDocumentation.tsx index ad9105b..98ce7ee 100644 --- a/src/pages/Project/ProjectManage/ProjectManager/ProjectDocumentation/components/ProjectDocumentation.tsx +++ b/src/pages/Project/ProjectManage/ProjectManager/ProjectDocumentation/components/ProjectDocumentation.tsx @@ -47,7 +47,7 @@ const ProjectDocumentation: React.FC = () => { title: '采购方式', dataIndex: 'bidMethodDict', valueType: 'select', - valueEnum: proTableValueEnumOther(dictData[procurementModeEntrust], proTypeCode), + valueEnum: proTableValueEnumOther(dictData?.[procurementModeEntrust], proTypeCode), search: proTypeCode.length > 1 ? void 0 : false, }, title: { diff --git a/src/pages/Tender/supplier/InvitationLetter/components/InvitationLetter.tsx b/src/pages/Tender/supplier/InvitationLetter/components/InvitationLetter.tsx index e99c566..437da6d 100644 --- a/src/pages/Tender/supplier/InvitationLetter/components/InvitationLetter.tsx +++ b/src/pages/Tender/supplier/InvitationLetter/components/InvitationLetter.tsx @@ -206,7 +206,7 @@ const LookingForBusinessOpportunitiesList: React.FC = () => { dataIndex: 'bidMethodDict', search: proTypeCode?.length > 1 ? void 0 : false, width: '8%', - valueEnum: proTableValueEnumOther(dictData[procurementModeEntrust], proTypeCode) + valueEnum: proTableValueEnumOther(dictData?.[procurementModeEntrust], proTypeCode) }, { title: '项目名称', diff --git a/src/services/login.ts b/src/services/login.ts index 075bca8..4632326 100644 --- a/src/services/login.ts +++ b/src/services/login.ts @@ -1,5 +1,6 @@ import request from '@/utils/request'; import { getEncrypt } from '@/utils/session'; +import { encryptData } from '@/utils/encrypt'; export interface LoginParamsType { userName: string; @@ -13,6 +14,14 @@ export interface FaceLoginParamsType { multipartFiles: Blob; } +export interface InternalUserLoginParamsType { + account: string; + password: string; + captcha: { + captcha: string; + captchaToken: string; + }; +} const sm2 = require('sm-crypto').sm2; const encrypt = getEncrypt(); @@ -61,7 +70,7 @@ export async function ZjfakeAccountLogin(params: LoginParamsType) { // 专家人脸登录 export async function ZjfakeFaceLogin(params: FaceLoginParamsType) { - var formData = new FormData(); + const formData = new FormData(); formData.append('idNo', params.userName); formData.append('multipartFiles', params.multipartFiles, 'upload_face.jpeg'); return request('/api/sys-manager-ebtp-project/outer/v1/ebtp/face/faceCompare', { @@ -133,3 +142,31 @@ export async function logoutTokenApi() { // params: params }); } + +/** + * 获取图形验证码 + * @returns Promise<{ success: boolean; data: { base64Image: string, code: string } }> + */ +export async function getCaptcha() { + return request('/api/v1/login/getCaptcha', { + method: 'GET', + }); +} + +/** + * 内部用户登录 + */ +export async function internalUserLogin(params: InternalUserLoginParamsType) { + // 加密密码 + const encryptedPassword = encryptData(params.password); + const data = { + account: params.account, + password: encryptedPassword, + identifying: params.captcha.captcha, + encryptValue: params.captcha.captchaToken, + } + return request('/api/v1/login/accountLogin', { + method: 'POST', + data, + }); +} \ No newline at end of file diff --git a/src/utils/encrypt.ts b/src/utils/encrypt.ts new file mode 100644 index 0000000..ae499a0 --- /dev/null +++ b/src/utils/encrypt.ts @@ -0,0 +1,9 @@ +import JSEncrypt from 'jsencrypt'; + +const encrypt = new JSEncrypt(); + +encrypt.setPublicKey(REACT_APP_PASSWORD_PUBLICKEY); + +export function encryptData(data: string) { + return encrypt.encrypt(data) || ''; +} diff --git a/src/utils/request.ts b/src/utils/request.ts index af6b1c6..db5c5b9 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -94,6 +94,7 @@ request.interceptors.request.use(async (url, options) => { headers = { Authorization: getUserToken() == null ? null : getUserToken(), currentRoleCode: getSessionRoleData()?.roleCode, + Mall3Check: 'mall3_token', ...options.headers, }; } diff --git a/src/utils/session.ts b/src/utils/session.ts index 004c04b..a4737c4 100644 --- a/src/utils/session.ts +++ b/src/utils/session.ts @@ -257,7 +257,7 @@ export async function jurySaveInfo(record: any) { * 获取国密加密算法需要的属性 */ export function getEncrypt() { - let encrypt = { + const encrypt = { cipherMode: REACT_APP_PASSWORD_CIPHERMODE, publicKey: REACT_APP_PASSWORD_PUBLICKEY } From 6b5ca668d692f580b3d93c2651c02256d8225bd8 Mon Sep 17 00:00:00 2001 From: houjishuang <46269784@qq.com> Date: Mon, 23 Jun 2025 14:10:32 +0800 Subject: [PATCH 07/21] qidongbaocuo --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 9fc119f..d694096 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,9 @@ "private": true, "description": "An out-of-box UI solution for enterprise applications", "scripts": { - "start-dev": "cross-env UMI_UI=none UMI_ENV=dev LOGIN_PATH=ebtp-frontend umi dev --port=3000", - "start-UAT": "cross-env UMI_UI=none UMI_ENV=UAT LOGIN_PATH=ebtp-frontend umi dev --port=3000", - "start-sim": "cross-env UMI_UI=none UMI_ENV=sim LOGIN_PATH=ebtp-frontend umi dev --port=3000", + "start-dev": "set NODE_OPTIONS=--openssl-legacy-provider & cross-env UMI_UI=none UMI_ENV=dev LOGIN_PATH=ebtp-frontend umi dev --port=3000", + "start-UAT": "set NODE_OPTIONS=--openssl-legacy-provider & cross-env UMI_UI=none UMI_ENV=UAT LOGIN_PATH=ebtp-frontend umi dev --port=3000", + "start-sim": "set NODE_OPTIONS=--openssl-legacy-provider & cross-env UMI_UI=none UMI_ENV=sim LOGIN_PATH=ebtp-frontend umi dev --port=3000", "start-prod": "cross-env UMI_UI=none UMI_ENV=prod LOGIN_PATH=prod/ebtp-frontend umi dev --port=3000", "build-dev": "cross-env UMI_ENV=dev LOGIN_PATH=ebtp-frontend umi build", "build-UAT": "cross-env UMI_ENV=UAT LOGIN_PATH=ebtp-frontend umi build", From 8a660bbb54c87c32df2dbc26406306d9e9a0dcf3 Mon Sep 17 00:00:00 2001 From: sunyu Date: Tue, 24 Jun 2025 17:08:26 +0800 Subject: [PATCH 08/21] =?UTF-8?q?=E6=8A=95=E6=A0=87=E3=80=81=E5=AE=9A?= =?UTF-8?q?=E6=A0=87=E4=BA=8B=E9=A1=B9=E7=B1=BB=E5=88=AB=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SupplierQuestionsOrObjections.tsx | 41 ++++++++++++------- .../SupplierQuestionsOrObjections/utils.ts | 23 ++++++----- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/pages/Tender/supplier/SupplierQuestionsOrObjections/components/SupplierQuestionsOrObjections.tsx b/src/pages/Tender/supplier/SupplierQuestionsOrObjections/components/SupplierQuestionsOrObjections.tsx index cee82de..68907c6 100644 --- a/src/pages/Tender/supplier/SupplierQuestionsOrObjections/components/SupplierQuestionsOrObjections.tsx +++ b/src/pages/Tender/supplier/SupplierQuestionsOrObjections/components/SupplierQuestionsOrObjections.tsx @@ -80,11 +80,24 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { const proceedingTypeByBidMethodDict = getProceedingTypeByBidMethodDict(bidMethodDict); const proceedingTypeByDefId = getProceedingTypeByDefId(getDefId()) const [spinning, setSping] = useState(false);//加载遮罩 + const type = window.location.pathname.includes("SupplierQuestionsOrObjectionsDing");//获取url判断投标、定标提疑 + const [proceedingTypeSelect] = useState(() => { - let arr = proceedingTypeByDefId.map((item: any) => - - ); - return arr; + //根据浏览器rul获取type值false为招标阶段提疑 true为定标阶段提疑 + //招标阶段 事项类别对应 招标文件异议、招标文件疑问 定标阶段事项类别对应 中标公示疑问、中标公示异议、中标结果疑问、中标结果异议 + if (!type) { + let arr = proceedingTypeByDefId.slice(-2) // 截取最后两个元素 + .map((item: any) => + + ); + return arr; + }else { + let arr = proceedingTypeByDefId.slice(0, 4) // 截取前四个元素 + .map((item: any) => + + ); + return arr; + } }); const [proceedingTypeColumns] = useState(() => { let obj = {}; @@ -191,8 +204,6 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { }) }, []); - - /** * 查看 * @param data @@ -235,7 +246,7 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { } /** * 根据id删除数据 - * @param id + * @param id */ const deleteDataBasedOnId = (id: any) => { setVisibleDelete(false); @@ -246,7 +257,7 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { } /** * 提交 - * @param data 数据 + * @param data 数据 */ const submit = (data: any) => { setVisibleSubmit(true); @@ -254,7 +265,7 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { } /** * 提交 - * @param data + * @param data */ const submitDataBasedOnId = (data: any) => { setVisibleSubmit(false); @@ -278,7 +289,7 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { /** * 弹出层关闭 - * @param data + * @param data */ const handleCancel = () => { setVisible(false); @@ -291,7 +302,7 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { } /** * 表单提交 - * @param data + * @param data */ const onFinish = (data: any) => { setVisible(false); @@ -484,14 +495,16 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { rowKey="id" size="small" pagination={{ defaultPageSize: 10 }} - params={{ projectId: projectId, roomType: roomType, dissentType: "1" }} + params={{ projectId: projectId, roomType: roomType, dissentType: "1" ,type:type}} actionRef={actionRef} columns={columns} request={params => queryingPagingData('/api/biz-service-ebtp-tender/v1/clarifydissent/supplier_dissents', 'post', params)} search={false} options={false} toolBarRender={() => [ - , ]} @@ -516,4 +529,4 @@ const SupplierQuestionsOrObjections: React.FC<{}> = () => { ) } -export default SupplierQuestionsOrObjections; \ No newline at end of file +export default SupplierQuestionsOrObjections; diff --git a/src/pages/Tender/supplier/SupplierQuestionsOrObjections/utils.ts b/src/pages/Tender/supplier/SupplierQuestionsOrObjections/utils.ts index 350bbe2..7fc934a 100644 --- a/src/pages/Tender/supplier/SupplierQuestionsOrObjections/utils.ts +++ b/src/pages/Tender/supplier/SupplierQuestionsOrObjections/utils.ts @@ -19,12 +19,12 @@ export function getProceedingTypeByBidMethodDict(bidMethodDict: string): any[] { case 'procurement_mode_1': case 'procurement_mode_2': arr = [ - getProceedingType('1', '异议评标结果'), - getProceedingType('2', '异议开标过程'), - getProceedingType('3', '异议中标公示'), - getProceedingType('4', '异议中标结果'), - getProceedingType('5', '提疑资格预审文件'), - getProceedingType('6', '提疑招标文件'), + getProceedingType('1', '中标公示疑问'), + getProceedingType('2', '中标公示异议'), + getProceedingType('3', '中标结果疑问'), + getProceedingType('4', '中标结果异议'), + getProceedingType('5', '招标文件异议'), + getProceedingType('6', '招标文件疑问'), ] break; case 'procurement_mode_3': @@ -78,11 +78,12 @@ export function getProceedingTypeByDefId(defId: string): any[] { case 'bid_centralized_prequalification_bid': case 'bid_invitation': arr = [ - getProceedingType('1', '异议评标结果'), - getProceedingType('2', '异议开标结果'), - getProceedingType('3', '异议中标公示'), - getProceedingType('4', '异议中标结果'), - getProceedingType('6', '提疑招标文件'), + getProceedingType('1', '中标公示疑问'), + getProceedingType('2', '中标公示异议'), + getProceedingType('3', '中标结果疑问'), + getProceedingType('4', '中标结果异议'), + getProceedingType('5', '招标文件异议'), + getProceedingType('6', '招标文件疑问'), ] break; case 'comparison_one_prequalification': From dba11c39462876074bdf4e5f29a2062c0832babc Mon Sep 17 00:00:00 2001 From: sunyu Date: Tue, 24 Jun 2025 17:13:22 +0800 Subject: [PATCH 09/21] =?UTF-8?q?=E4=BF=9D=E8=AF=81=E9=87=91=E4=B8=BA0?= =?UTF-8?q?=E6=83=B3=E8=87=AA=E5=8A=A8=E7=AE=97=E5=B7=B2=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IParticipate/components/IParticipate.tsx | 24 ++++++++++++++----- .../Tender/supplier/IParticipate/service.ts | 14 +++++++---- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/pages/Tender/supplier/IParticipate/components/IParticipate.tsx b/src/pages/Tender/supplier/IParticipate/components/IParticipate.tsx index 5d3a98a..31ccf5d 100644 --- a/src/pages/Tender/supplier/IParticipate/components/IParticipate.tsx +++ b/src/pages/Tender/supplier/IParticipate/components/IParticipate.tsx @@ -5,8 +5,8 @@ import ProTable from '@ant-design/pro-table'; import { digitalConversionAmount } from '@/utils/NumberUtils'; import { nowExceedSpecifiedTime } from '@/utils/DateUtils'; import { getURLInformation, isNotEmpty } from '@/utils/CommonUtils'; -import { cancelOrder, getByOrderId, paySuccess, payTenderFile, saveGenerateOrder, woPay } from '../service'; -import { getProMethod, getSessionProjectData } from '@/utils/session'; +import { cancelOrder, getByOrderId, paySuccess, payTenderFile, saveGenerateOrder, woPay ,queryMarginFees} from '../service'; +import { getProMethod, getSessionProjectData} from '@/utils/session'; import { isEmpty } from 'lodash'; import { getAllFlowName, getAllFlowNameByRoomType, getbidQualification, moduleName } from '@/utils/FlowUtils'; import { btnAuthority } from '@/utils/authority'; @@ -64,6 +64,8 @@ const IParticipate: React.FC = () => { //沃支付遮罩 const [spinningModelLoading, setSpinningModelLoading] = useState(false); const [form] = Form.useForm(); + // 存储sectionId列表的状态 + let sectionIds = ''; useEffect(() => { init(); }, []); @@ -260,7 +262,17 @@ const IParticipate: React.FC = () => { */ const settlementOnOk = async () => { setSpinningModelLoading(true); - if (Number(totalOrderAmount) === 0) { + let zeroAmountItems = ""; + //查询biz_bid_expenses表 根据projectId和sectionIds 查询保证金费用是否为0 + queryMarginFees({ projectId: projectId, sectionIds: sectionIds }).then(res => { + if (res.code === 200) { + if (res.data) { + //amount 为0的数据 + zeroAmountItems = res.data.filter(item => item.amount === 0); + } + } + }) + if (Number(totalOrderAmount) === 0 || zeroAmountItems !== null) { paySuccess(orderNumber).then(res => { if (res.data) { message.success('支付成功!'); @@ -298,7 +310,7 @@ const IParticipate: React.FC = () => { } }).finally(() => setSpinningModelLoading(false)); setOrderSpinning(false); - } + }; Modal.confirm({ title: '告知', content:
即将离开本系统跳转至【沃钱包-收银台】进行支付,在【沃钱包-收银台】支付前请仔细核对支付信息(包括:商品名称、商户名称、订单号、订单金额)是否与本系统订单信息一致。如若需要更改订单,请关闭【沃钱包-收银台】页面。
, @@ -482,7 +494,7 @@ const IParticipate: React.FC = () => { } /** * 勾选计算金额 - * @param selectedRows + * @param selectedRows */ const calculate = (selectedRows: any) => { let num = 0; @@ -524,4 +536,4 @@ const IParticipate: React.FC = () => { ) } -export default IParticipate \ No newline at end of file +export default IParticipate diff --git a/src/pages/Tender/supplier/IParticipate/service.ts b/src/pages/Tender/supplier/IParticipate/service.ts index 99f41c7..fdbc6b7 100644 --- a/src/pages/Tender/supplier/IParticipate/service.ts +++ b/src/pages/Tender/supplier/IParticipate/service.ts @@ -7,11 +7,11 @@ * @FilePath: \ebtp-cloud-frontend\src\pages\IParticipate\service.ts */ -import request from "@/utils/request"; +import request from '@/utils/request'; /** * 获取购标信息 - * @param id + * @param id */ export async function payTenderFile(id: string | null, roomType:any) { return request('/api/biz-service-ebtp-tender/v1/supplier_register/pay_tender_file/' + id + '?roomType=' + roomType); @@ -41,7 +41,7 @@ export async function woPay(orderId: any) { } /** * 取消订单 - * @param id + * @param id */ export async function cancelOrder(id: any) { return request('/api/biz-service-ebtp-expenses/v1/bizbidorder/cancelOrder/' + id, { @@ -61,4 +61,10 @@ export function paySuccess (id:any){ }) } - +//保证金费用查询 +export async function queryMarginFees(params?: any) { + return request(`/api/biz-service-ebtp-expenses/v1/bizbidexpenses/queryMarginFees`,{ + method:'POST', + data:{...params,}, + }); +} From 65ef171db50c95d0e4aa22f7d984580e1e607d67 Mon Sep 17 00:00:00 2001 From: sunyu Date: Tue, 24 Jun 2025 17:20:19 +0800 Subject: [PATCH 10/21] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=8B=9B=E6=A0=87=E6=96=87=E4=BB=B6=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/ClarifyTheList.tsx | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/pages/Tender/ProjectManager/ClarifyTheList/components/ClarifyTheList.tsx b/src/pages/Tender/ProjectManager/ClarifyTheList/components/ClarifyTheList.tsx index ccca394..812acde 100644 --- a/src/pages/Tender/ProjectManager/ClarifyTheList/components/ClarifyTheList.tsx +++ b/src/pages/Tender/ProjectManager/ClarifyTheList/components/ClarifyTheList.tsx @@ -285,7 +285,7 @@ const ClarifyTheList: React.FC<{}> = () => { /** * 供应商回执 - * @param record + * @param record */ const supplierReviewReceipt = (record: any) => { setVisibleModalReceipt(true); @@ -339,7 +339,7 @@ const ClarifyTheList: React.FC<{}> = () => { const [form] = Form.useForm(); /** * 查看回执 - * @param data + * @param data */ const viewReceipt = (data: any) => { setVisibleReceipt(true); @@ -394,7 +394,7 @@ const ClarifyTheList: React.FC<{}> = () => { /** * 删除 - * @param data + * @param data */ const del = (id: any) => { setModalDelete(true); @@ -411,7 +411,7 @@ const ClarifyTheList: React.FC<{}> = () => { /** * 查看 - * @param data + * @param data */ const examine = (data: any) => { setBid(data.attDatasetId); @@ -615,7 +615,7 @@ const ClarifyTheList: React.FC<{}> = () => { /** *与原时间的校验 * - * @return {*} + * @return {*} */ const verification = () => { //开标时间 @@ -644,7 +644,7 @@ const ClarifyTheList: React.FC<{}> = () => { /** * 澄清保存 - * @param data + * @param data */ const onFinish = (data: any) => { setButtonLoading(true); @@ -704,6 +704,9 @@ const ClarifyTheList: React.FC<{}> = () => { } } + const modTenderDocumentRadio = (data: any) => { + } + const bidOpeningTimeRadio = (data: any) => { let value = data.target.value; setBidOpeningTimeFlag(value === '1'); @@ -763,9 +766,9 @@ const ClarifyTheList: React.FC<{}> = () => { setActiveKey(key); } - const [filterTimes, filterTimesSet] = useState({});//根据传入标段筛选做为校验时间的标准时间 + const [filterTimes, filterTimesSet] = useState({});//根据传入标段筛选做为校验时间的标准时间 /** - *根据传入标段筛选做为校验时间的标准时间 + *根据传入标段筛选做为校验时间的标准时间 *开标时间-startTime; *招标文件获取截止时间-payEndTime; *应答截止时间-tenderEndTime; @@ -854,6 +857,16 @@ const ClarifyTheList: React.FC<{}> = () => { { fieldCheck && ( <> + + + + + + { (bidMethodDict === 'procurement_mode_5' || bidMethodDict === 'procurement_mode_6') ? ( = () => { label="澄清文件附件" name="attDatasetId" rules={[{ - required: true, + // required: true, message: '请上传澄清文件!' }]} > @@ -1117,4 +1130,4 @@ const ClarifyTheList: React.FC<{}> = () => { ) } -export default ClarifyTheList; \ No newline at end of file +export default ClarifyTheList; From 47ac0fdeee0812627fb697a0a7fe888b9cf131e5 Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Tue, 24 Jun 2025 17:28:11 +0800 Subject: [PATCH 11/21] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=8A=A5=E4=BB=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Evaluation/BidDetailed/BidDetailedReview/index.tsx | 2 +- .../Evaluation/BidDetailed/BidDetailedReviewLeader/index.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/Evaluation/BidDetailed/BidDetailedReview/index.tsx b/src/pages/Evaluation/BidDetailed/BidDetailedReview/index.tsx index d39986a..d369098 100644 --- a/src/pages/Evaluation/BidDetailed/BidDetailedReview/index.tsx +++ b/src/pages/Evaluation/BidDetailed/BidDetailedReview/index.tsx @@ -526,7 +526,7 @@ const Index: React.FC<{}> = () => { if (res.data.priceScoreMap.priceConfig.effectiveType == '1') { setTit1('全部报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '2') { - setTit1('去掉最高和最低各一家后的报价') + setTit1('去掉最高'+res.data.priceScoreMap.priceConfig.removeMaxNumber + '家 和 最低' + res.data.priceScoreMap.priceConfig.removeMinNumber + '家的报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '3') { setTit1('去掉最两家高和最低各一家后的报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '4') { diff --git a/src/pages/Evaluation/BidDetailed/BidDetailedReviewLeader/index.tsx b/src/pages/Evaluation/BidDetailed/BidDetailedReviewLeader/index.tsx index 4ad27f1..4bcbc7a 100644 --- a/src/pages/Evaluation/BidDetailed/BidDetailedReviewLeader/index.tsx +++ b/src/pages/Evaluation/BidDetailed/BidDetailedReviewLeader/index.tsx @@ -563,7 +563,8 @@ const Index: React.FC<{}> = () => { if (res.data.priceScoreMap.priceConfig.effectiveType == '1') { setTit1('全部报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '2') { - setTit1('去掉最高和最低各一家后的报价') + setTit1('去掉最高'+res.data.priceScoreMap.priceConfig.removeMaxNumber + '家 和 最低' + res.data.priceScoreMap.priceConfig.removeMinNumber + '家的报价') + // setTit1('去掉最高和最低各一家后的报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '3') { setTit1('去掉最两家高和最低各一家后的报价') } else if (res.data.priceScoreMap.priceConfig.effectiveType == '4') { From c801c687194fc94621825069c77ce5e367df8621 Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Thu, 26 Jun 2025 18:36:25 +0800 Subject: [PATCH 12/21] =?UTF-8?q?=E8=AF=84=E6=A0=87=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E8=BF=81=E5=88=B0rsms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/BidEvaluation/components/simpleUploadServis.ts | 4 ++-- .../Evaluation/expert/ReviewResults/GroupLeader/service.ts | 2 +- src/pages/Evaluation/expert/ReviewResults/Jury/service.ts | 4 ++-- .../Evaluation/projectManager/ReviewResults/service.ts | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/BidEvaluation/components/simpleUploadServis.ts b/src/pages/BidEvaluation/components/simpleUploadServis.ts index f74f39a..59ef38a 100644 --- a/src/pages/BidEvaluation/components/simpleUploadServis.ts +++ b/src/pages/BidEvaluation/components/simpleUploadServis.ts @@ -50,7 +50,7 @@ export async function finish(id: any) { * @param param */ export async function upReport(params: any) { - return request(`/api/biz-service-ebtp-evaluation/v1/review/report/save`, { + return request(`/api/biz-service-ebtp-rsms/v1/review/report/save`, { method:'POST', data: params, }) @@ -60,7 +60,7 @@ export async function upReport(params: any) { * @param param */ export async function serchReport(assessId: any) { - return request(`/api/biz-service-ebtp-evaluation/v1/review/report/${assessId}`, { + return request(`/api/biz-service-ebtp-rsms/v1/review/report/${assessId}`, { method: 'GET', }) } \ No newline at end of file diff --git a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/service.ts b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/service.ts index 6b662fd..b2a92c3 100644 --- a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/service.ts +++ b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/service.ts @@ -63,7 +63,7 @@ export function unlockResult(id: any) { * @param id */ export function unlockReportIF(id: any) { - return request(`/api/biz-service-ebtp-evaluation/v1/review/report/unlock/${id}`, { + return request(`/api/biz-service-ebtp-rsms/v1/review/report/unlock/${id}`, { method: 'post', }); } diff --git a/src/pages/Evaluation/expert/ReviewResults/Jury/service.ts b/src/pages/Evaluation/expert/ReviewResults/Jury/service.ts index 6e7e6ec..9c22c59 100644 --- a/src/pages/Evaluation/expert/ReviewResults/Jury/service.ts +++ b/src/pages/Evaluation/expert/ReviewResults/Jury/service.ts @@ -33,7 +33,7 @@ export function existingProblem(params: any) { * @param params */ export function reviewReportExpertsConfirmed(params: any) { - return request('/api/biz-service-ebtp-evaluation/v1/review/report/expert/confirm', { + return request('/api/biz-service-ebtp-rsms/v1/review/report/expert/confirm', { method: 'POST', data: params, }); @@ -44,5 +44,5 @@ export function reviewReportExpertsConfirmed(params: any) { * @param roleType */ export function queryReviewReport(assessId: string) { - return request(`/api/biz-service-ebtp-evaluation/v1/review/report/${assessId}`); + return request(`/api/biz-service-ebtp-rsms/v1/review/report/${assessId}`); } diff --git a/src/pages/Evaluation/projectManager/ReviewResults/service.ts b/src/pages/Evaluation/projectManager/ReviewResults/service.ts index 8effee3..acb2ea7 100644 --- a/src/pages/Evaluation/projectManager/ReviewResults/service.ts +++ b/src/pages/Evaluation/projectManager/ReviewResults/service.ts @@ -12,7 +12,7 @@ import request from '@/utils/request'; * 保存评审报告 */ export function reviewReportSave(data: any) { - return request('/api/biz-service-ebtp-evaluation/v1/review/report/save', { + return request('/api/biz-service-ebtp-rsms/v1/review/report/save', { method: 'post', data: data, }); @@ -22,7 +22,7 @@ export function reviewReportSave(data: any) { * @param id */ export function reviewReportSend(id: string) { - return request('/api/biz-service-ebtp-evaluation/v1/review/report/send/' + id, { + return request('/api/biz-service-ebtp-rsms/v1/review/report/send/' + id, { method: 'POST', }); } @@ -33,7 +33,7 @@ export function reviewReportSend(id: string) { * @param roleType */ export function queryReviewReport(assessId: any) { - return request(`/api/biz-service-ebtp-evaluation/v1/review/report/${assessId}`); + return request(`/api/biz-service-ebtp-rsms/v1/review/report/${assessId}`); } /** * 结束评标 From b23731ef63e207d8e70252e1cee3bcf4ebffa203 Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Mon, 30 Jun 2025 16:28:31 +0800 Subject: [PATCH 13/21] =?UTF-8?q?=E8=AF=84=E5=AE=A1=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=8B=9F=E7=AD=BE=E7=BA=A6=E9=87=91=E9=A2=9D?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GroupLeader/components/GroupLeader.tsx | 151 +++++++++--------- .../components/SortEditableTable.tsx | 12 +- 2 files changed, 83 insertions(+), 80 deletions(-) diff --git a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx index 82ca780..117f5fc 100644 --- a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx +++ b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx @@ -822,69 +822,70 @@ const GroupLeader: React.FC = () => { }; }, }, - { - title: `是否拟${candidateType}人`, - dataIndex: 'winnerBidder', - valueType: 'select', - width: 120, - editable: !confirmSubmitStatus, - valueEnum: successfulWinning, - formItemProps: () => { - return { - rules: [{ required: true, message: `请选择是否拟${candidateType}人` }], - }; - }, - }, - { - title: contractedMoneyName, - dataIndex: 'contractedMoney', - width: 150, - editable: !confirmSubmitStatus, - formItemProps: (from: any, { rowKey, rowIndex }: any) => { - return { - rules: quotationMethod ? [] : [ - { - pattern: regularCheck, - message: '请输入数字,并且小数点后最多只能输入五位' - }, - { - validator: () => { - from.validateFields([[rowKey, 'taxRatePrice']]); - return Promise.resolve() - }, - message: "增值税金额不能高于拟签约的金额" - } - ], - }; - }, - }, - { - title: taxRatePriceName, - dataIndex: 'taxRatePrice', - width: 150, - editable: !confirmSubmitStatus, - formItemProps: (from: any, { rowKey, rowIndex }: any) => { - let contractedMoney = from.getFieldValue([rowKey || '', 'contractedMoney']); - let taxRatePrice = from.getFieldValue([rowKey || '', 'taxRatePrice']); - return { - rules: quotationMethod ? [] : [ - { - pattern: regularCheck, - message: '请输入数字,并且小数点后最多只能输入五位' - }, - { - validator: () => { - if (isEmpty(contractedMoney) || isEmpty(taxRatePrice)) { - return Promise.resolve(); - } - return (Number(taxRatePrice) < Number(contractedMoney) || (Number(taxRatePrice) == Number(contractedMoney))) ? Promise.resolve() : Promise.reject(new Error('增值税金额不能高于拟签约的金额')) - }, - message: "增值税金额不能高于拟签约的金额" - } - ], - }; - }, - }, + // { + // title: `是否拟${candidateType}人`, + // dataIndex: 'winnerBidder', + // valueType: 'select', + // width: 120, + // editable: !confirmSubmitStatus, + // valueEnum: successfulWinning, + + // formItemProps: () => { + // return { + // rules: [{ required: true, message: `请选择是否拟${candidateType}人` }], + // }; + // }, + // }, + // { + // title: contractedMoneyName, + // dataIndex: 'contractedMoney', + // width: 150, + // editable: !confirmSubmitStatus, + // formItemProps: (from: any, { rowKey, rowIndex }: any) => { + // return { + // rules: quotationMethod ? [] : [ + // { + // pattern: regularCheck, + // message: '请输入数字,并且小数点后最多只能输入五位' + // }, + // { + // validator: () => { + // from.validateFields([[rowKey, 'taxRatePrice']]); + // return Promise.resolve() + // }, + // message: "增值税金额不能高于拟签约的金额" + // } + // ], + // }; + // }, + // }, + // { + // title: taxRatePriceName, + // dataIndex: 'taxRatePrice', + // width: 150, + // editable: !confirmSubmitStatus, + // formItemProps: (from: any, { rowKey, rowIndex }: any) => { + // let contractedMoney = from.getFieldValue([rowKey || '', 'contractedMoney']); + // let taxRatePrice = from.getFieldValue([rowKey || '', 'taxRatePrice']); + // return { + // rules: quotationMethod ? [] : [ + // { + // pattern: regularCheck, + // message: '请输入数字,并且小数点后最多只能输入五位' + // }, + // { + // validator: () => { + // if (isEmpty(contractedMoney) || isEmpty(taxRatePrice)) { + // return Promise.resolve(); + // } + // return (Number(taxRatePrice) < Number(contractedMoney) || (Number(taxRatePrice) == Number(contractedMoney))) ? Promise.resolve() : Promise.reject(new Error('增值税金额不能高于拟签约的金额')) + // }, + // message: "增值税金额不能高于拟签约的金额" + // } + // ], + // }; + // }, + // }, ] : //预审字段 [ @@ -1233,7 +1234,8 @@ const GroupLeader: React.FC = () => { // if (verificationDanger()) { // return; // } - verificationMoneyIsEdit(data); + //2025.6.25 zyx 中远海运去掉拟签约金额和增值税金额 verificationMoneyIsEdit(data); + submit()//2025.6.25 zyx 中远海运去掉拟签约金额和增值税金额 } //提交接口调用 function submit() { @@ -1415,16 +1417,17 @@ const GroupLeader: React.FC = () => { } return true; } - if (bidMethodDict != 'procurement_mode_7') { - if (winnerBidderData.length !== 0) {//验证是否拟中标人 - message.info(bidMethodDict === 'procurement_mode_4' ? `${winnerBidderData[0].companyName}未选择是否拟入围人!` : `${winnerBidderData[0].companyName}未选择是否拟${candidateType}人!`); - return true; - } - if (contractedMoneyData.length !== 0) {//验证拟签约金额是否高于标段预算 - message.info(`${contractedMoneyData[0].companyName}的拟签约金额不能高于标段预算(${bidSectContractPrice}元)`); - return true; - } - } + //2025.6.25 zyx 中远海运去掉是否拟中标人、拟签约金额和增值税金额 + // if (bidMethodDict != 'procurement_mode_7') { + // if (winnerBidderData.length !== 0) {//验证是否拟中标人 + // message.info(bidMethodDict === 'procurement_mode_4' ? `${winnerBidderData[0].companyName}未选择是否拟入围人!` : `${winnerBidderData[0].companyName}未选择是否拟${candidateType}人!`); + // return true; + // } + // if (contractedMoneyData.length !== 0) {//验证拟签约金额是否高于标段预算 + // message.info(`${contractedMoneyData[0].companyName}的拟签约金额不能高于标段预算(${bidSectContractPrice}元)`); + // return true; + // } + // } return false; } diff --git a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/SortEditableTable.tsx b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/SortEditableTable.tsx index 3cb3e2f..5af2723 100644 --- a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/SortEditableTable.tsx +++ b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/SortEditableTable.tsx @@ -151,12 +151,12 @@ const SortEditableTable: React.FC = (props) => { } } }, - { - title: `是否${candidateType}候选人`, - dataIndex: 'winnerCandidate', - valueType: 'select', - valueEnum: successfulCandidate, - }, + // { + // title: `是否${candidateType}候选人`, + // dataIndex: 'winnerCandidate', + // valueType: 'select', + // valueEnum: successfulCandidate, + // }, ] setColumns(enquiryColumns); return; From 3630d5377c493dab243129be8e4a0de7822114fa Mon Sep 17 00:00:00 2001 From: sunyu Date: Wed, 9 Jul 2025 10:59:18 +0800 Subject: [PATCH 14/21] =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E5=AE=9A=E6=A0=87?= =?UTF-8?q?=E7=BB=93=E6=9E=9C--=E5=AE=9A=E6=A0=87=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BidAssessmentResults/index.tsx | 228 ++++++++++++++++-- .../BidAssessmentResults/service.ts | 10 + 2 files changed, 220 insertions(+), 18 deletions(-) diff --git a/src/pages/Calibration/BidAssessmentResults/index.tsx b/src/pages/Calibration/BidAssessmentResults/index.tsx index 86ddda1..3027407 100644 --- a/src/pages/Calibration/BidAssessmentResults/index.tsx +++ b/src/pages/Calibration/BidAssessmentResults/index.tsx @@ -1,12 +1,30 @@ import React, { useEffect, useMemo, useState } from 'react'; -import { Button, Card, Collapse, Form, Input, List, message, Popover, Select, Space, Spin, Typography } from "antd"; +import { + Button, + Card, + Collapse, + Form, + Input, + List, + message, + Modal, + Popover, + Select, + Space, + Spin, + Typography, + Checkbox +} from "antd"; import ProTable from "@ant-design/pro-table"; -import { getBidAssessmentResultList, getBidAssessmentResultsList, pushBidAssessmentResult, saveResult } from "./service" +import { getBidAssessmentResultList, getBidAssessmentResultsList, pushBidAssessmentResult, saveResult ,saveReviewResultDetail} from "./service" import CurrentTable from "./components/currentTable" import { getDefId, getProId, getProMethod } from "@/utils/session"; import { btnAuthority } from "@/utils/authority"; import { isEmpty } from '@/utils/CommonUtils'; +const CheckboxGroup = Checkbox.Group +const defaultCheckedList: any[] = []; +const plainOptions: any[] = []; const BidAssessmentResults: React.FC<{}> = (props) => { const [Refresh, setRefresh] = useState(0); @@ -19,6 +37,14 @@ const BidAssessmentResults: React.FC<{}> = (props) => { const [name, setName] = useState(''); //折叠面板 const [collapseActiveKeys, setCollapseActiveKeys] = useState(['0']); + // 用于控制定标结果审批弹窗的显示与隐藏 + const [isCalibrationModalVisible, setIsCalibrationModalVisible] = useState(false); + + const [indeterminate, setIndeterminate] = useState(false); // 复选框全选 + const [checkAll, setCheckAll] = useState(false); // 复选框全选 + const [checkedList, setCheckedList] = useState(defaultCheckedList); // 全选选中数组 + const [sectionsVal, setSectionsVal] = useState([]); // 选中数组id + const [plainList, setPlainList] = useState(plainOptions); // 选择标段 const FormItem = Form.Item; const { Option } = Select; @@ -77,13 +103,64 @@ const BidAssessmentResults: React.FC<{}> = (props) => { /*projectType :2 评标 1 资审*/ getBidAssessmentResultsList({ "projectId": proID, "roomType": "2", "sectionName": name }).then(res => { if (res.code == 200) { + // 关键:把接口返回的 res.data 赋值给 ListData setListData(res.data); + const newPlainList = res.data.map(item => ({ + sectionId: item.sectionId, + sectionName: item.sectionName + })); + setPlainList(newPlainList); + // 初始化 sectionsVal:所有标段的 ID 数组 + setSectionsVal(newPlainList.map(item => item.sectionId)); } }).finally(() => { setSpintype(false); }) }, [proID, Refresh]) + // 重置全选相关状态 + const resetCalibrationStates = () => { + setCheckedList(defaultCheckedList); // 清空已选 + setCheckAll(false); // 取消全选 + setIndeterminate(false); // 取消半选 + }; + + // 定标结果审批方法,点击按钮时调用,显示弹窗 + const calibrationResult = () => { + setIsCalibrationModalVisible(true); + }; + + // 假设点击确定按钮的回调,可根据实际需求处理选中的标段逻辑,这里简单打印 + const handleCalibrationModalOk = () => { + setIsCalibrationModalVisible(false); + console.log('点击了确定,可处理标段选择逻辑'); + resetCalibrationStates(); // 确定后也重置(可选,看业务需求) + }; + + // 关闭定标结果审批弹窗的方法 + const handleCalibrationModalCancel = () => { + setIsCalibrationModalVisible(false); + resetCalibrationStates(); // 关键:关闭时重置 + }; + + // 全选事件 + const onCheckAllChange = (e: any) => { + // 全选:checkedList = 所有标段 ID(sectionsVal) + // 取消全选:checkedList = [] + setCheckedList(e.target.checked ? sectionsVal : []); + setIndeterminate(false); + setCheckAll(e.target.checked); + }; + + // 子选项改变事件 + const onChange = (checkedList: any) => { + setCheckedList(checkedList); + // 半选状态:已选数量 >0 且 < 总数量 + setIndeterminate(!!checkedList.length && checkedList.length < sectionsVal.length); + // 全选状态:已选数量 === 总数量 + setCheckAll(checkedList.length === sectionsVal.length); + }; + /*推送评标结果*/ const pushResult = (record: any) => { setSpintype(true); @@ -117,7 +194,7 @@ const BidAssessmentResults: React.FC<{}> = (props) => { const [expandTotalScore, setExpandTotalScore] = useState(proDict == "procurement_mode_7" ? false : true); //单一简化 - function returnInput(name: any, name2: any, val: any, must: boolean, pattern?: boolean, hid?: boolean) { + function returnInput(name: any, name2: any, val: any, must: boolean, pattern?: boolean, hid?: boolean,id?: any) { let rule = [ { required: must }, { pattern: /^.{0,21}$/, message: '超长' } @@ -173,6 +250,36 @@ const BidAssessmentResults: React.FC<{}> = (props) => { ) } + function transformData(data) { + const result = []; + const idMap = {}; + + // 遍历对象的每个属性 + for (const key in data) { + if (data.hasOwnProperty(key)) { + // 分割字段名,获取属性类型和ID + const [type, id] = key.split('_'); + if (!idMap[id]) { + idMap[id] = { id }; + result.push(idMap[id]); + } + // 处理值的类型转换 + let value = data[key]; + if (value === "null") { + value = null; + } else if (type === 'contractedMoney' || type === 'taxRatePrice') { + // 确保金额字段是数字类型 + value = parseFloat(value) || null; + } else if (type === 'winnerBidder') { + // 将"是/否"转换为1/0 + value = value === "是" ? 1 : 0; + } + idMap[id][type] = value; + } + } + return result; + } + return ( = (props) => { width: 80, dataIndex: 'winnerBidder', render: (_: any, record: any) => { - return record.winnerBidder === 1 ? '是' : record.winnerBidder === 0 ? '否' : '-' + // const isEditable = defId === 'negotiation_single_simple' && record.pushStatus === "0"; + // if (isEditable) { + return returnSelect('winnerBidder_'+record.id, record.winnerBidder) + // return ( + // + // ); + // } + // return record.winnerBidder === 1 ? '是' : record.winnerBidder === 0 ? '否' : '-'; } }, { @@ -348,19 +473,19 @@ const BidAssessmentResults: React.FC<{}> = (props) => { width: 150, dataIndex: 'contractedMoney', render: (_: any, record: any) => { - if (defId === 'negotiation_single_simple' && record.pushStatus == "0") { + // if (defId === 'negotiation_single_simple' && record.pushStatus == "0") { return ( <> - {returnInput('contractedMoney', '拟签约金额', record.contractedMoney, false, true)} - {returnInput('id', '供应商id', record.id, false, false, true)} - {returnInput('resultId', '结果id', record.resultId, false, false, true)} - {returnInput('companyId', '公司id', record.companyId, false, false, true)} - {returnInput('companyName', '公司名称', record.companyName, false, false, true)} + {returnInput('contractedMoney_'+record.id, '拟签约金额', record.contractedMoney, false, true,false,record.id)} + {/*{returnInput('id', '供应商id', record.id, false, false, true,record.id)}*/} + {/*{returnInput('resultId', '结果id', record.resultId, false, false, true,record.id)}*/} + {/*{returnInput('companyId', '公司id', record.companyId, false, false, true,record.id)}*/} + {/*{returnInput('companyName', '公司名称', record.companyName, false, false, true,record.id)}*/} ) - } else { - return record.contractedMoney - } + // } else { + // return record.contractedMoney + // } } }, { @@ -369,11 +494,11 @@ const BidAssessmentResults: React.FC<{}> = (props) => { width: 150, dataIndex: 'taxRatePrice', render: (_: any, record: any) => { - if (defId === 'negotiation_single_simple' && record.pushStatus == "0") { - return returnInput('taxRatePrice', '增值税金额', record.taxRatePrice, false, true) - } else { - return record.taxRatePrice - } + // if (defId === 'negotiation_single_simple' && record.pushStatus == "0") { + return returnInput('taxRatePrice_'+record.id, '增值税金额', record.taxRatePrice, false, true,false,record.id) + // } else { + // return record.taxRatePrice + // } } }, ] @@ -429,6 +554,18 @@ const BidAssessmentResults: React.FC<{}> = (props) => { } + ]} pagination={{ @@ -443,12 +580,66 @@ const BidAssessmentResults: React.FC<{}> = (props) => { ) } + const calibrationResultsModal = ( + +
+ {/* 全选 - 单独一行 */} +
+ + 全选 + +
+ + {/* 子选项 - 统一缩进 */} +
+ + {plainList.map((item, index) => ( +
+ + {item.sectionName} + +
+ ))} +
+
+
+
+ ); + return ( <>
+ setName(event.target.value)} />
工号: - {userData?.fullName || '-'} + {userData?.employeeNumber || '-'}
角色: @@ -327,11 +327,11 @@ const [currentProviderId, setCurrentProviderId] = useState('');
公司: - {userData?.fullName || '-'} + {userData?.organizationName || '-'}
部门: - {userData?.fullName || '-'} + {userData?.deptName || '-'}
From 0a3fa905cae0bc4cc5398b8e35737989d3406fbb Mon Sep 17 00:00:00 2001 From: jlzhangyx5 Date: Fri, 11 Jul 2025 08:44:50 +0800 Subject: [PATCH 16/21] =?UTF-8?q?=E6=89=8B=E5=86=99=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=EF=BC=8C=E7=BA=BF=E4=B8=8B=E8=AF=84=E5=AE=A1=EF=BC=8C=E9=A2=84?= =?UTF-8?q?=E5=AE=A1=E8=AF=84=E5=A7=94=E4=BC=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/JuryRoom/router_menuJury.config.ts | 5 + config/YuShen/router_yushen.ts | 2 +- src/assets/signPen/signPen.png | Bin 0 -> 18773 bytes src/assets/styles.module.less | 31 + src/components/BiddingRoom/index.js | 71 +- src/models/bidev.js | 19 +- .../GroupLeader/components/GroupLeader.tsx | 162 +- .../ReviewResults/Jury/components/Jury.tsx | 163 +- .../ReviewResults/ManagerEntry/index.tsx | 13 + .../projectManager/ReviewResults/service.ts | 7 + .../JudgingPanel/List/preIndex.tsx | 1730 +++++++++++++++++ src/services/bidev.js | 5 + 12 files changed, 2183 insertions(+), 25 deletions(-) create mode 100644 src/assets/signPen/signPen.png create mode 100644 src/assets/styles.module.less create mode 100644 src/pages/Evaluation/projectManager/ReviewResults/ManagerEntry/index.tsx create mode 100644 src/pages/Tender/ProjectManager/JudgingPanel/List/preIndex.tsx diff --git a/config/JuryRoom/router_menuJury.config.ts b/config/JuryRoom/router_menuJury.config.ts index ca1e891..9e6c9ae 100644 --- a/config/JuryRoom/router_menuJury.config.ts +++ b/config/JuryRoom/router_menuJury.config.ts @@ -38,6 +38,11 @@ export default [//评标 path: '/EvaRoom/Evaluation/projectManager/ReviewResults/Manager', component: './Evaluation/projectManager/ReviewResults/Manager', }, + //评审结果-线下评审-项目经理 + { + path: '/EvaRoom/Evaluation/projectManager/ReviewResults/ManagerEntry', + component: './Evaluation/projectManager/ReviewResults/ManagerEntry', + }, //评审结果-组长 { path: '/EvaRoom/Evaluation/expert/ReviewResults/GroupLeader', diff --git a/config/YuShen/router_yushen.ts b/config/YuShen/router_yushen.ts index 00f765c..21e0e43 100644 --- a/config/YuShen/router_yushen.ts +++ b/config/YuShen/router_yushen.ts @@ -39,7 +39,7 @@ export default //评委会设置 资审发售 项目经理 { path: '/ProjectLayout/ZYuShen/Tender/ProjectManager/JudgingPanel', - component: './Tender/ProjectManager/JudgingPanel/List' + component: './Tender/ProjectManager/JudgingPanel/List/preIndex' }, //澄清 资审发售 项目经理 { diff --git a/src/assets/signPen/signPen.png b/src/assets/signPen/signPen.png new file mode 100644 index 0000000000000000000000000000000000000000..02aa52c9873c8fcb218476ba2c8ea57f1ded3d6d GIT binary patch literal 18773 zcmeI33p7;S+rSUHpj>h-!ZgxbY0S;IOib=Z5xMI=X3j9ot(n1$B&E`wk|dGnO-k3d zA`xAYTU07kluJUWBvE}cRCKC&-*5fjZ++{(*34Qn=REt_&$G||?PouG?^)|?b6f1F zAg?740DyuM(av3X)fIhZCkTJ%qfVy_FLG?69~S^rc%rY=Q>q>x0OVb0wzh6=fh-=2 z8^~hAoNR4jYz~V`qk{mzuS@X=^NsJ*|H_de(B140n#RA z6{}mDx5|5~sZTjX^t!q6fjlu~>+`hPxdGPOw=Uh`wcPBrUPI=^b>ZDzU4st?^V<%! z4OI%Nl%l4n%-YkM9t4=XZ??cc(u;K^-YhMMl2#`+j)N(;mR%1Re+vM5WCZ+3-q{61 zQfF9zG{AmfG*hLx=}UB;+bkadwg+g0tF%p$igO1_j66%!fRd@eS&zRc^1wa-pbH{w z;J^t5p!1y*VLb3CE51P!c$7XpOBUEA1tiUOoGEQ}1z7F1!F`@|(RCm#+X`+puIRK> zl;0(cqjXfkcp!AQZ=90VY9K1fW?ne}Gm{2vbyX{5V9qjWsG7pYtX1sIxkM?Ts4Sr( zaZwFcEjQt=R@j@K#^*DhU#Fk5A!*K0rph(L4<#n+s}kE}oGT{-fYw0uwa;b?;@Vo9 zn_8)D^zL`J(mx0Hu;7Flz0W@9@01<~C@-$+u3Od8QY*tQmO2|!7@V~XsPhH_pAD?Q z*2|?WmA@N4utQ)rWTl&W#I3|aXS)2PNnHm1M+#6cb`ZW`n^=uIBHs(OpX$6M1NXCVuqe}-`!R=&IZlwZ`1!=ym|en-E*p+8=qS~Pkno@@3vewxJ$9%vilyp z8Knu&Rod5MdiC~yl8X;h0J68Z7A?Ls@nRXhDDt(G^bSSenoz(h@-1Sg)}%dva)2>L z&<_Cdg#)oxhEhO9;?WlXkpFV(^5gq7oo~wmfL+>#xo52>PQIp=U8H#EnofR^rZj1S zoz>)-MHb376Plx@%O9D#-+G#75&qG*i)UrD(xx12Qoe8vZKlxHsIq)R2U~N(>Zz&M zr{-^w8)sc2t4f-I-#W#A_ak_vtY*^gac~mRcyH8ESo>DBCGcA%oTJiNHbHw<5cS_6 zIBMp*mRo&{t1p3JwhwL3cSP^oaDIu*ed!RZ%g6P!w%<F}MI{VrlH|W&Appqx+BNx31efzn*))Ns&J&qD;lxc^YXLZCeN}o2% zo{!3gCGN?IQ;KulJ6L+7IY$kDYwL4ox%8RtNB5~L#DNQ1#{GF1W0RD2Vo60->V4T0 zTk(gNIx*5h-H;wJS*pe%2MsEcHEhd{A~GJ_JxB|n^#>x`d3kbAqIK;P?M1ajCNAM0i^>hFWBaS0@IY{4lIKY;rIRbY*Bx{4`pfM_mfU@flMk|Vysl)KoUU{a zbB}eaTCytR>Z(s0Kav&BZ`tgSwuPACNzS=FZPyHq+ZeFd*QS=^Ez>bC_<)Q5vhxF- z&Y|N6wL_6>ojq*1C#c!fJ=B!eH5F2dx6d{9m_I(WuyRJFLgiY73}OM|Ty4-P>Z!<6 zrgh=dh%c`1E(2EIQ;F3%)yN#5qX`jDzugnQ%;LAzYvoj%3( zC)JL9jCUD*nyk(=hc%ZyvqXe05I6zTkt@yy^@0c;)3K^BS@r zWtVpDHh*v^IF)quaen>KuFZeiAG)=0hsloO{dM~z%Es?^+25aiz?tvsU(Ib zYI-m-w`VdBhnFR^XuZy>xp=QHBl${l!>PxN`%lU(Z>>8y=wg(tUAp3iWw-Uao_^ow zYsz1wWF}``e;e0^Tp7C3Z{=WtuIpciW~J7m7$x;Lmo*lYtzC^LSb`rb+hqv13DSqd z564_Rb`}22@~VDhZDdm9#G%x|`5((Z#eOJk61>sqT|9oZ)HSIVse%n!8~&0BmeCuR zH15xdxbeHjUzvcMOi;I(ET`b7$BAbZX}-}OAY&T><{hk7zayKXzEt}os(hBSZtaxa zTdHKADMzx74LG-#Uy|M0=t$q1t4Eubq&cuoZO&ZG38Pm_E_m?P@cQS~W;go{1{Cb> zjm_G5d47G+B~EBSb`ag2PVP+3jmkZdyMZ6`!M-<9g{L}Gu4`NK%||yax4qy>x6uz` z4>ce3+|MJQZfQurtl8RLS(X}R;fM2!i!j@KKqc|~f|h8QjT>^RYfC26MMw3`rsU18 z_E*z)r7t;`le^GjZ)=Ko!h5qP^Viva4BX=C5ONzU=jv`K*fVYKW&O7<-gdQ5v#TDj zd5kdMcWB?C40i?E{tJc=Q8}}7T&aeJ@e0j?R>mFe_?SEW&H4k}xAp4u&Cb;s7u-*~ zDQY+)j~nurOzL_yqHx7@RTJ<8?#^)|u_?XPI)@9@wJ zGeWO$&!g~ZJvHmf0?W?t|K#@E*WK$)kf7nsZujV#KmW8f+~{MRkhQP0jCuOq(#vFZ zQUb-RJ1FtNGVk?sH4|24v$Kz%{&3bIxAnQt;#ChK`UH%+x~B_s?sRn!JC1fRv-|xD z&nzqmvVL%POOL`S?cQB2+N&4~pYo1`2lef)xKMGYLIy{|buBBulwJSkh)Kr#@Rao{ z%Dg|FI+=6z@vOSq!Y5&C-zrAysLy}ey{|L>q9NZWxWIm0AG7B5#wW2_{@Qtkt&vZ1 z9m8C2rN*xPbM3_U_T3#pJQls-Okv@9IflE*E?pv?-I5%|s!Q%V7y~SO zJUbS#_J!NaBb7HAZd5!=TA$M=+d&i<*5C_6vJn}KG|M9e-7j}$r0A^FalD%IC9)g+ zf*ewei}guOOPOuiJJ7r_{zWDwGc{%L0?YeJ4T65>p`_pyOI8#F*jA-3(B!>#&RNx8 z`u1sC?24Xz_B(jLf4xD@qEnWqEgd7-pPGngma#g({<1C~i_^S!E*LthwR4!Wo=nd*$m{zM`o2puO#ZcV!;0`&{+Xexb)Q~M{HXM5{e{ox zz#>NDht)-^t8Vxybt}rnq<-G_0a8Z@-(4(G713Rh;PYbf%a=K4uoxvCD7whF$3M_k%4V|j2U)P=6 zo%gJ`Krd{9r!UXf#Tid#F^otQ zmOp63XRw9aP@!%CpG_hMgFKi&7(ioM!n>~&!eKOuCEN$+f^uQof`K$*I0y6yU+hT^ z406!Q|?XIQizs4&;(K zG&YaMV!}jzN&c)5o+TVEYUumtYrh!m?+r1zU)c#MBKagX5^aP+{>I3~MZ6h<@k>iC z&puT6Bwu^>%Lcig0ycLmviA zAtOOL$Pl*4722VH*#{ntIyyK%bU~!~ZF3->_8T*iX2fhb6h=nKLKuH|TMkI#u{fSA z7M(B>WuvDj;o)hv4~mOtAfdHKhkDczXh-6K1Pls;Mxe|P7*kI)3Xe9yV^M}E zGdv14#>q%chz}QG*i%S6(obH{cr+T1!j1LvLtUsJ7KKI?{39=;HGlNs;(~W#a(N^s z8FaEE2>WhCqfzkw##l6l1mX~;6f6c|hBKxh%+RK02oum0gY(CtKx3@`a3_B>|H-u- ziyR^ffv>J9Lf2F(2%^m}AOc4rn<0dgn~LzqVvP|d{$w*W$xL`p#(Z-<#{4JOt{mY; zm`S3KsUv#&|7{b$aPw1BL>gBZI)X7FB@C?LG~)rT`LXnyf=(Mw7i?#Q@0MT9Xg?3&KchV2e~kI>+XxE;nc@O| z#MN-E-#g*5sJt)|2eb|l#>C%D!x4u+T0lKpAVoQuPWwL?11>4_KN|rQ&Yz4krH~O6 zD$WFf8<|2>9D)KGqdu@Pn6lYKjx3&%x*&p__0(3?Q6Ed+S}RN z*g06^Fy{6sV>25Z%G%W2&e|AbY-WqGF*E(Uv^2cTiWVxI8P)_v1riLq8seHv;o(Mju0no4Sp5{J-!};V=FMo2{!OnCUy?>3K*Wm@T;lma zv=UqpAmT*{F7bRIS_v))5b>e}mv}x9tppbYh63+*smEeK^5id$`iRS~+N^n7dh!-We#Pfk@CAc6!#ETMK;`uxV1Q!H|cu|5&JRgWwf(rsfyePpXo)1JT!36;#UX~p0E(j3u zq6C+CJ`k-07X*lSQ7kU`(N~p0rttmbFyV{H?nqv?@Fiv#ndt5U0O1Az5ETso17C#K zb^r)L0l=%(0DwOL0Gh15t8O^}fKrb+M0}k=`w4AO#T^M7vAtC1RZkHy~%C=cO zXJ;=l(KTAMe_ISFbLaYvx$y}bV!U?DFww1jERF8vJ=s<0y3U!rOZ9bH#bOfQCBN`i z%07q0E1R3tdkKmT`8Nx8dh32+@#UVn8pQ=ni_J_CSZwR{V0pNjA57OjvCN|M$;!9A z>ylHHWh%V}FIuU`_V{1xF>D*!cK$gnqVe|DLH@<&`*kkl>+ysA-3Du~EF~$2+`9L& zM~&5b#8jYtD!0`>apL3gks%rg^)0c>7qr#Jy{L~UZTqYU9GjNv>u!=j6uqDBWWU(% Jw9V>`{{s|`=%4@q literal 0 HcmV?d00001 diff --git a/src/assets/styles.module.less b/src/assets/styles.module.less new file mode 100644 index 0000000..2081384 --- /dev/null +++ b/src/assets/styles.module.less @@ -0,0 +1,31 @@ +/** +* 手写签名用 +*/ +.container { + top: 10%; + left: 10%; + width: 100%; + height: 50vh; +} + +.sigContainer { + width: 100%; + height: 100%; + margin: 0 auto; + background-color: #fff; + cursor: auto; +} + +.sigPointer { + width: 100%; + height: 100%; + margin: 0 auto; + background-color: #fff; + cursor: url("./signPen/signPen.png"),Crosshair; +} + +.sigPad { + width: 100%; + height: 100%; + background: #fff; +} diff --git a/src/components/BiddingRoom/index.js b/src/components/BiddingRoom/index.js index dc412ce..986f754 100644 --- a/src/components/BiddingRoom/index.js +++ b/src/components/BiddingRoom/index.js @@ -5,7 +5,7 @@ import styles from './index.less'; import { connect } from "dva"; import { routerRedux } from 'dva/router'; import React, { useState, useEffect, useReducer } from 'react'; -import { getSessionUserData, getRoomId, getProMethod, getSessionRoleData, getIPassDecode, getDefId, getProId } from '@/utils/session'; +import { getSessionUserData, getRoomId, getRoomStatus, getProMethod, getSessionRoleData, getIPassDecode, getDefId, getProId, getOfflineStatusById } from '@/utils/session'; import { getURLInformation } from '@/utils/CommonUtils'; import { getLeader, isShowResult, isShowCount, getErrorStatus, getRiskStatus, isShowRiskModal, saveConfirm, isLeaderConfirm } from './service'; import logo from '@/images/opening/logo.svg' @@ -34,8 +34,13 @@ const BiddingRoom = (props) => { let data = getSessionUserData(); //获取比选一阶段二次项目,自定义流程,当前供应商 const isBxOneSecondCustom = sessionStorage.getItem("isBxOneSecondCustom"); + //评审方式:状态:0-默认,1-已确认配置分工及组长 + const roomJuryConfigStatus = sessionStorage.getItem("roomJuryConfigStatus"); + //评审方式:0-线上、1-线下 + const roomReviewMethod = sessionStorage.getItem("roomReviewMethod"); //获取评审室id const roomId = getRoomId(); + const roomStatus = getRoomStatus(); const [list, setList] = useState(); //风险提示文字弹窗控制 const [riskVisible, setRiskVisible] = useState(false); @@ -96,6 +101,28 @@ const BiddingRoom = (props) => { path: "/EvaRoom/Evaluation/projectManager/ReviewResults/Manager", text: "评审结果" }] + //项目经理角色 + let managerOffList = [ + { + id: 1, + path: "/EvaRoom", + text: "基本信息" + }, + { + id: 2, + path: "/EvaRoom/BiddingDocumentsDecrypt", + text: `${responseType}文件查看` + }, + { + id: 3, + path: "/EvaRoom/Evaluation/BidControl/BidControlManager", + text: "风险点展示" + }, + { + id: 8, + path: "/EvaRoom/Evaluation/projectManager/ReviewResults/ManagerEntry", + text: "评审结果录入" + }] let JuryList = [ { id: 1, @@ -179,13 +206,25 @@ const BiddingRoom = (props) => { //评审结果页签点击事件 const onclick = async (path, id) => { + await getOfflineStatusById(roomId) if ((role == 'ebtp-agency-project-manager' || role == 'ebtp-purchase') && id == 8) { //代理&采购经理进入评审结果 - const success = await isClickResult(); - if (success) { - history.push({ pathname: path }); - setSelectedPath(path); + if (roomReviewMethod == 0){ + const success = await isClickResult(); + if (success) { + history.push({ pathname: path }); + setSelectedPath(path); + } else { + message.info("未到评审结果环节,无法进入评审结果") + } } else { - message.info("未到评审结果环节,无法进入评审结果") + console.log("roomJuryConfigStatus", roomJuryConfigStatus) + + if (roomJuryConfigStatus == 1) { + history.push({ pathname: path }); + setSelectedPath(path); + } else { + message.info("未到评审结果环节,无法进入评审结果") + } } } else if (role == 'ebtp-expert' && id == 8) {//专家进入评审结果 const success = await isClickResult(); @@ -246,14 +285,14 @@ const BiddingRoom = (props) => { if (res?.data == "Review") { return "/EvaRoom/Evaluation/expert/ReviewResults/Jury" } else { - const result = await isLeaderConfirm({ assessRoomId: roomId });//供应商股权关系-专家组长是否确认风险 - if (result?.success && result?.data) { + //TODO zyx暂时不需要const result = await isLeaderConfirm({ assessRoomId: roomId });//供应商股权关系-专家组长是否确认风险 + //TODO zyx暂时不需要if (result?.success && result?.data) { return "/EvaRoom/Evaluation/expert/ReviewResults/GroupLeader" - } else { - setIsResult(true) - setRiskVisible(true) - return false; - } + //TODO zyx暂时不需要} else { + //TODO zyx暂时不需要 setIsResult(true) + //TODO zyx暂时不需要 setRiskVisible(true) + //TODO zyx暂时不需要 return false; + //TODO zyx暂时不需要} } } else { return false @@ -347,7 +386,11 @@ const BiddingRoom = (props) => { } //代理&项目经理 if (role == "ebtp-agency-project-manager" || role == "ebtp-purchase") {//代理和采购经理 - setList(managerList); + if(true){ + setList(managerOffList); + }else { + setList(managerList); + } } else if (role == "ebtp-expert") {//专家 setList(JuryList) } else if (role == "ebtp-supplier") {//供应商 diff --git a/src/models/bidev.js b/src/models/bidev.js index d4d0e79..067150e 100644 --- a/src/models/bidev.js +++ b/src/models/bidev.js @@ -1,4 +1,4 @@ -import { fetchManagerList,openBizassessroom,resetVerificationCode,fetchJuryList,fetchSupplierList +import { fetchManagerList,openBizassessroom,openOffBizassessroom,resetVerificationCode,fetchJuryList,fetchSupplierList ,fetchJuryMemInfo,updateJuryMemInfo,validateVerificationCode,fetchbidslist ,fetchPreSupplierList,fetchPreList,fetchPreListt,bxmultifetchPreListt,pushRedirectRe,getCheckedByRoomId,checkOpenBidSupplier,zmmultiOpenBizassessroom } from '../services/bidev'; import { message } from 'antd'; @@ -43,6 +43,23 @@ export default { } callback(); }, + // 开启线下评审室 + *openOffBizassessroom({payload,callback}, { call, put }){ + const response =yield call(openOffBizassessroom,payload) + if(response?.code==200){ + // 查询招标代理列表 + const params={ + pageNo:1, + pageSize:10, + reviewMethod:1, + roomType: getURLInformation('roomType'), + tpId:getProId()//项目id + } + yield put({ type: 'fetchManagerList', payload: {...params} }); + message.success("开启成功!") + } + callback(); + }, // 开启评审室(多轮招募) *zmmultiOpenBizassessroom({payload,callback}, { call, put }){ const response =yield call(zmmultiOpenBizassessroom,payload) diff --git a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx index 117f5fc..110048b 100644 --- a/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx +++ b/src/pages/Evaluation/expert/ReviewResults/GroupLeader/components/GroupLeader.tsx @@ -11,6 +11,8 @@ import { reviewReportExpertsConfirmed } from '../../Jury/service'; import { getDicData, getProMethod, getRoomId } from '@/utils/session'; import { btnAuthority } from '@/utils/authority'; import WebOffice0609, { WebOfficeRefProps } from '@/pages/webOffice/weboffice0609'; +import styles from '@/assets/styles.module.less' +import SignaturePad from 'react-signature-canvas' import SortEditableTable from './SortEditableTable'; import ReviewReportUpload from '@/utils/ReviewReportUpload'; import { ExclamationCircleOutlined } from '@ant-design/icons'; @@ -111,6 +113,10 @@ const GroupLeader: React.FC = () => { const [resultDisabledStatus, setResultDisabledStatus] = useState(false); //报价类型 true-百分比类型(折扣率,优惠率)false-数值类型(总价,单价) const [quotationMethod, setQuotationMethod] = useState(false); + //评审报告确认无误弹出窗 + const [visibleConfirm, setVisibleConfirm] = useState(false); + //鼠标指针ref + const pointRef = useRef() //评价方法 eval_method_1 最低价法 eval_method_2 综合评估法 const [evalMethodDict, setEvalMethodDict] = useState(''); //评审结果排序弹窗 @@ -1446,6 +1452,142 @@ const GroupLeader: React.FC = () => { setSpinning(false); }) } + + /** + * 评审报告确认无误(签字面板) + * zhoujianlong 2021.8.19 + * @returns + */ + const modalConfirm = () => { + //保存loading + const [loading, setLoading] = useState(false); + //关闭modal + const onCancel = () => { + init(); + setVisibleConfirm(false); + } + //canvas ref + let sigPad: any = {} + //手写签名存储 + const [saveTrimCanvas, setSaveTrimCanvas] = useState('') + const canvasBase64 = reviewReportData?.expertList?.[0]?.expertSign + useEffect(() => { + if(canvasBase64 != undefined){ + setSaveTrimCanvas(canvasBase64) + } + }, [canvasBase64]) + + /** + * 保存或发送调用接口 + * @params expertSign 签名产生的base64值 + * status true-保存 false-发送 + */ + const toSaveOrSend = (expertSign: string,status: boolean) => { + let params = { + expertOpinion: 1, + reportId: reviewReportData.id, + expertSign: expertSign + }; + if(status){ //判断是保存还是发送 + params["status"] = 0 + } + setLoading(true) + reviewReportExpertsConfirmed(params).then(res => { + if(res?.code == 200 && res?.success === true) { + commonMessage(res); + if(status) {} else { + onCancel(); + } + } + }).finally(() => { + setLoading(false) + }) + } + //提交 status true-保存 false-发送 + const submit = (status: boolean) => { + let emptyStatus = sigPad.isEmpty(); + if(emptyStatus) { + message.error("当前无签名内容,请先签名"); + return; + } + //得到画布 + let canvas = sigPad._canvas; + if (canvas.getContext) { + let ctx = canvas.getContext('2d'); + // 将canvas的透明背景设置成白色 + let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + for(var i = 0; i < imageData.data.length; i += 4) { + // 当该像素是透明的,则设置成白色 + if(imageData.data[i + 3] == 0) { + imageData.data[i] = 255; + imageData.data[i + 1] = 255; + imageData.data[i + 2] = 255; + imageData.data[i + 3] = 255; + } + } + ctx.putImageData(imageData, 0, 0); + } + let imgUrl = sigPad.toDataURL('image/png',1); + setSaveTrimCanvas(imgUrl) + toSaveOrSend(imgUrl,status) + } + //clear + const clear = () => { + sigPad.clear(); + } + //SignaturePad ref + const refRender = (ref: any) => { + sigPad = ref //存储ref + if(ref != null) { + ref?.clear() + ref?.fromDataURL(saveTrimCanvas) + } + } + return ( + <> + submit(false)}> + 发送 + , + , + , + , + 提示:按住鼠标左键进行签名 + ]} + > + +
+
pointRef.current.className = styles.sigPointer} onMouseUp={() => pointRef.current.className = styles.sigContainer}> + +
+
+
+
+ + ) + } /** * 评审报告存在问题 @@ -1529,7 +1671,7 @@ const GroupLeader: React.FC = () => { ) } /** - * 评审报告确认无误 + * 评审报告确认无误(无需手写签名) */ const beConfirmed = () => { setReviewReportLoading(true); @@ -1544,6 +1686,14 @@ const GroupLeader: React.FC = () => { }) } + //确认无误的手写签名判断方法 + const toReportConfirm = () => { + if(String(reviewReportData?.signStatus) == '1') {//判断是否启用手写签名 1-是 0-否 + setVisibleConfirm(true); + } else { + beConfirmed(); + } + } const saveTable = (data: any, config: any) => { let form = config?.form; form.validateFields().then((res: any) => { @@ -1606,11 +1756,12 @@ const GroupLeader: React.FC = () => { value={supplierTableData} onChange={setSupplierTableData} scroll={{ x: 1300 }} - onRow={record => { + onRow={(record, index) => { return { // 鼠标移入行 onMouseEnter: () => { setEditableRowKeys(resultDisabledStatus ? [] : [record.id]) + setEditableRowKeys((resultDisabledStatus || (assessId == "1558990153220034560" && index == 0)) ? [] : [record.id]) }, onMouseLeave: () => { setEditableRowKeys([]); @@ -1633,12 +1784,12 @@ const GroupLeader: React.FC = () => {
{isNotEmpty(reviewReportData.id) && ( - + {reportFileList.length == 0 ? null : } - - + + @@ -1664,6 +1815,7 @@ const GroupLeader: React.FC = () => { )} {modelIssue()} + {modalConfirm()} {sortTableVisible && setSortTableVisible(false)} diff --git a/src/pages/Evaluation/expert/ReviewResults/Jury/components/Jury.tsx b/src/pages/Evaluation/expert/ReviewResults/Jury/components/Jury.tsx index 7f29f13..6337234 100644 --- a/src/pages/Evaluation/expert/ReviewResults/Jury/components/Jury.tsx +++ b/src/pages/Evaluation/expert/ReviewResults/Jury/components/Jury.tsx @@ -10,6 +10,8 @@ import Weboffice from "@/pages/webOffice/weboffice"; import { getDicData, getProMethod, getRoomId } from '@/utils/session'; import { btnAuthority } from '@/utils/authority'; import WebOffice0609, { WebOfficeRefProps } from '@/pages/webOffice/weboffice0609'; +import styles from '@/assets/styles.module.less' +import SignaturePad from 'react-signature-canvas' import ReviewReportUpload from '@/utils/ReviewReportUpload'; import { getFileListByBid } from '@/utils/DownloadUtils'; import MACAddressPrompt from '@/pages/Evaluation/BidControl/BidControlManager/components/MACAddressPrompt'; @@ -53,6 +55,10 @@ const Jury: React.FC = () => { const [ptcpMode, setPtcpMode] = useState(); //报价类型 %-百分比类型(折扣率,优惠率)元-数值类型(总价,单价) const [quotationMethod, setQuotationMethod] = useState('元'); + //评审报告确认无误弹出窗 + const [visibleConfirm, setVisibleConfirm] = useState(false); + //鼠标指针ref + const pointRef = useRef() //初始化显示字段 const candidateType = bidMethodDict == 'procurement_mode_1' || bidMethodDict == 'procurement_mode_2' ? '中标' : '中选';//初始化中标中选字段 //评审报告附件modal visible @@ -663,6 +669,143 @@ const Jury: React.FC = () => { ) } + + /** + * 评审报告确认无误(签字面板) + * zhoujianlong 2021.8.19 + * @returns + */ + const modalConfirm = () => { + //保存loading + const [loading, setLoading] = useState(false); + //关闭modal + const onCancel = () => { + init(); + setVisibleConfirm(false); + } + //canvas ref + let sigPad: any = {} + //手写签名存储 + const [saveTrimCanvas, setSaveTrimCanvas] = useState('') + const canvasBase64 = reviewReportData?.expertList?.[0]?.expertSign + useEffect(() => { + if(canvasBase64 != undefined){ + setSaveTrimCanvas(canvasBase64) + } + }, [canvasBase64]) + + /** + * 保存或发送调用接口 + * @params expertSign 签名产生的base64值 + * status true-保存 false-发送 + */ + const toSaveOrSend = (expertSign: string,status: boolean) => { + let params = { + expertOpinion: 1, + reportId: reviewReportData.id, + expertSign: expertSign + }; + if(status){ //判断是保存还是发送 + params["status"] = 0 + } + setLoading(true) + reviewReportExpertsConfirmed(params).then(res => { + if(res?.code == 200 && res?.success === true) { + commonMessage(res); + if(status) {} else { + onCancel(); + } + } + }).finally(() => { + setLoading(false) + }) + } + //提交 status true-保存 false-发送 + const submit = (status: boolean) => { + let emptyStatus = sigPad.isEmpty(); + if(emptyStatus) { + message.error("当前无签名内容,请先签名"); + return; + } + //得到画布 + let canvas = sigPad._canvas; + if (canvas.getContext) { + let ctx = canvas.getContext('2d'); + // 将canvas的透明背景设置成白色 + let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + for(var i = 0; i < imageData.data.length; i += 4) { + // 当该像素是透明的,则设置成白色 + if(imageData.data[i + 3] == 0) { + imageData.data[i] = 255; + imageData.data[i + 1] = 255; + imageData.data[i + 2] = 255; + imageData.data[i + 3] = 255; + } + } + ctx.putImageData(imageData, 0, 0); + } + let imgUrl = sigPad.toDataURL('image/png',1); + setSaveTrimCanvas(imgUrl) + toSaveOrSend(imgUrl,status) + } + //clear + const clear = () => { + sigPad.clear(); + } + //SignaturePad ref + const refRender = (ref: any) => { + sigPad = ref //存储ref + if(ref != null) { + ref?.clear() + ref?.fromDataURL(saveTrimCanvas) + } + } + return ( + <> + submit(false)}> + 发送 + , + , + , + , + 提示:按住鼠标左键进行签名 + ]} + > + +
+
pointRef.current.className = styles.sigPointer} onMouseUp={() => pointRef.current.className = styles.sigContainer}> + +
+
+
+
+ + ) + } + /** * 评审报告 我有问题 */ @@ -783,7 +926,7 @@ const Jury: React.FC = () => { ) } /** - * 确认无误 + * 确认无误(无需手写签名) */ const submitReviewReport = () => { setReviewReportLoading(true); @@ -797,6 +940,15 @@ const Jury: React.FC = () => { init(); }) } + //确认无误的手写签名判断方法 + const toReportConfirm = () => { + console.log(String(reviewReportData?.signStatus)) + if(String(reviewReportData?.signStatus) == '1') {//判断是否启用手写签名 1-是 0-否 + setVisibleConfirm(true); + } else { + submitReviewReport(); + } + } /** * 获取表头 */ @@ -844,12 +996,14 @@ const Jury: React.FC = () => { { (isNotEmpty(reviewReportData) && isNotEmpty(reviewReportData.id)) && ( - + {reportFileList.length == 0 ? null : } - - + {/* + */} + + @@ -876,6 +1030,7 @@ const Jury: React.FC = () => { {modelIssue()} {modelProblem()} + {modalConfirm()} {reportUploadVisible && setReportUploadVisible(false)} diff --git a/src/pages/Evaluation/projectManager/ReviewResults/ManagerEntry/index.tsx b/src/pages/Evaluation/projectManager/ReviewResults/ManagerEntry/index.tsx new file mode 100644 index 0000000..6169442 --- /dev/null +++ b/src/pages/Evaluation/projectManager/ReviewResults/ManagerEntry/index.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import Manager from './components/Manager'; +/** + * 项目经理 + */ +const Index: React.FC = () => { + return ( + <> + + + ); +} +export default Index; \ No newline at end of file diff --git a/src/pages/Evaluation/projectManager/ReviewResults/service.ts b/src/pages/Evaluation/projectManager/ReviewResults/service.ts index acb2ea7..bbce483 100644 --- a/src/pages/Evaluation/projectManager/ReviewResults/service.ts +++ b/src/pages/Evaluation/projectManager/ReviewResults/service.ts @@ -51,3 +51,10 @@ export function finishFlow(id: any) { export function getAssessRoomStatus(id: any) { return request('/api/biz-service-ebtp-process/v1/bizassessroom/info/' + id); } +/** + * 生成签名报告 + * @param id + */ +export function saveSignPdfReport(id: any) { + return request('/api/biz-service-ebtp-evaluation/v1/review/report/signpdf/' + id); +} diff --git a/src/pages/Tender/ProjectManager/JudgingPanel/List/preIndex.tsx b/src/pages/Tender/ProjectManager/JudgingPanel/List/preIndex.tsx new file mode 100644 index 0000000..63c7ceb --- /dev/null +++ b/src/pages/Tender/ProjectManager/JudgingPanel/List/preIndex.tsx @@ -0,0 +1,1730 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Button, Checkbox, Col, Collapse, DatePicker, Drawer, Form, Input, message, Modal, Popconfirm, Row, Select, Spin, Upload, Image, InputNumber } from 'antd' +import ProTable, { ActionType, EditableProTable, ProColumns } from '@ant-design/pro-table'; +import { getList, saveGroup, delOne, saveMember, changeEx, queryVoList, changeMember, applyFor, roomStatus, juryTem, rePassWord, getUserPhoto, unlockAccount, getCrotchListUsingGET, getSecs } from './service'; +import moment from 'moment'; +import { getDefId, getProId, getProMethod, getProOpenTenderForm, getSessionUserData } from '@/utils/session'; +import { getURLInformation, isEmpty } from '@/utils/CommonUtils'; +import './judgList.less'; +import '@/assets/xsy_style.less'; +import FileDown from '@/utils/Download'; +import { UploadOutlined } from '@ant-design/icons'; +import { btnAuthority } from '@/utils/authority'; +import RiskPrevention from '@/utils/RiskPrevention'; +import { downloadPath } from '@/utils/DownloadUtils'; +import { sortBy } from 'lodash'; +import ExpertSchemeProfessionalInfo from './ExpertSchemeProfessionalInfo'; + +const JudgingPanel: React.FC<{}> = () => { + const modalHeight = window.innerHeight * 96 / 100; + const proId = getProId(); + const roomType = getURLInformation('roomType'); + // const tailLayout = { wrapperCol: { offset: 8, span: 20 }, }; + const formLayout = { labelCol: { span: 8 }, wrapperCol: { span: 16 }, }; + const form24Layout = { labelCol: { span: 4 }, wrapperCol: { span: 20 }, }; + const FormItem = Form.Item; + const [form] = Form.useForm(); + const { Option } = Select; + const { Panel } = Collapse; + const { TextArea } = Input; + const CheckboxGroup = Checkbox.Group; + // const { TabPane } = Tabs; + const actionRef = useRef(); + const [spin, spinSet] = useState(false); + const [loading, loadingSet] = useState(false); + const [sections, setSections] = useState([]); + const [sectionsVal, setSectionsVal] = useState([]); + const [modalVis, setModalVis] = useState(false);//新增评委会 + const [updateData, updateDataSet] = useState();//评委会modal数据 + const [memberVis, setMemberVis] = useState(false); + const [open, openSet] = useState(true);//评委会里是否有开启评标的评审室 true有开启的 false无 + const [allEnd, allEndSet] = useState(true);//评委会关联标段的评审室是否都关闭了 + const [disabled, disabledSet] = useState(true);//禁用 + const [checkSectionName, checkSectionNameSet] = useState('');//查看 关联标包显示 + const [showName, showNameSet] = useState({ zbr: '', bb: '', pb: '', });//字段名 + // const [manNum, manNumSet] = useState(5);//人数 + const [riskVisible, setRiskVisible] = useState(false);//风控弹窗 2021.9.7 zhoujianlong + const [riskData, setRiskData] = useState([]);//风控数据 2021.9.7 zhoujianlong + // const [userPhotoId, setUserPhotoId] = useState("");//电子评标室-录入外部专家-相片id 2022.8.29 zhoujianlong + const userData = getSessionUserData();//当前登录人用户信息 + + const [professionalMap, setProfessionalMap] = useState(); + //当前可编辑的行 + const [editableKeys, setEditableRowKeys] = useState([]); + const [tableData, setTableData] = useState([]); + function getShouName() { + const method = getProMethod(); + let showNameT: any = { zbr: '', bb: '', pb: '', }//相关标段 标书费 保证金 服务费 + // let num = 3; + if (method === 'procurement_mode_1' || method === 'procurement_mode_2') {//招标 + showNameT = { zbr: '招标人', bb: '标段', pb: '评标', }; + // num = 5; + } else if (method === 'procurement_mode_4') {//招募类 + showNameT = { zbr: '采购人', bb: '包件', pb: '评审', } + } else {//谈判类 + showNameT = { zbr: '采购人', bb: '采购包', pb: '评审', } + } + showNameSet(showNameT); + } + + //多选控制 + const [indeterminate, setIndeterminate] = useState(false); + const [checkAll, setCheckAll] = useState(false); + const [checkedList, setCheckedList] = useState(); + const [sectionCount, sectionCountSet] = useState(0);//控制获取标包 + + //创建评委会小组 + const saveG = async (fields: any) => { + const hide = message.loading('正在配置'); + try { + const success = await saveGroup({ ...fields }).then((res) => { + if (res?.code == 4004 && res?.success == false) { //2021.9.7 zhoujianlong 新增评委会保存增加风控 + const data = res?.data?.result == undefined ? [] : res?.data?.result + setRiskData(data) + setRiskVisible(true) + } + return res.success + }); + hide(); + if (success) { + message.success('配置成功'); + } + return true; + } catch (error) { + hide(); + message.error('配置失败请重试!'); + return false; + } + }; + + //主页表格 + const columns: ProColumns[] = [ + { title: '序号', valueType: 'index', width: 50, }, + { title: `${showName.bb}名称`, dataIndex: 'sectionName', }, + { title: '专家抽取数量', dataIndex: 'expertNumber', width: 120 }, + { title: `直接录入数量`, dataIndex: 'representativeNumber', width: 120 }, + { title: '预计开始时间', dataIndex: 'startTime', valueType: 'dateTime', width: '10%', }, + { title: '预计结束时间', dataIndex: 'endTime', valueType: 'dateTime', width: '10%', }, + { + title: '操作', dataIndex: 'option', width: '16%', + valueType: 'option', + render: (_, record) => { + if (record.status == 0 || record.status == 2) { + return ( + <> + {returnCheck(record, false)} + { + spinSet(true) + await del({ id: record.id }); + actionRef.current?.reload(); + spinSet(false) + }} + okText="确定" + cancelText="取消" + > + + + + + ) + } else if (record.status == 1) {//已提交申请 + return ( + <>{returnCheck(record, true)} + ) + } else if (record.status == 3) { + return ( + <> + {returnCheck(record, true)} + + + ); + } else { + return (<>) + } + } + }, + ]; + function returnCheck(record: any, check: any) {//返回操作列查看、修改按钮 + return ( + + ) + } + const handleUpdate = async (record: any) => { + form.resetFields(); + const res = await queryVoList({ id: record.id }); + + + // 提取专业抽取列表 + const extractSpecialityList = res.data.extractSpecialityList || []; + // 设置表格数据 + let specList = extractSpecialityList.map((item: any, index: number) => ({ + ...item, + uid: item.id || String(index + Date.now()) // 确保每个条目有唯一 key + })) + res.data.extractSpecialityList = specList; + setTableData(specList); + // 设置 editableKeys,确保每一行都能编辑 + setEditableRowKeys(specList.map((item: any, index: number) => item.uid)); + // setEditableRowKeys(specList.map(item => item.uid)); + updateDataSet(res.data); + + //剔除代表 + let list = [...res.data.juryCategoryVOList]; + list.map((item: any, index: any) => { + if (item.category == 1) { + list.splice(index, 1); + } + }); + cqDataSet(list); + setModalVis(true); + sectionCountSet(sectionCount + 1); + // readOnlySet(check); + checkSectionNameSet(res.data.sectionName); + + }; + const handleMember = async (record: any) => { + form.resetFields(); + const res = await queryVoList({ id: record.id }); + await queryOpenStatus(record.id); + categorySet(res.data.juryCategoryVOList); + juryIdSet(record.id); + memberCountSet(memberCount + 1); + setMemberVis(true); + }; + + //删除 + const del = async (fields: any) => { + const hide = message.loading('正在删除'); + try { + const success = await delOne({ ...fields }).then((res) => { + return res.success + }); + hide(); + if (success) { + message.success('删除成功'); + return true; + } else { + message.error('删除失败'); + return false; + } + } catch (error) { + hide(); + message.error('删除失败请重试!'); + actionRef.current?.reload(); + return false; + } + }; + //提交申请 + const apply = async (fields: any) => { + const hide = message.loading('正在提交'); + try { + const success = await await applyFor({ ...fields }).then((res) => { + return res.success + }); + hide(); + if (success) { + message.success('提交成功'); + return true; + } else { + message.error('提交失败'); + return false; + } + } catch (error) { + hide(); + message.error('提交失败请重试!'); + actionRef.current?.reload(); + return false; + } + }; + + //创建修改 标包方法 + const onChangeCheckBox = (checkedList: any[]) => { + // 获取当前选中的所有 section 对象 + const selectedSections = sections.filter((section: any) => + checkedList.includes(section.sectionId) + ); + + // 获取所有不同的 juryNumber 值 + const uniqueJuryNumbers = [...new Set(selectedSections.map((s: any) => s.juryNumber))]; + + if (uniqueJuryNumbers.length > 1) { + message.error('所选标段的评标委员会人数不一致,不能同时选择'); + return; // 阻止更新 + } + + setCheckedList(checkedList); + getEarliestTime(sections, checkedList); + setIndeterminate(!!checkedList.length && checkedList.length < sectionsVal.length); + setCheckAll(checkedList.length === sectionsVal.length); + }; + const onCheckAllChange = (e: { target: { checked: any; }; }) => { + + const uniqueJuryNumbers = [ + ...new Set(sections.map((s: any) => s.juryNumber)), + ]; + + if (e.target.checked && uniqueJuryNumbers.length > 1) { + message.error("存在不同评标委员会人数,不能全选"); + return; + } + setCheckedList(e.target.checked ? sectionsVal : []); + getEarliestTime(sections, e.target.checked ? sectionsVal : []); + setIndeterminate(false); + setCheckAll(e.target.checked); + }; + + + function disabledDate(current: any) {//日期选择 + return current && current < moment().startOf('day'); + } + + + const rule = (mes: any) => {//创建修改 规则 + return [ + { + required: true, + message: `请录入${mes}`, + }, + ] + } + //专家账号解锁 + const unlockExportAccount = async (record: any, juryId: any, proId: any) => { + try { + const res = await unlockAccount(record.id, juryId, proId); + if (res.success) { + message.success(res.data); + } + } catch (error) { + + } + } + + useEffect(() => {//获取标包信息 + + let params = { tpId: proId, roomType: roomType }; + let checked: any = []; + if (updateData !== undefined && JSON.stringify(updateData) !== "{}") { + params['juryId'] = updateData.id; + updateData.juryRoomList.map((item: any) => { + checked.push(item.sectionId); + }); + setCheckedList(checked); + } else { + params['juryId'] = ''; + } + getShouName();//根据采购类型变名字 + modalVis == true ? getSecs({ ...params }).then((res) => { + let data = []; + let secVals = []; + if (res.success) { + secVals = res.data.map((item: any) => { return item.sectionId }) + data = res.data; + } + setSections(data); + setSectionsVal(secVals); + setIndeterminate(!!checked.length && checked.length < secVals.length); + setCheckAll(checked.length === secVals.length); + updateData && String(updateData?.reserveStatus) == "1" && getEarliestTime(data, checked);//初始化赋值数据 + }) : null; + + }, [sectionCount]); + + useEffect(() => {//给表单赋值 + form.setFieldsValue({ + juryType: updateData != undefined ? updateData.juryType : null, + representativeNumber: updateData != undefined ? updateData.representativeNumber : null, + expertNumber: updateData != undefined ? updateData.expertNumber : null, + startTime: updateData != undefined ? updateData.reserveStatus == 1 ? moment(updateData.elecEvalRoomReserve.reserveStartDate, 'yyyy-MM-DD HH:mm:ss') : moment(updateData.startTime, 'yyyy-MM-DD HH:mm:ss') : null, + endTime: updateData != undefined ? updateData.reserveStatus == 1 ? moment(updateData.elecEvalRoomReserve.reserveEndDate, 'yyyy-MM-DD HH:mm:ss') : moment(updateData.endTime, 'yyyy-MM-DD HH:mm:ss') : null, + evalLocation: updateData != undefined ? updateData.reserveStatus == 1 ? updateData.elecEvalRoomReserve.areaAddress : updateData.evalLocation : null, + description: updateData != undefined ? updateData.description : null, + extractSpecialityList: updateData != undefined ? updateData.extractSpecialityList : null, + }) + }, [updateData]); + + const group = () => {//评审小组modal + return ( + <> + { + setModalVis(false); + updateDataSet({}); + setTableData([]); + setCheckedList([]); + form.resetFields(); + }} + > + {tab1()} + + + ) + } + //人数校验 + function checkMan(count: number, expCon: any) { + let res = true; + const defId = getDefId();//16 + const method = getProMethod();//9 + const yushenType = getProOpenTenderForm(); + let manNumT = 5; + + if (method === 'procurement_mode_1' || method === 'procurement_mode_2') { + if (roomType == '1' && yushenType == 'open_tender_form_2') {//资格预审 自愿招标为3 + manNumT = 3; + } + // if (expCon < count * 2 / 3) { + // res = false; + // message.error("专家人数不少于评委会总人数2/3") + // } + } else if (method === 'procurement_mode_3') {//比选 + if (expCon < count * 2 / 5) { + res = false; + message.error("专家人数不少于评委会总人数2/5") + } + } else if (method === 'procurement_mode_4') {//招募 + manNumT = 1; + if (count < manNumT) { + res = false; + message.error(`评委会总人数需大于1`) + } else { + return true; + } + } else if (method === 'procurement_mode_5') {//竞谈 + if (manNumT = 5) {//最低价 + manNumT = 3; + } + if (expCon < count * 1 / 3) { + res = false; + message.error("专家人数不少于评委会总人数1/3") + } + } else if (method === 'procurement_mode_6') {//单一 + manNumT = 3; + } else if (method === 'procurement_mode_9') {//单一 + manNumT = 3; + } else if (defId == 'inquiry') {//询价 + manNumT = 3; + } + if (count < manNumT || count % 2 == 0) {//校验总人数 + res = false; + message.error(`评委会总人数需大于等于${manNumT}人且为单数`) + } + return res + } + //添加抽取drawer + const formLayoutDrawer = { labelCol: { span: 8 }, wrapperCol: { span: 16 }, }; + const tailLayoutDrawer = { wrapperCol: { offset: 8, span: 20 }, }; + const [cqData, cqDataSet] = useState([]);//抽取表格,提交时需要 + // 在组件内定义函数 + const calculateExpertNumber = () => { + // 没有选中标段时直接返回,不清空 expertNumber 是为了兼容已有值的情况 + if (!checkedList || checkedList.length === 0) return; + + const selectedSections = sections.filter((section: any) => + checkedList.includes(section.sectionId) + ); + + const uniqueJuryNumbers = [...new Set(selectedSections.map((s: any) => s.juryNumber))]; + + if (uniqueJuryNumbers.length > 1) { + form.setFieldsValue({ expertNumber: undefined }); + message.error("所选标段评标委员会人数不一致"); + return; + } + + const juryNumber = parseInt(uniqueJuryNumbers[0]) || 0; + const repNumber = parseInt(form.getFieldValue('representativeNumber')) || 0; + + + if (repNumber < 0 || repNumber > juryNumber) { + message.error(`直接录入数量应在 0 ~ ${juryNumber} 之间`); + form.setFieldsValue({ representativeNumber: undefined, expertNumber: undefined }); + return; + } + + const expertNumber = Math.max(0, juryNumber - repNumber); + (expertNumber === 0) && setTableData([]); + form.getFieldValue('representativeNumber') && form.setFieldsValue({ expertNumber }); + }; + + // 在 useEffect 中监听依赖项 + useEffect(() => { + if (Array.isArray(sections) && sections.length > 0) { + calculateExpertNumber(); + } + }, [form.getFieldValue('representativeNumber'), checkedList, sections]); + const tab1 = () => {//cqtab1 + return ( + <> +

关联{showName.bb}

+
+ + + { return '1' } + }, + () => ({ + validator(rule, value,) { + let leg = 0; + checkedList != undefined ? leg = checkedList.length : leg = 0; + if (leg > 0) { + return Promise.resolve(); + } else { + message.error(`请选择${showName.bb}`) + return Promise.reject(`请选择${showName.bb}`); + } + }, + }), + ]} + > + { + disabled ? + {checkSectionName} + : <> + { + sections.length > 0 ? <> +
+ 全选 +
+
+ + + { + sections.map((item: any, index: any) => { + return ( + + {item.sectionName} + + + + ) + }) + } + + + + : 无可用{showName.bb} + } + + } +
+ +
+
+

评标时间和地点管理

+
+ + + + + + + + + + + + + +
+

专家申请基本信息

+
+ + + { + // const value = e.target.value; + // if (value && !checkedList?.length) { + // form.resetFields(['representativeNumber']); + // message.error("请先选择关联标段"); + // return; + // } + + // 继续触发计算 + // form.setFieldsValue({ representativeNumber: value }); + // calculateExpertNumber(); + // }} + /> + + + + + + + + + {() => { + const expertNumber = form.getFieldValue('expertNumber'); + if (!expertNumber || expertNumber <= 0) return null; + + return ( + + + rowKey="uid" + toolBarRender={false} + columns={professColumns} + dataSource={tableData} + recordCreatorProps={{ + newRecordType: 'dataSource', + hidden: disabled, + creatorButtonText: '新增', + record: () => ({ + uid: String(Date.now()), + // id: "", + // extractNumber: "", + // specialityId: "", + }), + }} + editable={{ + type: 'multiple', + editableKeys, + onChange: (keys, rows) => { + setEditableRowKeys(keys); + }, + onValuesChange: (record, recordList) => { + setTableData(recordList); + }, + actionRender: (row, _, dom) => { + return [dom.delete]; + }, + }} + /> + + ); + }} + + + {/* + + */} + +
+ + ) + } + //抽取专业-表格类型定义 + type DataSourceType = { + id?: string; + extractNumber: number; + specialityId?: string; + }; + const professColumns: ProColumns[] = [ + { + title: '主键', + dataIndex: 'id', + hideInTable: true, + }, + { + title: '专业名称', + dataIndex: 'specialityId', + valueType: 'select', + valueEnum: professionalMap, + width: '30%', + }, + { + title: '人数', + dataIndex: 'extractNumber', + width: '30%', + renderFormItem: (_, { record }) => { + return ; + }, + }, + { + title: '操作', + valueType: 'option', + hideInTable: disabled, + }, + ]; + /** + * 校验函数 + * @param schemaData + * @returns + */ + const checkData = (schemaData: any) => { + let res = true; + let spec = 0; + let specNum = 0; + for (let i = 0; i < schemaData?.extractSpecialityList?.length; i++) { + const item = schemaData?.extractSpecialityList?.[i]; + if ( + item.hasOwnProperty("specialityId") && + item.hasOwnProperty("extractNumber") + ) { + spec += 1; + } + if (item?.extractNumber) { + specNum += Number(item?.extractNumber); + } + } + if (Number(schemaData?.expertNumber) !== specNum) { + res = false; + message.error("抽取专业人数与专家需求人数不符!"); + } + return res; + } + const checkSpecialityUnique = () => { + let res = true; + const specialityIds = tableData.map(item => item.specialityId).filter(Boolean); + const unique = [...new Set(specialityIds)]; + if (specialityIds.length !== unique.length) { + res = false; + message.error('抽取专业名称不可重复选择'); + } + return res; + }; + const idToNameMap = Object.entries(professionalMap || {}).reduce((acc, [id, option]) => { + acc[id] = option.text; + return acc; + }, {} as Record); + const idToCodeMap = Object.entries(professionalMap || {}).reduce((acc, [id, option]) => { + acc[id] = option.text; + return acc; + }, {} as Record); + // 遍历表格数据并附加专业名称 + const enhancedData = tableData.map(item => { + const name = idToNameMap[item.specialityId] || ''; // 获取对应名称 + const code = idToCodeMap[item.specialityId] || ''; // 获取对应名称 + return { + ...item, + specialityName: name, // 添加专业名称字段 + specialityNo: code, + }; + }); + const renderFooter = () => {//评审小组footer + return ( + <> + + + + ) + }; + + //成员管理 + const [add, setAdd] = useState(false);//录入外部专家Drawer显隐 + const [changeMan, changeManSet] = useState(false);//更换Drawer显隐 + const [juryId, juryIdSet] = useState('');//更换专家所需评委会id + const [reason, reasonSet] = useState('');//更换专家原因 + const [category, categorySet] = useState([]);//类别 juryCategoryVOList + const [daibiao, daibiaoSet] = useState({});//代表 + const [jishu, jishuSet] = useState({});//技术 + const [shangwu, shangwuSet] = useState({});//商务 + const [falv, falvSet] = useState({});//法律 + const [qita, qitaSet] = useState({});//其它 + const [luru, luruSet] = useState(0);//录入外部传类别 + const [updateKeyMem, updateKeyMemSet] = useState(-1);//触发修改存key + const [memberCount, memberCountSet] = useState(0);//刷新成员管理页面 + const [checkBoxs, checkBoxsSet] = useState([]);//更换专家按钮组 + const [checkBoxsStatus, checkBoxsStatusSet] = useState({});//更换专家按钮组 + const [changeMemberId, changeMemberIdSet] = useState('');//更换专家id + const [changeBtn, changeBtnSet] = useState(true);//更换按钮显隐 + const [formMem] = Form.useForm(); + function reset() {//重置 + categorySet([]); + luruSet(0); + updateKeyMemSet(-1); + checkBoxsSet([]); + changeMemberIdSet(''); + setCheckedList([]); + form.resetFields(); + } + const columnsMember: ProColumns[] = [//成员管理页面表格 + { title: '序号', valueType: 'index', width: 50, }, + { title: '专家姓名', dataIndex: 'name', }, + { title: '手机号码', dataIndex: 'mobile', }, + { title: '证件号码', dataIndex: 'certificate', }, + { title: '工作单位', dataIndex: 'workunit', }, + // { title: '通知状态', dataIndex: 'status', }, + // { title: '通知结果备注', dataIndex: 'remark', }, + // { + // title: '照片', + // dataIndex: 'faceId', + // render: (_, record) => { + // if (record.faceId) { + // return { + return ( + <> + + { confirmMem(record); }} + okText="确定" + cancelText="取消" + > + + + + + + + ); + } + }, + ]; + function returnType(inId: any) {//修改时根据record.categoryId判断类别 + category != undefined ? category.map((item: any,) => { + if (item.id == inId) { + if (item.category == 1) { + luruSet(1); + } else if (item.category == 2 && item.subCategory == 1) { + luruSet(2); + } else if (item.category == 2 && item.subCategory == 2) { + luruSet(3); + } else if (item.category == 2 && item.subCategory == 3) { + luruSet(4); + } else if (item.category == 2 && item.subCategory == 4) { + luruSet(5); + } + } + }) : null; + } + function returnCate(luru: any) {//取data + switch (luru) { + case 1: return daibiao; + case 2: return jishu; + case 3: return shangwu; + case 4: return falv; + case 5: return qita; + default: break; + } + } + function dataSet(data: any, luru: any) {//塞data + let dataT = []; + switch (luru) { + case 1: dataT = daibiao; dataT.juryMemberList = data; daibiaoSet(dataT); break; + case 2: dataT = jishu; dataT.juryMemberList = data; jishuSet(dataT); break; + case 3: dataT = shangwu; dataT.juryMemberList = data; shangwuSet(dataT); break; + case 4: dataT = falv; dataT.juryMemberList = data; falvSet(dataT); break; + case 5: dataT = qita; dataT.juryMemberList = data; qitaSet(dataT); break; + default: break; + } + } + function returnHeader(name: any) { + return ( +

{name}

+ ) + } + function returnCheckBox(type: any) {//更改选人 + return ( + <> + {type != undefined ? + type.map((item: any) => { + return ( + { + let data = [...checkBoxs]; + let status = { ...checkBoxsStatus }; + if (e.target.checked) { + data.push({ memberId: item.id }); + status[item.id] = true; + } else { + data.map((item: any, index: any) => { + item.memberId == e.target.value ? data.splice(index, 1) : null; + }) + status[item.id] = false; + } + checkBoxsStatusSet(status); + checkBoxsSet(data); + }}>{item.name} + ) + }) : null + } + + ) + } + useEffect(() => {//拆类别 + daibiaoSet({}); + jishuSet({}); + shangwuSet({}); + falvSet({}); + qitaSet({}); + category.map((item: any) => { + if (item.category == 1) { + daibiaoSet(item); + } else { + if (item.subCategory == 1) { + jishuSet(item); + } else if (item.subCategory == 2) { + shangwuSet(item); + } else if (item.subCategory == 3) { + falvSet(item); + } else if (item.subCategory == 4) { + qitaSet(item); + } + } + }); + }, [memberCount]); + async function queryOpenStatus(id: any) {//查是否开启评标 id:评委会id + await roomStatus(id).then((res) => { + if (res.data) { + openSet(res.data.anyOpenRoom); + allEndSet(res.data.allEndRoom); + } + }) + } + const returnPanel = () => {//返回手风琴 + return ( + <> + {daibiao.juryMemberList != undefined ? + + [ + + ]} + /> + + : null} + {jishu.juryMemberList != undefined ? + + [ + + ]} + /> + + : null} + {shangwu.juryMemberList != undefined ? + + [ + + ]} + /> + + : null} + {falv.juryMemberList != undefined ? + + [ + + ]} + /> + + : null} + {qita.juryMemberList != undefined ? + + [ + // + ]} + /> + + : null} + + ) + } + function checkRe(data: any) {//查重 + let pass = true; + !checkReRoot(daibiao, data, 1) ? pass = false : null; + !checkReRoot(jishu, data, 2) ? pass = false : null; + !checkReRoot(shangwu, data, 3) ? pass = false : null; + !checkReRoot(falv, data, 4) ? pass = false : null; + !checkReRoot(qita, data, 5) ? pass = false : null; + return pass; + } + function checkReRoot(type: any, data: any, updateType: any) {//查重 + const { certificate, mobile, name } = data; + let pass = true; + if (certificate == '' || mobile == '' || name == '' || certificate == undefined || mobile == undefined || name == undefined) { + pass = false; + } else { + if (type.juryMemberList != undefined && updateType != luru) { + for (const item of type.juryMemberList) { + if (item.certificate == certificate) {//身份证号重复 + pass = false; + message.error('身份证号重复'); + break; + } + if (item.mobile == mobile) {//手机号重复 + pass = false; + message.error('手机号重复'); + break; + } + } + } else if (type.juryMemberList != undefined && updateType == luru) { + for (const item of type.juryMemberList) { + if (item.certificate == certificate && item.key != updateKeyMem) {//身份证号重复 + pass = false; + message.error('身份证号重复'); + break; + } + if (item.mobile == mobile && item.key != updateKeyMem) {//手机号重复 + pass = false; + message.error('手机号重复'); + break; + } + } + } + } + + return pass; + } + const returnDrawerMem = () => {//成员管理抽屉(专家信息)添加、修改 + return ( + <> + { + setAdd(false); + changeBtnSet(true); + // formMem.resetFields(); + }} + visible={add} + getContainer={false} + style={{ position: 'absolute' }} + > +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + ) + } + const returnDrawerChange = () => {//更换专家抽屉 + return ( + <> + changeManSet(false)} + visible={changeMan} + getContainer={false} + style={{ position: 'absolute' }} + footer={
+    + +
} + > + {daibiao.juryMemberList != undefined ? <> + {returnHeader('直接录入专家')} + {returnCheckBox(daibiao.juryMemberList)} + : null} + {jishu.juryMemberList != undefined ? <> + {returnHeader('技术类专家')} + {returnCheckBox(jishu.juryMemberList)} + : null} + {shangwu.juryMemberList != undefined ? <> + {returnHeader('商务类专家')} + {returnCheckBox(shangwu.juryMemberList)} + : null} + {falv.juryMemberList != undefined ? <> + {returnHeader('法律类专家')} + {returnCheckBox(falv.juryMemberList)} + : null} + {qita.juryMemberList != undefined ? <> + {returnHeader('抽取专家')} + {returnCheckBox(qita.juryMemberList)} + : null} +

取消原因: +