|
@@ -1,7 +1,8 @@
|
|
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
|
import styles from './index.module.scss'
|
|
import styles from './index.module.scss'
|
|
|
-import { Select } from 'antd'
|
|
|
|
|
|
|
+import { Button, Select } from 'antd'
|
|
|
import { iconUrl } from '@/utils/http'
|
|
import { iconUrl } from '@/utils/http'
|
|
|
|
|
+import * as xlsx from 'xlsx'
|
|
|
import * as echarts from 'echarts'
|
|
import * as echarts from 'echarts'
|
|
|
import {
|
|
import {
|
|
|
A1_APIworkCount,
|
|
A1_APIworkCount,
|
|
@@ -23,7 +24,6 @@ const DEFAULT_COLORS = ['#c11b2d', '#243220', '#24664b', '#8acfb2', '#806e4c', '
|
|
|
|
|
|
|
|
// 先写一些静态的
|
|
// 先写一些静态的
|
|
|
type DictItem = { name: string; id: number }
|
|
type DictItem = { name: string; id: number }
|
|
|
-type TextureItem = { name: string; id: number; count: number }
|
|
|
|
|
type TotalItem = { pcs: number | null; level: string | null }
|
|
type TotalItem = { pcs: number | null; level: string | null }
|
|
|
|
|
|
|
|
function A1statistics() {
|
|
function A1statistics() {
|
|
@@ -156,9 +156,17 @@ function A1statistics() {
|
|
|
const fetch = async () => {
|
|
const fetch = async () => {
|
|
|
try {
|
|
try {
|
|
|
const res = await A1_APIgetDataTextureByTagId(textureTagId)
|
|
const res = await A1_APIgetDataTextureByTagId(textureTagId)
|
|
|
- if (res?.code === 0 && Array.isArray(res.data)) {
|
|
|
|
|
|
|
+ if (
|
|
|
|
|
+ res?.code === 0 &&
|
|
|
|
|
+ res.data &&
|
|
|
|
|
+ typeof res.data === 'object' &&
|
|
|
|
|
+ !Array.isArray(res.data)
|
|
|
|
|
+ ) {
|
|
|
setTextureData(
|
|
setTextureData(
|
|
|
- (res.data as TextureItem[]).map(({ name, count }) => ({ name, value: count }))
|
|
|
|
|
|
|
+ Object.entries(res.data as Record<string, number>).map(([name, value]) => ({
|
|
|
|
|
+ name,
|
|
|
|
|
+ value
|
|
|
|
|
+ }))
|
|
|
)
|
|
)
|
|
|
} else {
|
|
} else {
|
|
|
setTextureData([])
|
|
setTextureData([])
|
|
@@ -179,9 +187,17 @@ function A1statistics() {
|
|
|
const fetch = async () => {
|
|
const fetch = async () => {
|
|
|
try {
|
|
try {
|
|
|
const res = await A1_APIgetDataTagByTagId(categoryTagId)
|
|
const res = await A1_APIgetDataTagByTagId(categoryTagId)
|
|
|
- if (res?.code === 0 && Array.isArray(res.data)) {
|
|
|
|
|
|
|
+ if (
|
|
|
|
|
+ res?.code === 0 &&
|
|
|
|
|
+ res.data &&
|
|
|
|
|
+ typeof res.data === 'object' &&
|
|
|
|
|
+ !Array.isArray(res.data)
|
|
|
|
|
+ ) {
|
|
|
setCategoryData(
|
|
setCategoryData(
|
|
|
- (res.data as TextureItem[]).map(({ name, count }) => ({ name, value: count }))
|
|
|
|
|
|
|
+ Object.entries(res.data as Record<string, number>).map(([name, value]) => ({
|
|
|
|
|
+ name,
|
|
|
|
|
+ value
|
|
|
|
|
+ }))
|
|
|
)
|
|
)
|
|
|
} else {
|
|
} else {
|
|
|
setCategoryData([])
|
|
setCategoryData([])
|
|
@@ -379,6 +395,8 @@ function A1statistics() {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 有数据时先清除,避免从「暂无数据」切换后 graphic 残留
|
|
|
|
|
+ myChart.clear()
|
|
|
// 计算总数用于百分比
|
|
// 计算总数用于百分比
|
|
|
const total = data.reduce((sum, item) => sum + item.value, 0)
|
|
const total = data.reduce((sum, item) => sum + item.value, 0)
|
|
|
|
|
|
|
@@ -457,9 +475,105 @@ function A1statistics() {
|
|
|
binInitFu(categoryData, document.querySelector('#echBox4'))
|
|
binInitFu(categoryData, document.querySelector('#echBox4'))
|
|
|
}, [binInitFu, categoryData])
|
|
}, [binInitFu, categoryData])
|
|
|
|
|
|
|
|
|
|
+ // 数据导出
|
|
|
|
|
+ const dataExport = useCallback(() => {
|
|
|
|
|
+ const wb = xlsx.utils.book_new()
|
|
|
|
|
+
|
|
|
|
|
+ // 汇总数据
|
|
|
|
|
+ const summaryData = [
|
|
|
|
|
+ { 指标: '藏品总数', 数值: totalStats?.totalCount ?? '-', 单位: '件/套' },
|
|
|
|
|
+ { 指标: '藏品总数量', 数值: totalStats?.totalPcs ?? '-', 单位: '个' },
|
|
|
|
|
+ { 指标: '定级文物数量', 数值: totalStats?.leveledCount ?? '-', 单位: '件/套' },
|
|
|
|
|
+ { 指标: '一级文物', 数值: totalStats?.level1 ?? 0, 单位: '件/套' },
|
|
|
|
|
+ { 指标: '二级文物', 数值: totalStats?.level2 ?? 0, 单位: '件/套' },
|
|
|
|
|
+ { 指标: '三级文物', 数值: totalStats?.level3 ?? 0, 单位: '件/套' },
|
|
|
|
|
+ { 指标: '一般文物', 数值: totalStats?.level4 ?? 0, 单位: '件/套' },
|
|
|
|
|
+ { 指标: `年度新增产品数量(${yearCountYear}年)`, 数值: yearCount ?? '-', 单位: '件/套' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ const wsSummary = xlsx.utils.json_to_sheet(summaryData)
|
|
|
|
|
+ wsSummary['!cols'] = [{ wpx: 180 }, { wpx: 100 }, { wpx: 80 }]
|
|
|
|
|
+ xlsx.utils.book_append_sheet(wb, wsSummary, '汇总')
|
|
|
|
|
+
|
|
|
|
|
+ // 一级分类
|
|
|
|
|
+ const level1SheetData = level1Data.map((it, i) => ({
|
|
|
|
|
+ 序号: i + 1,
|
|
|
|
|
+ 分类名称: it.name,
|
|
|
|
|
+ 数量: it.value
|
|
|
|
|
+ }))
|
|
|
|
|
+ if (level1SheetData.length) {
|
|
|
|
|
+ const ws1 = xlsx.utils.json_to_sheet(level1SheetData)
|
|
|
|
|
+ ws1['!cols'] = [{ wpx: 60 }, { wpx: 150 }, { wpx: 80 }]
|
|
|
|
|
+ xlsx.utils.book_append_sheet(wb, ws1, '一级分类')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 二级分类
|
|
|
|
|
+ const level2SheetData = level2Data.map((it, i) => ({
|
|
|
|
|
+ 序号: i + 1,
|
|
|
|
|
+ 分类名称: it.name,
|
|
|
|
|
+ 数量: it.value
|
|
|
|
|
+ }))
|
|
|
|
|
+ if (level2SheetData.length) {
|
|
|
|
|
+ const ws2 = xlsx.utils.json_to_sheet(level2SheetData)
|
|
|
|
|
+ ws2['!cols'] = [{ wpx: 60 }, { wpx: 150 }, { wpx: 80 }]
|
|
|
|
|
+ xlsx.utils.book_append_sheet(wb, ws2, '二级分类')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 材质统计(当前筛选)
|
|
|
|
|
+ const textureSheetData = textureData.map((it, i) => ({
|
|
|
|
|
+ 序号: i + 1,
|
|
|
|
|
+ 材质: it.name,
|
|
|
|
|
+ 数量: it.value
|
|
|
|
|
+ }))
|
|
|
|
|
+ if (textureSheetData.length) {
|
|
|
|
|
+ const ws3 = xlsx.utils.json_to_sheet(textureSheetData)
|
|
|
|
|
+ ws3['!cols'] = [{ wpx: 60 }, { wpx: 150 }, { wpx: 80 }]
|
|
|
|
|
+ const tagName = (textureOptions.find(t => t.id === textureTagId)?.name ?? '').replace(
|
|
|
|
|
+ /[\\/*?:[\]]/g,
|
|
|
|
|
+ ''
|
|
|
|
|
+ )
|
|
|
|
|
+ xlsx.utils.book_append_sheet(wb, ws3, tagName ? `材质_${tagName.slice(0, 20)}` : '材质统计')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 品类统计(当前筛选)
|
|
|
|
|
+ const categorySheetData = categoryData.map((it, i) => ({
|
|
|
|
|
+ 序号: i + 1,
|
|
|
|
|
+ 品类: it.name,
|
|
|
|
|
+ 数量: it.value
|
|
|
|
|
+ }))
|
|
|
|
|
+ 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,
|
|
|
|
|
+ ''
|
|
|
|
|
+ )
|
|
|
|
|
+ xlsx.utils.book_append_sheet(wb, ws4, tagName ? `品类_${tagName.slice(0, 20)}` : '品类统计')
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const fileName = `数据统计_${new Date().toISOString().slice(0, 10)}.xlsx`
|
|
|
|
|
+ xlsx.writeFile(wb, fileName)
|
|
|
|
|
+ }, [
|
|
|
|
|
+ totalStats,
|
|
|
|
|
+ yearCount,
|
|
|
|
|
+ yearCountYear,
|
|
|
|
|
+ level1Data,
|
|
|
|
|
+ level2Data,
|
|
|
|
|
+ textureData,
|
|
|
|
|
+ textureTagId,
|
|
|
|
|
+ textureOptions,
|
|
|
|
|
+ categoryData,
|
|
|
|
|
+ categoryTagId,
|
|
|
|
|
+ categoryOptions
|
|
|
|
|
+ ])
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<div className={styles.A1statistics}>
|
|
<div className={styles.A1statistics}>
|
|
|
- <div className='pageTitle'>数据统计</div>
|
|
|
|
|
|
|
+ <div className={styles.A1header}>
|
|
|
|
|
+ <div className='pageTitle'>数据统计</div>
|
|
|
|
|
+ <Button className={styles.A1export} type='primary' onClick={dataExport}>
|
|
|
|
|
+ 数据导出
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
<div className='A1_1'>
|
|
<div className='A1_1'>
|
|
|
<div>
|
|
<div>
|