@@ -47,6 +47,8 @@ const tag_num = ref(2)
4747const word_num = ref (197220 )
4848// 声明默认展开状态常量
4949const DEFAULT_EXPANDED = true ;
50+ // 缓存配置:5分钟过期(单位:毫秒)
51+ const CACHE_EXPIRE_TIME = 5 * 60 * 1000 ; // 300000ms = 5分钟
5052// 获取Store实例
5153const counterStore = useCounterStore ()
5254const years = ref ([
@@ -98,84 +100,91 @@ const toggleExpand = (yearGroup) => {
98100 yearGroup .isExpanded = ! yearGroup .isExpanded ;
99101};
100102
101- // 发起请求的函数
102- const fetchData = async () => {
103- // years.value = null
104- if (loading .value ) return // 防止重复请求
105- error .value = null
106- loading .value = true
103+ // 核心请求逻辑(支持强制刷新、缓存过期判断)
104+ const fetchData = async (forceRefresh = false ) => {
105+ if (loading .value ) return ; // 防止重复请求
106+ error .value = null ;
107+ loading .value = true ;
107108
108109 try {
109- // 发起GET请求(使用之前配置的代理路径)
110- const response = await axios .get (' /api/blog/public/timeline' )
111- const status = response .data .statusCode
112- if (status !== 200 ) {
113- throw new Error (response .data .message || ' 请求失败,请稍后再试' )
110+ // ============== 1. 时间线数据处理(含缓存过期判断)==============
111+ const isTimelineExpired = ! counterStore .cacheTime || (Date .now () - counterStore .cacheTime ) > CACHE_EXPIRE_TIME ;
112+ if (! forceRefresh && counterStore .timelineCache && ! isTimelineExpired) {
113+ // 缓存有效:直接使用缓存
114+ years .value = counterStore .timelineCache ;
115+ } else {
116+ // 缓存过期/无缓存/强制刷新:重新请求
117+ const timelineRes = await axios .get (' /api/blog/public/timeline' );
118+ if (timelineRes .data .statusCode !== 200 ) throw new Error (timelineRes .data .message || ' 时间线请求失败' );
119+ const newYears = handleTimelineData (timelineRes .data .data );
120+ years .value = newYears;
121+ counterStore .setTimelineCache (newYears); // 更新缓存(自动刷新cacheTime)
114122 }
115- // 将结果存入响应式变量
116- const data = response .data .data
117- console .log (data)
118- // 步骤1:提取对象的所有年份键(得到 ["2023", "2024", "2025"])
119- const yearKeys = Object .keys (data);
120- // 步骤2:将年份键转为数字,并按倒序排序(得到 [2025, 2024, 2023])
121- const sortedYears = yearKeys
122- .map (year => Number (year)) // 字符串转数字(避免 "202" 比 "2023" 大的字符串排序坑)
123- .sort ((a , b ) => b - a); // 倒序排序(b - a 是倒序,a - b 是正序)
124- // 步骤3:遍历排序后的年份,再遍历对应文章
125- const new_years = []
126- sortedYears .forEach (year => {
127- const yearStr = String (year); // 转回字符串,匹配原始对象的键
128- const articles = data[yearStr]; // 当前年份的所有文章
129- new_years .push ({
130- year: yearStr,
131- isExpanded: DEFAULT_EXPANDED , // 每年分组的展开状态,默认展开
132- articles: articles
133- })
134- // 遍历当前年份的每篇文章
135- articles .forEach ((article , index ) => {
136- // 2025-10-24T16:31:03.078Z,转成时区时间 MM-DD 格式
137- const utcDate = new Date (article .createdAt );
138- article .date = ` ${ String (utcDate .getMonth () + 1 ).padStart (2 , ' 0' )} -${ String (utcDate .getDate ()).padStart (2 , ' 0' )} ` ;
139- });
140- });
141- years .value = new_years
142- } catch (err) {
143- // 处理错误
144- error .value = err .message || ' 请求失败,请稍后再试'
145- console .error (' 请求错误:' , err)
146- } finally {
147- // 结束加载状态
148- loading .value = false
149- }
150- try {
151- // 发起GET请求(使用之前配置的代理路径)
152- const response = await axios .get (' /api/blog/public/meta' )
153- const status = response .data .statusCode
154- if (status !== 200 ) {
155- throw new Error (response .data .message || ' 请求失败,请稍后再试' )
123+
124+ // ============== 2. 元数据处理(和时间线共用缓存过期状态)==============
125+ if (! forceRefresh && counterStore .metaCache && ! isTimelineExpired) {
126+ // 缓存有效:直接使用缓存
127+ const metaCache = counterStore .metaCache ;
128+ tag_num .value = metaCache .tagNum ;
129+ category_num .value = metaCache .categoryNum ;
130+ article_num .value = metaCache .articleNum ;
131+ word_num .value = metaCache .wordNum ;
132+ counterStore .setVisit (metaCache .visit );
133+ counterStore .setVisitor (metaCache .visitor );
134+ } else {
135+ // 缓存过期/无缓存/强制刷新:重新请求
136+ const metaRes = await axios .get (' /api/blog/public/meta' );
137+ if (metaRes .data .statusCode !== 200 ) throw new Error (metaRes .data .message || ' 元数据请求失败' );
138+ const metaData = metaRes .data .data ;
139+ // 处理元数据并缓存
140+ const metaCache = {
141+ tagNum: metaData .tags .length ,
142+ categoryNum: metaData .meta .categories .length ,
143+ articleNum: metaData .totalArticles ,
144+ wordNum: metaData .totalWordCount ,
145+ visit: metaData .meta .viewer ,
146+ visitor: metaData .meta .visited
147+ };
148+ // 更新组件状态
149+ tag_num .value = metaCache .tagNum ;
150+ category_num .value = metaCache .categoryNum ;
151+ article_num .value = metaCache .articleNum ;
152+ word_num .value = metaCache .wordNum ;
153+ counterStore .setVisit (metaCache .visit );
154+ counterStore .setVisitor (metaCache .visitor );
155+ counterStore .setMetaCache (metaCache); // 缓存元数据
156156 }
157- // 将结果存入响应式变量
158- const data = response .data .data
159- const tags = data .tags
160- tag_num .value = tags .length
161- const categories = data .meta .categories
162- category_num .value = categories .length
163- article_num .value = data .totalArticles
164- word_num .value = data .totalWordCount
165- counterStore .setVisit (data .meta .viewer )
166- counterStore .setVisitor (data .meta .visited )
167157 } catch (err) {
168- // 处理错误
169- error .value = err .message || ' 请求失败,请稍后再试'
170- console .error (' 请求错误:' , err)
158+ error .value = err .message || ' 请求失败,请稍后再试' ;
159+ console .error (' 请求错误:' , err);
171160 } finally {
172- // 结束加载状态
173- loading .value = false
161+ loading .value = false ;
174162 }
175- }
163+ };
164+
165+ // 提取原日期处理逻辑为独立函数(复用)
166+ const handleTimelineData = (data ) => {
167+ const yearKeys = Object .keys (data);
168+ const sortedYears = yearKeys .map (Number ).sort ((a , b ) => b - a);
169+ return sortedYears .map (year => {
170+ const yearStr = String (year);
171+ const articles = data[yearStr].map (article => {
172+ const utcDate = new Date (article .createdAt );
173+ return {
174+ ... article,
175+ date: ` ${ String (utcDate .getMonth () + 1 ).padStart (2 , ' 0' )} -${ String (utcDate .getDate ()).padStart (2 , ' 0' )} `
176+ };
177+ });
178+ return {
179+ year: yearStr,
180+ isExpanded: DEFAULT_EXPANDED ,
181+ articles
182+ };
183+ });
184+ };
176185
177- // 可选:组件挂载时自动请求
178- onMounted (fetchData)
186+ // 组件挂载时请求(优先用缓存)
187+ onMounted (() => fetchData ());
179188
180189 </script >
181190
0 commit comments