Browse Source

feat: 收入合同表格新增行功能。

lanjianrong 4 years ago
parent
commit
74b67d94e4

+ 5 - 6
package.json

@@ -134,6 +134,7 @@
     "fs-extra": "^8.1.0",
     "html-webpack-plugin": "4.0.0-beta.11",
     "identity-obj-proxy": "3.0.0",
+    "install": "^0.13.0",
     "jest": "24.9.0",
     "jest-environment-jsdom-fourteen": "1.0.1",
     "jest-resolve": "24.9.0",
@@ -143,6 +144,7 @@
     "mini-css-extract-plugin": "0.9.0",
     "mobx-react-devtools": "^6.1.1",
     "node-sass": "^4.14.1",
+    "npm": "^6.14.8",
     "optimize-css-assets-webpack-plugin": "5.0.3",
     "pnp-webpack-plugin": "1.6.4",
     "postcss-flexbugs-fixes": "4.1.0",
@@ -175,17 +177,14 @@
   },
   "dependencies": {
     "@ant-design/icons": "^4.2.2",
-    "@grapecity/spread-sheets": "^14.0.0",
-    "@grapecity/spread-sheets-react": "^14.0.0",
     "antd": "^4.6.4",
     "axios": "^0.20.0",
     "dayjs": "^1.9.5",
-    "mobx": "^6.0.1",
-    "mobx-react": "^7.0.0",
-    "moment": "^2.29.1",
+    "mobx": "^5.15.4",
+    "mobx-react": "^6.1.7",
     "nprogress": "^0.2.0",
     "react": "^17.0.1",
-    "react-activation": "^0.5.5",
+    "react-activation": "^0.5.6",
     "react-dom": "^16.13.1",
     "react-router": "^5.2.0",
     "react-router-dom": "^5.2.0"

+ 7 - 12
src/App.tsx

@@ -1,26 +1,21 @@
 import Guards from '@/components/Navigation'
 import history from '@/utils/history'
-import { Provider } from 'mobx-react'
 import 'nprogress/nprogress.css'
 import React from 'react'
 import { AliveScope } from 'react-activation'
 import { Router, Switch } from 'react-router-dom'
 import './index.scss'
 import { routeConfig } from './router/routes'
-import * as stores from './store/mobx'
 const App = () =>{
   return (
     <div className="App">
-      <Provider {...stores}>
-        <Router history={ history }>
-          <AliveScope>
-            <Switch>
-              <Guards routeConfig={routeConfig}></Guards>
-            </Switch>
-          </AliveScope>
-        </Router >
-
-      </Provider>
+      <Router history={ history }>
+        <AliveScope>
+          <Switch>
+            <Guards routeConfig={routeConfig}></Guards>
+          </Switch>
+        </AliveScope>
+      </Router >
     </div>
   )
 }

+ 1 - 1
src/components/Navigation/index.tsx

@@ -116,7 +116,7 @@ function LoginHandler(props: { targetRoute: RouteModel, ErrorPage: any }): any {
                     noCache ?
                         <targetRoute.component {...props} routeConfig={targetRoute.childRoutes}></targetRoute.component> :
                         (
-                            <KeepAlive id={path}>
+                            <KeepAlive id={`${path}`}>
                                 <targetRoute.component {...props} routeConfig={targetRoute.childRoutes}></targetRoute.component>
                             </KeepAlive>
                         )

+ 24 - 2
src/pages/Contract/Content/Income/api.ts

@@ -1,6 +1,28 @@
 import request from '@/utils/common/request'
 
-export async function apiContractSheet() {
-  const { data } = await request.get('/api/contract/income')
+
+export async function apiResfulContractTree(type: string, payload: object) {
+  let url: string = '', method: string = ''
+  switch (type) {
+    case 'serial':
+      url = '/api/contract/section/serial'
+      method = 'post'
+      break
+    case 'depth':
+      url = '/api/contract/section/depth'
+      method = 'post'
+      break
+    case 'add':
+      url = '/api/contract/section/add'
+      method = 'post'
+      break
+    case 'del':
+      url = '/api/contract/section'
+      method = 'del'
+      break
+    default:
+      break
+  }
+  const { data } = await request[method](url, payload)
   return data
 }

+ 18 - 8
src/pages/Contract/Content/Income/components/TableContent/index.tsx

@@ -2,7 +2,7 @@ import { contractStore, tenderStore } from '@/store/mobx'
 import { iIncomeTree } from '@/types/contract'
 import { contractConsts } from '@/utils/common/constStatus'
 import consts from '@/utils/consts'
-import { Button, message, Radio, Table, Tabs } from 'antd'
+import { Button, Input, message, Radio, Table, Tabs } from 'antd'
 import Modal from 'antd/lib/modal/Modal'
 import { RadioChangeEvent } from 'antd/lib/radio'
 import { ColumnsType } from 'antd/lib/table'
@@ -86,7 +86,7 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
           template2: data.sectionTemplate2
         })
       } else {
-        contractStore.updateTree(data.sectionTree)
+        contractStore.updateTree(data.sectionTree.children)
       }
     }
   }
@@ -116,7 +116,14 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
     },
     {
       title: '项目名称',
-      dataIndex: 'name'
+      dataIndex: 'name',
+      render: (text:any, record: iIncomeTree) => {
+        if (record.isEdit) {
+          return <Input size="small" type="text"></Input>
+        } else {
+        return <span>{text}</span>
+        }
+      }
     },
     {
       title: '合同名称',
@@ -129,19 +136,22 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
     {
       title: '合同金额',
       dataIndex: 'contractPrice',
-      align: 'right'
+      align: 'right',
+      // eslint-disable-next-line react/display-name
+      render: (text:any, record: iIncomeTree) => record.contractCode ? <span>{text}</span> : ''
     },
     {
       title: '回款金额',
       dataIndex: 'contractReturned',
-      align: 'right'
+      align: 'right',
+      // eslint-disable-next-line react/display-name
+      render: (text:any, record: iIncomeTree) => record.contractCode ? <span>{text}</span> : ''
     },
     {
       title: '状态',
       dataIndex: 'contractStatus',
       // eslint-disable-next-line react/display-name
-    render: (_: any, record: iIncomeTree) =>
-      <span><i className={contractConsts[record.contractStatus].className}></i>{contractConsts[record.contractStatus].text}</span>
+      render: (_: any, record: iIncomeTree) => record.contractCode ? <span><i className={contractConsts[record.contractStatus].className}></i>{contractConsts[record.contractStatus].text}</span> : ''
     }
 
   ]
@@ -253,7 +263,7 @@ const GCsheet: React.FC<iTableContentPorps> = ({ modalHandler, row, setRow }) =>
       {
         contractStore.showTable ?
         <Table<iIncomeTree>
-          dataSource={contractStore.tree.children}
+          dataSource={contractStore.tree}
           columns={TableColumns}
           bordered
           pagination={false}

+ 48 - 24
src/pages/Contract/Content/Income/index.tsx

@@ -1,12 +1,11 @@
 import Header from '@/components/Header'
 import Slot from '@/components/Header/slot'
+import { contractStore } from '@/store/mobx'
 import { iIncomeTree, iModalBooleanProps } from '@/types/contract'
 import { contractTreeBaseId } from '@/utils/common/constStatus'
-import consts from '@/utils/consts'
 import { ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined, ArrowUpOutlined, CloseOutlined, PlusOutlined, SettingOutlined } from '@ant-design/icons'
 import { Button, Tooltip } from 'antd'
 import React, { useState } from 'react'
-import { apiContractSheet } from './api'
 import ContractModal from './components/Modal'
 import TableContent from './components/TableContent'
 
@@ -17,6 +16,8 @@ export default function Income() {
     confirmLoading: false
   })
   const [ row, setRow ] = useState<iIncomeTree>({
+    elderBrother: false,
+    isEnd: false,
     attribsortution: 0,
     attribution: '',
     bidsectionId: '',
@@ -45,10 +46,10 @@ export default function Income() {
       ...modalObj,
       confirmLoading: true
     })
-    const { code = -1 } = await apiContractSheet()
-    if (code === consts.RET_CODE.SUCCESS) {
+    // const { code = -1 } = await apiContractIncome()
+    // if (code === consts.RET_CODE.SUCCESS) {
       //
-    }
+    // }
     setModalObj({
       ...modalObj,
       type: '',
@@ -63,6 +64,15 @@ export default function Income() {
       type
     })
   }
+  const treeResfulApiHandler = async (type: string, payload: any) => {
+    if (type === 'add') {
+      contractStore.addRowTree(payload.id)
+    }
+    // const { code } = await apiResfulContractTree(type, payload)
+    // if ( code === consts.RET_CODE.SUCCESS) {
+    //   contractStore.resetTree(tenderStore.bidsectionId)
+    // }
+  }
   return (
     <div className="content-wrap">
       <Header title="维护项目节:">
@@ -72,36 +82,50 @@ export default function Income() {
               row.id ?
               <>
                 <Tooltip title="添加子项">
-                  <Button type="text" icon={<PlusOutlined style={{ color: '#007bff' }}/>}></Button>
+                  <Button type="text" icon={<PlusOutlined style={{ color: '#007bff' }}/>} onClick={() => treeResfulApiHandler('add', { id: row.id, bidsctionId: row.bidsectionId })}></Button>
                 </Tooltip>
                 {
-                  !row.children ?
+                  !row.children?.length ?
                   <Tooltip title="删除">
-                    <Button type="text" icon={<CloseOutlined style={{ color: '#007bff' }}/>}/>
-                  </Tooltip> : ''
+                    <Button type="text" icon={<CloseOutlined style={{ color: '#007bff' }}/>} onClick={() => treeResfulApiHandler('del', { id: row.id, bidsctionId: row.bidsectionId })} />
+                  </Tooltip>
+                  : <span className="pi-width-32 pi-height-32 pi-pd-tb-4 pi-flex-row-center"><CloseOutlined style={{ color: '#9a9a9a', fontSize: '14px' }}/></span>
                 }
                 {
                   row.parentId && row.parentId !== contractTreeBaseId ?
                   <Tooltip title="升级">
-                    <Button type="text" icon={<ArrowLeftOutlined />} style={{ color: '#007bff' }}></Button>
-                  </Tooltip> : ''
+                    <Button type="text" icon={<ArrowLeftOutlined />} style={{ color: '#007bff' }} onClick={() => treeResfulApiHandler('depth', { id: row.id, bidsctionId: row.bidsectionId, operation: 'upDepth' })}></Button>
+                  </Tooltip>
+                  :
+                  <span className="pi-width-32 pi-height-32 pi-pd-tb-4 pi-flex-row-center"><ArrowLeftOutlined style={{ color: '#9a9a9a', fontSize: '14px' }}/></span>
+                }
+                {
+                  row.elderBrother ?
+                  <Tooltip title="降级">
+                    <Button type="text" icon={<ArrowRightOutlined style={{ color: '#007bff' }}/>} onClick={() => treeResfulApiHandler('depth', { id: row.id, bidsctionId: row.bidsectionId, operation: 'downDepth' })} ></Button>
+                  </Tooltip>
+                  :
+                  <span className="pi-width-32 pi-height-32 pi-pd-tb-4 pi-flex-row-center"><ArrowRightOutlined style={{ color: '#9a9a9a', fontSize: '14px' }}/></span>
+                }
+                {
+                  row.elderBrother ?
+                  <Tooltip title="上移">
+                    <Button type="text" icon={<ArrowUpOutlined style={{ color: '#007bff' }}/>} onClick={() => treeResfulApiHandler('serial', { id: row.id, bidsctionId: row.bidsectionId, operation: 'upSerial' })}  disabled={!row.elderBrother}></Button>
+                  </Tooltip>
+                  :
+                  <span className="pi-width-32 pi-height-32 pi-pd-tb-4 pi-flex-row-center"><ArrowUpOutlined style={{ color: '#9a9a9a', fontSize: '14px' }}/></span>
+                }
+                {
+                  !row.isEnd ?
+                  <Tooltip title="下移">
+                    <Button type="text" icon={<ArrowDownOutlined style={{ color: '#007bff' }}/>} onClick={() => treeResfulApiHandler('serial', { id: row.id, bidsctionId: row.bidsectionId, operation: 'downSerial' })} disabled={row.isEnd}></Button>
+                  </Tooltip>
+                  :
+                  <span className="pi-width-32 pi-height-32 pi-pd-tb-4 pi-flex-row-center"><ArrowDownOutlined style={{ color: '#9a9a9a', fontSize: '14px' }}/></span>
                 }
-
-                <Tooltip title="降级">
-                  <Button type="text" icon={<ArrowRightOutlined style={{ color: '#007bff' }}/>}></Button>
-                </Tooltip>
-
-                <Tooltip title="下移">
-                  <Button type="text" icon={<ArrowUpOutlined style={{ color: '#007bff' }}/>}></Button>
-                </Tooltip>
-
-                <Tooltip title="上移">
-                  <Button type="text" icon={<ArrowDownOutlined style={{ color: '#007bff' }}/>}></Button>
-                </Tooltip>
               </>
               : ''
             }
-
           </div>
         </Slot>
         <Slot position="right">

+ 0 - 3
src/pages/Contract/Content/Spending/index.tsx

@@ -1,4 +1,3 @@
-import { contractStore } from '@/store/mobx'
 import { observer } from 'mobx-react'
 import React from 'react'
 
@@ -6,8 +5,6 @@ const Spending:React.FC<{}> = () => {
 
   return (
     <div>
-      <h5>{contractStore.id}</h5>
-      <button onClick={() => contractStore.updateId()}>change</button>
     </div>
   )
 }

+ 1 - 1
src/pages/Contract/List/api.ts

@@ -1,6 +1,6 @@
 import request from "@/utils/common/request"
 
 export async function apiContractList() {
-  const { data } = await request.get('/api/contract')
+  const { data } = await request.get('/api/contract/folder')
   return data
 }

+ 60 - 33
src/store/mobx/contract/index.ts

@@ -1,47 +1,74 @@
+import { apiContractIncome } from "@/pages/Contract/Content/Income/components/Modal/api"
 import { iIncomeTree } from "@/types/contract"
+import consts from "@/utils/consts"
 import { action, computed, observable } from "mobx"
-
+const initData = [ {
+  elderBrother: false,
+  isEnd: false,
+  attribsortution: 0,
+  attribution: '',
+  bidsectionId: '',
+  children: undefined,
+  code: '',
+  contractCode: '',
+  contractId: '',
+  contractName: '',
+  contractPrice: '',
+  contractReturned: '',
+  contractStatus: 0,
+  contractsPaid: '',
+  createTime: '',
+  depth: 0,
+  id: '',
+  name: '',
+  operation: '',
+  parentId: '',
+  projectId: '',
+  serial: 0,
+  templateNumber: 0
+} ]
 class Contract {
-  @observable tree: iIncomeTree = {
-    attribsortution: 0,
-    attribution: '',
-    bidsectionId: '',
-    children: undefined,
-    code: '',
-    contractCode: '',
-    contractId: '',
-    contractName: '',
-    contractPrice: '',
-    contractReturned: '',
-    contractStatus: 0,
-    contractsPaid: '',
-    createTime: '',
-    depth: 0,
-    id: '',
-    name: '',
-    operation: '',
-    parentId: '',
-    projectId: '',
-    serial: 0,
-    templateNumber: 0
-  }
 
-  @observable id: string = Math.random() + ''
+  @observable tree: iIncomeTree[] = initData
 
-  @action updateId() {
-    console.log('执行了')
+  @action updateTree(tree: iIncomeTree[]) {
+    this.tree = tree
+  }
 
-    this.id = Math.random() + ''
+  @action resetTree(id: string) {
+    apiContractIncome(id).then(({ code = -1, data }) => {
+      if (code === consts.RET_CODE.SUCCESS) {
+        this.tree = data.sectionTree
+      }
+    })
   }
 
-  @action updateTree(tree: iIncomeTree) {
-    console.log(tree)
-    this.tree = tree
+  // 增加行
+  @action addRowTree(id: string) {
+    const newTree = lookupNode(id, this.tree)
+    this.tree = newTree
   }
 
-  @computed showTable() {
-    return this.tree.children && this.tree.children.length
+  @computed get showTable() {
+    return this.tree && this.tree.length > 1
   }
 }
 
+function lookupNode(id: string, tree: iIncomeTree[]) {
+  return tree.map((item:iIncomeTree) => {
+
+    if (item.id === id) {
+      if (Array.isArray(item.children)) {
+      item.children.push({ ...initData[0], isEdit: true, code: item.code + `-${item.children?.length || 1 }`, parentId: item.id })
+      } else {
+      item.children = [ { ...initData[0], isEdit: true, code: item.code + '-1', parentId: item.id } ]
+      }
+      return item
+    } else if(item.children && item.children.length) {
+      lookupNode(id, item.children)
+    }
+    return item
+  })
+  return tree
+}
 export default new Contract()

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

@@ -21,6 +21,8 @@ export interface ContractTree {
 }
 
 export interface iIncomeTree {
+  elderBrother: boolean;
+  isEnd: boolean;
   attribsortution: number;
   attribution: string;
   bidsectionId: string;
@@ -42,6 +44,7 @@ export interface iIncomeTree {
   projectId: string;
   serial: number;
   templateNumber: number;
+  isEdit?: boolean;
 }
 export interface iModalBooleanProps {
   type : string

+ 1 - 1
tsconfig.json

@@ -8,7 +8,7 @@
     "allowSyntheticDefaultImports": true,
     "strict": true,
     "forceConsistentCasingInFileNames": true,
-    "module": "commonjs",
+    "module": "esnext",
     "moduleResolution": "node",
     "resolveJsonModule": true,
     "isolatedModules": false,