Browse Source

OA审批多级主管

XuZinan 2 năm trước cách đây
mục cha
commit
0efb90feb1

+ 37 - 14
src/components/Flow/node/auditNode/index.tsx

@@ -1,13 +1,28 @@
 import React, { useMemo } from 'react';
 AuditServe;
 import AuditServe, { IDTYPE, TYPE } from './mapServe';
-import { connect } from "umi";
+import { connect } from 'umi';
 export { AuditServe };
 
-const CustomRect = props => {
-  const { size = { width: 130, height: 50 }, data, depUserTree, roleList, userList } = props;
+const CustomRect = (props: any) => {
+  const {
+    size = { width: 130, height: 50 },
+    data,
+    depUserTree,
+    roleList,
+    userList,
+  } = props;
   const { width, height } = size;
-  const { label, stroke, fill, fontFill, fontSize, type = 2, initiator, audits } = data;
+  const {
+    label,
+    stroke,
+    fill,
+    fontFill,
+    fontSize,
+    type = 2,
+    initiator,
+    audits,
+  } = data;
 
   const contentText = useMemo(() => {
     let text = '请选择审批人';
@@ -22,14 +37,14 @@ const CustomRect = props => {
         text = '请选择抄送人';
         break;
     }
-    const getName = (id, data) => {
+    const getName: any = (id: any, data: any) => {
       let name = '';
       for (let i = 0; i < data.length; i++) {
         let item = data[i];
         if (item.id == id) {
           return item.title;
         } else if (item.children?.length > 0) {
-          let title = getName(id, item.children);
+          let title: any = getName(id, item.children);
           if (title) return title;
         }
       }
@@ -38,20 +53,26 @@ const CustomRect = props => {
     if (type != TYPE.AUDIT) {
       if (initiator?.length > 0) {
         const list = initiator
-          .map(item => {
+          .map((item: any) => {
             return getName(item.origin, depUserTree);
           })
-          .filter(item => item);
+          .filter((item: any) => item);
         return list.join(',');
       } else {
         return text;
       }
     } else {
       if (audits?.length > 0) {
-        return audits[0].type == IDTYPE.ROLE
-          ? roleList.find(item => item.ID == audits[0].value)?.Name
-          : userList.find(item => item.ID == audits[0].value)?.CName;
-        // return roleList.find(item => item.ID == audits[0].value)?.Name;
+        switch (audits[0].type) {
+          case IDTYPE.ROLE:
+            return roleList.find((item: any) => item.ID == audits[0].value)
+              ?.Name;
+          case IDTYPE.USER:
+            return userList.find((item: any) => item.ID == audits[0].value)
+              ?.CName;
+          case IDTYPE.LEADER:
+            return '部门主管';
+        }
       } else {
         return text;
       }
@@ -91,12 +112,14 @@ const CustomRect = props => {
       </div>
     );
   };
+
   return (
     <div
       style={{
         width,
         height,
-        boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)',
+        boxShadow:
+          '0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)',
       }}
     >
       {titleDom()}
@@ -114,7 +137,7 @@ const CustomRect = props => {
   );
 };
 
-export default connect(({ user }) => ({
+export default connect(({ user }: any) => ({
   depUserTree: user.depUserTree,
   roleList: user.roleList,
   userList: user.list,

+ 143 - 63
src/components/Flow/node/auditNode/mapServe.tsx

@@ -1,10 +1,24 @@
 import React, { useState, useEffect, useMemo } from 'react';
 import { FlowchartFormWrapper } from '@antv/xflow';
-import { Position, Size, ColorPicker, InputNumberField, InputField, SelectField } from '../fields';
+import {
+  Position,
+  Size,
+  ColorPicker,
+  InputNumberField,
+  InputField,
+  SelectField,
+} from '../fields';
 import { PREFIX } from '../constants';
-import { connect } from "umi";
+import { connect } from 'umi';
 import { UnityAction } from '@/utils/utils';
-import { Button, Radio, RadioChangeEvent, Select, TreeSelect } from 'antd';
+import {
+  Button,
+  Radio,
+  RadioChangeEvent,
+  Select,
+  TreeSelect,
+  InputNumber,
+} from 'antd';
 
 const { Option } = Select;
 
@@ -36,15 +50,26 @@ export interface IConfig {
   flow_node_id?: string;
   process_code?: string;
   type: TYPE;
-  initiator: { type: string; value: number; origin?: string | number; name?: string }[];
+  initiator: {
+    type: string;
+    value: number;
+    origin?: string | number;
+    name?: string;
+  }[];
   //审批人目前只支持单选角色或者单选人
-  audits: { type: string; value: number; origin?: string | number; name?: string }[];
+  audits: {
+    type: string;
+    value: number;
+    origin?: string | number;
+    name?: string;
+  }[];
 }
 
 export const enum IDTYPE {
   DEP = 'dep',
   USER = 'user',
   ROLE = 'role',
+  LEADER = 'leader',
 }
 
 const Component = (props: any) => {
@@ -82,16 +107,32 @@ const Component = (props: any) => {
   };
 
   useEffect(() => {
-    const bool = nodeConfig.audits?.some(item => item.type == IDTYPE.USER) ? 0 : 1;
+    let bool = 1;
+    if (nodeConfig.audits?.length > 0)
+      switch (nodeConfig.audits[0].type) {
+        case IDTYPE.USER:
+          bool = 0;
+          break;
+        case IDTYPE.ROLE:
+          bool = 1;
+          break;
+        case IDTYPE.LEADER:
+          bool = 2;
+          break;
+      }
     console.log(bool);
     setIsRole(bool);
   }, []);
   console.log('===================', nodeConfig);
 
   const handleTreeChange = (values: (string | number)[]) => {
-    const newValues = values.map(cur => {
+    const newValues = values.map((cur) => {
       if (typeof cur == 'string' && cur.includes('||')) {
-        return { type: IDTYPE.USER, value: Number(cur.split('||')[0]), origin: cur };
+        return {
+          type: IDTYPE.USER,
+          value: Number(cur.split('||')[0]),
+          origin: cur,
+        };
       } else {
         return { type: IDTYPE.DEP, value: cur, origin: cur };
       }
@@ -99,9 +140,10 @@ const Component = (props: any) => {
     onNodeConfigChange('initiator', newValues);
   };
 
-  const onSave = () => {
-    UnityAction.emit('NODE_SAVE', nodeConfig);
-  };
+  // const onSave = () => {
+  //   UnityAction.emit('NODE_SAVE', nodeConfig);
+  // };
+
   useEffect(() => {
     setNodeConfig({
       ...defaultConfig,
@@ -109,6 +151,79 @@ const Component = (props: any) => {
     });
   }, [config]);
 
+  const renderAuditSelect = (key: Number) => {
+    switch (key) {
+      case 0:
+        return (
+          <>
+            <label>审批人</label>
+            <Select
+              showSearch
+              style={{ width: '100%' }}
+              value={nodeConfig.audits?.map((item) => item.value)}
+              onChange={(value) => {
+                onNodeConfigChange('audits', [
+                  { type: IDTYPE.USER, value: Number(value) },
+                ]);
+              }}
+              filterOption={(input, option) =>
+                option.props.children.indexOf(input) >= 0
+              }
+            >
+              {(userList || []).map((item) => (
+                <Option key={item.ID} value={item.ID}>
+                  {item.CName}
+                </Option>
+              ))}
+            </Select>
+          </>
+        );
+      case 1:
+        return (
+          <>
+            <label>审批角色</label>
+            <Select
+              showSearch
+              style={{ width: '100%' }}
+              value={nodeConfig.audits?.map((item) => item.value)}
+              filterOption={(input, option) =>
+                option.props.children.indexOf(input) >= 0
+              }
+              onChange={(value) => {
+                onNodeConfigChange('audits', [
+                  { type: IDTYPE.ROLE, value: Number(value) },
+                ]);
+              }}
+            >
+              {roleList &&
+                roleList.map((item) => (
+                  <Option key={item.ID} value={item.ID}>
+                    {item.Name}
+                  </Option>
+                ))}
+            </Select>
+          </>
+        );
+      case 2:
+        return (
+          <>
+            <label>多级审批</label>
+            <InputNumber
+              style={{ width: '100%' }}
+              value={
+                nodeConfig.audits?.length > 0 ? nodeConfig.audits[0].value : 0
+              }
+              onChange={(value) => {
+                onNodeConfigChange('audits', [
+                  { type: IDTYPE.LEADER, value: Number(value) },
+                ]);
+              }}
+            />
+          </>
+        );
+    }
+  };
+
   return (
     <div className={`${PREFIX}-panel-body`}>
       <div className={`${PREFIX}-panel-group`}>
@@ -116,14 +231,14 @@ const Component = (props: any) => {
         <InputField
           label="标题"
           value={nodeConfig.label}
-          onChange={value => {
+          onChange={(value) => {
             onNodeConfigChange('label', value);
           }}
         />
         <SelectField
           label="节点类型"
           value={nodeConfig.type}
-          onChange={value => {
+          onChange={(value) => {
             onNodeConfigChange('type', value);
           }}
           options={typeOption}
@@ -162,7 +277,7 @@ const Component = (props: any) => {
         <InputNumberField
           label="消息数量"
           value={nodeConfig.count}
-          onChange={value => {
+          onChange={(value) => {
             onNodeConfigChange('count', value);
           }}
         />
@@ -171,7 +286,7 @@ const Component = (props: any) => {
             label="字号"
             value={nodeConfig.fontSize}
             width={68}
-            onChange={value => {
+            onChange={(value) => {
               onNodeConfigChange('fontSize', value);
             }}
           />
@@ -184,16 +299,19 @@ const Component = (props: any) => {
         </div>
         {nodeConfig.type != TYPE.AUDIT && (
           <div className="group">
-            <label>{typeOption.find(item => item.value == nodeConfig.type)?.label || '-'}</label>
+            <label>
+              {typeOption.find((item) => item.value == nodeConfig.type)
+                ?.label || '-'}
+            </label>
             <TreeSelect
               showSearch
               multiple
               allowClear
-              value={nodeConfig.initiator?.map(item => item.origin)}
+              value={nodeConfig.initiator?.map((item) => item.origin)}
               style={{ width: '80%' }}
               placeholder="请选择"
               treeData={depUserTree}
-              onChange={values => {
+              onChange={(values) => {
                 handleTreeChange(values);
               }}
             />
@@ -213,56 +331,16 @@ const Component = (props: any) => {
             >
               <Radio value={1}>发起人自选</Radio>
               <Radio value={0}>指定人</Radio>
+              <Radio value={2}>部门主管</Radio>
             </Radio.Group>
-            <div className="group">
-              {isRole ? (
-                <>
-                  <label>审批角色</label>
-                  <Select
-                    showSearch
-                    style={{ width: '100%' }}
-                    value={nodeConfig.audits?.map(item => item.value)}
-                    filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
-                    onChange={value => {
-                      onNodeConfigChange('audits', [{ type: IDTYPE.ROLE, value: Number(value) }]);
-                    }}
-                  >
-                    {roleList &&
-                      roleList.map(item => (
-                        <Option key={item.ID} value={item.ID}>
-                          {item.Name}
-                        </Option>
-                      ))}
-                  </Select>
-                </>
-              ) : (
-                <>
-                  <label>审批人</label>
-                  <Select
-                    showSearch
-                    style={{ width: '100%' }}
-                    value={nodeConfig.audits?.map(item => item.value)}
-                    onChange={value => {
-                      onNodeConfigChange('audits', [{ type: IDTYPE.USER, value: Number(value) }]);
-                    }}
-                    filterOption={(input, option) => option.props.children.indexOf(input) >= 0}
-                  >
-                    {(userList || []).map(item => (
-                      <Option key={item.ID} value={item.ID}>
-                        {item.CName}
-                      </Option>
-                    ))}
-                  </Select>
-                </>
-              )}
-            </div>
+            <div className="group">{renderAuditSelect(isRole)}</div>
           </div>
         )}
       </div>
 
-      <Button style={{ marginTop: 20 }} type="primary" onClick={onSave}>
+      {/* <Button style={{ marginTop: 20 }} type="primary" onClick={onSave}>
         保存
-      </Button>
+      </Button> */}
     </div>
   );
 };
@@ -270,7 +348,9 @@ const Component = (props: any) => {
 function RecthServe(props: any) {
   return (
     <FlowchartFormWrapper {...props}>
-      {(config, plugin) => <Component {...props} plugin={plugin} config={config} />}
+      {(config, plugin) => (
+        <Component {...props} plugin={plugin} config={config} />
+      )}
     </FlowchartFormWrapper>
   );
 }

+ 7 - 1
src/pages/Flow/Audit.js

@@ -17,7 +17,9 @@ function Audit(props) {
   } = props;
   const [tabActiveKey, setTabActiveKey] = useState('1');
   const ref = useRef();
-  const { initialState: { user }  } = useModel('@@initialState');
+  const {
+    initialState: { user },
+  } = useModel('@@initialState');
   const permission = user?.Permission || {};
 
   const curItem = useMemo(() => {
@@ -49,6 +51,9 @@ function Audit(props) {
     dispatch({
       type: 'user/getRoleList',
     });
+    dispatch({
+      type: 'user/fetch',
+    });
   }, []);
 
   const onChange = (values) => {
@@ -132,4 +137,5 @@ export default connect(({ flow, loading, user, xflow }) => ({
   flowDetail: flow.flowDetail,
   formData: flow.formData,
   simpleFlowDteail: flow.simpleFlowDteail,
+  userList: user.list,
 }))(Audit);

+ 29 - 20
src/pages/Flow/OaDetail.js

@@ -9,6 +9,7 @@ import {
   createAduit,
   advanceSubmitNextNode,
   // queryOSSData,
+  queryLeader,
 } from '@/services/boom';
 import { useParams, useRequest, useNavigate } from 'umi';
 
@@ -46,6 +47,8 @@ const OaDetail = () => {
     },
   });
 
+  const { data: leaderData } = useRequest(queryLeader, {});
+
   //填写表单实时计算审批流程
   const advanceSubmit = async (changedFields, allValues) => {
     console.log(changedFields, allValues);
@@ -84,9 +87,14 @@ const OaDetail = () => {
 
   const submit = () => {
     const { form } = formValueRef.current;
-    const audit_list = approvalProcess?.map((item) => {
-      if (item[0].type == 'role') return item[0].nowValue;
-      return item[0].value;
+    let audit_list = [];
+    approvalProcess?.forEach((item) => {
+      if (item[0].type == 'role') audit_list.push(item[0].nowValue);
+      else if (item[0].type == 'leader')
+        audit_list.push(
+          ...leaderData.slice(0, item[0].value).map((leader) => leader.ID),
+        );
+      else audit_list.push(item[0].value);
     });
     let files = [],
       formData = [];
@@ -119,8 +127,8 @@ const OaDetail = () => {
       ]}
     >
       <Row gutter={24}>
-          <Col span={12}>
-            {/* {OSSData && (
+        <Col span={12}>
+          {/* {OSSData && (
               <AliyunOSSUpload
                 OSSData={OSSData}
                 onDone={OnModelFileDone}
@@ -129,22 +137,23 @@ const OaDetail = () => {
                 label="上传文件"
               />
             )} */}
-            <AuditDetailed
-              items={data?.formData}
-              onValuesChange={advanceSubmit}
+          <AuditDetailed
+            items={data?.formData}
+            onValuesChange={advanceSubmit}
+          />
+        </Col>
+        <Col span={12}>
+          {approvalProcess.length == 0 ? (
+            <Empty description="请先填写表单" />
+          ) : (
+            <ApprovalProcess
+              leaderData={leaderData}
+              approvalProcess={approvalProcess}
+              onChange={setApprovalProcess}
             />
-          </Col>
-          <Col span={12}>
-            {approvalProcess.length == 0 ? (
-              <Empty description="请先填写表单" />
-            ) : (
-              <ApprovalProcess
-                approvalProcess={approvalProcess}
-                onChange={setApprovalProcess}
-              />
-            )}
-          </Col>
-        </Row>
+          )}
+        </Col>
+      </Row>
     </PageContent>
   );
 };

+ 69 - 31
src/pages/Flow/components/ApprovalProcess.tsx

@@ -1,19 +1,26 @@
 import React, { useEffect, useMemo, useState } from 'react';
-import { queryUserListByRoleID } from '@/services/boom';
+import { queryUserListByRoleID, queryLeader } from '@/services/boom';
 import { connect } from 'umi';
 import { PlusOutlined } from '@ant-design/icons';
 import { Popover, Radio, RadioChangeEvent, Spin, Steps } from 'antd';
-import { useModel } from '@umijs/max';
+import { useModel, useRequest } from '@umijs/max';
 
 const { Step } = Steps;
 
-enum TYPR {
+enum TYPE {
   ROLE = 'role',
   USER = 'user',
+  LEADER = 'leader',
 }
 
 const ApprovalProcess = (props: any) => {
-  const { approvalProcess, dispatch, onChange, roleList = [] } = props;
+  const {
+    approvalProcess,
+    leaderData,
+    dispatch,
+    onChange,
+    roleList = [],
+  } = props;
   const [selectUserList, setSelectUserList] = useState([]);
   const [curNodeIdx, setCurNodeIdx] = useState(-1);
   const [loading, setLoading] = useState(false);
@@ -21,16 +28,16 @@ const ApprovalProcess = (props: any) => {
 
   const list = useMemo(() => {
     approvalProcess?.forEach((item: any) => {
-      if (item.length > 1 && item[0].type == TYPR.USER) {
+      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 == TYPR.USER) {
+      } 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 == TYPR.USER) {
+      } else if (item.length == 1 && item[0].nowType == TYPE.USER) {
         item[0].name =
           userList.find((user: any) => user.ID == item[0].nowValue)?.CName ||
           '-';
@@ -54,7 +61,7 @@ const ApprovalProcess = (props: any) => {
   const selectedUserId = ({ target: { value } }: RadioChangeEvent) => {
     //userId
     const name = userList.find((user: any) => user.ID == value)?.CName || '-';
-    const data = { nowType: TYPR.USER, nowValue: Number(value), name }; //type: TYPR.USER, value: Number(value)
+    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]);
@@ -71,6 +78,17 @@ const ApprovalProcess = (props: any) => {
     </Spin>
   );
 
+  const getLeaderContent = (length: any) => (
+    <Steps
+      progressDot
+      current={-1}
+      direction="vertical"
+      items={leaderData
+        ?.slice(0, length || 0)
+        .map((leader: any) => ({ title: leader.CName }))}
+    ></Steps>
+  );
+
   useEffect(() => {
     dispatch({
       type: 'user/getRoleList',
@@ -85,29 +103,49 @@ const ApprovalProcess = (props: any) => {
         direction="vertical"
         onChange={(value) => onStepsChange(value, list)}
       >
-        {list?.map((item: any) => (
-          <Step
-            key={item[0]?.value}
-            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 ||
-                '-'
-              }选择`
-            }
-          />
-        ))}
+        {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>
     </>
   );

+ 5 - 0
src/services/boom.js

@@ -225,6 +225,11 @@ export async function queryApplyList(params) {
   return request(`/api/v1/oa/audit/my/list`, { params });
 }
 
+//获取多级主管
+export async function queryLeader() {
+  return request(`/api/v1/oa/get-leader/list`);
+}
+
 // /**
 //   project_id
 //   version_id	大版本id