|
|
@@ -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>
|