Files
fe_service_ebtp_frontend/src/components/LayLeftMenu/index.tsx

628 lines
22 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { history } from 'umi';
import {
getLeftMenu,
getBtnText,
nextNode,
getLeader,
finishTurn,
openTurn,
getGys,
finishFlow,
getOfferUserId,
getSingIds,
firstNextNode,
queryGys
} from './service';
import { Menu, Button, Modal, message, Spin, Transfer, Tooltip, Tag, Select } from 'antd';
import { getRoomId, getSessionUserData, getSessionRoleData } from '@/utils/session';
import './index.less';
import { CarryOutOutlined, DownOutlined, ExclamationCircleOutlined, ReloadOutlined } from '@ant-design/icons';
import { btnAuthority } from '@/utils/authority';
//评审室内流程菜单
const Index: React.FC<{}> = () => {
const { confirm } = Modal;
const { SubMenu } = Menu;
const [data, setData] = React.useState<any>([]);
const [spin, spinSet] = useState<boolean>(false);
const [leader, setLeader] = useState('');
const [nodeId, nodeIdSet] = useState('');//节点id
const [turnId, turnIdSet] = useState('');//轮次id
const [btnText, btnTextSet] = useState(''); //按钮文字
const [firstNextStep, firstNextStepSet] = useState(false); //是否轮次第一个节点
const [instTurnName, instTurnNameSet] = useState(''); //第几轮
const [btnMes, btnMesSet] = useState('');
const [flowFinish, flowFinishSet] = useState<boolean>(false); //流程是否结束
const [stop, stopSet] = useState<boolean>(false); //终止流程 按钮显隐
const [finishAllTurn, finishAllTurnSet] = useState<boolean>(false); //所有轮次是否结束
const [menuShow, menuShowSet] = useState<string[]>([]);
const [count, countSet] = useState<any>(0); //触发useEffect
const [chooseGys, chooseGysSet] = useState<any>(false); //选择供应商
const [offerUserId, offerUserIdSet] = useState<any>(''); //评审专家id
const [singUserId, singUserIdSet] = useState<any>([]); //评审专家id
const userId = getSessionUserData().userId;
const role = getSessionRoleData().roleCode;
//获取比选一阶段二次项目,自定义流程,当前供应商
const isBxOneSecondCustom = sessionStorage.getItem("isBxOneSecondCustom");
function showConfirm(mes?: any, confirmFlag?: boolean) {
//环节流转提示
mes == '是否开启' ? (mes = mes + instTurnName + '') : mes;
confirm({
title: mes,
icon: <ExclamationCircleOutlined />,
centered: true,
okText: '确定',
cancelText: '取消',
async onOk() {
await handleOk(confirmFlag);
},
onCancel() {
spinSet(false);
},
});
}
function overConfirm(mes?: any) {
//结束流程提示
confirm({
title: mes,
icon: <ExclamationCircleOutlined />,
okText: '确定',
cancelText: '取消',
centered: true,
async onOk() {
await finishFlowFc();
},
onCancel() {
spinSet(false);
},
});
}
const handleOk = async (confirmFlag?: boolean) => {
if (btnText == '开启') {
await getGysData();
}
if (btnText == '结束轮次') {
await finishTurnFc(confirmFlag);
}
if (btnText == '下一步') {
await nextStep(confirmFlag);
}
return;
};
//下一步方法
async function nextStep(confirmFlag?: boolean) {
spinSet(true);
if (firstNextStep) {
await firstNextNode(turnId, confirmFlag).then((res: any) => {
if (res.code === 200) {
if (res.data.result) {
message.success('成功进入下一节点');
countSet(count + 1);
} else {
if (res.data.confirmFlag) {
showConfirm(res.data.message, true);
}
}
} else {
countSet(count + 1);
}
});
} else {
await nextNode(nodeId, confirmFlag).then((res) => {
if (res.code === 200) {
if (res.data.result) {
message.success('成功进入下一节点');
countSet(count + 1);
} else {
if (res.data.confirmFlag) {
showConfirm(res.data.message, true);
}
}
} else {
countSet(count + 1);
}
});
}
}
//开启轮次方法
async function openTurnFc() {
spinSet(true);
await openTurn({ assessRoomId: getRoomId(), roundIdList: targetKeys }).then((res) => {
if (res.code === 200) {
message.success('开启轮次成功');
chooseGysSet(false);
}
});
countSet(count + 1); //触发useEffect
}
//结束轮次方法
async function finishTurnFc(confirmFlag?: boolean) {
spinSet(true);
await finishTurn(turnId, confirmFlag).then((res) => {
if (res.code === 200) {
if (res.data.result) {
message.success('结束轮次成功');
countSet(count + 1); //触发useEffect
} else {
if (res.data.confirmFlag) {
showConfirm(res.data.message, true);
}
}
} else {
countSet(count + 1); //触发useEffect
}
});
}
//结束流程方法
async function finishFlowFc() {
spinSet(true);
await finishFlow(getRoomId()).then((res) => {
if (res.code === 200) {
message.success('结束流程成功');
}
});
countSet(count + 1); //触发useEffect
}
//取数据
async function getData(leader?: any, offerUserId?: any, ids?: any) {
let nowTurn: string[] = [];
let name: any = '';
let indexT: any = 0;
let url = '';
let nodeIdT = '';
let turnIdT = '';
spinSet(true);
await getLeftMenu(getRoomId()).then((res) => {
if (res.code == 200) {
res.data.map((item: any, index: any) => {
//跳转当前节点页面
if (item.status == 1) {
turnIdT = item.id;
}
item.nodeVOList.map((item: any) => {
if (item.status == 1 && item.moduleUrl != null) {
nodeIdT = item.id;
url =
makeUrl(item.moduleUrl, leader) +
`?turnId=${item.instTurnId}&nodeId=${item.id}&turnSort=${item.instTurnSort}`;
if (item.moduleUrl === '/EvaRoom/Eva/BidOffer' && userId != offerUserId) {
//报价评审 只有评审分工分到的专家能点
url = '';
}
if (item.moduleUrl === '/EvaRoom/Eva/Sing' || item.moduleUrl === '/EvaRoom/Eva/Openning') {
//唱价(询价)、唱价 只有可查看报价的专家可看
if (role == 'ebtp-expert' && ids.findIndex((item: any) => item == userId) == -1) {
url = '';
}
}
}
});
if (item.status == 1) {
nowTurn.push(`${item.instTurnSort}SubMenu`);
}
//获取要开启的轮次名
if (item.status == 2) {
indexT = index + 1;
}
if (index == indexT) {
name = item.instTurnName;
}
});
menuShowSet(nowTurn);
setData(res.data);
nodeIdSet(nodeIdT);
turnIdSet(turnIdT);
instTurnNameSet(name);
} else {
message.info('请联系管理员');
}
});
//取按钮
await getBtnText(getRoomId()).then((res) => {
let btntxt = '';
let btnMesT = '';
let flowFinishT = false;
let stopT = true;
let finishAllTurnT = false;
if (res.code == 200) {
if (res.data.openTurnButton) {
btntxt = '开启';
btnMesT = '是否开启';
stopT = false;
} else if (res.data.finishTurnButton) {
btntxt = '结束轮次';
btnMesT = '是否结束轮次?';
} else if (res.data.firstNextStepButton) {
btntxt = '下一步';
btnMesT = '是否进入下一环节?';
} else if (res.data.nextStepButton) {
btntxt = '下一步';
btnMesT = '是否进入下一环节?';
}
if (res.data.flowFinish) {
flowFinishT = true;
}
if (res.data.finishAllTurn) {
finishAllTurnT = true;
stopT = false;
}
}
btnTextSet(btntxt);
btnMesSet(btnMesT);
firstNextStepSet(res?.data?.firstNextStepButton);
flowFinishSet(flowFinishT);
finishAllTurnSet(finishAllTurnT);
stopSet(stopT);
});
spinSet(false);
url != '' && history.push(url);
}
//专家获取数据
async function expertGetData(ids: any) {
let leader = '';
let offerUserId = '';
await getLeader(getRoomId(), getSessionUserData().userId).then((res) => {
if (res.code == 200) {
leader = res.data;
setLeader(res.data);
}
});
await getOfferUserId(getRoomId()).then((res) => {
if (res.code == 200) {
offerUserId = res.data[0];
offerUserIdSet(res.data[0]);
}
});
getData(leader, offerUserId, ids);
}
//处理url
function makeUrl(url: any, leader: any) {
if (
url == '/EvaRoom/Eva/BidPreliminary' ||
url == '/EvaRoom/Eva/BidDetailed' ||
url == '/EvaRoom/Eva/BidOffer' ||
url == '/EvaRoom/Eva/BidNumber'
) {
url = url + leader;
}
return url;
}
//初始化
useEffect(() => {
spinSet(true);
let ids: any;
if (getSessionRoleData().roleCode === 'ebtp-expert') {
//ebtp-expert
//可查看报价专家ids
getSingIds(getRoomId()).then((res: any) => {
if (res.code == 200) {
ids = res.data;
singUserIdSet(res.data);
}
}).then(() => {
expertGetData(ids);
})
} else {
getData();
}
}, [count]);
//选择供应商
const [gysData, gysDataSet] = useState<any>([]);
const [firstRvwScs, firstRvwScsSet] = useState<any>([]);//初审合格的
const [firstRvwFail, firstRvwFailSet] = useState<any>([]);//初审不合格的
const [targetKeys, setTargetKeys] = useState<any>([]);
const [firstRvw, firstRvwSet] = useState<any>(false);//是否经历初审 控制显示合格不合格数量显隐
const [targetCount, targetCountSet] = useState<any>({ scsCount: 0, failCount: 0 });//进入下一轮的 合格的数量 不合格的数量
const [selectedKeys, setSelectedKeys] = useState<any>([]);
const [selectedKeysTransfer, setSelectedKeysTransfer] = useState<any>([]);//穿梭框用
const [chooseTurn, chooseTurnSet] = useState<boolean>(false);//查看供应商选择情况vis
const modalHeight = (window.innerHeight * 96) / 100;
const onChange = (nextTargetKeys: any, direction: any, moveKeys: any) => {
if (chooseTurn) return;
setTargetKeys(nextTargetKeys);
//遍历移动的数据 控制合格不合格显示数量
if (firstRvw) {
let scsChange: number = 0;
let failChange: number = 0;
moveKeys.map((item: any) => {
firstRvwScs.includes(item) && scsChange++;
firstRvwFail.includes(item) && failChange++;
});
if (direction === 'left') {
targetCountSet({ scsCount: targetCount.scsCount - scsChange, failCount: targetCount.failCount - failChange })
} else {
targetCountSet({ scsCount: targetCount.scsCount + scsChange, failCount: targetCount.failCount + failChange })
}
}
};
const onSelectChange = (sourceSelectedKeys: any, targetSelectedKeys: any) => {
if (chooseTurn) return;
setSelectedKeysTransfer([...sourceSelectedKeys, ...targetSelectedKeys]);
};
//取当前轮次所有供应商
async function getGysData() {
let dataT: any = [];
let _scs: any = [];
let _fail: any = [];
let target: any = [];
let firstRvw = false;//是否经历初审
await getGys(getRoomId()).then((res) => {
if (res.code == 200) {
res.data.map((item: any, index: number) => {
let one = {
key: item.id,
title: item.companyName,
firstRvwResult: item.firstRvwResult,//0 未通过 1通过 2没经历初审
}
dataT.push(one);
item.firstRvwResult === 0 && _fail.push(one.key);//按类别存key
item.firstRvwResult === 1 && _scs.push(one.key);
item.firstRvwResult !== 0 && target.push(item.id);//右侧数据
index === 1 && item.firstRvwResult < 2 && (firstRvw = true);//是否经历初审
});
}
});
gysDataSet(dataT);
setTargetKeys(target);
firstRvwScsSet(_scs);
firstRvwFailSet(_fail);
firstRvwSet(firstRvw);
targetCountSet({ scsCount: target.length, failCount: 0 })
chooseGysSet(true);
countSet(count + 1); //触发useEffect
}
const { Option } = Select;
function returnGysModal() {
const select = <Select
style={{ width: 100 }}
placeholder={'请选择'}
onChange={async (value: any) => {
spinSet(true);
let thisTurnId = data[value].id;
let preTurnId = data[value - 1].id;
await queryGys(thisTurnId, preTurnId).then((res) => {
if (res?.code == 200) {
let all = [...res?.data[thisTurnId], ...res?.data[preTurnId]]
let target: any[] = [];
res?.data[thisTurnId].map((i: { key: any; }) => {
target.push(i.key)
})
gysDataSet(all);//穿梭框数据源
setTargetKeys(target);//穿梭框右侧数据 keys
targetCountSet({ scsCount: target.length, failCount: 0 })
}
}).finally(() => spinSet(false))
}}
>
{
data?.map((i: any, index: any) => {
if (index == 0 || i.status === 3) return;//1:进行中2:已结束3:未开启
return <Option key={i.id + 'option'} value={index}>{i.instTurnName}</Option>
})
}
</Select >
const footer = chooseTurn ? { footer: <Button type='primary' onClick={() => closeFc()}></Button> } : {};
const closeFc = async () => {
chooseGysSet(false);
chooseTurnSet(false);
gysDataSet([]);
firstRvwSet(false);
}
return (
<Modal
visible={chooseGys}
centered
width={1200}
style={{ maxHeight: modalHeight }}
destroyOnClose
{...footer}
okButtonProps={{ disabled: spin }}
bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto' }}
title={chooseTurn ? '查看已开启轮次所选供应商' : '选择进入下一轮次的供应商'}
onCancel={() => closeFc()}
onOk={() => {
if (chooseTurn) {
closeFc();
return
}
if (targetKeys.length > 0) {
openTurnFc();
} else {
message.error('未选中供应商');
}
}}
>
<Spin spinning={spin}>
{
chooseTurn ?
<div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 16 }}>&nbsp;{select}&nbsp;</div>
:
<p style={{ fontSize: 16, fontWeight: 'bold' }}></p>
}
<Transfer
dataSource={gysData}
listStyle={{ width: '50%', height: 400 }}
titles={[chooseTurn ? '未进入所选轮次的供应商' : '可选供应商(不进入下一轮)', chooseTurn ? '已进入所选轮次的供应商' : '进入下一轮供应商']}
targetKeys={targetKeys}
selectedKeys={selectedKeysTransfer}
onChange={onChange}
onSelectChange={onSelectChange}
disabled={isBxOneSecondCustom == "1"}
selectAllLabels={[, (info: { selectedCount: number, totalCount: number }) => <>
{
info.selectedCount != 0 && `${info.selectedCount}/`
}
{info.totalCount}&nbsp;&nbsp;&nbsp;
{firstRvw &&
<>
{targetCount.scsCount > 0 &&
<><Tag color="success"></Tag>{targetCount.scsCount} &nbsp;&nbsp;</>
}
{targetCount.failCount > 0 &&
<><Tag color="error"></Tag>{targetCount.failCount} </>
}
</>
}
</>]}
render={(item: any) => {
return (
<>
{item.firstRvwResult === 1 && <Tag color="success"></Tag>}
{item.firstRvwResult === 0 && <Tag color="error"></Tag>}
{item.title}
</>
)
}}
/>
</Spin>
</Modal>
);
}
function onOpenChange(openKeys: any) {
menuShowSet([openKeys[openKeys.length - 1]]);
}
function onSelect({ selectedKeys }: any) {
setSelectedKeys(selectedKeys);
}
return (
<>
<div className="myselfContent xsy-menu-style" style={{ height: innerHeight - 106 }}>
<Spin spinning={spin} wrapperClassName="xsy-spin">
<div>
<Tooltip placement="top" title={'刷新流程'}>
<a
style={{ float: 'right', marginRight: '10px' }}
onClick={async () => {
spinSet(true);
setSelectedKeys([]);
menuShowSet([]);
await getData();
// await getBtn();
// history.push('/EvaRoom/Eva');
spinSet(false);
}}
>
<ReloadOutlined spin={spin} />
</a>
</Tooltip>
{
data?.length > 1 && <Tooltip placement="top" title={'查看已开启轮次所选供应商'}>
<a
style={{ float: 'right', marginRight: '10px' }}
onClick={async () => {
gysDataSet([]);//穿梭框数据源
setTargetKeys([]);//穿梭框右侧数据 keys
chooseGysSet(true);
chooseTurnSet(true);
}}
>
<CarryOutOutlined />
</a>
</Tooltip>
}
</div>
<div>
<Menu
// defaultSelectedKeys={['1SubMenu']}
openKeys={menuShow}
expandIcon={() => <DownOutlined style={{ fontSize: '10px', fontWeight: 'bolder' }} />}
mode="inline"
onOpenChange={onOpenChange}
selectedKeys={selectedKeys}
onSelect={onSelect}
className="xsy-menu-style"
style={{ height: innerHeight - 325, paddingBottom: '' }}
inlineIndent={58}
>
{data.map((item: any) => (
<SubMenu key={`${item.instTurnSort}SubMenu`} title={item.instTurnName}>
{item.nodeVOList.map((item2: any, index: any) => {
//可查看报价的专家 (唱价节点)
let singDis;
if (item2.moduleUrl === '/EvaRoom/Eva/Sing') {
singDis = item2.moduleUrl === '/EvaRoom/Eva/Sing' && role == 'ebtp-expert' && singUserId.findIndex((item: any) => item == userId) == -1;
}
if (item2.moduleUrl === '/EvaRoom/Eva/Openning') {
singDis = item2.moduleUrl === '/EvaRoom/Eva/Openning' && role == 'ebtp-expert' && singUserId.findIndex((item: any) => item == userId) == -1;
}
//修改跳转地址并加参数 轮次id 节点id 轮次号
let url = makeUrl(item2.moduleUrl, leader) + `?turnId=${item2.instTurnId}&nodeId=${item2.id}&turnSort=${item2.instTurnSort}`;
//报价评审 只有评审分工分到的专家能点
let offerDis = item2.moduleUrl === '/EvaRoom/Eva/BidOffer' && userId != offerUserId;
//是否跳过节点 0-不跳过 1-跳过节点
let skipStatus = item2.skipStatus == 1;
let disabled = item2.status == 3 ||
item2.moduleUrl == null ||
item2.moduleUrl == undefined ||
offerDis ||
singDis ||
skipStatus
return (
<Menu.Item
key={`${item.instTurnSort}${index}MenuItem`}
disabled={disabled}
onClick={() => {
let empty = new Promise(function (resolve, reject) {
if (makeUrl(item2.moduleUrl, leader) === window.location.pathname && !disabled) {
history.push('/EvaRoom/Eva')
}
resolve(true);
});
empty.finally(() => history.push(url));
}}
>
{item2.instNodeName}
</Menu.Item>
);
})}
</SubMenu>
))}
</Menu>
</div>
<div className="xsy-spin-div">
<div>
<Button
type="primary"
hidden={
flowFinish || btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])
}
onClick={() => showConfirm(btnMes, false)}
className="xsy-next-btn"
>
{btnText == '开启' ? btnText + instTurnName : btnText}
</Button>
</div>
<div>
<Button
hidden={
stop ||
flowFinish ||
btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])
}
className="xsy-over-btn"
onClick={() => {
overConfirm('是否要终止流程?');
}}
>
</Button>
</div>
</div>
</Spin>
</div>
{/* 选择供应商 */}
{returnGysModal()}
</>
);
};
export default Index;