This commit is contained in:
32503
2025-07-11 13:54:45 +08:00
77 changed files with 7089 additions and 568 deletions

View File

@ -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") {//供应商

View File

@ -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;
}
}
}

View File

@ -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<string>('');
const [captchaToken, setCaptchaToken] = useState<string>('');
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 (
<div className={styles.captchaContainer}>
<Input
name='captcha'
value={value?.captcha}
onChange={(e) => onChange?.({ captcha: e.target.value, captchaToken: captchaToken })}
placeholder={placeholder}
maxLength={4}
prefix={<SafetyOutlined style={{ color: '#bfbfbf' }} />}
suffix={
<div className={styles.captchaWrapper}>
{loading ? <Spin size="small" /> : <img src={imgUrl} alt="验证码" className={styles.captchaImage} onClick={fetchCaptcha} />}
</div>
}
/>
</div>
);
});
CaptchaInput.displayName = 'CaptchaInput';
export default CaptchaInput;

View File

@ -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<any>([]);
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 = (
<Menu style={{ top: "17px" }}>
{data?.authorityList != undefined ?
data?.authorityList?.map((item: any, index: any) => (
<Menu.Item key={index}>
data?.authorityList?.map((item: any) => (
<Menu.Item key={item.roleId}>
<a target="_blank" rel="noopener noreferrer" onClick={() => handelRole(item)}>{item.roleName}</a>
</Menu.Item>
)) : null}
<>
{/* <>
<Menu.Divider />
<Menu.Item key="exit">
<a key="1" onClick={() => toLogout()}>退出登录</a>
</Menu.Item>
</>
</> */}
</Menu>
);
@ -89,21 +100,35 @@ const GlobalHeaderRight: React.FC<{}> = (props) => {
return (
<div className="top-menu">
<div className="left-logo">
<img src={logo} alt="" />
<div className="logo-container" style={{ display: 'flex', alignItems: 'center' }}>
<div className="logo-img">
<img src={logo} alt="" />
</div>
<div className="logo-text" style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '0' }}>
<span style={{ lineHeight: '1', fontSize: '24px' }}></span>
<span style={{ lineHeight: '1', fontSize: '14px', fontWeight: 'normal' }}>CHINA COSCO SHIPPING CORPORATION LIMITED</span>
</div>
</div>
</div>
<ul className="right-btns">
<li><ImportOutlined /><a onClick={() => { urlRef.current && window.open(urlRef.current); }}>2.0</a></li>
<li><HomeOutlined /><a onClick={() => history.push('/Dashboard')}></a></li>
<li><CarryOutOutlined />{moment().format("YYYY-MM-DD")}</li>
{data?.organizationName == null ? null : (<li><UserSwitchOutlined />{data?.organizationName}</li>)}
{/* <li><ImportOutlined /><a onClick={() => { urlRef.current && window.open(urlRef.current); }}>交易平台2.0</a></li> */}
<li>
<Avatar size="small" src="https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png" style={{ width: '30px' }} />
<Avatar size="small" src={userIcon} style={{ width: '30px' }} />
<Dropdown overlay={droMenu}>
<a className="antd-dropdown-link" style={{ color: "#fff" }}>
<a className="antd-dropdown-link" style={{ color: "#fff", verticalAlign: 'middle' }}>
{data?.fullName} <DownOutlined />
</a>
</Dropdown>
</li>
<li>
<img src={homeIcon} style={{width: 22, cursor: 'pointer'}} alt="dashboard" onClick={() => history.push('/Dashboard')}/>
</li>
<li>
<img src={shutdownIcon} style={{width: 20, cursor: 'pointer'}} alt="shutdown" onClick={() => toLogout()}/>
</li>
{/* <li><CarryOutOutlined />{moment().format("YYYY-MM-DD")}</li> */}
{/* {data?.organizationName == null ? null : (<li><UserSwitchOutlined />{data?.organizationName}</li>)} */}
</ul>

View File

@ -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;
}
}
}

View File

@ -22,3 +22,9 @@ export async function getLogout() { // 退出登录,注销
// params
});
}
export async function logout() {
return request('/api/v1/login/logout', {
method: 'post',
});
}