Bläddra i källkod

项目详情及一些公共接口

hanxin 2 år sedan
förälder
incheckning
75cf12339a

+ 4 - 0
src/Engine/ECS/StateSystem.ts

@@ -31,6 +31,10 @@ class StateSystem<T> extends System {
   public changeState(state: T, beKeepStack: boolean = false): void {
     if (this.m_states.CurrentState == state) return;
     if (beKeepStack) this.m_stateStack.push(this.m_states.CurrentState);
+
+    if (this.openLog) {
+      console.log(`State switching ${this.Name}: ${this.m_states.CurrentState} -> ${state}`);
+    }
     this.m_states.changeState(state);
   }
   public CurrentState(): T {

+ 13 - 3
src/Engine/ECS/System.ts

@@ -26,9 +26,19 @@ class System {
     } else {
       this.onDisactived();
     }
+    if (this.openLog) {
+      console.log(`System ${this.Name}, SetActived: ${active}`);
+    }
   }
-  public onActived(): void {}
-  public onDisactived(): void {}
-  public onUpdate() {}
+
+  protected openLog: boolean = false;
+
+  public set OpenLog(openLog: boolean) {
+    this.openLog = openLog;
+  }
+
+  public onActived(): void { }
+  public onDisactived(): void { }
+  public onUpdate() { }
 }
 export default System;

+ 0 - 2
src/Frameworks/SysRouter/index.ts

@@ -56,8 +56,6 @@ export const route: GT.IRouterOptions[] = [
     key: PAGE_KEY.ProjectDetail,
     //@ts-ignore
     component: () => import('@/Project/pages/ProjectAdmin/ProjectDetail'),
-    //@ts-ignore
-    models: () => import('@/Project/pages/ProjectAdmin/models/project'),
     options: {
       header: false,
     },

+ 2 - 8
src/Project/Functions/FuncMain.ts

@@ -2,7 +2,7 @@ import Func from '@/Engine/ECS/Function';
 import LoginHandle from './Handlers/LoginHandler';
 import PlatformMenuHandle from './Handlers/PlatformMenuHandle';
 import DataMeterHandle from './Handlers/DataMeterHandler';
-
+import { FuncPageMenuState } from './LevelAFunctions/FuncPageMenu';
 export enum FuncMainState {
   Login, // 登录页
   PlatformMenu, // 首页
@@ -22,16 +22,10 @@ export default class FuncMain extends Func<FuncMainState> {
       //   () => null,
       //   () => window.GT_APP.funcProjectSelection.setActive(false),
       // );
-<<<<<<< HEAD
+
       // sm.addState(FuncMainState.Login, new LoginHandle());
       // sm.addState(FuncMainState.DataMeter, new DataMeterHandle());
       // sm.addState(FuncMainState.PlatformMenu, new PlatformMenuHandle());
-=======
-      sm.addState(FuncMainState.DataMeter, new DataMeterHandle());
-      sm.addState(FuncMainState.Login, new LoginHandle());
-      sm.addState(FuncMainState.PlatformMenu, new PlatformMenuHandle());
->>>>>>> d109ea915db62dc51bc3640fd6f8794015500715
-
       // sm.addState(
       //   FuncMainState.Map,
       //   () => window.GT_APP.funcMap.setActive(true),

+ 14 - 0
src/Project/Functions/LevelAFunctions/FuncPageMenu.ts

@@ -1,4 +1,5 @@
 import Func from '@/Engine/ECS/Function';
+import FuncProjectDetail from '@/Project/Functions/LevelBFunctions/FuncProjectDetail';
 
 export enum FuncPageMenuState {
   Menu, // 菜单栏页面
@@ -15,11 +16,24 @@ export enum FuncPageMenuState {
 }
 
 export default class FuncPageMenu extends Func<FuncPageMenuState> {
+
+  private funcProjectDetail: FuncProjectDetail;
   constructor(name: string) {
     super(name);
+    this.openLog = true;
+    this.funcProjectDetail = new FuncProjectDetail("FuncProjectDetail");
     super.initStates((sm) => {
       // sm.addState(FuncMainState.Login, new LoginHandle());
+      sm.addState(FuncPageMenuState.ProjectDetail, this.onProjectDetailStateIn.bind(this), null, this.onProjectDetailStateOut.bind(this))
     });
   }
+
+  onProjectDetailStateIn(): void {
+    this.funcProjectDetail.setActive(true);
+  }
+
+  onProjectDetailStateOut(): void {
+    this.funcProjectDetail.setActive(false);
+  }
 }
 

+ 21 - 0
src/Project/Functions/LevelBFunctions/FuncProjectDetail.ts

@@ -0,0 +1,21 @@
+import Func from '@/Engine/ECS/Function';
+import SysPage from '@/Frameworks/SysPage';
+import { PAGE_KEY } from '@/Project/constants';
+
+export enum FuncProjectDetailState {
+  Idle,
+}
+export default class FuncProjectDetail extends Func<FuncProjectDetailState> {
+  constructor(name: string) {
+    super(name);
+    super.initStates((sm) => {
+      sm.addState(FuncProjectDetailState.Idle, this.onIdleStateIn, null, this.onIdleStateExit);
+    });
+  }
+  onIdleStateIn(): void {
+    SysPage.add(PAGE_KEY.ProjectDetail);
+  }
+  onIdleStateExit(): void {
+    SysPage.removeByKey(PAGE_KEY.ProjectDetail);
+  }
+}

+ 9 - 6
src/Project/constants/index.ts

@@ -6,13 +6,7 @@ export enum PAGE_KEY {
   ProjectSelection,
   Map,
   DataMeter,
-<<<<<<< HEAD
   ProjectDetail,//项目详情
-
-=======
-  LimitedIndex,
-  LimitedData,
->>>>>>> d109ea915db62dc51bc3640fd6f8794015500715
 }
 
 export const ProjectStatus = [
@@ -73,5 +67,14 @@ export const ProjectStage = [
   { value: 3, name: '建设+运营' },
 ];
 
+export const RoleType = [
+  { value: 1, name: '项目' },
+  { value: 2, name: '菜单' },
+  { value: 3, name: '文档' },
+  { value: 4, name: '数据' },
+  { value: 5, name: 'BOM' },
+  { value: 6, name: '人日' },
+];
+
 export const BuildNodeCode = 'func-01-build';
 export const OpsNodeCode = 'func-01-build';

+ 174 - 0
src/Project/pages/ProjectAdmin/ProjectDetail.less

@@ -0,0 +1,174 @@
+// @import '~antd/lib/style/themes/default.less';
+//@import '~@/utils/utils.less';
+
+:global {
+  .ant-input[disabled] {
+    cursor: not-allowed;
+    opacity: 1;
+
+    &+.ant-calendar-picker-icon {
+      display: none !important;
+    }
+  }
+
+
+  .ant-select-disabled .ant-select-selection {
+    background: transparent;
+
+    i {
+      display: none;
+    }
+  }
+
+}
+
+.upload {
+  :global {
+    .ant-upload-picture-card-wrapper {
+      display: flex;
+      justify-content: center;
+    }
+
+    .ant-upload.ant-upload-select-picture-card {
+      width: 100%;
+      // height: 400px;
+    }
+  }
+}
+
+.card {
+  :global {
+    .ant-card-body {
+      padding: 20px 20px 0;
+
+      .ant-form-item {
+        padding-bottom: 0;
+      }
+    }
+  }
+}
+
+.heading {
+  margin: 0 0 16px 0;
+  font-size: 28px;
+  line-height: 22px;
+}
+
+.steps:global(.ant-steps) {
+  max-width: 750px;
+  margin: 16px auto;
+}
+
+.errorIcon {
+  margin-right: 24px;
+  color: #f5222d;
+  cursor: pointer;
+
+  i {
+    margin-right: 4px;
+  }
+}
+
+.errorPopover {
+  :global {
+    .ant-popover-inner-content {
+      min-width: 256px;
+      max-height: 290px;
+      padding: 0;
+      overflow: auto;
+    }
+  }
+}
+
+.errorListItem {
+  padding: 8px 16px;
+  list-style: none;
+  border-bottom: 1px solid hsv(0, 0, 91%);
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &:hover {
+    background: tint(#1890ff, 90%);
+  }
+
+  &:last-child {
+    border: 0;
+  }
+
+  .errorIcon {
+    float: left;
+    margin-top: 4px;
+    margin-right: 12px;
+    padding-bottom: 22px;
+    color: #f5222d;
+  }
+
+  .errorField {
+    margin-top: 2px;
+    color: fade(#000, 45%);
+    font-size: 28px;
+  }
+}
+
+.editable {
+  td {
+    padding-top: 13px !important;
+    padding-bottom: 12.5px !important;
+  }
+}
+
+// custom footer for fixed footer toolbar
+.advancedForm+div {
+  padding-bottom: 64px;
+}
+
+.advancedForm {
+  :global {
+    .ant-form .ant-row:last-child .ant-form-item {
+      margin-bottom: 24px;
+    }
+
+    .ant-table td {
+      transition: none !important;
+    }
+  }
+}
+
+.optional {
+  color: fade(#000, 45%);
+  font-style: normal;
+}
+
+//
+//.OperatorButtonGroup {
+//  margin-bottom: 15px;
+//}
+
+.OperatorButton {
+  margin-right: 15px;
+  margin-bottom: 15px;
+  background: #7BFFFB;
+  border-color: #7BFFFB;
+}
+
+.OperatorButtonRight {
+  margin-right: 15px;
+  float: right
+}
+
+.title {
+  :global {
+    .ant-table-title {
+      font-weight: bold;
+    }
+  }
+}
+
+.desc {
+  :global {
+    .ant-col-20 {
+      width: 89.7%;
+      margin-left: -44px;
+    }
+  }
+}

+ 1119 - 0
src/Project/pages/ProjectAdmin/ProjectDetail.tsx

@@ -0,0 +1,1119 @@
+import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react';
+import {
+  Card,
+  Form,
+  Col,
+  Row,
+  DatePicker,
+  Input,
+  Select,
+  TreeSelect,
+  Table,
+  Button,
+  Upload,
+  message,
+  InputNumber,
+  Modal,
+  Tooltip,
+  Switch,
+  Tabs,
+  Empty,
+  AutoComplete,
+  Spin,
+} from 'antd';
+import { Loading3QuartersOutlined, PlusOutlined } from '@ant-design/icons';
+import type { DatePickerProps } from 'antd';
+import type { UploadProps } from 'antd';
+import dayjs from 'dayjs';
+import moment from 'moment';
+import { connect } from 'umi';
+import styles from './ProjectDetail.less';
+import { ProjectStatus, ProjectType, Provinces, ProjectStage } from '@/Project/constants';
+import { useModel, useRequest } from '@umijs/max';
+import { queryProjectById, updateProject, removeProjectUser, addProjectUserV2 } from '@/Project/services/project';
+import UserRoleModal from './UserRoleModal';
+// import ContentPage from '@/pages/Unity/Components/ContentPage';
+// import cardStyle from '@/pages/Unity/Components/Card.less';
+// import { deleteScreenShort, queryScreenShort } from '@/services/ProjectAdmin';
+// import UnityPageTitle from '@/components/UnityPageTitle';
+import { STORAGE_TYPE, LocalService } from '@/Frameworks/SysStorage';
+import { FormInstance } from 'antd/es/form';
+const { TextArea } = Input;
+const { Option } = Select;
+const { TreeNode } = TreeSelect;
+const { confirm } = Modal;
+const { TabPane } = Tabs;
+const fieldLabels = {
+  Name: '项目名称',
+  Code: '项目编号',
+  StartDate: '开始日期',
+  EndDate: '结束日期',
+  Type: '项目类型',
+  Position: '项目地点',
+  LeaderId: '项目经理',
+  Status: '项目状态',
+  Remark: '项目简介',
+  Duration: '项目工期',
+  Customer: '客户信息',
+  Province: '项目所属省份',
+  UndertakenUnit: '承建单位',
+  ConstructionUnit: '建设单位',
+  SiteManager: '初级项目经理',
+  TechnicalDesigner: '工艺主设',
+  MechanicalDesigner: '机械主设',
+  ElectricalDesigner: '电气自控主设',
+  CurrentDuration: '当前工期执行天数',
+  CompanyName: '公司名称',
+  CompanyNumber: '员工人数',
+  Stage: '项目所属平台',
+  WaterName: '水厂名称',
+  // CurrentOperatorNum: '当前作业人数',
+};
+
+// @connect(({ user, pro, project, loading }) => ({
+//   user,
+//   depUserTree: pro.depUserTree,
+//   depTrees: pro.depTrees,
+//   cp: pro.currentProject,
+//   // currentUser: user.currentUser,
+//   projectRoleList: pro.projectRoleList,
+//   // permission: user.currentUser.Permission,
+//   // projectCodes: project.projectCodes,
+//   submitting: loading.effects['form/fetchById'],
+//   cpDetailLoading: loading.effects['pro/fetchById']
+// }))
+function ProjectDetail(props: any) {
+  // 编辑
+  const [editable, setEditable] = useState(false);
+  const [visible, setVisible] = useState(false);
+  const [item, setItem] = useState(null);
+  const [dep, setDep] = useState({});
+  const [screenShot, setScreenShot] = useState(null);
+  const [showUserSelectTree, setShowUserSelectTree] = useState(false);
+  // state = {
+  //   // editable: false,
+  //   // item: null,
+  //   // dep: {},
+  //   // screenShot: null,
+  //   showUserSelectTree: false,
+  // };
+  const [formRef] = Form.useForm();
+  const dateFormat = 'YYYY-MM-DD';
+  const projectId = 46;
+  // componentDidMount() {
+  //   // const projectId = this.props.match.params.projectId;
+  //   console.log(this.props);
+  //   const projectId = 92;
+  //   const { dispatch } = this.props;
+  //   dispatch({
+  //     type: 'pro/fetchById',
+  //     payload: {
+  //       ID: parseInt(projectId, 10),
+  //     },
+  //     callback: cp => {
+
+  //     }
+  //   });
+
+  //   dispatch({
+  //     type: 'pro/fetchDepV2',
+  //   });
+
+  //   dispatch({
+  //     type: 'user/fetchUserList',
+  //     payload: {
+  //       projectId,
+  //     },
+  //   });
+
+  //   dispatch({
+  //     type: 'pro/queryProjectRole',
+  //     payload: {
+  //       projectId,
+  //       mod: 1,
+  //     },
+  //   });
+  //   dispatch({
+  //     type: 'project/queryProjectCodes',
+  //     payload: {
+  //       projectId,
+  //     },
+  //   });
+
+  //   // 获取项目截图
+  //   // queryScreenShort({
+  //   //   projectId,
+  //   // }).then(res => {
+  //   //   this.setState({
+  //   //     screenShot: res.data[0],
+  //   //   });
+  //   // });
+  // }
+
+  const handleDeleteProjectUser = (userId: Number) => {
+    confirm({
+      title: '提醒',
+      content: '确认删除该人员,删除后无法复原',
+      okText: '确认',
+      cancelText: '取消',
+      onOk() {
+        removeProjectUserRequest.run({
+          ID: projectId,
+          ProjectId: projectId,
+          UserId: userId,
+        })
+      },
+    });
+  };
+
+  const projectDetailRequest = useRequest(queryProjectById, {
+    defaultParams: [
+      {
+        ID: projectId,
+      },
+    ],
+    onSuccess(data, params) {
+      formRef.setFieldsValue({
+        'Name': data.Name,
+        'Code': data.Code,
+        'CompanyName': data.CompanyName,
+        'WaterName': data.WaterName,
+        'CompanyNumber': data.CompanyNumber,
+        'StartDate': data.StartDate ? dayjs(moment(data.StartDate).format(dateFormat), dateFormat) : null,
+        'EndDate': data.EndDate ? dayjs(moment(data.EndDate).format(dateFormat), dateFormat) : null,
+        'Type': data.Type,
+        'Stage': data.Stage || 1,
+        'Position': data.Position,
+        'LeaderId': data.LeaderId === 0 ? undefined : data.LeaderId,
+        'UndertakenUnit': data.UndertakenUnit,
+        'Duration': getDuration(data),
+        'CurrentDuration': getDuration(data, true),
+        'ConstructionUnit': data.ConstructionUnit,
+        'SiteManager': data.SiteManager === 0 ? undefined : data.SiteManager,
+        'PurchaseManager': data.PurchaseManager === 0 ? undefined : data.PurchaseManager,
+        'DepartmentManager': data.DepartmentManager === 0 ? undefined : data.DepartmentManager,
+        'TechnicalDesigner': data.TechnicalDesigner === 0 ? undefined : data.TechnicalDesigner,
+        'MechanicalDesigner': data.MechanicalDesigner === 0 ? undefined : data.MechanicalDesigner,
+        'ElectricalDesigner': data.ElectricalDesigner === 0 ? undefined : data.ElectricalDesigner,
+        'Province': data.Province,
+        'Scale': data.Scale,
+        'MainProcess': data.MainProcess,
+        'ServiceScope': data.ServiceScope,
+        'ContractTime': data.ContractTime ? dayjs(data.ContractTime, dateFormat) : null,
+        'ServiceTime': data.ServiceTime,
+        'CooperateMode': data.CooperateMode,
+        'WaterStandard': data.WaterStandard,
+        'ConstructAlarmFlag': data.ConstructAlarmFlag == 1,
+        'OpsAlarmFlag': data.OpsAlarmFlag == 1,
+        'CarouselFlag': data.CarouselFlag == 1,
+        'Remark': data.Remark,
+      });
+    },
+  });
+
+  const updateProjectRequest = useRequest(updateProject, {
+    manual: true,
+    onSuccess(data, params) {
+      success('修改成功');
+      setEditable(false);
+      projectDetailRequest.run({ ID: projectId })
+    },
+  });
+
+  const removeProjectUserRequest = useRequest(removeProjectUser, {
+    manual: true,
+    onSuccess(data, params) {
+      success('删除成功');
+      projectDetailRequest.run({ ID: projectId })
+    },
+  });
+  const addProjectUserRequest = useRequest(addProjectUserV2, {
+    manual: true,
+    onSuccess(data, params) {
+      success('修改成功');
+      OnHandleAllotUserModalVisible(false, null);
+      projectDetailRequest.run({ ID: projectId })
+    },
+  });
+
+
+  const { loading, setCurProjectId, userList } = useModel('userList');
+  const { loading: depTreesLoading, depTrees } = useModel('dep');
+  const { full_roles: roleList } = useModel('projectRoleList');
+
+  const success = (content: string) => {
+    message.success(content);
+  };
+
+  const OnEdit = () => {
+    setEditable(true);
+  };
+
+  // const OnCancelEdit = () => {
+  //   formRef.resetFields({});
+  //   const newState = { ...this.state };
+  //   newState.editable = true;
+  //   newState.empty = true;
+  //   this.setState(newState);
+  // };
+
+  const OnSave = (fieldsValue: any) => {
+    const defaultRemark = `${fieldsValue.Province}${fieldsValue.Position}的${fieldsValue.Name}`;
+    fieldsValue.Duration = getDuration(fieldsValue) || 0;
+    fieldsValue.CurrentDuration = getDuration(fieldsValue, true) || 0;
+    if (fieldsValue.Remark == '' || fieldsValue.Remark == defaultRemark) {
+      Modal.confirm({
+        title: '提示',
+        content:
+          '项目描述将展示在驾驶舱内,默认内容格式为:[所在省份][所在城市]的[项目名称]。建议添加详细项目介绍,有助项目展示。是否继续使用默认内容?',
+        okText: '确定',
+        cancelText: '取消',
+        onOk: () => {
+          fieldsValue.Remark = defaultRemark;
+          save(fieldsValue);
+          formRef.setFieldsValue({ Remark: defaultRemark });
+        },
+        onCancel() { },
+      });
+    } else {
+      save(fieldsValue);
+    }
+
+  };
+  const save = (fieldsValue: any) => {
+    fieldsValue.ConstructAlarmFlag = fieldsValue.ConstructAlarmFlag ? 1 : 0;
+    fieldsValue.OpsAlarmFlag = fieldsValue.OpsAlarmFlag ? 1 : 0;
+    fieldsValue.CarouselFlag = fieldsValue.CarouselFlag ? 1 : 0;
+    fieldsValue.CompanyNumber = fieldsValue.CompanyNumber * 1;
+    fieldsValue.StartDate = fieldsValue.StartDate.format('YYYY-MM-DD');
+    fieldsValue.EndDate = fieldsValue.EndDate.format('YYYY-MM-DD');
+    fieldsValue.ContractTime = fieldsValue.ContractTime.format('YYYY-MM-DD');
+    fieldsValue.ID = projectId * 1;
+    updateProjectRequest.run(fieldsValue);
+  };
+
+  const OnHandleAllotUserModalVisible = (show: boolean, user: any) => {
+    setShowUserSelectTree(show);
+    setItem(user);
+  };
+
+  // HandleAllot = projectUser => {
+  //   const { dispatch } = this.props;
+  //   dispatch({
+  //     type: 'pro/addProjectUser',
+  //     payload: projectUser,
+  //   });
+  //   this.OnHandleAllotUserModalVisible(false);
+  // };
+  const addProjectUser = (values: any) => {
+    addProjectUserRequest.run({
+      project_id: Number(projectId),
+      ...values,
+    })
+  };
+
+  // renderUserSelectTreeNodes = data =>
+  //   data.map(item => {
+  //     if (item.children) {
+  //       return (
+  //         <TreeNode
+  //           title={item.title}
+  //           key={item.key}
+  //           value={item.value}
+  //           dataRef={item}
+  //           selectable={item.selectable}
+  //         >
+  //           {this.renderUserSelectTreeNodes(item.children)}
+  //         </TreeNode>
+  //       );
+  //     }
+  //     return (
+  //       <TreeNode
+  //         title={item.title}
+  //         key={item.ID}
+  //         value={item.value}
+  //         selectable={item.selectable}
+  //       />
+  //     );
+  //   });
+
+  const canAddProjectUser = () => {
+    let currentUser = props.initState.initialState.currentUser;
+    return currentUser.Permission && currentUser.Permission['func-010101'];
+  };
+
+  const getColumns = () => {
+    // 添加成员权限控制
+    let currentUser = props.initState.initialState.currentUser;
+    const addPermission =
+      currentUser.IsSuper || projectDetailRequest.data.LeaderId === currentUser.ID || canAddProjectUser();
+
+    const columns = [
+      {
+        title: '用户名',
+        dataIndex: 'UserName',
+      },
+      {
+        title: '姓名',
+        dataIndex: 'CName',
+      },
+      {
+        title: '手机号',
+        dataIndex: 'Mobile',
+      },
+      {
+        title: '邮箱',
+        dataIndex: 'Email',
+      },
+      {
+        title: '成员角色',
+        dataIndex: 'Role',
+        ellipsis: true,
+        width: 150,
+        render: (roles: any) =>
+          roles
+            .map((role: any) => role.Name)
+            .filter((item: any) => item)
+            .join(','),
+      },
+      // {
+      //   title: '所属部门',
+      //   dataIndex: 'DepId',
+      //   // render: id => {
+      //   //   return this.state.dep[id]?.Name;
+      //   // },
+      //   // dataIndex: 'Dep',
+      //   // render: (text, record) => {
+      //   //   return record.Dep.map(item => item.Name).join(',');
+      //   // },
+      // },
+      {
+        title: '操作',
+        render: (text: any, record: any) => {
+          return (
+            <Fragment>
+              <a
+                onClick={() => {
+                  OnHandleAllotUserModalVisible(true, record);
+                }}
+              >
+                编辑
+              </a>
+              &nbsp;&nbsp;&nbsp;&nbsp;
+              {addPermission && (
+                <a
+                  onClick={() => {
+                    handleDeleteProjectUser(record.ID);
+                  }}
+                >
+                  {' '}
+                  删除
+                </a>
+              )}
+            </Fragment>
+          );
+        },
+      },
+    ];
+
+    return columns;
+  };
+
+  const showJurisdiction = (item: string) => {
+    return props.access[item];
+  };
+  const onCancel = () => {
+    setVisible(false);
+  };
+  const showModal = () => {
+    setVisible(true);
+  };
+  // uploadSuccess = () => {
+  //   const { dispatch } = this.props;
+  //   const {
+  //     match: {
+  //       params: { projectId },
+  //     },
+  //   } = this.props;
+  //   dispatch({
+  //     type: 'pro/fetchById',
+  //     payload: {
+  //       ID: parseInt(projectId, 10),
+  //     },
+  //   });
+  // };
+
+  const screenShotSuccess = () => {
+    // console.log(projectId);
+    // queryScreenShort({
+    //   projectId,
+    // }).then(res => {
+    //   this.setState({
+    //     screenShot: res.data[0],
+    //   });
+    // });
+  };
+
+  const getDuration = (data: any, isCurrent: boolean = false) => {
+    const { StartDate, EndDate } = data;
+    if (!StartDate) return '';
+    if (isCurrent) {
+      return moment().diff(StartDate, 'days') || '';
+    } else {
+      if (!EndDate) return '';
+      return moment(EndDate).diff(StartDate, 'days') || '';
+    }
+  };
+
+  const changeDate = () => {
+    setTimeout(() => {
+      const { StartDate, EndDate } = formRef.getFieldsValue();
+      let CurrentDuration, Duration;
+
+      if (!StartDate) {
+        CurrentDuration = '';
+        Duration = '';
+      } else {
+        CurrentDuration = moment().diff(StartDate.format('YYYY-MM-DD'), 'days') || '';
+        Duration = EndDate ? moment(EndDate.format('YYYY-MM-DD')).diff(StartDate.format('YYYY-MM-DD'), 'days') : '';
+      }
+      formRef.setFieldsValue({ Duration, CurrentDuration });
+    }, 200);
+  };
+
+  // deletePic = () => {
+  //   const { screenShot } = this.state;
+  //   Modal.confirm({
+  //     title: '删除',
+  //     content: '是否确认删除项目截图?',
+  //     okText: '确定',
+  //     okType: 'danger',
+  //     cancelText: '取消',
+  //     onOk: () => {
+  //       // deleteScreenShort({
+  //       //   id: screenShot.ID,
+  //       // }).then(() => {
+  //       //   message.success('删除成功');
+  //       //   this.setState({
+  //       //     screenShot: null,
+  //       //   });
+  //       // });
+  //     },
+  //   });
+  // };
+  // const {
+  //   submitting,
+  //   depUserTree,
+  //   cp,
+  //   currentUser,
+  //   // match: {
+  //   //   params: { projectId },
+  //   // },
+  //   projectId = 46,
+  //   user: { userList },
+  //   projectRoleList,
+  //   projectCodes,
+  //   cpDetailLoading
+  // } = this.props;
+  // const { editable, showUserSelectTree, empty, visible, screenShot, item } = this.state;
+
+  // 修改编辑权限控制
+  // const permission = projectDetailRequest.da.LeaderId === currentUser.ID || currentUser.IsSuper;
+
+  // 添加成员权限控制
+  // const addPermission =
+  //   currentUser.IsSuper || cp.LeaderId === currentUser.ID || this.canAddProjectUser();
+  // const allotMethod = {
+  //   handleAllot: this.HandleAllot,
+  //   handleModalVisible: this.OnHandleAllotUserModalVisible,
+  // };
+
+  useEffect(() => {
+    setCurProjectId(46)
+  }, []);
+  const layout = {
+    labelCol: { span: 6 },
+    wrapperCol: { span: 18 },
+  };
+  const descLayout = {
+    labelCol: { span: 3 },
+    wrapperCol: { span: 20 },
+  };
+  console.log(props);
+
+  return (
+    <>
+      <Card bordered={false}>
+        <Spin spinning={projectDetailRequest.loading || updateProjectRequest.loading}>
+          <Form layout="vertical"
+            form={formRef}
+            onFinish={OnSave}
+          // onFinishFailed={onFinishFailed}
+          >
+            <Row>
+              <div className={styles.OperatorButtonGroup}>
+                {editable &&
+                  (showJurisdiction('func-01-build-8-1-03') ||
+                    showJurisdiction('func-01-ops-2-0-03')) ? (
+                  <Button
+                    className={styles.OperatorButton}
+                    type="primary"
+                    htmlType="submit"
+                  // onClick={this.OnSave}
+                  // loading={submitting}
+                  >
+                    保存
+                  </Button>
+                ) : null}
+                {!editable &&
+                  (showJurisdiction('func-01-build-8-1-03') ||
+                    showJurisdiction('func-01-ops-2-0-03')) ? (
+                  <Button
+                    className={styles.OperatorButton}
+                    type="primary"
+                    onClick={OnEdit}
+                  // loading={submitting}
+                  >
+                    编辑
+                  </Button>
+                ) : null}
+                {(showJurisdiction('func-01-build-8-1-03') ||
+                  showJurisdiction('func-01-ops-2-0-03')) && (
+                    <Button type="primary"
+                      onClick={showModal}
+                    >
+                      项目图片
+                    </Button>
+                  )}
+              </div>
+            </Row>
+            <Row gutter={24}>
+              <Col span={12}>
+                <Form.Item
+                  {...layout}
+                  label={fieldLabels.Name}
+                  name='Name'
+                  rules={[{ required: true, message: '请输入项目名称' }]}>
+                  <Input placeholder="请输入项目名称" disabled={!editable} />
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item
+                  label={fieldLabels.Code}
+                  {...layout}
+                  name='Code'
+                  rules={[{ required: true, message: '请输入项目编号' }]}
+                >
+                  <AutoComplete
+                    // dataSource={projectCodes}
+                    style={{ width: '100%' }}
+                    disabled={!editable}
+                    placeholder="请输入项目编号"
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item
+                  label={fieldLabels.CompanyName}
+                  {...layout}
+                  name='CompanyName'
+                  rules={[{ required: true, message: '请输入公司名称' }]}
+                >
+                  <Input placeholder="请输入公司名称" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item
+                  label={fieldLabels.WaterName}
+                  {...layout}
+                  name='WaterName'
+                  rules={[
+                    { required: true, message: '请输入水厂名称' },
+                    { message: '超过12字数限制', max: 12 },
+                  ]}
+                >
+                  <Input placeholder="请输入水厂名称" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.CompanyNumber} {...layout} name='CompanyNumber' rules={[{ required: true, message: '请输入员工人数' }]}>
+                  <Input type="number" placeholder="请输入员工人数" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.StartDate} {...layout} name='StartDate' rules={[{ required: true, message: '请选择开始日期' }]}>
+                  <DatePicker
+                    // onChange={changeDate}
+                    style={{ width: '100%' }}
+                    disabled={!editable}
+                  />
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item label={fieldLabels.EndDate} {...layout} name='EndDate' rules={[{ required: true, message: '请选择结束日期' }]}>
+                  <DatePicker
+                    // onChange={changeDate}
+                    style={{ width: '100%' }}
+                    disabled={!editable}
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.Type} {...layout} name='Type' rules={[{ required: true, message: '请输入项目类型' }]}>
+                  <Select placeholder="请选择项目状态" disabled={!editable}>
+                    {ProjectType.map(item => {
+                      return (
+                        <Option value={item.value} key={item.value}>
+                          {item.name}
+                        </Option>
+                      );
+                    })}
+                  </Select>
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item label={fieldLabels.Stage} {...layout} name='Stage' rules={[{ required: true, message: '请选择项目所属平台' }]}>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择项目所属平台"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {ProjectStage &&
+                      ProjectStage.map(item => (
+                        <Select.Option key={item.value} value={item.value}>
+                          {item.name}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.Position} {...layout} name='Position' rules={[{ required: true, message: '请输入项目地点' }]}>
+                  <Input
+                    style={{ width: '100%' }}
+                    placeholder="请输入项目地点"
+                    disabled={!editable}
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.LeaderId} {...layout} name='LeaderId' rules={[{ required: true, message: '请选择项目经理' }]}>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择项目经理"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item {...layout} label={fieldLabels.UndertakenUnit} name='UndertakenUnit'>
+                  <Input
+                    placeholder="请输入承建单位"
+                    disabled={!editable}
+                    style={{ width: '100%' }}
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label={fieldLabels.Duration} name='Duration'>
+                  <Input disabled style={{ width: '100%' }} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label={fieldLabels.CurrentDuration} name='CurrentDuration'>
+                  <Input disabled style={{ width: '100%' }} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label={fieldLabels.ConstructionUnit} name='ConstructionUnit'>
+                  <Input placeholder="请输入建设单位" disabled={!editable} />
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item label={fieldLabels.SiteManager} {...layout} name='SiteManager'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择现场经理"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label="采购经理" {...layout} name='PurchaseManager'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择采购经理"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label="分部经理" {...layout} name='DepartmentManager'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择分部经理"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.TechnicalDesigner} {...layout} name='TechnicalDesigner'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择工艺主设"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item label={fieldLabels.MechanicalDesigner} {...layout} name='MechanicalDesigner'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择机械主设"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item label={fieldLabels.ElectricalDesigner} {...layout} name='ElectricalDesigner'>
+                  <Select
+                    showSearch
+                    style={{ width: '100%' }}
+                    placeholder="请选择电气自控主设"
+                    optionFilterProp="children"
+                    filterOption={(input, option) => option?.props.children.indexOf(input) >= 0}
+                    disabled={!editable}
+                  >
+                    {userList &&
+                      userList.map((item: Api.IUser) => (
+                        <Select.Option key={item.ID} value={item.ID}>
+                          {item.CName}
+                        </Select.Option>
+                      ))}
+                  </Select>
+                </Form.Item>
+              </Col>
+              <Col span={12} className={styles.desc}>
+                <Form.Item label={fieldLabels.Province} {...layout} name='Province' rules={[{ required: true, message: '请选择所属省份' }]}>
+                  <Select
+                    placeholder="请选择所属省份"
+                    disabled={!editable}
+                    optionFilterProp="children"
+                  // filterOption={(input, option) =>
+                  //   option?.children?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                  // }
+                  >
+                    {Provinces.map(item => {
+                      return (
+                        <Option value={item} key={item}>
+                          {item}
+                        </Option>
+                      );
+                    })}
+                  </Select>
+                </Form.Item>
+              </Col>
+
+              <Col span={12}>
+                <Form.Item {...layout} label="项目规模" name='Scale'>
+                  <Input placeholder="请输入项目规模" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="主体工艺" name='MainProcess'>
+                  <Input placeholder="请输入主体工艺" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="服务范围" name='ServiceScope'>
+                  <Input placeholder="请输入服务范围" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="签约时间" name='ContractTime'>
+                  <DatePicker style={{ width: '100%' }} disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="运营服务时间" name='ServiceTime'>
+                  <Input placeholder="请输入运营服务时间" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="合作模式" name='CooperateMode'>
+                  <Input placeholder="请输入合作模式" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="出水执行标准" name='WaterStandard'>
+                  <Input placeholder="请输入出水执行标准" disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="推送建设消息" name='ConstructAlarmFlag' valuePropName='checked'>
+                  <Switch
+                    disabled={!editable || !showJurisdiction('func-01-build-8-1-04')}
+                  />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="推送运营消息" name='OpsAlarmFlag' valuePropName='checked'>
+                  <Switch disabled={!editable || !showJurisdiction('func-01-ops-2-0-06')} />
+                </Form.Item>
+              </Col>
+              <Col span={12}>
+                <Form.Item {...layout} label="允许轮播" name='CarouselFlag' valuePropName='checked'>
+                  <Switch disabled={!editable} />
+                </Form.Item>
+              </Col>
+              <Col span={12} className={styles.desc}>
+                <Form.Item label="项目描述" {...layout} name='Remark'>
+                  <TextArea placeholder="请输入项目描述" disabled={!editable} autoSize={true} />
+                </Form.Item>
+              </Col>
+            </Row>
+          </Form>
+        </Spin>
+        <div className={styles.OperatorButtonGroup}>
+          {(showJurisdiction('func-01-build-8-1-02') ||
+            showJurisdiction('func-01-ops-2-0-02')) && (
+              <>
+                <Button
+                  className={styles.OperatorButton}
+                  type="primary"
+                  loading={addProjectUserRequest.loading}
+                  onClick={() => {
+                    OnHandleAllotUserModalVisible(true, null);
+                  }}
+                >
+                  添加项目成员
+                </Button>
+              </>
+            )}
+        </div>
+        {/* <UnityPageTitle style={{ marginTop: 50, marginBottom: 25 }}>项目成员</UnityPageTitle> */}
+        <Table
+          bordered
+          columns={getColumns()}
+          dataSource={projectDetailRequest.data?.User || []}
+          pagination={false}
+          rowKey="ID"
+          title={() => '项目成员'}
+        />
+        <UserRoleModal
+          onOk={(data: any) => {
+            addProjectUser(data);
+          }}
+          onCancel={() => {
+            OnHandleAllotUserModalVisible(false, null);
+          }}
+          values={item}
+          visible={showUserSelectTree}
+          depUserTree={depTrees}
+          roleList={roleList}
+        />
+      </Card>
+      <ImgModal
+        imgUrl={projectDetailRequest?.data?.ImageUrl}
+        screenShot={screenShot}
+        visible={visible}
+        onCancel={onCancel}
+        screenShotSuccess={screenShotSuccess}
+        // uploadSuccess={uploadSuccess}
+        showJurisdiction={showJurisdiction}
+        projectId={projectId}
+      // deletePic={deletePic}
+      />
+    </>
+  );
+
+}
+
+function ImgModal(props: any) {
+  const {
+    visible,
+    imgUrl,
+    screenShot,
+    projectId,
+    onCancel,
+    uploadSuccess,
+    deletePic,
+    screenShotSuccess,
+    showJurisdiction,
+  } = props;
+  const [loading, setLoading] = useState(false);
+  const uploadProps: UploadProps = {
+    accept: 'image/*',
+    name: 'file',
+    action: `/api/v1/project-image-file/${projectId}`,
+    showUploadList: false,
+    listType: 'picture-card',
+    headers: {
+      'JWT-TOKEN': LocalService.getItem(STORAGE_TYPE.token)
+    },
+    className: 'avatar-uploader',
+    beforeUpload: (file: any) => {
+      const isLt = file.size / 1024 < 200;
+      if (!isLt) {
+        message.error('图片必须小于200 KB');
+      }
+      setLoading(isLt);
+      return isLt;
+    },
+    onChange(info: any) {
+      if (info.file.status !== 'uploading') {
+        // console.log(info.file, info.fileList);
+      }
+      if (info.file.status === 'done') {
+        message.success(`${info.file.name} 文件上传成功`);
+        setLoading(false);
+        uploadSuccess();
+      } else if (info.file.status === 'error') {
+        message.error(`${info.file.name} 文件上传失败`);
+        setLoading(false);
+      }
+    },
+  };
+  const sendMessageToUnity = () => {
+    // if (isClick) {
+    // if (window.screenShot) {
+    //   window.screenShot(JSON.stringify('screenShot'));
+    // }
+  };
+  // window.screenShotSuccess = idStr => {
+  //   screenShotSuccess();
+  // };
+  const uploadScreenShot = () => {
+    confirm({
+      title: '提醒',
+      content: '确认上传截图,上传后无法复原',
+      okText: '确认',
+      cancelText: '取消',
+      onOk() {
+        sendMessageToUnity();
+      },
+    });
+  };
+
+  const uploadButton = (
+    <div>,
+      {loading ? <Loading3QuartersOutlined></Loading3QuartersOutlined> : <PlusOutlined></PlusOutlined>}
+      <div className="ant-upload-text">上传</div>
+    </div>
+  );
+
+  return (
+    <Modal title="图片" open={visible} footer={null} onCancel={onCancel}>
+      <Tabs defaultActiveKey="1">
+        <TabPane tab="项目封面" key="1">
+          <div className={styles.upload}>
+            <Upload {...uploadProps}>
+              {imgUrl ? <img src={imgUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
+            </Upload>
+            {/* <Button type="danger" style={{ marginTop: 20 }}>
+            删除
+          </Button> */}
+          </div>
+        </TabPane>
+        <TabPane tab="模型截图" key="2">
+          <div className={styles.upload} style={{ position: 'relative' }}>
+            {(showJurisdiction('func-01-ops-2-0-05') ||
+              showJurisdiction('func-01-build-8-1-05')) && (
+                <Button
+                  type="primary"
+                  onClick={uploadScreenShot}
+                  style={{ marginTop: 20, position: 'absolute', right: 0, bottom: 0, zIndex: 10 }}
+                >
+                  上传预览图
+                </Button>
+              )}
+            {screenShot?.Url ? (
+              <>
+                <img src={screenShot.Url} alt="avatar" style={{ width: '100%' }} />
+                {(showJurisdiction('func-01-ops-2-0-04') ||
+                  showJurisdiction('func-01-build-8-1-06')) && (
+                    <Button type="primary" danger onClick={deletePic} style={{ marginTop: 20 }}>
+                      删除
+                    </Button>
+                  )}
+              </>
+            ) : (
+              <Empty />
+            )}
+          </div>
+        </TabPane>
+      </Tabs>
+    </Modal>
+  );
+}
+export default ProjectDetail;
+

+ 104 - 0
src/Project/pages/ProjectAdmin/UserRoleModal.tsx

@@ -0,0 +1,104 @@
+import React from 'react';
+import { Modal, Select, Form, TreeSelect } from 'antd';
+import { RoleType } from '@/Project/constants/index';
+const { Option } = Select;
+const { TreeNode } = TreeSelect;
+
+function RoleModal(props: any) {
+  const { onOk, onCancel, visible, values, roleList, depUserTree } = props;
+
+  const [form] = Form.useForm();
+
+  const handleOk = () => {
+    form.validateFields().then((fieldsValue: any) => {
+      onOk(fieldsValue);
+    });
+  };
+  const handleCancel = () => {
+    form.resetFields();
+    onCancel();
+  };
+  const renderName = (role: any) => {
+    let type = RoleType.find(item => item.value == role.role_type)?.name;
+    return `${role.name}-${type}`;
+  };
+  const renderUserSelectTreeNodes = (data: any): React.ReactElement => {
+    return data?.map((item: any) => {
+      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}
+        />
+      );
+    });
+  };
+
+  return (
+    <>
+      <Modal
+        title="设置角色"
+        maskClosable={false}
+        destroyOnClose={true}
+        open={visible}
+        onCancel={handleCancel}
+        onOk={handleOk}
+      >
+        <Form labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} form={form}>
+          <Form.Item
+            label="成员"
+            name='user_id'
+            initialValue={values?.ID}
+            rules={[{ required: true, message: '请选择用户' },
+            ]}>
+            <TreeSelect
+              disabled={Boolean(values?.ID)}
+              showSearch
+              allowClear
+              style={{ width: '100%' }}
+              placeholder="请选择用户"
+              multiple={false}
+              filterTreeNode={(input, option) => { return option.props.title === input }}
+              dropdownStyle={{ maxHeight: 348, overflow: 'auto' }}>
+              {renderUserSelectTreeNodes(depUserTree)}
+            </TreeSelect>
+          </Form.Item>
+          <Form.Item
+            label="角色"
+            name='role_ids'
+            initialValue={(values?.Role || []).map((item: any) => item.ID).filter((id: any) => id != '0')}
+          >
+            <Select
+              mode="multiple"
+              filterOption={(input, option: any) =>
+                option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+              }
+            >
+              {roleList?.map((item: any) => (
+                <Option key={item.id} value={item.id} >
+                  {renderName(item)}
+                </Option>
+              ))}
+            </Select>
+          </Form.Item>
+        </Form>
+      </Modal>
+    </>
+  );
+}
+export default RoleModal;

+ 237 - 0
src/Project/pages/ProjectAdmin/models/project.js

@@ -0,0 +1,237 @@
+import { message } from 'antd';
+import { queryRole, queryDep, queryDepV2, queryProjectRole } from '@/Project/services/SysAdmin';
+
+import {
+  addProject,
+  updateProject,
+  removeProject,
+  // addProjectUser,
+  addProjectUserV2,
+  queryProjectById,
+  queryProject,
+  removeProjectUser,
+} from '@/Project/services/ProjectAdmin';
+
+function getSelectTreeData(data) {
+  data.title = `${data.Name}`;
+  data.key = data.ID;
+  data.value = data.ID;
+  return data;
+}
+
+function getDepTreeData(data) {
+  data.title = `${data.Name}`;
+  data.key = data.ID;
+  data.value = data.ID;
+  if (data.children) {
+    data.children.forEach(item => {
+      getDepTreeData(item, false);
+    });
+  }
+  return data;
+}
+
+function getDepUserTree(data) {
+  data.title = `${data.Name}`;
+  data.key = `dep-${data.ID}`;
+  data.value = `dep-${data.ID}`;
+  data.selectable = false;
+  if (!data.children) data.children = new Array();
+
+  if (data.children) {
+    data.children.forEach(item => {
+      getDepUserTree(item, false);
+    });
+  }
+
+  if (data.Users && data.Users.length !== 0) {
+    data.Users.forEach(item => {
+      item.title = item.CName;
+      item.key = item.ID;
+      item.value = item.ID;
+      item.selectable = true;
+      data.children.push(item);
+    });
+  }
+  return data;
+}
+
+const depDict = {};
+
+function getDepMapData(data) {
+  depDict[data.ID] = data;
+  if (data.children) {
+    data.children.forEach(item => {
+      getDepMapData(item, false);
+    });
+  }
+}
+
+export default {
+  namespace: 'pro',
+  state: {
+    data: {
+      list: [],
+      pagination: {},
+    },
+    roleList: {},
+    projectRoleList: [],
+    depTrees: [],
+    depDict: {},
+    currentProject: {},
+    depUserTree: [],
+  },
+
+  effects: {
+    *fetchById({ payload, callback }, { call, put }) {
+      const response = yield call(queryProjectById, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { currentProject: response.data },
+        });
+        callback?.(response.data);
+      }
+      
+    },
+
+    *fetch({ payload }, { call, put }) {
+      const response = yield call(queryProject, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { data: response.data },
+        });
+      }
+    },
+
+    // 查询项目所拥有的角色
+    *queryProjectRole({ payload }, { call, put }) {
+      const response = yield call(queryProjectRole, payload);
+      if (response) {
+        yield put({
+          type: 'save',
+          payload: { projectRoleList: response.data.full_roles },
+        });
+      }
+    },
+    *fetchRole({ payload }, { call, put }) {
+      const response = yield call(queryRole, { pageSize: 999999 });
+      if (response) {
+        const roleList = response.data.list.map(item => {
+          return getSelectTreeData(item);
+        });
+        yield put({
+          type: 'save',
+          payload: { roleList },
+        });
+      }
+    },
+    *fetchDep({ payload, callback }, { call, put }) {
+      const response = yield call(queryDep, { pageSize: 999999 });
+      if (response) {
+        const depTrees = response.data.list.map(item => {
+          getDepMapData(item);
+          return getDepTreeData(item);
+        });
+        callback && callback(depTrees);
+        const depUserTree = response.data.list.map(item => {
+          return getDepUserTree(item);
+        });
+
+        yield put({
+          type: 'save',
+          payload: { depTrees, depDict, depUserTree },
+        });
+      }
+    },
+    *fetchDepV2({ payload, callback }, { call, put }) {
+      const response = yield call(queryDepV2, { pageSize: 999999 });
+      if (response) {
+        const depTrees = response.data.list.map(item => {
+          getDepMapData(item);
+          return getDepTreeData(item);
+        });
+        // console.log(depTrees);
+        var arr = JSON.parse(JSON.stringify(response.data.list));
+        const depUserTree = arr.map(item => {
+          return getDepUserTree(item);
+        });
+        callback && callback(depTrees);
+        yield put({
+          type: 'save',
+          payload: { depTrees, depDict, depUserTree },
+        });
+      }
+    },
+    *add({ payload, callback }, { call, put }) {
+      const response = yield call(addProject, { ...payload.item });
+      if (response) {
+        yield put({
+          type: 'fetch',
+          payload: { ...payload.value },
+        });
+        if (callback) callback();
+      }
+    },
+
+    *update({ payload, callback }, { call, put }) {
+      const response = yield call(updateProject, payload);
+      if (response) {
+        yield put({
+          type: 'fetch',
+          payload: {},
+        });
+        if (callback) callback();
+        message.success('修改成功');
+      }
+    },
+
+    *remove({ payload, callback }, { call, put }) {
+      const response = yield call(removeProject, payload);
+      if (response) {
+        yield put({
+          type: 'fetch',
+          payload: {},
+        });
+        if (callback) callback();
+        message.success('删除成功');
+      }
+    },
+
+    *addProjectUser({ payload, callback }, { call, put }) {
+      const response = yield call(addProjectUserV2, payload);
+      // const response = yield call(addProjectUser, payload);
+      if (response) {
+        yield put({
+          type: 'fetchById',
+          // payload: { ID: payload.ID },
+          payload: { ID: payload.project_id },
+        });
+        if (callback) callback();
+        message.success('添加项目用户成功');
+      }
+    },
+
+    *deleteProjectUser({ payload, callback }, { call, put }) {
+      const response = yield call(removeProjectUser, payload);
+      if (response) {
+        yield put({
+          type: 'fetchById',
+          payload: { ID: payload.ID },
+        });
+        if (callback) callback();
+        message.success('删除项目用户成功');
+      }
+    },
+  },
+
+  reducers: {
+    save(state, action) {
+      return {
+        ...state,
+        ...action.payload,
+      };
+    },
+  },
+};

+ 5 - 0
src/Project/pages/ProjectAdmin/typing.d.ts

@@ -0,0 +1,5 @@
+declare namespace ProjectDetail {
+  interface IProjectDetailProps {
+    detail: Api.IProject
+  }
+}

+ 280 - 0
src/Project/services/SysAdmin.js

@@ -0,0 +1,280 @@
+import { request } from 'umi';
+// import { stringify } from 'qs';
+
+export async function queryRes(params) {
+  return request(`/res`, { params });
+}
+export async function queryWork(params) {
+  return request(`/api/v2/workload/type/info`, { params });
+}
+export async function queryWorkDetail(params) {
+  return request(`/api/v2/workload/type/auth`, { params });
+}
+export async function authWork(data) {
+  return request(`/api/v2/workload/type/auth`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
+export async function queryMenu(params = {}) {
+  return request(`/menu&version=0`, { params });
+}
+
+export async function queryProjectMenu(params) {
+  return request(`/api/v2/user/project/menu/${params.ID}`);
+}
+
+export async function updateMenu(param = {}) {
+  return request(`/menu/update`, {
+    method: 'PUT',
+    body: param,
+  });
+}
+/**
+ *
+ * @param {object} param
+ * @param {string} param.ParentCode 二级节点的编码
+ * @param {string} param.Code 要增加的编码
+ * @param {string} param.Name 要增加的名称
+ * @returns
+ */
+export async function checkMenu(param = {}) {
+  return request(`/check/menu/info`, { param });
+}
+
+export async function addMenu(param) {
+  return request(`/menu/create`, {
+    method: 'POST',
+    body: param,
+  });
+}
+export async function removeMenu(param) {
+  return request(`/menu/delete/${param.ID}`, { method: 'DELETE' });
+}
+
+export async function addRoleRes(param) {
+  return request(`/role/res`, {
+    method: 'POST',
+    body: param,
+  });
+}
+
+export async function removeRes(params) {
+  return request(`/res/delete/${params.ID}`, { method: 'DELETE' });
+}
+
+export async function addRes(params) {
+  return request('/res/create', {
+    method: 'POST',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function updateRes(params = {}, currentPage, pageSize) {
+  return request(`/res/update?currentPage=${currentPage}&pageSize=${pageSize}`, {
+    method: 'PUT',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function queryRole(params) {
+  return request(`/role`, { params });
+}
+
+export async function queryProjectRole(params) {
+  return request(`/api/v2/project/roles/get`, { params });
+}
+
+export async function removeRole(params) {
+  return request(`/role/delete/${params.ID}`, { method: 'DELETE' });
+}
+
+export async function addRole(params) {
+  return request('/role/create', {
+    method: 'POST',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function updateRole(params = {}, currentPage, pageSize) {
+  return request(`/role/update?currentPage=${currentPage}&pageSize=${pageSize}`, {
+    method: 'PUT',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function queryUser(params) {
+  return request(`/user`, { params });
+}
+
+export async function queryUserV2(params) {
+  return request(`/api/v2/user`, { params });
+}
+
+export async function addUserRole(param) {
+  return request(`/user/role`, {
+    method: 'POST',
+    body: param,
+  });
+}
+
+export async function removeUser(params) {
+  return request(`/user/delete/${params.ID}`, { method: 'DELETE' });
+}
+
+export async function addUser(params) {
+  return request('/user/register', {
+    method: 'POST',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function updateUser(params = {}, currentPage, pageSize) {
+  return request(`/user/update?currentPage=${currentPage}&pageSize=${pageSize}`, {
+    method: 'PUT',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function queryDepRole(params) {
+  return request(`/api/v2/dep/role?${stringify(params)}`);
+}
+// 为部门设置角色
+export async function bindDepRole(params) {
+  return request(`/api/v2/dep/role`, {
+    method: 'POST',
+    body: params,
+  });
+}
+
+export async function queryUserDetail(user) {
+  return request(`/api/v2/user/detail/${user.ID}`);
+}
+// 为用户设置角色
+export async function setupDepRole(data) {
+  return request(`/api/v2/user/dep/role`, {
+    method: 'POST',
+    body: data,
+  });
+}
+
+export async function queryDep(params) {
+  return request(`/dep`, { params });
+}
+export async function queryDepV2(params) {
+  return request(`/api/v2/dep`, { params });
+}
+
+export async function queryDepUser(params) {
+  return request(`/api/v2/dep/user`, { params });
+}
+
+export async function removeDep(params) {
+  return request(`/dep/delete/${params.ID}`, {
+    method: 'DELETE',
+  });
+}
+
+export async function deleteDepRole(params) {
+  return request(`/api/v2/dep/role/${params.depID}/${params.roleID}`, {
+    method: 'DELETE',
+  });
+}
+
+export async function addDep(params) {
+  return request('/dep/create', {
+    method: 'POST',
+    body: {
+      ...params,
+    },
+  });
+}
+
+export async function updateDep(params = {}, currentPage, pageSize) {
+  return request(`/dep/update?currentPage=${currentPage}&pageSize=${pageSize}`, {
+    method: 'PUT',
+    body: {
+      ...params,
+    },
+  });
+}
+export async function deleteDep(data = {}) {
+  return request(`/api/v2/dep/role/${data.depID}/${data.roleID},`, {
+    method: 'DELETE',
+  });
+}
+
+export async function queryRoleV2(params) {
+  return request(`/api/v2/project/role/get`, { params });
+}
+// 为项目设置roleType=1的角色
+export async function setupRoleV2(params) {
+  return request(`/api/v2/project/role/setup`, {
+    method: 'POST',
+    body: params,
+  });
+}
+// 为项目设置roleType=2,3,4的角色
+export async function setupRolesV2(params) {
+  return request(`/api/v2/project/roles/setup`, {
+    method: 'POST',
+    body: params,
+  });
+}
+export async function setupMenuV2(params) {
+  return request(`/api/v2/project/menu/setup`, {
+    method: 'POST',
+    body: params,
+  });
+}
+export async function setupBom(params) {
+  return request(`/purchase/bom/excel/col`, {
+    method: 'POST',
+    body: params,
+  });
+}
+export async function menuMove(params = {}) {
+  return request(`/menu/move`, {
+    method: 'PUT',
+    body: params,
+  });
+}
+
+export async function queryFeedbackList(params = {}) {
+  return request(`/issue_feedback/list`, { params });
+}
+
+export async function queryBomList(params = {}) {
+  return request(`/purchase/bom/excel/col`);
+}
+
+export async function updateFeedbackList(params = {}) {
+  return request(`/issue_feedback/status`, {
+    method: 'PUT',
+    body: params,
+  });
+}
+
+export async function queryWorkload(params = {}) {
+  return request(`/api/v2/workload/report/permission`)
+}
+
+export async function setupWorkload(params) {
+  return request(`/api/v2/workload/report/assign_permission`, {
+    method: 'POST',
+    body: params,
+  })
+}

+ 40 - 0
src/Project/services/dep.ts

@@ -0,0 +1,40 @@
+
+import { request } from 'umi';
+
+export async function queryDepV2(params: any) {
+  function getDepUserTree(data: any) {
+    data.title = `${data.Name}`;
+    data.key = `dep-${data.ID}`;
+    data.value = `dep-${data.ID}`;
+    data.selectable = false;
+    if (!data.children) data.children = new Array();
+
+    if (data.children) {
+      data.children.forEach((item: any) => {
+        getDepUserTree(item);
+      });
+    }
+
+    if (data.Users && data.Users.length !== 0) {
+      data.Users.forEach((item: any) => {
+        item.title = item.CName;
+        item.key = item.ID;
+        item.value = item.ID;
+        item.selectable = true;
+        data.children.push(item);
+      });
+    }
+    return data;
+  }
+  const response = await request(`/api/v2/dep`, { params });
+  var data = response.data;
+  try {
+    const depUserTree = data?.list?.map((item: Api.IDep) => {
+      return getDepUserTree(item);
+    });
+    console.log(depUserTree);
+    return { data: depUserTree };
+  } catch (error) {
+    return response;
+  }
+}

+ 55 - 0
src/Project/services/plant.js

@@ -0,0 +1,55 @@
+import { request } from 'umi';
+
+export async function queryList(param) {
+  return request(`/plant-global-info/list/${param.ProjectId}`)
+}
+
+export async function queryItem(param) {
+  return request(`/plant-global-info/item/${param.id}`)
+}
+
+export async function queryUserList(param) {
+  return request(`api/v1/user/project/${param.projectId}`)
+}
+
+export async function updateItem(param) {
+  return request(`/plant-global-info/item`, {
+    method: 'PUT',
+    body: {
+      ...param
+    },
+  })
+}
+
+export async function createItem(param) {
+  return request(`/plant-global-info/item`, {
+    method: 'POST',
+    body: {
+      ...param
+    },
+  })
+}
+
+export async function removeItem(Id) {
+  return request(`/plant-global-info/item/${Id}`, {
+    method: 'DELETE',
+  })
+}
+
+export async function getInfoDetail(param) {
+  return request(`/plant-global-info/item/${param.detailId}/detail`)
+}
+
+export async function removeInfoDetailList(param) {
+  return request(`/plant-global-info/item/${param.detailId}/file/${param.Id}`, {
+    method: 'DELETE',
+  })
+}
+
+export async function changeInfoStatus(param) {
+  return request(`/plant-global-info/item`, {
+    method: 'PATCH',
+    body: JSON.stringify(param),
+  })
+}
+

+ 33 - 0
src/Project/services/project.ts

@@ -6,3 +6,36 @@ export async function getProjectList(params: any): Promise<Api.IResponseStructur
     params,
   });
 }
+
+//获取当前项目详情
+export async function queryProjectById(params: any): Promise<Api.IResponseStructure> {
+  return request(`/api/v2/project/detail/${params.ID}`);
+}
+
+//获取当前项目角色列表
+export async function queryProjectRole(params: any) {
+  return request(`/api/v2/project/roles/get`, { params });
+}
+
+export async function addProjectUserV2(param: any) {
+  return request(`/api/v2/project/user`, {
+    method: 'POST',
+    data: param,
+  });
+}
+
+
+export async function queryUserList(Id: Number) {
+  return request(`/api/v1/user/project/${Id}`);
+}
+
+export async function updateProject(params = {}) {
+  return request(`/api/v1/project/update`, {
+    method: 'PUT',
+    data: params,
+  });
+}
+
+export async function removeProjectUser(params: any) {
+  return request(`/api/v1/project/user/${params.ProjectId}/${params.UserId}`, { method: 'DELETE' });
+}

+ 17 - 0
src/Project/services/typings.d.ts

@@ -95,4 +95,21 @@ declare namespace Api {
     m_time: string;
     status: number;
   }
+
+  interface IDep {
+    Code: string;
+    CreatedBy: number;
+    CreatedOn: string;
+    DeletedBy: number;
+    DeletedFlag: number;
+    DeletedOn: number;
+    ID: number;
+    Name: string;
+    ParentID: number;
+    Remark: string;
+    UpdatedOn: string;
+    UpdatedBy: number;
+    Users: IUser[];
+    children: IDep[];
+  }
 }

+ 13 - 0
src/Project/services/user.ts

@@ -41,3 +41,16 @@ export async function queryAccess(
   });
   return permission;
 }
+
+export async function query() {
+  return request('/api/users');
+}
+export async function queryCurrentV2() {
+  return request('/api/v2/user/current-user');
+}
+export async function queryUnreadNotification() {
+  return request('/notification/unread/');
+}
+export async function SetNotificationRead(Id: number) {
+  return request(`/notification/read/${Id}`, { method: 'PUT' });
+}

+ 13 - 0
src/models/dep.ts

@@ -0,0 +1,13 @@
+import { useRequest } from '@umijs/max';
+import { queryDepV2 } from '@/Project/services/dep';
+const dep = () => {
+  const { data: depTrees, loading: loading, run: run } = useRequest(queryDepV2, {
+    defaultParams: [
+      {
+        pageSize: 9999,
+      },
+    ],
+  });
+  return { depTrees, loading }
+}
+export default dep;

+ 8 - 0
src/models/projectRoleList.ts

@@ -0,0 +1,8 @@
+import { useRequest, useModel } from '@umijs/max';
+import { queryProjectRole } from '@/Project/services/project';
+const projectRoleList = () => {
+  // const { project } = useModel('project');
+  const { data: { full_roles }, loading: loading } = useRequest(queryProjectRole, { defaultParams: [{ projectId: 46, mod: 1 }] });
+  return { full_roles }
+}
+export default projectRoleList;

+ 14 - 0
src/models/userList.ts

@@ -0,0 +1,14 @@
+import React, { useEffect, useMemo, useRef, useState } from 'react';
+import { useModel, useRequest } from '@umijs/max';
+import { queryUserList } from '@/Project/services/project';
+
+export default () => {
+  const [curProjectId, setCurProjectId] = useState(0);
+  const { data: userList, loading: loading, run: run } = useRequest(queryUserList, { manual: true });
+  useEffect(() => {
+    if (curProjectId) {
+      run(curProjectId)
+    }
+  }, [curProjectId]);
+  return { userList, loading, setCurProjectId }
+}