|
@@ -1,85 +1,137 @@
|
|
|
-import React, { useEffect, useMemo, useState } from 'react';
|
|
|
+import React, { CSSProperties, useEffect, useMemo, useState } from 'react';
|
|
|
import { queryUserListByRoleID, queryLeader } from '@/services/boom';
|
|
|
import { connect } from 'umi';
|
|
|
-import { PlusOutlined } from '@ant-design/icons';
|
|
|
+import { CheckOutlined, PlusOutlined } from '@ant-design/icons';
|
|
|
import { Popover, Radio, RadioChangeEvent, Spin, Steps } from 'antd';
|
|
|
import { useModel, useRequest } from '@umijs/max';
|
|
|
|
|
|
const { Step } = Steps;
|
|
|
|
|
|
-enum TYPE {
|
|
|
- ROLE = 'role',
|
|
|
- USER = 'user',
|
|
|
- LEADER = 'leader',
|
|
|
+const TYPE = {
|
|
|
+ ROLE: 'role',
|
|
|
+ USER: 'user',
|
|
|
+ LEADER: 'leader',
|
|
|
+} as const;
|
|
|
+
|
|
|
+interface AuditNode {
|
|
|
+ is_cc: 0 | 1;
|
|
|
+ seq: number;
|
|
|
+ type: (typeof TYPE)[keyof typeof TYPE];
|
|
|
+ value: number[];
|
|
|
+ checkValue: [];
|
|
|
}
|
|
|
|
|
|
const ApprovalProcess = (props: any) => {
|
|
|
const {
|
|
|
approvalProcess,
|
|
|
- leaderData,
|
|
|
+ leaderData = [],
|
|
|
dispatch,
|
|
|
onChange,
|
|
|
roleList = [],
|
|
|
} = props;
|
|
|
- const [selectUserList, setSelectUserList] = useState([]);
|
|
|
- const [curNodeIdx, setCurNodeIdx] = useState(-1);
|
|
|
- const [loading, setLoading] = useState(false);
|
|
|
const { userList, run } = useModel('userList');
|
|
|
+ const [checkValue, setCheckValue] = useState<number[]>([]);
|
|
|
|
|
|
- const list = useMemo(() => {
|
|
|
- approvalProcess
|
|
|
- ?.filter((item: any) => item)
|
|
|
- .forEach((item: any) => {
|
|
|
- if (item.length > 1 && item[0].type == TYPE.USER) {
|
|
|
- item.forEach((curUser: any) => {
|
|
|
- curUser.name =
|
|
|
- userList?.find((user: any) => user.ID == curUser.value)?.CName ||
|
|
|
- '-';
|
|
|
- });
|
|
|
- } else if (item.length == 1 && item[0].type == TYPE.USER) {
|
|
|
- item[0].name =
|
|
|
- userList?.find((user: any) => user.ID == item[0].value)?.CName ||
|
|
|
- '-';
|
|
|
- } else if (item.length == 1 && item[0].nowType == TYPE.USER) {
|
|
|
- item[0].name =
|
|
|
- userList?.find((user: any) => user.ID == item[0].nowValue)?.CName ||
|
|
|
- '-';
|
|
|
- } else {
|
|
|
- item[0].name = null;
|
|
|
- }
|
|
|
- });
|
|
|
- return approvalProcess?.filter((item: any) => item);
|
|
|
+ const { auditList, ccList } = useMemo<{
|
|
|
+ auditList: AuditNode[];
|
|
|
+ ccList: AuditNode[];
|
|
|
+ }>(() => {
|
|
|
+ let auditList: AuditNode[] = [],
|
|
|
+ ccList: AuditNode[] = [];
|
|
|
+ approvalProcess.forEach((item: any, index: number) => {
|
|
|
+ if (!item) return;
|
|
|
+ let node: AuditNode = {
|
|
|
+ is_cc: item[0].is_cc,
|
|
|
+ type: item[0].type,
|
|
|
+ checkValue: [],
|
|
|
+ seq: index,
|
|
|
+ value: item.map((node: any) => node.value),
|
|
|
+ };
|
|
|
+
|
|
|
+ if (node.is_cc == 1) {
|
|
|
+ ccList.push(node);
|
|
|
+ } else {
|
|
|
+ auditList.push(node);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return { auditList, ccList };
|
|
|
}, [approvalProcess]);
|
|
|
|
|
|
- const onStepsChange = async (current: any, list: any) => {
|
|
|
- setLoading(true);
|
|
|
- const itemNode = list[current][0];
|
|
|
- if (itemNode.type !== 'role') return;
|
|
|
- const data = await queryUserListByRoleID({ role_id: itemNode.value });
|
|
|
- setCurNodeIdx(current);
|
|
|
- setSelectUserList(data);
|
|
|
- setLoading(false);
|
|
|
+ const onCheckValue = (value: number, index: number) => {
|
|
|
+ let values = [...checkValue];
|
|
|
+ values[index] = value;
|
|
|
+ setCheckValue(values);
|
|
|
+ onChange(values);
|
|
|
};
|
|
|
|
|
|
- const selectedUserId = ({ target: { value } }: RadioChangeEvent) => {
|
|
|
- //userId
|
|
|
- const name = userList?.find((user: any) => user.ID == value)?.CName || '-';
|
|
|
- const data = { nowType: TYPE.USER, nowValue: Number(value), name }; //type: TYPE.USER, value: Number(value)
|
|
|
- list[curNodeIdx][0] = { ...list[curNodeIdx][0], ...data };
|
|
|
- console.log([...list]);
|
|
|
- onChange?.([...list]);
|
|
|
+ useEffect(() => {
|
|
|
+ dispatch({
|
|
|
+ type: 'user/getRoleList',
|
|
|
+ });
|
|
|
+ run();
|
|
|
+ }, []);
|
|
|
+ const rowStyle: CSSProperties = {
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'column',
|
|
|
+ fontSize: 16,
|
|
|
};
|
|
|
|
|
|
- const content = (
|
|
|
- <Spin spinning={loading}>
|
|
|
- <Radio.Group onChange={selectedUserId}>
|
|
|
- {selectUserList.map((item: any) => (
|
|
|
- // <Button onClick={() => selectedUserId(item.user_id)}>{item.c_name}</Button>
|
|
|
- <Radio.Button value={item.user_id}>{item.c_name}</Radio.Button>
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div style={rowStyle}>
|
|
|
+ {auditList.map((item: AuditNode, index: number) => (
|
|
|
+ <AuditNodeStep
|
|
|
+ key={`${item.type}-${item.value.join('.')}-${index}`}
|
|
|
+ leaderData={leaderData}
|
|
|
+ item={item}
|
|
|
+ roleList={roleList}
|
|
|
+ userList={userList}
|
|
|
+ value={checkValue[item.seq]}
|
|
|
+ onChange={(value: number) => onCheckValue(value, item.seq)}
|
|
|
+ />
|
|
|
))}
|
|
|
- </Radio.Group>
|
|
|
- </Spin>
|
|
|
+ </div>
|
|
|
+ {ccList.length > 0 && (
|
|
|
+ <div style={rowStyle}>
|
|
|
+ <h3 style={{ margin: "20px 0", fontWeight: 'bold' }}>抄送人</h3>
|
|
|
+ {ccList.map((item: AuditNode, index: number) => (
|
|
|
+ <AuditNodeStep
|
|
|
+ key={`${item.type}-${item.value.join('.')}-${index}`}
|
|
|
+ leaderData={leaderData}
|
|
|
+ item={item}
|
|
|
+ roleList={roleList}
|
|
|
+ userList={userList}
|
|
|
+ value={checkValue[item.seq]}
|
|
|
+ onChange={(value: number) => onCheckValue(value, item.seq)}
|
|
|
+ />
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
);
|
|
|
+};
|
|
|
+
|
|
|
+interface AuditNodeStepProps {
|
|
|
+ item: AuditNode;
|
|
|
+ leaderData: any;
|
|
|
+ roleList: any;
|
|
|
+ userList: any;
|
|
|
+ value: number;
|
|
|
+ onChange: (value: number) => void;
|
|
|
+}
|
|
|
+
|
|
|
+const AuditNodeStep = (props: AuditNodeStepProps) => {
|
|
|
+ const {
|
|
|
+ item,
|
|
|
+ leaderData,
|
|
|
+ roleList = [],
|
|
|
+ userList = [],
|
|
|
+ value,
|
|
|
+ onChange,
|
|
|
+ } = props;
|
|
|
+
|
|
|
+ const [selectUserList, setSelectUserList] = useState([]);
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const getLeaderContent = (length: any) => (
|
|
|
<Steps
|
|
@@ -92,67 +144,84 @@ const ApprovalProcess = (props: any) => {
|
|
|
></Steps>
|
|
|
);
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- dispatch({
|
|
|
- type: 'user/getRoleList',
|
|
|
- });
|
|
|
- run();
|
|
|
- }, []);
|
|
|
+ const handleOpen = async () => {
|
|
|
+ setLoading(true);
|
|
|
+ if (item.type !== 'role') return;
|
|
|
+ const data = await queryUserListByRoleID({ role_id: item.value[0] });
|
|
|
+ setSelectUserList(data);
|
|
|
+ setLoading(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const selectedUserId = ({ target: { value } }: RadioChangeEvent) => {
|
|
|
+ onChange(Number(value));
|
|
|
+ };
|
|
|
+
|
|
|
+ const content = (
|
|
|
+ <Spin spinning={loading}>
|
|
|
+ <Radio.Group onChange={selectedUserId} value={value}>
|
|
|
+ {selectUserList.map((item: any) => (
|
|
|
+ <Radio.Button value={Number(item.user_id)}>
|
|
|
+ {item.c_name}
|
|
|
+ </Radio.Button>
|
|
|
+ ))}
|
|
|
+ </Radio.Group>
|
|
|
+ </Spin>
|
|
|
+ );
|
|
|
+
|
|
|
+ if (item.type == TYPE.LEADER) {
|
|
|
+ return (
|
|
|
+ <div style={{ marginBottom: 20 }}>
|
|
|
+ <Popover
|
|
|
+ placement="bottomLeft"
|
|
|
+ title="查看审批人"
|
|
|
+ content={getLeaderContent(item.value[0])}
|
|
|
+ overlayStyle={{ width: '300px' }}
|
|
|
+ >
|
|
|
+ <CheckOutlined style={{ marginRight: 20 }} />
|
|
|
+ {Math.min(item.value[0], leaderData?.length)}级主管审批
|
|
|
+ </Popover>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (item.type == TYPE.ROLE) {
|
|
|
+ let title = '';
|
|
|
+ if (value) {
|
|
|
+ title = userList.find((cur: any) => cur.ID == value)?.CName;
|
|
|
+ } else {
|
|
|
+ const names = item.value.map((id) => {
|
|
|
+ const role = roleList.find((cur: any) => cur.ID == id);
|
|
|
+ return role?.Name;
|
|
|
+ });
|
|
|
+ title = `从${names.join('、')}选择`;
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ <div style={{ marginBottom: 20, cursor: 'pointer' }}>
|
|
|
+ <Popover
|
|
|
+ placement="bottomLeft"
|
|
|
+ title={'选择审批人'}
|
|
|
+ content={content}
|
|
|
+ trigger="click"
|
|
|
+ overlayStyle={{ width: '300px' }}
|
|
|
+ onOpenChange={handleOpen}
|
|
|
+ style={{ marginBottom: 20 }}
|
|
|
+ >
|
|
|
+ <PlusOutlined style={{ marginRight: 20 }} /> {title}
|
|
|
+ </Popover>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ const names = item.value.map((id) => {
|
|
|
+ const user = userList.find((cur: any) => cur.ID == id);
|
|
|
+ return user?.CName;
|
|
|
+ });
|
|
|
|
|
|
return (
|
|
|
- <>
|
|
|
- <Steps
|
|
|
- current={-1}
|
|
|
- direction="vertical"
|
|
|
- onChange={(value) => onStepsChange(value, list)}
|
|
|
- >
|
|
|
- {list?.map((item: any, index: Number) =>
|
|
|
- item[0]?.type == TYPE.LEADER ? (
|
|
|
- <Step
|
|
|
- key={String(index)}
|
|
|
- icon={
|
|
|
- <Popover
|
|
|
- placement="bottomLeft"
|
|
|
- title="查看审批人"
|
|
|
- content={getLeaderContent(item[0]?.value)}
|
|
|
- overlayStyle={{ width: '300px' }}
|
|
|
- >
|
|
|
- <PlusOutlined />
|
|
|
- </Popover>
|
|
|
- }
|
|
|
- title={`${Math.min(
|
|
|
- item[0]?.value,
|
|
|
- leaderData?.length,
|
|
|
- )}级主管审批`}
|
|
|
- />
|
|
|
- ) : (
|
|
|
- <Step
|
|
|
- key={String(index)}
|
|
|
- icon={
|
|
|
- <Popover
|
|
|
- placement="bottomLeft"
|
|
|
- title={'选择审批人'}
|
|
|
- content={content}
|
|
|
- trigger="click"
|
|
|
- overlayStyle={{ width: '300px' }}
|
|
|
- >
|
|
|
- <PlusOutlined />
|
|
|
- </Popover>
|
|
|
- }
|
|
|
- title={
|
|
|
- item[0]?.name ||
|
|
|
- `从${
|
|
|
- roleList?.find((cur: any) => cur.ID == item[0]?.value)
|
|
|
- ?.Name || '-'
|
|
|
- }选择`
|
|
|
- }
|
|
|
- />
|
|
|
- ),
|
|
|
- )}
|
|
|
- </Steps>
|
|
|
- </>
|
|
|
+ <div style={{ marginBottom: 20 }}>
|
|
|
+ <CheckOutlined style={{ marginRight: 20 }} /> {names.join('、')}
|
|
|
+ </div>
|
|
|
);
|
|
|
};
|
|
|
+
|
|
|
export default connect(({ user }: any) => ({
|
|
|
roleList: user.roleList,
|
|
|
}))(ApprovalProcess);
|