Kaynağa Gözat

藏品登记完成一部分

shaogen1995 1 ay önce
ebeveyn
işleme
8926da58a1

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

@@ -22,6 +22,7 @@
     "dayjs": "^1.11.10",
     "echarts": "^6.0.0",
     "js-base64": "^3.7.3",
+    "js-export-excel": "^1.1.4",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-redux": "^8.0.4",

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

@@ -93,7 +93,7 @@ function A0addGoods({ sId, closeFu }: Props) {
         MessageFu.success(sId > 0 ? '修改成功' : '登记成功')
         if (sId > 0) {
           // 待完善
-        } else history.push('/register/look')
+        } else history.push(`/register_look/1/${res.data.id}`)
       }
     },
     [sId]

+ 4 - 0
后台管理/src/pages/A0goodsInfo/index.module.scss

@@ -0,0 +1,4 @@
+.A0goodsInfo {
+  :global {
+  }
+}

+ 13 - 0
后台管理/src/pages/A0goodsInfo/index.tsx

@@ -0,0 +1,13 @@
+import React from 'react'
+import styles from './index.module.scss'
+function A0goodsInfo() {
+  return (
+    <div className={styles.A0goodsInfo}>
+      <h1>A0goodsInfo</h1>
+    </div>
+  )
+}
+
+const MemoA0goodsInfo = React.memo(A0goodsInfo)
+
+export default MemoA0goodsInfo

+ 8 - 2
后台管理/src/pages/B1ledger/data.ts

@@ -1,5 +1,5 @@
 export type B1fromDataType = {
-  name: string
+  searchkey: string
   typeDictId: null | number
   textureDictId: null | number
   pageNum: number
@@ -7,7 +7,7 @@ export type B1fromDataType = {
 }
 
 export const B1fromDataBase: B1fromDataType = {
-  name: '',
+  searchkey: '',
   typeDictId: null,
   textureDictId: null,
   pageNum: 1,
@@ -22,4 +22,10 @@ export type B1listType = {
   num: string
   status: number
   updateTime: string
+  inHouseTime?: string
+  registerTime?: string
+  typeDictId?: number
+  textureDictId?: number
+  pcs?: number
+  pcsUnitDictId?: number
 }

+ 0 - 3
后台管理/src/pages/B1ledger/index.module.scss

@@ -9,9 +9,6 @@
       margin-bottom: 15px;
       .B1topll {
         display: flex;
-        .ant-select-selection-placeholder {
-          color: black;
-        }
       }
     }
     .ant-table-cell {

+ 10 - 5
后台管理/src/pages/B1ledger/index.tsx

@@ -9,8 +9,11 @@ import MyTable from '@/components/MyTable'
 import { RootState } from '@/store'
 import A0addGoods from '../A0addGoods'
 import { B1tableC } from '@/utils/tableData'
+import { B1devFu } from '@/utils/deriveFu'
+import history from '@/utils/history'
+
 function B1ledger() {
-  // 待完善
+  // 待完善 表格/导出 入库时间 出库时间 当前位置相关
   const dispatch = useDispatch()
   const [formData, setFormData] = useState(B1fromDataBase)
 
@@ -25,7 +28,7 @@ function B1ledger() {
   // 输入框改变
   const timeRef = useRef(-1)
   const txtChangeFu = useCallback(
-    (e: React.ChangeEvent<HTMLInputElement>, key: 'name') => {
+    (e: React.ChangeEvent<HTMLInputElement>, key: 'searchkey') => {
       clearTimeout(timeRef.current)
       timeRef.current = window.setTimeout(() => {
         setFormData({
@@ -55,7 +58,7 @@ function B1ledger() {
         title: '操作',
         render: (item: B1listType) => {
           return (
-            <Button size='small' type='text'>
+            <Button size='small' type='text' onClick={() => history.push(`/goodsLook/${item.id}`)}>
               查看
             </Button>
           )
@@ -87,7 +90,7 @@ function B1ledger() {
             showCount
             key={inputKey}
             allowClear
-            onChange={e => txtChangeFu(e, 'name')}
+            onChange={e => txtChangeFu(e, 'searchkey')}
             style={{ width: 300 }}
           />
           &emsp;
@@ -115,7 +118,9 @@ function B1ledger() {
           </Button>
           &emsp;
           <Button onClick={resetSelectFu}>重置</Button>&emsp;
-          <Button type='primary'>数据导出</Button>
+          <Button type='primary' onClick={() => B1devFu(formData)}>
+            数据导出
+          </Button>
         </div>
       </div>
 

+ 4 - 0
后台管理/src/pages/B2register/B2look/index.module.scss

@@ -0,0 +1,4 @@
+.B2look {
+  :global {
+  }
+}

+ 21 - 0
后台管理/src/pages/B2register/B2look/index.tsx

@@ -0,0 +1,21 @@
+import React, { useEffect } from 'react'
+import styles from './index.module.scss'
+import { useParams } from 'react-router-dom'
+
+function B2look() {
+  const { key, id } = useParams<any>()
+
+  useEffect(() => {
+    console.log(key, id)
+  }, [id, key])
+
+  return (
+    <div className={styles.B2look}>
+      <div className='pageTitle'>藏品登记 - {key === '1' ? '查看' : '审批'}</div>
+    </div>
+  )
+}
+
+const MemoB2look = React.memo(B2look)
+
+export default MemoB2look

+ 20 - 1
后台管理/src/pages/Layout/data.ts

@@ -1,4 +1,4 @@
-import { RouterType } from '@/types'
+import { RouterType, RouterTypeRow } from '@/types'
 import React from 'react'
 
 const tabLeftArr: RouterType = [
@@ -117,9 +117,28 @@ const tabLeftArr: RouterType = [
         name: '系统日志',
         path: '/log',
         Com: React.lazy(() => import('../Z2log'))
+      },
+      // 不需要 高亮的 详情页
+      {
+        id: 9901,
+        name: '藏品详情',
+        path: '/goodsLook/:id',
+        pathLast: '/goodsLook',
+        Com: React.lazy(() => import('../A0goodsInfo'))
       }
     ]
   }
 ]
 
 export default tabLeftArr
+
+// 里面的页面,不是左边的tab栏
+export const routerSon: RouterTypeRow = [
+  // 藏品登记-查看
+  {
+    id: 1,
+    name: '藏品登记-查看',
+    path: '/register_look/:key/:id',
+    Com: React.lazy(() => import('../B2register/B2look'))
+  }
+]

+ 40 - 7
后台管理/src/pages/Layout/index.tsx

@@ -14,7 +14,7 @@ import { MessageFu } from '@/utils/message'
 import NotFound from '@/components/NotFound'
 import classNames from 'classnames'
 import { RouterType, RouterTypeRow } from '@/types'
-import tabLeftArr from './data'
+import tabLeftArr, { routerSon } from './data'
 import MyPopconfirm from '@/components/MyPopconfirm'
 import { useDispatch } from 'react-redux'
 import { D1_APIgetlist } from '@/store/action/D1dict'
@@ -57,7 +57,7 @@ function Layout() {
     const res = await D3_APIgetInfo(userInfo.roleId)
 
     if (res.code === 0) {
-      const isOkIdArr: number[] = []
+      const isOkIdArr: number[] = [9901]
 
       const roleArr: any[] = res.data.permission
 
@@ -89,10 +89,23 @@ function Layout() {
       // 如果当前页面没有权限了,跳转有权限的第一个页面
       const urlAll = window.location.hash
       const isNowPath = urlAll.replace('#', '')
-      const pathArr = tempArr.map(v => v.path)
-      if (!pathArr.includes(isNowPath)) {
-        history.push(pathArr[0])
-      }
+      const pathArr = tempArr.map(v => v.pathLast || v.path)
+
+      const routerSonArr = routerSon.map(v => v.path)
+
+      const lastArr = [...pathArr, ...routerSonArr]
+
+      let flagPush = true
+
+      lastArr.forEach(v => {
+        if (v === '/') {
+          if (isNowPath === '/') flagPush = false
+        } else {
+          if (isNowPath.includes(v)) flagPush = false
+        }
+      })
+
+      if (flagPush) history.push(pathArr[0])
 
       const resList = tabLeftArr.map(v => ({
         ...v,
@@ -156,6 +169,20 @@ function Layout() {
   // 点击用户 出来 退出登录 修改密码
   const [isUserBtnShow, setIsUserBtnShow] = useState(false)
 
+  // path的高亮判断
+  const pathAcFu = useCallback(
+    (url: string) => {
+      let flag = false
+      if (url === '/') {
+        if (path.includes('/_') || path === '/') flag = true
+      } else {
+        if (path.includes(url)) flag = true
+      }
+      return flag
+    },
+    [path]
+  )
+
   return (
     <div className={styles.Layout}>
       {/* 左边 */}
@@ -171,7 +198,8 @@ function Layout() {
               {v.son.map(v2 => (
                 <div
                   key={v2.id}
-                  className={classNames('layoutLRowBoxRow', path === v2.path ? 'active' : '')}
+                  hidden={v2.id >= 9901}
+                  className={classNames('layoutLRowBoxRow', pathAcFu(v2.path) ? 'active' : '')}
                   onClick={() => pathCutFu(v2.path)}
                 >
                   {v2.name}
@@ -216,6 +244,11 @@ function Layout() {
                     <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
                   ))}
 
+                  {/* 非tab栏页面 */}
+                  {routerSon.map(v => (
+                    <AuthRoute key={v.id} exact path={v.path} component={v.Com} />
+                  ))}
+
                   <Route path='*' component={NotFound} />
                 </Switch>
               </React.Suspense>

+ 12 - 9
后台管理/src/store/action/B1ledger.ts

@@ -3,16 +3,19 @@ import { AppDispatch } from '..'
 /**
  * 藏品总账-获取列表
  */
-export const B1_APIgetlist = (data: any): any => {
-  return async (dispatch: AppDispatch) => {
-    const res = await http.post('cms/goods/page', data)
-    if (res.code === 0) {
-      const obj = {
-        list: res.data.records,
-        total: res.data.total
-      }
+export const B1_APIgetlist = (data: any, exportFlag?: boolean): any => {
+  if (exportFlag) return http.post('cms/goods/page', data)
+  else {
+    return async (dispatch: AppDispatch) => {
+      const res = await http.post('cms/goods/page', data)
+      if (res.code === 0) {
+        const obj = {
+          list: res.data.records,
+          total: res.data.total
+        }
 
-      dispatch({ type: 'B1/getList', payload: obj })
+        dispatch({ type: 'B1/getList', payload: obj })
+      }
     }
   }
 }

+ 19 - 18
后台管理/src/types/api/layot.d.ts

@@ -1,25 +1,26 @@
 export type LookDomType = {
-  src: string;
-  type: "video" | "audio" | "model" | "";
-  flag?: boolean;
-};
+  src: string
+  type: 'video' | 'audio' | 'model' | ''
+  flag?: boolean
+}
 
 export type RouterTypeRow = {
-  id: number;
-  name: string;
-  path: string;
-  Com: React.LazyExoticComponent<React.MemoExoticComponent<() => JSX.Element>>;
-}[];
+  id: number
+  name: string
+  path: string
+  pathLast?: string
+  Com: React.LazyExoticComponent<React.MemoExoticComponent<() => JSX.Element>>
+}[]
 
 export type RouterType = {
-  id: number;
-  name: string;
-  son: RouterTypeRow;
-}[];
+  id: number
+  name: string
+  son: RouterTypeRow
+}[]
 
 export type FileImgListType = {
-  id: number;
-  fileName: string;
-  filePath: string;
-  type: "img" | "video" | "doc";
-};
+  id: number
+  fileName: string
+  filePath: string
+  type: 'img' | 'video' | 'doc'
+}

+ 120 - 0
后台管理/src/utils/deriveFu.ts

@@ -0,0 +1,120 @@
+// 导出相关
+import ExportJsonExcel from 'js-export-excel'
+import { B1_APIgetlist } from '@/store/action/B1ledger'
+import { MessageFu } from './message'
+import dayjs from 'dayjs'
+import { dictSelect } from './select'
+
+// 入口
+const devDownFu = (
+  sheetData: any[],
+  nameTemp: string,
+  sheetFilter: string[],
+  sheetHeader: string[]
+) => {
+  const name = nameTemp + dayjs(new Date()).format('YYYY-MM-DD HH:mm')
+
+  const option = {
+    fileName: name,
+    datas: [
+      {
+        sheetData,
+        sheetName: name,
+        sheetFilter,
+        sheetHeader,
+        columnWidths: sheetFilter.map(v => 10)
+      }
+    ]
+  }
+
+  const toExcel = new ExportJsonExcel(option) //new
+  toExcel.saveExcel() //保存
+}
+
+// 日期处理
+const timeChange = (val?: string) => {
+  return val ? dayjs(val).format('YYYY-MM-DD') : '(空)'
+}
+
+// 下拉框处理
+const selectChange = (data: any[], val?: number) => {
+  let txt = '(空)'
+  if (val) {
+    const obj = data.find(v => v.value === val)
+    if (obj) txt = obj.label
+  }
+  return txt
+}
+
+// 数量处理
+const pcsPingFu = (data: any[], val1?: number, val2?: number) => {
+  let txt = '(空)'
+  if (val1) {
+    txt = val1 + ''
+    if (val2) {
+      const txt2 = selectChange(data, val2)
+      if (txt2 !== '(空)') txt += txt2
+    }
+  }
+  return txt
+}
+
+const dataChange = (key: string, val: any, val2?: any) => {
+  if (['inHouseTime', 'registerTime'].includes(key)) return timeChange(val)
+  else if (['typeDictId'].includes(key)) return selectChange(dictSelect('藏品类型'), val)
+  else if (['textureDictId'].includes(key)) return selectChange(dictSelect('藏品材质'), val)
+  else if (['pcs'].includes(key)) return pcsPingFu(dictSelect('数量单位'), val, val2)
+  else return val
+}
+
+// ------------------藏品登记
+export const B1devFu = async (formData: any) => {
+  const res = await B1_APIgetlist({ ...formData, pageNum: 1, pageSize: 99999 }, true)
+  if (res.code === 0) {
+    let data: any[] = res.data.records || []
+
+    if (data.length <= 0) return MessageFu.warning('当前搜索条件没有数据')
+
+    const arr1 = [
+      'num',
+      'name',
+      'inHouseTime',
+      'registerTime',
+      '待完善',
+      '待完善',
+      'typeDictId',
+      'textureDictId',
+      '待完善',
+      'pcs',
+      'isNote'
+    ]
+
+    const arr2 = [
+      '藏品编号',
+      '藏品标题',
+      '入馆时间',
+      '登记时间',
+      '入库时间',
+      '出库时间',
+      '类型',
+      '材质',
+      '当前位置',
+      '数量',
+      '有无说明牌'
+    ]
+
+    data.forEach(v => {
+      let val2: any = undefined
+
+      arr1.forEach(c => {
+        if (v[c]) {
+          if (c === 'pcs') val2 = v.pcsUnitDictId
+          else val2 = undefined
+          v[c] = dataChange(c, v[c], val2)
+        } else v[c] = '(空)'
+      })
+    })
+
+    devDownFu(data, '藏品总账', arr1, arr2)
+  }
+}

+ 0 - 1
后台管理/src/utils/tableData.ts

@@ -20,7 +20,6 @@ export const B1tableC = [
   ['txt', '藏品编号', 'num'],
   ['txt', '藏品标题', 'name'],
   ['img', '封面图', 'thumb'],
-
   ['time', '入馆时间', 'inHouseTime'],
   ['time', '登记时间', 'registerTime'],
   ['time', '入库时间', '待完善'],

+ 123 - 0
后台管理/yarn.lock

@@ -2830,6 +2830,19 @@ adjust-sourcemap-loader@^4.0.0:
     loader-utils "^2.0.0"
     regex-parser "^2.2.11"
 
+adler-32@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.npmmirror.com/adler-32/-/adler-32-1.2.0.tgz#6a3e6bf0a63900ba15652808cb15c6813d1a5f25"
+  integrity sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==
+  dependencies:
+    exit-on-epipe "~1.0.1"
+    printj "~1.1.0"
+
+adler-32@~1.3.0:
+  version "1.3.1"
+  resolved "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz#1dbf0b36dda0012189a32b3679061932df1821e2"
+  integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==
+
 agent-base@6:
   version "6.0.2"
   resolved "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
@@ -3422,6 +3435,11 @@ binary-extensions@^2.0.0:
   resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
   integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
 
+blob.js@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/blob.js/-/blob.js-1.0.1.tgz#547b449b252c855313e837b53d15b41d000ea1d2"
+  integrity sha512-TkPuWPeCHBbN+LWFg7BlXdSh6stRxwmAbuirKfiiHTMmo/uQfKFQMx2jrxVUkueKRiG+Tc7Os1Zn618Yc0MZpg==
+
 bluebird@^3.7.2:
   version "3.7.2"
   resolved "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
@@ -3614,6 +3632,14 @@ 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:
+  version "1.2.2"
+  resolved "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz#94e687628c700e5155436dac05f74e08df23bc44"
+  integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==
+  dependencies:
+    adler-32 "~1.3.0"
+    crc-32 "~1.2.0"
+
 chalk@^2.4.1, chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -3724,6 +3750,14 @@ coa@^2.0.2:
     chalk "^2.4.1"
     q "^1.1.2"
 
+codepage@~1.14.0:
+  version "1.14.0"
+  resolved "https://registry.npmmirror.com/codepage/-/codepage-1.14.0.tgz#8cbe25481323559d7d307571b0fff91e7a1d2f99"
+  integrity sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==
+  dependencies:
+    commander "~2.14.1"
+    exit-on-epipe "~1.0.1"
+
 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"
@@ -3790,6 +3824,16 @@ commander@^8.3.0:
   resolved "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
   integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
 
+commander@~2.14.1:
+  version "2.14.1"
+  resolved "https://registry.npmmirror.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
+  integrity sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==
+
+commander@~2.17.1:
+  version "2.17.1"
+  resolved "https://registry.npmmirror.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+  integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
 common-path-prefix@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmmirror.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0"
@@ -3933,6 +3977,11 @@ cosmiconfig@^7.0.0:
     path-type "^4.0.0"
     yaml "^1.10.0"
 
+crc-32@~1.2.0:
+  version "1.2.2"
+  resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff"
+  integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==
+
 cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -5043,6 +5092,11 @@ execa@^5.0.0:
     signal-exit "^3.0.3"
     strip-final-newline "^2.0.0"
 
+exit-on-epipe@~1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
+  integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
+
 exit@^0.1.2:
   version "0.1.2"
   resolved "https://registry.npmmirror.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -5181,6 +5235,11 @@ file-loader@^6.2.0:
     loader-utils "^2.0.0"
     schema-utils "^3.0.0"
 
+file-saver@^1.3.3:
+  version "1.3.8"
+  resolved "https://registry.npmmirror.com/file-saver/-/file-saver-1.3.8.tgz#e68a30c7cb044e2fb362b428469feb291c2e09d8"
+  integrity sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg==
+
 filelist@^1.0.4:
   version "1.0.4"
   resolved "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
@@ -5321,6 +5380,11 @@ forwarded@0.2.0:
   resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
   integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
 
+frac@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
+  integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==
+
 fraction.js@^4.3.7:
   version "4.3.7"
   resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
@@ -6799,6 +6863,16 @@ js-cookie@^2.x.x:
   resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
   integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
 
+js-export-excel@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.npmmirror.com/js-export-excel/-/js-export-excel-1.1.4.tgz#65ebeb278010f301bee26bba909d7ffec7f28877"
+  integrity sha512-19m7e3Gnn4CRfHXoFrLYj4fFfJ/KpvI7HRRn25p4GXYD+AlTV+1oU24NH6S904Ksi44tSx7futxhouOPAQ22oQ==
+  dependencies:
+    blob.js "^1.0.1"
+    file-saver "^1.3.3"
+    script-loader "0.7.2"
+    xlsx "0.16.3"
+
 "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -8373,6 +8447,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
     ansi-styles "^5.0.0"
     react-is "^18.0.0"
 
+printj@~1.1.0:
+  version "1.1.2"
+  resolved "https://registry.npmmirror.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
+  integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
+
 process-nextick-args@~2.0.0:
   version "2.0.1"
   resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -8488,6 +8567,11 @@ raw-body@2.5.1:
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
+raw-loader@~0.5.1:
+  version "0.5.1"
+  resolved "https://registry.npmmirror.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa"
+  integrity sha512-sf7oGoLuaYAScB4VGr0tzetsYlS8EJH6qnTCfQ/WVEa89hALQ4RQfCKt5xCyPQKPDUbVUAIP1QsxAwfAjlDp7Q==
+
 rc-cascader@~3.21.2:
   version "3.21.2"
   resolved "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.21.2.tgz#3421841131cdc15157201fefd955da31f409ac85"
@@ -9439,6 +9523,13 @@ screenfull@^5.0.0:
   resolved "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
   integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
 
+script-loader@0.7.2:
+  version "0.7.2"
+  resolved "https://registry.npmmirror.com/script-loader/-/script-loader-0.7.2.tgz#2016db6f86f25f5cf56da38915d83378bb166ba7"
+  integrity sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==
+  dependencies:
+    raw-loader "~0.5.1"
+
 scroll-into-view-if-needed@^3.1.0:
   version "3.1.0"
   resolved "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f"
@@ -9707,6 +9798,13 @@ sprintf-js@~1.0.2:
   resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
   integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
 
+ssf@~0.11.2:
+  version "0.11.2"
+  resolved "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz#0b99698b237548d088fc43cdf2b70c1a7512c06c"
+  integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==
+  dependencies:
+    frac "~1.1.2"
+
 stable@^0.1.8:
   version "0.1.8"
   resolved "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
@@ -10799,11 +10897,21 @@ which@^2.0.1:
   dependencies:
     isexe "^2.0.0"
 
+wmf@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz#7d19d621071a08c2bdc6b7e688a9c435298cc2da"
+  integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==
+
 word-wrap@~1.2.3:
   version "1.2.5"
   resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
   integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
 
+word@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.npmmirror.com/word/-/word-0.3.0.tgz#8542157e4f8e849f4a363a288992d47612db9961"
+  integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==
+
 workbox-background-sync@6.6.1:
   version "6.6.1"
   resolved "https://registry.npmmirror.com/workbox-background-sync/-/workbox-background-sync-6.6.1.tgz#08d603a33717ce663e718c30cc336f74909aff2f"
@@ -11025,6 +11133,21 @@ ws@^8.13.0:
   resolved "https://registry.npmmirror.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4"
   integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==
 
+xlsx@0.16.3:
+  version "0.16.3"
+  resolved "https://registry.npmmirror.com/xlsx/-/xlsx-0.16.3.tgz#7a91a75eb939db4961122da6f949b8a8f0c8af1a"
+  integrity sha512-LInZ1OK6vpe+Em8XDZ5gDH3WixARwxI7UWc+3chLeafI6gUwECEgL43k4Tjbs1uRfkxpM7wQFy5DLE0hFBRqRw==
+  dependencies:
+    adler-32 "~1.2.0"
+    cfb "^1.1.4"
+    codepage "~1.14.0"
+    commander "~2.17.1"
+    crc-32 "~1.2.0"
+    exit-on-epipe "~1.0.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"