From a9e649e110f65448dbca144e6a4eb776b3eff674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=8E=AB=E5=94=90=E5=B0=BC?= Date: Tue, 16 Jun 2026 00:43:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=82=B9=E8=B5=9E?= =?UTF-8?q?=E3=80=81=E6=B8=B8=E5=AE=A2=E8=AF=84=E8=AE=BA=E3=80=81=E5=88=86?= =?UTF-8?q?=E4=BA=AB=E7=AD=89=E6=A0=B8=E5=BF=83=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B5=E9=9D=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增全局点赞状态管理,使用metadata.name做key并持久化存储 2. 新增游客信息存储与评论面板,支持游客评论互动 3. 新增全局分享hook,为多个页面配置分享功能 4. 重构登录页面,支持登录/注册切换与游客访问模式 5. 合并注册页到登录页,简化路由结构 6. 优化剪贴板工具函数,支持自定义提示文本 7. 重构个人中心页面,支持游客信息管理 8. 修复相册页面标题与样式问题 9. 移除无用的备份文件与测试代码 --- docs/q1.md | 2 + src/api/halo-plugin/uni-halo.ts | 4 + .../post-detail/uh-guest-info-panel.vue | 137 +++++++ .../post-detail/uh-post-comment-panel.vue | 116 +++++- src/hooks/useShare.ts | 47 +++ src/pages/auth/login.vue | 370 +++++++++++++++++- src/pages/auth/register.vue | 30 -- src/pages/gallery/gallery-bak.vue | 348 ---------------- src/pages/gallery/gallery.vue | 18 +- src/pages/home/home.vue | 20 +- src/pages/links/links.vue | 14 +- src/pages/mine/mine.vue | 263 +++++++++---- src/pages/moments/moments.vue | 10 +- src/router/config.ts | 4 +- src/store/config.ts | 3 + src/store/guest.ts | 48 +++ src/store/upvote.ts | 47 +++ src/subpkg-blog/post-detail/post-detail.vue | 185 +++++---- src/utils/base/clipboard.ts | 8 +- 19 files changed, 1077 insertions(+), 597 deletions(-) create mode 100644 docs/q1.md create mode 100644 src/components/post-detail/uh-guest-info-panel.vue create mode 100644 src/hooks/useShare.ts delete mode 100644 src/pages/auth/register.vue delete mode 100644 src/pages/gallery/gallery-bak.vue create mode 100644 src/store/guest.ts create mode 100644 src/store/upvote.ts diff --git a/docs/q1.md b/docs/q1.md new file mode 100644 index 0000000..690531d --- /dev/null +++ b/docs/q1.md @@ -0,0 +1,2 @@ +我们需要全局缓存一个点赞的列表,使用 metadata.name 做key,存储到store并且开启持久化存储,如果已经点过赞,直接显示已 + 经点赞的样式。同时我们的点赞接口是不会返回内容的,所以再捕获异常的时候不要提示异常信息。 \ No newline at end of file diff --git a/src/api/halo-plugin/uni-halo.ts b/src/api/halo-plugin/uni-halo.ts index 85772da..8fc919f 100644 --- a/src/api/halo-plugin/uni-halo.ts +++ b/src/api/halo-plugin/uni-halo.ts @@ -1,6 +1,10 @@ import { http } from '@/http/alova' export interface IUniHaloConfig { + // 应用信息配置 + app: { + name: string + } base: { // 博客域名 domain: string diff --git a/src/components/post-detail/uh-guest-info-panel.vue b/src/components/post-detail/uh-guest-info-panel.vue new file mode 100644 index 0000000..e1712e2 --- /dev/null +++ b/src/components/post-detail/uh-guest-info-panel.vue @@ -0,0 +1,137 @@ + + + diff --git a/src/components/post-detail/uh-post-comment-panel.vue b/src/components/post-detail/uh-post-comment-panel.vue index c57b458..3396361 100644 --- a/src/components/post-detail/uh-post-comment-panel.vue +++ b/src/components/post-detail/uh-post-comment-panel.vue @@ -2,8 +2,11 @@ import { createComment, createReply, listCommentReplies, listComments } from '@/api/halo-base/comment' import { avatar } from '@/utils/imageHelper' import { timeFrom } from '@/utils/base/timeFrom' +import { useGuestStore } from '@/store/guest' +import { useUpvoteStore } from '@/store/upvote' import type { CommentV1alpha1PublicApiListCommentRepliesRequest, CommentV1alpha1PublicApiListComments1Request, CommentWithReplyVo, ReplyVo } from '@halo-dev/api-client' import type { IHaloListResponseBase } from '@/api/types/halo' +import UhGuestInfoPanel from './uh-guest-info-panel.vue' interface IProps { postName: string @@ -20,6 +23,9 @@ const emits = defineEmits<{ (e: 'commented'): void }>() +const guestStore = useGuestStore() +const upvoteStore = useUpvoteStore() + // --- 评论列表 --- const commentList = ref([]) const commentPage = ref(1) @@ -44,6 +50,26 @@ const replyLoadingMap = ref>({}) const replyHasNextMap = ref>({}) const replyPageMap = ref>({}) +// --- 游客信息面板 --- +const showGuestPanel = ref(false) + +// --- 点赞(切换) --- +async function handleUpvote(name: string) { + const nowUpvoted = await upvoteStore.toggle(name, 'comments') + // 更新本地计数 + for (const comment of commentList.value) { + if (comment.metadata.name === name) { + comment.stats.upvote = Math.max(0, (comment.stats.upvote ?? 0) + (nowUpvoted ? 1 : -1)) + break + } + const reply = comment.replies?.items?.find(r => r.metadata.name === name) + if (reply) { + reply.stats.upvote = Math.max(0, (reply.stats.upvote ?? 0) + (nowUpvoted ? 1 : -1)) + break + } + } +} + // --- 获取评论列表 --- async function fetchComments(page = 1, append = false) { commentLoading.value = true @@ -152,13 +178,29 @@ function handleCancelReply() { } // --- 提交评论/回复 --- -async function handleSubmit() { +function handleSubmit() { const text = inputText.value.trim() if (!text || submitLoading.value) return + // 检查游客信息,未设置直接弹出面板 + if (!guestStore.isComplete) { + showGuestPanel.value = true + return + } + + doSubmit(text) +} + +async function doSubmit(text: string) { submitLoading.value = true try { + const owner = { + displayName: guestStore.info.displayName, + email: guestStore.info.email, + website: guestStore.info.website || undefined, + } + if (replyTarget.value) { await createReply({ name: replyTarget.value.commentName, @@ -167,6 +209,7 @@ async function handleSubmit() { raw: text, quoteReply: replyTarget.value.replyName || undefined, allowNotification: true, + owner, }, } as any) } @@ -182,6 +225,8 @@ async function handleSubmit() { version: props.commentSubjectVersion, }, allowNotification: true, + hidden: false, + owner, }, } as any) } @@ -201,6 +246,16 @@ async function handleSubmit() { } } +// --- 游客信息保存后自动提交 --- +function handleGuestSaved() { + showGuestPanel.value = false + // 保存后如果有输入内容,自动提交 + const text = inputText.value.trim() + if (text) { + doSubmit(text) + } +} + // --- 查找被引用的回复 --- function findQuotedReply(comment: CommentWithReplyVo, quoteReplyName: string): ReplyVo | undefined { return comment.replies?.items?.find(r => r.metadata.name === quoteReplyName) @@ -291,6 +346,24 @@ onMounted(() => { + + + + + {{ comment.stats.upvote || '' }} + + + { 回复 + { - - - 回复 + + + + + + + {{ reply.stats.upvote || '' }} + + + + + + 回复 + @@ -422,4 +517,11 @@ onMounted(() => { + + + diff --git a/src/hooks/useShare.ts b/src/hooks/useShare.ts new file mode 100644 index 0000000..0219189 --- /dev/null +++ b/src/hooks/useShare.ts @@ -0,0 +1,47 @@ +import { storeToRefs } from 'pinia' +import { useUniHaloConfigStore } from '@/store/config' + +export interface IShareAppMessageOption { + title?: string + path: string + query?: string + imageUrl?: string + onlyAppNameTitle?: boolean +} + +/** + * 应用分享 + */ +export function useAppShare() { + const { config } = storeToRefs(useUniHaloConfigStore()) + + const setShareOptions = (options: IShareAppMessageOption) => { + const { onlyAppNameTitle = false } = options + if (!options.path) { + return + } + + const title = onlyAppNameTitle ? config.value.app.name : options.title + + onShareAppMessage(() => { + return { + title, + path: options.path + (options.query ? `?${options.query}` : ''), + imageUrl: options.imageUrl, + } + }) + + onShareTimeline(() => { + return { + title, + path: options.path, + imageUrl: options.imageUrl, + query: options.query, + } + }) + } + + return { + setShareOptions, + } +} diff --git a/src/pages/auth/login.vue b/src/pages/auth/login.vue index ecdfe74..6821304 100644 --- a/src/pages/auth/login.vue +++ b/src/pages/auth/login.vue @@ -1,40 +1,378 @@ diff --git a/src/pages/auth/register.vue b/src/pages/auth/register.vue deleted file mode 100644 index 767097c..0000000 --- a/src/pages/auth/register.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/src/pages/gallery/gallery-bak.vue b/src/pages/gallery/gallery-bak.vue deleted file mode 100644 index 3c233ae..0000000 --- a/src/pages/gallery/gallery-bak.vue +++ /dev/null @@ -1,348 +0,0 @@ - - - diff --git a/src/pages/gallery/gallery.vue b/src/pages/gallery/gallery.vue index 05813b2..7b5d7ef 100644 --- a/src/pages/gallery/gallery.vue +++ b/src/pages/gallery/gallery.vue @@ -1,9 +1,10 @@