Переглянути джерело

feat: 重写任务列表和详情页面

ZhaoJun 1 рік тому
батько
коміт
1a02c26c85

+ 6 - 5
.umirc.ts

@@ -79,6 +79,11 @@ export default defineConfig({
       path: '/task-manage/:projectID',
       component: './TaskManage',
     },
+    {
+      name: '任务管理-详情',
+      path: '/task-manage/detail',
+      component: './TaskManage/Detail/TaskDetail',
+    },
     {
       name: '消息中心',
       path: '/message/:projectId',
@@ -89,11 +94,7 @@ export default defineConfig({
       path: '/device/:projectId',
       component: './DeviceManager',
     },
-    {
-      name: '任务管理-详情',
-      path: '/task-manage/detail',
-      component: './TaskManage/Detail/TaskDetail',
-    },
+
     // {
     //   name: '权限演示',
     //   path: '/access',

+ 223 - 39
src/pages/TaskManage/Detail/TaskDetail.tsx

@@ -1,11 +1,12 @@
 import PageContent from '@/components/PageContent';
 import PageTitle from '@/components/PageTitle';
 import {
-  MandateChildType,
-  MandateDetailType,
-  PropsType,
-  UserType,
-  WorkOrderType,
+  IMandateChildType,
+  IMandateDetailType,
+  IPropsType,
+  ITopFilter,
+  IUserType,
+  IWorkOrderType,
 } from '@/pages/TaskManage/Detail/detail.types';
 import {
   MandateClass,
@@ -18,58 +19,77 @@ import {
   dispatchOrder,
   getMandateChildList,
   getMandateDetail,
+  getMandateList,
   ignoreTask,
   setTaskAutomation,
 } from '@/services/TaskManage';
 import { connect, useLocation, useRequest } from '@umijs/max';
+
+import TopFilter from '@/pages/TaskManage/components/TopFilter';
+import { IMandateType } from '@/pages/TaskManage/index.types';
+import { Col, Collapse, CollapseProps, Divider, List, Row } from 'antd';
 import React, { useEffect, useState } from 'react';
+import styles from './detail.less';
 
-const TaskDetail: React.FC<PropsType> = (props) => {
+const TaskDetail: React.FC<IPropsType> = (props) => {
   const { userList, dispatch } = props;
   const md5 = require('md5');
   const location = useLocation();
   const queryParams = new URLSearchParams(location.search);
   const project_id = Number(queryParams.get('project_id'));
-  const mandate_id = Number(queryParams.get('mandate_id'));
+  const mandateType = Number(queryParams.get('mandateType'));
 
-  const [mandateDetail, setMandateDetail] = useState<MandateDetailType>();
-  const [handledWorkOrders, setHandledWorkOrders] = useState<WorkOrderType[]>(
+  const [mandateList, setMandateList] = useState<IMandateType[]>([]);
+  const [mandateDetail, setMandateDetail] = useState<IMandateDetailType>();
+  const [handledWorkOrders, setHandledWorkOrders] = useState<IWorkOrderType[]>(
     [],
   );
-  const [subMandateList, setSubMandateList] = useState<MandateChildType[]>([]);
+  const [subMandateList, setSubMandateList] = useState<IMandateChildType[]>([]);
+
+  const [topFilters, setTopFilters] = useState<ITopFilter[]>([]);
+
+  const {
+    data: originMandateList,
+    run: runGetMandateList,
+    refresh: refreshMandateList,
+  } = useRequest(getMandateList, {
+    manual: true,
+    onSuccess: (data) => {
+      setMandateList(data.list);
+    },
+  });
 
   const { run: getDetail, refresh: refreshDetail } = useRequest(
     getMandateDetail,
     {
-      defaultParams: [
-        {
-          project_id,
-          mandate_id,
-        },
-      ],
+      manual: true,
       formatResult: (result) => {
-        const mandate: MandateDetailType = {
+        const mandate: IMandateDetailType = {
           ...result.data,
-          Status: MandateStatus.find((item) => item.value === result.data.Status),
+          Status: MandateStatus.find(
+            (item) => item.value === result.data.Status,
+          ),
           MandateClass: MandateClass.find(
             (item) => item.value === result.data.MandateClass,
           ),
           MandateType: MandateType.find(
             (item) => item.value === result.data.MandateType,
           ),
+          ResponsiblePeople: userList.find(
+            (item) => item.ID === result.data.ResponsiblePeople,
+          ),
         };
-        const workOrderList: WorkOrderType[] = result.data.Records.map(
-          (record: WorkOrderType) => {
+
+        const workOrderList: IWorkOrderType[] = result.data.Records.map(
+          (record: IWorkOrderType) => {
             return {
               ...record,
-              Status: OrderStatus.find(
-                (item) => item.value === record.Status,
-              ),
+              Status: OrderStatus.find((item) => item.value === record.Status),
               RecordType: OrderType.find(
                 (item) => item.value === record.RecordType,
               ),
               Responsible: userList.find(
-                (item: UserType) => item.ID === record.Responsible,
+                (item: IUserType) => item.ID === record.Responsible,
               ),
             };
           },
@@ -80,20 +100,15 @@ const TaskDetail: React.FC<PropsType> = (props) => {
     },
   );
 
-  const {
-    run: getMandateChild,
-    loading,
-    refresh: refreshMandateChild,
-  } = useRequest(getMandateChildList, {
-    defaultParams: [
-      {
-        mandateId: mandate_id,
+  const { run: getMandateChild, refresh: refreshMandateChild } = useRequest(
+    getMandateChildList,
+    {
+      manual: true,
+      formatResult: (result) => {
+        setSubMandateList(result.data);
       },
-    ],
-    formatResult: (result) => {
-      setSubMandateList(result.data);
     },
-  });
+  );
 
   const { run: setAuto } = useRequest(setTaskAutomation, {
     manual: true,
@@ -119,6 +134,30 @@ const TaskDetail: React.FC<PropsType> = (props) => {
     },
   });
 
+  const onTopFilterChange = (value: any, item: ITopFilter, index: number) => {
+    switch (index) {
+      case 0:
+        setMandateList(
+          originMandateList.list.filter(
+            (item: IMandateType) => item.MandateClass === value,
+          ),
+        );
+        break;
+      case 1:
+        setMandateList(
+          originMandateList.list.filter(
+            (item: IMandateType) => item.Status === value,
+          ),
+        );
+        break;
+    }
+  };
+
+  const onTopFilterClean = () => {
+    setMandateList(originMandateList.list)
+  };
+
+  // 获取用户
   useEffect(() => {
     if (userList.length === 0) {
       dispatch({
@@ -127,16 +166,161 @@ const TaskDetail: React.FC<PropsType> = (props) => {
       });
     }
   }, []);
+  // 获取列表
+  useEffect(() => {
+    runGetMandateList({
+      project_id,
+      pageSize: 9999,
+    });
+  }, [userList]);
+  // 顶部下拉过滤器
+  useEffect(() => {
+    const filters: ITopFilter[] = [];
+
+    filters.push({
+      key: '任务类别',
+      placeholder: '任务类别',
+      // @ts-ignore
+      options: MandateClass.map((item) => {
+        if (item.MandateType === mandateType) {
+          return {
+            value: item.value,
+            label: item.label,
+            key: item.value + '任务类别',
+          };
+        }
+      }).filter((item) => item),
+    });
+
+    filters.push({
+      key: '任务状态',
+      placeholder: '任务状态',
+      options: MandateStatus.map((item) => {
+        return {
+          ...item,
+          key: item.value + '任务状态',
+        };
+      }),
+    });
+    setTopFilters(filters);
+  }, [mandateType]);
+
+  const buildTaskList = (item: IMandateType, index: number) => {
+    const formatItem = {
+      ...item,
+      Status: MandateStatus.find((status) => status.value === item.Status),
+      MandateType: MandateType.find((type) => type.value === item.MandateType),
+      MandateClass: MandateClass.find(
+        (itemClass) => itemClass.value === item.MandateClass,
+      ),
+      ResponsiblePeople: userList.find(
+        (user) => user.ID === item.ResponsiblePeople,
+      ),
+    };
+
+    const workOrder = item.Records.map((record) => {
+      return {
+        ...record,
+        Status: OrderStatus.find((status) => status.value === record.Status),
+        RecordType: OrderType.find((type) => type.value === record.RecordType),
+        Responsible: userList.find((user) => user.ID === record.Responsible),
+      };
+    });
+
+    const collapseData: CollapseProps['items'] = [
+      {
+        key: '1',
+        label: (
+          <span style={{ color: '#5697e4' }}>关联工单({workOrder.length})</span>
+        ),
+        children: workOrder.map((order) => {
+          return (
+            <div className={styles.workOrderCard}>
+              <div className={styles.leftInfo}>
+                <Row>
+                  <Col span={12}>工单编号:{order.Id}</Col>
+                  <Col span={12}>时间:{order.CreateTime}</Col>
+                </Row>
+                <Row>
+                  <Col span={12}>
+                    工单状态:
+                    <span style={{ color: '#5697e4' }}>
+                      {order.Status?.label}
+                    </span>
+                  </Col>
+                  <Col span={12}>工单负责人:{order.Responsible?.CName}</Col>
+                </Row>
+              </div>
+              <Divider type="vertical" style={{ height: '40px' }} />
+              <div className={styles.rightButton}>查看工单</div>
+            </div>
+          );
+        }),
+      },
+    ];
+
+    return (
+      <List.Item>
+        <div className={`${styles.cardContainer} card-box`}>
+          <div className={styles.taskInfo}>
+            <Row justify="space-between" style={{ marginBottom: '20px' }}>
+              <Col>时间:{formatItem.CreateTime}</Col>
+              <Col>任务类别:{formatItem.MandateClass?.label}</Col>
+              <Col>
+                任务负责人:{formatItem.ResponsiblePeople?.CName || '-'}
+              </Col>
+            </Row>
+            <Row
+              justify="space-between"
+              style={{ paddingBottom: '10px', borderBottom: '1px solid gray' }}
+            >
+              <Col>任务状态:{formatItem.Status?.label || '-'}</Col>
+              <Col>
+                <div
+                  style={{
+                    width: '80px',
+                    color: 'white',
+                    backgroundColor: '#f5a623',
+                    textAlign: 'center',
+                  }}
+                >
+                  任务详情
+                </div>
+              </Col>
+            </Row>
+            <Row>
+              <Collapse
+                className={styles.collapseLabel}
+                ghost
+                items={collapseData}
+              />
+            </Row>
+          </div>
+        </div>
+      </List.Item>
+    );
+  };
 
   return (
     <PageContent>
-      <PageTitle returnable>任务详情</PageTitle>
-
+      <PageTitle returnable>
+        {MandateType.find((item) => item.value === mandateType)?.label}
+      </PageTitle>
+      <TopFilter
+        filters={topFilters}
+        onChange={onTopFilterChange}
+        onClean={onTopFilterClean}
+      />
+      <List
+        itemLayout="horizontal"
+        dataSource={mandateList}
+        renderItem={buildTaskList}
+      />
     </PageContent>
   );
 };
 
-export default connect(({ taskUser }: any): { userList: UserType[] } => {
+export default connect(({ taskUser }: any): { userList: IUserType[] } => {
   return {
     userList: taskUser.userList,
   };

+ 47 - 0
src/pages/TaskManage/Detail/detail.less

@@ -0,0 +1,47 @@
+
+.cardContainer {
+  width: 100%;
+  padding: 20px 20px;
+  background-color: white;
+
+  .collapseLabel {
+    width: 100%;
+
+    :global {
+      .ant-collapse-header {
+        justify-content: center;
+        flex-direction: row-reverse;
+
+        .ant-collapse-header-text {
+          flex: unset;
+          margin-inline-end: unset;
+        }
+      }
+    }
+
+    .workOrderCard {
+      margin-bottom: 20px;
+      padding: 20px 10px;
+      border-radius: 8px;
+      background-color: #e5effa;
+      display: flex;
+      align-items: center;
+
+      .leftInfo {
+        width: 80%;
+      }
+
+      .rightButton {
+        flex: auto;
+        color: #5697e4;
+        text-align: center;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+      }
+    }
+  }
+}
+
+
+

+ 20 - 14
src/pages/TaskManage/Detail/detail.types.ts

@@ -1,11 +1,11 @@
-import User from "@/pages/TaskManage/models/user";
+import { BaseOptionType } from 'rc-select/es/Select';
 
-export interface PropsType{
-  userList: UserType[],
-  dispatch: (args:{type:string, payload: object})=>{}
+export interface IPropsType {
+  userList: IUserType[];
+  dispatch: (args: { type: string; payload: object }) => {};
 }
 
-export interface MandateChildType {
+export interface IMandateChildType {
   Content: string;
   CreateTime: string;
   ExtendId: number;
@@ -17,7 +17,7 @@ export interface MandateChildType {
   Title: string;
 }
 
-export interface WorkOrderType {
+export interface IWorkOrderType {
   ActualDoneTime: string;
   CreateTime: string;
   Detail: string;
@@ -29,28 +29,34 @@ export interface WorkOrderType {
   Status: number;
 }
 
-export interface MandateDetailType {
+export interface IMandateDetailType {
   Id: number;
   ProjectId: number;
-  MandateType: number;
-  MandateClass: number;
-  ResponsiblePeople: number;
+  MandateType: number | BaseOptionType;
+  MandateClass: number | BaseOptionType;
+  ResponsiblePeople: number | IUserType;
   Detail: string;
-  MandateChild: MandateChildType[];
-  Records: WorkOrderType[];
+  MandateChild: IMandateChildType[];
+  Records: IWorkOrderType[];
   Summary: string;
   CreateTime: string;
-  Status: number;
+  Status: number | BaseOptionType;
   Note: string;
   OperationLog: string;
   OperationPeople: number;
   ExtendId: number;
 }
 
-export interface UserType {
+export interface IUserType {
   CName: string;
   ID: number;
   RoleID: string;
   RoleName: string;
   UserName: string;
 }
+
+export interface ITopFilter {
+  key?: string;
+  placeholder: string;
+  options: { label:string|number, value: any }[];
+}

+ 48 - 0
src/pages/TaskManage/components/TopFilter.tsx

@@ -0,0 +1,48 @@
+import { ITopFilter } from '@/pages/TaskManage/Detail/detail.types';
+import { Divider, Select } from 'antd';
+
+interface IProps {
+  filters: ITopFilter | ITopFilter[];
+  onChange: (value: any, item: ITopFilter, index: number) => void;
+  onClean: () => void;
+}
+
+const TopFilter: React.FC<IProps> = ({ filters, onChange, onClean }) => {
+  return (
+    <div style={{ display: 'flex', justifyContent: 'center' }}>
+      {Array.isArray(filters) ? (
+        filters.map((item, index) => {
+          return (
+            <>
+              <Select
+                key={`${index}${item.placeholder}`}
+                style={{ width: 120 }}
+                size="large"
+                bordered={false}
+                placeholder={item.placeholder}
+                options={item.options}
+                allowClear
+                onClear={onClean}
+                onChange={(value, option) => {
+                  onChange(value, item, index);
+                }}
+              />
+              {filters.length > 1 && index !== filters.length - 1 && (
+                <Divider type="vertical" style={{ margin: '0 50px' }} />
+              )}
+            </>
+          );
+        })
+      ) : (
+        <Select
+          style={{ width: 120 }}
+          bordered={false}
+          defaultValue={filters.placeholder}
+          options={filters.options}
+        />
+      )}
+    </div>
+  );
+};
+
+export default TopFilter;

+ 29 - 1
src/pages/TaskManage/constent.ts

@@ -2,58 +2,86 @@ export const MandateClass = [
   {
     value: 1,
     label: '生产调度类',
+    MandateType: 1,
+    OrderType: 1,
   },
   {
     value: 2,
     label: '成本节约类',
+    MandateType: 1,
+    OrderType: 1,
   },
   {
     value: 3,
     label: '设备自检',
+    MandateType: 2,
+    OrderType: 2,
   },
   {
     value: 4,
     label: '工艺自检',
+    MandateType: 2,
+    OrderType: 1,
   },
   {
     value: 5,
     label: '电气检测',
+    MandateType: 2,
+    OrderType: 2,
   },
   {
     value: 6,
     label: '环境检测',
+    MandateType: 2,
+    OrderType: 2,
   },
   {
     value: 7,
     label: '安防检测',
+    MandateType: 2,
+    OrderType: 2,
   },
   {
     value: 8,
     label: '密闭空间检测',
+    MandateType: 2,
+    OrderType: 2,
   },
   {
     value: 9,
     label: '设备保养',
+    MandateType: 3,
+    OrderType: 3,
   },
   {
     value: 10,
     label: '设备维修',
+    MandateType: 3,
+    OrderType: 2,
   },
   {
     value: 11,
     label: '故障上报',
+    MandateType: 3,
+    OrderType: 2,
   },
   {
     value: 12,
     label: '工艺数据',
+    MandateType: 3,
+    OrderType: 2,
   },
   {
     value: 13,
     label: '设备巡检',
+    MandateType: 3,
+    OrderType: 2,
   },
   {
     value: 14,
     label: '数据超限',
+    MandateType: 3,
+    OrderType: 2,
   },
 ];
 
@@ -64,7 +92,7 @@ export const MandateType = [
   },
   {
     value: 2,
-    label: '系统自检',
+    label: '系统自检任务',
   },
   {
     value: 3,

+ 0 - 2
src/pages/TaskManage/index.less

@@ -1,6 +1,4 @@
 .taskList {
-  height: calc(100vh - 70px);
-  overflow-y: scroll;
   border: none;
 
   .listItem {

+ 43 - 71
src/pages/TaskManage/index.tsx

@@ -1,97 +1,74 @@
 import PageContent from '@/components/PageContent';
 import PageTitle from '@/components/PageTitle';
-import {
-  MandateClass,
-  MandateStatus,
-  MandateType,
-} from '@/pages/TaskManage/constent';
+import { MandateType } from '@/pages/TaskManage/constent';
 import styles from '@/pages/TaskManage/index.less';
-import { PropTypes, mandateType } from '@/pages/TaskManage/index.types';
+import { IMandateType, IPropTypes } from '@/pages/TaskManage/index.types';
 import { getMandateList } from '@/services/TaskManage';
 import { RightOutlined } from '@ant-design/icons';
-import { useParams, useRequest } from '@umijs/max';
+import { connect, useParams, useRequest } from '@umijs/max';
 import { List, Spin } from 'antd';
+import { BaseOptionType } from 'rc-select/es/Select';
 import React, { useEffect, useState } from 'react';
 import { useNavigate } from 'umi';
 
-const TaskManage: React.FC<PropTypes> = (props) => {
+const TaskManage: React.FC<IPropTypes> = (props) => {
+  const { mandateList, dispatch } = props;
   const { projectID } = useParams();
-  console.log(projectID);
   const project_id = Number(projectID === '' ? '0' : projectID);
 
   const navigate = useNavigate();
-
-  const [pagination, setPagination] = useState({
-    total: 0,
-    pageSize: 5,
-    current: 1,
-  });
-  const [mandateList, setMandateList] = useState<mandateType[]>([]);
+  const [mandateCount, setMandateCount] = useState<number[]>([0, 0, 0]);
 
   const {
     run: runGetMandateList,
     loading,
     refresh: refreshMandateList,
   } = useRequest(getMandateList, {
+    manual: true,
     defaultParams: [
       {
         project_id,
-        pageSize: pagination.pageSize,
-        currentPage: pagination.current,
+        pageSize: 99999,
       },
     ],
-    onSuccess: () => {},
-    formatResult: (result) => {
-      const mandates = result.data.list;
-      mandates.forEach((mandate: mandateType) => {
-        mandate.Status =
-          MandateStatus.find((status) => status.value === mandate.Status) || 0;
-        mandate.MandateClass =
-          MandateClass.find(
-            (classItem) => classItem.value === mandate.MandateClass,
-          ) || 0;
-        mandate.MandateType =
-          MandateType.find((type) => type.value === mandate.MandateType) || 0;
-      });
-      setMandateList(result.data.list);
-      setPagination(result.data.pagination);
-    },
   });
 
-  const goToDetail = (item: mandateType) => {
+  useEffect(() => {
+    if (mandateList.length == 0) {
+      dispatch({
+        type: 'mandate/fetchMandateList',
+        payload: { project_id, pageSize: 9999 },
+      });
+    }
+  }, []);
+
+  useEffect(() => {
+    const typeCount = [];
+    for (let i = 0; i < 3; i++) {
+      typeCount[i] = mandateList.filter(
+        (item: IMandateType) => item.MandateType === i + 1,
+      ).length;
+    }
+    setMandateCount(typeCount);
+  }, [mandateList]);
+
+  const goToDetail = (item: number) => {
     navigate(
-      `/task-manage/detail?project_id=${project_id}&mandate_id=${item.Id}`,
+      `/task-manage/detail?project_id=${project_id}&mandateType=${item}`,
     );
   };
 
-  const onPageChange = (page: number, pageSize: number) => {
-    runGetMandateList({ project_id, currentPage: page, pageSize });
-  };
-
-  useEffect(() => {
-    const bodyStyle = document.body.style.background;
-    document.body.style.background = 'none';
-    return () => {
-      document.body.style.background = bodyStyle;
-    };
-  }, []);
-
-  const makeList = (item: mandateType, index: number) => {
+  const makeList = (item: BaseOptionType, index: number) => {
     return (
       <List.Item
         className={styles.listItem}
         onClick={() => {
-          goToDetail(item);
+          goToDetail(item.value);
         }}
       >
-        <List.Item.Meta
-          title={
-            typeof item.MandateType === 'number' ? '' : item.MandateType.label
-          }
-          description={item.Detail}
-        />
+        <List.Item.Meta title={item.label} />
         <div className={styles.itemCount}>
-          <div className={styles.countNumber}>10</div>
+          <div className={styles.countNumber}>{mandateCount[index]}</div>
           <div>任务数量</div>
         </div>
         <RightOutlined />
@@ -107,24 +84,19 @@ const TaskManage: React.FC<PropTypes> = (props) => {
           className={styles.taskList}
           bordered
           itemLayout="horizontal"
-          dataSource={mandateList}
+          dataSource={MandateType}
           renderItem={makeList}
-          pagination={
-            mandateList.length
-              ? {
-                  position: 'bottom',
-                  align: 'end',
-                  simple: true,
-                  showSizeChanger: false,
-                  onChange: onPageChange,
-                  ...pagination,
-                }
-              : false
-          }
+          pagination={false}
         />
       </Spin>
     </PageContent>
   );
 };
 
-export default TaskManage;
+export default connect(({ mandate }: any): { mandateList: IMandateType[] } => {
+  return {
+    mandateList: mandate.mandateList,
+  };
+})(TaskManage);
+
+// export default TaskManage;

+ 11 - 10
src/pages/TaskManage/index.types.ts

@@ -1,24 +1,25 @@
-export interface PropTypes {
-  projectID: string;
-}
 
-export interface selectOption {
-  value: number;
-  label: string;
+import { BaseOptionType } from "rc-select/es/Select";
+import { IUserType, IWorkOrderType } from "@/pages/TaskManage/Detail/detail.types";
+
+export interface IPropTypes {
+  mandateList: IMandateType[];
+  dispatch: (args: { type: string; payload: object }) => {};
 }
 
-export interface mandateType {
+export interface IMandateType {
   Id: number;
   ProjectId: number;
-  MandateType: number | selectOption;
-  MandateClass: number | selectOption;
+  MandateType: number | BaseOptionType;
+  MandateClass: number | BaseOptionType;
   ResponsiblePeople: number;
   Detail: string;
   Summary: string;
   CreateTime: string;
-  Status: number | selectOption;
+  Status: number | BaseOptionType;
   Note: string;
   OperationLog: string;
   OperationPeople: number;
+  Records: IWorkOrderType[];
   ExtendId: string;
 }

+ 28 - 0
src/pages/TaskManage/models/mandate.js

@@ -0,0 +1,28 @@
+import { getMandateList } from "../../../services/TaskManage";
+
+export default {
+  namespace: 'mandate',
+  state: {
+    mandateList: [],
+  },
+  effects: {
+    *fetchMandateList({ payload }, { call, put }) {
+      const response = yield call(getMandateList, payload);
+      if (response) {
+        yield put({
+          type: 'mandateListHandler',
+          payload: response.data.list,
+        });
+      }
+    },
+  },
+
+  reducers:{
+    mandateListHandler(state, { payload }) {
+      return {
+        ...state,
+        mandateList: payload,
+      };
+    },
+  }
+};