瀏覽代碼

Merge branch 'develop' of http://120.55.44.4:10080/xujunjie/WorkloadWeb into develop

xujunjie 3 年之前
父節點
當前提交
441c9be8f2
共有 31 個文件被更改,包括 1604 次插入1035 次删除
  1. 4 0
      config/router.config.js
  2. 116 120
      src/pages/PurchaseAdmin/PurchaseList/Approval/ApprovalModal.js
  3. 76 70
      src/pages/PurchaseAdmin/PurchaseList/Approval/Auth.js
  4. 18 9
      src/pages/PurchaseAdmin/PurchaseList/Approval/AuthModal.js
  5. 104 22
      src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.js
  6. 16 0
      src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.less
  7. 35 74
      src/pages/PurchaseAdmin/PurchaseList/Approval/ExecutionModal.js
  8. 112 63
      src/pages/PurchaseAdmin/PurchaseList/Approval/List.js
  9. 33 81
      src/pages/PurchaseAdmin/PurchaseList/Approval/MemberModal.js
  10. 39 75
      src/pages/PurchaseAdmin/PurchaseList/Approval/QualityOperateModal.js
  11. 24 7
      src/pages/PurchaseAdmin/PurchaseList/Approval/models/approval.js
  12. 33 17
      src/pages/PurchaseAdmin/PurchaseList/Index.js
  13. 176 0
      src/pages/PurchaseAdmin/PurchaseList/Report/DepCompareModal.js
  14. 31 41
      src/pages/PurchaseAdmin/PurchaseList/Report/Department.js
  15. 122 0
      src/pages/PurchaseAdmin/PurchaseList/Report/Finance.js
  16. 137 112
      src/pages/PurchaseAdmin/PurchaseList/Report/Project.js
  17. 1 3
      src/pages/PurchaseAdmin/PurchaseList/Report/Resource.js
  18. 55 21
      src/pages/PurchaseAdmin/PurchaseList/Report/UserProjectRptModal.js
  19. 2 2
      src/pages/PurchaseAdmin/PurchaseList/Report/UserRptModal.js
  20. 149 54
      src/pages/PurchaseAdmin/PurchaseList/Report/models/report.js
  21. 101 94
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/AddModal.js
  22. 59 14
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/Auth.js
  23. 31 47
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/AuthWorkList.js
  24. 13 26
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/CalendarModal.js
  25. 9 10
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/RejectModal.js
  26. 1 3
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/SearchForm.js
  27. 30 16
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/WorkList.js
  28. 18 32
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/index.js
  29. 26 21
      src/pages/PurchaseAdmin/PurchaseList/WorkingHours/models/workingHours.js
  30. 16 0
      src/services/approval.js
  31. 17 1
      src/services/workHours.js

+ 4 - 0
config/router.config.js

@@ -40,6 +40,10 @@ export default [
             path: '/home/report/department',
             component: './PurchaseAdmin/PurchaseList/Report/Department',
           },
+          {
+            path: '/home/report/finance',
+            component: './PurchaseAdmin/PurchaseList/Report/Finance',
+          },
           {
             path: '/home/approval/list',
             component: './PurchaseAdmin/PurchaseList/Approval/List',

+ 116 - 120
src/pages/PurchaseAdmin/PurchaseList/Approval/ApprovalModal.js

@@ -1,11 +1,8 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Select, Modal, Input, TreeSelect } from 'antd';
+import { Form, Select, Modal, Input, TreeSelect } from 'antd';
 import moment from 'moment';
 import provinces from './provinces';
 import { queryApproval } from '@/services/approval';
-// import project from '@/pages/ProjectAdmin/ProjectAdmin/models/project';
 const { Option } = Select;
 const { TreeNode } = TreeSelect;
 // 新建
@@ -16,14 +13,16 @@ function AddModal(props) {
     visible,
     onClose,
     onOk,
-    form,
     data,
+    currentUser,
+    depUserTree,
     flowList = [],
     industryList = [],
     typeList = [],
     disabled,
     loading,
   } = props;
+  const [form] = Form.useForm();
   const [codes, setCodes] = useState({
     type: '',
     industry: '',
@@ -34,51 +33,28 @@ function AddModal(props) {
   const [type, setType] = useState({});
 
   const handleOk = () => {
-    form.validateFields((err, fieldsValue) => {
-      if (err) return;
+    form.validateFields().then(fieldsValue => {
       let values = { ...fieldsValue, id: data.id };
-      //项目分类为研发时
-      if (fieldsValue.type_id == 7) {
-        values.project_name = fieldsValue.project_name;
-        values.flow_id = Number(fieldsValue.flow_id);
-        values.type_id = Number(fieldsValue.type_id);
-        // 获得flow下第一个node的id
-        values.node_id = flowList.find(item => item.id == values.flow_id).Nodes[0].id;
-        //以下为测试用默认值
-        // values.industry_id = 0;
-        // values.location = '';
-        // values.location_code = '';
-        // values.project_full_code = '';
-        // values.name = '';
-        // values.version = '';
-
-        //通过当前项目数生成项目编号
-        // dispatch({
-        //   type: 'approval/queryApproval',
-        //   callback: data => {
-        //     let project_full_code = '';
-        //     if (total < 10) {
-        //       project_full_code = '00' + data.pagination.total;
-        //     } else if (total < 100) project_full_code = '0' + data.pagination.total;
-        //     else project_full_code = data.pagination.total;
-        //     values.project_full_code = `RD${moment().format('YYYYMM')}${project_full_code}`;
-        //     onOk(values);
-        //   },
-        // });
-        onOk(values);
-      } else {
-        values.project_name = fieldsValue.project_name;
-        values.type_id = Number(fieldsValue.type_id);
+      values.project_name = fieldsValue.project_name;
+      values.flow_id = Number(fieldsValue.flow_id);
+      values.type_id = Number(fieldsValue.type_id);
+      // 获得flow下第一个node的id
+      values.node_id = flowList.find(item => item.id == values.flow_id).Nodes[0].id;
+      //项目分类为不为研发时
+      if (fieldsValue.type_id != 7) {
         values.industry_id = Number(fieldsValue.industry_id);
-        values.flow_id = Number(fieldsValue.flow_id);
-        // 获得flow下第一个node的id
-        values.node_id = flowList.find(item => item.id == values.flow_id).Nodes[0].id;
         let [location, location_code] = fieldsValue.location.split('##');
         values.location = location;
         values.location_code = location_code;
         values.project_full_code = `${codes.type}${codes.industry}${codes.location}${codes.name}${codes.version}`;
-        onOk(values);
       }
+      if (fieldsValue.author) {
+        values.author = Number(fieldsValue.author.split('||')[0]);
+        values.author_dep_id = Number(fieldsValue.author.split('||')[1]);
+      } else {
+        values.author = null;
+      }
+      onOk(values);
     });
   };
 
@@ -88,7 +64,6 @@ function AddModal(props) {
       let code = item.code || '';
       if (code.length == 4) {
         code = code.substr(1);
-        console.log(code);
       }
       if (code) {
         title += `(${code})`;
@@ -108,7 +83,7 @@ function AddModal(props) {
       type: item.code,
     });
     setType(item);
-    form.setFieldsValue({ flow_id: id == 7 ? '4' : '1'});
+    form.setFieldsValue({ flow_id: id == 7 ? '4' : '1' });
   };
   const changeIndustry = id => {
     const item = industryList.find(item => item.id == id);
@@ -133,7 +108,7 @@ function AddModal(props) {
   const onBlurName = e => {
     let value = e.target.value.toUpperCase();
     while (value.length < 3) {
-      value = value + "V";
+      value = value + 'V';
     }
     form.setFieldsValue({
       name: value,
@@ -145,12 +120,14 @@ function AddModal(props) {
   };
 
   const renderDetail = () => {
-    return <>
-      <Form.Item label="行业名称">
-        {form.getFieldDecorator('industry_id', {
-          initialValue: String(data.industry_id || ''),
-          rules: [{ required: true, message: '请选择行业名称' }],
-        })(
+    return (
+      <>
+        <Form.Item
+          label="行业名称"
+          name="industry_id"
+          initialValue={String(data.industry_id || '')}
+          rules={[{ required: true, message: '请选择行业名称' }]}
+        >
           <Select style={{ width: '100%' }} onChange={changeIndustry}>
             {industryList.map(item => (
               <Option key={item.id}>
@@ -158,55 +135,54 @@ function AddModal(props) {
               </Option>
             ))}
           </Select>
-        )}
-      </Form.Item>
-      <Form.Item label="项目地区">
-        {form.getFieldDecorator('location', {
-          initialValue: data.location,
-          rules: [{ required: true, message: '请选择项目地区' }],
-        })(
+        </Form.Item>
+        <Form.Item
+          label="项目地区"
+          name="location"
+          initialValue={data.location}
+          rules={[{ required: true, message: '请选择项目地区' }]}
+        >
           <TreeSelect
             dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
             onChange={changeLocation}
           >
             {renderTreeNodes(provinces)}
           </TreeSelect>
-        )}
-      </Form.Item>
-      <Form.Item label="项目简称">
-        {form.getFieldDecorator('name', {
-          initialValue: data.name,
-          rules: [
+        </Form.Item>
+        <Form.Item
+          label="项目简称"
+          name="name"
+          initialValue={data.name}
+          rules={[
             { required: true, message: '请输入项目简称' },
             {
               validator: (rule, value, callback) => {
-                if (value.match(/[^A-Za-z]/g)) {
-                  callback('项目简称只能是英文字符');
-                } else {
-                  callback();
-                }
+                if (value.match(/[^A-Za-z]/g)) callback('项目简称只能是英文字符');
+                else callback();
               },
             },
-          ],
-        })(<Input maxLength={3} onBlur={onBlurName} />)}
-      </Form.Item>
-      <Form.Item label="项目期数">
-        {form.getFieldDecorator('version', {
-          initialValue: data.version,
-          rules: [{ required: true, message: '请选择项目期数' }],
-        })(
+          ]}
+        >
+          <Input maxLength={3} onBlur={onBlurName} />
+        </Form.Item>
+        <Form.Item
+          label="项目期数"
+          name="version"
+          initialValue={data.version}
+          rules={[{ required: true, message: '请选择项目期数' }]}
+        >
           <Select style={{ width: '100%' }} onChange={changeVersion}>
             {['一期', '二期', '三期', '四期', '五期'].map((item, index) => (
               <Option key={index + 1}>{item}</Option>
             ))}
           </Select>
-        )}
-      </Form.Item>
-      <Form.Item label="项目编号">
-        {codes.type || '***'}-{codes.industry || '***'}-{codes.location || '***'}-
-        {codes.name || '***'}-{codes.version || '*'}
-      </Form.Item>
-    </>;
+        </Form.Item>
+        <Form.Item label="项目编号">
+          {codes.type || '***'}-{codes.industry || '***'}-{codes.location || '***'}-
+          {codes.name || '***'}-{codes.version || '*'}
+        </Form.Item>
+      </>
+    );
   };
 
   // const renderCode = () => {
@@ -253,46 +229,66 @@ function AddModal(props) {
       onCancel={onClose}
       onOk={handleOk}
     >
-      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }}>
-        <Form.Item label="项目名称">
-          {form.getFieldDecorator('project_name', {
-            initialValue: String(data.project_name || ''),
-            rules: [{ required: true, message: '请输入项目名称' }],
-          })(
-            <Input style={{ width: '100%' }}/>
-          )}
+      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} form={form}>
+        <Form.Item
+          label="项目名称"
+          name="project_name"
+          initialValue={String(data.project_name || '')}
+          rules={[{ required: true, message: '请输入项目名称' }]}
+        >
+          <Input style={{ width: '100%' }} />
         </Form.Item>
-        <Form.Item label="项目类别">
-          {form.getFieldDecorator('type_id', {
-            initialValue: String(data.type_id || ''),
-            rules: [{ required: true, message: '请选择项目类别' }],
-          })(
-            <Select style={{ width: '100%' }} onChange={changeType}>
-              {typeList.map(item => (
-                <Option key={item.id}>
-                  {item.name}({item.code})
-                </Option>
-              ))}
-            </Select>
-          )}
+        <Form.Item
+          label="项目类别"
+          name="type_id"
+          initialValue={String(data.type_id || '')}
+          rules={[{ required: true, message: '请选择项目类别' }]}
+        >
+          <Select style={{ width: '100%' }} onChange={changeType}>
+            {typeList.map(item => (
+              <Option key={item.id}>
+                {item.name}({item.code})
+              </Option>
+            ))}
+          </Select>
         </Form.Item>
-        <Form.Item label="流程">
-          {form.getFieldDecorator('flow_id', {
-            initialValue: String(data.flow_id || ''),
-            rules: [{ required: true, message: '请选择流程' }],
-          })(
-            <Select style={{ width: '100%' }} disabled>
-              {flowList
-                .filter(item => item && (item.id != 2 && item.id != 3))
-                .map(item => (
-                  <Option key={item.id}>{item.name}</Option>
-                ))}
-            </Select>
-          )}
+        <Form.Item
+          label="流程"
+          name="flow_id"
+          initialValue={String(data.flow_id || '')}
+          rules={[{ required: true, message: '请选择流程' }]}
+        >
+          <Select style={{ width: '100%' }} disabled>
+            {flowList
+              .filter(item => item && item.id != 2 && item.id != 3)
+              .map(item => (
+                <Option key={item.id}>{item.name}</Option>
+              ))}
+          </Select>
         </Form.Item>
+        {currentUser.IsSuper && (
+          <Form.Item
+            label="售前经理"
+            name="author"
+            initialValue={String(
+              data.author && data.author_dep_id ? `${data.author}||${data.author_dep_id}` : ''
+            )}
+          >
+            <TreeSelect
+              showSearch
+              allowClear
+              style={{ width: '100%' }}
+              multiple={false}
+              filterTreeNode={(input, option) => {
+                return option.props.title === input;
+              }}
+              treeData={depUserTree}
+            />
+          </Form.Item>
+        )}
         {type?.id != 7 && renderDetail()}
       </Form>
     </Modal>
   );
 }
-export default Form.create()(AddModal);
+export default AddModal;

+ 76 - 70
src/pages/PurchaseAdmin/PurchaseList/Approval/Auth.js

@@ -1,7 +1,5 @@
 import React, { useState, useEffect, useMemo } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Table, Button, Divider, Modal, Popover, Input, Select } from 'antd';
+import { Table, Button, Form, Divider, Modal, Popover, Input, Select } from 'antd';
 import moment from 'moment';
 import router from 'umi/router';
 import styles from './List.less';
@@ -21,20 +19,19 @@ const STATUS = [
     value: 1,
     label: '转执行',
   },
+  {
+    value: 2,
+    label: '转运营',
+  },
+  {
+    value: 3,
+    label: '转质保',
+  },
 ];
 
 function Auth(props) {
-  const {
-    industryList,
-    typeList,
-    data,
-    flowList,
-    currentUser,
-    depRole,
-    dispatch,
-    loading,
-    form,
-  } = props;
+  const { industryList, typeList, data, flowList, currentUser, depRole, dispatch, loading } = props;
+  const [form] = Form.useForm();
   const [visible, setVisible] = useState(false);
   const [detailVisible, setDetailVisible] = useState(false);
   const [rejectVisible, setRejectVisible] = useState(false);
@@ -51,7 +48,7 @@ function Auth(props) {
     {
       title: '分类',
       dataIndex: 'TypeInfo',
-      render: TypeInfo => TypeInfo ?`${TypeInfo.name}(${TypeInfo.code})`: "-",
+      render: TypeInfo => (TypeInfo ? `${TypeInfo.name}(${TypeInfo.code})` : '-'),
     },
     /*
     {
@@ -82,16 +79,18 @@ function Auth(props) {
       title: '状态',
       dataIndex: 'project_status',
       render: project_status => {
-        return project_status === 0 ? <>售前</> : <>转执行</>;
+        // return project_status === 0 ? <>售前</> : <>转执行</>;
         //若添加其他状态则启用以下switch case:
-        /*
-        switch (project_status){
+        switch (project_status) {
           case 0:
-            return <>{'售前'}</>;
+            return <>售前</>;
           case 1:
-            return <>{'转执行'}</>;
+            return <>转执行</>;
+          case 2:
+            return <>转运营</>;
+          case 3:
+            return <>转质保</>;
         }
-        */
       },
     },
     {
@@ -125,31 +124,33 @@ function Auth(props) {
       },
     },
     {
-      title: '创建人',
-      dataIndex: 'AuthorUser.CName',
+      title: '售前项目经理',
+      dataIndex: 'AuthorUser',
+      render: AuthorUser => (AuthorUser ? AuthorUser.CName : '-'),
     },
     {
       title: '创建时间',
       dataIndex: 'c_time',
       render: c_time => moment(c_time).format('YYYY.MM.DD'),
     },
+    {
+      title: '执行经理',
+      dataIndex: 'Leader',
+      render: Leader => (Leader ? Leader.CName : '-'),
+    },
     {
       title: '操作',
       render: record => (
         <>
-          {record.type_id != 7 && (
-            <>
-              <a
-                onClick={() => {
-                  setCurrentItem(record);
-                  setDetailVisible(true);
-                }}
-              >
-                项目详情
-              </a>
-              <Divider type="vertical" />
-            </>
-          )}
+          <a
+            onClick={() => {
+              setCurrentItem(record);
+              setDetailVisible(true);
+            }}
+          >
+            项目详情
+          </a>
+          <Divider type="vertical" />
           <a
             onClick={() => {
               setCurrentItem(record);
@@ -164,11 +165,15 @@ function Auth(props) {
   ];
 
   const canAuth = useMemo(() => {
-    let { NodeInfo, audit_status } = currentItem;
+    let { NodeInfo, audit_status, project_status } = currentItem;
     if (!NodeInfo || flowList.length == 0 || depRole.length == 0) return;
     if (audit_status != 1) return;
     let flow = flowList.find(item => item.id == NodeInfo.flow_id);
     if (!flow) return false;
+
+    if (project_status == 2) return currentItem.opt_manager_id == currentUser.ID;
+    if (project_status == 3) return currentItem.wty_manager_id == currentUser.ID;
+
     let { NodeAudits } = flow.Nodes.find(item => item.id == NodeInfo.id);
 
     const role = depRole.find(item => {
@@ -229,45 +234,46 @@ function Auth(props) {
   };
 
   const handleSearch = () => {
-    form.validateFields((error, { projectCode, projectStatus }) => {
-      // console.log(error,values);
-      let params = {};
-      params.project_code = projectCode;
-      params.project_status = projectStatus;
+    const { projectName, projectCode, projectStatus } = form.getFieldsValue();
+    // console.log(error,values);
+    let params = {};
+    params.project_name = projectName;
+    params.project_code = projectCode?.toUpperCase();
+    params.project_status = projectStatus;
 
-      dispatch({
-        type: 'approval/queryAuth',
-        payload: params,
-      });
+    dispatch({
+      type: 'approval/queryAuth',
+      payload: params,
     });
   };
 
   const renderSearch = () => {
     return (
-      <Form style={{ marginBottom: 20 }} layout="inline">
-        <Form.Item label="项目编号">
-          {form.getFieldDecorator('projectCode', {
-            initialValue: null,
-          })(<Input style={{ width: 200 }}></Input>)}
+      <Form
+        style={{ marginBottom: 20 }}
+        layout="inline"
+        initialValues={{ projectName: null, projectCode: null, projectStatus: null }}
+        form={form}
+      >
+        <Form.Item label="项目名称" name="projectName">
+          <Input style={{ width: 200 }} />
         </Form.Item>
-        <Form.Item label="状态">
-          {form.getFieldDecorator('projectStatus', {
-            initialValue: null,
-          })(
-            <Select
-              allowClear
-              showSearch
-              style={{ width: 120 }}
-              filterOption={(input, option) =>
-                option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }
-            >
-              <Option value={null}>全部</Option>
-              {STATUS.map(item => (
-                <Option key={item.value}>{item.label}</Option>
-              ))}
-            </Select>
-          )}
+        <Form.Item label="项目编号" name="projectCode">
+          <Input style={{ width: 200 }} />
+        </Form.Item>
+        <Form.Item label="状态" name="projectStatus">
+          <Select
+            showSearch
+            style={{ width: 120 }}
+            filterOption={(input, option) =>
+              option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }
+          >
+            <Option value={null}>全部</Option>
+            {STATUS.map(item => (
+              <Option key={item.value}>{item.label}</Option>
+            ))}
+          </Select>
         </Form.Item>
         <Form.Item>
           <Button type="primary" loading={loading} onClick={handleSearch}>
@@ -337,4 +343,4 @@ export default connect(({ approval, user, loading }) => ({
   currentUser: user.currentUser,
   depRole: user.depRole,
   loading: loading.models.approval,
-}))(Form.create()(Auth));
+}))(Auth);

+ 18 - 9
src/pages/PurchaseAdmin/PurchaseList/Approval/AuthModal.js

@@ -1,25 +1,34 @@
 import React, { useState, useEffect, useMemo } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Button, Modal, Steps } from 'antd';
+import { Button, Form, Modal, Steps } from 'antd';
 
 const { Step } = Steps;
 // 新建
 function AuthModal(props) {
   const { visible, onClose, onAuth, form, data, flowList = [], canAuth, loading } = props;
 
-  const folw = useMemo(() => {
+  const flow = useMemo(() => {
     if (!data.flow_id) return {};
     return flowList.find(item => item.id == data.flow_id) || {};
   }, [flowList, data]);
 
   const current = useMemo(() => {
     if (!data.node_id) return 0;
-    return folw.Nodes?.findIndex(item => item.id == data.node_id);
+    return flow.Nodes?.findIndex(item => item.id == data.node_id);
   }, [flowList, data]);
 
   const getAudits = nodeInfo => {
-    return (nodeInfo || []).map(item => item.AuthorRoleInfo.Name).join(',');
+    switch (nodeInfo.id) {
+      case 11:
+        return '执行项目经理';
+      case 12:
+        return '运营经理';
+      case 13:
+        return '执行项目经理';
+      case 14:
+        return '质保经理';
+      default:
+        return (nodeInfo.NodeAudits || []).map(item => item.AuthorRoleInfo.Name).join(',');
+    }
   };
 
   const renderFooter = () => {
@@ -42,7 +51,7 @@ function AuthModal(props) {
 
   return (
     <Modal
-      title="项目立项"
+      title="审核详情"
       width={800}
       visible={visible}
       onCancel={onClose}
@@ -50,11 +59,11 @@ function AuthModal(props) {
     >
       <Steps current={current}>
         {/* <Steps current={data?.node_id}> */}
-        {(folw.Nodes || []).map(item => (
+        {(flow.Nodes || []).map(item => (
           <Step
             key={item.id}
             title={item.node}
-            description={`审批人:${getAudits(item.NodeAudits)}`}
+            description={`审批人:${getAudits(item)}`}
           />
         ))}
       </Steps>

+ 104 - 22
src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.js

@@ -1,7 +1,8 @@
-import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Modal } from 'antd';
+import React, { useState, useEffect, useMemo } from 'react';
+import { Form, Modal, Steps } from 'antd';
+import styles from './DetailModal.less';
+
+const { Step } = Steps;
 // 新建
 function DetailModal(props) {
   const { visible, onClose, onOk, form, data, flowList = [], disabled, loading } = props;
@@ -24,31 +25,112 @@ function DetailModal(props) {
     });
   }, [data, visible]);
 
-  return (
-    <Modal title="项目立项" visible={visible} onCancel={onClose} footer={null}>
-      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }}>
-        <Form.Item label="项目名称">{data.project_name}</Form.Item>
-        {data.TypeInfo && <Form.Item label="项目类别">{data.TypeInfo?.name}</Form.Item>}
-        {data.IndustryInfo && <Form.Item label="行业名称">{data.IndustryInfo?.name}</Form.Item>}
-        <Form.Item label="流程">{flowList.find(item => item.id == data.flow_id)?.name}</Form.Item>
+  const renderDetail = () => (
+    <>
+      <div className={styles.subTitle}>项目详情</div>
+      <Form labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}>
+        <Form.Item className={styles.formItem} label="项目名称">
+          {data.project_name}
+        </Form.Item>
+        {data.TypeInfo && (
+          <Form.Item className={styles.formItem} label="项目类别">
+            {data.TypeInfo?.name}
+          </Form.Item>
+        )}
+        {data.IndustryInfo && (
+          <Form.Item className={styles.formItem} label="行业名称">
+            {data.IndustryInfo?.name}
+          </Form.Item>
+        )}
+        <Form.Item className={styles.formItem} label="流程">
+          {flowList.find(item => item.id == data.flow_id)?.name}
+        </Form.Item>
         {data.location && (
-          <Form.Item label="项目地区">
+          <Form.Item className={styles.formItem} label="项目地区">
             {data.location}({data.location_code})
           </Form.Item>
         )}
-        {data.name && <Form.Item label="项目简称">{data.name}</Form.Item>}
-
-        {data.version && <Form.Item label="项目批次">{data.version}期</Form.Item>}
-
-        <Form.Item label="审核人">{data.AuthorUser?.CName}</Form.Item>
-        <Form.Item label="所属部门">{data.AuthorDepInfo?.Name}</Form.Item>
-        {codes.type && (
-          <Form.Item label="项目编号">
-            {codes.type || '***'}-{codes.industry || '***'}-{codes.location || '***'}-
-            {codes.name || '***'}-{codes.version || '*'}
+        {data.name && (
+          <Form.Item className={styles.formItem} label="项目简称">
+            {data.name}
+          </Form.Item>
+        )}
+        {data.version && (
+          <Form.Item className={styles.formItem} label="项目批次">
+            {data.version}期
+          </Form.Item>
+        )}
+        {data.AuthorUser && (
+          <Form.Item className={styles.formItem} label="售前项目经理">
+            {data.AuthorUser.CName}
+          </Form.Item>
+        )}
+        {data.AuthorDepInfo && (
+          <Form.Item className={styles.formItem} label="所属部门">
+            {data.AuthorDepInfo.Name}
+          </Form.Item>
+        )}
+        {data.project_full_code && (
+          <Form.Item className={styles.formItem} label="项目编号">
+            {data.project_full_code}
+          </Form.Item>
+        )}
+        {data.WtyManager && (
+          <Form.Item className={styles.formItem} label="质保经理">
+            {data.WtyManager.CName}
+          </Form.Item>
+        )}
+        {data.OptManager && (
+          <Form.Item className={styles.formItem} label="运营经理">
+            {data.OptManager.CName}
           </Form.Item>
         )}
       </Form>
+    </>
+  );
+
+  const flow = useMemo(() => {
+    if (!data.flow_id) return {};
+    return flowList.find(item => item.id == data.flow_id) || {};
+  }, [flowList, data]);
+
+  const current = useMemo(() => {
+    if (!data.node_id) return 0;
+    return flow.Nodes?.findIndex(item => item.id == data.node_id);
+  }, [flowList, data]);
+
+  const getAudits = nodeInfo => {
+    switch (nodeInfo.id) {
+      case 11:
+        return '执行项目经理';
+      case 12:
+        return '运营经理';
+      case 13:
+        return '执行项目经理';
+      case 14:
+        return '质保经理';
+      default:
+        return (nodeInfo.NodeAudits || []).map(item => item.AuthorRoleInfo.Name).join(',');
+    }
+  };
+
+  const renderAuth = () => (
+    <div className={styles.authDetail}>
+      <div className={styles.subTitle}>审核详情</div>
+      <Steps className={styles.auth} current={current}>
+        {/* <Steps current={data?.node_id}> */}
+        {(flow.Nodes || []).map(item => (
+          <Step key={item.id} title={item.node} description={`审批人:${getAudits(item)}`} />
+        ))}
+      </Steps>
+    </div>
+  );
+
+  return (
+    <Modal title="项目详情" width={800} visible={visible} onCancel={onClose} footer={null}>
+      {/* {data.type_id != 7 && renderDetail()} */}
+      {renderDetail()}
+      {data.audit_status != 0 && renderAuth()}
     </Modal>
   );
 }

+ 16 - 0
src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.less

@@ -0,0 +1,16 @@
+.authDetail {
+  margin-top: 20px;
+  .auth {
+    padding-top: 10px;
+  }
+}
+
+.subTitle {
+  font-size: 20px;
+  font-weight: bold;
+  margin-bottom: 10px;
+}
+
+.formItem {
+  margin-bottom: 0;
+}

+ 35 - 74
src/pages/PurchaseAdmin/PurchaseList/Approval/ExecutionModal.js

@@ -1,18 +1,16 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Select, Modal, Input, TreeSelect } from 'antd';
-import { connect } from 'dva'
+import { Form, Select, Modal, Input, TreeSelect } from 'antd';
+import { connect } from 'dva';
 const { Option } = Select;
 const { TreeNode } = TreeSelect;
 
 function ExecutionModal(props) {
-  const { visible, onOk, onClose, form, currentItem, flowList = [], loading, depUserTree, dispatch } = props;
+  const { visible, onOk, onClose, currentItem, loading, depUserTree, dispatch } = props;
+  const [form] = Form.useForm();
 
   const handleOk = () => {
-    form.validateFields((err, {managerID, contractStatus}) => {
-      if (err) return;
-      const [exe_manager_id,dep_id] = managerID.split("||")
+    form.validateFields().then(({ managerID, contractStatus }) => {
+      const [exe_manager_id, dep_id] = managerID.split('||');
       dispatch({
         type: 'approval/startExecution',
         payload: {
@@ -22,40 +20,10 @@ function ExecutionModal(props) {
           exe_manager_id: Number(exe_manager_id),
         },
         callback: () => onOk(),
-      })
+      });
     });
   };
-
-  const onChangeManager = (id,e) => {
-    console.log(id)
-  }
-
-  const renderUserSelectTreeNodes = data => {
-    return data.map(item => {
-      if (item.children) {
-        return (
-          <TreeNode
-            title={item.title}
-            key={item.key}
-            value={item.manage || item.value}
-            dataRef={item}
-            selectable={item.selectable}
-          >
-            {renderUserSelectTreeNodes(item.children)}
-          </TreeNode>
-        );
-      }
-      return (
-        <TreeNode
-          title={item.title}
-          key={item.ID}
-          value={item.manage || item.value}
-          selectable={item.selectable}
-        />
-      );
-    });
-  };
-
+  
   return (
     <Modal
       title="转执行"
@@ -66,44 +34,37 @@ function ExecutionModal(props) {
       onCancel={onClose}
       onOk={handleOk}
     >
-      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }}>
-        <Form.Item label="项目经理">
-          {form.getFieldDecorator('managerID', {
-            rules: [
-              {
-                required: true,
-                message: '请选择项目经理',
-              },
-            ],
-          })(
-            <TreeSelect
-              showSearch
-              allowClear
-              style={{ width: '100%' }}
-              placeholder="请选择项目经理"
-              multiple={false}
-              filterTreeNode={(input, option) => {
-                return option.props.title === input;
-              }}
-              onChange={onChangeManager}
-            >
-              {renderUserSelectTreeNodes(depUserTree)}
-            </TreeSelect>
-          )}
+      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} form={form}>
+        <Form.Item
+          label="项目经理"
+          name="managerID"
+          rules={[{ required: true, message: '请选择项目经理' }]}
+        >
+          <TreeSelect
+            showSearch
+            allowClear
+            style={{ width: '100%' }}
+            placeholder="请选择项目经理"
+            multiple={false}
+            filterTreeNode={(input, option) => {
+              return option.props.title === input;
+            }}
+            treeData={depUserTree}
+          />
         </Form.Item>
 
-        <Form.Item label="合同状态">
-          {form.getFieldDecorator('contractStatus', {
-            rules: [{ required: true, message: '请选择合同状态' }],
-          })(
-            <Select style={{ width: '100%' }}>
-              <Option key={0}>无合同</Option>
-              <Option key={1}>有合同</Option>
-            </Select>
-          )}
+        <Form.Item
+          label="合同状态"
+          name="contractStatus"
+          rules={[{ required: true, message: '请选择合同状态' }]}
+        >
+          <Select style={{ width: '100%' }}>
+            <Option key={0}>无合同</Option>
+            <Option key={1}>有合同</Option>
+          </Select>
         </Form.Item>
       </Form>
     </Modal>
   );
 }
-export default connect()(Form.create()(ExecutionModal));
+export default connect()(ExecutionModal);

+ 112 - 63
src/pages/PurchaseAdmin/PurchaseList/Approval/List.js

@@ -1,7 +1,5 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Table, Button, Select, Divider, Modal, Popover, Input, Checkbox } from 'antd';
+import { Table, Button, Form, Select, Divider, Modal, Popover, Input, Checkbox } from 'antd';
 import moment from 'moment';
 import router from 'umi/router';
 import styles from './List.less';
@@ -23,6 +21,14 @@ const STATUS = [
     value: 1,
     label: '转执行',
   },
+  {
+    value: 2,
+    label: '转运营',
+  },
+  {
+    value: 3,
+    label: '转质保',
+  },
 ];
 
 function List(props) {
@@ -34,10 +40,10 @@ function List(props) {
     currentUser,
     dispatch,
     loading,
-    form,
     depUserTree,
     member,
   } = props;
+  const [form] = Form.useForm();
   const [addVisible, setAddVisible] = useState(false);
   const [detailVisible, setDetailVisible] = useState(false);
   const [executionVisible, setExecutionVisible] = useState(false);
@@ -89,16 +95,18 @@ function List(props) {
       title: '状态',
       dataIndex: 'project_status',
       render: project_status => {
-        return project_status === 0 ? <>售前</> : <>转执行</>;
+        // return project_status === 0 ? <>售前</> : <>转执行</>;
         //若添加其他状态则启用以下switch case:
-        /*
-        switch (project_status){
+        switch (project_status) {
           case 0:
             return <>售前</>;
           case 1:
             return <>转执行</>;
+          case 2:
+            return <>转运营</>;
+          case 3:
+            return <>转质保</>;
         }
-        */
       },
     },
     {
@@ -132,14 +140,20 @@ function List(props) {
       },
     },
     {
-      title: '创建人',
-      dataIndex: 'AuthorUser.CName',
+      title: '售前项目经理',
+      dataIndex: 'AuthorUser',
+      render: AuthorUser => (AuthorUser ? AuthorUser.CName : '-'),
     },
     {
       title: '创建时间',
       dataIndex: 'c_time',
       render: c_time => moment(c_time).format('YYYY.MM.DD'),
     },
+    {
+      title: '执行经理',
+      dataIndex: 'Leader',
+      render: Leader => (Leader ? Leader.CName : '-'),
+    },
     {
       title: '操作',
       render: record => renderEditBtns(record),
@@ -147,17 +161,16 @@ function List(props) {
   ];
 
   const handleSearch = () => {
-    form.validateFields((error, { projectCode, projectStatus }) => {
-      // console.log(error,values);
-      let params = {};
-      params.project_code = projectCode;
-      params.project_status = projectStatus;
-      params.currentPage = 1;
+    const { projectName, projectCode, projectStatus } = form.getFieldsValue();
+    let params = {};
+    params.project_name = projectName;
+    params.project_code = projectCode?.toUpperCase();
+    params.project_status = projectStatus;
+    params.currentPage = 1;
 
-      dispatch({
-        type: 'approval/queryApproval',
-        payload: params,
-      });
+    dispatch({
+      type: 'approval/queryApproval',
+      payload: params,
     });
   };
 
@@ -176,30 +189,30 @@ function List(props) {
 
   const renderSearch = () => {
     return (
-      <Form layout="inline">
-        <Form.Item label="项目编号">
-          {form.getFieldDecorator('projectCode', {
-            initialValue: null,
-          })(<Input style={{ width: 200 }}></Input>)}
+      <Form
+        form={form}
+        layout="inline"
+        initialValues={{ projectName: null, projectCode: null, projectStatus: null }}
+      >
+        <Form.Item label="项目名称" name="projectName">
+          <Input style={{ width: 200 }} />
+        </Form.Item>
+        <Form.Item label="项目编号" name="projectCode">
+          <Input style={{ width: 200 }} />
         </Form.Item>
-        <Form.Item label="状态">
-          {form.getFieldDecorator('projectStatus', {
-            initialValue: null,
-          })(
-            <Select
-              allowClear
-              showSearch
-              style={{ width: 120 }}
-              filterOption={(input, option) =>
-                option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-              }
-            >
-              <Option value={null}>全部</Option>
-              {STATUS.map(item => (
-                <Option key={item.value}>{item.label}</Option>
-              ))}
-            </Select>
-          )}
+        <Form.Item label="状态" name="projectStatus">
+          <Select
+            showSearch
+            style={{ width: 120 }}
+            filterOption={(input, option) =>
+              option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+            }
+          >
+            <Option value={null}>全部</Option>
+            {STATUS.map(item => (
+              <Option key={item.value}>{item.label}</Option>
+            ))}
+          </Select>
         </Form.Item>
         <Form.Item>
           <Button type="primary" loading={loading} onClick={handleSearch}>
@@ -361,39 +374,75 @@ function List(props) {
       </>
     );
     let { audit_status, project_status, type_id } = record;
+    //权限审核
+    let canEdit = () => {
+      if (currentUser.IsSuper) return true;
+      switch (audit_status) {
+        case 0:
+          return currentUser.ID == record.author;
+        case 1:
+          return false;
+        case 2:
+          if (project_status == 0) return currentUser.ID == record.author;
+          if (project_status == 1) return currentUser.ID == record.LeaderId;
+          return false;
+        case 3:
+          switch (project_status) {
+            case 0:
+              return currentUser.ID == record.author;
+            case 1:
+              return currentUser.ID == record.LeaderId;
+            case 2:
+              return currentUser.ID == record.LeaderId || currentUser.ID == record.opt_manager_id;
+            case 3:
+              return currentUser.ID == record.LeaderId || currentUser.ID == record.wty_manager_id;
+          }
+          return false;
+      }
+    };
     let toReturn = [];
-    if (type_id != 7) dividerPush(detailBtn, toReturn);
+    dividerPush(detailBtn, toReturn);
     switch (audit_status) {
       //未提交
       case 0:
-        if (currentUser.ID == record.author || currentUser.IsSuper) dividerPush(editBtn, toReturn);
+        canEdit() && dividerPush(editBtn, toReturn);
         break;
       //审核中
       case 1:
         break;
       //审核拒绝
       case 2:
-        if (project_status == 0 && (currentUser.ID == record.author || currentUser.IsSuper))
-          dividerPush(editBtn, toReturn);
-        else if (
-          project_status == 1 &&
-          (currentUser.ID == record.LeaderId || currentUser.IsSuper)
-        ) {
+        if (project_status == 0 && canEdit()) dividerPush(editBtn, toReturn);
+        else if (project_status == 1 && canEdit()) {
           dividerPush(memberBtn, toReturn);
           dividerPush(statusBtn, toReturn);
         }
         break;
       //审核通过
       case 3:
-        if (project_status == 0 && (currentUser.ID == record.author || currentUser.IsSuper)) {
-          dividerPush(memberBtn, toReturn);
-          dividerPush(executionBtn, toReturn);
-        } else if (
-          project_status == 1 &&
-          (currentUser.ID == record.LeaderId || currentUser.IsSuper)
-        ) {
-          dividerPush(memberBtn, toReturn);
-          dividerPush(statusBtn, toReturn);
+        switch (project_status) {
+          //售前
+          case 0:
+            if (canEdit()) {
+              dividerPush(memberBtn, toReturn);
+              dividerPush(executionBtn, toReturn);
+            }
+            break;
+          //转执行
+          case 1:
+            if (canEdit()) {
+              dividerPush(memberBtn, toReturn);
+              dividerPush(statusBtn, toReturn);
+            }
+            break;
+          //转运营
+          case 2:
+            canEdit() && dividerPush(memberBtn, toReturn);
+            break;
+          //转质保
+          case 3:
+            canEdit() && dividerPush(memberBtn, toReturn);
+            break;
         }
         break;
     }
@@ -443,6 +492,8 @@ function List(props) {
         onChange={queryList}
       />
       <ApprovalModal
+        currentUser={currentUser}
+        depUserTree={depUserTree}
         loading={loading}
         industryList={industryList}
         flowList={flowList}
@@ -464,7 +515,6 @@ function List(props) {
       <ExecutionModal
         depUserTree={depUserTree}
         loading={loading}
-        flowList={flowList}
         visible={executionVisible}
         currentItem={currentItem}
         onOk={() => setExecutionVisible(false)}
@@ -481,7 +531,6 @@ function List(props) {
       <QualityOperateModal
         depUserTree={depUserTree}
         loading={loading}
-        flowList={flowList}
         visible={qualityOperateVisible}
         currentItem={currentItem}
         onOk={() => setQualityOperateVisible(false)}
@@ -501,4 +550,4 @@ export default connect(({ approval, user, loading }) => ({
   loading: loading.models.approval,
   depUserTree: approval.depUserTree,
   member: approval.member,
-}))(Form.create()(List));
+}))(List);

+ 33 - 81
src/pages/PurchaseAdmin/PurchaseList/Approval/MemberModal.js

@@ -1,40 +1,11 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Modal, TreeSelect, Table, Button } from 'antd';
+import { Form, Modal, TreeSelect, Table, Button, Input } from 'antd';
 import { connect } from 'dva';
 const { TreeNode } = TreeSelect;
 
-//测试用临时数据
-const tempData = [
-  {
-    name: 'aaa',
-    phone: '111',
-    email: 'aaa@a.com',
-  },
-  {
-    name: 'bbb',
-    phone: '222',
-    email: 'bbb@b.com',
-  },
-  {
-    name: 'ccc',
-    phone: '333',
-    email: 'ccc@c.com',
-  },
-];
-
 function MemberModal(props) {
-  const {
-    visible,
-    onClose,
-    form,
-    currentItem,
-    loading,
-    depUserTree,
-    dataSource,
-    dispatch,
-  } = props;
+  const { visible, onClose, currentItem, loading, depUserTree, dataSource, dispatch } = props;
+  const [form] = Form.useForm();
   const [currentMember, setCurrentMember] = useState({});
 
   const columns = [
@@ -53,36 +24,14 @@ function MemberModal(props) {
     {
       title: '操作',
       //移除按钮,此处应传入当前成员的数据
-      render: member => <a onClick={() => onDelete(member)}>移除</a>,
+      render: member =>
+        member.ID != currentItem.author &&
+        member.ID != currentItem.LeaderId &&
+        member.ID != currentItem.wty_manager_id &&
+        member.ID != currentItem.opt_manager_id && <a onClick={() => onDelete(member)}>移除</a>,
     },
   ];
 
-  const renderUserSelectTreeNodes = data => {
-    return data.map(item => {
-      if (item.children) {
-        return (
-          <TreeNode
-            title={item.title}
-            key={item.key}
-            value={item.value}
-            dataRef={item}
-            selectable={item.selectable}
-          >
-            {renderUserSelectTreeNodes(item.children)}
-          </TreeNode>
-        );
-      }
-      return (
-        <TreeNode
-          title={item.title}
-          key={item.ID}
-          value={item.value}
-          selectable={item.selectable}
-        />
-      );
-    });
-  };
-
   const onDelete = item => {
     Modal.confirm({
       title: '移除成员',
@@ -100,17 +49,19 @@ function MemberModal(props) {
   };
 
   const handleAddMember = () => {
-    form.validateFields((error, { memberID }) => {
-      if (error) return;
+    form.validateFields().then(({ memberID }) => {
       dispatch({
         type: 'approval/addMember',
         payload: {
           project_code_id: currentItem.id,
-          user_id: memberID,
+          user_id: Number(memberID.split('||')[0]),
+        },
+        callback: () => {
+          form.resetFields();
         },
       });
     });
-    form.resetFields();
+    // form.resetFields();
   };
 
   return (
@@ -130,24 +81,25 @@ function MemberModal(props) {
         width="100%"
         style={{ marginBottom: 20 }}
         layout="inline"
+        form={form}
       >
-        <Form.Item label="添加成员">
-          {form.getFieldDecorator('memberID', {
-            initialValue: null,
-          })(
-            <TreeSelect
-              showSearch
-              allowClear
-              style={{ width: 240 }}
-              placeholder="请选择项目成员"
-              multiple={false}
-              filterTreeNode={(input, option) => {
-                return option.props.title === input;
-              }}
-            >
-              {renderUserSelectTreeNodes(depUserTree)}
-            </TreeSelect>
-          )}
+        <Form.Item
+          label="添加成员"
+          name="memberID"
+          initialValue={null}
+          rules={[{ required: true, message: '请选择成员' }]}
+        >
+          <TreeSelect
+            showSearch
+            allowClear
+            style={{ width: 240 }}
+            placeholder="请选择项目成员"
+            multiple={false}
+            treeData={depUserTree}
+            filterTreeNode={(input, option) => {
+              return option.props.title === input;
+            }}
+          />
         </Form.Item>
         <Form.Item>
           <Button type="primary" loading={loading} onClick={handleAddMember}>
@@ -160,4 +112,4 @@ function MemberModal(props) {
   );
 }
 
-export default connect()(Form.create()(MemberModal));
+export default connect()(MemberModal);

+ 39 - 75
src/pages/PurchaseAdmin/PurchaseList/Approval/QualityOperateModal.js

@@ -1,7 +1,5 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Select, Modal, Input, TreeSelect } from 'antd';
+import { Form, Select, Modal, Input, TreeSelect } from 'antd';
 import { connect } from 'dva';
 const { Option } = Select;
 const { TreeNode } = TreeSelect;
@@ -11,59 +9,30 @@ function QualityOperateModal(props) {
     visible,
     onOk,
     onClose,
-    form,
     currentItem,
-    flowList = [],
     loading,
     depUserTree,
     dispatch,
     qualityOperate,
   } = props;
+  const [form] = Form.useForm();
 
-  //   const handleOk = () => {
-  //     form.validateFields((err, {managerID, contractStatus}) => {
-  //       if (err) return;
-  //       const [exe_manager_id,dep_id] = managerID.split("||")
-  //       dispatch({
-  //         type: 'approval/startExecution',
-  //         payload: {
-  //           project_code_id: currentItem.id,
-  //           with_contract: Number(contractStatus),
-  //           dep_id: Number(dep_id),
-  //           exe_manager_id: Number(exe_manager_id),
-  //         },
-  //         callback: () => onOk(),
-  //       })
-  //     });
-  //   };
-
-  const onChangeManager = (id, e) => {
-    console.log(id);
-  };
-
-  const renderUserSelectTreeNodes = data => {
-    return data.map(item => {
-      if (item.children) {
-        return (
-          <TreeNode
-            title={item.title}
-            key={item.key}
-            value={item.manage || item.value}
-            dataRef={item}
-            selectable={item.selectable}
-          >
-            {renderUserSelectTreeNodes(item.children)}
-          </TreeNode>
-        );
-      }
-      return (
-        <TreeNode
-          title={item.title}
-          key={item.ID}
-          value={item.manage || item.value}
-          selectable={item.selectable}
-        />
-      );
+  const handleOk = () => {
+    form.validateFields().then(({ managerID }) => {
+      const [manager_id, dep_id] = managerID.split('||');
+      let params = {};
+      params.type = qualityOperate ? 'approval/startOperate' : 'approval/startQuality';
+      params.payload = {
+        project_code_id: currentItem.id,
+        dep_id: Number(dep_id),
+      };
+      qualityOperate
+        ? (params.payload.opt_manager_id = Number(manager_id))
+        : (params.payload.wty_manager_id = Number(manager_id));
+      dispatch({
+        ...params,
+        callback: () => onOk(),
+      });
     });
   };
 
@@ -75,35 +44,30 @@ function QualityOperateModal(props) {
       destroyOnClose
       visible={visible}
       onCancel={onClose}
-      onOk={onOk}
+      onOk={handleOk}
     >
-      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }}>
-        <Form.Item label={qualityOperate ? '运营经理' : '质保经理'}>
-          {form.getFieldDecorator('managerID', {
-            rules: [
-              {
-                required: true,
-                message: qualityOperate ? '请选择运营经理' : '请选择质保经理',
-              },
-            ],
-          })(
-            <TreeSelect
-              showSearch
-              allowClear
-              style={{ width: '100%' }}
-              placeholder={qualityOperate ? '请选择运营经理' : '请选择质保经理'}
-              multiple={false}
-              filterTreeNode={(input, option) => {
-                return option.props.title === input;
-              }}
-              onChange={onChangeManager}
-            >
-              {renderUserSelectTreeNodes(depUserTree)}
-            </TreeSelect>
-          )}
+      <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} form={form}>
+        <Form.Item
+          label={qualityOperate ? '运营经理' : '质保经理'}
+          name="managerID"
+          rules={[
+            { required: true, message: qualityOperate ? '请选择运营经理' : '请选择质保经理' },
+          ]}
+        >
+          <TreeSelect
+            showSearch
+            allowClear
+            style={{ width: '100%' }}
+            placeholder={qualityOperate ? '请选择运营经理' : '请选择质保经理'}
+            multiple={false}
+            filterTreeNode={(input, option) => {
+              return option.props.title === input;
+            }}
+            treeData={depUserTree}
+          ></TreeSelect>
         </Form.Item>
       </Form>
     </Modal>
   );
 }
-export default connect()(Form.create()(QualityOperateModal));
+export default connect()(QualityOperateModal);

+ 24 - 7
src/pages/PurchaseAdmin/PurchaseList/Approval/models/approval.js

@@ -13,6 +13,8 @@ import {
   addMember,
   queryMember,
   startExecution,
+  startOperate,
+  startQuality,
   deleteMember,
 } from '@/services/approval';
 import { message } from 'antd';
@@ -27,17 +29,17 @@ function getDepUserTree(data) {
 
   if (data.children) {
     data.children.forEach(item => {
-      getDepUserTree(item, false);
+      getDepUserTree(item);
     });
   }
 
   if (data.Users && data.Users.length !== 0) {
     data.Users.forEach(item => {
       item.title = item.CName;
-      item.key = item.ID;
-      item.value = item.ID;
-      item.manage =  item.ID + "||" + data.ID
+      item.key = item.ID + '||' + data.ID;
+      item.value = item.ID + '||' + data.ID;
       item.selectable = true;
+      item.DepId = data.ID;
       data.children.push(item);
     });
   }
@@ -130,7 +132,6 @@ export default {
       });
     },
     *queryMember({ payload }, { call, put }) {
-      console.log(111);
       const { data } = yield call(queryMember, payload);
       if (!data) return;
       yield put({
@@ -156,10 +157,8 @@ export default {
     },
     *createApproval({ payload, callback }, { call, put }) {
       const res = yield call(createApproval, payload);
-      console.log(res);
       if (res) {
         const { data } = res;
-        console.log(data);
         callback && callback();
         message.success('创建成功');
         yield put({
@@ -223,6 +222,24 @@ export default {
         type: 'queryApproval',
       });
     },
+    *startOperate({ payload, callback }, { call, put }) {
+      const res = yield call(startOperate, payload);
+      if (!res) return;
+      callback && callback();
+      message.success('转运营送审成功');
+      yield put({
+        type: 'queryApproval',
+      });
+    },
+    *startQuality({ payload, callback }, { call, put }) {
+      const res = yield call(startQuality, payload);
+      if (!res) return;
+      callback && callback();
+      message.success('转质保送审成功');
+      yield put({
+        type: 'queryApproval',
+      });
+    },
   },
 
   reducers: {

+ 33 - 17
src/pages/PurchaseAdmin/PurchaseList/Index.js

@@ -25,6 +25,20 @@ function LayoutDetail(props) {
       type: 'user/fetchCurrent',
     });
   }, []);
+  const checkReport = state => {
+    if (isAdmin) return true;
+    const manager = currentUser.is_leader || currentUser.is_opt_mgr || currentUser.is_wty_mgr;
+    switch (state) {
+      case 0:
+        return currentUser.is_accountant || manager || permission['func-01-point-works-report'];
+      case 1:
+        return manager || permission['func-01-point-works-report-p'];
+      case 2:
+        return permission['func-01-point-works-report-d'];
+      case 3:
+        return currentUser.is_accountant || permission['func-01-point-works-report-p-s'];
+    }
+  };
   return (
     <Layout>
       <Header>
@@ -37,7 +51,7 @@ function LayoutDetail(props) {
               defaultSelectedKeys={[props.location.pathname]}
               style={{ lineHeight: '64px', width: '100%' }}
             >
-              {/* <SubMenu key="/home/work-hours" title="工时管理">
+              <SubMenu key="/home/work-hours" title="工时管理">
                 <Menu.Item key="/home/work-hours">
                   <Link to="/home/work-hours">上报工时</Link>
                 </Menu.Item>
@@ -54,33 +68,35 @@ function LayoutDetail(props) {
                   <Link to="/home/approval/auth">审核列表</Link>
                 </Menu.Item>
               </SubMenu>
-      
-              {(isAdmin ||
-                currentUser.is_leader ||
-                currentUser.is_accountant ||
-                permission['func-01-point-works-report']) && (
+
+              {checkReport(0) && (
                 <SubMenu key="/home/report" title="工时报表">
-                  {(isAdmin ||
-                    currentUser.is_leader ||
-                    currentUser.is_accountant ||
-                    permission['func-01-point-works-report-p'] ||
-                    permission['func-01-point-works-report-p-s']) && (
+                  {/* <Menu.Item key="/home/report/resource">
+                  <Link to="/home/report/resource">资源报表</Link>
+                </Menu.Item> */}
+                  {checkReport(1) && (
                     <Menu.Item key="/home/report/project">
                       <Link to="/home/report/project">项目报表</Link>
                     </Menu.Item>
                   )}
-                  {(isAdmin || permission['func-01-point-works-report-d']) && (
+                  {checkReport(2) && (
                     <Menu.Item key="/home/report/department">
                       <Link to="/home/report/department">部门报表</Link>
                     </Menu.Item>
                   )}
+                  {checkReport(3) && (
+                    <Menu.Item key="/home/report/finance">
+                      <Link to="/home/report/finance">财务报表</Link>
+                    </Menu.Item>
+                  )}
                 </SubMenu>
+              )}
+
+              {/* {isAdmin && (
+              <Menu.Item key="/home">
+                <Link to="/home">采购清单</Link>
+              </Menu.Item>
               )} */}
-              {/* {isAdmin && ( */}
-                <Menu.Item key="/home">
-                  <Link to="/home">采购清单</Link>
-                </Menu.Item>
-              {/* )} */}
               <Menu.Item key="/home/flow-list">
                 <Link to="/home/flow-list">流程图</Link>
               </Menu.Item>

+ 176 - 0
src/pages/PurchaseAdmin/PurchaseList/Report/DepCompareModal.js

@@ -0,0 +1,176 @@
+import React, { useState, useEffect } from 'react';
+import { Modal, Table } from 'antd';
+import { connect } from 'dva';
+import moment from 'moment';
+import { set } from 'lodash';
+
+function DepCompareModal(props) {
+  const {
+    dispatch,
+    visible,
+    onOk,
+    onCancel,
+    depCompare,
+    depUserProject,
+    depUser,
+    filter,
+    loading,
+  } = props;
+  const [userVisible, setUserVisible] = useState(false);
+  //本部门
+  const columns = [
+    { title: '用户名称', dataIndex: 'c_name' },
+    { title: '员工号', dataIndex: 'user_name' },
+    { title: '执行项目人日', dataIndex: 'type_project_cnt' },
+    { title: '售前支持', dataIndex: 'type_sale_cnt' },
+    { title: '市场品牌', dataIndex: 'type_market_cnt' },
+    { title: '日常', dataIndex: 'type_normal_cnt' },
+    { title: '标准化', dataIndex: 'type_standardize_cnt' },
+    { title: '研发', dataIndex: 'type_rd_cnt' },
+    { title: '漏填工时', dataIndex: 'type_lost_cnt' },
+    { title: '总计', dataIndex: 'total_cnt' },
+    {
+      title: '有效利用率',
+      dataIndex: 'usage_percent',
+      render: (percent = 0) => (percent * 100).toFixed(2) + '%',
+    },
+  ];
+  // 其他部门
+  const columnsDep = [
+    {
+      width: 350,
+      render: record =>
+        // record.dep_name || <a onClick={() => onClickUser(record)}>{record.c_name}</a>,
+        record.dep_name || record.c_name,
+    },
+    { title: '执行项目', dataIndex: 'type_project_cnt' },
+    { title: '售前项目', dataIndex: 'type_sale_cnt' },
+    { title: '研发项目', dataIndex: 'type_rd_cnt' },
+    { title: '运营项目', dataIndex: 'type_opt_cnt' },
+    { title: '质保项目', dataIndex: 'type_wty_cnt' },
+    { title: '总计', dataIndex: 'total_cnt' },
+  ];
+  const columnsUser = [
+    { title: '项目名称', dataIndex: 'project_name' },
+    { title: '总工时', dataIndex: 'total_cnt' },
+  ];
+
+  const onChangePage = pagination => {
+    dispatch({
+      type: 'report/queryUserReport',
+      payload: {
+        ...filter,
+        currentPage: pagination.current,
+      },
+    });
+  };
+
+  const onExpand = (expanded, record) => {
+    if (expanded && !record.isLoad) {
+      dispatch({
+        type: 'report/queryDepCompareUser',
+        payload: {
+          s_time: filter.s_time,
+          e_time: filter.e_time,
+          project_dep_id: filter.dep_id,
+          record: record,
+        },
+      });
+    }
+  };
+
+  const onClickUser = user => {
+    dispatch({
+      type: 'report/queryDepUserProject',
+      payload: {
+        s_time: filter.s_time,
+        e_time: filter.e_time,
+        project_dep_id: filter.dep_id,
+        dep_id: user.dep_id,
+        user_id: user.user_id,
+      },
+    });
+    setUserVisible(true);
+  };
+
+  useEffect(() => {
+    if (!filter?.dep_id) return;
+    dispatch({
+      type: 'report/queryUserReport',
+      payload: filter,
+    });
+    dispatch({
+      type: 'report/queryDepCompare',
+      payload: filter,
+    });
+  }, [filter]);
+
+  return (
+    <>
+      <Modal
+        title="部门对账单"
+        width="80%"
+        visible={visible}
+        onCancel={onCancel}
+        footer={false}
+        destroyOnClose
+      >
+        <Table
+          title={() => '本部门工时详情'}
+          columns={columns}
+          loading={loading}
+          dataSource={depUser.list}
+          pagination={depUser.pagination}
+          onChange={onChangePage}
+        ></Table>
+        {/* <Table
+          title={() => '本部门在所属项目下产生的工时'}
+          columns={columns}
+          loading={loading}
+          dataSource={depCompare.length == 0 ? [] : [depCompare[0]]}
+          rowKey="key"
+          childrenColumnName="child"
+          pagination={false}
+          onExpand={onExpand}
+        /> */}
+        {console.log(depCompare)}
+        {depCompare.length > 0 && (
+          <Table
+            title={() => '其他部门在所属项目下产生的工时'}
+            columns={columnsDep}
+            loading={loading}
+            dataSource={depCompare}
+            rowKey="key"
+            childrenColumnName="child"
+            pagination={false}
+            onExpand={onExpand}
+          />
+        )}
+      </Modal>
+
+      {/* <Modal
+        title="用户详情"
+        width="80%"
+        visible={userVisible}
+        onCancel={() => setUserVisible(false)}
+        footer={false}
+        destroyOnClose
+      >
+        <Table
+          columns={columnsUser}
+          loading={loading}
+          dataSource={depUserProject}
+          pagination={false}
+          rowKey="project_name"
+        ></Table>
+      </Modal> */}
+    </>
+  );
+}
+
+export default connect(({ report, loading }) => ({
+  depCompare: report.depCompare,
+  depUserProject: report.depUserProject,
+  depUser: report.depUser,
+  loading: loading.models.report,
+}))(DepCompareModal);

+ 31 - 41
src/pages/PurchaseAdmin/PurchaseList/Report/Department.js

@@ -1,23 +1,24 @@
 import React, { useEffect, useState, useRef } from 'react';
 import { connect } from 'dva';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Table, DatePicker, Input, Button } from 'antd';
+import { Form, Table, DatePicker, Input, Button } from 'antd';
 import styles from './report.less';
 import UserRptModal from './UserRptModal';
+import DepCompareModal from './DepCompareModal';
 import moment from 'moment';
-import { downloadFile, getToken } from '@/utils/utils.js'
+import { downloadFile, getToken } from '@/utils/utils.js';
 
 const { RangePicker } = DatePicker;
 
 function Department(props) {
-  const { dispatch, form, loading, dep } = props;
+  const { dispatch, loading, dep } = props;
+  const [form] = Form.useForm();
   const [visible, setVisible] = useState(false);
   const [modalFilter, setModalFilter] = useState({});
   const columns = [
     {
       title: '部门名称',
-      render: record => <a onClick={() => showUserModal(record)}>{record.dep_name}</a>,
+      // render: record => <a onClick={() => showUserModal(record)}>{record.dep_name}</a>,
+      render: record => <a onClick={() => showDepCompare(record)}>{record.dep_name}</a>,
     },
     {
       title: '执行项目人日',
@@ -67,46 +68,32 @@ function Department(props) {
     // },
   ];
   const filterRef = useRef({ pageSize: 99999 });
-  const onChangePage = pagination => {
+  const handleSearch = () => {
+    const { time } = form.getFieldsValue();
+    filterRef.current.s_time = time[0] ? moment(time[0]).format('YYYY-MM-DD') : null;
+    filterRef.current.e_time = time[1] ? moment(time[1]).format('YYYY-MM-DD') : null;
+
     dispatch({
-      type: 'report/queryUserReport',
+      type: 'report/queryDepReport',
       payload: {
-        ...filterRef.current,
-        currentPage: pagination.current,
+        filter: filterRef.current,
       },
     });
   };
-  const handleSearch = () => {
-    form.validateFields((error, { time }) => {
-      filterRef.current.s_time = time[0] ? moment(time[0]).format('YYYY-MM-DD') : null;
-      filterRef.current.e_time = time[1] ? moment(time[1]).format('YYYY-MM-DD') : null;
-
-      dispatch({
-        type: 'report/queryDepReport',
-        payload: {
-          filter: filterRef.current,
-        },
-      });
-    });
-  };
   const handleDownload = () => {
     const token = getToken();
-    const s_time = !(filterRef.current.s_time) ? '' : filterRef.current.s_time;
-    const e_time = !(filterRef.current.e_time) ? '' : filterRef.current.e_time;
-    downloadFile(`/api/v2/workload/rpt/dep/export2excel?JWT-TOKEN=${token}&s_time=${s_time}&e_time=${e_time}`, `项目报表${moment().format('YYYYMMDDHHMMSS')}.xlsx`)
+    const s_time = !filterRef.current.s_time ? '' : filterRef.current.s_time;
+    const e_time = !filterRef.current.e_time ? '' : filterRef.current.e_time;
+    downloadFile(
+      `/api/v2/workload/rpt/dep/export2excel?JWT-TOKEN=${token}&s_time=${s_time}&e_time=${e_time}`,
+      `项目报表${moment().format('YYYYMMDDHHMMSS')}.xlsx`
+    );
   };
   const renderSearch = () => {
-    const formItemLayout = {
-      labelCol: { span: 5 },
-      wrapperCol: { span: 18 },
-    };
-
     return (
-      <Form layout="inline" {...formItemLayout}>
-        <Form.Item label="时间">
-          {form.getFieldDecorator('time', {
-            initialValue: [moment().startOf('years'), moment().endOf('years')],
-          })(<RangePicker placeholder="选择时间" />)}
+      <Form layout="inline" form={form}>
+        <Form.Item label="时间" name="time" initialValue={[moment().startOf('years'), moment()]}>
+          <RangePicker placeholder="选择时间" allowClear={false} />
         </Form.Item>
         <Form.Item>
           <Button type="primary" loading={loading} onClick={handleSearch}>
@@ -127,7 +114,8 @@ function Department(props) {
       });
     }
   };
-  const showUserModal = item => {
+  // const showUserModal = item => {
+  const showDepCompare = item => {
     const { s_time, e_time } = filterRef.current;
     setModalFilter({
       s_time: s_time,
@@ -147,7 +135,9 @@ function Department(props) {
     <div>
       <div className={styles.topPart}>
         {renderSearch()}
-        <Button type="primary" onClick={handleDownload}>导出</Button>
+        <Button type="primary" onClick={handleDownload}>
+          导出
+        </Button>
       </div>
       <Table
         loading={loading}
@@ -156,10 +146,10 @@ function Department(props) {
         columns={columns}
         dataSource={dep.list}
         pagination={false}
-        onChange={onChangePage}
         onExpand={onExpand}
       />
-      <UserRptModal filter={modalFilter} visible={visible} onCancel={() => setVisible(false)} />
+      {/* <UserRptModal filter={modalFilter} visible={visible} onCancel={() => setVisible(false)} /> */}
+      <DepCompareModal filter={modalFilter} visible={visible} onCancel={() => setVisible(false)} />
     </div>
   );
 }
@@ -167,4 +157,4 @@ function Department(props) {
 export default connect(({ report, loading }) => ({
   dep: report.dep,
   loading: loading.models.report,
-}))(Form.create()(Department));
+}))(Department);

+ 122 - 0
src/pages/PurchaseAdmin/PurchaseList/Report/Finance.js

@@ -0,0 +1,122 @@
+import React, { useEffect, useState, useRef } from 'react';
+import { connect } from 'dva';
+import { Form, Table, DatePicker, Input, Button, Select } from 'antd';
+import styles from './report.less';
+import moment from 'moment';
+import { downloadFile, getToken } from '@/utils/utils.js';
+
+const { RangePicker } = DatePicker;
+
+function Finance(props) {
+  const { dispatch, loading, finance } = props;
+  const [form] = Form.useForm();
+  const [modalFilter, setModalFilter] = useState({});
+  const columns = [
+    { title: '资源名称', dataIndex: 'c_name' },
+    { title: '资源编号', dataIndex: 'user_name' },
+    { title: '资源归属部门', dataIndex: 'dep_name' },
+    { title: '项目名称', dataIndex: 'project_name' },
+    { title: '项目编号', dataIndex: 'project_code' },
+    { title: '项目状态', dataIndex: 'project_status' },
+    { title: '项目归属部门', dataIndex: 'project_dep_name' },
+    { title: '工时类型', dataIndex: 'type_name' },
+    { title: '保存未提交', dataIndex: 'un_audit_cnt' },
+    { title: '提交未审批', dataIndex: 'pending_audit_cnt' },
+    { title: '已拒绝', dataIndex: 'refuse_audit_cnt' },
+    { title: '审批通过', dataIndex: 'pass_audit_cnt' },
+  ];
+  const STATUS = [
+    { value: 0, label: '售前' },
+    { value: 1, label: '转执行' },
+    { value: 2, label: '转运营' },
+    { value: 3, label: '转质保' },
+  ];
+  const filterRef = useRef({ pageSize: 20 });
+  const onChangePage = pagination => {
+    dispatch({
+      type: 'report/queryFinanceReport',
+      payload: {
+        ...filterRef.current,
+        currentPage: pagination.current,
+      },
+    });
+  };
+  const handleSearch = () => {
+    const { time, project_name, project_status } = form.getFieldsValue();
+    filterRef.current.s_time = time[0] ? moment(time[0]).format('YYYY-MM-DD') : null;
+    filterRef.current.e_time = time[1] ? moment(time[1]).format('YYYY-MM-DD') : null;
+    filterRef.current.project_name = project_name;
+    filterRef.current.project_status = project_status;
+
+    dispatch({
+      type: 'report/queryFinanceReport',
+      payload: {
+        ...filterRef.current,
+      },
+    });
+  };
+  const handleDownload = () => {
+    const token = getToken();
+    const s_time = filterRef.current?.s_time || '';
+    const e_time = filterRef.current?.e_time || '';
+    const project_name = filterRef.current?.project_name || '';
+    const project_status = filterRef.current?.project_status || '';
+    downloadFile(
+      `/api/v2/workload/finance/export2excel?JWT-TOKEN=${token}&s_time=${s_time}&e_time=${e_time}&project_name=${project_name}&project_status${project_status}`,
+      `财务报表${moment().format('YYYYMMDDHHMMSS')}.xlsx`
+    );
+  };
+  const renderSearch = () => {
+    return (
+      <Form layout="inline" form={form}>
+        <Form.Item label="时间" name="time" initialValue={[moment().startOf('years'), moment()]}>
+          <RangePicker placeholder="选择时间" allowClear={false} />
+        </Form.Item>
+        <Form.Item label="项目名称" name="project_name">
+          <Input />
+        </Form.Item>
+        <Form.Item label="项目状态" name="project_status" initialValue={null}>
+          <Select style={{ width: 120 }}>
+            <Select.Option value={null}>全部</Select.Option>
+            {STATUS.map(item => (
+              <Select.Option key={item.value}>{item.label}</Select.Option>
+            ))}
+          </Select>
+        </Form.Item>
+        <Form.Item>
+          <Button type="primary" loading={loading} onClick={handleSearch}>
+            查询
+          </Button>
+        </Form.Item>
+      </Form>
+    );
+  };
+  useEffect(() => {
+    handleSearch();
+  }, []);
+
+  return (
+    <div>
+      <div className={styles.topPart}>
+        {renderSearch()}
+        <Button type="primary" onClick={handleDownload}>
+          导出
+        </Button>
+      </div>
+      <Table
+        loading={loading}
+        style={{ marginTop: 20 }}
+        rowKey={record => `${record.user_name}-${record.project_code}-${record.type_name}`}
+        columns={columns}
+        dataSource={finance.list}
+        pagination={finance.pagination}
+        onChange={onChangePage}
+      />
+    </div>
+  );
+}
+
+export default connect(({ report, loading }) => ({
+  finance: report.finance,
+  loading: loading.models.report,
+}))(Finance);

+ 137 - 112
src/pages/PurchaseAdmin/PurchaseList/Report/Project.js

@@ -1,8 +1,6 @@
 import React, { useEffect, useState, useRef } from 'react';
 import { connect } from 'dva';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Table, DatePicker, Input, Button, Select, message } from 'antd';
+import { Form, Table, DatePicker, Input, Button, Select, message, Popover } from 'antd';
 import report from './models/report';
 import styles from './report.less';
 import moment from 'moment';
@@ -11,7 +9,7 @@ import { downloadFile, getToken } from '@/utils/utils.js';
 
 const { Option } = Select;
 const { RangePicker } = DatePicker;
-const initDate = [moment().startOf('years'), moment().endOf('years')];
+const initDate = [moment().startOf('years'), moment()];
 
 // var currentYear = new Date().getFullYear();
 // var yearList = [];
@@ -21,20 +19,21 @@ const initDate = [moment().startOf('years'), moment().endOf('years')];
 // }
 
 function Resource(props) {
-  const { dispatch, form, loading, project } = props;
+  const { dispatch, loading, project } = props;
+  const [form] = Form.useForm();
   const [expandedRowKeys, setExpandedRowKeys] = useState([]);
   const [visible, setVisible] = useState(false);
   const [modalFilter, setModalFilter] = useState({});
   const filterRef = useRef({});
-  const onChangePage = pagination => {
-    dispatch({
-      type: 'report/queryProjectReport',
-      payload: {
-        ...filterRef.current,
-        currentPage: pagination.current,
-      },
-    });
-  };
+  // const onChangePage = pagination => {
+  //   dispatch({
+  //     type: 'report/queryProjectReport',
+  //     payload: {
+  //       ...filterRef.current,
+  //       currentPage: pagination.current,
+  //     },
+  //   });
+  // };
   const getMonthColumns = () => {
     let arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
     var time;
@@ -63,65 +62,72 @@ function Resource(props) {
       date[cYear].push(arr[cMonth]);
       current.add('month', 1);
     }
-    console.log(date);
     current.subtract('month', 12);
     let monthColumns = Object.keys(date).map(year => ({
       title: year + '年',
-      children: date[year].map((item) => {
+      children: date[year].map(item => {
         let key = current.format('YYYY-MM');
         current.add('month', 1);
         return {
           title: `${item}`,
           render: record => {
             const { month } = record;
-            return month[key]?.total_audit_cnt || 0;
+            return month.find(item => item.st == key)?.pass_audit_cnt || 0;
+            // return month[key]?.total_audit_cnt || 0;
+            // return (
+            //   <Popover
+            //     content={
+            //       <>
+            //         {`审核通过: ${month[key]?.pass_audit_cnt || 0}`}
+            //         <br />
+            //         {`审核中: ${month[key]?.pending_audit_cnt || 0}`}
+            //         <br />
+            //         {`审核拒绝: ${month[key]?.refuse_audit_cnt || 0}`}
+            //         <br />
+            //         {`未提审: ${month[key]?.refuse_audit_cnt || 0}`}
+            //       </>
+            //     }
+            //   >
+            //     {month[key]?.total_audit_cnt || 0}
+            //   </Popover>
+            // );
             // return `${JSON.stringify(month)}`;
           },
         };
       }),
     }));
     return monthColumns;
-
-    // return {
-    //   title: '月份',
-    //   children: arr.map((item, index) => ({
-    //     title: `${item}`,
-    //     dataIndex: `month[${String(index)}].total_audit_cnt`,
-    //     render: cnt => cnt || 0,
-    //   })),
-    // };
-  };
-  const onExpand = (expanded, record) => {
-    if (expanded && !record.isLoad) {
-      dispatch({
-        type: 'report/queryProjectReportDetail',
-        payload: {
-          ...filterRef.current,
-          record: record,
-        },
-      });
-    }
   };
+  // const onExpand = (expanded, record) => {
+  //   if (expanded && !record.isLoad) {
+  //     dispatch({
+  //       type: 'report/queryProjectReportDetail',
+  //       payload: {
+  //         ...filterRef.current,
+  //         record: record,
+  //       },
+  //     });
+  //   }
+  // };
 
   const handleSearch = () => {
-    form.validateFields((error, { time, project_name }) => {
-      if (
-        !moment(time[0])
-          .add(12, 'month')
-          .isSameOrAfter(time[1])
-      ) {
-        message.error('时间间隔超过12个月,请重新选择。');
-        return;
-      }
-      filterRef.current.s_time = time[0] ? moment(time[0]).format('YYYY-MM-DD') : null;
-      filterRef.current.e_time = time[1] ? moment(time[1]).format('YYYY-MM-DD') : null;
-      dispatch({
-        type: 'report/queryProjectReport',
-        payload: {
-          ...filterRef.current,
-          project_name: project_name,
-        },
-      });
+    const { time, project_name } = form.getFieldsValue();
+    if (
+      !moment(time[0])
+        .add(12, 'month')
+        .isSameOrAfter(time[1])
+    ) {
+      message.error('时间间隔超过12个月,请重新选择。');
+      return;
+    }
+    filterRef.current.s_time = time[0] ? moment(time[0]).format('YYYY-MM-DD') : null;
+    filterRef.current.e_time = time[1] ? moment(time[1]).format('YYYY-MM-DD') : null;
+    dispatch({
+      type: 'report/queryProjectReport',
+      payload: {
+        ...filterRef.current,
+        project_name: project_name,
+      },
     });
   };
   const handleDownload = () => {
@@ -138,21 +144,12 @@ function Resource(props) {
   };
   const renderSearch = () => {
     return (
-      <Form layout="inline">
-        <Form.Item label="时间">
-          {form.getFieldDecorator('time', {
-            initialValue: initDate,
-          })(<RangePicker placeholder="选择时间" />)}
+      <Form layout="inline" form={form}>
+        <Form.Item label="时间" name="time" initialValue={initDate}>
+          <RangePicker placeholder="选择时间" allowClear={false} />
         </Form.Item>
-        <Form.Item label="项目">
-          {form.getFieldDecorator('project_name')(
-            <Input />
-            // <Select allowClear showSearch style={{ width: 240 }} placeholder="请选择项目" >
-            //   {projectList.map(item => (
-            //     <Option key={item.ID} value={item.Name}>{item.Name}</Option>
-            //   ))}
-            // </Select>
-          )}
+        <Form.Item label="项目" name="project_name">
+          <Input />
         </Form.Item>
         <Form.Item>
           <Button type="primary" loading={loading} onClick={handleSearch}>
@@ -166,61 +163,89 @@ function Resource(props) {
     {
       title: '项目名称',
       render: record =>
-        !record.isParent ? (
-          <a onClick={() => showUserModal(record)}>{record.type_name}</a>
+        !record.child && record.total_audit_cnt ? (
+          <a onClick={() => showUserModal(record)}>{record.name}</a>
         ) : (
-          record.type_name
+          record.name
         ),
     },
-    {
-      title: '分项工作代码',
-      align: 'center',
-      dataIndex: 'type_code',
-    },
-    // {
-    //   title: '项目名称',
-    //   render: record => (record.project_id == 0 ? '' : record.project_name),
-    // },
-    // {
-    //   title: '项目编号',
-    //   dataIndex: 'project_code',
-    // },
-    // {
-    //   title: '工作内容',
-    //   dataIndex: 'type_name',
-    // },
     ...getMonthColumns(),
-    {
-      title: '总计',
-      dataIndex: 'month_rpt',
-      render: arr => (arr ? arr.reduce((total, item) => total + item.total_audit_cnt, 0) : ''),
-    },
+    { title: '总计', dataIndex: 'total_audit_cnt' },
   ];
+  // const columns = [
+  //   {
+  //     title: '项目名称',
+  //     render: record =>
+  //       !record.isParent ? (
+  //         <a onClick={() => showUserModal(record)}>{record.type_name}</a>
+  //       ) : (
+  //         record.type_name
+  //       ),
+  //   },
+  //   {
+  //     title: '分项工作代码',
+  //     align: 'center',
+  //     dataIndex: 'type_code',
+  //   },
+  //   // {
+  //   //   title: '项目名称',
+  //   //   render: record => (record.project_id == 0 ? '' : record.project_name),
+  //   // },
+  //   // {
+  //   //   title: '项目编号',
+  //   //   dataIndex: 'project_code',
+  //   // },
+  //   // {
+  //   //   title: '工作内容',
+  //   //   dataIndex: 'type_name',
+  //   // },
+  //   ...getMonthColumns(),
+  //   {
+  //     title: '总计',
+  //     dataIndex: 'month_rpt',
+  //     render: arr => (
+  //       <Popover
+  //         content={
+  //           <>
+  //             {`审核通过: ${
+  //               arr ? arr.reduce((total, item) => total + item.pass_audit_cnt, 0) : ''
+  //             }`}
+  //             <br />
+  //             {`审核中: ${
+  //               arr ? arr.reduce((total, item) => total + item.pending_audit_cnt, 0) : ''
+  //             }`}
+  //             <br />
+  //             {`审核拒绝: ${
+  //               arr ? arr.reduce((total, item) => total + item.refuse_audit_cnt, 0) : ''
+  //             }`}
+  //             <br />
+  //             {`未提审: ${arr ? arr.reduce((total, item) => total + item.un_audit_cnt, 0) : ''}`}
+  //           </>
+  //         }
+  //       >
+  //         {arr ? arr.reduce((total, item) => total + item.total_audit_cnt, 0) : ''}
+  //       </Popover>
+  //     ),
+  //   },
+  // ];
   const showUserModal = item => {
     const { s_time, e_time } = filterRef.current;
     setModalFilter({
       s_time: s_time,
       e_time: e_time,
+      type_id: item.id,
       project_id: item.project_id,
-      p_type_id: item.project_id == 0 ? item.p_type_id : 0,
-      type_id: item.type_id,
+      flag: item.flag,
     });
     setVisible(true);
   };
   useEffect(() => {
-    // dispatch({
-    //   type: 'report/queryProjectReport',
-    // });
-    // dispatch({
-    //   type: 'report/queryProject',
-    // });
     handleSearch();
   }, []);
 
-  useEffect(() => {
-    setExpandedRowKeys(project.list.map(item => item.id));
-  }, [project.list]);
-  console.log(project.list)
+  // useEffect(() => {
+  //   setExpandedRowKeys(project.list.map(item => item.id));
+  // }, [project.list]);
 
   return (
     <div className={styles.page}>
@@ -233,11 +258,11 @@ function Resource(props) {
       <Table
         style={{ marginTop: 20 }}
         columns={columns}
-        rowKey="id"
-        onExpand={onExpand}
-        dataSource={project.list}
-        pagination={project.pagination}
-        onChange={onChangePage}
+        rowKey="key"
+        childrenColumnName="child"
+        // onExpand={onExpand}
+        dataSource={project}
+        pagination={false}
       />
       <UserProjectRptModal
         filter={modalFilter}
@@ -252,4 +277,4 @@ export default connect(({ report, loading }) => ({
   project: report.project,
   // projectList: report.projectList,
   loading: loading.models.report,
-}))(Form.create()(Resource));
+}))(Resource);

+ 1 - 3
src/pages/PurchaseAdmin/PurchaseList/Report/Resource.js

@@ -1,8 +1,6 @@
 import React, { useEffect, useState, useRef } from 'react';
 import { connect } from 'dva';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Table, DatePicker, Input, Button } from 'antd';
+import { Form, Table, DatePicker, Input, Button } from 'antd';
 import report from './models/report';
 import moment from 'moment';
 

+ 55 - 21
src/pages/PurchaseAdmin/PurchaseList/Report/UserProjectRptModal.js

@@ -1,23 +1,55 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Modal, Table, Input, Button } from 'antd';
+import { Modal, Table, Form, Input, Button } from 'antd';
 import { connect } from 'dva';
 import moment from 'moment';
 
-function AddModal(props) {
-  const { dispatch, visible, onOk, onCancel, data, filter, loading, form } = props;
+function UserProjectRptModal(props) {
+  const { dispatch, visible, onOk, onCancel, data, filter, loading } = props;
+  const [form] = Form.useForm();
+  // const getMonthColumns = () => {
+  //   let arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
+
+  //   return {
+  //     title: '月份',
+  //     children: arr.map((item, index) => ({
+  //       title: `${item}`,
+  //       dataIndex: `month[${String(index)}].total_audit_cnt`,
+  //       render: cnt => cnt || 0,
+  //     })),
+  //   };
+  // };
   const getMonthColumns = () => {
     let arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];
+    var time = [moment(filter.s_time), moment(filter.e_time)];
+    var date = {};
+    let eYear = time[1].year();
+    let eMonth = time[1].month();
+    let current = moment(time[0]);
+    let cYear, cMonth;
 
-    return {
-      title: '月份',
-      children: arr.map((item, index) => ({
-        title: `${item}`,
-        dataIndex: `month[${String(index)}].total_audit_cnt`,
-        render: cnt => cnt || 0,
-      })),
-    };
+    for (let i = 0; i < 12; i++) {
+      cYear = current.year();
+      cMonth = current.month();
+      if (!date[cYear]) date[cYear] = [];
+      date[cYear].push(arr[cMonth]);
+      current.add('month', 1);
+    }
+    current.subtract('month', 12);
+    let monthColumns = Object.keys(date).map(year => ({
+      title: year + '年',
+      children: date[year].map(item => {
+        let key = current.format('YYYY-MM');
+        current.add('month', 1);
+        return {
+          title: `${item}`,
+          render: record => {
+            const { month_rpt } = record;
+            return month_rpt.find(item => item.ts == key)?.pass_audit_cnt || 0;
+          },
+        };
+      }),
+    }));
+    return monthColumns;
   };
   const columns = [
     {
@@ -28,11 +60,12 @@ function AddModal(props) {
       title: '部门',
       dataIndex: 'dep_name',
     },
-    getMonthColumns(),
+    // getMonthColumns(),
+    ...getMonthColumns(),
     {
       title: '总计',
       dataIndex: 'month_rpt',
-      render: arr => (arr ? arr.reduce((total, item) => total + item.total_audit_cnt, 0) : ''),
+      render: arr => (arr ? arr.reduce((total, item) => total + item.pass_audit_cnt, 0) : ''),
     },
   ];
   const onChangePage = pagination => {
@@ -45,7 +78,8 @@ function AddModal(props) {
     });
   };
   const handleSearch = () => {
-    if (!filter?.project_id && !filter?.p_type_id) return;
+    // if (!filter?.project_id && !filter?.p_type_id) return;
+    if (!filter?.classification) return;
     const dep_name = form.getFieldValue('dep_name');
     dispatch({
       type: 'report/queryUserProjectReport',
@@ -56,7 +90,7 @@ function AddModal(props) {
     });
   };
   useEffect(() => {
-    if (!filter?.project_id && !filter?.p_type_id) return;
+    if (!filter?.project_id) return;
     dispatch({
       type: 'report/queryUserProjectReport',
       payload: filter,
@@ -65,9 +99,9 @@ function AddModal(props) {
 
   return (
     <Modal title="工时" width="80%" visible={visible} onCancel={onCancel} footer={false}>
-      <Form layout="inline" style={{ marginBottom: 20 }}>
-        <Form.Item lable="部门">
-          {form.getFieldDecorator('dep_name')(<Input placeholder="请输入部门" />)}
+      <Form layout="inline" style={{ marginBottom: 20 }} form={form}>
+        <Form.Item lable="部门" name="dep_name">
+          <Input placeholder="请输入部门" />
         </Form.Item>
         <Form.Item>
           <Button type="primary" onClick={handleSearch}>
@@ -89,4 +123,4 @@ function AddModal(props) {
 export default connect(({ report, loading }) => ({
   data: report.projectUser,
   loading: loading.models.report,
-}))(Form.create()(AddModal));
+}))(UserProjectRptModal);

+ 2 - 2
src/pages/PurchaseAdmin/PurchaseList/Report/UserRptModal.js

@@ -3,7 +3,7 @@ import { Modal, Table } from 'antd';
 import { connect } from 'dva';
 import moment from 'moment';
 
-function AddModal(props) {
+function UserRptModal(props) {
   const { dispatch, visible, onOk, onCancel, data, filter, loading } = props;
   const columns = [
     {
@@ -94,4 +94,4 @@ function AddModal(props) {
 export default connect(({ report, loading }) => ({
   data: report.depUser,
   loading: loading.models.report,
-}))(AddModal);
+}))(UserRptModal);

+ 149 - 54
src/pages/PurchaseAdmin/PurchaseList/Report/models/report.js

@@ -6,11 +6,15 @@ import {
   queryProjectReportDetail,
   queryUserProjectReport,
   queryProject,
+  queryDepCompare,
+  queryDepCompareUser,
+  queryFinanceReport,
+  queryUserProject,
 } from '@/services/workHours';
 import { queryRole } from '@/services/SysAdmin';
 import { message } from 'antd';
 import moment from 'moment';
-import { filter } from 'lodash';
+import { filter, times } from 'lodash';
 import list from '../../List/models/list';
 
 export default {
@@ -32,10 +36,17 @@ export default {
       list: [],
       pagination: {},
     },
-    project: {
+    // project: {
+    //   list: [],
+    //   pagination: {},
+    // },
+    project: [],
+    finance: {
       list: [],
       pagination: {},
     },
+    depCompare: [],
+    depUserProject: [],
     projectList: [],
   },
 
@@ -63,18 +74,18 @@ export default {
     },
     *queryUserProjectReport({ payload }, { call, put }) {
       const { data } = yield call(queryUserProjectReport, payload);
-      try {
-        data.list.forEach(item => {
-          let month = {};
-          item.month_rpt.forEach(mItem => {
-            let m = moment(mItem.ts).month();
-            month[m] = mItem;
-          });
-          item.month = month;
-        });
-      } catch (error) {
-        console.error(error);
-      }
+      // try {
+      //   data.list.forEach(item => {
+      //     let month = {};
+      //     item.month_rpt.forEach(mItem => {
+      //       let m = moment(mItem.ts).month();
+      //       month[m] = mItem;
+      //     });
+      //     item.month = month;
+      //   });
+      // } catch (error) {
+      //   console.error(error);
+      // }
       yield put({
         type: 'save',
         payload: { projectUser: data },
@@ -84,7 +95,7 @@ export default {
       const { filter = {}, record = {} } = payload;
       const { data } = yield call(queryDepReport, { ...filter, dep_id: record.dep_id });
       data.list.forEach(item => {
-        if(item.sub_dep_num) item.children = [];
+        if (item.sub_dep_num) item.children = [];
         item.isLoad = false;
       });
       // 判断是否为根节点
@@ -94,7 +105,7 @@ export default {
         record.isLoad = true;
         yield put({
           type: 'save',
-          payload: { dep: { ...dep } },
+          payload: { dep: { ...dep, list: [...dep.list] } },
         });
       } else {
         yield put({
@@ -106,55 +117,88 @@ export default {
     *queryProjectReport({ payload }, { call, put }) {
       const { data } = yield call(queryProjectReport, {
         ...payload,
-        // pageSize: 20,
       });
-      let treeData = {};
-      try {
-        data.list.forEach(item => {
-          let p_type_id = item.project_id == 0 ? 't' + item.p_type_id : 'p' + item.project_id;
-          treeData[p_type_id] = {
-            id: p_type_id,
-            type_name:
-              item.project_id == 0
-                ? item.project_name
-                : `${item.project_name}(${item.project_code})`,
-            project_name: item.project_name,
-            project_id: item.project_id,
-            project_code: item.project_code,
-            p_type_id: item.p_type_id,
-            month_rpt: item.month_rpt,
-            type_code: '',
-            children: [],
-            month: {},
-            isLoad: false,
-            isParent: true,
-          };
-          item.month_rpt.forEach(mItem => {
-            // let m = moment(mItem.ts).month();
-            treeData[p_type_id].month[mItem.ts] = mItem;
-          });
-        });
-      } catch (error) {
-        console.log(error);
-      }
-      console.log(treeData);
+      const idHelper = (item, params) => {
+        if (params.flag === undefined) {
+          item.child.forEach(childItem => idHelper(childItem, { flag: item.id }));
+          item.key = 'f' + item.id;
+        } else {
+          item.flag = params.flag;
+          if (params.project_id === undefined) {
+            item.child?.forEach(childItem =>
+              idHelper(childItem, { flag: item.flag, project_id: item.id })
+            );
+            item.key = 'f' + item.flag + 'p' + item.id;
+          } else {
+            item.project_id = params.project_id;
+            item.key = 'f' + item.flag + 'p' + item.project_id + 't' + item.id;
+          }
+        }
+      };
+      data.forEach(item => idHelper(item, {}));
       yield put({
         type: 'save',
         payload: {
-          project: {
-            list: Object.values(treeData),
-            pagination: data.pagination,
-          },
+          project: data,
         },
       });
     },
+    // *queryProjectReport({ payload }, { call, put }) {
+    //   const { data } = yield call(queryProjectReport, {
+    //     ...payload,
+    //     // pageSize: 20,
+    //   });
+    //   let treeData = {};
+    //   try {
+    //     data.list.forEach(item => {
+    //       let p_type_id =
+    //         item.rpt.project_id == 0 ? 't' + item.rpt.p_type_id : 'p' + item.rpt.project_id;
+    //       treeData[p_type_id] = {
+    //         id: p_type_id,
+    //         type_name:
+    //           item.rpt.project_id == 0
+    //             ? item.rpt.project_name
+    //             : `${item.rpt.project_name}(${item.rpt.project_code})`,
+    //         project_name: item.rpt.project_name,
+    //         project_id: item.rpt.project_id,
+    //         project_code: item.rpt.project_code,
+    //         p_type_id: item.rpt.p_type_id,
+    //         month_rpt: item.rpt.month_rpt,
+    //         classification: item.classification,
+    //         project_ids: item.project_ids,
+    //         type_code: '',
+    //         children: [],
+    //         month: {},
+    //         isLoad: false,
+    //         isParent: true,
+    //       };
+    //       item.rpt.month_rpt.forEach(mItem => {
+    //         // let m = moment(mItem.ts).month();
+    //         treeData[p_type_id].month[mItem.ts] = mItem;
+    //       });
+    //     });
+    //   } catch (error) {
+    //     console.log(error);
+    //   }
+    //   console.log(treeData);
+    //   yield put({
+    //     type: 'save',
+    //     payload: {
+    //       project: {
+    //         list: Object.values(treeData),
+    //         pagination: data.pagination,
+    //       },
+    //     },
+    //   });
+    // },
     *queryProjectReportDetail({ payload = {} }, { call, put, select }) {
       const { record = {} } = payload;
       const { data } = yield call(queryProjectReportDetail, {
         s_time: payload.s_time,
         e_time: payload.e_time,
-        project_id: record.project_id,
+        classification: record.classification,
         p_type_id: record.p_type_id,
+        project_ids: record.project_ids.join(','),
       });
       data.forEach((item, index) => {
         let month = {};
@@ -162,18 +206,69 @@ export default {
           // let m = moment(mItem.ts).month();
           month[mItem.ts] = mItem;
         });
-      
+
         item.month = month;
         item.id = record.id + '_' + index;
       });
       const project = yield select(s => s.report.project);
-      record.children = data.length == 0 ? null : data;
+      record.children =
+        data.length == 0 ? null : data.map(item => ({ ...item, project_ids: record.project_ids }));
       record.isLoad = true;
       yield put({
         type: 'save',
         payload: { project: { ...project } },
       });
     },
+    *queryFinanceReport({ payload = {} }, { call, put }) {
+      const { data } = yield call(queryFinanceReport, payload);
+      yield put({
+        type: 'save',
+        payload: { finance: data },
+      });
+    },
+    *queryDepCompare({ payload }, { call, put }) {
+      let { data } = yield call(queryDepCompare, payload);
+      if (data) {
+        const treeHelper = item => {
+          item.key = 'd' + item.dep_id;
+          if (!item.child && item.total_cnt) item.child = [];
+          item.child && item.child.forEach(childItem => treeHelper(childItem));
+        };
+        data.forEach(item => treeHelper(item));
+      } else data = [];
+      yield put({
+        type: 'save',
+        payload: { depCompare: data },
+      });
+    },
+    *queryDepCompareUser({ payload }, { call, put, select }) {
+      try {
+        let record = payload.record;
+        payload.dep_id = record.dep_id;
+        delete payload.record;
+        let { data } = yield call(queryDepCompareUser, payload);
+        data.forEach(item => {
+          item.key = 'u' + item.user_id;
+          item.dep_id = payload.dep_id;
+        });
+        record.child = [...record.child, ...data];
+        record.isLoad = true;
+      } catch (error) {
+        console.log(error);
+      }
+      const depCompare = yield select(s => s.report.depCompare);
+      yield put({
+        type: 'save',
+        payload: { depCompare: [...depCompare] },
+      });
+    },
+    *queryDepUserProject({ payload }, { call, put }) {
+      const { data } = yield call(queryUserProject, payload);
+      yield put({
+        type: 'save',
+        payload: { depUserProject: data },
+      });
+    },
   },
 
   reducers: {

+ 101 - 94
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/AddModal.js

@@ -1,19 +1,28 @@
 import React, { useState } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { message, Modal, Select, DatePicker } from 'antd';
+import { message, Form, Modal, Select, DatePicker } from 'antd';
+import { connect } from 'dva';
 import moment from 'moment';
 
 const { Option } = Select;
 const { MonthPicker } = DatePicker;
 
 function AddModal(props) {
-  const { visible, onOk, onCancel, time, form, typeList = [], projectList = {}, loading } = props;
+  const {
+    visible,
+    onOk,
+    onCancel,
+    time,
+    typeList = [],
+    subTypeList = [],
+    dispatch,
+    project = [],
+    loading,
+  } = props;
+  const [form] = Form.useForm();
   const [type, setType] = useState({});
   const [subType, setSubType] = useState({});
   const handleOk = () => {
-    form.validateFields((error, values) => {
-      if (error) return;
+    form.validateFields().then(values => {
       if (type.type == 0 || subType.type == 0) {
         if (!values.project) {
           message.error('请选择项目');
@@ -50,56 +59,75 @@ function AddModal(props) {
   };
   const onChangeType = value => {
     let item = typeList.find(t => t.id == value);
-    if (value == 35) {
-      form.setFieldsValue({
-        project: null,
-        subType: item.children[0].id + '',
+    form.setFieldsValue({
+      project: null,
+      subType: null,
+    });
+    setType(item);
+    setSubType({});
+    dispatch({
+      type: 'workload/save',
+      payload: { subTypeList: [] },
+    });
+    if (!item.type) {
+      dispatch({
+        type: 'workload/queryProject',
+        payload: { stage: value },
       });
-      setSubType(item.children[0]);
-      setType(item);
     } else {
-      form.setFieldsValue({
-        project: null,
-        subType: null,
+      dispatch({
+        type: 'workload/querySubType',
+        payload: { parent_id: item.id },
+        callback: subTypeList => {
+          if (value == 33) {
+            form.setFieldsValue({
+              project: null,
+              subType: subTypeList[0].id + '',
+            });
+            setSubType(subTypeList[0]);
+          }
+        },
       });
-      setSubType({});
-      setType(item);
     }
   };
   const onChangeSubType = value => {
-    let item = type.children.find(t => t.id == value);
+    let item = subTypeList.find(t => t.id == value);
     setSubType(item);
   };
 
   //售前支持更改项目时与子类选单联动
   const onChangeProject = value => {
-    if (value == '0') {
-      form.setFieldsValue({ subType: type.children[0].id + '' });
-      setSubType(type.children[0]);
-    } else {
-      form.setFieldsValue({ subType: type.children[1].id + '' });
-      setSubType(type.children[1]);
-    }
+    form.setFieldsValue({ subType: '' });
+    dispatch({
+      type: 'workload/querySubType',
+      payload: { parent_id: type.id, project_id: value },
+      callback: subTypeList => {
+        if (type.id == 35) {
+          form.setFieldsValue({ subType: subTypeList[0].id + '' });
+          setSubType(subTypeList[0]);
+        }
+        if (type.id == 2) {
+          if (value == '0') {
+            form.setFieldsValue({ subType: subTypeList[0].id + '' });
+            setSubType(subTypeList[0]);
+          } else {
+            form.setFieldsValue({ subType: subTypeList[1].id + '' });
+            setSubType(subTypeList[1]);
+          }
+        }
+      },
+    });
   };
 
   //分类选单
   const renderType = () => {
     return (
-      <Form.Item label="分类">
-        {form.getFieldDecorator('type', {
-          rules: [
-            {
-              required: true,
-              message: '请选择分类',
-            },
-          ],
-        })(
-          <Select onChange={onChangeType} placeholder="请选择分类">
-            {typeList.map(item => (
-              <Option key={String(item.id)}>{item.name}</Option>
-            ))}
-          </Select>
-        )}
+      <Form.Item label="分类" name="type" rules={[{ required: true, message: '请选择分类' }]}>
+        <Select onChange={onChangeType} placeholder="请选择分类">
+          {typeList.map(item => (
+            <Option key={String(item.id)}>{item.name}</Option>
+          ))}
+        </Select>
       </Form.Item>
     );
   };
@@ -107,37 +135,22 @@ function AddModal(props) {
   //项目选单
   const renderProject = () => {
     return (
-      <Form.Item label="项目">
-        {form.getFieldDecorator('project', {
-          rules: [
-            {
-              required: true,
-              message: '请选择项目',
-            },
-          ],
-        })(
-          //售前支持特殊判断,增加“无项目”,选择项目时与子类联动
-          <Select
-            showSearch
-            onChange={type.id === 2 ? onChangeProject : null}
-            placeholder="请选择项目"
-            optionFilterProp="children"
-            filterOption={(input, option) =>
-              // console.log(option.props.children)
-              option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-            }
-          >
-            {type.id === 2 && <Option key={'0'}>售前支持(10100)</Option>}
-            {(type.id === 2
-              ? projectList.project0
-              : type.id === 3
-              ? projectList.project1
-              : projectList.project7
-            ).map(item => (
-              <Option key={String(item.ID)}>{`${item.Name}(${item.Code})`}</Option>
-            ))}
-          </Select>
-        )}
+      <Form.Item label="项目" name="project" rules={[{ required: true, message: '请选择项目' }]}>
+        {/* 售前支持特殊判断,增加“无项目”,选择项目时与子类联动 */}
+        <Select
+          showSearch
+          onChange={onChangeProject}
+          placeholder="请选择项目"
+          optionFilterProp="children"
+          filterOption={(input, option) =>
+            option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+          }
+        >
+          {type.id === 2 && <Option key={'0'}>售前支持(10100)</Option>}
+          {project.map(item => (
+            <Option key={String(item.ID)}>{`${item.Name}(${item.Code})`}</Option>
+          ))}
+        </Select>
       </Form.Item>
     );
   };
@@ -145,26 +158,17 @@ function AddModal(props) {
   //子类选单
   const renderSubType = () => {
     return (
-      <Form.Item label="子类">
-        {form.getFieldDecorator('subType', {
-          rules: [
-            {
-              required: true,
-              message: '请选择子类',
-            },
-          ],
-        })(
-          //售前支持特殊判断,子类不可选
-          <Select
-            disabled={type.id === 2 || type.id === 35}
-            onChange={onChangeSubType}
-            placeholder={type.id === 2 || type.id === 35 ? null : '请选择子类'}
-          >
-            {(type.children || []).map(item => (
-              <Option key={String(item.id)}>{`${item.name}(${item.code})`}</Option>
-            ))}
-          </Select>
-        )}
+      <Form.Item label="子类" name="subType" rules={[{ required: true, message: '请选择子类' }]}>
+        {/* 售前支持特殊判断,子类不可选 */}
+        <Select
+          disabled={type.id === 2}
+          onChange={onChangeSubType}
+          placeholder={type.id === 2 ? null : '请选择子类'}
+        >
+          {(subTypeList || []).map(item => (
+            <Option key={String(item.id)}>{`${item.name}(${item.code})`}</Option>
+          ))}
+        </Select>
       </Form.Item>
     );
   };
@@ -179,9 +183,9 @@ function AddModal(props) {
       onOk={handleOk}
       destroyOnClose
     >
-      <Form labelCol={{ span: 4 }} wrapperCol={{ span: 16 }}>
+      <Form labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} form={form}>
         {renderType()}
-        {(type.id === 2 || type.id === 3 || type.id === 35) && renderProject()}
+        {type.type == 0 && renderProject()}
         {renderSubType()}
         <Form.Item label="时间">{time}</Form.Item>
       </Form>
@@ -189,4 +193,7 @@ function AddModal(props) {
   );
 }
 
-export default Form.create()(AddModal);
+export default connect(({ workload }) => ({
+  project: workload.project,
+  subTypeList: workload.subTypeList,
+}))(AddModal);

+ 59 - 14
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/Auth.js

@@ -1,6 +1,4 @@
 import React, { useState, useEffect, useRef } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
 import {
   message,
   InputNumber,
@@ -20,10 +18,9 @@ import AuthWorkList from './AuthWorkList';
 import { connect } from 'dva';
 import styles from './index.less';
 import moment from 'moment';
-import { getList } from '@/services/devOpsScoreRule';
 
 function List(props) {
-  const { typeList, dispatch, loading, form, list, project, currentUser, allType, user } = props;
+  const { dispatch, loading, list, project, currentUser, allType, user } = props;
   const [visible, setVisible] = useState(false);
   const [filter, setFilter] = useState({});
   const [current, setCurrent] = useState({
@@ -45,9 +42,16 @@ function List(props) {
           status: 2,
           desc: '',
         }));
+        let time = current.date.format('YYYY-MM-DD');
         dispatch({
           type: 'workload/authWorkload',
           payload: params,
+          callback: list => {
+            setCurrent({
+              ...current,
+              list: list.filter(item => item.time == time),
+            });
+          },
         });
       },
     });
@@ -62,11 +66,16 @@ function List(props) {
       status: 3,
       desc: data.desc || '',
     }));
+    let time = current.date.format('YYYY-MM-DD');
     dispatch({
       type: 'workload/authWorkload',
       payload: params,
-      callback: () => {
+      callback: list => {
         setVisible(false);
+        setCurrent({
+          ...current,
+          list: list.filter(item => item.time == time),
+        });
       },
     });
   };
@@ -84,10 +93,32 @@ function List(props) {
 
   const onChangeDate = value => {
     let time = value.format('YYYY-MM-DD');
-    setCurrent({
-      date: value,
-      list: list.filter(item => item.time == time),
-    });
+    if (current.date.format('YYYY-MM') != value.format('YYYY-MM')) {
+      const s_date = value.format('YYYY-MM') + '-01';
+      const e_date = moment(s_date)
+        .add('month', 1)
+        .add('days', -1)
+        .format('YYYY-MM-DD');
+      dispatch({
+        type: 'workload/queryAuthWorkHours',
+        payload: {
+          pageSize: 9999,
+          s_time: s_date + ' 00:00:00',
+          e_time: e_date + ' 23:59:59',
+        },
+        callback: list => {
+          setCurrent({
+            date: value,
+            list: list.filter(item => item.time == time),
+          });
+        },
+      });
+    } else {
+      setCurrent({
+        date: value,
+        list: list.filter(item => item.time == time),
+      });
+    }
   };
 
   const getList = () => {
@@ -105,14 +136,29 @@ function List(props) {
     dispatch({
       type: 'workload/queryWorkType',
       callback: () => {
+        const s_date = current.date.format('YYYY-MM') + '-01';
+        const e_date = moment(s_date)
+          .add('month', 1)
+          .add('days', -1)
+          .format('YYYY-MM-DD');
         dispatch({
           type: 'workload/queryAuthWorkHours',
           payload: {
             pageSize: 9999,
+            s_time: s_date + ' 00:00:00',
+            e_time: e_date + ' 23:59:59',
+          },
+          callback: list => {
+            let time = current.date.format('YYYY-MM-DD');
+            setCurrent({
+              ...current,
+              list: list.filter(item => item.time == time),
+            });
           },
         });
       },
     });
+
     // 查询项目列表
     dispatch({
       type: 'workload/queryProject',
@@ -132,9 +178,9 @@ function List(props) {
     };
   }, [currentUser.ID]);
 
-  useEffect(() => {
-    onChangeDate(current.date);
-  }, [list]);
+  // useEffect(() => {
+  //   onChangeDate(current.date);
+  // }, [list]);
 
   return (
     <div>
@@ -170,10 +216,9 @@ function List(props) {
 
 export default connect(({ workload, user, loading }) => ({
   list: workload.list,
-  typeList: workload.typeList,
   user: user.list,
   allType: workload.allType,
   project: workload.project,
   currentUser: user.currentUser,
   loading: loading.models.workload,
-}))(Form.create()(List));
+}))(List);

+ 31 - 47
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/AuthWorkList.js

@@ -1,7 +1,6 @@
 import React, { useState } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
 import {
+  Form,
   InputNumber,
   Input,
   Button,
@@ -20,18 +19,8 @@ const { Panel } = Collapse;
 const { Option } = Select;
 
 function AuthWorkList(props) {
-  const {
-    list,
-    onAuth,
-    onSearch,
-    onSave,
-    project = [],
-    allType,
-    onAgree,
-    onReject,
-    user,
-    form,
-  } = props;
+  const { list, onAuth, onSearch, onSave, project = [], allType, onAgree, onReject, user } = props;
+  const [form] = Form.useForm();
   const [edit, setEdit] = useState(false);
   const columns = [
     {
@@ -107,7 +96,7 @@ function AuthWorkList(props) {
       if (id == '0') {
         name = '其他';
       } else {
-        name = project.find(p => p.ID == id)?.Name;
+        name = item.Project.Name;
       }
 
       if (!data[id]) data[id] = { list: [], name, id };
@@ -155,46 +144,41 @@ function AuthWorkList(props) {
 
   const renderSearch = () => {
     const onHandleSearch = () => {
-      form.validateFields((error, values) => {
-        if (error) return;
+      form.validateFields().then(values => {
         onSearch(values);
       });
     };
     return (
-      <Form style={{ marginBottom: 20 }}>
+      <Form style={{ marginBottom: 20 }} form={form}>
         <Row gutter={12}>
           <Col span={12}>
-            <Form.Item label="人员">
-              {form.getFieldDecorator('userId')(
-                <Select
-                  allowClear
-                  showSearch
-                  filterOption={(input, option) =>
-                    option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                  }
-                >
-                  {user.map(item => (
-                    <Option key={item.ID}>{item.CName}</Option>
-                  ))}
-                </Select>
-              )}
+            <Form.Item label="人员" name="userId">
+              <Select
+                allowClear
+                showSearch
+                filterOption={(input, option) =>
+                  option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                }
+              >
+                {user.map(item => (
+                  <Option key={item.ID}>{item.CName}</Option>
+                ))}
+              </Select>
             </Form.Item>
           </Col>
           <Col span={12}>
-            <Form.Item label="项目">
-              {form.getFieldDecorator('projectId')(
-                <Select
-                  allowClear
-                  showSearch
-                  filterOption={(input, option) =>
-                    option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
-                  }
-                >
-                  {project.map(item => (
-                    <Option key={item.ID}>{item.Name}</Option>
-                  ))}
-                </Select>
-              )}
+            <Form.Item label="项目" name="projectId">
+              <Select
+                allowClear
+                showSearch
+                filterOption={(input, option) =>
+                  option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                }
+              >
+                {project.map(item => (
+                  <Option key={item.ID}>{`${item.Name}(${item.Code})`}</Option>
+                ))}
+              </Select>
             </Form.Item>
           </Col>
         </Row>
@@ -243,4 +227,4 @@ function AuthWorkList(props) {
   );
 }
 
-export default Form.create()(AuthWorkList);
+export default AuthWorkList;

+ 13 - 26
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/CalendarModal.js

@@ -1,12 +1,11 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
 import {
   InputNumber,
   message,
   Modal,
   Calendar,
   Popover,
+  Form,
   Input,
   Row,
   Col,
@@ -17,18 +16,8 @@ import styles from './index.less';
 import moment from 'moment';
 
 function CalendarModal(props) {
-  const {
-    allType,
-    projectList,
-    visible,
-    onOk,
-    onCancel,
-    data,
-    title,
-    form,
-    footer,
-    loading,
-  } = props;
+  const { allType, projectList, visible, onOk, onCancel, data, title, footer, loading } = props;
+  const [form] = Form.useForm();
   const [type, setType] = useState({});
   const [edit, setEdit] = useState(false);
   const [validRange, setValidRange] = useState(null);
@@ -37,9 +26,7 @@ function CalendarModal(props) {
     list: [],
   });
   const handleOk = () => {
-    form.validateFields((error, values) => {
-      if (error) return;
-      console.log(values);
+    form.validateFields().then(values => {
       let params = [];
       Object.keys(values).forEach(type_id => {
         if (type_id == 'comment') return;
@@ -147,16 +134,16 @@ function CalendarModal(props) {
         <Col span={6}>
           <Button>添加</Button>
           {current.list.map(item => (
-            <Form.Item label={item.TypeInfo?.name}>
-              {form.getFieldDecorator(`${item.type_id}.${item.time}`, {
-                initialValue: item?.workload,
-              })(<InputNumber min={0} max={8} disabled={!edit} />)}
+            <Form.Item
+              label={item.TypeInfo?.name}
+              name={`${item.type_id}.${item.time}`}
+              initialValue={item?.workload}
+            >
+              <InputNumber min={0} max={8} disabled={!edit} />
             </Form.Item>
           ))}
-          <Form.Item label="日志">
-            {form.getFieldDecorator('comment', { initialValue: current.list[0]?.comment })(
-              <Input.TextArea rows={5} disabled={!edit} />
-            )}
+          <Form.Item label="日志" name="comment" initialValue={current.list[0]?.comment}>
+            <Input.TextArea rows={5} disabled={!edit} />
           </Form.Item>
 
           <div className={styles.btns}>
@@ -186,4 +173,4 @@ function CalendarModal(props) {
   );
 }
 
-export default Form.create()(CalendarModal);
+export default CalendarModal;

+ 9 - 10
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/RejectModal.js

@@ -1,15 +1,12 @@
 import React, { useState } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Input, message, Modal } from 'antd';
+import { Input, message, Form, Modal } from 'antd';
 
 function RejectModal(props) {
-  const { visible, onOk, onCancel, form, loading } = props;
+  const { visible, onOk, onCancel, loading } = props;
+  const [form] = Form.useForm();
   const [type, setType] = useState({});
   const handleOk = () => {
-    form.validateFields((error, values) => {
-      if (error) return;
-
+    form.validateFields().then(values => {
       onOk(values);
     });
   };
@@ -24,11 +21,13 @@ function RejectModal(props) {
       onOk={handleOk}
       destroyOnClose
     >
-      <Form labelCol={{ span: 4 }} wrapperCol={{ span: 16 }}>
-        <Form.Item label="拒绝理由">{form.getFieldDecorator('desc')(<Input.TextArea />)}</Form.Item>
+      <Form labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} form={form}>
+        <Form.Item label="拒绝理由" name="desc">
+          <Input.TextArea />
+        </Form.Item>
       </Form>
     </Modal>
   );
 }
 
-export default Form.create()(RejectModal);
+export default RejectModal;

+ 1 - 3
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/SearchForm.js

@@ -1,7 +1,5 @@
 import React from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Select, DatePicker, Button } from 'antd';
+import { Form, Select, DatePicker, Button } from 'antd';
 import moment from 'moment';
 
 const { Option } = Select;

+ 30 - 16
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/WorkList.js

@@ -1,60 +1,74 @@
 import React, { useState, useEffect } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
 import { InputNumber, Popover, Divider, Table, message } from 'antd';
 
 function WorkList(props) {
-  const { list, form, onAuth, onSave, project = [], allType } = props;
+  const { list, onAuth, onSave, allType } = props;
   const [expandedRowKeys, setExpandedRowKeys] = useState([]);
   const [dataSource, setDataSource] = useState([]);
+  let workHour = {};
   const columns = [
     {
       title: '分类',
       dataIndex: 'type_id',
-      width: 230,
+      width: '25%',
       render: type_id => allType[type_id]?.name,
     },
     {
       title: '所属项目',
-      dataIndex: 'project_id',
-      render: (project_id, item) => {
+      width: '30%',
+      render: item => {
         if (item.zIndex === 0) return '';
-        return project.find(p => p.ID == project_id)?.Name || '-';
+        return item.Project?.Name || '-';
       },
     },
     {
       title: '审核状态',
-      width: 100,
+      width: '15%',
       render: record => renderStatus(record),
     },
     {
       title: '工时',
-      width: 110,
+      width: '15%',
       render: item => {
         if (item.zIndex === 0) {
           return '总计 ' + item.children.reduce((total, item) => total + item.workload, 0) + '小时';
         }
         if (item.audit_state == 1 || item.audit_state == 2) return item?.workload + '小时';
-        return form.getFieldDecorator(`${item.type_id}.${item.time}`, {
-          initialValue: item?.workload,
-        })(<InputNumber style={{width: 60}} min={0} step={0.5} />);
+        workHour[`${item.type_id}.${item.project_id}.${item.time}`] = item?.workload;
+        return (
+          <InputNumber
+            style={{ width: 60 }}
+            min={0}
+            step={0.5}
+            defaultValue={item?.workload}
+            onChange={value => {
+              workHour[`${item.type_id}.${item.project_id}.${item.time}`] = value;
+            }}
+          />
+        );
       },
     },
     {
       title: '操作',
-      width: 140,
+      width: '15%',
       render: item => {
         if (item.zIndex === 0) return '';
         if (item.audit_state == 1 || item.audit_state == 2) return;
         return (
           <>
             <a
-              onClick={() => onHandleSave(item, form.getFieldValue(`${item.type_id}.${item.time}`))}
+              onClick={() =>
+                onHandleSave(item, workHour[`${item.type_id}.${item.project_id}.${item.time}`])
+              }
             >
               保存
             </a>
             <Divider type="vertical"></Divider>
-            <a onClick={() => onAuth(item, form.getFieldValue(`${item.type_id}.${item.time}`))}>
+            <a
+              onClick={() =>
+                onAuth(item, workHour[`${item.type_id}.${item.project_id}.${item.time}`])
+              }
+            >
               上报审批
             </a>
           </>
@@ -128,4 +142,4 @@ function WorkList(props) {
   );
 }
 
-export default Form.create()(WorkList);
+export default WorkList;

+ 18 - 32
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/index.js

@@ -1,24 +1,12 @@
 import React, { useState, useEffect, useRef } from 'react';
-import { Form } from '@ant-design/compatible';
-import '@ant-design/compatible/assets/index.css';
-import { Modal, Button, Calendar, Popover, Spin, Row, Col } from 'antd';
+import { Modal, Button, Calendar, Popover, Spin, Row, Col, message } from 'antd';
 import AddModal from './AddModal';
 import WorkList from './WorkList';
 import { connect } from 'dva';
 import moment from 'moment';
 
 function List(props) {
-  const {
-    typeList,
-    dispatch,
-    loading,
-    form,
-    dataList,
-    project,
-    projectList,
-    currentUser,
-    allType,
-  } = props;
+  const { typeList, dispatch, loading, dataList, projectList, currentUser, allType } = props;
   const [visible, setVisible] = useState(false);
   const [current, setCurrent] = useState({
     date: moment(),
@@ -26,7 +14,7 @@ function List(props) {
   });
 
   const onAuth = (item, workload) => {
-    console.log(workload);
+    if (workload == 0) return message.error('请上报有效工时');
     Modal.confirm({
       title: '提示',
       content: '是否上报审批?',
@@ -178,6 +166,13 @@ function List(props) {
     dispatch({
       type: 'workload/addWorkHours',
       payload: params,
+      callback: list => {
+        let time = current.date.format('YYYY-MM-DD');
+        setCurrent({
+          ...current,
+          list: list.filter(item => item.time == time),
+        });
+      },
     });
   };
 
@@ -265,7 +260,7 @@ function List(props) {
       if (!pid) return '';
       name = allType[pid].name;
     } else {
-      name = project?.find(p => p.ID == item.project_id)?.Name;
+      name = item.Project.Name;
     }
     return name;
   };
@@ -300,9 +295,9 @@ function List(props) {
       },
     });
     // 查询项目列表
-    dispatch({
-      type: 'workload/queryProject',
-    });
+    // dispatch({
+    //   type: 'workload/queryProject',
+    // });
     return () => {
       // 清空查询数据
       dispatch({
@@ -323,14 +318,14 @@ function List(props) {
     <div>
       <Spin spinning={loading}>
         <Row gutter={8}>
-          <Col span={12}>
+          <Col span={10}>
             <Calendar
               value={current.date}
               dateCellRender={dateCellRender}
               onChange={onChangeDate}
             />
           </Col>
-          <Col span={12}>
+          <Col span={14}>
             <div>
               <Button type="primary" style={{ marginBottom: 20 }} onClick={() => setVisible(true)}>
                 新增
@@ -353,20 +348,13 @@ function List(props) {
               )}
             </div>
 
-            <WorkList
-              allType={allType}
-              project={project}
-              list={current.list}
-              onAuth={onAuth}
-              onSave={onSave}
-            />
+            <WorkList allType={allType} list={current.list} onAuth={onAuth} onSave={onSave} />
           </Col>
         </Row>
       </Spin>
 
       <AddModal
         typeList={typeList}
-        projectList={projectList}
         visible={visible}
         onOk={onAddWork}
         time={current.date?.format('YYYY-MM-DD')}
@@ -380,8 +368,6 @@ export default connect(({ workload, user, loading }) => ({
   dataList: workload.dataList,
   typeList: workload.typeList,
   allType: workload.allType,
-  project: workload.project,
-  projectList: workload.projectList,
   currentUser: user.currentUser,
   loading: loading.models.workload,
-}))(Form.create()(List));
+}))(List);

+ 26 - 21
src/pages/PurchaseAdmin/PurchaseList/WorkingHours/models/workingHours.js

@@ -18,35 +18,43 @@ export default {
     dataList: [],
     typeList: [],
     allType: {},
+    subTypeList: [],
     project: [],
     projectList: { project0: [], project1: [] },
     filter: {},
   },
 
   effects: {
-    *queryWorkType({ payload, callback }, { call, put }) {
-      const { data } = yield call(queryWorkType, {});
+    *queryWorkType({ callback }, { call, put }) {
+      const { data } = yield call(queryWorkType, { parent_id: -1 });
+      let typeList = [];
       let allType = {};
       for (let i = 0; i < data.length; i++) {
         let item = data[i];
         allType[item.id] = item;
-        let { data: subData } = yield call(queryWorkType, { parent_id: item.id });
-        item.children = subData;
-        subData.forEach(item => {
-          allType[item.id] = item;
-        });
+        if (item.parent_id == 0) {
+          typeList.push(item);
+        }
       }
       yield put({
         type: 'save',
-        payload: { typeList: data, allType },
+        payload: { typeList, allType },
       });
       callback && callback();
     },
+    *querySubType({ payload, callback }, { call, put }) {
+      const { data } = yield call(queryWorkType, payload);
+      callback && callback(data);
+      yield put({
+        type: 'save',
+        payload: { subTypeList: data },
+      });
+    },
     /**
      *
      * payload = {s_time,e_time,user_id}
      */
-    *queryAuthWorkHours({ payload }, { call, put, select }) {
+    *queryAuthWorkHours({ payload, callback }, { call, put, select }) {
       const workload = yield select(s => s.workload);
       const { typeList, filter, allType } = workload;
       // 合并新旧过滤条件
@@ -80,6 +88,9 @@ export default {
       //     });
       //   });
       // });
+
+      callback && callback(data.list);
+
       yield put({
         type: 'save',
         payload: { list: data.list, filter: newFilter },
@@ -156,29 +167,23 @@ export default {
       const res = yield call(authWorkload, payload);
       if (res) {
         message.success('操作成功');
-        callback && callback();
         yield put({
           type: 'queryAuthWorkHours',
           payload: {},
+          callback,
         });
       }
     },
-    *queryProject({ callback }, { call, put }) {
-      const response0 = yield call(queryProject, { stage: 0 });
-      const response1 = yield call(queryProject, { stage: 1 });
-      const response7 = yield call(queryProject, { stage: 7 });
-      if (response0 && response1 && response7) {
+    *queryProject({ payload = {}, callback }, { call, put }) {
+      const res = yield call(queryProject, payload);
+      if (res) {
         yield put({
           type: 'save',
           payload: {
-            project: [...response0.data.list, ...response1.data.list, ...response7.data.list],
-            projectList: {
-              project0: response0.data.list,
-              project1: response1.data.list,
-              project7: response7.data.list,
-            },
+            project: res.data.list,
           },
         });
+        callback && callback();
       }
     },
   },

+ 16 - 0
src/services/approval.js

@@ -88,6 +88,22 @@ export async function startExecution(data) {
   });
 }
 
+//转运营
+export async function startOperate(data) {
+  return request(`/api/v2/project_code/to_opt`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
+//转质保
+export async function startQuality(data) {
+  return request(`/api/v2/project_code/to_wty`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
 //移除成员
 export async function deleteMember(data) {
   return request(`/api/v2/project_code/user/${data.project_code_id}/${data.user_id}`, {

+ 17 - 1
src/services/workHours.js

@@ -79,5 +79,21 @@ export async function queryProjectReport(params) {
 }
 
 export async function queryProjectReportDetail(params) {
-  return request(`/api/v2/workload/project/month/rpt?${stringify(params)}`)
+  return request(`/api/v2/workload/project/month/rpt?${stringify(params)}`);
 }
+
+export async function queryFinanceReport(params) {
+  return request(`/api/v2/workload/finance/rpt?${stringify(params)}`);
+}
+
+export async function queryDepCompare(params) {
+  return request(`/api/v2/workload/dep/compare?${stringify(params)}`);
+}
+
+export async function queryDepCompareUser(params) {
+  return request(`/api/v2/workload/dep/compare/users?${stringify(params)}`);
+}
+
+export async function queryUserProject(params){
+  return request(`/api/v2/workload/dep/compare/users/project?${stringify(params)}`)
+}