Explorar o código

Squashed commit of the following:
merge
commit 4fcff5a2ed33923c6f60af8f314ae1ba7157db77
Author: Renxy <18510891294@163.com>
Date: Wed Dec 7 15:29:54 2022 +0800

分类相关提交

commit 7a35be8efb0cf23310db724c31f4ffed59befe39
Author: 任雪彦 <18510891294@163.com>
Date: Tue Dec 6 20:11:53 2022 +0800

bom分类添加

commit ded7e785a648a9d8999612d5a945ee770e3e330b
Author: xujunjie <645007605@qq.com>
Date: Mon Nov 21 16:53:17 2022 +0800

更正ws地址

commit a16fd4d029a7a206e9cad0dc802c185374d8a658
Author: xujunjie <645007605@qq.com>
Date: Mon Nov 21 16:52:23 2022 +0800

修复多sheet页不兼容

# Conflicts:
# src/pages/Detail/FlowModal.js
# src/pages/List/List.js

Renxy %!s(int64=2) %!d(string=hai) anos
pai
achega
826c8bd9b5

+ 1 - 0
config/config.js

@@ -142,6 +142,7 @@ export default {
     '/api': {
       // target: 'http://192.168.20.152:8888/',
       target: 'http://120.55.44.4:8896/',
+      // target: 'http://47.96.12.136:8888/',
       // target: 'http://47.96.12.136:8896/',
       // target: 'http://oraysmart.com:8889/',
       // target: 'http://oraysmart.com:8888/api',

+ 3 - 1
package.json

@@ -68,6 +68,7 @@
     "lodash-decorators": "^6.0.1",
     "luckyexcel": "^1.0.1",
     "memoize-one": "^5.0.0",
+    "module": "^1.2.5",
     "moment": "^2.24.0",
     "nanoid": "1.0.0",
     "numeral": "^2.0.6",
@@ -97,7 +98,8 @@
     "react-router-dom": "^4.3.1",
     "react-sizeme": "^2.6.7",
     "react-sortable-hoc": "^2.0.0",
-    "react-zmage": "^0.8.5"
+    "react-zmage": "^0.8.5",
+    "swiper": "^8.4.5"
   },
   "devDependencies": {
     "@types/react": "^16.8.1",

+ 71 - 18
src/pages/Detail/FilesModal.js

@@ -1,28 +1,73 @@
-import React, { useEffect, useState, useRef } from 'react';
+import React, { useEffect, useState, useRef, useMemo } from 'react';
 import { UploadOutlined } from '@ant-design/icons';
 import { Form } from '@ant-design/compatible';
 import '@ant-design/compatible/assets/index.css';
-import { Button, Modal, message, Table, Spin, Tabs, Upload } from 'antd';
+import { Button, Modal, message, Table, Spin, Tabs, Upload, Select, Space } from 'antd';
 const { TabPane } = Tabs;
 const { confirm } = Modal;
 import moment from 'moment/moment';
 import PreviewFile from '@/components/PreviewFile';
+import { getToken, GetTokenFromUrl } from '@/utils/utils';
 // 历史清单
 function FilesModal(props) {
   const {
+    projectId,
     visible,
     onClose,
     onUpload,
     data,
-    uploadProps,
+    // uploadProps,
+    queryFiles,
     DeleteFile,
     downloadFile,
     loading,
+    typeOptions,
   } = props;
-  const handleSelect = item => {
-    // onSelect(item);
-    // onClose();
-  };
+  const [value, setValue] = useState();
+  const [showData, setShowData] = useState();
+
+  useEffect(() => {
+    if (!value) {
+      setShowData(data);
+      return;
+    }
+    const newData = data.filter(item => item.classify_id == value);
+    setShowData(newData);
+  }, [data, value]);
+
+  const uploadProps = useMemo(() => {
+    const token = getToken() || GetTokenFromUrl();
+    const uploadProps = {
+      name: 'file',
+      showUploadList: false,
+      action: `/api/v1/purchase/attachment/${projectId}`,
+      headers: {
+        'JWT-TOKEN': token,
+      },
+      data: {
+        classify_id: value,
+      },
+      beforeUpload(file) {
+        if (!value) {
+          message.error('请先选择附件分类');
+          return false;
+        }
+      },
+      onChange(info) {
+        if (info.file.status !== 'uploading') {
+          console.log(info.file, info.fileList);
+        }
+        if (info.file.status === 'done') {
+          message.success(`${info.file.name} 文件上传成功`);
+          queryFiles();
+        } else if (info.file.status === 'error') {
+          message.error(`${info.file.name} 文件上传失败`);
+        }
+      },
+    };
+    return uploadProps;
+  }, [value, projectId]);
+
   const columns = [
     {
       title: '预览',
@@ -43,6 +88,11 @@ function FilesModal(props) {
       dataIndex: 'CreatorUser',
       render: record => record.CName || '',
     },
+    {
+      title: '分类',
+      dataIndex: 'classify_id',
+      render: id => typeOptions.find(item => item.id == id)?.name,
+    },
     {
       title: '操作',
       render: record => (
@@ -52,7 +102,7 @@ function FilesModal(props) {
               downloadFile(record);
             }}
           >
-            查看
+            下载
           </a>
           <a
             onClick={() => {
@@ -74,21 +124,24 @@ function FilesModal(props) {
       ),
     },
   ];
-
-  const onClick = item => {
-    // onClose();
-    // onSelect(item);
-  };
   return (
-    <Modal title="附件列表" width="60%" onCancel={onClose} visible={visible} footer={false}>
-      <div>
+    <Modal title="附件列表" width="70%" onCancel={onClose} visible={visible} footer={false}>
+      <Space style={{ display: 'flex', marginBottom: '20px' }}>
+        <div>附件类型:</div>
+        <Select
+          style={{ width: 400 }}
+          value={value}
+          allowClear
+          options={typeOptions}
+          onChange={value => setValue(value)}
+        />
         <Upload {...uploadProps}>
-          <Button type="primary" style={{ marginBottom: 20 }} loading={loading}>
+          <Button type="primary" loading={loading}>
             <UploadOutlined /> 上传文件
           </Button>
         </Upload>
-      </div>
-      <Table rowKey="id" columns={columns} dataSource={data} loading={loading} />
+      </Space>
+      <Table rowKey="id" columns={columns} dataSource={showData} loading={loading} />
     </Modal>
   );
 }

+ 223 - 22
src/pages/Detail/FlowModal.js

@@ -12,17 +12,25 @@ import {
   Space,
   Button,
   Popover,
+  Cascader,
+  AutoComplete,
 } from 'antd';
 import Flow from '@/components/Flow/index';
 import { connect } from 'dva';
 import { GetTokenFromUrl, getToken } from '@/utils/utils';
 import { MODELS, useXFlowApp, useModelAsync } from '@antv/xflow';
 import { CheckOutlined } from '@ant-design/icons';
-import { queryDingInstanceDetail, queryRecordSheet, queryVserionByNode } from '@/services/boom';
+import {
+  queryDelPurchaseExcel,
+  queryDingInstanceDetail,
+  queryRecordSheet,
+  queryVserionByNode,
+} from '@/services/boom';
 import { async } from '@antv/x6/lib/registry/marker/async';
 import VersionModal from './VersionModal';
 import AuditFlow from './AuditFlow';
 
+const { Option } = Select;
 const { Step } = Steps;
 
 const { TextArea } = Input;
@@ -31,11 +39,18 @@ const PAGE_SIZE = 8;
 
 // 提交
 function FlowModal(props) {
+  let token = getToken();
+  const SELECT_TYPE = {
+    NAME: '0',
+    TYPE: '1',
+    CREATOR: '2',
+  };
   const {
     visible,
     version,
     onClose,
     onChangeVersion,
+    onDelVersion,
     form,
     loading,
     flowDetail,
@@ -44,13 +59,17 @@ function FlowModal(props) {
     onCommit,
     commitLoading,
     currentUser,
+    typeOptions,
+    userList,
   } = props;
   const [data, setData] = useState([]);
+  const [showData, setShowData] = useState([]);
   const [nodeLoading, setNodeLoading] = useState(false);
   const [pageSize, setPageSize] = useState(PAGE_SIZE);
   const [stepsData, setStepsData] = useState([]);
   const [versionVisible, setVersionVisible] = useState(false);
-  let token = getToken();
+  const [selectType, setSelectType] = useState(SELECT_TYPE.NAME);
+  const [inputValue, setInputValue] = useState('');
 
   const graphData = useMemo(() => {
     if (!flowDetail) return;
@@ -141,7 +160,6 @@ function FlowModal(props) {
       // });
       return obj;
     });
-    console.log(dataList);
     setStepsData(dataList);
   };
 
@@ -205,7 +223,7 @@ function FlowModal(props) {
     return [
       {
         title: '名称',
-        // width: '33%',
+        width: '25%',
         render: item => (
           <span style={{ color: item.audit_status != 0 ? '#9b9b9b' : '' }}>
             {item.id == version.id && !item.isParent && (
@@ -217,9 +235,31 @@ function FlowModal(props) {
           </span>
         ),
       },
+      {
+        title: '创建人',
+        width: '15%',
+        render: item => {
+          return (
+            item.isParent && (
+              <span>{userList.find(cur => cur.ID == item.author)?.CName || '-'}</span>
+            )
+          );
+        },
+      },
+      {
+        title: '分类',
+        width: '15%',
+        render: item => {
+          return (
+            item.isParent && (
+              <span>{typeOptions.find(cur => cur.id == item.classify_id)?.name}</span>
+            )
+          );
+        },
+      },
       {
         title: '状态',
-        width: '30%',
+        width: '15%',
         render: item => {
           if (!item.flow_id && item.isParent) return;
           let style = { color: getColor(item) };
@@ -255,7 +295,7 @@ function FlowModal(props) {
             dom = txt;
           }
           return item.audit_status != 0 ? (
-            <Button onClick={() => handleChangeClick(item)}>{dom}</Button>
+            <Button onClick={() => onDelVersion(item)}>{dom}</Button>
           ) : (
             <span style={style}>{dom}</span>
           );
@@ -267,24 +307,150 @@ function FlowModal(props) {
         render: item =>
           (item.flow_id || !item.isParent) &&
           item.id != version.id && (
-            <a
-              onClick={() => {
-                console.log(item);
-                onChangeVersion(item);
-                onClose();
-              }}
-            >
-              加载
-            </a>
+            <Space>
+              <a
+                onClick={() => {
+                  console.log(item);
+                  onChangeVersion(item);
+                  onClose();
+                }}
+              >
+                加载
+              </a>
+              {item.audit_status == 0 &&
+              item.author == currentUser.ID && ( //自己创建的&&未提交的清单自己可以删除
+                  <a
+                    onClick={() => {
+                      onDelVersion({ excel_id: item.id });
+                    }}
+                  >
+                    删除
+                  </a>
+                )}
+            </Space>
           ),
       },
     ];
   }, [version]);
 
-  const onChange = () => {
+  const childColumns = useMemo(() => {
+    return [
+      {
+        title: '名称',
+        width: '50%',
+        render: item => (
+          <span style={{ color: item.audit_status != 0 ? '#9b9b9b' : '' }}>
+            {item.id == version.id && !item.isParent && (
+              <CheckOutlined style={{ marginRight: 10 }} />
+            )}
+            {item.version_no && !item.children?.length
+              ? `${item.version_name}.${item.version_no}`
+              : item.version_name}
+          </span>
+        ),
+      },
+      {
+        title: '状态',
+        render: item => {
+          if (!item.flow_id && item.isParent) return;
+          let style = { color: getColor(item) };
+          let txt = '';
+          let dom = '';
+          switch (item.audit_status) {
+            case 0:
+              txt = '未提交';
+              break;
+            case 1:
+              txt = '待审批';
+              break;
+            case 2:
+              txt = '已拒绝';
+              break;
+            case 3:
+              txt = '已通过';
+              break;
+            case 4:
+              txt = '已提交';
+              break;
+          }
+          if (item.status == 1) txt = '已失效';
+
+          // 显示拒绝原因
+          if (item.audit_comment) {
+            dom = (
+              <Popover content={item.audit_comment} title="原因">
+                {txt}
+              </Popover>
+            );
+          } else {
+            dom = txt;
+          }
+          return item.audit_status != 0 ? (
+            <Button onClick={() => onDelVersion(item)}>{dom}</Button>
+          ) : (
+            <span style={style}>{dom}</span>
+          );
+        },
+      },
+      {
+        title: '操作',
+        width: '30%',
+        render: item =>
+          (item.flow_id || !item.isParent) &&
+          item.id != version.id && (
+            <Space>
+              <a
+                onClick={() => {
+                  console.log(item);
+                  onChangeVersion(item);
+                  onClose();
+                }}
+              >
+                加载
+              </a>
+              {item.audit_status == 0 &&
+              item.author == currentUser.ID && ( //自己创建的&&未提交的清单自己可以删除
+                  <a
+                    onClick={() => {
+                      onDelVersion({ excel_id: item.id });
+                    }}
+                  >
+                    删除
+                  </a>
+                )}
+            </Space>
+          ),
+      },
+    ];
+  }, [version]);
+
+  const onChange = value => {
     updateSteps([]);
   };
 
+  useEffect(() => {
+    if (!inputValue) {
+      setShowData(data);
+      return;
+    }
+    let resultData = [...data];
+    switch (selectType) {
+      case SELECT_TYPE.NAME:
+        resultData = data.filter(item => item.version_name.includes(inputValue));
+        break;
+      case SELECT_TYPE.TYPE:
+        const classify = typeOptions.find(item => item.name.includes(inputValue));
+        if (classify) {
+          resultData = data.filter(item => item.classify_id == classify.id);
+        }
+        break;
+      case SELECT_TYPE.CREATOR:
+        resultData = data.filter(item => item.AuthorInfo?.CName.includes(inputValue));
+        break;
+    }
+    setShowData(resultData);
+  }, [inputValue, data]);
+
   return (
     <>
       <Modal
@@ -297,10 +463,10 @@ function FlowModal(props) {
         width="98%"
       >
         <Row gutter={8}>
-          <Col span={16}>
+          <Col span={14}>
             <Flow meta={{ type: 'view' }} flowDetail={graphData} onSelectNode={handleSelectNode} />
           </Col>
-          <Col span={8}>
+          <Col span={10}>
             <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
               <div style={{ fontSize: '16px' }}>清单列表</div>
               {isOut && (
@@ -314,15 +480,48 @@ function FlowModal(props) {
               )}
             </div>
 
-            <div style={{ width: '100%' }}>
+            <div style={{ display: 'flex' }}>
+              <Select
+                defaultValue={selectType}
+                style={{ width: '30%' }}
+                onChange={value => {
+                  setSelectType(value);
+                  setInputValue('');
+                }}
+              >
+                <Option value={SELECT_TYPE.NAME}>名称:</Option>
+                <Option value={SELECT_TYPE.TYPE}>分类:</Option>
+                <Option value={SELECT_TYPE.CREATOR}>创建人:</Option>
+              </Select>
+              <Input
+                placeholder="请输入"
+                value={inputValue}
+                onChange={e => setInputValue(e.target.value)}
+              />
+              <Button type="primary" style={{ marginLeft: '10px' }}>
+                搜索
+              </Button>
+            </div>
+            <div style={{ width: '100%', marginTop: '10px' }}>
               <Table
-                style={{ maxHeight: '90%' }}
+                style={{ maxHeight: '80%' }}
                 columns={columns}
-                dataSource={data}
+                dataSource={showData} //data
                 loading={nodeLoading}
                 bordered={false}
-                pagination={{ pageSize: 8, onChange }}
+                pagination={{ position: ['none', 'none'], pageSize: 999, onChange }}
                 scroll={{ y: 65 * pageSize }}
+                // childrenColumnName="none"
+                // expandable={{
+                //   expandedRowRender: record => (
+                //     <Table
+                //       columns={columns}
+                //       dataSource={record.children}
+                //       pagination={{ position: ['none', 'none'] }}
+                //     />
+                //   ),
+                //   rowExpandable: record => record.children?.length > 0,
+                // }}
               />
             </div>
             {stepsData.map((item, idx) => (
@@ -343,6 +542,7 @@ function FlowModal(props) {
         </Row>
       </Modal>
       <VersionModal
+        typeOptions={typeOptions}
         visible={versionVisible}
         onClose={() => setVersionVisible(false)}
         onOk={values => {
@@ -381,5 +581,6 @@ const getColor = item => {
 export default connect(({ loading, user }) => ({
   loading,
   currentUser: user.currentUser,
+  userList: user.list,
 }))(FlowModal);
 // export default FlowModal;

+ 60 - 9
src/pages/Detail/Index.js

@@ -20,7 +20,7 @@ import CommitAuditModal from './CommitAuditModal';
 import CommentContent from '@/components/CommentContent';
 import MergeModal from './MergeModal';
 import { GetTokenFromUrl, getToken } from '@/utils/utils';
-import { queryDetail, queryDingInstanceExecute } from '@/services/boom';
+import { queryDelPurchaseExcel, queryDetail, queryDingInstanceExecute } from '@/services/boom';
 import HistoryDrawer from './HistoryDrawer';
 import AuditFlow from './AuditFlow';
 import { getCurrentUser } from '@/utils/authority';
@@ -45,6 +45,8 @@ function Detail(props) {
     versionTree,
     match: { params },
     instanceDetail,
+    typeOptions,
+    classifyList,
   } = props;
   const [versionTreeVisible, setVersionTreeVisible] = useState(false);
   const [commentVisible, setCommentVisible] = useState(false);
@@ -81,7 +83,6 @@ function Detail(props) {
 
   const projectId = parseInt(params.projectId);
   const templateId = parseInt(params.templateId);
-
   const auditDetail = useMemo(() => {
     let data = {
       processCode: '',
@@ -678,19 +679,25 @@ function Detail(props) {
     // version.audit_status:4 为副本。不可操作
     if (version.audit_status != 4) {
       //判断权限配置,如果配置了,就指定权限的人可提交,没配置就全部人都可提交
+      //判断分类,这个清单所属分类的操作人可以提交
       const getIsSubmit = () => {
+        let bool = true;
         const nodeId = version.template_node_id;
         if (!flowDetail?.nodes || !nodeId) return;
         const node = flowDetail.nodes.find(item => item.Id == nodeId);
         if (!node || node.name == 'custom-circle') return;
         if (node?.role_list) {
-          return node.role_list
+          bool = node.role_list
             .split(',')
             .some(id => currentUser.roleList?.find(role => role.ID == id));
         }
-        return true;
+        const uidsStr = classifyList.find(item => item.classify_id == version.classify_id)?.uid;
+        if (uidsStr && uidsStr.split(',')?.findIndex(item => item == currentUser.ID) < 0) {
+          bool = false;
+        }
+        return bool;
       };
-      // console.log('是否有权限提交流转   ', getIsSubmit());
+      console.log('是否有权限提交流转   ', getIsSubmit());
       if (getIsSubmit() && version.audit_status != 3)
         menuList.push(<Menu.Item key="commitAudit">提交流转</Menu.Item>);
 
@@ -791,7 +798,7 @@ function Detail(props) {
       type: 'detail/queryFiles',
       payload: {
         // excel_id: id || excelId,
-        excel_id: version.id,
+        excel_id: projectId,
       },
     });
   };
@@ -805,6 +812,9 @@ function Detail(props) {
       headers: {
         'JWT-TOKEN': token,
       },
+      data: {
+        type: 'file',
+      },
       onChange(info) {
         if (info.file.status !== 'uploading') {
           console.log(info.file, info.fileList);
@@ -950,6 +960,28 @@ function Detail(props) {
       callback,
     });
   };
+
+  const onDelVersion = data => {
+    Modal.confirm({
+      title: '提示',
+      content: `是否确认删除清单?`,
+      okText: '确定',
+      cancelText: '取消',
+      onOk: async () => {
+        const res = await queryDelPurchaseExcel(data);
+        if (res.code == 200) {
+          message.success('删除成功');
+          dispatch({
+            type: 'xflow/queryBoomFlowDetail',
+            payload: {
+              id: templateId,
+            },
+          });
+        }
+      },
+    });
+  };
+
   useEffect(() => {
     dispatch({
       type: 'detail/queryProjectRecord',
@@ -966,12 +998,23 @@ function Detail(props) {
     dispatch({
       type: 'user/getRoleList',
     });
+    // dispatch({
+    //   type: 'user/fetch',
+    // });
     dispatch({
-      type: 'user/fetch',
+      type: 'user/fetchDepV2',
     });
     dispatch({
-      type: 'user/fetchDepV2',
+      type: 'detail/queryClassify',
+    });
+
+    dispatch({
+      type: 'detail/queryBindClassify',
+      payload: {
+        project_id: projectId,
+      },
     });
+
     // dispatch({
     //   type: 'detail/queryListParentByUser',
     //   payload: {
@@ -1121,11 +1164,13 @@ function Detail(props) {
         onOk={downloadExcel}
       />
       <FlowModal
+        typeOptions={typeOptions}
         flowDetail={flowDetail}
         visible={flowVisible}
         onClose={() => setFlowVisible(false)}
         version={version}
         onChangeVersion={version => changeVersion(version)}
+        onDelVersion={onDelVersion}
       />
       <AuditModal
         loading={getLoading()}
@@ -1134,15 +1179,19 @@ function Detail(props) {
         onOk={onAudit}
       />
       <FilesModal
+        projectId={projectId}
+        typeOptions={typeOptions}
         loading={getFilesLoading()}
         visible={fileVisible}
         onClose={() => setFileVisible(false)}
-        uploadProps={getUploadProps()}
+        queryFiles={queryFiles}
+        // uploadProps={getUploadProps()}
         DeleteFile={deleteFile}
         downloadFile={downloadFile}
         data={fileList}
       />
       <VersionModal
+        typeOptions={typeOptions}
         loading={getLoading()}
         visible={versionVisible}
         onClose={() => setVersionVisible(false)}
@@ -1171,5 +1220,7 @@ export default connect(({ detail, user, xflow, loading }) => ({
   roleList: detail.roleList,
   versionList: detail.versionList,
   versionTree: detail.versionTree,
+  typeOptions: detail.typeOptions,
+  classifyList: detail.classifyList,
   loading,
 }))(Detail);

+ 11 - 3
src/pages/Detail/LuckySheet.js

@@ -93,6 +93,12 @@ class LuckySheet extends React.Component {
           console.log(operate);
           onUpdate && onUpdate();
         },
+        sheetActivate: sheet => {
+          console.log(sheet);
+          setTimeout(() => {
+            this.luckysheet.setCellFormat(0, 0, 'bg', '#fff');
+          }, 100);
+        },
       },
     };
     if (version) {
@@ -154,12 +160,14 @@ class LuckySheet extends React.Component {
         },
       ];
     }
-    
+
     this.luckysheet.destroy();
     this.luckysheet.create(option);
+    // 比对模式会导致单元格出现[Object object]的情况  任意编辑后才会正常显示
+    // 所以默认设置第一个单元格的背景色
     setTimeout(() => {
-      this.luckysheet.setCellFormat(0, 0, 'bg', "#fff");
-    }, 1000)
+      this.luckysheet.setCellFormat(0, 0, 'bg', '#fff');
+    }, 500);
   }
 
   // componentDidUpdate(prevProps) {

+ 10 - 3
src/pages/Detail/VersionModal.js

@@ -1,18 +1,18 @@
 import React, { useEffect } from 'react';
-import { Modal, Input, Form } from 'antd';
+import { Modal, Input, Form, Select } from 'antd';
 
 // 新建流程
 function VersionModal(props) {
-  const { visible, onClose, onOk, userList = [], data = {}, loading } = props;
+  const { visible, onClose, onOk, userList = [], data = {}, loading ,typeOptions} = props;
   const [form] = Form.useForm();
   const formLayout = { labelCol: { span: 4 }, wrapperCol: { span: 14 } };
 
   const handleOk = async () => {
     let fieldsValue = await form.validateFields();
+    if (!fieldsValue.classify_id) fieldsValue.classify_id = 1;
     fieldsValue.new_version = 0;
     onOk(fieldsValue);
   };
-
   useEffect(() => {
     if (visible) form.resetFields();
   }, [visible]);
@@ -29,6 +29,13 @@ function VersionModal(props) {
         <Form.Item label="名称" name="version_name">
           <Input />
         </Form.Item>
+        <Form.Item label="分类" name="classify_id">
+          <Select
+            defaultValue={typeOptions[0]?.value || 1}
+            options={typeOptions}
+          >
+          </Select>
+        </Form.Item>
         <Form.Item label="详情" name="description">
           <Input.TextArea />
         </Form.Item>

+ 26 - 0
src/pages/Detail/models/detail.js

@@ -35,6 +35,8 @@ import {
   queryDingSchema,
   queryDingInstanceDetail,
   queryListParentByUser,
+  queryClassify,
+  queryBindClassify,
 } from '@/services/boom';
 import { queryRole } from '@/services/SysAdmin';
 import { setCurrentUser } from '@/utils/authority';
@@ -78,6 +80,8 @@ export default {
     versionTree: [],
     auditExcel: [],
     dingInstanceD: [],
+    typeOptions: [],
+    classifyList:[],
   },
 
   effects: {
@@ -561,6 +565,28 @@ export default {
         });
       }
     },
+    *queryClassify ({ payload, callback }, { call, put }) {
+      const data = yield call(queryClassify, payload);
+      if (data) {
+         yield put({
+          type: 'save',
+          payload: {
+            typeOptions: data?.map(item=>{return {...item, label:item.name, value:item.id}}),
+          },
+        });
+      }
+    },
+    *queryBindClassify({ payload, callback }, { call, put }) {
+      const data = yield call(queryBindClassify, payload);
+      if (data) {
+         yield put({
+          type: 'save',
+          payload: {
+            classifyList: data?.map(item=>{return {...item, label:item.name, value:item.id}}),
+          },
+        });
+      }
+    },
   },
 
   reducers: {

+ 14 - 10
src/pages/Flow/Audit.js

@@ -22,10 +22,10 @@ function Audit(props) {
     formData,
     flowDetail,
     simpleFlowDteail,
-    currentUser
+    currentUser,
   } = props;
   const ref = useRef();
-  const permission = currentUser.Permission
+  const permission = currentUser.Permission;
 
   const curItem = useMemo(() => {
     let item = localStorage.getItem('currentAudit');
@@ -34,16 +34,16 @@ function Audit(props) {
 
   const editMode = useMemo(() => {
     // 判断是否有权限
-    if(permission['func-01-point-bom-flow']) {
-      return 1
+    if (permission['func-01-point-bom-flow']) {
+      return 1;
     }
     // 判断是否为创建者
-    if(flowDetail.Creator == currentUser.ID) {
-      return 1
+    if (currentUser.IsSuper) {
+      return 1;
     }
 
-    return 2
-  },[permission,flowDetail])
+    return 2;
+  }, [permission, flowDetail]);
 
   useEffect(() => {
     dispatch({
@@ -61,7 +61,7 @@ function Audit(props) {
       type: 'user/fetchDepV2',
     });
   }, []);
-  
+
   const onChange = values => {
     dispatch({
       type: 'xflow/save',
@@ -103,7 +103,11 @@ function Audit(props) {
           <AuditForm value={formData} onChange={values => onChange(values)} />
         </TabPane>
         <TabPane tab="流程控制" key="2">
-          <Flow meta={{ type: 'edit', editMode, flowId: curItem.id }} flowDetail={flowDetail} ref={ref} />
+          <Flow
+            meta={{ type: 'edit', editMode, flowId: curItem.id }}
+            flowDetail={flowDetail}
+            ref={ref}
+          />
         </TabPane>
       </Tabs>
       <Button

+ 12 - 5
src/pages/Flow/List.js

@@ -8,7 +8,7 @@ import Link from 'umi/link';
 const { Option } = Select;
 
 function List(props) {
-  const { userList, list, dispatch, projectList, permission } = props;
+  const { userList, list, dispatch, projectList, permission, currentUser } = props;
   const [visible, setVisible] = useState(false);
   const columns = [
     {
@@ -19,9 +19,9 @@ function List(props) {
       title: '所属项目',
       dataIndex: 'ProjectId',
       render: projectId => {
-        let project = projectList.find(item => item.id == projectId)
-        if(project) return `${project.project_name}(${project.project_full_code})`
-      }
+        let project = projectList.find(item => item.id == projectId);
+        if (project) return `${project.project_name}(${project.project_full_code})`;
+      },
     },
     {
       title: '操作',
@@ -40,6 +40,12 @@ function List(props) {
       payload: values,
       callback: () => {
         setVisible(false);
+        dispatch({
+          type: 'flow/queryDefaultBindClassify',
+          payload: {
+            project_id: values.project_id,
+          },
+        });
       },
     });
   };
@@ -66,7 +72,7 @@ function List(props) {
         <Button type="primary" style={{ marginRight: 20 }} onClick={() => setVisible(true)}>
           新增工作流
         </Button>
-        {permission['func-01-point-bom-flow'] && (
+        {(permission['func-01-point-bom-flow'] || currentUser.IsSuper) && (
           <Link to="/home/audit-list">
             <Button type="primary">审批流管理</Button>
           </Link>
@@ -87,6 +93,7 @@ function List(props) {
 export default connect(({ user, flow, loading }) => ({
   userList: user.list,
   permission: user.currentUser.Permission,
+  currentUser: user.currentUser,
   list: flow.flowList,
   projectList: flow.projectList,
   loading: loading.models.purchaseList2,

+ 7 - 0
src/pages/Flow/models/flow.js

@@ -10,6 +10,7 @@ import {
   saveAuditFlowInfo,
   queryDepV2,
   queryProcessFlows,
+  queryDefaultBindClassify,
 } from '@/services/boom';
 import {
   queryApproval,
@@ -272,6 +273,12 @@ export default {
         });
       }
     },
+    *queryDefaultBindClassify({ payload }, { call, put }) {
+      const data = yield call(queryDefaultBindClassify, payload);
+      if (data) {
+       
+      }
+    },
   },
 
   reducers: {

+ 70 - 0
src/pages/List/ClassifyModal.js

@@ -0,0 +1,70 @@
+import { List, Modal, Select, Table } from "antd";
+import TreeSelect from "rc-tree-select";
+import React, { useEffect, useMemo } from "react";
+
+const ClassifyModal = ({ data, visible,userList, onClose, handleChange }) => {
+  const {classify =[], project_id} = data
+  const list = useMemo(() => {
+    return userList.map(item => {
+      return {label:item.CName, value:item.ID}
+    })
+  }, [userList])
+
+  const onChange = (e, item) => {
+    console.log(e, item)
+    const idx = classify.findIndex(cur => cur.classify_id == item.classify_id);
+    if (idx > -1) {
+      const curClassifyItem = { ...classify[idx], uid: e.join(',') };
+      classify[idx] = curClassifyItem;
+      handleChange({project_id, classify})
+    }
+  }
+
+  const columns = [
+    {
+      title: '分类名称',
+      width: '50%',
+      render: item =>  item.name,
+    },
+    {
+      title: '选择操作人',
+      width: '50%',
+      render: item => {
+        return ( 
+          <Select
+            mode="multiple"
+            allowClear
+            style={{ width: '100%' }}
+            placeholder="选择操作人"
+            defaultValue={item.uid ? item.uid.split(",").map(item=>Number(item)) : []}
+            onChange={(e) =>  onChange(e,item) }
+            options={list}
+          />
+        )
+      }
+    }
+  ]
+  
+
+  return ( 
+    <Modal
+      width='60%'
+      // confirmLoading={loading}
+      maskClosable={false}
+      destroyOnClose
+      title="编辑分类"
+      visible={visible}
+      onCancel={onClose}
+      onOk={onClose}
+    >
+      <Table
+        columns={columns}
+        dataSource={classify}
+        pagination={{ position: ['none', 'none'] }}
+        scroll={{ y: 500 }}
+      />
+    </Modal>
+  )
+
+}
+export default ClassifyModal;

+ 68 - 7
src/pages/List/List.js

@@ -1,19 +1,29 @@
 import React, { useState, useEffect } from 'react';
-import { Table } from 'antd';
+import { message, Modal, Table } from 'antd';
 import { connect } from 'dva';
 import router from 'umi/router';
 import FlowModal from '../Detail/FlowModal';
-import { queryBoomFlowDetail, queryRecordSheet } from '@/services/boom';
+import {
+  queryAddBindClassify,
+  queryBindClassify,
+  queryBoomFlowDetail,
+  queryDelPurchaseExcel,
+  queryRecordSheet,
+} from '@/services/boom';
 import { getToken } from '@/utils/utils';
+import ClassifyModal from './ClassifyModal';
 
 function List(props) {
-  const { excel, loading, project, dispatch, versionList } = props;
+  const { excel, loading, project, dispatch, versionList, typeOptions, userList } = props;
   const [flowVisible, setFlowVisible] = useState(false);
   const [version, setVersion] = useState({});
   const [versionVisible, setVersionVisible] = useState(false);
   const [flowDetail, setFlowDetail] = useState();
   const [loading2, setLoading2] = useState(false);
   const [commitLoading, setCommitLoading] = useState(false);
+  const [visible, setVisible] = useState(false);
+
+  const [data, setData] = useState([]);
 
   let token = getToken();
 
@@ -43,7 +53,21 @@ function List(props) {
     {
       title: '操作',
       render: record => {
-        if (record.is_parent) return null;
+        if (record.is_parent) {
+          return (
+            <a
+              onClick={async () => {
+                try {
+                  const data = await queryBindClassify({ project_id: record.project_id }); //record.project_id
+                  setData({ project_id: record.project_id, classify: data });
+                  setVisible(true);
+                } catch (error) {}
+              }}
+            >
+              编辑
+            </a>
+          );
+        }
         return (
           <a
             onClick={async () => {
@@ -66,7 +90,6 @@ function List(props) {
       },
     },
   ];
-  console.log(project);
   const queryList = page => {
     console.log(page);
     dispatch({
@@ -91,10 +114,15 @@ function List(props) {
     dispatch({
       type: 'list/queryVersionsList',
     });
-
+    dispatch({
+      type: 'user/fetch',
+    });
     dispatch({
       type: 'user/queryDepV2',
     });
+    dispatch({
+      type: 'list/queryClassify',
+    });
   }, []);
 
   const changeVersion = item => {
@@ -152,6 +180,28 @@ function List(props) {
     });
   };
 
+  const handleChange = async data => {
+    const res = await queryAddBindClassify(data);
+  };
+
+  const onDelVersion = async data => {
+    Modal.confirm({
+      title: '提示',
+      content: `是否确认删除清单?`,
+      okText: '确定',
+      cancelText: '取消',
+      onOk: async () => {
+        const res = await queryDelPurchaseExcel(data);
+        if (res.code == 200) {
+          message.success('删除成功');
+          const data = await queryBoomFlowDetail({ id: version.template_id });
+          console.log(data);
+          setFlowDetail(data);
+        }
+      },
+    });
+  };
+
   return (
     <div>
       <Table
@@ -163,6 +213,7 @@ function List(props) {
         onChange={queryList}
       />
       <FlowModal
+        typeOptions={typeOptions}
         isOut={true}
         flowDetail={flowDetail}
         visible={flowVisible}
@@ -171,15 +222,25 @@ function List(props) {
         onCommit={onCommit}
         onChangeVersion={version => changeVersion(version)}
         commitLoading={commitLoading}
+        onDelVersion={onDelVersion}
+      />
+      <ClassifyModal
+        visible={visible}
+        data={data}
+        userList={userList}
+        onClose={() => setVisible(false)}
+        handleChange={handleChange}
       />
     </div>
   );
 }
 
-export default connect(({ list, loading, detail }) => ({
+export default connect(({ list, loading, detail, user }) => ({
   excel: list.excel,
   project: list.project,
   loading: loading.models.list,
   loadingVersion: loading,
   versionList: list.versionList,
+  typeOptions: list.typeOptions,
+  userList: user.list,
 }))(List);

+ 24 - 1
src/pages/List/models/list.js

@@ -1,4 +1,4 @@
-import { queryProjectRecord } from '@/services/boom';
+import { queryBindClassify, queryClassify, queryProjectRecord } from '@/services/boom';
 import { queryProject } from '@/services/PurchaseList';
 import {
   queryApproval,
@@ -18,6 +18,7 @@ export default {
       pagination: false,
     },
     versionList: [],
+    typeOptions:[ ],
   },
 
   effects: {
@@ -96,6 +97,28 @@ export default {
         callback && callback(response.data?.all);
       }
     },
+    *queryClassify ({ payload, callback }, { call, put }) {
+      const data = yield call(queryClassify, payload);
+      if (data) {
+         yield put({
+          type: 'save',
+          payload: {
+            typeOptions: data?.map(item=>{return {...item, label:item.name, value:item.id}}),
+          },
+        });
+      }
+    },
+    *queryBindClassify({ payload, callback }, { call, put }) {
+      const data = yield call(queryBindClassify, payload);
+      if (data) {
+         yield put({
+          type: 'save',
+          payload: {
+            typeOptions: data?.map(item=>{return {...item, label:item.name, value:item.id}}),
+          },
+        });
+      }
+    },
   },
 
   reducers: {

+ 39 - 0
src/services/boom.js

@@ -395,3 +395,42 @@ export async function queryUserListByRoleID(params) {
   });
   return res.data;
 }
+
+//新增工作流时调用接口 给项目绑定默认分类列表
+//purchase/bom/default-bind-classify?project_id=1
+export async function queryDefaultBindClassify (params) {
+  let res = await request(`/purchase/bom/default-bind-classify?${stringify(params)}`, {
+    method: 'GET',
+  });
+  return res.data;
+}
+
+//获取分类列表
+export async function queryClassify() {
+  let res = await request(`/purchase/bom/get-classify`, {
+    method: 'GET',
+  });
+  return res.data;
+}
+
+export async function queryBindClassify (params) {
+  let res = await request(`/purchase/bom/get-bind-classify?${stringify(params)}`, {
+    method: 'GET',
+  });
+  return res.data;
+}
+
+export async function queryAddBindClassify(data) {
+  return request(`/purchase/bom/add-bind-classify`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
+export async function queryDelPurchaseExcel(params) {
+  let res = await request(`/purchase/bom/del-purchase-excel?${stringify(params)}`, {
+    method: 'GET',
+  });
+  return res;
+}
+