shaogen1995 1 miesiąc temu
rodzic
commit
7ac8229f04

+ 3 - 1
后台管理/package.json

@@ -21,6 +21,7 @@
     "braft-utils": "^3.0.12",
     "dayjs": "^1.11.10",
     "echarts": "^6.0.0",
+    "file-saver": "^2.0.5",
     "js-base64": "^3.7.3",
     "js-export-excel": "^1.1.4",
     "react": "^18.2.0",
@@ -34,7 +35,8 @@
     "redux-thunk": "^2.4.1",
     "sass": "^1.55.0",
     "typescript": "^4.8.4",
-    "web-vitals": "^2.1.4"
+    "web-vitals": "^2.1.4",
+    "xlsx": "^0.18.5"
   },
   "scripts": {
     "dev": "react-app-rewired start",

+ 14 - 0
后台管理/src/pages/A2statistics/data.ts

@@ -0,0 +1,14 @@
+export type A2dataSonType = {
+  name: string
+  value: number
+}
+
+export type A2data2Type = {
+  name: string
+  son: A2dataSonType[]
+}
+
+export type A2dataType = {
+  total: number
+  data: A2data2Type[]
+}

+ 78 - 0
后台管理/src/pages/A2statistics/index.module.scss

@@ -1,4 +1,82 @@
 .A2statistics {
+  background-color: #fff;
+  border-radius: 10px;
+  padding: 20px;
+  font-size: 16px;
   :global {
+    .A2top {
+      display: flex;
+      justify-content: space-between;
+      margin-bottom: 25px;
+    }
+    .A2main {
+      width: 94%;
+      height: calc(100% - 50px);
+      overflow: auto;
+      padding-right: 20px;
+      .A2Row {
+        display: flex;
+        text-align: center;
+        // border: 1px solid #ccc;
+        .A2Row1 {
+          font-weight: 700;
+          text-align: center;
+          width: 700px;
+          border: 1px solid #ccc;
+          border-bottom: none;
+          border-right: none;
+          padding: 8px 0;
+        }
+        .A2Row2 {
+          padding: 8px 0;
+          width: calc(100% - 700px);
+          border: 1px solid #ccc;
+          border-bottom: none;
+        }
+        .A2Row2Ac {
+          font-weight: 700;
+
+          color: var(--themeColor);
+          cursor: pointer;
+        }
+      }
+
+      .A2son {
+        display: flex;
+        text-align: center;
+        flex-wrap: wrap;
+        .A2sonll {
+          width: 350px;
+          padding: 8px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          border: 1px solid #ccc;
+          border-bottom: none;
+          font-weight: 700;
+        }
+        .A2sonrrBox {
+          width: calc(100% - 350px);
+          .A2sonrr {
+            display: flex;
+            .A2sonrr1 {
+              padding: 8px;
+              width: 350px;
+              border-top: 1px solid #ccc;
+              font-weight: 700;
+            }
+            .A2sonrr2 {
+              border: 1px solid #ccc;
+              border-bottom: none;
+              padding: 8px;
+              width: calc(100% - 350px);
+            }
+          }
+        }
+        &:last-child {
+          border-bottom: 1px solid #ccc;
+        }
+      }
+    }
   }
 }

+ 113 - 1
后台管理/src/pages/A2statistics/index.tsx

@@ -1,9 +1,121 @@
-import React from 'react'
+import React, { useCallback, useEffect } from 'react'
 import styles from './index.module.scss'
+import { useDispatch, useSelector } from 'react-redux'
+import { A2_APIgetlist } from '@/store/action/A2statistics'
+import { Button } from 'antd'
+import { RootState } from '@/store'
+import { authorityFu } from '@/utils/authority'
+import history from '@/utils/history'
+
+import * as XLSX from 'xlsx'
+import { saveAs } from 'file-saver'
+import { MessageFu } from '@/utils/message'
+import dayjs from 'dayjs'
+
 function A2statistics() {
+  const dispatch = useDispatch()
+
+  const getListFu = useCallback(() => {
+    dispatch(A2_APIgetlist())
+  }, [dispatch])
+
+  useEffect(() => {
+    getListFu()
+  }, [getListFu])
+
+  const info = useSelector((state: RootState) => state.A2statistics.info)
+
+  // 导出表格函数
+  const exportToExcel = useCallback(() => {
+    if (!info.total || !info.data.length) {
+      MessageFu.warning('暂无数据可导出')
+      return
+    }
+
+    try {
+      // 准备数据
+      const worksheetData = [
+        ['分类', '子分类', '数量'], // 表头
+        ['藏品总账数量', '', info.total || 0] // 总账数量
+      ]
+
+      // 添加分类数据
+      info.data.forEach(item => {
+        item.son.forEach((son, index) => {
+          worksheetData.push([
+            index === 0 ? item.name : '', // 只有第一行显示分类名
+            son.name,
+            son.value
+          ])
+        })
+      })
+
+      // 创建工作簿和工作表
+      const workbook = XLSX.utils.book_new()
+      const worksheet = XLSX.utils.aoa_to_sheet(worksheetData)
+
+      // 设置列宽
+      const colWidth = [
+        { wch: 15 }, // 分类列
+        { wch: 25 }, // 子分类列
+        { wch: 10 } // 数量列
+      ]
+      worksheet['!cols'] = colWidth
+
+      // 添加工作表到工作簿
+      XLSX.utils.book_append_sheet(workbook, worksheet, '数据统计')
+
+      // 导出文件
+      const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' })
+      const data = new Blob([excelBuffer], { type: 'application/octet-stream' })
+      saveAs(data, `数据统计_${dayjs(new Date()).format('YYYY-MM-DD HH:mm')}.xlsx`)
+    } catch (error) {
+      MessageFu.error('导出失败')
+      console.error('导出错误:', error)
+    }
+  }, [info.data, info.total])
+
   return (
     <div className={styles.A2statistics}>
       <div className='pageTitle'>数据统计</div>
+
+      <div className='A2top'>
+        数量统计以藏品总账中的藏品数据(包括已登记/修改中/删除中)为准
+        <Button type='primary' onClick={exportToExcel}>
+          导出表格
+        </Button>
+      </div>
+
+      <div className='A2main'>
+        <div className='A2Row'>
+          <div className='A2Row1'>藏品总账数量</div>
+          <div
+            className='A2Row2 A2Row2Ac'
+            onClick={() => {
+              authorityFu(300, '您没有藏品总账页面权限', () => {
+                history.push('/ledger')
+              })
+            }}
+          >
+            {info.total}
+          </div>
+        </div>
+
+        {info.data.map(item => (
+          <div className='A2son' key={item.name}>
+            <div className='A2sonll'>{item.name}</div>
+
+            <div className='A2sonrrBox'>
+              {item.son.map(son => (
+                <div className='A2sonrr' key={son.name}>
+                  <div className='A2sonrr1'>{son.name}</div>
+                  <div className='A2sonrr2'>{son.value}</div>
+                </div>
+              ))}
+            </div>
+          </div>
+        ))}
+      </div>
     </div>
   )
 }

+ 46 - 0
后台管理/src/store/action/A2statistics.ts

@@ -0,0 +1,46 @@
+import http from '@/utils/http'
+import store, { AppDispatch } from '..'
+import { A2dataSonType, A2dataType } from '@/pages/A2statistics/data'
+import { D1listType } from '@/pages/D1dict/data'
+/**
+ * 数据统计-获取数据
+ */
+export const A2_APIgetlist = (): any => {
+  return async (dispatch: AppDispatch) => {
+    const res = await http.get('cms/bench/count')
+    if (res.code === 0) {
+      // 获取完整字典数据
+      const dictArrAll = store.getState().D1dict.list
+
+      const dictArr: D1listType[] = []
+
+      dictArrAll.forEach(v => {
+        if (v.children && v.children.length) {
+          v.children.forEach(v2 => {
+            dictArr.push(v2)
+          })
+        }
+      })
+
+      const objAll = res.data
+
+      const obj = { total: 0, data: [] } as A2dataType
+
+      for (const k in objAll) {
+        if (k === 'total') obj.total = objAll[k]
+        else {
+          const objSon = objAll[k]
+          const arrSon: A2dataSonType[] = []
+          for (const k2 in objSon) {
+            const objName = dictArr.find(v => v.id === k2)
+
+            arrSon.push({ name: objName ? objName.name : k2, value: objSon[k2] })
+          }
+          obj.data.push({ name: k, son: arrSon })
+        }
+      }
+
+      dispatch({ type: 'A2/getInfo', payload: obj })
+    }
+  }
+}

+ 25 - 0
后台管理/src/store/reducer/A2statistics.ts

@@ -0,0 +1,25 @@
+import { A2dataType } from '@/pages/A2statistics/data'
+
+// 初始化状态
+const initState = {
+  // 数据
+  info: { total: 0, data: [] } as A2dataType
+}
+
+// 定义 action 类型
+type Props = {
+  type: 'A2/getInfo'
+  payload: A2dataType
+}
+
+// reducer
+export default function userReducer(state = initState, action: Props) {
+  switch (action.type) {
+    // 获取列表数据
+    case 'A2/getInfo':
+      return { ...state, info: action.payload }
+
+    default:
+      return state
+  }
+}

+ 2 - 0
后台管理/src/store/reducer/index.ts

@@ -3,6 +3,7 @@ import { combineReducers } from 'redux'
 
 // 导入 登录 模块的 reducer
 import A0Layout from './layout'
+import A2statistics from './A2statistics'
 import B1ledger from './B1ledger'
 import B2register from './B2register'
 import B3edit from './B3edit'
@@ -20,6 +21,7 @@ import Z2log from './Z2log'
 // 合并 reducer
 const rootReducer = combineReducers({
   A0Layout,
+  A2statistics,
   B1ledger,
   B2register,
   B3edit,

+ 1 - 0
后台管理/src/types/declaration.d.ts

@@ -6,3 +6,4 @@ declare module '*.gif'
 declare module '*.svg'
 declare module 'js-export-excel'
 declare module 'braft-utils'
+declare module 'file-saver'

+ 25 - 2
后台管理/yarn.lock

@@ -3632,7 +3632,7 @@ case-sensitive-paths-webpack-plugin@^2.4.0:
   resolved "https://registry.npmmirror.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
   integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
 
-cfb@^1.1.4:
+cfb@^1.1.4, cfb@~1.2.1:
   version "1.2.2"
   resolved "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
   integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
@@ -3758,6 +3758,11 @@ codepage@~1.14.0:
     commander "~2.14.1"
     exit-on-epipe "~1.0.1"
 
+codepage@~1.15.0:
+  version "1.15.0"
+  resolved "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz#2e00519024b39424ec66eeb3ec07227e692618ab"
+  integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==
+
 collect-v8-coverage@^1.0.0:
   version "1.0.2"
   resolved "https://registry.npmmirror.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
@@ -3977,7 +3982,7 @@ cosmiconfig@^7.0.0:
     path-type "^4.0.0"
     yaml "^1.10.0"
 
-crc-32@~1.2.0:
+crc-32@~1.2.0, crc-32@~1.2.1:
   version "1.2.2"
   resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
   integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
@@ -5240,6 +5245,11 @@ file-saver@^1.3.3:
   resolved "https://registry.npmmirror.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
   integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==
 
+file-saver@^2.0.5:
+  version "2.0.5"
+  resolved "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
+  integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
+
 filelist@^1.0.4:
   version "1.0.4"
   resolved "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
@@ -11148,6 +11158,19 @@ xlsx@0.16.3:
     wmf "~1.0.1"
     word "~0.3.0"
 
+xlsx@^0.18.5:
+  version "0.18.5"
+  resolved "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz#16711b9113c848076b8a177022799ad356eba7d0"
+  integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==
+  dependencies:
+    adler-32 "~1.3.0"
+    cfb "~1.2.1"
+    codepage "~1.15.0"
+    crc-32 "~1.2.1"
+    ssf "~0.11.2"
+    wmf "~1.0.1"
+    word "~0.3.0"
+
 xml-name-validator@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"