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'; import { TimeDimension, AnalysisType, IndustryTrendState, IndustryDataItem, ChartConfig } from '@/types/analysis/industry'; import { formatQuarter, formatDateForDisplay, convertApiData } from './utils'; const { Option } = Select; const { RangePicker } = DatePicker; const IndustryTrendPage: React.FC = () => { const [params, setParams] = useState({ timeDimension: '月', type: '岗位发布数量', 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 () => { let { startTime, endTime, timeDimension, type } = params; if (timeDimension === '季度') { startTime = formatQuarter(startTime); endTime = formatQuarter(endTime); } return await getIndustryTrend({ timeDimension, type, startTime, endTime }); }, { manual: true, onSuccess: (data) => { const formattedData = convertApiData(data); setAllData(formattedData); const industries = Array.from( new Set(formattedData.map((item: { category: any; }) => item.category)) ).filter(Boolean).sort(); setAvailableIndustries(industries); if (industries.length > 0 && !industries.includes(params.selectedIndustry)) { setParams(p => ({ ...p, selectedIndustry: industries[0] })); } }, onError: () => message.error('数据加载失败') } ); const handleTimeDimensionChange = (value: TimeDimension) => { const now = dayjs(); let newStartTime = ''; if (value === '月') { newStartTime = now.subtract(5, 'month').format('YYYY-MM'); } else if (value === '季度') { newStartTime = now.subtract(6, 'quarter').format('YYYY-Q'); } else { 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 disabledDate = (current: dayjs.Dayjs) => { const now = dayjs(); if (params.timeDimension === '月') { return current.isAfter(now.endOf('month')); } else if (params.timeDimension === '季度') { return current.isAfter(now.endOf('quarter')); } else { return current.isAfter(now.endOf('year')); } }; const currentIndustryData = useMemo(() => { if (!params.selectedIndustry || allData.length === 0) return []; return allData .filter(item => item.category === params.selectedIndustry) .map(item => ({ ...item, originalDate: item.date, date: formatDateForDisplay(item.date, params.timeDimension) })) .sort((a, b) => { if (params.timeDimension === '季度') { // 处理中文季度格式,如 "2024-第一季度" -> ["2024", "第一"] const [yearA, quarterA] = a.originalDate.split('-'); const [yearB, quarterB] = b.originalDate.split('-'); // 转换中文季度为数字("第一" -> 1, "第二" -> 2...) const quarterToNumber = (q: string) => { if (q.includes('第一')) return 1; if (q.includes('第二')) return 2; if (q.includes('第三')) return 3; if (q.includes('第四')) return 4; return 0; }; return yearA === yearB ? quarterToNumber(quarterA) - quarterToNumber(quarterB) : parseInt(yearA) - parseInt(yearB); } else if (params.timeDimension === '年') { return parseInt(a.originalDate) - parseInt(b.originalDate); } else { return dayjs(a.originalDate).valueOf() - dayjs(b.originalDate).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: 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 === '招聘增长率' ? '%' : ''}`, }, }, point: { size: 4, shape: 'circle', }, animation: { appear: { animation: 'path-in', duration: 1000, }, }, smooth: true, interactions: [ { type: 'tooltip', cfg: { render: (e, { title, items }) => { const list = items.filter((item) => item.value); return (

{title}

{list.map((item, index) => { const { name, value, color } = item; return (
{name}
{value}{params.type === '招聘增长率' ? '%' : ''}
); })}
); }, }, }, ], legend: false, tooltip: { showTitle: undefined, title: undefined, customContent: undefined } }; useEffect(() => { fetchData(); }, [params.timeDimension, params.startTime, params.endTime, params.type]); return (
{currentIndustryData.length > 0 ? ( ) : ( )}
); }; export default IndustryTrendPage;