Quellcode durchsuchen

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

ZhaoJun vor 1 Jahr
Ursprung
Commit
7cd7b4a2bc

+ 2 - 2
package.json

@@ -5,7 +5,7 @@
   "private": true,
   "private": true,
   "scripts": {
   "scripts": {
     "presite": "cd functions && npm install",
     "presite": "cd functions && npm install",
-    "start": "cross-env APP_TYPE=site UMI_UI=none umi dev",
+    "start": "cross-env NODE_OPTIONS=--max-old-space-size=8000 APP_TYPE=site UMI_UI=none umi dev",
     "start:no-mock": "cross-env MOCK=none umi dev",
     "start:no-mock": "cross-env MOCK=none umi dev",
     "build": "umi build",
     "build": "umi build",
     "build-prod": "cross-env UMI_ENV=prod umi build umi build",
     "build-prod": "cross-env UMI_ENV=prod umi build umi build",
@@ -124,7 +124,7 @@
     "gh-pages": "^2.0.1",
     "gh-pages": "^2.0.1",
     "husky": "^1.3.1",
     "husky": "^1.3.1",
     "jest-puppeteer": "^4.0.0",
     "jest-puppeteer": "^4.0.0",
-    "less": "^4.1.2",
+    "less": "3.13.1",
     "lint-staged": "^8.1.1",
     "lint-staged": "^8.1.1",
     "merge-umi-mock-data": "^1.0.4",
     "merge-umi-mock-data": "^1.0.4",
     "mockjs": "^1.0.1-beta3",
     "mockjs": "^1.0.1-beta3",

+ 1 - 1
src/components/charts/BarChartModule.js

@@ -34,7 +34,7 @@ const BarChartModule = props => {
     option.xAxis.data = xData;
     option.xAxis.data = xData;
     option.series = dataList.map((item, idx) => {
     option.series = dataList.map((item, idx) => {
       return {
       return {
-        ...option.series[idx],
+        ...option.series[0],
         ...item,
         ...item,
       };
       };
     });
     });

+ 3 - 0
src/pages/PurchaseAdmin/PurchaseList/Approval/ApprovalModal.js

@@ -35,6 +35,9 @@ function AddModal(props) {
     version: '',
     version: '',
   });
   });
   const [type, setType] = useState({});
   const [type, setType] = useState({});
+  const [list1, setList1] = useState([]);
+  const [list2, setList2] = useState([]);
+  const [list3, setList3] = useState([]);
   const [addFirmVisible, setAddFirmVisible] = useState(false);
   const [addFirmVisible, setAddFirmVisible] = useState(false);
 
 
   const handleOk = () => {
   const handleOk = () => {

+ 105 - 26
src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.js

@@ -1,5 +1,5 @@
 import React, { useState, useEffect, useMemo, useRef } from 'react';
 import React, { useState, useEffect, useMemo, useRef } from 'react';
-import { Button, Form, Modal, Select, Steps, Tabs, TreeSelect, Upload } from 'antd';
+import { Button, Form, Modal, Select, Steps, Tabs, TreeSelect, Upload, message } from 'antd';
 import styles from './DetailModal.less';
 import styles from './DetailModal.less';
 import TableRender from './TableRender';
 import TableRender from './TableRender';
 import MemberModal from './MemberModal';
 import MemberModal from './MemberModal';
@@ -9,6 +9,7 @@ import { async } from '@antv/x6/lib/registry/marker/async';
 import { queryStatusHistory } from '@/services/approval';
 import { queryStatusHistory } from '@/services/approval';
 import { UploadOutlined } from '@ant-design/icons';
 import { UploadOutlined } from '@ant-design/icons';
 import { startExecution, startOperate, startQuality } from '@/services/approval';
 import { startExecution, startOperate, startQuality } from '@/services/approval';
+import { connect } from 'dva';
 
 
 const { Step } = Steps;
 const { Step } = Steps;
 // 新建
 // 新建
@@ -25,6 +26,7 @@ function DetailModal(props) {
     disabled,
     disabled,
     currentUser,
     currentUser,
     loading,
     loading,
+    dispatch,
   } = props;
   } = props;
   const [codes, setCodes] = useState({
   const [codes, setCodes] = useState({
     type: '',
     type: '',
@@ -45,10 +47,10 @@ function DetailModal(props) {
       name: data.name,
       name: data.name,
       version: data.version,
       version: data.version,
     });
     });
-    setParams({
-      project_status: data?.project_status,
-      // status: data?.status,
-    });
+    // setParams({
+    //   project_status: data?.project_status,
+    //   // status: data?.status,
+    // });
     if (data?.id) initStatueHistory(data.id);
     if (data?.id) initStatueHistory(data.id);
   }, [data, visible]);
   }, [data, visible]);
 
 
@@ -138,6 +140,32 @@ function DetailModal(props) {
 
 
     return { showModifyManager, showEditBtn, showMember, showStatus, showExecution };
     return { showModifyManager, showEditBtn, showMember, showStatus, showExecution };
   }, [currentUser, data, isEdit]);
   }, [currentUser, data, isEdit]);
+  const manager = useMemo(() => {
+    let manager = {};
+    switch (data.project_status) {
+      case 0:
+        // 售前
+        manager = data.AuditUser || {};
+        manager.DepID = data.author_dep_id;
+        break;
+      case 1:
+        // 执行
+        manager = data.Leader || {};
+        manager.DepID = data.leader_dep_id;
+        break;
+      case 2:
+        // 运营
+        manager = data.OptManager || {};
+        manager.DepID = data.opt_manager_dep_id;
+        break;
+      case 3:
+        // 质保
+        manager = data.WtyManager || {};
+        manager.DepID = data.wty_manager_dep_id;
+        break;
+    }
+    return manager;
+  }, [data]);
   const statusOptions = useMemo(() => {
   const statusOptions = useMemo(() => {
     if (!data?.id) return [];
     if (!data?.id) return [];
     const { showStatus, showExecution } = promise;
     const { showStatus, showExecution } = promise;
@@ -195,30 +223,25 @@ function DetailModal(props) {
     if (!label) return null;
     if (!label) return null;
     return (
     return (
       <>
       <>
-        <Form.Item
-          label={label}
-          name="managerID"
-          rules={[{ required: true, message: `请选择${label}` }]}
-        >
+        <Form.Item label={label} rules={[{ required: true, message: `请选择${label}` }]}>
           <TreeSelect
           <TreeSelect
             showSearch
             showSearch
             allowClear
             allowClear
-            style={{ width: '100%' }}
             placeholder={`请选择${label}`}
             placeholder={`请选择${label}`}
             multiple={false}
             multiple={false}
             filterTreeNode={(input, option) => {
             filterTreeNode={(input, option) => {
-              return option.props.title === input;
+              return option.props.title.industry(input);
             }}
             }}
+            onChange={value => setParams({ ...params, Manager: value })}
             treeData={depUserTree}
             treeData={depUserTree}
           />
           />
         </Form.Item>
         </Form.Item>
         {params.status == 11 && (
         {params.status == 11 && (
-          <Form.Item
-            label="合同状态"
-            name="contractStatus"
-            rules={[{ required: true, message: '请选择合同状态' }]}
-          >
-            <Select style={{ width: '100%' }}>
+          <Form.Item label="合同状态">
+            <Select
+              onChange={value => setParams({ ...params, contractStatus: value })}
+              placeholder="请选择有无合同"
+            >
               <Option key={0}>无合同</Option>
               <Option key={0}>无合同</Option>
               <Option key={1}>有合同</Option>
               <Option key={1}>有合同</Option>
             </Select>
             </Select>
@@ -245,13 +268,68 @@ function DetailModal(props) {
   };
   };
 
 
   const onSave = () => {
   const onSave = () => {
+    let type = '';
+    let payload = null;
     if (params.status == 11) {
     if (params.status == 11) {
       // '项目经理'
       // '项目经理'
+      if (!params.Manager) return message.error('请选择项目经理');
+      if (!params.contractStatus) return message.error('请选择有无合同');
+      type = 'approval/startExecution';
+      const [manager_id, dep_id] = params.Manager.split('||');
+      payload = {
+        project_code_id: data.id,
+        with_contract: Number(params.contractStatus),
+        dep_id: Number(dep_id),
+        exe_manager_id: Number(manager_id),
+      };
+      if (params.attach && params.attach.length > 0) {
+        try {
+          payload.attach = JSON.stringify(params.attach);
+        } catch (e) {
+          console.error(e);
+          payload.attach = '';
+        }
+      }
     } else if (params.status == 21) {
     } else if (params.status == 21) {
       // '运营经理'
       // '运营经理'
+      if (!params.Manager) return message.error('请选择运营经理');
+      type = 'approval/startOperate';
+      const [manager_id, dep_id] = params.Manager.split('||');
+      payload = {
+        project_code_id: data.id,
+        dep_id: Number(dep_id),
+        opt_manager_id: Number(manager_id),
+      };
     } else if (params.status == 31) {
     } else if (params.status == 31) {
       // '质保经理'
       // '质保经理'
+      type = 'approval/startQuality';
+      const [manager_id, dep_id] = params.Manager.split('||');
+      payload = {
+        project_code_id: data.id,
+        dep_id: Number(dep_id),
+        wty_manager_id: Number(manager_id),
+      };
+    } else {
+      type = 'approval/updateApproval';
+      payload = {
+        ...data,
+        ...params,
+        manager_id: manager.ID,
+      };
+      if (params.attach && params.attach.length > 0) {
+        try {
+          payload.attach = JSON.stringify(params.attach);
+        } catch (e) {
+          console.error(e);
+          payload.attach = '';
+        }
+      }
     }
     }
+    dispatch({
+      type,
+      payload,
+      callback: () => onClose(),
+    });
   };
   };
 
 
   const uploadProps = {
   const uploadProps = {
@@ -264,8 +342,8 @@ function DetailModal(props) {
     // defaultFileList: attachData?.attach_extend,
     // defaultFileList: attachData?.attach_extend,
     onChange({ file, fileList }) {
     onChange({ file, fileList }) {
       if (file.status !== 'uploading') {
       if (file.status !== 'uploading') {
-        const data = fileList.map(item => item.response?.data);
-        setParams({ ...params, attach: [...params.attach, data] });
+        const urlList = fileList.map(item => item.response?.data);
+        setParams({ ...params, attach: urlList });
       }
       }
     },
     },
   };
   };
@@ -302,18 +380,19 @@ function DetailModal(props) {
         )}
         )}
         <Form.Item className={styles.formItem} label="项目经理">
         <Form.Item className={styles.formItem} label="项目经理">
           {!promise.showModifyManager ? (
           {!promise.showModifyManager ? (
-            data.AuthorUser?.CName
+            manager?.CName
           ) : (
           ) : (
             <TreeSelect
             <TreeSelect
-              defaultValue={data.AuthorUser?.CName}
+              // defaultValue={`${manager.ID}||${manager.DepID}`}
+              placeholder={manager.CName || '请选择项目经理'}
               showSearch
               showSearch
               allowClear
               allowClear
               style={{ width: '60%' }}
               style={{ width: '60%' }}
-              placeholder="请选择项目经理"
               multiple={false}
               multiple={false}
               filterTreeNode={(input, option) => {
               filterTreeNode={(input, option) => {
                 return option.props.title === input;
                 return option.props.title === input;
               }}
               }}
+              onChange={value => setParams({ ...params, manager_id: Number(value.split('||')[0]) })}
               treeData={depUserTree}
               treeData={depUserTree}
             />
             />
           )}
           )}
@@ -339,7 +418,7 @@ function DetailModal(props) {
           </Form.Item>
           </Form.Item>
         )}
         )}
         <Form.Item className={styles.formItem} label="项目阶段">
         <Form.Item className={styles.formItem} label="项目阶段">
-          {STATUS.find(item => item.value == params?.project_status)?.label}
+          {STATUS.find(item => item.value == data?.project_status)?.label}
         </Form.Item>
         </Form.Item>
         <Form.Item className={styles.formItem} label="现阶段状态">
         <Form.Item className={styles.formItem} label="现阶段状态">
           {isEdit ? (
           {isEdit ? (
@@ -366,7 +445,7 @@ function DetailModal(props) {
           <TableRender onlyShow={true} value={data.process_info} />
           <TableRender onlyShow={true} value={data.process_info} />
         </Form.Item>
         </Form.Item>
         <Form.Item>
         <Form.Item>
-          <Button type="primary" onClick={onSave}>
+          <Button type="primary" loading={loading} onClick={onSave}>
             保存
             保存
           </Button>
           </Button>
         </Form.Item>
         </Form.Item>
@@ -428,4 +507,4 @@ function DetailModal(props) {
     </Modal>
     </Modal>
   );
   );
 }
 }
-export default DetailModal;
+export default connect(({ loading }) => ({ loading: loading.models.approval }))(DetailModal);

+ 1 - 1
src/pages/PurchaseAdmin/PurchaseList/Approval/DetailModal.less

@@ -12,5 +12,5 @@
 }
 }
 
 
 .formItem {
 .formItem {
-  margin-bottom: 0;
+  margin-bottom: 11px;
 }
 }

+ 39 - 34
src/pages/PurchaseAdmin/PurchaseList/Approval/Statistic.js

@@ -6,7 +6,7 @@ import { Radio } from 'antd';
 import { useRequest } from 'ahooks';
 import { useRequest } from 'ahooks';
 import { workloadDepProjectChart, workloadDepProjectTypeChart } from '@/services/record';
 import { workloadDepProjectChart, workloadDepProjectTypeChart } from '@/services/record';
 import PieChartModule from '@/components/charts/PieChartModule';
 import PieChartModule from '@/components/charts/PieChartModule';
-import { STATUS } from './List';
+import { SUB_STATUS } from './List';
 import { connect } from 'dva';
 import { connect } from 'dva';
 const Statistic = props => {
 const Statistic = props => {
   const { typeList, dispatch } = props;
   const { typeList, dispatch } = props;
@@ -19,9 +19,31 @@ const Statistic = props => {
       type: 'approval/queryType',
       type: 'approval/queryType',
     });
     });
   }, []);
   }, []);
+
+  const titleData = useMemo(() => {
+    return [
+      {
+        name: '项目总数',
+        count: data?.total,
+      },
+      {
+        name: '审核通过项目数',
+        count: data?.pass,
+      },
+      {
+        name: '审核中项目数',
+        count: data?.audit,
+      },
+      {
+        name: '本月新增立项项目',
+        count: data?.add,
+      },
+    ];
+  }, [data]);
+
   const pieData = useMemo(() => {
   const pieData = useMemo(() => {
     return data?.status_chart?.map(item => {
     return data?.status_chart?.map(item => {
-      const name = STATUS.find(cur => cur.value == item.status)?.label || '';
+      const name = SUB_STATUS.find(cur => cur.value == item.status)?.label || '';
       return { value: item.num, name };
       return { value: item.num, name };
     });
     });
   }, [data]);
   }, [data]);
@@ -38,7 +60,7 @@ const Statistic = props => {
     });
     });
     return newData;
     return newData;
   }, [typeData]);
   }, [typeData]);
-  console.log('------------piedata -----', pieData, barData);
+  console.log(barData);
 
 
   const options = [
   const options = [
     {
     {
@@ -57,43 +79,26 @@ const Statistic = props => {
   return (
   return (
     <div className={styles.statistic}>
     <div className={styles.statistic}>
       <div className={styles.boxCon}>
       <div className={styles.boxCon}>
-        <div style={{ fontSize: '22px' }}>项目统计</div>
-        <div
-          style={{
-            display: 'flex',
-            width: '100%',
-            justifyContent: 'space-around',
-            margin: '20px 0',
-          }}
-        >
-          <div style={{ textAlign: 'center' }}>
-            <div style={{ color: '#f5a41f', fontSize: '32px' }}>{data?.total}</div>
-            <div>项目总数</div>
-          </div>
-          <div style={{ textAlign: 'center' }}>
-            <div style={{ color: '#f5a41f', fontSize: '32px' }}>{data?.pass}</div>
-            <div>审核通过项目数</div>
-          </div>
-          <div style={{ textAlign: 'center' }}>
-            <div style={{ color: '#f5a41f', fontSize: '32px' }}>{data?.audit}</div>
-            <div>审核中项目数</div>
-          </div>
-          <div style={{ textAlign: 'center' }}>
-            <div style={{ color: '#f5a41f', fontSize: '32px' }}>{data?.add}</div>
-            <div>本月新增立项项目</div>
-          </div>
+        <div className={styles.titleText}>项目统计</div>
+        <div className={styles.titleCon}>
+          {titleData.map(item => (
+            <div className={styles.item}>
+              <div className={styles.itemNum}>{item.count}</div>
+              <div>{item.name}</div>
+            </div>
+          ))}
         </div>
         </div>
       </div>
       </div>
-      <div style={{ display: 'flex', marginTop: '26px', justifyContent: 'space-between' }}>
+      <div className={styles.bottomCon}>
         <div className={styles.boxCon} style={{ width: '49.2%' }}>
         <div className={styles.boxCon} style={{ width: '49.2%' }}>
-          <div style={{ fontSize: '22px' }}>项目状态统计</div>
-          <div style={{ height: '400px' }}>
+          <div className={styles.titleText}>项目状态统计</div>
+          <div className={styles.chartCon}>
             {data?.status_chart?.length > 0 && <PieChartModule data={pieData} />}
             {data?.status_chart?.length > 0 && <PieChartModule data={pieData} />}
           </div>
           </div>
         </div>
         </div>
         <div className={styles.boxCon} style={{ width: '49.2%', position: 'relative' }}>
         <div className={styles.boxCon} style={{ width: '49.2%', position: 'relative' }}>
-          <div style={{ fontSize: '22px' }}>项目分类统计</div>
-          <div style={{ position: 'absolute', top: '16px', right: '20px' }}>
+          <div className={styles.titleText}>项目分类统计</div>
+          <div className={styles.pieContent}>
             <Radio.Group
             <Radio.Group
               options={options}
               options={options}
               onChange={e => runTypeData({ t: e.target.value })}
               onChange={e => runTypeData({ t: e.target.value })}
@@ -102,7 +107,7 @@ const Statistic = props => {
               buttonStyle="solid"
               buttonStyle="solid"
             />
             />
           </div>
           </div>
-          <div style={{ height: '400px' }}>{typeData && <BarChartModule {...barData} />}</div>
+          <div className={styles.chartCon}>{typeData && <BarChartModule {...barData} />}</div>
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>

+ 39 - 8
src/pages/PurchaseAdmin/PurchaseList/Approval/StatusRender.js

@@ -2,18 +2,49 @@ import { Timeline } from 'antd';
 import styles from './index.less';
 import styles from './index.less';
 import { STATUS, SUB_STATUS } from './List';
 import { STATUS, SUB_STATUS } from './List';
 import moment from 'moment';
 import moment from 'moment';
+import { useMemo } from 'react';
 
 
 const StatusRender = ({ statusList }) => {
 const StatusRender = ({ statusList }) => {
+  const list = useMemo(() => {
+    return statusList.map(item => {
+      let attach = [];
+      if (item.attach) {
+        try {
+          attach = JSON.parse(item.attach);
+        } catch (e) {
+          console.error(e);
+        }
+        attach = attach
+          .map(item => {
+            if (item instanceof Object) {
+              return (
+                <div>
+                  <a target="_blank" download={item.name} href={item.url}>
+                    {item.name}
+                  </a>
+                </div>
+              );
+            }
+          })
+          .filter(item => item);
+      }
+      return { ...item, attach };
+    });
+  });
   return (
   return (
     <Timeline>
     <Timeline>
-      {statusList?.map(item => (
-        <Timeline.Item dot={<div className={styles.icon}>1</div>}>
-          <div style={{ fontSize: '16px', color: '#1890ff' }}>{`${
-            STATUS.find(cur => cur.value == item.project_status)?.label
-          }-${SUB_STATUS.find(cur => cur.value == item.status)?.label}`}</div>
-          <div>{`持续时间:${item.continuously}    修改人员:${author_name}   修改时间:${moment(
-            item.c_time
-          ).format('YYYY-MM-DD')}`}</div>
+      {list?.map((item, index) => (
+        <Timeline.Item dot={<div className={styles.icon}>{index + 1}</div>}>
+          <div style={{ fontSize: '16px', color: '#1890ff' }}>
+            {STATUS.find(cur => cur.value == item.project_status)?.label}-
+            {SUB_STATUS.find(cur => cur.value == item.status)?.label}
+          </div>
+          <div>
+            持续时间:{item.continuously}
+            &nbsp;&nbsp;&nbsp;&nbsp; 修改人员:{item.author_name}
+            &nbsp;&nbsp;&nbsp;&nbsp; 修改时间:{moment(item.c_time).format('YYYY-MM-DD')}
+          </div>
+          {item.attach.length > 0 && <div>附件: {item.attach}</div>}
         </Timeline.Item>
         </Timeline.Item>
       ))}
       ))}
     </Timeline>
     </Timeline>

+ 30 - 0
src/pages/PurchaseAdmin/PurchaseList/Approval/index.less

@@ -71,5 +71,35 @@
     padding: 10px;
     padding: 10px;
     border-radius: 12px;
     border-radius: 12px;
     box-shadow: 0px 0px 10px 4px rgba(0, 0, 0, 0.2);
     box-shadow: 0px 0px 10px 4px rgba(0, 0, 0, 0.2);
+    .titleCon {
+      display: flex;
+      width: 100%;
+      justify-content: space-around;
+      margin: 20px 0;
+      .item {
+        text-align: center;
+      }
+      .itemNum {
+        color: #f5a41f;
+        font-size: 32px;
+      }
+    }
+  }
+  .titleText {
+    font-size: 22px;
+  }
+  .bottomCon {
+    display: flex;
+    margin-top: 26px;
+    justify-content: space-between;
+  }
+  .pieContent {
+    position: absolute;
+    top: 16px;
+    right: 20px;
+  }
+
+  .chartCon {
+    height: 400px;
   }
   }
 }
 }

+ 2 - 2
src/services/approval.js

@@ -136,6 +136,6 @@ export async function modifyManager(params) {
 }
 }
 
 
 //历史状态接口
 //历史状态接口
-export async function queryStatusHistory() {
-  return request(`/api/v2/approval/status/history`);
+export async function queryStatusHistory({ id }) {
+  return request(`/api/v2/approval/status/history?id=${id}`);
 }
 }