xjj пре 2 година
родитељ
комит
c3a2bb947f

+ 5 - 0
.umirc.ts

@@ -71,6 +71,11 @@ export default defineConfig({
           path: '/oa/detail/:oaId',
           component: './Flow/OaDetail',
         },
+        {
+          name: '审批详情',
+          path: '/oa/audit/:oaId/:id',
+          component: './Flow/OaAuditDetail',
+        },
       ],
     },
     {

+ 18 - 23
src/components/DDComponents/DDAttachment/index.js

@@ -2,34 +2,29 @@ import React, { useState, useEffect } from 'react';
 import { Upload, Button, message } from 'antd';
 import { PlusOutlined } from '@ant-design/icons';
 
-const CORP_ID = 'ding0cdce2d5dbf986d9';
-const AGENT_ID = '1788653353';
-
 function DDAttachment(props) {
-  const { disabled, onChange, spaceId = '213865445' } = props;
-  const [value, setValue] = useState([]);
-
-  const upload = () => {
-    // dd.biz.util.uploadAttachment({
-    //   // image: { multiple: true, compress: false, max: 9, spaceId: '12345' },
-    //   space: { corpId: CORP_ID, spaceId: spaceId, isCopy: 1, max: 9 },
-    //   file: { spaceId: spaceId, max: 1 },
-    //   types: ['file', 'space'], //PC端支持["photo","file","space"]
-    //   onSuccess: function(result) {
-    //     //onSuccess将在文件上传成功之后调用
-    //     onChange?.(result.data);
-    //   },
-    //   onFail: function(err) {
-    //     console.log(err);
-    //     message.error('附件上传失败');
-    //   },
-    // });
+  const { disabled, onChange } = props;
+  const uploadProps = {
+    name: 'file',
+    action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
+    headers: {
+      authorization: 'authorization-text',
+    },
+    onChange(info) {
+      if (info.file.status === 'done') {
+        console.log(info.file.url);
+        onChange(info.file.url)
+        message.success(`附件${info.file.name}上传成功`);
+      } else if (info.file.status === 'error') {
+        message.error(`附件${info.file.name}上传失败`);
+      }
+    },
   };
 
   return (
-    <div onClick={upload}>
+    <Upload {...uploadProps}>
       <Button icon={<PlusOutlined />}>添加附件</Button>
-    </div>
+    </Upload>
   );
 }
 

+ 85 - 0
src/pages/Flow/OaAuditDetail.js

@@ -0,0 +1,85 @@
+// 审批详情
+import React, { useEffect, useState, useRef, useMemo } from 'react';
+import { Steps, Button, Tooltip } from 'antd';
+import { useParams, useRequest, useNavigate } from 'umi';
+import { useModel } from 'umi';
+import AuditModal from './components/AuditModal';
+import FormAndFilesNode from './components/FormAndFilesNode';
+import { PageContainer, ProCard } from '@ant-design/pro-components';
+import { queryAuditDetail } from '@/services/boom';
+
+function OaAuditDetail(props) {
+  const [auditVisible, setAuditVisible] = useState(false);
+  const { oaId, id } = useParams();
+
+  const { data, loading, refresh } = useRequest(queryAuditDetail, {
+    defaultParams: [{ id }],
+  });
+  const { current_seq, form, OaAuditList, audit_status, AuditorInfo } =
+    data || {};
+  const { user } = useModel('userInfo');
+  const getDescription = (node) => {
+    let str = node?.AuditRoleInfo
+      ? `审批人:${node?.AuditRoleInfo.Name || '-'}`
+      : `审批人:${node?.AuditorUser.CName || '-'}`;
+    if (node.desc) {
+      return (
+        <div>
+          {str}
+          <div>
+            <Tooltip title={node.desc}>
+              <span style={{ color: '#1A73E8', textDecoration: 'undeline' }}>
+                审批意见
+              </span>
+            </Tooltip>
+          </div>
+        </div>
+      );
+    }
+    return str;
+  };
+
+  const btns = useMemo(() => {
+    if (!user || !data) return;
+    if (user.ID == AuditorInfo.ID && audit_status === 0) {
+      return [
+        <Button
+          style={{ marginRight: 10 }}
+          type="primary"
+          onClick={() => setAuditVisible(1)}
+        >
+          审批通过
+        </Button>,
+        <Button onClick={() => setAuditVisible(2)} danger>
+          审批拒绝
+        </Button>,
+      ];
+    }
+    return [];
+  }, [user, data]);
+
+  return (
+    <PageContainer extra={btns} loading={loading}>
+      <ProCard>
+        <Steps
+          style={{ marginBottom: 20 }}
+          current={current_seq - 1}
+          status={audit_status == 2 ? 'error' : 'process'}
+          items={OaAuditList?.map((item) => ({
+            title: item.seq_name,
+            description: getDescription(item),
+          }))}
+        ></Steps>
+        <FormAndFilesNode formData={form} />
+      </ProCard>
+
+      <AuditModal
+        visible={auditVisible}
+        onClose={() => setAuditVisible(false)}
+        onOk={refresh}
+      />
+    </PageContainer>
+  );
+}
+
+export default OaAuditDetail;

+ 83 - 11
src/pages/Flow/OaDetail.js

@@ -1,37 +1,109 @@
-import React, { useState } from 'react';
+import React, { useRef, useState } from 'react';
 import { PageContainer, ProCard } from '@ant-design/pro-components';
-import { Col, Empty, Row } from 'antd';
+import { Button, Col, Empty, Row, message } from 'antd';
 import ApprovalProcess from './components/ApprovalProcess';
 import AuditDetailed from './components/AuditDetailed';
-import { queryGetBomForm, queryProcessFlows } from '@/services/boom';
-import { useParams, useRequest } from 'umi';
+import {
+  queryProcessFlows,
+  createAduit,
+  advanceSubmitNextNode,
+} from '@/services/boom';
+import { useParams, useRequest, useNavigate } from 'umi';
 
 const OaDetail = () => {
   const [approvalProcess, setApprovalProcess] = useState([]);
   const { oaId } = useParams();
-  const items = [];
-
+  const formValueRef = useRef({
+    form: '',
+  });
+  const navigate = useNavigate();
   const { data, loading } = useRequest(queryProcessFlows, {
     defaultParams: [{ ids: oaId }],
   });
+  const { loading: createLoadin, run: createRun } = useRequest(createAduit, {
+    manual: true,
+    onSuccess() {
+      message.success('申请审批成功');
+      navigate(-1);
+    },
+  });
+
+  const { run } = useRequest(advanceSubmitNextNode, {
+    debounceInterval: 500,
+    manual: true,
+    formatResult(res) {
+      setApprovalProcess(res.data[0]);
+    },
+  });
 
   //填写表单实时计算审批流程
-  const advanceSubmit = async (changedFields, allFields) => {
-    console.log(changedFields, allFields);
+  const advanceSubmit = async (changedFields, allValues) => {
+    console.log(changedFields, allValues);
+    let formValues = data.formData
+      .map((item) => {
+        const itemProps = item.props;
+        let val = allValues[itemProps.id];
+        if (!itemProps.label) return;
+        if (!val && val !== 0) return;
+        if (val instanceof Object) {
+          return {
+            name: itemProps.label,
+            id: itemProps.id,
+            value: [...val],
+          };
+        } else if (allValues[itemProps.id]) {
+          return {
+            name: itemProps.label,
+            id: itemProps.id,
+            value: [allValues[itemProps.id]] || undefined,
+          };
+        }
+      })
+      .filter((item) => item);
+
+    let params = {
+      flow_id: Number(oaId),
+      template_node_id: 0,
+      formComponentValues: formValues,
+      audit_list: [],
+    };
+    formValueRef.current.form = formValues;
+    run(params);
+  };
+
+  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;
+    });
+    createRun({
+      flow_id: Number(oaId),
+      form: JSON.stringify(form),
+      audit_list,
+      files: '',
+    });
   };
 
   return (
-    <PageContainer loading={loading}>
+    <PageContainer
+      loading={loading}
+      footer={[
+        <Button onClick={submit} type="primary" loading={createLoadin}>
+          提交审批
+        </Button>,
+      ]}
+    >
       <ProCard style={{ minHeight: '80vh' }}>
         <Row gutter={24}>
           <Col span={12}>
             <AuditDetailed
               items={data?.formData}
-              onFieldsChange={advanceSubmit}
+              onValuesChange={advanceSubmit}
             />
           </Col>
           <Col span={12}>
-            {approvalProcess.length == 0 ? ( //!formComponentValues[item.nodeId] ||
+            {approvalProcess.length == 0 ? (
               <Empty description="请先填写表单" />
             ) : (
               <ApprovalProcess

+ 14 - 5
src/pages/Flow/components/ApprovalProcess.tsx

@@ -1,8 +1,9 @@
-import React, { useMemo, useState } from 'react';
+import React, { useEffect, 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';
+import { useModel } from '@umijs/max';
 
 const { Step } = Steps;
 
@@ -12,13 +13,14 @@ enum TYPR {
 }
 
 const ApprovalProcess = (props: any) => {
-  const { approvalProcess, userList, onChange, roleList = [] } = props;
+  const { approvalProcess, dispatch, onChange, roleList = [] } = props;
   const [selectUserList, setSelectUserList] = useState([]);
   const [curNodeIdx, setCurNodeIdx] = useState(-1);
   const [loading, setLoading] = useState(false);
+  const { userList, run } = useModel('userList');
 
   const list = useMemo(() => {
-    return approvalProcess?.forEach((item: any) => {
+    approvalProcess?.forEach((item: any) => {
       if (item.length > 1 && item[0].type == TYPR.USER) {
         item.forEach((curUser: any) => {
           curUser.name =
@@ -36,6 +38,7 @@ const ApprovalProcess = (props: any) => {
         item[0].name = null;
       }
     });
+    return approvalProcess;
   }, [approvalProcess]);
 
   const onStepsChange = async (current: any, list: any) => {
@@ -53,7 +56,7 @@ const ApprovalProcess = (props: any) => {
     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 };
-
+    console.log([...list]);
     onChange?.([...list]);
   };
 
@@ -68,6 +71,13 @@ const ApprovalProcess = (props: any) => {
     </Spin>
   );
 
+  useEffect(() => {
+    dispatch({
+      type: 'user/getRoleList',
+    });
+    run();
+  }, []);
+
   return (
     <>
       <Steps
@@ -102,6 +112,5 @@ const ApprovalProcess = (props: any) => {
   );
 };
 export default connect(({ user }: any) => ({
-  userList: user.list,
   roleList: user.roleList,
 }))(ApprovalProcess);

+ 9 - 3
src/pages/Flow/components/AuditDetailed.js

@@ -1,10 +1,10 @@
 import DDComponents from '@/components/DDComponents';
 import React, { useMemo, useState } from 'react';
-import { Form } from 'antd';
+import { Button, Form } from 'antd';
 
 const AuditDetailed = (props) => {
   const [form] = Form.useForm();
-  const { items, onFieldsChange } = props;
+  const { items, onValuesChange } = props;
 
   const behavior = useMemo(() => {
     let data = {};
@@ -88,9 +88,15 @@ const AuditDetailed = (props) => {
       style={{ minHeight: '80vh', overflowY: 'auto', paddingRight: 20 }}
       layout="vertical"
       autoComplete="off"
-      onFieldsChange={onFieldsChange}
+      onValuesChange={onValuesChange}
+      onFinish={onFinish}
     >
       {items.map((item) => GetComponent(item))}
+      <Form.Item>
+        <Button htmlType="submit" type="primary">
+          提交
+        </Button>
+      </Form.Item>
     </Form>
   );
 };

+ 42 - 0
src/pages/Flow/components/AuditModal.js

@@ -0,0 +1,42 @@
+import React, { useEffect, useMemo } from 'react';
+import { Form } from 'antd';
+import { Modal, Input } from 'antd';
+
+// 审批意见
+function AuditModal(props) {
+  const { visible, onClose, onOk, loading } = props;
+  const [form] = Form.useForm();
+
+  const handleOk = () => {
+    form.validateFields((err, fieldsValue) => {
+      if (err) return;
+      onOk({
+        ...fieldsValue,
+        // 3 通过审批   2 拒绝审批
+        audit_status: visible == 1 ? 3 : 2,
+      });
+    });
+  };
+
+  return (
+    <Modal
+      confirmLoading={loading}
+      destroyOnClose
+      title={visible == 1 ? '是否确认通过审批?' : '是否确认拒绝审批?'}
+      open={visible}
+      onCancel={onClose}
+      onOk={handleOk}
+    >
+      <Form.Item
+        labelCol={{ span: 5 }}
+        wrapperCol={{ span: 15 }}
+        name="audit_comment"
+        label="审批意见"
+      >
+        <Input.TextArea />
+      </Form.Item>
+    </Modal>
+  );
+}
+
+export default AuditModal;

+ 67 - 0
src/pages/Flow/components/FormAndFilesNode.js

@@ -0,0 +1,67 @@
+import { Card, Col, Row,  Empty } from 'antd';
+import { Form } from 'antd';
+import { useMemo, useState } from 'react';
+// import AttachmentTable from '@/components/AttachmentTable';
+
+
+
+const FormAndFilesNode = (props) => {
+  const { formData } = props;
+
+  const FormContent = useMemo(() => {
+    return renderFrom(formData);
+  }, [formData]);
+
+  return (
+    <Card title="审批信息">
+      <Row gutter={20}>
+        <Col span={12}>{FormContent}</Col>
+
+        <Col span={12}>
+          {/* <AttachmentTable
+            version={version}
+            canDelete={version.last_version == 0}
+          /> */}
+        </Col>
+      </Row>
+    </Card>
+  );
+};
+
+const renderFrom = (data) => {
+  if (!data) return <Empty description="没有表单信息" />;
+  try {
+    const formData = JSON.parse(data);
+    if (formData.length == 0) return <Empty description="没有表单信息" />;
+    return (
+      <>
+        {formData.map((item, idx) => {
+          const value = item.value.join(',');
+          return (
+            <Form.Item
+              key={`FormAndFilesNode_${idx}`}
+              labelCol={{ span: 4 }}
+              wrapperCol={{ span: 14 }}
+              label={item.name}
+            >
+              <div
+                style={{
+                  width: '100%',
+                  padding: '4px 12px',
+                  backgroundColor: '#ececef',
+                  border: '1px solid #bcb9b9',
+                  borderRadius: '4px',
+                }}
+              >
+                {value}
+              </div>
+            </Form.Item>
+          );
+        })}
+      </>
+    );
+  } catch {
+    return <Empty description="没有表单信息" />;
+  }
+};
+export default FormAndFilesNode;

+ 37 - 1
src/services/boom.js

@@ -18,6 +18,13 @@ export async function addAudit(data) {
   });
 }
 
+export async function queryAuditDetail(params) {
+  return request(`/api/v1/oa/audit/detail`, {
+    method: 'GET',
+    params,
+  });
+}
+
 const getFlowDetail = (data) => {
   const groups = {
     top: {
@@ -159,7 +166,36 @@ export async function queryClassify(data) {
 }
 
 export async function queryOSSData() {
-  return request(`/config/chart-template-img?destDir=public/bom`);
+  return request(`/api/v1/config/chart-template-img?destDir=public/bom`);
+}
+
+// 提交审批
+export async function createAduit(data) {
+  return request(`/api/v1/oa/submit`, {
+    method: 'POST',
+    data,
+  });
+}
+// 计算审批节点
+export async function advanceSubmitNextNode(params) {
+  let data = {
+    flow_id: 0,
+    node_level_id: 0,
+    id: 0,
+    project_id: 0,
+    cur_template_node_id: 0,
+    next_template_node_id: 0,
+    template_node_id: null,
+    flow_path: null,
+    template_id: 0,
+    cur_template_id: 0,
+    next_template_id: 0,
+    form_list: [JSON.stringify(params)],
+  };
+  return request(`/api/v1/oa/next/node/advance-submit`, {
+    method: 'POST',
+    data,
+  });
 }
 
 // /**