From be71c15b3c15e2f292aeba4e5ef4e7dc7f80bf2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=AE=87=E9=98=B3?= Date: Wed, 8 Jul 2026 10:58:58 +0800 Subject: [PATCH] =?UTF-8?q?refactor(api):=20=E6=9B=B4=E6=96=B0=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E6=A0=87=E7=AD=BE=E5=A4=84=E7=90=86=E5=92=8CAPI?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 revalidate 路由中引入 isAllowedCacheTag 函数,优化无效标签过滤逻辑。 - 更新评论和点赞相关组件,替换 API 调用为新的 action 函数,提升代码一致性。 - 在多个页面中使用缓存 API 以提高数据获取效率,简化 API 请求逻辑。 --- src/actions/article.ts | 36 ++++++++++++++++++ src/actions/record.ts | 37 +++++++++++++++++++ src/actions/wall.ts | 25 +++++++++++++ src/actions/web.ts | 21 +++++++++++ src/app/api/revalidate/route.ts | 8 ++-- src/app/article/components/Comment/index.tsx | 4 +- src/app/article/components/Like/index.tsx | 4 +- .../friend/components/ApplyForAdd/index.tsx | 15 +++----- src/app/friend/page.tsx | 5 ++- src/app/record/components/Comment/index.tsx | 5 ++- src/app/record/components/RecordCard.tsx | 4 +- src/app/record/page.tsx | 4 +- src/app/wall/[cate]/page.tsx | 6 +-- src/app/wall/components/AddWallInfo/index.tsx | 15 +++----- src/lib/cache-tags.ts | 28 +++++++++++++- src/lib/record.ts | 15 ++++++++ src/lib/wall.ts | 13 +++++++ src/lib/web.ts | 13 +++++++ 18 files changed, 217 insertions(+), 41 deletions(-) create mode 100644 src/actions/article.ts create mode 100644 src/actions/record.ts create mode 100644 src/actions/wall.ts create mode 100644 src/actions/web.ts create mode 100644 src/lib/record.ts create mode 100644 src/lib/wall.ts create mode 100644 src/lib/web.ts diff --git a/src/actions/article.ts b/src/actions/article.ts new file mode 100644 index 0000000..07ed369 --- /dev/null +++ b/src/actions/article.ts @@ -0,0 +1,36 @@ +'use server'; + +import { refresh, updateTag } from 'next/cache'; + +import { Request } from '@/utils/request'; +import { CACHE_TAGS } from '@/lib/cache-tags'; +import { Comment } from '@/types/app/comment'; + +export async function likeArticleAction(id: number, count: number) { + const result = await Request('POST', `/article/${id}/like`, { count }); + + if (result.code === 200) { + updateTag(`${CACHE_TAGS.article}-${id}`); + updateTag(CACHE_TAGS.articles); + } + + return result; +} + +export async function addArticleCommentAction(data: Comment) { + const result = await Request('POST', '/comment', data); + + // 如果请求成功则更新缓存 + if (data.articleId && result.code === 200) { + // 更新文章详情缓存 + updateTag(`${CACHE_TAGS.article}-${data.articleId}`); + // 更新文章列表缓存 + updateTag(CACHE_TAGS.articles); + // 更新文章评论列表缓存 + updateTag(`${CACHE_TAGS.comments}-${data.articleId}`); + // 触发页面重新渲染 + refresh(); + } + + return result; +} diff --git a/src/actions/record.ts b/src/actions/record.ts new file mode 100644 index 0000000..d758a48 --- /dev/null +++ b/src/actions/record.ts @@ -0,0 +1,37 @@ +'use server'; + +import { refresh, updateTag } from 'next/cache'; + +import { Request } from '@/utils/request'; +import { CACHE_TAGS } from '@/lib/cache-tags'; +import { RecordComment } from '@/types/app/recordComment'; + +export async function likeRecordAction(id: number, count: number) { + const result = await Request('POST', `/record/${id}/like`, { count }); + + if (result.code === 200) { + updateTag(CACHE_TAGS.records); + updateTag(`${CACHE_TAGS.record}-${id}`); + refresh(); + } + + return result; +} + +export async function addRecordCommentAction(data: RecordComment) { + const result = await Request('POST', '/record/comment', data); + + // 如果请求成功则更新缓存 + if (data.recordId && result.code === 200) { + // 更新说说列表缓存 + updateTag(CACHE_TAGS.records); + // 更新说说详情缓存 + updateTag(`${CACHE_TAGS.record}-${data.recordId}`); + // 更新说说评论列表缓存 + updateTag(`${CACHE_TAGS.comments}-${data.recordId}`); + // 触发页面重新渲染 + refresh(); + } + + return result; +} diff --git a/src/actions/wall.ts b/src/actions/wall.ts new file mode 100644 index 0000000..1e47b3b --- /dev/null +++ b/src/actions/wall.ts @@ -0,0 +1,25 @@ +'use server'; + +import { refresh, updateTag } from 'next/cache'; + +import { Request } from '@/utils/request'; +import { CACHE_TAGS } from '@/lib/cache-tags'; +import { Wall } from '@/types/app/wall'; + +export async function addWallAction(data: Wall) { + const result = await Request('POST', '/wall', data); + + // 如果请求成功则更新缓存 + if (result.code === 200) { + // 更新留言列表缓存 + updateTag(CACHE_TAGS.walls); + // 更新留言分类缓存 + if (data.cateId) { + updateTag(`${CACHE_TAGS.wall}-${data.cateId}`); + } + // 触发页面重新渲染 + refresh(); + } + + return result; +} diff --git a/src/actions/web.ts b/src/actions/web.ts new file mode 100644 index 0000000..3cd7092 --- /dev/null +++ b/src/actions/web.ts @@ -0,0 +1,21 @@ +'use server'; + +import { refresh, updateTag } from 'next/cache'; + +import { Request } from '@/utils/request'; +import { CACHE_TAGS } from '@/lib/cache-tags'; +import { Web } from '@/types/app/web'; + +export async function addWebAction(data: Web) { + const result = await Request('POST', '/link', data); + + // 如果请求成功则更新缓存 + if (result.code === 200) { + // 更新友链列表缓存 + updateTag(CACHE_TAGS.webs); + // 触发页面重新渲染 + refresh(); + } + + return result; +} diff --git a/src/app/api/revalidate/route.ts b/src/app/api/revalidate/route.ts index 36c2ab6..937cbfa 100644 --- a/src/app/api/revalidate/route.ts +++ b/src/app/api/revalidate/route.ts @@ -6,9 +6,7 @@ import { revalidateTag } from 'next/cache'; import { NextRequest, NextResponse } from 'next/server'; -import { CACHE_TAGS } from '@/lib/cache-tags'; - -const ALLOWED_TAGS = new Set(Object.values(CACHE_TAGS)); +import { CACHE_TAGS, isAllowedCacheTag } from '@/lib/cache-tags'; export async function POST(req: NextRequest) { const secret = req.headers.get('x-revalidate-secret'); @@ -33,8 +31,8 @@ export async function POST(req: NextRequest) { // 无 body 时使用默认 tags } - // 过滤掉无效的标签 - const invalidTags = tags.filter((tag) => !ALLOWED_TAGS.has(tag as (typeof CACHE_TAGS)[keyof typeof CACHE_TAGS]) && !tag.startsWith(`${CACHE_TAGS.article}-`) && !tag.startsWith(`${CACHE_TAGS.articlesList}-`)); + // 过滤掉无效的标签 使用 isAllowedCacheTag 判断是否是允许的缓存标签 + const invalidTags = tags.filter((tag) => !isAllowedCacheTag(tag)); // 如果无效的标签,则返回 400 错误 if (invalidTags.length) { return NextResponse.json({ message: 'Invalid tags', invalidTags }, { status: 400 }); diff --git a/src/app/article/components/Comment/index.tsx b/src/app/article/components/Comment/index.tsx index d377799..1ec8af7 100755 --- a/src/app/article/components/Comment/index.tsx +++ b/src/app/article/components/Comment/index.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from 'react'; import { useForm } from 'react-hook-form'; -import { addCommentDataAPI } from '@/api/comment'; +import { addArticleCommentAction } from '@/actions/article'; import { Bounce, ToastOptions, toast } from 'react-toastify'; import { Spinner, Popover, PopoverTrigger, PopoverContent } from '@/ThriveUI'; import HCaptchaType from '@hcaptcha/react-hcaptcha'; @@ -89,7 +89,7 @@ const CommentForm = ({ articleId }: Props) => { if (!isNaN(+qq)) data.avatar = `https://q1.qlogo.cn/g?b=qq&nk=${qq}&s=640`; } - const { code, message } = await addCommentDataAPI({ + const { code, message } = await addArticleCommentAction({ ...data, articleId, commentId: commentId === articleId ? 0 : commentId, diff --git a/src/app/article/components/Like/index.tsx b/src/app/article/components/Like/index.tsx index 6103a6e..5518453 100644 --- a/src/app/article/components/Like/index.tsx +++ b/src/app/article/components/Like/index.tsx @@ -2,7 +2,7 @@ import { createContext, useContext, type ReactNode } from 'react'; import useDebouncedLike from '@/hooks/useDebouncedLike'; -import { likeArticleAPI } from '@/api/article'; +import { likeArticleAction } from '@/actions/article'; import LikeButtonCore from '@/components/LikeButton/LikeButtonCore'; interface ArticleLikeContextValue { @@ -27,7 +27,7 @@ export function ArticleLikeProvider({ initialCount?: number; children: ReactNode; }) { - const value = useDebouncedLike(articleId, initialCount, likeArticleAPI); + const value = useDebouncedLike(articleId, initialCount, likeArticleAction); return {children}; } diff --git a/src/app/friend/components/ApplyForAdd/index.tsx b/src/app/friend/components/ApplyForAdd/index.tsx index 9c7542a..cb3674e 100755 --- a/src/app/friend/components/ApplyForAdd/index.tsx +++ b/src/app/friend/components/ApplyForAdd/index.tsx @@ -13,7 +13,8 @@ import { } from '@/ThriveUI'; import { type SubmitHandler } from 'react-hook-form'; import { Web, WebType } from '@/types/app/web'; -import { addWebDataAPI, getWebTypeListAPI } from '@/api/web'; +import { addWebAction } from '@/actions/web'; +import { getWebTypeListAPI } from '@/api/web'; import { Bounce, toast, ToastOptions } from 'react-toastify'; import HCaptchaType from '@hcaptcha/react-hcaptcha'; import HCaptcha from '@/components/HCaptcha'; @@ -50,12 +51,6 @@ export default () => { }; useEffect(() => { - const message = localStorage.getItem('toastMessage'); - if (message) { - toast.success(message, toastConfig); - localStorage.removeItem('toastMessage'); - } - getWebTypeList(); }, []); @@ -68,7 +63,7 @@ export default () => { if (hasHCaptcha && !captchaToken) return setCaptchaError('请完成人机验证'); setLoading(true); - const { code, message } = await addWebDataAPI({ + const { code, message } = await addWebAction({ ...data, createTime: Date.now().toString(), h_captcha_response: captchaToken!, @@ -83,9 +78,9 @@ export default () => { setCaptchaError(''); setCaptchaToken(null); captchaRef.current?.resetCaptcha(); + methods.reset({} as Web); - localStorage.setItem('toastMessage', '🎉 提交成功, 请等待审核!'); - window.location.reload(); + toast.success('🎉 提交成功, 请等待审核!', toastConfig); onClose(); }; diff --git a/src/app/friend/page.tsx b/src/app/friend/page.tsx index f45f4a2..953684b 100755 --- a/src/app/friend/page.tsx +++ b/src/app/friend/page.tsx @@ -1,6 +1,7 @@ import { Metadata } from 'next'; -import { getWebListAPI, getWebTypeListAPI } from '@/api/web'; +import { getWebListCacheAPI } from '@/lib/web'; +import { getWebTypeListAPI } from '@/api/web'; import { Web as WebLink } from '@/types/app/web'; import Friend from './index'; @@ -11,7 +12,7 @@ export const metadata: Metadata = { }; export default async () => { - const linkRes = await getWebListAPI(); + const linkRes = await getWebListCacheAPI(); const typeRes = await getWebTypeListAPI(); const linkList = linkRes?.data ?? []; const typeList = typeRes?.data ?? []; diff --git a/src/app/record/components/Comment/index.tsx b/src/app/record/components/Comment/index.tsx index f69bae4..ccb987e 100755 --- a/src/app/record/components/Comment/index.tsx +++ b/src/app/record/components/Comment/index.tsx @@ -10,7 +10,8 @@ import { RiMessage3Line } from 'react-icons/ri'; import RandomAvatar from '@/components/RandomAvatar'; import HCaptcha from '@/components/HCaptcha'; import Show from '@/components/Show'; -import { addRecordCommentDataAPI, getRecordCommentListAPI } from '@/api/recordComment'; +import { addRecordCommentAction } from '@/actions/record'; +import { getRecordCommentListAPI } from '@/api/recordComment'; import { RecordComment } from '@/types/app/recordComment'; import { useAppConfig } from '@/components/AppConfigProvider'; @@ -122,7 +123,7 @@ export default function RecordCommentPanel({ recordId, onCountChange }: Props) { } } - const { code, message } = await addRecordCommentDataAPI({ + const { code, message } = await addRecordCommentAction({ ...data, recordId, commentId, diff --git a/src/app/record/components/RecordCard.tsx b/src/app/record/components/RecordCard.tsx index d8cac04..72da98e 100644 --- a/src/app/record/components/RecordCard.tsx +++ b/src/app/record/components/RecordCard.tsx @@ -5,7 +5,7 @@ import { RiChat3Line } from 'react-icons/ri'; import ImageList from './ImageList'; import RecordCommentPanel from './Comment'; import LikeButton from '@/components/LikeButton'; -import { likeRecordAPI } from '@/api/record'; +import { likeRecordAction } from '@/actions/record'; import { getRecordCommentListAPI } from '@/api/recordComment'; import { getRelativeTimeLabel } from '@/utils'; import { User } from '@/types/app/user'; @@ -73,7 +73,7 @@ export default function RecordCard({ id, content, images, likeCount, mood, locat
- +