From dd3c670021372fbe5f26049090fc2432736e4a14 Mon Sep 17 00:00:00 2001 From: cheng <545895878@qq.com> Date: Thu, 10 Sep 2026 21:43:46 +0800 Subject: [PATCH] feat: add guest mode and optimize login experience MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 针对微信审核要求新增游客浏览模式,用户可无需登录直接浏览应用内容,仅在使用发布、点赞、记录等需要身份的功能时才弹窗引导登录。具体修改包括: 1. 新增游客态判断工具函数与登录守卫逻辑 2. 为登录页添加游客直接进入入口 3. 为首页、酒友圈、个人页、动态页、记录页添加游客适配逻辑 4. 优化登录态失效处理逻辑,不再强制跳转登录页 5. 调整部分页面的返回逻辑适配分享直接进入场景 6. 为各页面添加游客引导UI与交互 --- common/api.js | 47 +++++++++------ pages.json | 7 ++- pages/circle-detail/circle-detail.vue | 24 +++++++- pages/circle/circle.vue | 29 ++++++--- pages/index/index.vue | 84 ++++++++++++++++++++++++++- pages/login/login.vue | 58 ++++++++++++++++-- pages/profile/profile.vue | 74 ++++++++++++++++++++--- pages/record/record.vue | 22 ++++++- pages/share-profile/share-profile.vue | 8 ++- 9 files changed, 307 insertions(+), 46 deletions(-) diff --git a/common/api.js b/common/api.js index ea31dc6..4489cac 100644 --- a/common/api.js +++ b/common/api.js @@ -10,19 +10,35 @@ import UniAppWebSocket from './uni-websocket' export const API_HOST = 'https://dev.wash-painting.cn' // ========================================== -// 401 跳登录页防重锁:token 失效时多个接口会同时返回 401, -// 各自 reLaunch 会并发冲突导致 reLaunch:fail timeout,只放行第一次 +// 登录态工具(微信审核要求:不得在浏览时强制登录) +// 游客可直接浏览首页/酒友圈等公开内容,仅在用户主动使用 +// 记录、发布、点赞等需要身份的功能时,才弹窗由其自行选择是否登录。 // ========================================== -let authRedirectLock = false -function redirectToLogin() { - if (authRedirectLock) return - authRedirectLock = true - setTimeout(() => { authRedirectLock = false }, 3000) - const pages = getCurrentPages() - const current = pages.length ? pages[pages.length - 1].route : '' - // 已在登录页则不重复跳转 - if (current === 'pages/login/login') return - uni.reLaunch({ url: '/pages/login/login', fail: () => {} }) + +/** 判断当前是否已登录(本地降级登录也算登录态) */ +export function isLoggedIn() { + return uni.getStorageSync('is_logged_in') === 'true' +} + +/** + * 需要登录才能使用的功能入口守卫。 + * 已登录直接放行;未登录弹窗询问,用户可取消继续浏览(不强制)。 + * @returns {boolean} 是否已登录 + */ +export function requireLogin() { + if (isLoggedIn()) return true + uni.showModal({ + title: '登录提示', + content: '该功能需要登录后使用,登录后记录可云端同步,是否立即登录?', + confirmText: '去登录', + cancelText: '再看看', + success: (res) => { + if (res.confirm) { + uni.navigateTo({ url: '/pages/login/login', fail: () => {} }) + } + } + }) + return false } // ========================================== @@ -60,14 +76,11 @@ function httpRequest(url, params) { } resolve(res.data) } else if (code === 401 ) { - // token/refresh_token 过期或无效,清除登录态 + // token/refresh_token 过期或无效:仅静默清除登录态并 reject, + // 不强制跳转登录页(游客可继续浏览),后续写操作由 requireLogin 引导 uni.removeStorageSync('auth_token') uni.removeStorageSync('refresh_token') uni.removeStorageSync('is_logged_in') - if (!silent) { - redirectToLogin() - uni.showToast({ title: '登录已过期,请重新登录', icon: 'none', duration: 2500 }) - } reject({ msg: '登录已过期,请重新登录', code }) } else { const rawMsg = (res.data && res.data.msg) || (res.data && res.data.errmsg) || '请求失败' diff --git a/pages.json b/pages.json index f744b97..58a1f3a 100644 --- a/pages.json +++ b/pages.json @@ -53,7 +53,12 @@ "path": "pages/circle/circle", "style": { "navigationStyle": "custom", - "navigationBarTitleText": "" + "navigationBarTitleText": "", + "app-plus": { + "background": "#0B0B14", + "bounceBackground": "#0B0B14", + "animationAlphaBGColor": "#0B0B14" + } } }, { diff --git a/pages/circle-detail/circle-detail.vue b/pages/circle-detail/circle-detail.vue index 19304ae..8124c65 100644 --- a/pages/circle-detail/circle-detail.vue +++ b/pages/circle-detail/circle-detail.vue @@ -65,7 +65,7 @@ import FeedCard from '../../components/FeedCard.vue' import CommentItem from '../../components/CommentItem.vue' import EmptyState from '../../components/EmptyState.vue' -import { GetFeedComments, AddComment, LikeFeed, UnlikeFeed, DeleteFeed } from '../../common/api' +import { GetFeedComments, AddComment, LikeFeed, UnlikeFeed, DeleteFeed, requireLogin } from '../../common/api' import themeMixin from '../../common/theme-mixin' export default { @@ -93,7 +93,23 @@ export default { }, methods: { goBack() { - uni.navigateBack() + // 分享落地场景:本页是页面栈中唯一页面(好友直接从分享卡片进入,未经过首页), + // navigateBack 无页面可退,此时直接回首页 + if (getCurrentPages().length > 1) { + uni.navigateBack({ + fail: () => { + uni.switchTab({ + url: '/pages/index/index', + fail: () => uni.reLaunch({ url: '/pages/index/index' }) + }) + } + }) + } else { + uni.switchTab({ + url: '/pages/index/index', + fail: () => uni.reLaunch({ url: '/pages/index/index' }) + }) + } }, async loadFeed() { // 优先从 globalData 中查找对应动态 @@ -127,6 +143,7 @@ export default { } }, async handleLike(feed) { + if (!requireLogin()) return feed.liked = !feed.liked feed.likes += feed.liked ? 1 : -1 try { @@ -160,7 +177,7 @@ export default { try { await DeleteFeed({ feedId: feed.id }) uni.showToast({ title: '已删除', icon: 'none' }) - setTimeout(() => uni.navigateBack(), 600) + setTimeout(() => this.goBack(), 600) } catch (e) { // httpRequest 已全局弹错误提示(如非本人动态后端会拒绝) } @@ -170,6 +187,7 @@ export default { async submitComment() { const text = this.commentText.trim() if (!text) return + if (!requireLogin()) return try { await AddComment({ feedId: this.feedId, content: text }) this.comments.push({ diff --git a/pages/circle/circle.vue b/pages/circle/circle.vue index c24e4d8..deb7a30 100644 --- a/pages/circle/circle.vue +++ b/pages/circle/circle.vue @@ -63,10 +63,10 @@ @@ -78,7 +78,7 @@ import FeedCard from '../../components/FeedCard.vue' import FriendItem from '../../components/FriendItem.vue' import EventCard from '../../components/EventCard.vue' import EmptyState from '../../components/EmptyState.vue' -import { GetCircleFeeds, LikeFeed, UnlikeFeed, DeleteFeed, GetFriends, GetFriendRequests, GetEvents, DeleteEvent, GetUnreadCount } from '../../common/api' +import { GetCircleFeeds, LikeFeed, UnlikeFeed, DeleteFeed, GetFriends, GetFriendRequests, GetEvents, DeleteEvent, GetUnreadCount, isLoggedIn, requireLogin } from '../../common/api' import wsManager from '../../common/websocket' import { getMyInviteCode } from '../../common/invite' import themeMixin from '../../common/theme-mixin' @@ -114,11 +114,20 @@ export default { // 我的邀请码(分享时携带,一次性) inviteCode: '', // 当前登录用户ID(用于判断动态是否为自己发布) - myUserId: '' + myUserId: '', + // 游客标记:游客可浏览页面,互动时再引导登录 + isGuest: false } }, onShow() { - this.loadFeeds(true) + this.isGuest = !isLoggedIn() + if (this.isGuest) { + // 游客态不发起鉴权请求,展示空态与登录引导 + this.feeds = [] + this.loading = false + } else { + this.loadFeeds(true) + } // 消息入口已隐藏,未读角标暂不展示,空转请求先停掉(恢复入口时打开) // this.loadUnread() // this.bindWsEvents() @@ -212,6 +221,7 @@ export default { } }, async handleLike(feed) { + if (!requireLogin()) return feed.liked = !feed.liked feed.likes += feed.liked ? 1 : -1 try { @@ -266,8 +276,13 @@ export default { }) }, goPublish() { + if (!requireLogin()) return uni.navigateTo({ url: '/pages/circle-publish/circle-publish' }) }, + // 游客在空态点击"去登录" + goLogin() { + uni.navigateTo({ url: '/pages/login/login' }) + }, // === 酒友 === async loadFriends() { try { diff --git a/pages/index/index.vue b/pages/index/index.vue index d2816a1..b43bf85 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -8,6 +8,15 @@ + + + + 登录后开启完整记录 + 云端同步 · 成就徽章 · 酒友互动 + + 去登录 + + @@ -139,7 +148,7 @@