فهرست منبع

feat: 仪表盘增加骨架屏

lanjianrong 5 سال پیش
والد
کامیت
bbcfcb5132
4فایلهای تغییر یافته به همراه170 افزوده شده و 118 حذف شده
  1. 3 3
      config/config.js
  2. 4 0
      src/global.less
  3. 21 17
      src/pages/workbench/Dashboard/components/LeaderBoard.jsx
  4. 142 98
      src/pages/workbench/Dashboard/index.jsx

+ 3 - 3
config/config.js

@@ -32,9 +32,9 @@ export default defineConfig({
     // default true, when it is true, will use `navigator.language` overwrite default
     baseNavigator: false
   },
-  dynamicImport: {
-    loading: '@/components/PageLoading/index'
-  },
+  // dynamicImport: {
+  //   loading: '@/components/PageLoading/index'
+  // },
   targets: {
     ie: 11
   },

+ 4 - 0
src/global.less

@@ -111,6 +111,10 @@ input:-webkit-autofill:active {
 .ant-drawer-body {
   padding: 0;
 }
+
+.ant-skeleton-element {
+  width: 100% !important;
+}
 // 弹窗左右结构
 .sheet-box {
   overflow: hidden;

+ 21 - 17
src/pages/workbench/Dashboard/components/LeaderBoard.jsx

@@ -1,5 +1,5 @@
 import ProTable from '@ant-design/pro-table'
-import { Select } from 'antd'
+import { Select, Card } from 'antd'
 import Iconfont from '@/components/SvgIcon'
 import React, { useState, useMemo } from 'react'
 
@@ -18,7 +18,7 @@ const colorMap = {
   2: 'text-hex-1dc9b7',
   3: 'text-hex-868e96'
 }
-const LeaderBoard = ({ dataList = [] }) => {
+const LeaderBoard = ({ loading = false, dataList = [] }) => {
   const [activeOp, setActiveOp] = useState('customer')
   const columns = useMemo(() => {
     const oColumns = [
@@ -93,20 +93,24 @@ const LeaderBoard = ({ dataList = [] }) => {
   }, [activeOp])
 
   return (
-    <>
-      <div className="px-4 pt-2 pb-0 flex items-center justify-between">
-        <span>排行榜</span>
-        <Select defaultValue="customer" onChange={e => setActiveOp(e)}>
-          <Option value="customer">新增客户</Option>
-          <Option value="customerService">客户服务</Option>
-          <Option value="client">新增联系人</Option>
-          <Option value="clientService">联系人服务</Option>
-          <Option value="business">新增商机</Option>
-          <Option value="businessService">商机服务</Option>
-          {/* <Option value="开票金额">开票金额</Option>
-          <Option value="回款金额">回款金额</Option> */}
-        </Select>
-      </div>
+    <Card
+      loading={loading}
+      bodyStyle={{ padding: loading ? '24px' : 0 }}
+      title={
+        <div className="px-4 pt-2 pb-0 flex items-center justify-between">
+          <span>排行榜</span>
+          <Select defaultValue="customer" onChange={e => setActiveOp(e)}>
+            <Option value="customer">新增客户</Option>
+            <Option value="customerService">客户服务</Option>
+            <Option value="client">新增联系人</Option>
+            <Option value="clientService">联系人服务</Option>
+            <Option value="business">新增商机</Option>
+            <Option value="businessService">商机服务</Option>
+            {/* <Option value="开票金额">开票金额</Option>
+      <Option value="回款金额">回款金额</Option> */}
+          </Select>
+        </div>
+      }>
       <div className="text-center border border-x-0 mt-2 p-2">{opMap[activeOp]}排行榜</div>
       <div className="">
         <ProTable
@@ -120,7 +124,7 @@ const LeaderBoard = ({ dataList = [] }) => {
           pagination={false}
         />
       </div>
-    </>
+    </Card>
   )
 }
 

+ 142 - 98
src/pages/workbench/Dashboard/index.jsx

@@ -1,7 +1,7 @@
 import React, { useState, useEffect } from 'react'
 import ProTable from '@ant-design/pro-table'
 import { connect, useModel } from 'umi'
-import { Row, Col, Divider, Select } from 'antd'
+import { Row, Col, Select, Card, Skeleton } from 'antd'
 import { AddressBook, City, Finance, Comment } from '@icon-park/react'
 import { DualAxes } from '@ant-design/charts'
 import consts from '@/consts'
@@ -14,6 +14,7 @@ import { cyclicalOp } from './consts'
 const Dashboard = ({ dispatch, groupList = [] }) => {
   const { initialState: { permData } = { permData: {} } } = useModel('@@initialState')
   const [state, setState] = useState({
+    loading: true,
     visible: false,
     reminderData: [],
     leaderboard: [],
@@ -50,17 +51,20 @@ const Dashboard = ({ dispatch, groupList = [] }) => {
       }
     } = await queryDashboard(payload)
     if (code === consts.RET_CODE.SUCCESS) {
-      setState({
-        ...state,
-        reminderData,
-        leaderboard,
-        clientChainRatio,
-        customerChainRatio,
-        businessChainRatio,
-        serviceLogChainRatio,
-        aggregation,
-        businessChar
-      })
+      setTimeout(() => {
+        setState({
+          ...state,
+          loading: false,
+          reminderData,
+          leaderboard,
+          clientChainRatio,
+          customerChainRatio,
+          businessChainRatio,
+          serviceLogChainRatio,
+          aggregation,
+          businessChar
+        })
+      }, 1000)
     }
   }
   useEffect(() => {
@@ -201,11 +205,17 @@ const Dashboard = ({ dispatch, groupList = [] }) => {
       <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>
@@ -226,128 +236,162 @@ const Dashboard = ({ dispatch, groupList = [] }) => {
         </span>
       </div>
       <div className="mt-4">
-        <div className="p-4 bg-white border rounded-lg shadow-card">
-          <Row gutter={16}>
-            <Col className="gutter-row" span={6}>
-              <div className="p-4 bg-white border rounded-lg">
+        <Row gutter={16}>
+          <Col className="gutter-row" span={6}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
                 <Row>
                   <Col span={6}>
                     <div className="w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
-                      {/* <span className="absolute top-9px left-9px"> */}
                       <City size="26" fill="#fff" />
-                      {/* </span> */}
                     </div>
                   </Col>
-                  <Col span={9}>
-                    <h3 className="text-2xl">{state.customerChainRatio.count}</h3>
-                    <span>新增客户</span>
-                  </Col>
-                  <Col span={9} className="text-right">
-                    <h3 className="text-xl text-green-500">
-                      {state.customerChainRatio.percentage}
-                    </h3>
-                    <span>
-                      {cyclicalOp.find(item => item.value === state.params.cyclical)?.title}
-                    </span>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.customerChainRatio.count}</div>
+                      <span className="text-xl text-green-500">
+                        {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 className="gutter-row" span={6}>
-              <div className="p-4 bg-white border rounded-lg shadow-card">
+              )}
+            </div>
+          </Col>
+          <Col className="gutter-row" span={6}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
                 <Row>
                   <Col span={6}>
                     <div className="w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
                       <AddressBook size="26" fill="#fff" />
                     </div>
                   </Col>
-                  <Col span={9}>
-                    <h3 className="text-2xl">{state.clientChainRatio.count}</h3>
-                    <span>新增联系人</span>
-                  </Col>
-                  <Col span={9} className="text-right">
-                    <h3 className="text-xl text-red-500">{state.clientChainRatio.percentage}</h3>
-                    <span>
-                      {cyclicalOp.find(item => item.value === state.params.cyclical)?.title}
-                    </span>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.clientChainRatio.count}</div>
+                      <span className="text-xl text-green-500">
+                        {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 className="gutter-row" span={6}>
-              <div className="p-4 bg-white border rounded-lg">
+              )}
+            </div>
+          </Col>
+          <Col className="gutter-row" span={6}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
                 <Row>
                   <Col span={6}>
                     <div className="w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
                       <Finance size="26" fill="#fff" />
                     </div>
                   </Col>
-                  <Col span={9}>
-                    <h3 className="text-2xl">{state.businessChainRatio.count}</h3>
-                    <span>新增商机</span>
-                  </Col>
-                  <Col span={9} className="text-right">
-                    <h3 className="text-xl text-green-500">
-                      {state.businessChainRatio.percentage}
-                    </h3>
-                    <span>
-                      {cyclicalOp.find(item => item.value === state.params.cyclical)?.title}
-                    </span>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.businessChainRatio.count}</div>
+                      <span className="text-xl text-green-500">
+                        {state.businessChainRatio.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 className="gutter-row" span={6}>
-              <div className="p-4 bg-white border rounded-lg">
+              )}
+            </div>
+          </Col>
+          <Col className="gutter-row" span={6}>
+            <div className="p-4 bg-white border rounded-2px border-hex-f0f0f0">
+              {state.loading ? (
+                <Skeleton active avatar />
+              ) : (
                 <Row>
                   <Col span={6}>
                     <div className="w-48px h-48px border rounded-48px bg-[#0c7cd5] flex items-center justify-center">
                       <Comment size="26" fill="#fff" />
                     </div>
                   </Col>
-                  <Col span={9}>
-                    <h3 className="text-2xl">{state.serviceLogChainRatio.count}</h3>
-                    <span>服务记录</span>
-                  </Col>
-                  <Col span={9} className="text-right">
-                    <h3 className="text-xl text-green-500">
-                      {state.serviceLogChainRatio.percentage}
-                    </h3>
-                    <span>
-                      {cyclicalOp.find(item => item.value === state.params.cyclical)?.title}
-                    </span>
+                  <Col span={18} flex="wrap">
+                    <div className="flex items-center justify-between ">
+                      <div className="text-2xl">{state.serviceLogChainRatio.count}</div>
+                      <span className="text-xl text-green-500">
+                        {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>
+              )}
+            </div>
+          </Col>
+        </Row>
       </div>
       <div className="mt-4">
         <Row gutter={16}>
           <Col className="gutter-row" span={16}>
-            <div className="p-4 bg-white border rounded-lg shadow-card">
-              <div className="relative">
-                <span>销售漏斗</span>
-                <div className="absolute right-1 top-0">
-                  {groupList ? (
-                    <Select
-                      defaultValue={groupList[0]?.value}
-                      options={groupList}
-                      onChange={e =>
-                        setState({ ...state, params: { ...state.params, businessGroupId: e } })
-                      }
-                    />
-                  ) : null}
+            <Card
+              loading={state.loading}
+              bodyStyle={{ minHeight: '230px' }}
+              title={
+                <div className="relative">
+                  <span>销售漏斗</span>
+                  <div className="absolute right-1 top-0">
+                    {groupList ? (
+                      <Select
+                        defaultValue={groupList[0]?.value}
+                        options={groupList}
+                        onChange={e =>
+                          setState({ ...state, params: { ...state.params, businessGroupId: e } })
+                        }
+                      />
+                    ) : null}
+                  </div>
                 </div>
-              </div>
-              <Divider />
+              }>
               {char && thread && <DualAxes {...config} />}
-            </div>
+            </Card>
+            {/* <div className="p-4 bg-white border rounded-lg shadow-card"> */}
+            {/* <Divider /> */}
+            {/* </div> */}
           </Col>
           <Col className="gutter-row" span={8}>
-            <div className="bg-white border rounded-lg shadow-card">
-              <h4 className="px-12px py-16px border-b-1">数据汇总</h4>
+            <Card
+              headStyle={{ padding: '0 12px' }}
+              title="数据汇总"
+              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.customerCount}</b>个,服务
@@ -364,16 +408,16 @@ const Dashboard = ({ dispatch, groupList = [] }) => {
                   条,赢单<b className="px-1">{state.aggregation.businessWinCount}</b>个
                 </li>
               </ul>
-            </div>
+            </Card>
           </Col>
         </Row>
       </div>
       <div className="mt-4">
         <Row gutter={16}>
           <Col className="gutter-row" span={12}>
-            <div className="bg-white border rounded-lg shadow-card">
-              <LeaderBoard dataList={state.leaderboard} />
-            </div>
+            {/* <div className="bg-white border rounded-lg shadow-card"> */}
+            <LeaderBoard dataList={state.leaderboard} loading={state.loading} />
+            {/* </div> */}
           </Col>
         </Row>
       </div>