xjj 2 år sedan
förälder
incheckning
16077d5427

+ 5 - 0
.umirc.ts

@@ -52,6 +52,11 @@ export default defineConfig({
         },
       ],
     },
+    {
+      name: 'OA审批',
+      path: '/oa',
+      component: './Flow/Oa',
+    },
     {
       name: '权限演示',
       path: '/access',

+ 6 - 4
src/app.tsx

@@ -4,6 +4,7 @@ import { message } from 'antd';
 import UserDropdown from '@/components/UserDropdown';
 import { getToken } from '@/utils/utils';
 import { history } from 'umi';
+import logo from "@/assets/logo.jpg"
 
 // 全局初始化数据配置,用于 Layout 用户信息和权限初始化
 // 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate
@@ -14,14 +15,15 @@ export async function getInitialState(): Promise<{ name: string }> {
 export const layout: RunTimeLayoutConfig = (initialState) => {
   return {
     navTheme: 'light',
-    layout: 'top',
+    layout: 'side',
     contentWidth: 'Fluid',
-    fixedHeader: true,
-    fixSiderbar: true,
+    title: "",
+    // fixedHeader: true,
+    // fixSiderbar: true,
     rightRender(initialState, setInitialState, runtimeConfig) {
       return <UserDropdown />;
     },
-    logo: null,
+    logo: <img src={logo} style={{height: 28}} />,
   };
 };
 

BIN
src/assets/logo.jpg


+ 18 - 18
src/components/Flow/node/registerNode.tsx

@@ -6,24 +6,24 @@ import AuditNode, { AuditServe } from './auditNode';
 import judgeNode, { judgeServe } from './judgeNode';
 
 export const registerNode = [
-  {
-    component: Rect,
-    popover: () => <div>业务组件</div>,
-    name: 'custom-rect',
-    width: 120,
-    height: 50,
-    label: '业务节点',
-    service: RectServe,
-  },
-  {
-    component: Circle,
-    popover: () => <div>审批节点</div>,
-    name: 'custom-circle',
-    width: 90,
-    height: 90,
-    label: '审批节点',
-    service: CircleServe,
-  },
+  // {
+  //   component: Rect,
+  //   popover: () => <div>业务组件</div>,
+  //   name: 'custom-rect',
+  //   width: 120,
+  //   height: 50,
+  //   label: '业务节点',
+  //   service: RectServe,
+  // },
+  // {
+  //   component: Circle,
+  //   popover: () => <div>审批节点</div>,
+  //   name: 'custom-circle',
+  //   width: 90,
+  //   height: 90,
+  //   label: '审批节点',
+  //   service: CircleServe,
+  // },
   {
     component: AuditNode,
     popover: () => <div>动作节点</div>,

+ 0 - 1
src/global.less

@@ -3,7 +3,6 @@
   box-sizing: border-box;
 }
 
-body,
 #root {
   min-height: 100vh;
 }

+ 1 - 1
src/models/user.js

@@ -47,7 +47,7 @@ export default {
 
   state: {
     list: [],
-    currentUser: { Permission: {} },
+    // currentUser: { Permission: {} },
     message: {},
     userList: [],
     depRole: [],

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

@@ -1,5 +1,5 @@
 import React, { useEffect } from "react";
-import { Modal, Input, Form } from "antd";
+import { Modal, Input, Form, Select } from "antd";
 
 // 审批意见
 function AuditModal(props) {
@@ -31,6 +31,12 @@ function AuditModal(props) {
         <Form.Item label="详情" name="desc">
           <Input.TextArea />
         </Form.Item>
+        <Form.Item label="分类" name="desc">
+          <Select options={[
+            {value: 1,label: "BOM"},
+            {value: 2,label: "OA"},
+          ]}></Select>
+        </Form.Item>
       </Form>
     </Modal>
   );

+ 174 - 0
src/pages/Flow/Oa.js

@@ -0,0 +1,174 @@
+import React from 'react';
+import { Collapse, Layout, List } from 'antd';
+import {
+  UserOutlined,
+  FileOutlined,
+  EditOutlined,
+  ExceptionOutlined,
+} from '@ant-design/icons';
+import { PageContainer } from '@ant-design/pro-components';
+import { Link } from '@umijs/max';
+
+const { Sider, Content } = Layout;
+const { Panel } = Collapse;
+
+const categories = [
+  {
+    name: '请假审批',
+    items: [
+      {
+        name: '病假申请',
+        icon: <UserOutlined />,
+      },
+      {
+        name: '事假申请',
+        icon: <FileOutlined />,
+      },
+      {
+        name: '探亲假申请',
+        icon: <UserOutlined />,
+      },
+      {
+        name: '婚假申请',
+        icon: <UserOutlined />,
+      },
+      {
+        name: '产假申请',
+        icon: <UserOutlined />,
+      },
+      {
+        name: '陪产假申请',
+        icon: <UserOutlined />,
+      },
+      {
+        name: '丧假申请',
+        icon: <UserOutlined />,
+      },
+    ],
+  },
+  {
+    name: '加班审批',
+    items: [
+      {
+        name: '普通加班申请',
+        icon: <EditOutlined />,
+      },
+      {
+        name: '周末加班申请',
+        icon: <EditOutlined />,
+      },
+      {
+        name: '节假日加班申请',
+        icon: <EditOutlined />,
+      },
+    ],
+  },
+  {
+    name: '报销审批',
+    items: [
+      {
+        name: '差旅费报销',
+        icon: <FileOutlined />,
+      },
+      {
+        name: '通讯费报销',
+        icon: <FileOutlined />,
+      },
+      {
+        name: '餐费报销',
+        icon: <FileOutlined />,
+      },
+      {
+        name: '办公用品采购报销办公用品采购报销办公用品采购报销办公用品采购报销',
+        icon: <FileOutlined />,
+      },
+      {
+        name: '项目费用报销',
+        icon: <FileOutlined />,
+      },
+    ],
+  },
+  {
+    name: '异常审批',
+    items: [
+      {
+        name: '物品遗失申请',
+        icon: <ExceptionOutlined />,
+      },
+      {
+        name: '客诉申请',
+        icon: <ExceptionOutlined />,
+      },
+      {
+        name: '工作计划申请',
+        icon: <ExceptionOutlined />,
+      },
+    ],
+  },
+];
+const getBackgroundColors = (index) => {
+  const backgroundColors = [
+    '#1ABC9C', // 深绿色
+    '#3498DB', // 蓝色
+    '#9B59B6', // 紫色
+    '#F1C40F', // 黄色
+    '#E67E22', // 橙色
+    '#E74C3C', // 红色
+    '#2C3E50', // 深蓝色
+    '#34495E', // 深灰色
+  ];
+
+  return backgroundColors[index % backgroundColors.length];
+};
+const Approval = () => {
+  return (
+    <PageContainer>
+      <Collapse defaultActiveKey={categories.map((category) => category.name)}>
+        {categories.map((category, index) => (
+          <Panel style={{userSelect: 'none'}} header={category.name} key={category.name}>
+            <List
+              grid={{ gutter: 16, column: 3 }}
+              dataSource={category.items}
+              renderItem={(item) => (
+                <List.Item key={item.name}>
+                  <Link
+                    to={`/oa/${item.name}`}
+                    style={{ display: 'flex', alignItems: 'center' }}
+                  >
+                    <div
+                      style={{
+                        width: 48,
+                        height: 48,
+                        borderRadius: 8,
+                        textAlign: 'center',
+                        lineHeight: '48px',
+                        color: '#fff',
+                        fontSize: 24,
+                        backgroundColor: getBackgroundColors(index),
+                      }}
+                    >
+                      {item.icon}
+                    </div>
+                    <span
+                      style={{
+                        marginLeft: 12,
+                        flex: 1,
+                        fontSize: 18,
+                        maxWidth: '100%',
+                        paddingRight: 30,
+                      }}
+                    >
+                      {item.name}
+                    </span>
+                  </Link>
+                </List.Item>
+              )}
+            ></List>
+          </Panel>
+        ))}
+      </Collapse>
+    </PageContainer>
+  );
+};
+
+export default Approval;

+ 80 - 0
src/pages/Flow/OaDetail.js

@@ -0,0 +1,80 @@
+import React from 'react';
+import { PageContainer } from '@ant-design/pro-components';
+import { Col, Empty, Row } from 'antd';
+import ApprovalProcess from './components/ApprovalProcess';
+import { queryGetBomForm } from '@/services/boom';
+
+const OaDetail = () => {
+  const [approvalProcess, setApprovalProcess] = useState([]);
+  const items = [];
+  const initFormList = async () => {
+    const res = await queryGetBomForm({
+      project_id: version.project_id,
+      node_id: version.template_node_id,
+    });
+    if (res.data) {
+      const formList = JSON.parse(res.data.json);
+      setApprovalProcess(formList.approvalProcess || {});
+      return formList.approvalProcess;
+    }
+  };
+  //填写表单实时计算审批流程
+  const advanceSubmit = async () => {
+    console.log('重重新计算审批流程');
+    var fieldsValue = await form.validateFields();
+
+    let result = Object.values(fieldsValue)
+      .map((item) => {
+        if (item && Array.isArray(item)) return item;
+      })
+      .filter((item) => item);
+    const formList = await getFromData(result);
+    let params = {
+      desc: fieldsValue.desc,
+      // 审核流程id
+      flow_id: 0,
+      node_level_id: 0,
+      id: version.id,
+      project_id: version.project_id,
+      cur_template_node_id: version.template_node_id * 1, // 当前节点
+      next_template_node_id: 0, // 审核完成后的业务节点
+      template_node_id: null, // 将要流转的节点审批节点
+      flow_path: null, //审批节点数组
+      // 模板id.一致就行
+      template_id: version.template_id,
+      cur_template_id: version.template_id,
+      next_template_id: version.template_id,
+      form_list: formList,
+    };
+    dispatch({
+      type: 'detail/advanceSubmitNextNode',
+      payload: params, //values,
+      callback: (data) => {
+        if (data) {
+          setApprovalProcess(data);
+        }
+      },
+    });
+  };
+  return (
+    <PageContainer>
+      <Row>
+        <Col span={17}>
+          <Components items={items} onChange={advanceSubmit} />
+        </Col>
+        <Col offset={1} span={6}>
+          {approvalProcess.length == 0 ? ( //!formComponentValues[item.nodeId] ||
+            <Empty description="请先填写表单" />
+          ) : (
+            <ApprovalProcess
+              approvalProcess={approvalProcess}
+              onChange={setApprovalProcess}
+            />
+          )}
+        </Col>
+      </Row>
+    </PageContainer>
+  );
+};
+
+export default OaDetail;

+ 107 - 0
src/pages/Flow/components/ApprovalProcess.tsx

@@ -0,0 +1,107 @@
+import React, { useMemo, useState } from 'react';
+import { queryUserListByRoleID } from '@/services/boom';
+import { connect } from 'umi';
+import { PlusOutlined } from '@ant-design/icons';
+import { Popover, Radio, RadioChangeEvent, Spin, Steps } from 'antd';
+
+const { Step } = Steps;
+
+enum TYPR {
+  ROLE = 'role',
+  USER = 'user',
+}
+
+const ApprovalProcess = (props: any) => {
+  const { approvalProcess, userList, onChange, roleList = [] } = props;
+  const [selectUserList, setSelectUserList] = useState([]);
+  const [curNodeIdx, setCurNodeIdx] = useState(-1);
+  const [loading, setLoading] = useState(false);
+
+  const list = useMemo(() => {
+    return approvalProcess?.forEach((item: any) => {
+      if (item.length > 1 && item[0].type == TYPR.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) {
+        item[0].name =
+          userList.find((user: any) => user.ID == item[0].value)?.CName || '-';
+      } else if (item.length == 1 && item[0].nowType == TYPR.USER) {
+        item[0].name =
+          userList.find((user: any) => user.ID == item[0].nowValue)?.CName ||
+          '-';
+      } else {
+        item[0].name = null;
+      }
+    });
+  }, [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 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)
+    list[curNodeIdx][0] = { ...list[curNodeIdx][0], ...data };
+
+    onChange?.([...list]);
+  };
+
+  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>
+        ))}
+      </Radio.Group>
+    </Spin>
+  );
+
+  return (
+    <>
+      <Steps
+        current={-1}
+        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
+              }选择`
+            }
+          />
+        ))}
+      </Steps>
+    </>
+  );
+};
+export default connect(({ user }: any) => ({
+  userList: user.list,
+  roleList: user.roleList,
+}))(ApprovalProcess);

+ 18 - 13
src/services/boom.js

@@ -26,6 +26,24 @@ export async function saveAuditFlowInfo(data) {
     data,
   });
 }
+export async function queryUserListByRoleID(params) {
+  let res = await request(
+    `/api/v1/purchase/process/get-role-user?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res.data;
+}
+export async function queryGetBomForm(params) {
+  let res = await request(
+    `/api/v1/purchase/bom/get-bom-form?${stringify(params)}`,
+    {
+      method: 'GET',
+    },
+  );
+  return res;
+}
 // /**
 //   project_id
 //   version_id	大版本id
@@ -398,13 +416,6 @@ export async function saveAuditFlowInfo(data) {
 //   return request(`/api/v2/dep?${stringify(params)}`);
 // }
 
-// export async function queryUserListByRoleID(params) {
-//   let res = await request(`/api/v1/purchase/process/get-role-user?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res.data;
-// }
-
 // //新增工作流时调用接口 给项目绑定默认分类列表
 // //purchase/bom/default-bind-classify?project_id=1
 // export async function queryDefaultBindClassify(params) {
@@ -449,12 +460,6 @@ export async function saveAuditFlowInfo(data) {
 //     body: data,
 //   });
 // }
-// export async function queryGetBomForm(params) {
-//   let res = await request(`/api/v1/purchase/bom/get-bom-form?${stringify(params)}`, {
-//     method: 'GET',
-//   });
-//   return res;
-// }
 
 // //章管家失败,重新申请用印
 // export async function queryTrySeal(params) {