Jelajahi Sumber

Merge branch 'dev' of http://192.168.1.41:3000/outaozhen/cldV2react into dev

outaozhen 5 tahun lalu
induk
melakukan
3b01d32a6d
28 mengubah file dengan 619 tambahan dan 186 penghapusan
  1. 31 21
      config/routes.js
  2. 1 1
      src/components/RightContent/NoticeIcon/NoticeIcon.tsx
  3. 16 11
      src/components/RightContent/NoticeIcon/index.tsx
  4. 1 1
      src/components/RightContent/index.tsx
  5. 10 3
      src/components/Table/src/BasicTable.tsx
  6. 35 1
      src/hooks/core/useWebSocketFn.ts
  7. 2 0
      src/locales/zh-CN/menu.js
  8. 2 1
      src/models/refresh.js
  9. 14 14
      src/pages/Customer/Business/components/BusinessDetail/Form.jsx
  10. 9 5
      src/pages/Customer/Business/components/BusinessDetail/Step/index.jsx
  11. 4 21
      src/pages/Customer/Business/index.jsx
  12. 34 30
      src/pages/Customer/Client/index.jsx
  13. 28 7
      src/pages/Customer/Client/model.js
  14. 36 29
      src/pages/Customer/Company/index.jsx
  15. 28 7
      src/pages/Customer/Company/model.js
  16. 246 7
      src/pages/Product/Cloud/Building/index.jsx
  17. 9 0
      src/pages/Product/Cloud/Gs/index.jsx
  18. 9 0
      src/pages/Product/Cloud/Highway/index.jsx
  19. 37 0
      src/pages/Product/Cloud/model.js
  20. 10 6
      src/pages/Product/Lock/Lockstore/components/LocksDetail/LockModal.jsx
  21. 13 7
      src/pages/Product/Lock/Lockstore/components/LocksDetail/TabList.jsx
  22. 5 3
      src/pages/Product/Lock/Lockstore/components/LocksDetail/index.jsx
  23. 3 2
      src/pages/Product/Lock/Lockstore/components/ReceiveLock.jsx
  24. 3 2
      src/pages/Product/Lock/Lockstore/components/ReceiveNewLock.jsx
  25. 9 5
      src/pages/Product/Lock/Lockstore/index.jsx
  26. 1 1
      src/pages/Product/Lock/model.js
  27. 14 0
      src/services/lock.js
  28. 9 1
      src/utils/cache/cacheEnum.ts

+ 31 - 21
config/routes.js

@@ -104,28 +104,38 @@ export default [
           //   component: './Product/Lock/LockCount'
           // }
         ]
+      },
+      {
+        path: '/product/cloud',
+        name: 'cloud',
+        icon: 'icon-cloud',
+        routes: [
+          {
+            path: '/product/cloud',
+            redirect: '/product/cloud/building'
+          },
+          {
+            path: '/product/cloud/building',
+            name: 'build',
+            component: './Product/Cloud/Building'
+          },
+          {
+            path: '/product/cloud/curing',
+            name: 'curing',
+            component: './Product/Cloud/Curing'
+          },
+          {
+            path: '/product/cloud/highway',
+            name: 'highway',
+            component: './Product/Cloud/Highway'
+          },
+          {
+            path: '/product/cloud/gs',
+            name: 'gs',
+            component: './Product/Cloud/Gs'
+          }
+        ]
       }
-      // {
-      //   path: '/product/cloud',
-      //   name: 'cloud',
-      //   icon: 'icon-cloud',
-      //   routes: [
-      //     {
-      //       path: '/product/cloud',
-      //       redirect: '/product/cloud/building'
-      //     },
-      //     {
-      //       path: '/product/cloud/building',
-      //       name: 'build',
-      //       component: './Product/Cloud/Building'
-      //     },
-      //     {
-      //       path: '/product/cloud/curing',
-      //       name: 'curing',
-      //       component: './Product/Cloud/Curing'
-      //     }
-      //   ]
-      // }
     ]
   },
   {

+ 1 - 1
src/components/RightContent/NoticeIcon/NoticeIcon.tsx

@@ -118,7 +118,7 @@ const NoticeIcon: React.FC<NoticeIconProps> & {
 }
 
 NoticeIcon.defaultProps = {
-  emptyImage: '/public/notice_empty.svg'
+  emptyImage: 'https://zhcld.com/static/notice_bell.png'
 }
 
 NoticeIcon.Tab = NoticeList

+ 16 - 11
src/components/RightContent/NoticeIcon/index.tsx

@@ -6,8 +6,9 @@ import { useModel } from 'umi'
 import NoticeIcon from './NoticeIcon'
 import styles from './index.less'
 import dayjs from 'dayjs'
-import { queryNoticeList } from '@/services/login'
+import { queryNoticeList, updateNotice } from '@/services/login'
 import consts from '@/consts'
+import useWebSocketFn from '@/hooks/core/useWebSocketFn'
 
 export type GlobalHeaderRightProps = {
   fetchingNotices?: boolean
@@ -75,6 +76,7 @@ const NoticeIconView = () => {
   const { initialState } = useModel('@@initialState')
   const { currentUser } = initialState || {}
   const [notices, setNotices] = useState([])
+  useWebSocketFn()
   const getNotices = useCallback(async () => {
     const { code = -1, data } = await queryNoticeList()
     if (code === consts.RET_CODE.SUCCESS) {
@@ -88,16 +90,19 @@ const NoticeIconView = () => {
   const noticeData = getNoticeData(notices)
   const unreadMsg = getUnreadData(noticeData || {})
 
-  const changeReadState = (id: string) => {
-    setNotices(
-      notices.map(item => {
-        const notice = { ...item }
-        if (notice.id === id) {
-          notice.isRead = true
-        }
-        return notice
-      })
-    )
+  const changeReadState = async (id: string) => {
+    const { code = -1 } = await updateNotice({ id })
+    if (code === consts.RET_CODE.SUCCESS) {
+      setNotices(
+        notices.map(item => {
+          const notice = { ...item }
+          if (notice.id === id) {
+            notice.isRead = true
+          }
+          return notice
+        })
+      )
+    }
   }
 
   const clearReadState = (title: string, key: string) => {

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

@@ -60,7 +60,7 @@ const GlobalHeaderRight: React.FC = () => {
       >
         <QuestionCircleOutlined />
       </span> */}
-      <Notify />
+      {/* <Notify /> */}
       <Avatar />
       {REACT_APP_ENV && REACT_APP_ENV !== 'prod' && (
         <span>

+ 10 - 3
src/components/Table/src/BasicTable.tsx

@@ -50,6 +50,7 @@ const BasicTable: {
   Summary: typeof import('rc-table/lib/Footer/Summary').default
 } = ({
   // resizable = false,
+  rowKey,
   headerTitle,
   params,
   mainMenuType,
@@ -86,7 +87,6 @@ const BasicTable: {
       const column = state.columnsStateMap[columnsKey]
       if (!column.show) filterKey.push(columnsKey)
     })
-
     return originalColumns?.filter((_, i) => !filterKey.includes(i.toString()))
   }, [state.columnsStateMap])
 
@@ -133,7 +133,11 @@ const BasicTable: {
 
   const handleOnColumnsChange = (map: Record<string, ColumnsState>) => {
     setState({ ...state, columnsStateMap: map })
-    setAuthCache(TABLE_COLUMNS_MAP, { [ColumnStateEnum[columnStateType]]: map })
+    const authColumnsStateMap = getAuthCache(TABLE_COLUMNS_MAP)
+    setAuthCache(TABLE_COLUMNS_MAP, {
+      ...authColumnsStateMap,
+      [ColumnStateEnum[columnStateType]]: map
+    })
   }
 
   const handleOnSizeChange = (size: DensitySize) => {
@@ -192,12 +196,15 @@ const BasicTable: {
   //   return columns
   // }, [columns])
 
+  const computedParams = mainMenuType ? { ...params, ...state.params } : params
+
   return (
     <div ref={tableElRef} className={styles.BasicTable}>
       <ProTable
         {...resetProps}
+        rowKey={rowKey || 'id'}
         columns={originalColumns}
-        params={{ ...params, ...state.params }}
+        params={computedParams}
         columnsStateMap={state.columnsStateMap}
         onColumnsStateChange={handleOnColumnsChange}
         scroll={getScrollRef}

+ 35 - 1
src/hooks/core/useWebSocketFn.ts

@@ -1,5 +1,6 @@
 /* eslint-disable react-hooks/rules-of-hooks */
 import { useWebSocket } from 'ahooks'
+import { notification } from 'antd'
 import { useEffect } from 'react'
 import { useModel } from 'umi'
 
@@ -15,6 +16,19 @@ export enum noticeType {
   Message = 2
 }
 
+// function noticeHandler (op) {}
+
+// function cmdReducer(cmd: cmdType, op: any) {
+//   switch (cmd) {
+//     case 13:
+
+//       break
+
+//     default:
+//       break
+//   }
+// }
+
 export default function useWebSocketFn() {
   const { initialState } = useModel('@@initialState')
 
@@ -25,7 +39,27 @@ export default function useWebSocketFn() {
     {
       manual: true,
       reconnectLimit: 3,
-      reconnectInterval: 2000
+      reconnectInterval: 2000,
+      onMessage: (message: WebSocketEventMap['message']) => {
+        const data = message && JSON.parse(message.data)
+        // console.log('data', data)
+        // cmdReducer(data.cmd)
+        if (data.cmd === cmdType.Notice) {
+          notification.warning({
+            message: '有新的版本更新, 请及时刷新页面',
+            description: data.title,
+            duration: null,
+            btn: (
+              <span
+                className="text-primary cursor-pointer hover:text-hex-967bbd"
+                onClick={() => window.location.reload()}
+              >
+                点击刷新
+              </span>
+            )
+          })
+        }
+      }
     }
   )
   useEffect(() => {

+ 2 - 0
src/locales/zh-CN/menu.js

@@ -14,6 +14,8 @@ export default {
   'menu.product.cloud': '云版管理',
   'menu.product.cloud.curing': '养护云造价',
   'menu.product.cloud.build': '大司空云计价',
+  'menu.product.cloud.highway': '公路云计价',
+  'menu.product.cloud.gs': '大司空概算',
   'menu.hr': '人资',
   'menu.hr.employee': '部门与员工',
   'menu.login': '登录',

+ 2 - 1
src/models/refresh.js

@@ -7,7 +7,8 @@ export default {
     longle: false,
     department: false,
     staffList: false,
-    business: false
+    business: false,
+    cloud: false
   },
   // 用于处理异步操作和业务逻辑,由action触发,但不能修改state
   effects: {

+ 14 - 14
src/pages/Customer/Business/components/BusinessDetail/Form.jsx

@@ -4,7 +4,7 @@ import EditableForm from '@/components/EditableForm'
 import ChangeCompanyInput, {
   ChangeCompMap
 } from '@/pages/Customer/Company/components/ChangeCompany'
-import ChangeStaff from '../ChangeStaff/index'
+// import ChangeStaff from '../ChangeStaff/index'
 import Step from './Step/index'
 
 const Form = props => {
@@ -19,12 +19,12 @@ const Form = props => {
     title: ChangeCompMap.BUSINESS.title
   }
 
-  const changeStaffOpt = {
-    responsibleId: business.responsibleId,
-    dataId: business.id,
-    actionPayload: ChangeCompMap.BUSINESS.key,
-    text: business.responsible
-  }
+  // const changeStaffOpt = {
+  //   responsibleId: business.responsibleId,
+  //   dataId: business.id,
+  //   actionPayload: ChangeCompMap.BUSINESS.key,
+  //   text: business.responsible
+  // }
   const columns = [
     {
       dataIndex: 'name',
@@ -49,13 +49,13 @@ const Form = props => {
       editCellType: 'datePicker',
       span: 12
     },
-    {
-      dataIndex: 'responsibleId',
-      label: '负责人',
-      editCellType: 'custom',
-      customCell: <ChangeStaff dataSource={changeStaffOpt} />,
-      span: 24
-    },
+    // {
+    //   dataIndex: 'responsibleId',
+    //   label: '负责人',
+    //   editCellType: 'custom',
+    //   customCell: <ChangeStaff dataSource={changeStaffOpt} />,
+    //   span: 24
+    // },
     {
       dataIndex: 'remark',
       label: '备注',

+ 9 - 5
src/pages/Customer/Business/components/BusinessDetail/Step/index.jsx

@@ -58,7 +58,7 @@ const Step = ({ id, statusId, groupStatus = [] }) => {
       className="w-120px"
       onClick={e => {
         if (!op.isSelected) {
-          return message.error('请选择阶段再结束')
+          return message.error('请选择阶段再结束')
         }
         return Modal.confirm({
           title: '提示',
@@ -67,7 +67,8 @@ const Step = ({ id, statusId, groupStatus = [] }) => {
             tryChangeStatus({ id, businessStatusId: e.key })
           }
         })
-      }}>
+      }}
+    >
       {op.otherItems.map(item => (
         <Menu.Item key={item.id}>
           <div className="flex justify-between items-center">
@@ -92,7 +93,8 @@ const Step = ({ id, statusId, groupStatus = [] }) => {
               <p>赢单率{item.percentage}%</p>
             </div>
           }
-          key={item.id}>
+          key={item.id}
+        >
           <div
             onClick={() => {
               if (!op.isEnd) {
@@ -121,7 +123,8 @@ const Step = ({ id, statusId, groupStatus = [] }) => {
                 : op.selectedItemIdx > idx
                 ? 'state-suc'
                 : 'state-undo'
-            }`}>
+            }`}
+          >
             <span className="title ">{item.name}</span>
             {idx === 0 ? (
               <>
@@ -140,7 +143,8 @@ const Step = ({ id, statusId, groupStatus = [] }) => {
       <div
         className={`busi-state-item ${
           op.isEnd ? stateMap[op.otherItems[op.endItemIdx].key].class : 'state-undo'
-        }`}>
+        }`}
+      >
         <span className="title">
           {op.isEnd ? (
             <>

+ 4 - 21
src/pages/Customer/Business/index.jsx

@@ -1,7 +1,6 @@
 import React, { useState, useEffect, useRef } from 'react'
 import { connect } from 'umi'
 import { getBusinessList } from '@/services/customer'
-import ProTable from '@ant-design/pro-table'
 import consts from '@/consts'
 import { Select } from 'antd'
 import AddBusiness from './components/AddBusiness'
@@ -9,8 +8,7 @@ import Detail from './components/BusinessDetail'
 import { useModal } from '@/components/Modal'
 import CompanyDetail from '../Company/components/CompanyDetail'
 import { Funnel } from '@ant-design/charts'
-import PermSelect from '../Company/components/PermSelect'
-import { PermDataTypeEunm } from '../Company/components/PermSelect'
+import BasicTable from '@/components/Table'
 
 const Business = ({ dispatch, groupList, shouldUpdate, loading }) => {
   const tRef = useRef(null)
@@ -21,8 +19,6 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading }) => {
     funnelData: []
   })
 
-  // const { initialState: { permData } = { permData: {} } } = useModel('@@initialState')
-
   useEffect(() => {
     if (!groupList) {
       dispatch({
@@ -131,20 +127,9 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading }) => {
   const conifg = {
     xField: 'name',
     yField: 'count',
-    // legend: false,
     shape: 'pyramid',
     conversionTag: false
   }
-  // const { getScrollRef, redoHeight } = useTableScroll(columns)
-
-  // 处理权限Select下拉组件OnChange事件
-  const handlePermChange = ({ staffIds = [], dataPermission }) => {
-    if (staffIds?.length) {
-      setState({ ...state, params: { ...state.params, staffIds, dataPermission: null } })
-      return
-    }
-    setState({ ...state, params: { ...state.params, staffIds: null, dataPermission } })
-  }
 
   return (
     <div className="h-full w-full flex flex-row justify-between">
@@ -181,9 +166,10 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading }) => {
       <div className="w-17/20">
         <div className="ml-8 bg-white shadow-card">
           {state.params.businessGroupId ? (
-            <ProTable
-              bordered
+            <BasicTable
               actionRef={tRef}
+              mainMenuType="customer"
+              columnStateType="BUSINESS"
               params={state.params}
               rowKey={record => record.id}
               columns={columns}
@@ -199,9 +185,6 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading }) => {
                   total
                 }
               }}
-              headerTitle={
-                <PermSelect onConfirm={handlePermChange} dataType={PermDataTypeEunm.CUSTOMER} />
-              }
               search={false}
               toolbar={{
                 actions: [

+ 34 - 30
src/pages/Customer/Client/index.jsx

@@ -42,6 +42,11 @@ const Client = props => {
     tagCooperationIds: []
   })
 
+  const [state, setState] = useState({
+    params: {},
+    orderIds: []
+  })
+
   const tag = useMemo(() => {
     const personTagMap = {}
     const teamTagMap = {}
@@ -80,15 +85,29 @@ const Client = props => {
     return { personTagMap, teamTagMap, personOptions, teamOptions }
   }, [loading])
 
+  // 默认刷新一次列表请求数据
+  useEffect(() => {
+    if (!personTags.length) {
+      dispatch({
+        type: 'client/fetchPersonTags',
+        payload: { tagType: TagTypeEnum.PERSONTAG, tagColumn: TagDataTypeEnum.CLIENT }
+      })
+    }
+    if (!teamTags.length) {
+      dispatch({
+        type: 'client/fetchTeamTags',
+        payload: { tagType: TagTypeEnum.TEAMTAG, tagColumn: TagDataTypeEnum.CLIENT }
+      })
+    }
+    if (shouldUpdate) {
+      tRef.current.reload()
+    }
+  }, [shouldUpdate])
+
   const toolbarOptionsChange = (type, ids) => {
     setTagState({ ...tagState, [type]: ids })
   }
 
-  const [state, setState] = useState({
-    params: {},
-    orderIds: []
-  })
-
   const [defaultPermAuthCache] = getPermAuthCache(PermDataTypeEunm.CUSTOMER)
   // 重置到默认值,包括表单
   const initData = () => {
@@ -153,7 +172,8 @@ const Client = props => {
       render: (clientName, record) => (
         <span
           onClick={() => showDrawer(record.id)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {clientName}
         </span>
       ),
@@ -270,7 +290,8 @@ const Client = props => {
             tagType={TagTypeEnum.PERSONTAG}
             tagColumn={TagDataTypeEnum.CLIENT}
             checkCallBack={refreshData}
-            modeType={LabelModeType.column}>
+            modeType={LabelModeType.column}
+          >
             <Add theme="filled" size="20" fill="#868e96" className="cursor-pointer" />
           </PersonLabel>
         </div>
@@ -307,7 +328,8 @@ const Client = props => {
             tagType={TagTypeEnum.TEAMTAG}
             tagColumn={TagDataTypeEnum.CLIENT}
             checkCallBack={refreshData}
-            modeType={LabelModeType.column}>
+            modeType={LabelModeType.column}
+          >
             <Add theme="filled" size="20" fill="#868e96" className="cursor-pointer" />
           </PersonLabel>
         </div>
@@ -410,26 +432,6 @@ const Client = props => {
     }
   }
 
-  // 默认刷新一次列表请求数据
-  useEffect(() => {
-    // initData()
-    if (!personTags.length) {
-      dispatch({
-        type: 'client/fetchTags',
-        payload: { tagType: TagTypeEnum.PERSONTAG, tagColumn: TagDataTypeEnum.CLIENT }
-      })
-    }
-    if (!teamTags.length) {
-      dispatch({
-        type: 'client/fetchTags',
-        payload: { tagType: TagTypeEnum.TEAMTAG, tagColumn: TagDataTypeEnum.CLIENT }
-      })
-    }
-    if (shouldUpdate) {
-      tRef.current.reload()
-    }
-  }, [shouldUpdate])
-
   const handleSearch = value => {
     tRef.current.reset()
     setState({ ...state, params: { ...state.params, search: value } })
@@ -478,7 +480,8 @@ const Client = props => {
             tagType={TagTypeEnum.PERSONTAG}
             tagColumn={TagDataTypeEnum.CLIENT}
             checkCallBack={toolbarOptionsChange}
-            modeType={LabelModeType.toolbar}>
+            modeType={LabelModeType.toolbar}
+          >
             {tagState.tagIds.length ? (
               <Button>
                 {tagState.tagIds.map(item => (
@@ -503,7 +506,8 @@ const Client = props => {
             tagType={TagTypeEnum.TEAMTAG}
             tagColumn={TagDataTypeEnum.CLIENT}
             checkCallBack={toolbarOptionsChange}
-            modeType={LabelModeType.toolbar}>
+            modeType={LabelModeType.toolbar}
+          >
             {tagState.tagCooperationIds.length ? (
               <Button>
                 {tagState.tagCooperationIds.map(item => (

+ 28 - 7
src/pages/Customer/Client/model.js

@@ -1,8 +1,5 @@
 import consts from '@/consts'
-import {
-  LabelStatusColorMap,
-  TagTypeEnum
-} from '@/pages/Customer/Company/components/PersonLabel/const'
+import { LabelStatusColorMap } from '@/pages/Customer/Company/components/PersonLabel/const'
 import { queryTagList } from '@/services/customer'
 
 export default {
@@ -15,21 +12,45 @@ export default {
   },
   // 用于处理异步操作和业务逻辑,由action触发,但不能修改state
   effects: {
-    *fetchTags({ payload }, { call, put }) {
+    *fetchPersonTags({ payload }, { call, put }) {
       const response = yield call(queryTagList, payload)
       if (response?.code === consts.RET_CODE.SUCCESS) {
         const { tagType } = payload
         yield put({
           type: 'changeState',
           payload: {
-            key: tagType === TagTypeEnum.PERSONTAG ? 'personTags' : 'teamTags',
+            key: 'personTags',
             data: response.data || []
           }
         })
         yield put({
           type: 'changeState',
           payload: {
-            key: tagType === TagTypeEnum.PERSONTAG ? 'personTagColorMap' : 'teamTagColorMap',
+            key: 'personTagColorMap',
+            data:
+              response.data?.reduce((curr, prev, idx) => {
+                const item = { ...curr, [prev.id]: LabelStatusColorMap[tagType][idx] }
+                return item
+              }, {}) || {}
+          }
+        })
+      }
+    },
+    *fetchTeamTags({ payload }, { call, put }) {
+      const response = yield call(queryTagList, payload)
+      if (response?.code === consts.RET_CODE.SUCCESS) {
+        const { tagType } = payload
+        yield put({
+          type: 'changeState',
+          payload: {
+            key: 'teamTags',
+            data: response.data || []
+          }
+        })
+        yield put({
+          type: 'changeState',
+          payload: {
+            key: 'teamTagColorMap',
             data:
               response.data?.reduce((curr, prev, idx) => {
                 const item = { ...curr, [prev.id]: LabelStatusColorMap[tagType][idx] }

+ 36 - 29
src/pages/Customer/Company/index.jsx

@@ -40,6 +40,29 @@ const Company = props => {
     tagCooperationIds: []
   })
 
+  const [state, setState] = useState({
+    params: {},
+    orderIds: []
+  })
+
+  useEffect(() => {
+    if (!personTags.length) {
+      dispatch({
+        type: 'company/fetchPersonTags',
+        payload: { tagType: TagTypeEnum.PERSONTAG, tagColumn: TagDataTypeEnum.COMPANY }
+      })
+    }
+    if (!teamTags.length) {
+      dispatch({
+        type: 'company/fetchTeamTags',
+        payload: { tagType: TagTypeEnum.TEAMTAG, tagColumn: TagDataTypeEnum.COMPANY }
+      })
+    }
+    if (shouldUpdate) {
+      tRef.current.reload()
+    }
+  }, [shouldUpdate])
+
   const tag = useMemo(() => {
     const personTagMap = {}
     const teamTagMap = {}
@@ -87,10 +110,7 @@ const Company = props => {
     return { personTagMap, teamTagMap, natureMap, personOptions, teamOptions }
   }, [loading])
 
-  const [state, setState] = useState({
-    params: {},
-    orderIds: []
-  })
+  const [defaultPermAuthCache] = getPermAuthCache(PermDataTypeEunm.CUSTOMER)
 
   // 重置到默认值,包括表单
   const initData = () => {
@@ -110,24 +130,6 @@ const Company = props => {
       initData()
     }
   }
-
-  useEffect(() => {
-    if (!personTags.length) {
-      dispatch({
-        type: 'company/fetchTags',
-        payload: { tagType: TagTypeEnum.PERSONTAG, tagColumn: TagDataTypeEnum.COMPANY }
-      })
-    }
-    if (!teamTags.length) {
-      dispatch({
-        type: 'company/fetchTags',
-        payload: { tagType: TagTypeEnum.TEAMTAG, tagColumn: TagDataTypeEnum.COMPANY }
-      })
-    }
-    if (shouldUpdate) {
-      tRef.current.reload()
-    }
-  }, [shouldUpdate])
   const handleSearch = value => {
     tRef.current.reset()
     setState({ ...state, params: { ...state.params, search: value } })
@@ -165,7 +167,8 @@ const Company = props => {
       render: (companyName, record) => (
         <span
           onClick={() => showDrawer(record.id)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {companyName}
         </span>
       )
@@ -210,7 +213,8 @@ const Company = props => {
             tagType={TagTypeEnum.PERSONTAG}
             tagColumn={TagDataTypeEnum.COMPANY}
             checkCallBack={refreshData}
-            modeType={LabelModeType.column}>
+            modeType={LabelModeType.column}
+          >
             <Add theme="filled" size="20" fill="#868e96" className="cursor-pointer" />
           </PersonLabel>
         </div>
@@ -241,7 +245,8 @@ const Company = props => {
             tagType={TagTypeEnum.TEAMTAG}
             tagColumn={TagDataTypeEnum.COMPANY}
             checkCallBack={refreshData}
-            modeType={LabelModeType.column}>
+            modeType={LabelModeType.column}
+          >
             <Add theme="filled" size="20" fill="#868e96" className="cursor-pointer" />
           </PersonLabel>
         </div>
@@ -390,8 +395,6 @@ const Company = props => {
     requestSuccess && refreshData()
   }
 
-  const [defaultPermAuthCache] = getPermAuthCache(PermDataTypeEunm.CUSTOMER)
-
   const renderTableAlert = ({ selectedRowKeys }) => {
     return (
       <div className="flex flex-row">
@@ -400,7 +403,8 @@ const Company = props => {
             tagType={TagTypeEnum.PERSONTAG}
             tagColumn={TagDataTypeEnum.COMPANY}
             checkCallBack={toolbarOptionsChange}
-            modeType={LabelModeType.toolbar}>
+            modeType={LabelModeType.toolbar}
+          >
             {tagState.tagIds.length ? (
               <Button>
                 {tagState.tagIds.map(item => (
@@ -425,7 +429,8 @@ const Company = props => {
             tagType={TagTypeEnum.TEAMTAG}
             tagColumn={TagDataTypeEnum.COMPANY}
             checkCallBack={toolbarOptionsChange}
-            modeType={LabelModeType.toolbar}>
+            modeType={LabelModeType.toolbar}
+          >
             {tagState.tagCooperationIds.length ? (
               <Button>
                 {tagState.tagCooperationIds.map(item => (
@@ -453,6 +458,8 @@ const Company = props => {
     )
   }
 
+  if (!personTags?.length || !teamTags?.length) return null
+
   return (
     <div className={styles.companyContent}>
       <BasicTable

+ 28 - 7
src/pages/Customer/Company/model.js

@@ -1,8 +1,5 @@
 import consts from '@/consts'
-import {
-  LabelStatusColorMap,
-  TagTypeEnum
-} from '@/pages/Customer/Company/components/PersonLabel/const'
+import { LabelStatusColorMap } from '@/pages/Customer/Company/components/PersonLabel/const'
 import { queryNatures, queryTagList } from '@/services/customer'
 
 export default {
@@ -16,21 +13,45 @@ export default {
   },
   // 用于处理异步操作和业务逻辑,由action触发,但不能修改state
   effects: {
-    *fetchTags({ payload }, { call, put }) {
+    *fetchPersonTags({ payload }, { call, put }) {
       const response = yield call(queryTagList, payload)
       if (response?.code === consts.RET_CODE.SUCCESS) {
         const { tagType } = payload
         yield put({
           type: 'changeState',
           payload: {
-            key: tagType === TagTypeEnum.PERSONTAG ? 'personTags' : 'teamTags',
+            key: 'personTags',
             data: response.data || []
           }
         })
         yield put({
           type: 'changeState',
           payload: {
-            key: tagType === TagTypeEnum.PERSONTAG ? 'personTagColorMap' : 'teamTagColorMap',
+            key: 'personTagColorMap',
+            data:
+              response.data?.reduce((curr, prev, idx) => {
+                const item = { ...curr, [prev.id]: LabelStatusColorMap[tagType][idx] }
+                return item
+              }, {}) || {}
+          }
+        })
+      }
+    },
+    *fetchTeamTags({ payload }, { call, put }) {
+      const response = yield call(queryTagList, payload)
+      if (response?.code === consts.RET_CODE.SUCCESS) {
+        const { tagType } = payload
+        yield put({
+          type: 'changeState',
+          payload: {
+            key: 'teamTags',
+            data: response.data || []
+          }
+        })
+        yield put({
+          type: 'changeState',
+          payload: {
+            key: 'teamTagColorMap',
             data:
               response.data?.reduce((curr, prev, idx) => {
                 const item = { ...curr, [prev.id]: LabelStatusColorMap[tagType][idx] }

+ 246 - 7
src/pages/Product/Cloud/Building/index.jsx

@@ -1,13 +1,252 @@
-import React from 'react'
-import { Card } from 'antd'
+/* eslint-disable no-underscore-dangle */
+import React, { useState, useEffect } from 'react'
+import BasicTable from '@/components/Table'
+import { dayjsFormat, refactorSortField } from '@/utils/utils'
+import { queryRoadpricingList } from '@/services/product'
+import { Input, Tag, Tooltip } from 'antd'
+import consts from '@/consts'
+import { useSelector, useDispatch } from 'umi'
+
+export const roadpricingEnum = {
+  CURING: 1, // 养护云
+  BUILDING: 2, // 大司空
+  HIGHWAY: 3, // 公路云
+  GS: 4 // 大司空概算
+}
+
+const CloudTable = ({ columnStateType }) => {
+  const dispatch = useDispatch()
+  const { cloud } = useSelector(state => ({
+    cloud: state.cloud,
+    shouldUpdate: state.refresh.cloud
+  }))
+  const roadpricing = cloud.roadpricing[roadpricingEnum[columnStateType]]
+  const [state, setState] = useState({
+    params: {
+      projectPype: roadpricingEnum[columnStateType],
+      search: null
+    }
+  })
+
+  useEffect(() => {
+    if (!roadpricing?.length) {
+      dispatch({
+        type: 'cloud/fetchCompilation',
+        payload: {
+          projectPype: roadpricingEnum[columnStateType]
+        }
+      })
+    }
+  }, [])
+
+  if (!roadpricing?.length) return null
+  const columns = [
+    {
+      title: '通行账号',
+      dataIndex: 'mobile',
+      key: 'mobile',
+      fixed: 'left',
+      search: false,
+      width: 50
+    },
+    {
+      title: '称呼',
+      dataIndex: 'username',
+      key: 'username',
+      ellipsis: true,
+      width: 60,
+      search: false
+    },
+    {
+      title: '真实姓名',
+      dataIndex: 'real_name',
+      key: 'real_name',
+      ellipsis: true,
+      width: 60,
+      search: false
+    },
+    {
+      title: 'QQ',
+      dataIndex: 'qq',
+      key: 'qq',
+      search: false,
+      ellipsis: true,
+      width: 60
+    },
+    {
+      title: '企业名称',
+      dataIndex: 'company',
+      search: false,
+      key: 'company',
+      ellipsis: true,
+      width: 100
+    },
+    {
+      title: 'CLD联系人',
+      dataIndex: 'cld',
+      search: false,
+      key: 'cld',
+      ellipsis: true,
+      width: 50,
+      renderText: cld => cld.clientName
+    },
+    {
+      title: '最近使用',
+      dataIndex: 'latestUsedName',
+      key: 'latestUsedName',
+      valueType: 'select',
+      width: 50,
+      valueEnum: roadpricing.reduce((prev, curr) => {
+        const obj = { ...prev }
+        if (curr._id) {
+          obj[curr._id] = {
+            text: curr.name
+          }
+        }
+        return obj
+      }, {}),
+      renderText: text => text && <Tag color="purple">{text}</Tag>
+    },
+    {
+      title: '截至上一次登录时长',
+      dataIndex: 'all_online_times',
+      key: 'all_online_times',
+      valueType: 'select',
+      width: 70,
+      valueEnum: {
+        1: { text: '超过30分钟' },
+        2: { text: '超过1小时' },
+        3: { text: '超过2小时' },
+        4: { text: '超过3小时' }
+      },
+      renderText: (t, record) => {
+        if (t && record.online_list?.length) {
+          return (
+            <Tooltip
+              title={
+                <div>
+                  <div>最近登陆:</div>
+                  {record.online_list?.map(
+                    (item, i) =>
+                      i < 10 && (
+                        <div className="flex justify-between">
+                          <span>{item.online_times}</span>
+                          <span className="ml-4">{item.dateString}</span>
+                        </div>
+                      )
+                  )}
+                </div>
+              }
+            >
+              {t}
+            </Tooltip>
+          )
+        }
+        return '-'
+      }
+    },
+    {
+      title: '注册时间',
+      dataIndex: 'create_time',
+      key: 'create_time',
+      search: false,
+      sorter: true,
+      ellipsis: true,
+      width: 60,
+      renderText: text => dayjsFormat(text, 'YYYY-MM-DD HH:mm')
+    },
+    {
+      title: '已升级专业版',
+      dataIndex: 'upgrade_list',
+      key: 'upgrade_list',
+      search: false,
+      filters: true,
+      width: 150,
+      valueEnum: roadpricing.reduce((prev, curr) => {
+        const obj = { ...prev }
+        if (curr._id) {
+          obj[curr._id] = {
+            text: curr.name
+          }
+        }
+        return obj
+      }, {}),
+      renderText: text => (
+        <div>
+          {text
+            .filter(item => item.isUpgrade)
+            .map(item => {
+              return (
+                <Tag color="purple" key={item.compilationID}>
+                  {roadpricing?.find(i => i._id === item.compilationID)?.name}
+                </Tag>
+              )
+            })}
+        </div>
+      )
+    }
+  ]
+  const columnsMap = {
+    username: {
+      show: false
+    },
+    qq: {
+      show: false
+    },
+    latestUsedName: {
+      show: false
+    },
+    create_time: {
+      show: false
+    },
+    cld: {
+      show: false
+    },
+    upgrade_list: {
+      show: false
+    }
+  }
+
+  const handleSearch = value => {
+    setState({ ...state, params: { ...state.params, search: value } })
+  }
 
-const Building = () => {
-  // const { modalVisible, onCancel } = props;
   return (
-    <Card bordered={false}>
-      Building
-    </Card>
+    <BasicTable
+      rowKey={record => record._id}
+      columnStateType={columnStateType}
+      params={state.params}
+      request={async (params, sort, filter) => {
+        const sortOrder = refactorSortField(sort)
+        const {
+          code = -1,
+          data: { list = [], total = 0 }
+        } = await queryRoadpricingList({ ...params, ...sortOrder, ...filter })
+        return {
+          data: list,
+          success: code === consts.RET_CODE.SUCCESS,
+          total
+        }
+      }}
+      toolbar={{
+        search: (
+          <Input.Search
+            style={{ width: '300px' }}
+            allowClear={true}
+            placeholder="请输入手机、QQ进行搜索"
+            onSearch={handleSearch}
+          />
+        )
+      }}
+      search={{ filterType: 'light' }}
+      columns={columns}
+      columnsStateMap={columnsMap}
+    />
   )
 }
 
+const Building = () => {
+  return <CloudTable columnStateType="BUILDING" />
+}
+
 export default Building

+ 9 - 0
src/pages/Product/Cloud/Gs/index.jsx

@@ -0,0 +1,9 @@
+import React from 'react'
+import { Card } from 'antd'
+
+const Curing = () => {
+  // const { modalVisible, onCancel } = props;
+  return <Card bordered={false}>Curing</Card>
+}
+
+export default Curing

+ 9 - 0
src/pages/Product/Cloud/Highway/index.jsx

@@ -0,0 +1,9 @@
+import React from 'react'
+import { Card } from 'antd'
+
+const Curing = () => {
+  // const { modalVisible, onCancel } = props;
+  return <Card bordered={false}>Curing</Card>
+}
+
+export default Curing

+ 37 - 0
src/pages/Product/Cloud/model.js

@@ -0,0 +1,37 @@
+import consts from '@/consts'
+import { queryCompilationList } from '@/services/product'
+import { roadpricingEnum } from './Building'
+
+export default {
+  namespace: 'cloud',
+  state: {
+    roadpricing: {
+      [roadpricingEnum.BUILDING]: [],
+      [roadpricingEnum.CURING]: [],
+      [roadpricingEnum.GS]: [],
+      [roadpricingEnum.HIGHWAY]: []
+    }
+  },
+  effects: {
+    *fetchCompilation({ payload }, { call, put }) {
+      const response = yield call(queryCompilationList, payload)
+      if (response && response.code === consts.RET_CODE.SUCCESS) {
+        yield put({
+          type: 'changeRoadpricingState',
+          payload: {
+            key: payload?.projectPype,
+            data: response.data
+          }
+        })
+      }
+    }
+  },
+  reducers: {
+    changeRoadpricingState(state, action) {
+      return {
+        ...state,
+        roadpricing: { ...state.roadpricing, [action.payload.key]: action.payload.data }
+      }
+    }
+  }
+}

+ 10 - 6
src/pages/Product/Lock/Lockstore/components/LocksDetail/LockModal.jsx

@@ -3,10 +3,10 @@ import { Modal, Form, Select, Input, Spin, Button, Radio, Popconfirm, message }
 import styles from './index.less'
 import { SearchOutlined } from '@ant-design/icons'
 import { queryClient } from '@/services/customer'
-import { queryLock } from '@/services/lock'
+import { queryLock } from '@/services/product'
 import consts from '@/basic/consts'
 import { useDebounceFn } from 'ahooks'
-import { apiSoftwareAddLonglelog } from '@/services/lock'
+import { apiSoftwareAddLonglelog } from '@/services/product'
 import { useDispatch, connect } from 'umi'
 // import { createUid } from '@/utils/utils'
 // import DragIniter from '@/components/Modal/src/components/DragIniter'
@@ -245,7 +245,8 @@ const LockModal = props => {
             </Button>
           </div>
         )
-      }>
+      }
+    >
       {type === lockTypeEnum.SALE ? (
         <div className="text-center mb-6">
           <Radio.Group value={state.sellStatus} buttonStyle="solid" onChange={checkGroupOnChange}>
@@ -260,7 +261,8 @@ const LockModal = props => {
           className={styles.modalContainer}
           ref={scrollRef}
           onScroll={handleListScroll}
-          style={{ paddingBottom: 0 }}>
+          style={{ paddingBottom: 0 }}
+        >
           <div className={styles.modalContent}>
             <Spin spinning={state.loading}>
               {type === lockTypeEnum.SALE &&
@@ -275,7 +277,8 @@ const LockModal = props => {
                         title="确认选择ta"
                         onConfirm={() => connectClient(item.id)}
                         okText="确认"
-                        cancelText="取消">
+                        cancelText="取消"
+                      >
                         <Button type="primary" size="small">
                           选择ta
                         </Button>
@@ -293,7 +296,8 @@ const LockModal = props => {
                         title="确认选择ta"
                         onConfirm={() => connectLongle(item.id)}
                         okText="确认"
-                        cancelText="取消">
+                        cancelText="取消"
+                      >
                         <Button type="primary" size="small">
                           更换
                         </Button>

+ 13 - 7
src/pages/Product/Lock/Lockstore/components/LocksDetail/TabList.jsx

@@ -2,7 +2,7 @@ import React, { useState } from 'react'
 import { Row, Col, List, Tabs, message, Button } from 'antd'
 import { dayjsFormat } from '@/utils/utils'
 import consts from '@/consts'
-import { apiSoftwareAddLonglelog } from '@/services/lock'
+import { apiSoftwareAddLonglelog } from '@/services/product'
 import { ProductLabel } from '@/pages/Product/Lock/LockStore'
 import LockModal, { lockTypeEnum } from './LockModal'
 import ClientDetail from '@/pages/Customer/Client/components/ClientDetail'
@@ -89,7 +89,8 @@ const LockTabList = props => {
                         {servicelogEnum[item.status]}{' '}
                         <span
                           className="textPurple text-hex-967bbd cursor-pointer"
-                          onClick={handleClientClick}>
+                          onClick={handleClientClick}
+                        >
                           {item.client}
                         </span>
                         <br />
@@ -120,7 +121,8 @@ const LockTabList = props => {
           className="mr-3px"
           onClick={() =>
             setAddLonglelog({ ...setAddLonglelog, visible: true, type: lockTypeEnum.SALE })
-          }>
+          }
+        >
           借出/销售/赠送
         </Button>
         <Button
@@ -130,7 +132,8 @@ const LockTabList = props => {
           className="mr-1"
           onClick={() =>
             setAddLonglelog({ ...setAddLonglelog, visible: true, type: lockTypeEnum.UPDATE })
-          }>
+          }
+        >
           升级
         </Button>
         <Button
@@ -144,7 +147,8 @@ const LockTabList = props => {
               visible: true,
               type: lockTypeEnum.CHANGE
             })
-          }>
+          }
+        >
           更换
         </Button>
         <Button
@@ -154,7 +158,8 @@ const LockTabList = props => {
           className="mr-1"
           onClick={() =>
             setAddLonglelog({ ...setAddLonglelog, visible: true, type: lockTypeEnum.RECOVER })
-          }>
+          }
+        >
           收回
         </Button>
         <Button
@@ -163,7 +168,8 @@ const LockTabList = props => {
           size="small"
           onClick={() =>
             setAddLonglelog({ ...setAddLonglelog, visible: true, type: lockTypeEnum.REMARK })
-          }>
+          }
+        >
           备注
         </Button>
 

+ 5 - 3
src/pages/Product/Lock/Lockstore/components/LocksDetail/index.jsx

@@ -1,7 +1,7 @@
 import React, { useState, useEffect } from 'react'
 import { Row, Col, Tooltip } from 'antd'
 import consts from '@/consts'
-import { apiSoftwareDetail } from '@/services/lock'
+import { apiSoftwareDetail } from '@/services/product'
 import LockForm from './Form.jsx'
 import LockLowerList from './LowerList'
 import LockTabList from './TabList'
@@ -55,7 +55,8 @@ const Index = props => {
             md={{ span: 24 }}
             lg={{ span: 9 }}
             xl={{ span: 9 }}
-            className="sheet-box-left">
+            className="sheet-box-left"
+          >
             {orderIds.length ? (
               <div className="mb-3">
                 <Tooltip title="上一条记录">
@@ -90,7 +91,8 @@ const Index = props => {
             md={{ span: 24 }}
             lg={{ span: 15 }}
             xl={{ span: 15 }}
-            className="sheet-box-right">
+            className="sheet-box-right"
+          >
             <LockTabList
               longleLog={state.longleLog}
               longleId={state.longle.id}

+ 3 - 2
src/pages/Product/Lock/Lockstore/components/ReceiveLock.jsx

@@ -2,7 +2,7 @@ import { Button, Input, message } from 'antd'
 import React, { useState, useRef } from 'react'
 import styles from '@/pages/Customer/Company/components/ConnectCompany/index.less'
 import consts from '@/basic/consts'
-import { apiReceiveOldLock, queryOldLockList } from '@/services/lock'
+import { apiReceiveOldLock, queryOldLockList } from '@/services/product'
 import { ProductLabel } from '../index'
 import ProTable from '@ant-design/pro-table'
 import CustomModal from '@/components/Modal/src/components/CustomModal'
@@ -68,7 +68,8 @@ const ReceiveLock = ({ refresh }) => {
             onSearch={handleOnSearch}
           />
         </div>
-      }>
+      }
+    >
       <div className={styles.modalContent}>
         <ProTable
           rowKey={record => record.id}

+ 3 - 2
src/pages/Product/Lock/Lockstore/components/ReceiveNewLock.jsx

@@ -2,7 +2,7 @@ import { Button, Input, message } from 'antd'
 import React, { useRef, useState } from 'react'
 import styles from '@/pages/Customer/Company/components/ConnectCompany/index.less'
 import consts from '@/basic/consts'
-import { apiReceiveLock, queryReceiveList } from '@/services/lock'
+import { apiReceiveLock, queryReceiveList } from '@/services/product'
 import { ProductLabel } from '../index'
 import ProTable from '@ant-design/pro-table'
 import CustomModal from '@/components/Modal/src/components/CustomModal'
@@ -64,7 +64,8 @@ const ReceiveNewLock = ({ refresh }) => {
             onSearch={handleOnSearch}
           />
         </div>
-      }>
+      }
+    >
       <div className={styles.modalContent}>
         <ProTable
           rowKey={record => record.id}

+ 9 - 5
src/pages/Product/Lock/Lockstore/index.jsx

@@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react'
 import { Tag, Select, Tooltip, Input, DatePicker, Button } from 'antd'
 import consts from '@/consts'
 import { useModel, connect } from 'umi'
-import { queryLock } from '@/services/lock'
+import { queryLock } from '@/services/product'
 import LocksDetail from '@/pages/Product/Lock/LockStore/components/LocksDetail'
 import ContactDetail from '@/pages/Customer/Client/components/ClientDetail'
 import SoftwareDetail from '@/pages/Product/Lock/LockStore/components/SoftwareDetail'
@@ -193,7 +193,8 @@ const LockStore = ({ prodList = [], dispatch, shouldUpdate }) => {
       render: (keyNum, record) => (
         <span
           onClick={() => showDrawer(record.id)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {keyNum}
         </span>
       )
@@ -282,7 +283,8 @@ const LockStore = ({ prodList = [], dispatch, shouldUpdate }) => {
       render: (text, record) => (
         <span
           onClick={() => showDrawerResponsible(record.responsibleId)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {text}
         </span>
       )
@@ -294,7 +296,8 @@ const LockStore = ({ prodList = [], dispatch, shouldUpdate }) => {
       render: (text, record) => (
         <span
           onClick={() => showCompanyDrawer(record.customerId)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {text}
         </span>
       )
@@ -306,7 +309,8 @@ const LockStore = ({ prodList = [], dispatch, shouldUpdate }) => {
       render: (text, record) => (
         <span
           onClick={() => showDrawerClient(record.clientId)}
-          className="text-primary cursor-pointer hover:text-[#967bbd]">
+          className="text-primary cursor-pointer hover:text-[#967bbd]"
+        >
           {text}
         </span>
       )

+ 1 - 1
src/pages/Product/Lock/model.js

@@ -1,5 +1,5 @@
 import consts from '@/consts'
-import { querySoftwareProducts } from '@/services/lock'
+import { querySoftwareProducts } from '@/services/product'
 
 export default {
   namespace: 'lock',

+ 14 - 0
src/services/lock.js

@@ -55,3 +55,17 @@ export async function apiReceiveLock(params) {
     data: params
   })
 }
+
+/** 云版产品列表 */
+export async function queryRoadpricingList(params) {
+  return request.post('/RoadPricing/list', {
+    data: params
+  })
+}
+
+/** 编办列表 */
+export async function queryCompilationList(params) {
+  return request('/RoadPricing/compilation', {
+    params
+  })
+}

+ 9 - 1
src/utils/cache/cacheEnum.ts

@@ -42,7 +42,15 @@ export enum ColumnStateEnum {
   /** @name 公共锁库 */
   LOCKSTORE = 'LOCKSTORE',
   /** @name 部门与员工 */
-  EMPLOYEE = 'EMPLOYEE'
+  EMPLOYEE = 'EMPLOYEE',
+  /** @name  养护云造价 */
+  CURING = 'CURING',
+  /** @name  大司空云计价 */
+  BUILDING = 'BUILDING',
+  /** @name  公路云造价 */
+  HIGHWAY = 'HIGHWAY',
+  /** @name  大司空概算 */
+  GS = 'GS'
 }
 export enum CacheTypeEnum {
   SESSION,