Przeglądaj źródła

feat: 配置layout默认激活的水印

lanjianrong 4 lat temu
rodzic
commit
cebcc5c42e

+ 5 - 2
src/app.tsx

@@ -71,9 +71,12 @@ export const layout = ({ initialState, setInitialState }) => {
       </ModalStore>
     ),
     disableContentMargin: false,
-    waterMarkProps: {
-      content: initialState?.currentUser?.username
+    waterMarkProps: initialState.currentUser && {
+      fontColor: 'rgba(0,0,0,.1)',
+      offsetTop: 200,
+      content: `${initialState.currentUser?.username}  ${initialState.currentUser?.telephone.slice(-4)}`
     },
+
     onPageChange: async location => {
       // 如果没有登录,重定向到 login
       if (!initialState?.currentUser?.staffId && location.pathname !== loginPath) {

+ 22 - 92
src/components/Table/src/BasicTable.tsx

@@ -1,46 +1,19 @@
 /* eslint-disable react-hooks/rules-of-hooks */
 /* eslint-disable no-param-reassign */
+import React, { useRef, useState, useLayoutEffect, useMemo } from 'react'
 import PermSelect from '@/pages/Customer/Company/components/PermSelect'
 import { TABLE_COLUMNS_MAP, ColumnStateEnum } from '@/utils/cache/cacheEnum'
 import { isBoolean, isMobile, isNullOrUnDef, isObject, isUnDef } from '@/utils/is'
-import type { ColumnsState } from '@ant-design/pro-table'
 import ProTable from '@ant-design/pro-table'
 import { useModel } from 'umi'
 import { getAuthCache, getPermAuthCache, setAuthCache } from '@/utils/auth'
-import React, { useRef, useState, useLayoutEffect, useMemo } from 'react'
-// import { useMount } from 'ahooks'
 import { useTableScroll } from './hooks/useTableScroll'
+import type { ColumnsState } from '@ant-design/pro-table'
 import type { BasicTableProps, PermStateEnum } from '@/types/typing'
 import type { ParamsType } from '@ant-design/pro-provider'
 import type { DensitySize } from '@ant-design/pro-table/lib/components/ToolBar/DensityIcon'
-// import { Resizable } from 'react-resizable'
-import styles from './index.less'
-
-// const ResizableTitle = props => {
-//   const { onResize, width, ...restProps } = props
-
-//   if (!width) {
-//     return <th {...restProps} />
-//   }
 
-//   return (
-//     <Resizable
-//       width={width}
-//       height={0}
-//       handle={
-//         <span
-//           className="table-resizable-handle"
-//           onClick={e => {
-//             e.stopPropagation()
-//           }}
-//         />
-//       }
-//       onResize={onResize}
-//       draggableOpts={{ enableUserSelectHack: false }}>
-//       <th {...restProps} />
-//     </Resizable>
-//   )
-// }
+import styles from './index.less'
 
 const BasicTable: {
   <T extends Record<string, any>, U extends ParamsType = ParamsType, ValueType = 'text'>(
@@ -49,7 +22,6 @@ const BasicTable: {
   // eslint-disable-next-line @typescript-eslint/consistent-type-imports
   Summary: typeof import('rc-table/lib/Footer/Summary').default
 } = ({
-  // resizable = false,
   onPermChange,
   rowKey,
   headerTitle,
@@ -110,19 +82,6 @@ const BasicTable: {
     }
   }, [state.dataSource])
 
-  // useMount(() => {
-  //   // 处理本地化存储
-  //   const authColumnsStateMap = getAuthCache(TABLE_COLUMNS_MAP)
-  //   console.log('111')
-
-  //   if (authColumnsStateMap && authColumnsStateMap[ColumnStateEnum[columnStateType]]) {
-  //     setState({
-  //       ...state,
-  //       columnsStateMap: authColumnsStateMap[ColumnStateEnum[columnStateType]]
-  //     })
-  //   }
-  // })
-
   /** 增加头部 */
   if (mainMenuType) {
     resetProps.headerTitle = (
@@ -184,57 +143,28 @@ const BasicTable: {
     }
   }, [rowSelection])
 
-  // 配置可伸缩列相关
-  // if (resizable) {
-  //   resetProps.components = {
-  //     header: {
-  //       cell: ResizableTitle
-  //     }
-  //   }
-  // }
-  // const handleResize =
-  //   i =>
-  //   (e, { size }) => {
-  //     const nextColumns = [...columns]
-  //     nextColumns[i] = {
-  //       ...nextColumns[i],
-  //       width: size.width
-  //     }
-  //     setColumns(nextColumns)
-  //   }
-  // const finallyColumns = useMemo(() => {
-  // if (resizable) {
-  //   return columns.map((col, index) => ({
-  //     ...col,
-  //     onHeaderCell: column => ({
-  //       width: column.width,
-  //       onResize: handleResize(index)
-  //     })
-  //   }))
-  // }
-  //   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={computedParams}
-        scroll={getScrollRef}
-        columnsState={{
-          defaultValue: state.columnsStateMap,
-          onChange: handleOnColumnsChange
-        }}
-        bordered={isNullOrUnDef(bordered) ? bordered : true}
-        onLoad={dataSource => setState({ ...state, dataSource })}
-        onSizeChange={handleOnSizeChange}
-        rowSelection={rowSelectionOptions}
-      />
-    </div>
+    <React.StrictMode>
+      <div ref={tableElRef} className={styles.BasicTable}>
+        <ProTable
+          {...resetProps}
+          rowKey={rowKey || 'id'}
+          columns={originalColumns}
+          params={computedParams}
+          scroll={getScrollRef}
+          columnsState={{
+            defaultValue: state.columnsStateMap,
+            onChange: handleOnColumnsChange
+          }}
+          bordered={isNullOrUnDef(bordered) ? bordered : true}
+          onLoad={dataSource => setState({ ...state, dataSource })}
+          onSizeChange={handleOnSizeChange}
+          rowSelection={rowSelectionOptions}
+        />
+      </div>
+    </React.StrictMode>
   )
 }
 

+ 88 - 94
src/pages/Customer/Business/index.jsx

@@ -10,6 +10,7 @@ import { PermDataTypeEunm } from '@/pages/Customer/Company/components/PermSelect
 import { BUSINESS_GROUP_KEY } from '@/utils/cache/cacheEnum'
 import { Plus } from '@icon-park/react'
 import { useModal } from '@/components/ModalStore'
+import { PageContainer } from '@ant-design/pro-layout'
 
 const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList }) => {
   const [defaultPermAuthCache, defaultStaffIds] = getPermAuthCache(PermDataTypeEunm.CUSTOMER)
@@ -29,12 +30,7 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList
       .find(item => item.value === state.params.businessGroupId)
       ?.items?.filter(item => !item.endProcess)
       ?.map(item => ({ ...item, percentage: parseInt(item.percentage, 10) }))
-  }, [
-    groupList,
-    state.params.businessGroupId,
-    state.groupParams.dataPermission,
-    state.groupParams.staffIds
-  ])
+  }, [groupList, state.params.businessGroupId, state.groupParams.dataPermission, state.groupParams.staffIds])
 
   const { initialState: { permData } = { permData: {} } } = useModel('@@initialState')
   const handleSearch = value => {
@@ -79,8 +75,7 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList
               group: groupList
             })
           }
-          className="text-primary cursor-pointer hover:text-hex-967bbd"
-        >
+          className="text-primary cursor-pointer hover:text-hex-967bbd">
           {text}
         </span>
       )
@@ -93,8 +88,7 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList
         record.customerId && (
           <span
             onClick={() => dispatchModal('D_COMPANY_DETAIL', { dataId: record.customerId })}
-            className="text-primary cursor-pointer hover:text-hex-967bbd"
-          >
+            className="text-primary cursor-pointer hover:text-hex-967bbd">
             {text}
           </span>
         )
@@ -150,97 +144,97 @@ const Business = ({ dispatch, groupList, shouldUpdate, loading, refreshGroupList
     })
   }
   return (
-    <div className="h-full w-full flex flex-row justify-between">
-      <div className="h-full w-1/5 rounded-4px shadow-card">
-        <div className="p-4 border-b-1 border-solid border-black border-opacity-10 bg-[#f7f9fa] flex justify-around items-center">
-          <div className="w-1/2 text-md">商机漏斗</div>
-          <div className="w-1/2">
-            {groupList?.length ? (
-              <Select
-                placeholder="请选择商机组"
-                size="small"
-                className="w-full"
-                bordered={false}
-                options={groupList}
-                defaultValue={defaultGroupId}
-                onChange={handleBussinessChange}
-              />
-            ) : null}
+    <PageContainer title={false} breadcrumb={false}>
+      <div className="h-full w-full flex flex-row justify-between">
+        <div className="h-full w-1/5 rounded-4px shadow-card">
+          <div className="p-4 border-b-1 border-solid border-black border-opacity-10 bg-[#f7f9fa] flex justify-around items-center">
+            <div className="w-1/2 text-md">商机漏斗</div>
+            <div className="w-1/2">
+              {groupList?.length ? (
+                <Select
+                  placeholder="请选择商机组"
+                  size="small"
+                  className="w-full"
+                  bordered={false}
+                  options={groupList}
+                  defaultValue={defaultGroupId}
+                  onChange={handleBussinessChange}
+                />
+              ) : null}
+            </div>
           </div>
-        </div>
-        <div className="p-4 bg-white " style={{ height: 'calc(100% - 1rem*2 - 25px)' }}>
-          <div className="max-h-1/3">
-            {funnelData?.length ? <Funnel data={funnelData} {...conifg} /> : null}
+          <div className="p-4 bg-white " style={{ height: 'calc(100% - 1rem*2 - 25px)' }}>
+            <div className="max-h-1/3">
+              {funnelData?.length ? <Funnel data={funnelData} {...conifg} /> : null}
+            </div>
           </div>
         </div>
-      </div>
-      <div className="w-4/5">
-        <div className="ml-8 bg-white shadow-card">
-          <BasicTable
-            actionRef={tRef}
-            mainMenuType="customer"
-            columnStateType="BUSINESS"
-            onPermChange={handleOnPermChange}
-            params={state.params}
-            rowKey={record => record.id}
-            columns={columns}
-            request={async (params, sort, filter) => {
-              if (!state.params.businessGroupId) {
+        <div className="w-4/5">
+          <div className="ml-8 bg-white shadow-card">
+            <BasicTable
+              actionRef={tRef}
+              mainMenuType="customer"
+              columnStateType="BUSINESS"
+              onPermChange={handleOnPermChange}
+              params={state.params}
+              rowKey={record => record.id}
+              columns={columns}
+              request={async (params, sort, filter) => {
+                if (!state.params.businessGroupId) {
+                  return {
+                    data: [],
+                    success: true,
+                    total: 0
+                  }
+                }
+                const {
+                  code = -1,
+                  data: { business = [], total = 0 }
+                } = await getBusinessList({ ...params, ...sort, ...filter })
+                setState({ ...state, orderIds: business.map(item => item.id) })
                 return {
-                  data: [],
-                  success: true,
-                  total: 0
+                  data: business,
+                  success: code === consts.RET_CODE.SUCCESS,
+                  total
                 }
-              }
-              const {
-                code = -1,
-                data: { business = [], total = 0 }
-              } = await getBusinessList({ ...params, ...sort, ...filter })
-              setState({ ...state, orderIds: business.map(item => item.id) })
-              return {
-                data: business,
-                success: code === consts.RET_CODE.SUCCESS,
-                total
-              }
-            }}
-            search={false}
-            toolbar={{
-              search: (
-                <Tooltip placement="bottom" title="输入商机名称、单位名称">
-                  <Input.Search
-                    style={{ width: '300px' }}
-                    allowClear={true}
-                    placeholder={`在${
-                      permData[PermDataTypeEunm.CUSTOMER]?.find(
-                        item => item.value === defaultPermAuthCache
-                      )?.label
-                    }下搜索`}
-                    onSearch={handleSearch}
-                  />
-                </Tooltip>
-              ),
-              actions: [
-                <Button
-                  type="primary"
-                  key="add_business"
-                  className="flex items-center"
-                  disabled={!hasAddPerm}
-                  onClick={() =>
-                    dispatchModal('M_BUSINESS_ADD', {
-                      groupList: state.groupList,
-                      reload: () => tRef.current?.reload()
-                    })
-                  }
-                >
-                  <Plus className="mr-1" />
-                  商机
-                </Button>
-              ]
-            }}
-          />
+              }}
+              search={false}
+              toolbar={{
+                search: (
+                  <Tooltip placement="bottom" title="输入商机名称、单位名称">
+                    <Input.Search
+                      style={{ width: '300px' }}
+                      allowClear={true}
+                      placeholder={`在${
+                        permData[PermDataTypeEunm.CUSTOMER]?.find(item => item.value === defaultPermAuthCache)
+                          ?.label
+                      }下搜索`}
+                      onSearch={handleSearch}
+                    />
+                  </Tooltip>
+                ),
+                actions: [
+                  <Button
+                    type="primary"
+                    key="add_business"
+                    className="flex items-center"
+                    disabled={!hasAddPerm}
+                    onClick={() =>
+                      dispatchModal('M_BUSINESS_ADD', {
+                        groupList: state.groupList,
+                        reload: () => tRef.current?.reload()
+                      })
+                    }>
+                    <Plus className="mr-1" />
+                    商机
+                  </Button>
+                ]
+              }}
+            />
+          </div>
         </div>
       </div>
-    </div>
+    </PageContainer>
   )
 }
 

+ 78 - 82
src/pages/Customer/Client/index.jsx

@@ -15,6 +15,7 @@ import BasicTable from '@/components/Table'
 import { getPermAuthCache } from '@/utils/auth'
 import { useModal } from '@/components/ModalStore'
 import { Plus } from '@icon-park/react'
+import { PageContainer } from '@ant-design/pro-layout'
 const Client = props => {
   const dispatchModal = useModal()
   const {
@@ -139,8 +140,7 @@ const Client = props => {
       render: (clientName, record) => (
         <span
           onClick={() => dispatchModal('D_CLIENT_DETAIL', { dataId: record.id, orderIds: state.orderIds })}
-          className="text-primary cursor-pointer hover:text-hex-967bbd"
-        >
+          className="text-primary cursor-pointer hover:text-hex-967bbd">
           {clientName}
         </span>
       ),
@@ -163,8 +163,7 @@ const Client = props => {
                 orderIds: state.orderIds
               })
             }}
-            className="text-primary cursor-pointer hover:text-hex-967bbd"
-          >
+            className="text-primary cursor-pointer hover:text-hex-967bbd">
             {companyName}
           </span>
         ) : (
@@ -270,8 +269,7 @@ 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>
@@ -308,8 +306,7 @@ 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>
@@ -476,8 +473,7 @@ 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 => (
@@ -502,8 +498,7 @@ 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 => (
@@ -531,77 +526,78 @@ const Client = props => {
     )
   }
   return (
-    <div className={styles.contactContent}>
-      <BasicTable
-        mainMenuType="customer"
-        columnStateType="CLIENT"
-        params={state.params}
-        actionRef={tRef}
-        rowKey={record => record.id}
-        columns={columns}
-        request={async (params, sort, filter) => {
-          const srotOrder = generateSortField(sort)
-          const nFilter = generateFilterField(filter)
-          const {
-            code = -1,
-            data: { client = [], total = 0 }
-          } = await queryClient({ ...params, ...srotOrder, ...nFilter })
-          setState({ ...state, orderIds: client.map(item => item.id) })
-          return {
-            data: client,
-            success: code === consts.RET_CODE.SUCCESS,
-            total
-          }
-        }}
-        tableAlertRender={renderTableAlert}
-        rowSelection={{
-          type: 'checkbox',
-          columnWidth: 25
-        }}
-        search={{ filterType: 'light' }}
-        toolbar={{
-          search: (
-            <Tooltip placement="bottom" title="输入客户、单位名称、电话邮箱等">
-              <Input.Search
-                style={{ width: '250px' }}
-                allowClear={true}
-                placeholder={`在${
-                  permData[PermDataTypeEunm.CUSTOMER]?.find(item => item.value === defaultPermAuthCache)
-                    ?.label
-                }下搜索`}
-                onSearch={handleSearch}
-              />
-            </Tooltip>
-          ),
+    <PageContainer title={false} breadcrumb={false}>
+      <div className={styles.contactContent}>
+        <BasicTable
+          mainMenuType="customer"
+          columnStateType="CLIENT"
+          params={state.params}
+          actionRef={tRef}
+          rowKey={record => record.id}
+          columns={columns}
+          request={async (params, sort, filter) => {
+            const srotOrder = generateSortField(sort)
+            const nFilter = generateFilterField(filter)
+            const {
+              code = -1,
+              data: { client = [], total = 0 }
+            } = await queryClient({ ...params, ...srotOrder, ...nFilter })
+            setState({ ...state, orderIds: client.map(item => item.id) })
+            return {
+              data: client,
+              success: code === consts.RET_CODE.SUCCESS,
+              total
+            }
+          }}
+          tableAlertRender={renderTableAlert}
+          rowSelection={{
+            type: 'checkbox',
+            columnWidth: 25
+          }}
+          search={{ filterType: 'light' }}
+          toolbar={{
+            search: (
+              <Tooltip placement="bottom" title="输入客户、单位名称、电话邮箱等">
+                <Input.Search
+                  style={{ width: '250px' }}
+                  allowClear={true}
+                  placeholder={`在${
+                    permData[PermDataTypeEunm.CUSTOMER]?.find(item => item.value === defaultPermAuthCache)
+                      ?.label
+                  }下搜索`}
+                  onSearch={handleSearch}
+                />
+              </Tooltip>
+            ),
 
-          actions: [
-            <LazyCascader
-              key="lazyCascader"
-              onChange={onDistrictChange}
-              changeOnSelect={true}
-              bordered={false}
-              showFooter={true}
-              className="hover:bg-[rgba(0,0,0,0.1)]"
-            />,
-            <Button
-              type="primary"
-              key="addClientBtn"
-              disabled={!hasAddPerm}
-              onClick={() =>
-                dispatchModal('M_CLIENT_ADD', {
-                  onConfirm: handleAddClient,
-                  reload: () => tRef.current?.reload()
-                })
-              }
-            >
-              <Plus className="mr-1" />
-              客户
-            </Button>
-          ]
-        }}
-        columnsStateMap={columnsStateMap}
-      />
-    </div>
+            actions: [
+              <LazyCascader
+                key="lazyCascader"
+                onChange={onDistrictChange}
+                changeOnSelect={true}
+                bordered={false}
+                showFooter={true}
+                className="hover:bg-[rgba(0,0,0,0.1)]"
+              />,
+              <Button
+                type="primary"
+                key="addClientBtn"
+                disabled={!hasAddPerm}
+                onClick={() =>
+                  dispatchModal('M_CLIENT_ADD', {
+                    onConfirm: handleAddClient,
+                    reload: () => tRef.current?.reload()
+                  })
+                }>
+                <Plus className="mr-1" />
+                客户
+              </Button>
+            ]
+          }}
+          columnsStateMap={columnsStateMap}
+        />
+      </div>
+    </PageContainer>
   )
 }
 

+ 88 - 71
src/pages/Customer/Company/index.jsx

@@ -14,10 +14,20 @@ import { PermDataTypeEunm } from './components/PermSelect'
 import BasicTable from '@/components/Table'
 import { getPermAuthCache } from '@/utils/auth'
 import { useModal } from '@/components/ModalStore'
+import { PageContainer } from '@ant-design/pro-layout'
 // import FilterCascader from '@/components/Table/src/components/FilterCascader'
 
 const Company = props => {
-  const { personTagColorMap, teamTagColorMap, personTags, teamTags, natures, dispatch, shouldUpdate, loading } = props
+  const {
+    personTagColorMap,
+    teamTagColorMap,
+    personTags,
+    teamTags,
+    natures,
+    dispatch,
+    shouldUpdate,
+    loading
+  } = props
 
   const { initialState: { permData } = { permData: {} } } = useModel('@@initialState')
 
@@ -84,7 +94,10 @@ const Company = props => {
       teamTagMap[item.id] = {
         text: (
           <>
-            <span className="inline-block w-12px h-12px mr-3px" style={{ backgroundColor: teamTagColorMap[item.id] }} />
+            <span
+              className="inline-block w-12px h-12px mr-3px"
+              style={{ backgroundColor: teamTagColorMap[item.id] }}
+            />
             <span>{item.name}</span>
           </>
         )
@@ -444,75 +457,79 @@ const Company = props => {
   if (!personTags?.length || !teamTags?.length) return null
 
   return (
-    <div className={styles.companyContent}>
-      <BasicTable
-        rowKey={record => record.id}
-        actionRef={tRef}
-        mainMenuType="customer"
-        columnStateType="COMPANY"
-        params={state.params}
-        request={async (params, sort, filter) => {
-          const srotOrder = generateSortField(sort)
-          const nFilter = generateFilterField(filter)
-          const { code = -1, data: { customer = [], total = 0 } = { customer: [], total: 0 } } = await queryCompany({
-            ...params,
-            ...srotOrder,
-            ...nFilter
-          })
-          setState({ ...state, orderIds: customer.map(item => item.id) })
-          return {
-            data: customer,
-            success: code === consts.RET_CODE.SUCCESS,
-            total
-          }
-        }}
-        search={{ filterType: 'light' }}
-        toolbar={{
-          search: (
-            <Tooltip placement="bottom" title="输入单位名称、单位性质等">
-              <Input.Search
-                style={{ width: '250px' }}
-                allowClear={true}
-                placeholder={`在${
-                  permData[PermDataTypeEunm.CUSTOMER]?.find(item => item.value === defaultPermAuthCache)?.label
-                }下搜索`}
-                onSearch={handleSearch}
-              />
-            </Tooltip>
-          ),
-          actions: [
-            <LazyCascader
-              onChange={onDistrictChange}
-              changeOnSelect={true}
-              key="lazyCascader"
-              showFooter={true}
-              className="hover:bg-[rgba(0,0,0,0.1)]"
-              bordered={false}
-            />,
-            <Button
-              key="add_company"
-              disabled={!hasAddPerm}
-              type="primary"
-              onClick={() =>
-                dispatchModal('M_COMPANY_ADD', {
-                  onConfirm: handleAddCompany,
-                  reload: () => tRef.current?.reload()
-                })
-              }>
-              <Plus className="mr-1" />
-              单位
-            </Button>
-          ]
-        }}
-        rowSelection={{
-          type: 'checkbox',
-          columnWidth: 25
-        }}
-        tableAlertRender={renderTableAlert}
-        columnsStateMap={columnsStateMap}
-        columns={columns}
-      />
-    </div>
+    <PageContainer title={false} breadcrumb={false}>
+      <div className={styles.companyContent}>
+        <BasicTable
+          rowKey={record => record.id}
+          actionRef={tRef}
+          mainMenuType="customer"
+          columnStateType="COMPANY"
+          params={state.params}
+          request={async (params, sort, filter) => {
+            const srotOrder = generateSortField(sort)
+            const nFilter = generateFilterField(filter)
+            const { code = -1, data: { customer = [], total = 0 } = { customer: [], total: 0 } } =
+              await queryCompany({
+                ...params,
+                ...srotOrder,
+                ...nFilter
+              })
+            setState({ ...state, orderIds: customer.map(item => item.id) })
+            return {
+              data: customer,
+              success: code === consts.RET_CODE.SUCCESS,
+              total
+            }
+          }}
+          search={{ filterType: 'light' }}
+          toolbar={{
+            search: (
+              <Tooltip placement="bottom" title="输入单位名称、单位性质等">
+                <Input.Search
+                  style={{ width: '250px' }}
+                  allowClear={true}
+                  placeholder={`在${
+                    permData[PermDataTypeEunm.CUSTOMER]?.find(item => item.value === defaultPermAuthCache)
+                      ?.label
+                  }下搜索`}
+                  onSearch={handleSearch}
+                />
+              </Tooltip>
+            ),
+            actions: [
+              <LazyCascader
+                onChange={onDistrictChange}
+                changeOnSelect={true}
+                key="lazyCascader"
+                showFooter={true}
+                className="hover:bg-[rgba(0,0,0,0.1)]"
+                bordered={false}
+              />,
+              <Button
+                key="add_company"
+                disabled={!hasAddPerm}
+                type="primary"
+                onClick={() =>
+                  dispatchModal('M_COMPANY_ADD', {
+                    onConfirm: handleAddCompany,
+                    reload: () => tRef.current?.reload()
+                  })
+                }>
+                <Plus className="mr-1" />
+                单位
+              </Button>
+            ]
+          }}
+          rowSelection={{
+            type: 'checkbox',
+            columnWidth: 25
+          }}
+          tableAlertRender={renderTableAlert}
+          columnsStateMap={columnsStateMap}
+          columns={columns}
+        />
+      </div>
+    </PageContainer>
   )
 }
 

+ 245 - 240
src/pages/Workbench/Dashboard/index.jsx

@@ -18,6 +18,7 @@ import { isDevMode } from '@/utils/env'
 import { isMobile } from '@/utils/is'
 import { useModal } from '@/components/ModalStore'
 import classNames from 'classnames'
+import { PageContainer } from '@ant-design/pro-layout'
 
 const Dashboard = ({ dispatch, departments = [] }) => {
   const { initialState: { currentUser } = { currentUser: {} } } = useModel('@@initialState')
@@ -292,181 +293,184 @@ const Dashboard = ({ dispatch, departments = [] }) => {
     setState({ ...state, immediate: true, params: { ...state.params, cyclical: value } })
   }
   return (
-    <div className={styles.dashboard}>
-      <div>
-        <Row gutter={[8, 8]}>
-          <Col xs={24} sm={24} md={24} lg={18} xl={18}>
-            <div className="shadow-card">
-              <ProTable
-                bordered
+    <PageContainer title={false} breadcrumb={false} waterMarkProps={{ offsetTop: 111 }}>
+      <div className={styles.dashboard}>
+        <div>
+          <Row gutter={[8, 8]}>
+            <Col xs={24} sm={24} md={24} lg={18} xl={18}>
+              <div className="shadow-card">
+                <ProTable
+                  bordered
+                  loading={state.loading}
+                  rowKey={record => record.type + Date.now()}
+                  columns={columns}
+                  dataSource={state.reminderData}
+                  search={false}
+                  toolBarRender={false}
+                  tableRender={(_, dom) => (
+                    <Card bodyStyle={{ padding: state.loading ? '24px' : 0 }} loading={state.loading}>
+                      {dom}
+                    </Card>
+                  )}
+                  pagination={false}
+                />
+              </div>
+            </Col>
+            <Col xs={24} sm={24} md={24} lg={6} xl={6}>
+              <div className="shadow-card">
+                <ProTable
+                  bordered
+                  loading={state.loading}
+                  rowKey={record => record.type + Date.now()}
+                  columns={columnsSmall}
+                  dataSource={state.reminderData}
+                  search={false}
+                  toolBarRender={false}
+                  tableRender={(_, dom) => (
+                    <Card bodyStyle={{ padding: state.loading ? '24px' : 0 }} loading={state.loading}>
+                      {dom}
+                    </Card>
+                  )}
+                  pagination={false}
+                />
+              </div>
+            </Col>
+          </Row>
+        </div>
+
+        <div className="flex flex-wrap">
+          <div className="mr-4 my-4 flex">
+            <Select
+              disabled={state.disabled}
+              loading={state.loading}
+              options={cyclicalOp}
+              dropdownMatchSelectWidth={false}
+              defaultValue={defaultCyclicalValue}
+              onChange={handleCyclicalChange}
+            />
+            <div className="mx-2">
+              <PermSelect
                 loading={state.loading}
-                rowKey={record => record.type + Date.now()}
-                columns={columns}
-                dataSource={state.reminderData}
-                search={false}
-                toolBarRender={false}
-                tableRender={(_, dom) => (
-                  <Card bodyStyle={{ padding: state.loading ? '24px' : 0 }} loading={state.loading}>
-                    {dom}
-                  </Card>
-                )}
-                pagination={false}
+                disabled={state.disabled}
+                onConfirm={handlePermChange}
+                dataType="workbench"
               />
             </div>
-          </Col>
-          <Col xs={24} sm={24} md={24} lg={6} xl={6}>
-            <div className="shadow-card">
-              <ProTable
-                bordered
+            {state.params.dataPermission === 'all' ? (
+              <TreeSelect
+                size="middle"
+                style={{ width: 150 }}
+                dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
                 loading={state.loading}
-                rowKey={record => record.type + Date.now()}
-                columns={columnsSmall}
-                dataSource={state.reminderData}
-                search={false}
-                toolBarRender={false}
-                tableRender={(_, dom) => (
-                  <Card bodyStyle={{ padding: state.loading ? '24px' : 0 }} loading={state.loading}>
-                    {dom}
-                  </Card>
-                )}
-                pagination={false}
+                disabled={state.disabled}
+                treeDefaultExpandAll
+                placeholder="办事处"
+                treeData={departments}
+                allowClear
+                onSelect={queryStaffList}
+                onChange={e => {
+                  if (!e)
+                    setState({
+                      ...state,
+                      params: { ...state.params, staffIds: null },
+                      staffList: [],
+                      selectId: null
+                    })
+                }}
               />
-            </div>
-          </Col>
-        </Row>
-      </div>
-
-      <div className="flex flex-wrap">
-        <div className="mr-4 my-4 flex">
-          <Select
-            disabled={state.disabled}
-            loading={state.loading}
-            options={cyclicalOp}
-            dropdownMatchSelectWidth={false}
-            defaultValue={defaultCyclicalValue}
-            onChange={handleCyclicalChange}
-          />
-          <div className="mx-2">
-            <PermSelect
-              loading={state.loading}
-              disabled={state.disabled}
-              onConfirm={handlePermChange}
-              dataType="workbench"
-            />
+            ) : null}
           </div>
-          {state.params.dataPermission === 'all' ? (
-            <TreeSelect
-              size="middle"
-              style={{ width: 150 }}
-              dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
-              loading={state.loading}
-              disabled={state.disabled}
-              treeDefaultExpandAll
-              placeholder="办事处"
-              treeData={departments}
-              allowClear
-              onSelect={queryStaffList}
-              onChange={e => {
-                if (!e)
-                  setState({
-                    ...state,
-                    params: { ...state.params, staffIds: null },
-                    staffList: [],
-                    selectId: null
-                  })
-              }}
-            />
-          ) : null}
-        </div>
 
-        <div className="flex items-center flex-row ml-2">
-          {['all', 'department'].includes(state.params.dataPermission) &&
-            state.staffList.map(item => (
-              <div
-                className={classNames('relative cursor-pointer', styles.staffItem, {
-                  [styles.active]: state.selectId === item.id
-                })}
-                key={item.id}
-                onClick={() => handleStaffClick(item.id)}>
-                <img
-                  className="w-full max-w-30px h-30px border rounded-30px"
-                  src={
-                    (isDevMode() ? 'http://cld2qa.com' : 'http://zhcld.com') +
-                    (item?.avatar ?? consts.DEFAULT_AVATAR)
-                  }
-                />
-                <span className={styles.extra}>{item.username}</span>
-              </div>
-            ))}
-        </div>
-      </div>
-      <Row gutter={[8, 8]}>
-        <Col xs={24} sm={24} md={24} lg={8} xl={8}>
-          <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
-            {state.loading ? (
-              <Skeleton active avatar />
-            ) : (
-              <Row className="cursor-pointer" onClick={() => handleRatioCard(cardTypeMap.CLIENT)}>
-                <Col span={6}>
-                  <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
-                    <AddressBook size="26" fill="#fff" />
-                  </div>
-                </Col>
-                <Col span={18} flex="wrap">
-                  <div className="flex items-center justify-between ">
-                    <div className="text-2xl">{state.clientChainRatio.count}</div>
-                    <span
-                      className={[
-                        'text-xl',
-                        state.clientChainRatio.percentage.startsWith('-') ? 'text-green-500' : 'text-red-500'
-                      ].join(' ')}>
-                      {state.clientChainRatio.percentage}
-                    </span>
-                  </div>
-                  <div className="flex justify-between items-center">
-                    <div>新增客户</div>
-                    <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
-                  </div>
-                </Col>
-              </Row>
-            )}
+          <div className="flex items-center flex-row ml-2">
+            {['all', 'department'].includes(state.params.dataPermission) &&
+              state.staffList.map(item => (
+                <div
+                  className={classNames('relative cursor-pointer', styles.staffItem, {
+                    [styles.active]: state.selectId === item.id
+                  })}
+                  key={item.id}
+                  onClick={() => handleStaffClick(item.id)}>
+                  <img
+                    className="w-full max-w-30px h-30px border rounded-30px"
+                    src={
+                      (isDevMode() ? 'http://cld2qa.com' : 'http://zhcld.com') +
+                      (item?.avatar ?? consts.DEFAULT_AVATAR)
+                    }
+                  />
+                  <span className={styles.extra}>{item.username}</span>
+                </div>
+              ))}
           </div>
-        </Col>
-        <Col xs={24} sm={24} md={24} lg={8} xl={8}>
-          <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
-            {state.loading ? (
-              <Skeleton active avatar />
-            ) : (
-              <Row className="cursor-pointer" onClick={() => handleRatioCard(cardTypeMap.COMPANY)}>
-                <Col span={6}>
-                  <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
-                    <City size="26" fill="#fff" />
-                  </div>
-                </Col>
-                <Col span={18} flex="wrap">
-                  <div className="flex items-center justify-between ">
-                    <div className="text-2xl">{state.customerChainRatio.count}</div>
-                    <span
-                      className={[
-                        'text-xl',
-                        state.customerChainRatio.percentage.startsWith('-')
-                          ? 'text-green-500'
-                          : 'text-red-500'
-                      ].join(' ')}>
-                      {state.customerChainRatio.percentage}
-                    </span>
-                  </div>
+        </div>
+        <Row gutter={[8, 8]}>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
+                <Row className="cursor-pointer" onClick={() => handleRatioCard(cardTypeMap.CLIENT)}>
+                  <Col span={6}>
+                    <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
+                      <AddressBook size="26" fill="#fff" />
+                    </div>
+                  </Col>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.clientChainRatio.count}</div>
+                      <span
+                        className={[
+                          'text-xl',
+                          state.clientChainRatio.percentage.startsWith('-')
+                            ? 'text-green-500'
+                            : 'text-red-500'
+                        ].join(' ')}>
+                        {state.clientChainRatio.percentage}
+                      </span>
+                    </div>
+                    <div className="flex justify-between items-center">
+                      <div>新增客户</div>
+                      <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
+                    </div>
+                  </Col>
+                </Row>
+              )}
+            </div>
+          </Col>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
+                <Row className="cursor-pointer" onClick={() => handleRatioCard(cardTypeMap.COMPANY)}>
+                  <Col span={6}>
+                    <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
+                      <City size="26" fill="#fff" />
+                    </div>
+                  </Col>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.customerChainRatio.count}</div>
+                      <span
+                        className={[
+                          'text-xl',
+                          state.customerChainRatio.percentage.startsWith('-')
+                            ? 'text-green-500'
+                            : 'text-red-500'
+                        ].join(' ')}>
+                        {state.customerChainRatio.percentage}
+                      </span>
+                    </div>
 
-                  <div className="flex justify-between items-center">
-                    <div>新增单位</div>
-                    <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
-                  </div>
-                </Col>
-              </Row>
-            )}
-          </div>
-        </Col>
-        {/* <Col xs={24} sm={24} md={24} lg={6} xl={6}>
+                    <div className="flex justify-between items-center">
+                      <div>新增单位</div>
+                      <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
+                    </div>
+                  </Col>
+                </Row>
+              )}
+            </div>
+          </Col>
+          {/* <Col xs={24} sm={24} md={24} lg={6} xl={6}>
             <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
               {state.loading ? (
                 <Skeleton active avatar />
@@ -504,44 +508,44 @@ const Dashboard = ({ dispatch, departments = [] }) => {
               )}
             </div>
           </Col> */}
-        <Col xs={24} sm={24} md={24} lg={8} xl={8}>
-          <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
-            {state.loading ? (
-              <Skeleton active avatar />
-            ) : (
-              <Row onClick={() => handleRatioCard(cardTypeMap.SERVICE)} className="cursor-pointer">
-                <Col span={6}>
-                  <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
-                    <Comment size="26" fill="#fff" />
-                  </div>
-                </Col>
-                <Col span={18} flex="wrap">
-                  <div className="flex items-center justify-between ">
-                    <div className="text-2xl">{state.serviceLogChainRatio.count}</div>
-                    <span
-                      className={[
-                        'text-xl',
-                        state.serviceLogChainRatio.percentage.startsWith('-')
-                          ? 'text-green-500'
-                          : 'text-red-500'
-                      ].join(' ')}>
-                      {state.serviceLogChainRatio.percentage}
-                    </span>
-                  </div>
+          <Col xs={24} sm={24} md={24} lg={8} xl={8}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0 shadow-card">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
+                <Row onClick={() => handleRatioCard(cardTypeMap.SERVICE)} className="cursor-pointer">
+                  <Col span={6}>
+                    <div className="w-full max-w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
+                      <Comment size="26" fill="#fff" />
+                    </div>
+                  </Col>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.serviceLogChainRatio.count}</div>
+                      <span
+                        className={[
+                          'text-xl',
+                          state.serviceLogChainRatio.percentage.startsWith('-')
+                            ? 'text-green-500'
+                            : 'text-red-500'
+                        ].join(' ')}>
+                        {state.serviceLogChainRatio.percentage}
+                      </span>
+                    </div>
 
-                  <div className="flex justify-between items-center">
-                    <div>服务记录</div>
-                    <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
-                  </div>
-                </Col>
-              </Row>
-            )}
-          </div>
-        </Col>
-      </Row>
-      <div className="mt-4">
-        <Row gutter={[8, 8]}>
-          {/* <Col xs={24} sm={24} md={24} lg={12} xl={12}>
+                    <div className="flex justify-between items-center">
+                      <div>服务记录</div>
+                      <span>{cyclicalOp.find(item => item.value === state.params.cyclical)?.title}</span>
+                    </div>
+                  </Col>
+                </Row>
+              )}
+            </div>
+          </Col>
+        </Row>
+        <div className="mt-4">
+          <Row gutter={[8, 8]}>
+            {/* <Col xs={24} sm={24} md={24} lg={12} xl={12}>
             <BusinessChar
               loading={state.loading}
               data={state.businessChar}
@@ -549,44 +553,45 @@ const Dashboard = ({ dispatch, departments = [] }) => {
             />
           </Col> */}
 
-          <Col xs={24} sm={24} md={24} lg={24} xl={24}>
-            <Card
-              headStyle={{ padding: '0 12px' }}
-              title="数据汇总"
-              className="shadow-card"
-              bodyStyle={{ padding: state.loading ? '24px' : 0 }}
-              loading={state.loading}>
-              <ul>
-                <li className="px-12px py-16px border-b-1">
-                  新增客户<b className="px-1">{state.aggregation.clientCount}</b>个,服务
-                  <b className="px-1">{state.aggregation.clientServiceCount}</b> 条
-                </li>
-                <li className="px-12px py-16px border-b-1">
-                  新增单位<b className="px-1">{state.aggregation.customerCount}</b>个,服务
-                  <b className="px-1">{state.aggregation.customerServiceCount}</b>条
-                </li>
-                <li className="px-12px py-16px">
-                  新增商机<b className="px-1">{state.aggregation.businessCount}</b>个,金额
-                  <b className="px-1">{state.aggregation.businessSum}</b> 元,服务
-                  <b className="px-1">{state.aggregation.businessServiceCount}</b>
-                  条,赢单<b className="px-1">{state.aggregation.businessWinCount}</b>个
-                </li>
-              </ul>
-            </Card>
-          </Col>
-        </Row>
-      </div>
-      <div className="mt-4">
-        <Row gutter={[8, 8]}>
-          <Col xs={24} sm={24} md={24} lg={12} xl={12}>
-            <LeaderBoard dataList={state.leaderboard} loading={state.loading} />
-          </Col>
-          <Col xs={24} sm={24} md={24} lg={12} xl={12}>
-            <SoftLeaderboard productLeaderBoard={state.productLeaderBoard} loading={state.loading} />
-          </Col>
-        </Row>
+            <Col xs={24} sm={24} md={24} lg={24} xl={24}>
+              <Card
+                headStyle={{ padding: '0 12px' }}
+                title="数据汇总"
+                className="shadow-card"
+                bodyStyle={{ padding: state.loading ? '24px' : 0 }}
+                loading={state.loading}>
+                <ul>
+                  <li className="px-12px py-16px border-b-1">
+                    新增客户<b className="px-1">{state.aggregation.clientCount}</b>个,服务
+                    <b className="px-1">{state.aggregation.clientServiceCount}</b> 条
+                  </li>
+                  <li className="px-12px py-16px border-b-1">
+                    新增单位<b className="px-1">{state.aggregation.customerCount}</b>个,服务
+                    <b className="px-1">{state.aggregation.customerServiceCount}</b>条
+                  </li>
+                  <li className="px-12px py-16px">
+                    新增商机<b className="px-1">{state.aggregation.businessCount}</b>个,金额
+                    <b className="px-1">{state.aggregation.businessSum}</b> 元,服务
+                    <b className="px-1">{state.aggregation.businessServiceCount}</b>
+                    条,赢单<b className="px-1">{state.aggregation.businessWinCount}</b>个
+                  </li>
+                </ul>
+              </Card>
+            </Col>
+          </Row>
+        </div>
+        <div className="mt-4">
+          <Row gutter={[8, 8]}>
+            <Col xs={24} sm={24} md={24} lg={12} xl={12}>
+              <LeaderBoard dataList={state.leaderboard} loading={state.loading} />
+            </Col>
+            <Col xs={24} sm={24} md={24} lg={12} xl={12}>
+              <SoftLeaderboard productLeaderBoard={state.productLeaderBoard} loading={state.loading} />
+            </Col>
+          </Row>
+        </div>
       </div>
-    </div>
+    </PageContainer>
   )
 }
 

+ 3 - 4
src/types/typing.d.ts

@@ -18,7 +18,6 @@ import type { SortOrder } from 'antd/lib/table/interface'
 import type { ProFieldEmptyText } from '@ant-design/pro-field'
 import type { Bordered } from '@ant-design/pro-table/lib/typing'
 import type { ReactNode } from 'react-router/node_modules/@types/react'
-
 export type PermStateEnum = {
   staffIds: string[] | null
   dataPermission: string | null
@@ -28,11 +27,11 @@ export type BasicTableProps<T, U extends ParamsType, ValueType = 'text'> = {
   onPermChange?: (map: PermStateEnum) => void
   /** @name 配置search栏tooltip的title属性 */
   searchTooptip?: boolean | string | ReactNode
-  /** @name 启用列可伸缩功能 */
+  /** @deprecated 启用列可伸缩功能(已弃用) */
   resizable?: boolean
-  /** @type 枚举表中的菜单常量 */
+  /** @name 枚举表中的菜单常量 */
   mainMenuType?: MainMenuKeyEnum
-  /** @type 枚举表中的表格列常量 */
+  /** @name 枚举表中的表格列常量 */
   columnStateType?: ColumnStateEnum
   columns?: ProColumns<T, ValueType>[]
   /** @name ListToolBar 的属性 */