فهرست منبع

feat: 添加自定义hooks库来实现合同列表数据展示与树结构展开收起的逻辑复用

lanjianrong 4 سال پیش
والد
کامیت
d74278ee0c
5فایلهای تغییر یافته به همراه164 افزوده شده و 109 حذف شده
  1. 16 28
      src/pages/Contract/List/index.tsx
  2. 50 43
      src/pages/Quality/List/index.tsx
  3. 18 37
      src/pages/Safe/List/index.tsx
  4. 3 1
      src/types/contract.d.ts
  5. 77 0
      src/utils/common/customHooks.ts

+ 16 - 28
src/pages/Contract/List/index.tsx

@@ -5,14 +5,14 @@ import { tenderStore } from '@/store/mobx'
 import { ContractTree } from '@/types/contract'
 import consts from '@/utils/consts'
 import { CaretDownOutlined } from '@ant-design/icons'
-import { Button, Dropdown, Menu, message, Table } from 'antd'
+import { useContractTree, useTableExpand } from '@/utils/common/customHooks'
+import { Button, Dropdown, Menu, Table } from 'antd'
 import { ColumnsType } from 'antd/lib/table'
-import React, { useEffect, useState } from 'react'
+import React, { useEffect } from 'react'
 import { useAliveController } from 'react-activation'
 import { RouteComponentProps, withRouter } from 'react-router-dom'
 import { apiContractList } from './api'
 import styles from './index.module.scss'
-import './index.scss'
 const List: React.FC<RouteComponentProps> = (props) => {
   const { clear } = useAliveController()
   useEffect(() => {
@@ -20,27 +20,7 @@ const List: React.FC<RouteComponentProps> = (props) => {
     clear()
     getTree()
   }, [])
-  const [ tree, setTree ] = useState({
-    bidsectionId: '',
-    children: [],
-    childsTotal: 0,
-    contracts: 0,
-    contractsIncome: '',
-    contractsIncomeProgress: '',
-    contractsPaid: '',
-    contractsPay: '',
-    contractsPayProgress: '',
-    contractsReturned: '',
-    csrf: '',
-    hasFolder: false,
-    id: '',
-    isBid: false,
-    isEnd: false,
-    isfolder: 0,
-    name: '',
-    parentId: '',
-    projectId: ''
-  })
+
   const getTree = async () => {
     const { data, code = -1 } = await apiContractList()
     if (code === consts.RET_CODE.SUCCESS) {
@@ -48,6 +28,9 @@ const List: React.FC<RouteComponentProps> = (props) => {
     }
   }
 
+  const [ tree, setTree ] = useContractTree()
+  const [ expandedRowKeys, setRowKeys ] = useTableExpand(tree)
+
   const linkHandler = (id: string, name: string) => {
     tenderStore.saveTenderInfo({ bidsectionId: id, name })
     props.history.push('/console/contract/content/summary')
@@ -107,17 +90,21 @@ const List: React.FC<RouteComponentProps> = (props) => {
     }
   ]
   const handleMenuClick = ({ key }: any) => {
-    message.info(`Click on item ${key}`)
+    if (key === 'expanded') {
+      setRowKeys(true)
+    } else {
+      setRowKeys(false)
+    }
   }
   const menu = (
     <Menu onClick={handleMenuClick}>
-      <Menu.Item key="1">展开所有</Menu.Item>
-      <Menu.Item key="2">收起所有</Menu.Item>
+      <Menu.Item key="expanded">展开所有</Menu.Item>
+      <Menu.Item key="collapsed">收起所有</Menu.Item>
     </Menu>
   )
 
   return (
-    <div className="list-content">
+    <div className="wrap-contaniner hide-menu pi-bg-white">
       <Header>
         <Slot>
           <Dropdown overlay={menu}>
@@ -132,6 +119,7 @@ const List: React.FC<RouteComponentProps> = (props) => {
           pagination={false}
           rowKey={record => record.id}
           indentSize={20}
+          expandable={{ expandedRowKeys, onExpand: setRowKeys }}
           bordered
         >
         </Table>

+ 50 - 43
src/pages/Quality/List/index.tsx

@@ -3,56 +3,46 @@ import Slot from '@/components/Header/slot'
 import SvgIcon from '@/components/SvgIcon'
 import { tenderStore } from '@/store/mobx'
 import { ContractTree } from '@/types/contract'
+import { useContractTree, useTableExpand } from '@/utils/common/customHooks'
 import consts from '@/utils/consts'
 import { CaretDownOutlined } from '@ant-design/icons'
-import { Button, Dropdown, Menu, message, Table } from 'antd'
+import { Button, Dropdown, Menu, Table } from 'antd'
 import { ColumnsType } from 'antd/lib/table'
 import React, { useEffect, useState } from 'react'
 import { useAliveController } from 'react-activation'
 import { RouteComponentProps, withRouter } from 'react-router-dom'
 import { apiContractList } from './api'
 import styles from './index.module.scss'
-const List: React.FC<RouteComponentProps> = (props) => {
+
+interface TableState {
+  loading: boolean
+  expandedIds: string[]
+}
+const List: React.FC<RouteComponentProps> = props => {
   const { clear } = useAliveController()
   useEffect(() => {
     // 清除所有的缓存页面
     clear()
     getTree()
   }, [])
-  const [ tree, setTree ] = useState({
-    bidsectionId: '',
-    children: [],
-    childsTotal: 0,
-    contracts: 0,
-    contractsIncome: '',
-    contractsIncomeProgress: '',
-    contractsPaid: '',
-    contractsPay: '',
-    contractsPayProgress: '',
-    contractsReturned: '',
-    csrf: '',
-    hasFolder: false,
-    id: '',
-    isBid: false,
-    isEnd: false,
-    isfolder: 0,
-    name: '',
-    parentId: '',
-    projectId: ''
-  })
+  const [ tree, setTree ] = useContractTree()
+  const [ expandedRowKeys, setRowKeys ] = useTableExpand(tree)
+
+  const [ tableState, setTableState ] = useState<TableState>({ loading: false, expandedIds: [] })
   const getTree = async () => {
+    setTableState({ ...tableState, loading: true })
     const { data, code = -1 } = await apiContractList()
     if (code === consts.RET_CODE.SUCCESS) {
       setTree(data)
+      setTableState({ ...tableState, loading: false })
     }
   }
 
   const linkHandler = (id: string, name: string) => {
     tenderStore.saveTenderInfo({ bidsectionId: id, name })
-    // tenderStore.saveName(name)
     props.history.push('/console/quality/content/summary')
   }
-  const columns:ColumnsType<ContractTree> = [
+  const columns: ColumnsType<ContractTree> = [
     {
       title: '名称',
       dataIndex: 'name',
@@ -60,11 +50,21 @@ const List: React.FC<RouteComponentProps> = (props) => {
       width: '40%',
       render: (text: string, record: ContractTree) => {
         if (record.isfolder) {
-          return <div style={{ verticalAlign: "baseline" }}><SvgIcon type={record.hasFolder ? "xxh-folder-open" : "xxh-folder"} /><span className="pi-mg-left-2">{text}</span></div>
+          return (
+            <div style={{ verticalAlign: 'baseline' }}>
+              <SvgIcon type={record.hasFolder ? 'xxh-folder-open' : 'xxh-folder'} />
+              <span className="pi-mg-left-2">{text}</span>
+            </div>
+          )
         } else {
-        return <div><span style={{ color: '#6c757d', marginRight: '.5rem' }}>{record.isEnd ? '└' : '├'}</span>
-          <span className="pi-link-blue" onClick={() => linkHandler(record.bidsectionId, record.name)}>{text}</span>
-        </div>
+          return (
+            <div>
+              <span style={{ color: '#6c757d', marginRight: '.5rem' }}>{record.isEnd ? '└' : '├'}</span>
+              <span className="pi-link-blue" onClick={() => linkHandler(record.bidsectionId, record.name)}>
+                {text}
+              </span>
+            </div>
+          )
         }
       }
     },
@@ -75,49 +75,56 @@ const List: React.FC<RouteComponentProps> = (props) => {
     },
     {
       title: '待整改',
-      dataIndex: 'quality_rectification',
-      key: 'quality_rectification'
+      dataIndex: 'qualityRectification',
+      key: 'qualityRectification'
     },
     {
       title: '整改中',
-      dataIndex: 'quality_rectification_in',
-      key: 'quality_rectification_in'
+      dataIndex: 'qualityRectificationIn',
+      key: 'qualityRectificationIn'
     },
     {
       title: '已整改',
-      dataIndex: 'quality_rectification_finish',
-      key: 'quality_rectification_finish'
+      dataIndex: 'qualityRectificationFinish',
+      key: 'qualityRectificationFinish'
     }
   ]
   const handleMenuClick = ({ key }: any) => {
-    message.info(`Click on item ${key}`)
+    if (key === 'expanded') {
+      setRowKeys(true)
+    } else {
+      setRowKeys(false)
+    }
   }
   const menu = (
     <Menu onClick={handleMenuClick}>
-      <Menu.Item key="1">展开所有</Menu.Item>
-      <Menu.Item key="2">收起所有</Menu.Item>
+      <Menu.Item key="expanded">展开所有</Menu.Item>
+      <Menu.Item key="collapsed">收起所有</Menu.Item>
     </Menu>
   )
 
   return (
-    <div className="wrap-contaniner hide-menu">
+    <div className="wrap-contaniner hide-menu pi-bg-white">
       <Header>
         <Slot>
           <Dropdown overlay={menu}>
-            <Button type="text" size="small" className={styles.textBtn}>展开/收起<CaretDownOutlined /></Button>
+            <Button type="text" size="small" className={styles.textBtn}>
+              展开/收起
+              <CaretDownOutlined />
+            </Button>
           </Dropdown>
         </Slot>
       </Header>
       <div className={styles.tableContent}>
         <Table<ContractTree>
+          loading={tableState.loading}
           columns={columns}
           dataSource={tree.children}
           pagination={false}
           rowKey={record => record.id}
           indentSize={20}
-          bordered
-        >
-        </Table>
+          expandable={{ expandedRowKeys, onExpand: setRowKeys }}
+          bordered></Table>
       </div>
     </div>
   )

+ 18 - 37
src/pages/Safe/List/index.tsx

@@ -1,4 +1,5 @@
 import Header from '@/components/Header'
+import { useContractTree, useTableExpand } from '@/utils/common/customHooks'
 import Slot from '@/components/Header/slot'
 import SvgIcon from '@/components/SvgIcon'
 import { tenderStore } from '@/store/mobx'
@@ -19,39 +20,14 @@ const List: React.FC<RouteComponentProps> = (props) => {
     clear()
     getTree()
   }, [])
-  const [ tree, setTree ] = useState({
-    bidsectionId: '',
-    children: [],
-    childsTotal: 0,
-    contracts: 0,
-    contractsIncome: '',
-    contractsIncomeProgress: '',
-    contractsPaid: '',
-    contractsPay: '',
-    contractsPayProgress: '',
-    contractsReturned: '',
-    csrf: '',
-    hasFolder: false,
-    id: '',
-    isBid: false,
-    isEnd: false,
-    isfolder: 0,
-    name: '',
-    parentId: '',
-    projectId: '',
-    qualityRectificationIn: 0,
-    qualityTotal: 0,
-    safeRectification: 0,
-    safeRectificationIn: 0,
-    safeTotal: 0,
-    qualityRectification: 0
-  })
   const getTree = async () => {
     const { data, code = -1 } = await apiContractList()
     if (code === consts.RET_CODE.SUCCESS) {
       setTree(data)
     }
   }
+  const [ tree, setTree ] = useContractTree()
+  const [ expandedRowKeys, setRowKeys ] = useTableExpand(tree)
 
   const linkHandler = (id: string, name: string) => {
     tenderStore.saveTenderInfo({ bidsectionId: id, name })
@@ -81,32 +57,36 @@ const List: React.FC<RouteComponentProps> = (props) => {
     },
     {
       title: '待整改',
-      dataIndex: 'safe_rectification',
-      key: 'safe_rectification'
+      dataIndex: 'safeRectification',
+      key: 'safeRectification'
     },
     {
       title: '整改中',
-      dataIndex: 'safe_rectification_in',
-      key: 'safe_rectification_in'
+      dataIndex: 'safeRectificationIn',
+      key: 'safeRectificationIn'
     },
     {
       title: '已整改',
-      dataIndex: 'safe_rectification_finish',
-      key: 'safe_rectification_finish'
+      dataIndex: 'safeRectificationFinish',
+      key: 'safeRectificationFinish'
     }
   ]
   const handleMenuClick = ({ key }: any) => {
-    message.info(`Click on item ${key}`)
+    if (key === 'expanded') {
+      setRowKeys(true)
+    } else {
+      setRowKeys(false)
+    }
   }
   const menu = (
     <Menu onClick={handleMenuClick}>
-      <Menu.Item key="1">展开所有</Menu.Item>
-      <Menu.Item key="2">收起所有</Menu.Item>
+      <Menu.Item key="expanded">展开所有</Menu.Item>
+      <Menu.Item key="collapsed">收起所有</Menu.Item>
     </Menu>
   )
 
   return (
-    <div className="wrap-contaniner hide-menu">
+    <div className="wrap-contaniner hide-menu pi-bg-white">
       <Header>
         <Slot>
           <Dropdown overlay={menu}>
@@ -121,6 +101,7 @@ const List: React.FC<RouteComponentProps> = (props) => {
           pagination={false}
           rowKey={record => record.id}
           indentSize={20}
+          expandable={{ expandedRowKeys, onExpand: setRowKeys }}
           bordered
         >
         </Table>

+ 3 - 1
src/types/contract.d.ts

@@ -1,6 +1,6 @@
 export interface ContractTree {
   bidsectionId: string
-  children: ContractTree[] | null[]
+  children: ContractTree[] | undefined
   childsTotal: number
   contracts: number
   contractsIncome: string
@@ -20,9 +20,11 @@ export interface ContractTree {
   projectId: string
   qualityRectification: number
   qualityRectificationIn: number
+  qualityRectificationFinish: number
   qualityTotal: number
   safeRectification: number
   safeRectificationIn: number
+  safeRectificationFinish: number
   safeTotal: number
 }
 

+ 77 - 0
src/utils/common/customHooks.ts

@@ -0,0 +1,77 @@
+/** 自定义hooks库 */
+import { useState } from 'react'
+import { ContractTree } from '@/types/contract'
+
+/** 合同树的自定义hook */
+export const useContractTree = (): [ContractTree, (newTree: ContractTree) => void] => {
+  const [ tree, setTree ] = useState<ContractTree>({
+    bidsectionId: '',
+    children: [],
+    childsTotal: 0,
+    contracts: 0,
+    contractsIncome: '',
+    contractsIncomeProgress: '',
+    contractsPaid: '',
+    contractsPay: '',
+    contractsPayProgress: '',
+    contractsReturned: '',
+    csrf: '',
+    hasFolder: false,
+    id: '',
+    isBid: false,
+    isEnd: false,
+    isfolder: 0,
+    name: '',
+    parentId: '',
+    projectId: '',
+    qualityRectification: 0,
+    qualityRectificationIn: 0,
+    qualityRectificationFinish: 0,
+    qualityTotal: 0,
+    safeRectification: 0,
+    safeRectificationIn: 0,
+    safeRectificationFinish: 0,
+    safeTotal: 0
+  })
+  const onChange = (newTree: ContractTree) => {
+    setTree({ ...tree, ...newTree })
+  }
+  return [ tree, onChange ]
+}
+
+export const useTableExpand = (tree: ContractTree): [string[], (expanded: boolean, record?: ContractTree) => void] => {
+  const [ ids, setIds ] = useState<Array<string>>([])
+  const onChange = (expanded: boolean, record?: ContractTree) => {
+    // 点击图标的展开收起
+    if (record) {
+      if (expanded) {
+        const newIds = ids
+        newIds.push(record.id)
+        setIds(newIds)
+      } else {
+        setIds(ids.filter(item => item !== record.id))
+      }
+    } else {
+      // 手动控制展开收起全部节点
+      if (expanded && tree.children) {
+        const newIds = expandTree(tree.children)
+        setIds(newIds)
+      } else {
+        setIds([])
+      }
+    }
+  }
+  function expandTree(data: ContractTree[]): string[] {
+    const idArr: Array<string> = []
+
+    data.forEach((item: ContractTree) => {
+      if (item.isfolder && item.children?.length) {
+        idArr.push(item.id)
+        idArr.concat(expandTree(item.children))
+      }
+    })
+    return idArr
+  }
+
+  return [ ids, onChange ]
+}