From fa577431b8c828422ed2b6df051721ed972d3060 Mon Sep 17 00:00:00 2001 From: yy <3078169442@qq.com> Date: Mon, 26 May 2025 12:19:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=97=A5=E6=9C=9F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Analysis/Industrytrend/index.tsx | 320 ++++++++++++--------- 1 file changed, 179 insertions(+), 141 deletions(-) diff --git a/src/pages/Analysis/Industrytrend/index.tsx b/src/pages/Analysis/Industrytrend/index.tsx index 1d793b7..28da5fe 100644 --- a/src/pages/Analysis/Industrytrend/index.tsx +++ b/src/pages/Analysis/Industrytrend/index.tsx @@ -1,76 +1,122 @@ import React, { useEffect, useState, useMemo } from 'react'; -import { Card, Select, Button, Space, Spin, Empty, Row, Col, message } from 'antd'; +import { Card, Select, Button, Space, Spin, Empty, Row, Col, message, DatePicker } from 'antd'; import { Line } from '@ant-design/charts'; import { getIndustryTrend } from '@/services/analysis/industry'; import dayjs from 'dayjs'; import { useRequest } from '@umijs/max'; const { Option } = Select; +const { RangePicker } = DatePicker; + type IndustryDataItem = { date: string; category: string; value: number; }; +const formatDateForDisplay = (dateStr: string, dimension: string): string => { + try { + if (dimension === '年') { + return dateStr.split('-')[0]; + } + if (dimension === '季度') { + const [year, quarter] = dateStr.split('-Q'); + return `${year}年Q${quarter}`; + } + // 默认按月显示 + const [year, month] = dateStr.split('-'); + return `${year}年${month}月`; + } catch (e) { + console.error('日期格式化错误:', e); + return dateStr; + } +}; + const IndustryTrendPage: React.FC = () => { const [params, setParams] = useState({ timeDimension: '月' as '月' | '季度' | '年', type: '岗位发布数量' as '岗位发布数量' | '招聘增长率', - startTime: dayjs().subtract(6, 'month').format('YYYY-MM'), + startTime: dayjs().subtract(5, 'month').format('YYYY-MM'), endTime: dayjs().format('YYYY-MM'), - selectedIndustry: '' + selectedIndustry: '' }); + const [allData, setAllData] = useState([]); - const [prevSelectedIndustry, setPrevSelectedIndustry] = useState(''); - const { loading, run } = useRequest( - () => getIndustryTrend({ - ...params, - startTime: formatTimeParam(params.startTime, params.timeDimension), - endTime: formatTimeParam(params.endTime, params.timeDimension) - }), + const [availableIndustries, setAvailableIndustries] = useState([]); + const { loading, run: fetchData } = useRequest( + async () => { + try { + const resp = await getIndustryTrend({ + timeDimension: params.timeDimension, + type: params.type, + startTime: formatTimeParam(params.startTime, params.timeDimension), + endTime: formatTimeParam(params.endTime, params.timeDimension) + }); + return resp; + } catch (error) { + message.error('数据加载失败'); + throw error; + } + }, { manual: true, - onError: (error) => message.error('数据加载失败: ' + error.message), - onSuccess: (responseData) => { - const formattedData = convertApiData(responseData); + onSuccess: (data) => { + const formattedData = convertApiData(data); setAllData(formattedData); - const industryToSelect = prevSelectedIndustry || - (formattedData.length > 0 ? formattedData[0].category : ''); - setParams(prev => ({ ...prev, selectedIndustry: industryToSelect })); + const industries = Array.from( + new Set(formattedData.map(item => item.category)) + ).filter(Boolean).sort(); + + setAvailableIndustries(industries); + if (industries.length > 0 && !industries.includes(params.selectedIndustry)) { + setParams(p => ({ ...p, selectedIndustry: industries[0] })); + } } } ); + + const formatTimeParam = (dateStr: string, dimension: string): string => { + try { + const date = dayjs(dateStr); + switch (dimension) { + case '季度': + return `${date.year()}-Q${Math.ceil((date.month() + 1) / 3)}`; + case '年': + return `${date.year()}`; + default: + return date.format('YYYY-MM'); + } + } catch (e) { + console.error('日期参数格式化错误:', e); + return dateStr; + } + }; + const convertApiData = (apiData: any): IndustryDataItem[] => { if (!apiData) return []; try { - const result: IndustryDataItem[] = []; - if (typeof apiData === 'object' && !Array.isArray(apiData)) { - Object.entries(apiData).forEach(([month, monthData]) => { - if (Array.isArray(monthData)) { - (monthData as any[]).forEach(item => { - const convertedItem = { - date: month, - category: item.name || item.category, + if (Array.isArray(apiData)) { + return apiData.map(item => ({ + date: item.time || item.date, + category: item.name || item.category || '未知行业', + value: Number(item.data || item.value) || 0 + })); + } + if (typeof apiData === 'object') { + const result: IndustryDataItem[] = []; + Object.entries(apiData).forEach(([date, items]) => { + if (Array.isArray(items)) { + items.forEach((item: any) => { + result.push({ + date, + category: item.name || item.category || '未知行业', value: Number(item.data || item.value) || 0 - }; - console.log('转换后的数据项:', convertedItem); - result.push(convertedItem); + }); }); } }); return result; } - if (Array.isArray(apiData)) { - return apiData.map(item => { - const convertedItem = { - date: item.time || item.date, - category: item.name || item.category, - value: Number(item.data || item.value) || 0 - }; - console.log('转换后的数据项:', convertedItem); - return convertedItem; - }); - } return []; } catch (error) { @@ -78,40 +124,65 @@ const IndustryTrendPage: React.FC = () => { return []; } }; - const industries = useMemo(() => { - if (allData.length === 0) return []; - const categories = new Set(); - allData.forEach(item => categories.add(item.category)); - return Array.from(categories).sort(); - }, [allData]); - const formatTimeParam = (dateStr: string, dimension: string) => { - const date = dayjs(dateStr); - switch (dimension) { - case '季度': return `${date.year()}-Q${Math.ceil((date.month() + 1) / 3)}`; - case '年': return `${date.year()}`; - default: return date.format('YYYY-MM'); + const handleTimeDimensionChange = (value: '月' | '季度' | '年') => { + const now = dayjs(); + let newStartTime = ''; + switch (value) { + case '月': + newStartTime = now.subtract(6, 'month').format('YYYY-MM'); + break; + case '季度': + newStartTime = now.subtract(6, 'quarter').format('YYYY-Q'); + break; + case '年': + default: + newStartTime = now.subtract(5, 'year').format('YYYY'); + } + setParams(p => ({ + ...p, + timeDimension: value, + startTime: newStartTime, + endTime: value === '月' ? now.format('YYYY-MM') : + value === '季度' ? now.format('YYYY-Q') : + now.format('YYYY'), + selectedIndustry: '' + })); + }; + const handleDateRangeChange = (dates: any, dateStrings: [string, string]) => { + if (dates && dates[0] && dates[1]) { + setParams(p => ({ + ...p, + startTime: dateStrings[0], + endTime: dateStrings[1] + })); } }; - const handleIndustryChange = (value: string) => { - setPrevSelectedIndustry(value); - setParams(p => ({ ...p, selectedIndustry: value })); - }; - const currentIndustryData = useMemo(() => { - if (!params.selectedIndustry) return []; - - const filteredData = allData + if (!params.selectedIndustry || allData.length === 0) return []; + + return allData .filter(item => item.category === params.selectedIndustry) .map(item => ({ - date: item.date, - category: item.category, - value: item.value ?? 0, + ...item, + date: formatDateForDisplay(item.date, params.timeDimension) })) .sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf()); - console.log("当前行业数据 (过滤后):", filteredData); - return filteredData; - }, [allData, params.selectedIndustry]); - console.log("最终图表数据:", currentIndustryData); + }, [allData, params.selectedIndustry, params.timeDimension]); + const getPickerValue = () => { + try { + return [ + dayjs(params.startTime, params.timeDimension === '年' ? 'YYYY' : + params.timeDimension === '季度' ? 'YYYY-Q' : 'YYYY-MM'), + dayjs(params.endTime, params.timeDimension === '年' ? 'YYYY' : + params.timeDimension === '季度' ? 'YYYY-Q' : 'YYYY-MM') + ]; + } catch (e) { + console.error('日期解析错误:', e); + return null; + } + }; + + // 图表配置 const chartConfig = { data: currentIndustryData, height: 180, @@ -120,13 +191,8 @@ const IndustryTrendPage: React.FC = () => { seriesField: 'category', xAxis: { type: 'cat', - tickCount: 5, label: { - formatter: (text: string) => { - if (params.timeDimension === '年') return text.split('-')[0]; - if (params.timeDimension === '季度') return text.split('-')[1]; - return text.split('-')[1]; - }, + formatter: (text: string) => text, }, }, yAxis: { @@ -145,36 +211,35 @@ const IndustryTrendPage: React.FC = () => { duration: 1000, }, }, + smooth: true, }; - + // 初始化加载数据 useEffect(() => { - run(); - }, [params.timeDimension, params.startTime, params.endTime]); + fetchData(); + }, [params.timeDimension, params.startTime, params.endTime, params.type]); return (
- -
+ +
+ +