import React, { useEffect, useState, useMemo } from 'react'; 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(5, 'month').format('YYYY-MM'), endTime: dayjs().format('YYYY-MM'), selectedIndustry: '' }); const [allData, setAllData] = useState([]); 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, onSuccess: (data) => { const formattedData = convertApiData(data); setAllData(formattedData); 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 { 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 }); }); } }); return result; } return []; } catch (error) { console.error('数据转换错误:', error); return []; } }; 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 currentIndustryData = useMemo(() => { if (!params.selectedIndustry || allData.length === 0) return []; return allData .filter(item => item.category === params.selectedIndustry) .map(item => ({ ...item, date: formatDateForDisplay(item.date, params.timeDimension) })) .sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf()); }, [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, xField: 'date', yField: 'value', seriesField: 'category', xAxis: { type: 'cat', label: { formatter: (text: string) => text, }, }, yAxis: { label: { formatter: (val: string) => `${val}${params.type === '招聘增长率' ? '%' : '个'}`, }, }, tooltip: false, point: { size: 4, shape: 'circle', }, animation: { appear: { animation: 'path-in', duration: 1000, }, }, smooth: true, }; // 初始化加载数据 useEffect(() => { fetchData(); }, [params.timeDimension, params.startTime, params.endTime, params.type]); return (
{currentIndustryData.length > 0 ? ( ) : ( )}
); }; export default IndustryTrendPage;