feat: 添加修改行业分类不展示的问题
This commit is contained in:
@@ -1,12 +1,17 @@
|
|||||||
// src/contexts/IndustryContext.js
|
// src/contexts/IndustryContext.js
|
||||||
// 行业分类数据全局上下文 - 直接使用静态数据
|
// 行业分类数据全局上下文 - 使用API获取 + 缓存机制
|
||||||
|
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useState, useEffect, useRef } from 'react';
|
||||||
import { industryData as staticIndustryData } from '../data/industryData';
|
import { industryData as staticIndustryData } from '../data/industryData';
|
||||||
|
import { industryService } from '../services/industryService';
|
||||||
import { logger } from '../utils/logger';
|
import { logger } from '../utils/logger';
|
||||||
|
|
||||||
const IndustryContext = createContext();
|
const IndustryContext = createContext();
|
||||||
|
|
||||||
|
// 缓存配置
|
||||||
|
const CACHE_KEY = 'industry_classifications_cache';
|
||||||
|
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 1天(24小时)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* useIndustry Hook
|
* useIndustry Hook
|
||||||
* 在任何组件中使用行业数据
|
* 在任何组件中使用行业数据
|
||||||
@@ -19,28 +24,148 @@ export const useIndustry = () => {
|
|||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 localStorage 读取缓存
|
||||||
|
*/
|
||||||
|
const loadFromCache = () => {
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem(CACHE_KEY);
|
||||||
|
if (!cached) return null;
|
||||||
|
|
||||||
|
const { data, timestamp } = JSON.parse(cached);
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// 检查缓存是否过期(1天)
|
||||||
|
if (now - timestamp > CACHE_DURATION) {
|
||||||
|
localStorage.removeItem(CACHE_KEY);
|
||||||
|
logger.debug('IndustryContext', '缓存已过期,清除缓存');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug('IndustryContext', '从缓存加载行业数据', {
|
||||||
|
count: data?.length || 0,
|
||||||
|
age: Math.round((now - timestamp) / 1000 / 60) + ' 分钟前'
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('IndustryContext', 'loadFromCache', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存到 localStorage
|
||||||
|
*/
|
||||||
|
const saveToCache = (data) => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(CACHE_KEY, JSON.stringify({
|
||||||
|
data,
|
||||||
|
timestamp: Date.now()
|
||||||
|
}));
|
||||||
|
logger.debug('IndustryContext', '行业数据已缓存', {
|
||||||
|
count: data?.length || 0
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('IndustryContext', 'saveToCache', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IndustryProvider 组件
|
* IndustryProvider 组件
|
||||||
* 提供全局行业数据管理 - 直接使用静态数据,无需加载
|
* 提供全局行业数据管理 - 使用API获取 + 缓存机制
|
||||||
*/
|
*/
|
||||||
export const IndustryProvider = ({ children }) => {
|
export const IndustryProvider = ({ children }) => {
|
||||||
// 直接使用静态数据,无需状态管理
|
const [industryData, setIndustryData] = useState(null);
|
||||||
const industryData = staticIndustryData;
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const hasLoadedRef = useRef(false);
|
||||||
|
const isLoadingRef = useRef(false);
|
||||||
|
|
||||||
logger.debug('IndustryContext', '使用静态行业数据', {
|
/**
|
||||||
count: industryData?.length || 0
|
* 加载行业数据
|
||||||
|
*/
|
||||||
|
const loadIndustryData = async () => {
|
||||||
|
// 防止重复加载(处理 StrictMode 双重调用)
|
||||||
|
if (hasLoadedRef.current || isLoadingRef.current) {
|
||||||
|
logger.debug('IndustryContext', '跳过重复加载', {
|
||||||
|
hasLoaded: hasLoadedRef.current,
|
||||||
|
isLoading: isLoadingRef.current
|
||||||
|
});
|
||||||
|
return industryData;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
isLoadingRef.current = true;
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
logger.debug('IndustryContext', '开始加载行业数据');
|
||||||
|
|
||||||
|
// 1. 先尝试从缓存加载
|
||||||
|
const cachedData = loadFromCache();
|
||||||
|
if (cachedData && cachedData.length > 0) {
|
||||||
|
setIndustryData(cachedData);
|
||||||
|
hasLoadedRef.current = true;
|
||||||
|
return cachedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 缓存不存在或过期,调用 API
|
||||||
|
logger.debug('IndustryContext', '缓存无效,调用API获取数据');
|
||||||
|
const response = await industryService.getClassifications();
|
||||||
|
|
||||||
|
if (response.success && response.data && response.data.length > 0) {
|
||||||
|
setIndustryData(response.data);
|
||||||
|
saveToCache(response.data);
|
||||||
|
hasLoadedRef.current = true;
|
||||||
|
|
||||||
|
logger.debug('IndustryContext', 'API数据加载成功', {
|
||||||
|
count: response.data.length
|
||||||
});
|
});
|
||||||
|
|
||||||
const value = {
|
return response.data;
|
||||||
industryData, // 行业数据(静态)
|
} else {
|
||||||
loading: false, // 静态数据无需加载
|
throw new Error('API返回数据为空');
|
||||||
error: null, // 静态数据无错误
|
|
||||||
loadIndustryData: () => { // 兼容旧接口,返回数据
|
|
||||||
return Promise.resolve(industryData);
|
|
||||||
},
|
|
||||||
refreshIndustryData: () => { // 兼容旧接口,返回数据
|
|
||||||
return Promise.resolve(industryData);
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// 3. API 失败,回退到静态数据
|
||||||
|
logger.warn('IndustryContext', 'API加载失败,使用静态数据', {
|
||||||
|
error: err.message
|
||||||
|
});
|
||||||
|
|
||||||
|
setError(err.message);
|
||||||
|
setIndustryData(staticIndustryData);
|
||||||
|
hasLoadedRef.current = true;
|
||||||
|
|
||||||
|
return staticIndustryData;
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
isLoadingRef.current = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新行业数据(清除缓存并重新加载)
|
||||||
|
*/
|
||||||
|
const refreshIndustryData = async () => {
|
||||||
|
logger.debug('IndustryContext', '刷新行业数据,清除缓存');
|
||||||
|
localStorage.removeItem(CACHE_KEY);
|
||||||
|
hasLoadedRef.current = false;
|
||||||
|
isLoadingRef.current = false;
|
||||||
|
return loadIndustryData();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件挂载时自动加载数据
|
||||||
|
useEffect(() => {
|
||||||
|
loadIndustryData();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
industryData,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
loadIndustryData,
|
||||||
|
refreshIndustryData
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// src/views/Community/components/EventFilters.js
|
// src/views/Community/components/EventFilters.js
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Card, Row, Col, DatePicker, Button, Select, Form, Input, Cascader } from 'antd';
|
import { Card, Row, Col, DatePicker, Button, Select, Form, Cascader } from 'antd';
|
||||||
import { FilterOutlined } from '@ant-design/icons';
|
import { FilterOutlined } from '@ant-design/icons';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import locale from 'antd/es/date-picker/locale/zh_CN';
|
import locale from 'antd/es/date-picker/locale/zh_CN';
|
||||||
@@ -12,7 +12,9 @@ const { Option } = Select;
|
|||||||
|
|
||||||
const EventFilters = ({ filters, onFilterChange, loading }) => {
|
const EventFilters = ({ filters, onFilterChange, loading }) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [industryOptions, setIndustryOptions] = useState([]);
|
|
||||||
|
// 使用全局行业数据
|
||||||
|
const { industryData, loading: industryLoading, loadIndustryData } = useIndustry();
|
||||||
|
|
||||||
// 初始化表单值
|
// 初始化表单值
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -25,25 +27,14 @@ const EventFilters = ({ filters, onFilterChange, loading }) => {
|
|||||||
form.setFieldsValue(initialValues);
|
form.setFieldsValue(initialValues);
|
||||||
}, [filters, form]);
|
}, [filters, form]);
|
||||||
|
|
||||||
// 加载申银万国行业分类树形数据
|
// Cascader 获得焦点时确保数据已加载
|
||||||
const loadIndustryClassifications = async () => {
|
const handleCascaderFocus = async () => {
|
||||||
try {
|
if (!industryData || industryData.length === 0) {
|
||||||
const response = await industryService.getClassifications();
|
logger.debug('EventFilters', 'Cascader 获得焦点,触发数据加载');
|
||||||
if (response.success && response.data) {
|
await loadIndustryData();
|
||||||
setIndustryOptions(response.data);
|
|
||||||
logger.debug('EventFilters', '申银万国行业分类加载成功', {
|
|
||||||
count: response.data?.length || 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('EventFilters', 'loadIndustryClassifications', error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadIndustryClassifications();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleDateRangeChange = (dates) => {
|
const handleDateRangeChange = (dates) => {
|
||||||
if (dates && dates.length === 2) {
|
if (dates && dates.length === 2) {
|
||||||
const dateRange = `${dates[0].format('YYYY-MM-DD')} 至 ${dates[1].format('YYYY-MM-DD')}`;
|
const dateRange = `${dates[0].format('YYYY-MM-DD')} 至 ${dates[1].format('YYYY-MM-DD')}`;
|
||||||
@@ -92,14 +83,14 @@ const EventFilters = ({ filters, onFilterChange, loading }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 行业级联选择变化
|
// 行业级联选择变化
|
||||||
const handleIndustryChange = (value, selectedOptions) => {
|
const handleIndustryChange = (value) => {
|
||||||
if (!value || value.length === 0) {
|
if (!value || value.length === 0) {
|
||||||
onFilterChange('industry_code', '');
|
onFilterChange('industry_code', '');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取选中的节点
|
// 获取选中的节点
|
||||||
const selectedNode = findNodeByPath(industryOptions, value);
|
const selectedNode = findNodeByPath(industryData || [], value);
|
||||||
|
|
||||||
if (!selectedNode) {
|
if (!selectedNode) {
|
||||||
// 如果找不到节点,使用最后一个值
|
// 如果找不到节点,使用最后一个值
|
||||||
@@ -163,17 +154,20 @@ const EventFilters = ({ filters, onFilterChange, loading }) => {
|
|||||||
{/* 行业分类级联选择器 - 替换原来的 5 个独立 Select */}
|
{/* 行业分类级联选择器 - 替换原来的 5 个独立 Select */}
|
||||||
<Row gutter={16}>
|
<Row gutter={16}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Form.Item label="申银万国行业分类" name="industry_cascade">
|
<Form.Item label="行业" name="industry_cascade">
|
||||||
<Cascader
|
<Cascader
|
||||||
options={industryOptions}
|
options={industryData || []}
|
||||||
onChange={handleIndustryChange}
|
onChange={handleIndustryChange}
|
||||||
placeholder="请选择行业(支持选择任意级别)"
|
onFocus={handleCascaderFocus}
|
||||||
|
placeholder={industryLoading ? "加载中..." : "请选择行业(支持选择任意级别)"}
|
||||||
changeOnSelect
|
changeOnSelect
|
||||||
|
expandTrigger="hover"
|
||||||
showSearch={{
|
showSearch={{
|
||||||
filter: (inputValue, path) =>
|
filter: (inputValue, path) =>
|
||||||
path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1)
|
path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1)
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading || industryLoading}
|
||||||
|
loading={industryLoading}
|
||||||
allowClear
|
allowClear
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
displayRender={(labels) => labels.join(' / ')}
|
displayRender={(labels) => labels.join(' / ')}
|
||||||
|
|||||||
Reference in New Issue
Block a user