ソースを参照

feat[数据统计]: 品类统计改成树状结构

chenlei 14 時間 前
コミット
eb63eb0b16
1 ファイル変更61 行追加22 行削除
  1. 61 22
      src/pages/Abench/A1statistics/index.tsx

+ 61 - 22
src/pages/Abench/A1statistics/index.tsx

@@ -1,7 +1,11 @@
-import React, { useCallback, useEffect, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import styles from './index.module.scss'
-import { Button, Select } from 'antd'
+import { Button, Select, TreeSelect } from 'antd'
 import { iconUrl } from '@/utils/http'
+import { useDispatch, useSelector } from 'react-redux'
+import { RootState } from '@/store'
+import { E1_APIgetTree } from '@/store/action/Eculture/E1tag'
+import type { TypeI5Tree } from '@/pages/Isystem/I5organization/data'
 import * as xlsx from 'xlsx'
 import * as echarts from 'echarts'
 import {
@@ -38,11 +42,13 @@ function A1statistics() {
   const [textureTagId, setTextureTagId] = useState<number | null>(null)
   const [textureData, setTextureData] = useState<{ name: string; value: number }[]>([])
 
-  // 品类统计
-  const [categoryOptions, setCategoryOptions] = useState<DictItem[]>([])
-  const [categoryTagId, setCategoryTagId] = useState<number | null>(null)
+  // 品类统计(使用 cms/tag/getTree 树状结构)
+  const [categoryTagId, setCategoryTagId] = useState<string | null>(null)
   const [categoryData, setCategoryData] = useState<{ name: string; value: number }[]>([])
 
+  const dispatch = useDispatch()
+  const categoryTreeData = useSelector((state: RootState) => state.E1tag.treeData)
+
   // 一级/二级分类
   const [level1Data, setLevel1Data] = useState<{ name: string; value: number }[]>([])
   const [level2Data, setLevel2Data] = useState<{ name: string; value: number }[]>([])
@@ -50,6 +56,36 @@ function A1statistics() {
   const textureInitialized = useRef(false)
   const categoryInitialized = useRef(false)
 
+  // 将 TypeI5Tree 转为 TreeSelect 的 treeData 格式
+  const categoryTreeSelectData = useMemo(() => {
+    const convert = (nodes: TypeI5Tree[]): { value: string; label: string; children?: any[] }[] =>
+      nodes.map(node => ({
+        value: node.id,
+        label: node.name,
+        children: node.children?.length ? convert(node.children) : undefined
+      }))
+    return convert(categoryTreeData || [])
+  }, [categoryTreeData])
+
+  // 从树中根据 id 查找 name(用于导出)
+  const getCategoryNameById = useCallback(
+    (id: string | null) => {
+      if (!id) return ''
+      const find = (nodes: TypeI5Tree[]): string | undefined => {
+        for (const n of nodes) {
+          if (n.id === id) return n.name
+          if (n.children?.length) {
+            const found = find(n.children)
+            if (found) return found
+          }
+        }
+        return undefined
+      }
+      return find(categoryTreeData || []) ?? ''
+    },
+    [categoryTreeData]
+  )
+
   // 获取一级/二级分类数据
   useEffect(() => {
     const fetchTagLevel = async () => {
@@ -117,31 +153,36 @@ function A1statistics() {
       })()
     : null
 
-  // 获取筛选字典(材质+品类)
+  // 获取品类树(cms/tag/getTree)
+  useEffect(() => {
+    dispatch(E1_APIgetTree())
+  }, [dispatch])
+
+  // 品类树加载后默认选中第一个
+  useEffect(() => {
+    if (categoryTreeData?.length > 0 && !categoryInitialized.current) {
+      categoryInitialized.current = true
+      setCategoryTagId(categoryTreeData[0].id)
+    }
+  }, [categoryTreeData])
+
+  // 获取筛选字典(材质)
   useEffect(() => {
     const fetchDict = async () => {
       try {
         const res = await A1_APIgetDictById()
         if (res?.code === 0 && res.data) {
           const list3 = res.data.texture || []
-          const list4 = res.data.category || []
           setTextureOptions(list3)
-          setCategoryOptions(list4)
           if (list3.length > 0 && !textureInitialized.current) {
             textureInitialized.current = true
             setTextureTagId(list3[0].id)
           }
-          if (list4.length > 0 && !categoryInitialized.current) {
-            categoryInitialized.current = true
-            setCategoryTagId(list4[0].id)
-          }
         } else {
           setTextureOptions([])
-          setCategoryOptions([])
         }
       } catch {
         setTextureOptions([])
-        setCategoryOptions([])
       }
     }
     fetchDict()
@@ -186,7 +227,7 @@ function A1statistics() {
     }
     const fetch = async () => {
       try {
-        const res = await A1_APIgetDataTagByTagId(categoryTagId)
+        const res = await A1_APIgetDataTagByTagId(Number(categoryTagId))
         if (
           res?.code === 0 &&
           res.data &&
@@ -544,10 +585,7 @@ function A1statistics() {
     if (categorySheetData.length) {
       const ws4 = xlsx.utils.json_to_sheet(categorySheetData)
       ws4['!cols'] = [{ wpx: 60 }, { wpx: 150 }, { wpx: 80 }]
-      const tagName = (categoryOptions.find(c => c.id === categoryTagId)?.name ?? '').replace(
-        /[\\/*?:[\]]/g,
-        ''
-      )
+      const tagName = getCategoryNameById(categoryTagId).replace(/[\\/*?:[\]]/g, '')
       xlsx.utils.book_append_sheet(wb, ws4, tagName ? `品类_${tagName.slice(0, 20)}` : '品类统计')
     }
 
@@ -564,7 +602,7 @@ function A1statistics() {
     textureOptions,
     categoryData,
     categoryTagId,
-    categoryOptions
+    getCategoryNameById
   ])
 
   return (
@@ -662,13 +700,14 @@ function A1statistics() {
           <div className='A1_3row'>
             <div className='A1tit2'>
               <div>品类统计</div>
-              <Select
+              <TreeSelect
                 value={categoryTagId ?? undefined}
                 onChange={v => setCategoryTagId(v ?? null)}
-                options={categoryOptions.map(({ id, name }) => ({ value: id, label: name }))}
+                treeData={categoryTreeSelectData}
                 placeholder='请选择'
                 allowClear
                 style={{ width: 200 }}
+                treeDefaultExpandAll
               />
             </div>
             <div className='A1_3ech' id='echBox4'></div>