feat: add guest mode and optimize login experience
针对微信审核要求新增游客浏览模式,用户可无需登录直接浏览应用内容,仅在使用发布、点赞、记录等需要身份的功能时才弹窗引导登录。具体修改包括: 1. 新增游客态判断工具函数与登录守卫逻辑 2. 为登录页添加游客直接进入入口 3. 为首页、酒友圈、个人页、动态页、记录页添加游客适配逻辑 4. 优化登录态失效处理逻辑,不再强制跳转登录页 5. 调整部分页面的返回逻辑适配分享直接进入场景 6. 为各页面添加游客引导UI与交互
This commit is contained in:
+30
-17
@@ -10,19 +10,35 @@ import UniAppWebSocket from './uni-websocket'
|
|||||||
export const API_HOST = 'https://dev.wash-painting.cn'
|
export const API_HOST = 'https://dev.wash-painting.cn'
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 401 跳登录页防重锁:token 失效时多个接口会同时返回 401,
|
// 登录态工具(微信审核要求:不得在浏览时强制登录)
|
||||||
// 各自 reLaunch 会并发冲突导致 reLaunch:fail timeout,只放行第一次
|
// 游客可直接浏览首页/酒友圈等公开内容,仅在用户主动使用
|
||||||
|
// 记录、发布、点赞等需要身份的功能时,才弹窗由其自行选择是否登录。
|
||||||
// ==========================================
|
// ==========================================
|
||||||
let authRedirectLock = false
|
|
||||||
function redirectToLogin() {
|
/** 判断当前是否已登录(本地降级登录也算登录态) */
|
||||||
if (authRedirectLock) return
|
export function isLoggedIn() {
|
||||||
authRedirectLock = true
|
return uni.getStorageSync('is_logged_in') === '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: () => {} })
|
* @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)
|
resolve(res.data)
|
||||||
} else if (code === 401 ) {
|
} else if (code === 401 ) {
|
||||||
// token/refresh_token 过期或无效,清除登录态
|
// token/refresh_token 过期或无效:仅静默清除登录态并 reject,
|
||||||
|
// 不强制跳转登录页(游客可继续浏览),后续写操作由 requireLogin 引导
|
||||||
uni.removeStorageSync('auth_token')
|
uni.removeStorageSync('auth_token')
|
||||||
uni.removeStorageSync('refresh_token')
|
uni.removeStorageSync('refresh_token')
|
||||||
uni.removeStorageSync('is_logged_in')
|
uni.removeStorageSync('is_logged_in')
|
||||||
if (!silent) {
|
|
||||||
redirectToLogin()
|
|
||||||
uni.showToast({ title: '登录已过期,请重新登录', icon: 'none', duration: 2500 })
|
|
||||||
}
|
|
||||||
reject({ msg: '登录已过期,请重新登录', code })
|
reject({ msg: '登录已过期,请重新登录', code })
|
||||||
} else {
|
} else {
|
||||||
const rawMsg = (res.data && res.data.msg) || (res.data && res.data.errmsg) || '请求失败'
|
const rawMsg = (res.data && res.data.msg) || (res.data && res.data.errmsg) || '请求失败'
|
||||||
|
|||||||
+6
-1
@@ -53,7 +53,12 @@
|
|||||||
"path": "pages/circle/circle",
|
"path": "pages/circle/circle",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": ""
|
"navigationBarTitleText": "",
|
||||||
|
"app-plus": {
|
||||||
|
"background": "#0B0B14",
|
||||||
|
"bounceBackground": "#0B0B14",
|
||||||
|
"animationAlphaBGColor": "#0B0B14"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
import FeedCard from '../../components/FeedCard.vue'
|
import FeedCard from '../../components/FeedCard.vue'
|
||||||
import CommentItem from '../../components/CommentItem.vue'
|
import CommentItem from '../../components/CommentItem.vue'
|
||||||
import EmptyState from '../../components/EmptyState.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'
|
import themeMixin from '../../common/theme-mixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -93,7 +93,23 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
goBack() {
|
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() {
|
async loadFeed() {
|
||||||
// 优先从 globalData 中查找对应动态
|
// 优先从 globalData 中查找对应动态
|
||||||
@@ -127,6 +143,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async handleLike(feed) {
|
async handleLike(feed) {
|
||||||
|
if (!requireLogin()) return
|
||||||
feed.liked = !feed.liked
|
feed.liked = !feed.liked
|
||||||
feed.likes += feed.liked ? 1 : -1
|
feed.likes += feed.liked ? 1 : -1
|
||||||
try {
|
try {
|
||||||
@@ -160,7 +177,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
await DeleteFeed({ feedId: feed.id })
|
await DeleteFeed({ feedId: feed.id })
|
||||||
uni.showToast({ title: '已删除', icon: 'none' })
|
uni.showToast({ title: '已删除', icon: 'none' })
|
||||||
setTimeout(() => uni.navigateBack(), 600)
|
setTimeout(() => this.goBack(), 600)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// httpRequest 已全局弹错误提示(如非本人动态后端会拒绝)
|
// httpRequest 已全局弹错误提示(如非本人动态后端会拒绝)
|
||||||
}
|
}
|
||||||
@@ -170,6 +187,7 @@ export default {
|
|||||||
async submitComment() {
|
async submitComment() {
|
||||||
const text = this.commentText.trim()
|
const text = this.commentText.trim()
|
||||||
if (!text) return
|
if (!text) return
|
||||||
|
if (!requireLogin()) return
|
||||||
try {
|
try {
|
||||||
await AddComment({ feedId: this.feedId, content: text })
|
await AddComment({ feedId: this.feedId, content: text })
|
||||||
this.comments.push({
|
this.comments.push({
|
||||||
|
|||||||
+21
-6
@@ -63,10 +63,10 @@
|
|||||||
<EmptyState
|
<EmptyState
|
||||||
v-if="!feeds.length && !loading"
|
v-if="!feeds.length && !loading"
|
||||||
icon="🍻"
|
icon="🍻"
|
||||||
title="还没有动态"
|
:title="isGuest ? '登录后查看酒友动态' : '还没有动态'"
|
||||||
desc="发布你的第一条饮酒动态吧"
|
:desc="isGuest ? '浏览酒友分享、发布你的饮酒记录' : '发布你的第一条饮酒动态吧'"
|
||||||
actionText="发动态"
|
:actionText="isGuest ? '去登录' : '发动态'"
|
||||||
@action="goPublish"
|
@action="isGuest ? goLogin : goPublish"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
@@ -78,7 +78,7 @@ import FeedCard from '../../components/FeedCard.vue'
|
|||||||
import FriendItem from '../../components/FriendItem.vue'
|
import FriendItem from '../../components/FriendItem.vue'
|
||||||
import EventCard from '../../components/EventCard.vue'
|
import EventCard from '../../components/EventCard.vue'
|
||||||
import EmptyState from '../../components/EmptyState.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 wsManager from '../../common/websocket'
|
||||||
import { getMyInviteCode } from '../../common/invite'
|
import { getMyInviteCode } from '../../common/invite'
|
||||||
import themeMixin from '../../common/theme-mixin'
|
import themeMixin from '../../common/theme-mixin'
|
||||||
@@ -114,11 +114,20 @@ export default {
|
|||||||
// 我的邀请码(分享时携带,一次性)
|
// 我的邀请码(分享时携带,一次性)
|
||||||
inviteCode: '',
|
inviteCode: '',
|
||||||
// 当前登录用户ID(用于判断动态是否为自己发布)
|
// 当前登录用户ID(用于判断动态是否为自己发布)
|
||||||
myUserId: ''
|
myUserId: '',
|
||||||
|
// 游客标记:游客可浏览页面,互动时再引导登录
|
||||||
|
isGuest: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onShow() {
|
onShow() {
|
||||||
|
this.isGuest = !isLoggedIn()
|
||||||
|
if (this.isGuest) {
|
||||||
|
// 游客态不发起鉴权请求,展示空态与登录引导
|
||||||
|
this.feeds = []
|
||||||
|
this.loading = false
|
||||||
|
} else {
|
||||||
this.loadFeeds(true)
|
this.loadFeeds(true)
|
||||||
|
}
|
||||||
// 消息入口已隐藏,未读角标暂不展示,空转请求先停掉(恢复入口时打开)
|
// 消息入口已隐藏,未读角标暂不展示,空转请求先停掉(恢复入口时打开)
|
||||||
// this.loadUnread()
|
// this.loadUnread()
|
||||||
// this.bindWsEvents()
|
// this.bindWsEvents()
|
||||||
@@ -212,6 +221,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async handleLike(feed) {
|
async handleLike(feed) {
|
||||||
|
if (!requireLogin()) return
|
||||||
feed.liked = !feed.liked
|
feed.liked = !feed.liked
|
||||||
feed.likes += feed.liked ? 1 : -1
|
feed.likes += feed.liked ? 1 : -1
|
||||||
try {
|
try {
|
||||||
@@ -266,8 +276,13 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
goPublish() {
|
goPublish() {
|
||||||
|
if (!requireLogin()) return
|
||||||
uni.navigateTo({ url: '/pages/circle-publish/circle-publish' })
|
uni.navigateTo({ url: '/pages/circle-publish/circle-publish' })
|
||||||
},
|
},
|
||||||
|
// 游客在空态点击"去登录"
|
||||||
|
goLogin() {
|
||||||
|
uni.navigateTo({ url: '/pages/login/login' })
|
||||||
|
},
|
||||||
// === 酒友 ===
|
// === 酒友 ===
|
||||||
async loadFriends() {
|
async loadFriends() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+83
-1
@@ -8,6 +8,15 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 游客登录引导条(非阻断,可继续浏览;登录由用户自行选择) -->
|
||||||
|
<view v-if="isGuest" class="guest-banner" @click="goLogin">
|
||||||
|
<view class="guest-banner-info">
|
||||||
|
<text class="guest-banner-title">登录后开启完整记录</text>
|
||||||
|
<text class="guest-banner-desc">云端同步 · 成就徽章 · 酒友互动</text>
|
||||||
|
</view>
|
||||||
|
<text class="guest-banner-btn">去登录</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 核心CTA - 首页最醒目位置 -->
|
<!-- 核心CTA - 首页最醒目位置 -->
|
||||||
<view class="hero-cta" @click="goRecord">
|
<view class="hero-cta" @click="goRecord">
|
||||||
<view class="hero-cta-bg"></view>
|
<view class="hero-cta-bg"></view>
|
||||||
@@ -139,7 +148,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DrinkCalendar from '../../components/DrinkCalendar.vue'
|
import DrinkCalendar from '../../components/DrinkCalendar.vue'
|
||||||
import client from '../../common/api'
|
import client, { isLoggedIn, requireLogin } from '../../common/api'
|
||||||
import { GetCalendarReq, DeleteRecordReq, CreateRecordReq, GetRecordDetailReq } from 'HaveADrink'
|
import { GetCalendarReq, DeleteRecordReq, CreateRecordReq, GetRecordDetailReq } from 'HaveADrink'
|
||||||
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath, calcLocalStreak } from '../../common/utils'
|
import { getGreeting, formatDate, getWeekStart, getCatIcon, isIconPath, calcLocalStreak } from '../../common/utils'
|
||||||
import { FEELINGS, DRINK_CATEGORIES, DRINK_UNITS } from '../../common/constants'
|
import { FEELINGS, DRINK_CATEGORIES, DRINK_UNITS } from '../../common/constants'
|
||||||
@@ -196,6 +205,13 @@ export default {
|
|||||||
if (isFirst === 'true') {
|
if (isFirst === 'true') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 游客可直接浏览首页:不发起鉴权请求,展示空数据;
|
||||||
|
// 仅在用户主动点击记录等功能时才引导登录(微信审核要求:先浏览后登录)
|
||||||
|
this.isGuest = !isLoggedIn()
|
||||||
|
if (this.isGuest) {
|
||||||
|
this.initGuestView()
|
||||||
|
return
|
||||||
|
}
|
||||||
this.loadData()
|
this.loadData()
|
||||||
},
|
},
|
||||||
onShareAppMessage() {
|
onShareAppMessage() {
|
||||||
@@ -211,6 +227,26 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// 游客浏览视图:问候语与零数据,页面结构可完整浏览,不发起任何鉴权请求
|
||||||
|
initGuestView() {
|
||||||
|
this.greeting = getGreeting()
|
||||||
|
this.userName = '酒友'
|
||||||
|
this.records = []
|
||||||
|
this.stats = {
|
||||||
|
weekDrinkCount: 0,
|
||||||
|
weekCups: 0,
|
||||||
|
monthDrinkCount: 0,
|
||||||
|
monthCups: 0,
|
||||||
|
streak: 0,
|
||||||
|
streakType: 'drank',
|
||||||
|
drankStreak: 0,
|
||||||
|
abstainStreak: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 游客主动点击"去登录"
|
||||||
|
goLogin() {
|
||||||
|
uni.navigateTo({ url: '/pages/login/login' })
|
||||||
|
},
|
||||||
async loadData() {
|
async loadData() {
|
||||||
this.greeting = getGreeting()
|
this.greeting = getGreeting()
|
||||||
// 并行加载用户信息、统计概览、记录列表
|
// 并行加载用户信息、统计概览、记录列表
|
||||||
@@ -436,14 +472,17 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
goRecord() {
|
goRecord() {
|
||||||
|
if (!requireLogin()) return
|
||||||
uni.navigateTo({ url: '/pages/record/record' })
|
uni.navigateTo({ url: '/pages/record/record' })
|
||||||
},
|
},
|
||||||
goRecordToday() {
|
goRecordToday() {
|
||||||
|
if (!requireLogin()) return
|
||||||
this.showDayDetail = false
|
this.showDayDetail = false
|
||||||
uni.navigateTo({ url: '/pages/record/record' })
|
uni.navigateTo({ url: '/pages/record/record' })
|
||||||
},
|
},
|
||||||
// 标记为未饮酒(直接创建 abstain 记录)
|
// 标记为未饮酒(直接创建 abstain 记录)
|
||||||
async markAbstain() {
|
async markAbstain() {
|
||||||
|
if (!requireLogin()) return
|
||||||
const recordData = {
|
const recordData = {
|
||||||
date: this.selectedDate,
|
date: this.selectedDate,
|
||||||
mode: 'abstain',
|
mode: 'abstain',
|
||||||
@@ -497,6 +536,49 @@ export default {
|
|||||||
margin-top: 4rpx;
|
margin-top: 4rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 游客登录引导条(非阻断) */
|
||||||
|
.guest-banner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $sp-md $sp-lg;
|
||||||
|
margin-bottom: $sp-md;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
background: rgba(232, 168, 56, 0.08);
|
||||||
|
border: 2rpx solid rgba(232, 168, 56, 0.25);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: rgba(232, 168, 56, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-banner-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-banner-title {
|
||||||
|
font-size: $fs-sm;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
color: $amber;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-banner-desc {
|
||||||
|
font-size: $fs-xs;
|
||||||
|
color: $text-tertiary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-banner-btn {
|
||||||
|
font-size: $fs-sm;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
color: $text-on-amber;
|
||||||
|
background: linear-gradient(135deg, $amber-light, $amber-deep);
|
||||||
|
padding: $sp-xs $sp-lg;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.calendar-section {
|
.calendar-section {
|
||||||
margin-bottom: $sp-md;
|
margin-bottom: $sp-md;
|
||||||
padding: $sp-md;
|
padding: $sp-md;
|
||||||
|
|||||||
+52
-6
@@ -78,12 +78,17 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部协议(非登录状态时显示) -->
|
<!-- 游客模式入口:不强制登录,可先进首页浏览体验,需要时再自行登录 -->
|
||||||
|
<view class="guest-entry" @click="enterGuest">
|
||||||
|
<text class="guest-entry-text">暂不登录,先逛逛</text>
|
||||||
|
<text class="guest-entry-arrow">›</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部协议查阅入口(仅提供查看,不构成默认同意;是否同意由用户在下一屏主动勾选) -->
|
||||||
<view v-if="showNotice" class="agreement">
|
<view v-if="showNotice" class="agreement">
|
||||||
<text class="text-tiny">登录即代表同意</text>
|
<text class="text-tiny agreement-link" @click="openAgreement('user')">《用户协议》</text>
|
||||||
<text class="text-tiny text-amber" @click="openAgreement('user')">《用户协议》</text>
|
<text class="text-tiny agreement-dot">·</text>
|
||||||
<text class="text-tiny">和</text>
|
<text class="text-tiny agreement-link" @click="openAgreement('privacy')">《隐私政策》</text>
|
||||||
<text class="text-tiny text-amber" @click="openAgreement('privacy')">《隐私政策》</text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -123,6 +128,13 @@ export default {
|
|||||||
this.showNotice = false
|
this.showNotice = false
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 游客模式:不登录直接进入首页浏览(微信审核要求:先体验功能,登录由用户自行选择)
|
||||||
|
enterGuest() {
|
||||||
|
uni.setStorageSync('is_first_launch', 'false')
|
||||||
|
uni.setStorageSync('is_guest', 'true')
|
||||||
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
|
},
|
||||||
|
|
||||||
// ===== 微信新规范:头像选择 =====
|
// ===== 微信新规范:头像选择 =====
|
||||||
// chooseAvatar 返回的是 wxfile://tmp_ 本地临时路径(微信随时会清理、仅本机有效),
|
// chooseAvatar 返回的是 wxfile://tmp_ 本地临时路径(微信随时会清理、仅本机有效),
|
||||||
// 上传接口需要登录 token,而选头像时还未登录,因此这里只暂存临时路径,
|
// 上传接口需要登录 token,而选头像时还未登录,因此这里只暂存临时路径,
|
||||||
@@ -529,12 +541,46 @@ export default {
|
|||||||
color: $text-tertiary;
|
color: $text-tertiary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 底部协议 */
|
/* 游客入口 */
|
||||||
|
.guest-entry {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4rpx;
|
||||||
|
padding: $sp-md 0;
|
||||||
|
margin-top: auto;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-entry-text {
|
||||||
|
font-size: $fs-sm;
|
||||||
|
color: $text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-entry-arrow {
|
||||||
|
font-size: $fs-md;
|
||||||
|
color: $text-secondary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部协议查阅入口 */
|
||||||
.agreement {
|
.agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
gap: $sp-xs;
|
gap: $sp-xs;
|
||||||
padding: $sp-sm 0;
|
padding: $sp-sm 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.agreement-link {
|
||||||
|
color: $text-tertiary;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.agreement-dot {
|
||||||
|
color: $text-tertiary;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -173,7 +173,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import AchievementBadge from '../../components/AchievementBadge.vue'
|
import AchievementBadge from '../../components/AchievementBadge.vue'
|
||||||
import client, { clearAuth, GetAchievements } from '../../common/api'
|
import client, { clearAuth, GetAchievements, isLoggedIn, requireLogin } from '../../common/api'
|
||||||
import { checkAchievements, getCatIcon, isIconPath, calcLocalStreak, isValidAvatar } from '../../common/utils'
|
import { checkAchievements, getCatIcon, isIconPath, calcLocalStreak, isValidAvatar } from '../../common/utils'
|
||||||
import { ACHIEVEMENTS, DRINK_CATEGORIES } from '../../common/constants'
|
import { ACHIEVEMENTS, DRINK_CATEGORIES } from '../../common/constants'
|
||||||
import themeMixin from '../../common/theme-mixin'
|
import themeMixin from '../../common/theme-mixin'
|
||||||
@@ -391,16 +391,12 @@ export default {
|
|||||||
uni.switchTab({ url: '/pages/index/index' })
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
},
|
},
|
||||||
goRecord() {
|
goRecord() {
|
||||||
|
if (!requireLogin()) return
|
||||||
uni.navigateTo({ url: '/pages/record/record' })
|
uni.navigateTo({ url: '/pages/record/record' })
|
||||||
},
|
},
|
||||||
checkLoginState() {
|
checkLoginState() {
|
||||||
const isLoggedIn = uni.getStorageSync('is_logged_in')
|
// 微信审核要求:游客可停留在"我的"页浏览,不强制跳转登录,仅展示登录入口
|
||||||
const isGuest = uni.getStorageSync('is_guest')
|
this.isGuest = !isLoggedIn()
|
||||||
if (!isLoggedIn || isLoggedIn !== 'true') {
|
|
||||||
uni.reLaunch({ url: '/pages/login/login' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.isGuest = isGuest === 'true'
|
|
||||||
},
|
},
|
||||||
handleLogout() {
|
handleLogout() {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
@@ -411,7 +407,10 @@ export default {
|
|||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.confirm) {
|
if (res.confirm) {
|
||||||
clearAuth()
|
clearAuth()
|
||||||
uni.reLaunch({ url: '/pages/login/login' })
|
// 退出后以游客身份留在当前页继续浏览,不强制跳登录
|
||||||
|
this.isGuest = true
|
||||||
|
this.loadData()
|
||||||
|
uni.showToast({ title: '已退出登录', icon: 'none' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -437,6 +436,63 @@ export default {
|
|||||||
padding-bottom: calc(env(safe-area-inset-bottom) + 40rpx);
|
padding-bottom: calc(env(safe-area-inset-bottom) + 40rpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 游客登录引导卡片 */
|
||||||
|
.guest-login-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $sp-md;
|
||||||
|
margin: 0 $sp-lg $sp-md;
|
||||||
|
padding: $sp-md $sp-lg;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
background: rgba(232, 168, 56, 0.08);
|
||||||
|
border: 2rpx solid rgba(232, 168, 56, 0.25);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: rgba(232, 168, 56, 0.14);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-login-icon {
|
||||||
|
width: 72rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
background: $bg-card;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 40rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-login-text {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4rpx;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-login-title {
|
||||||
|
font-size: $fs-sm;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
color: $text-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-login-desc {
|
||||||
|
font-size: $fs-xs;
|
||||||
|
color: $text-tertiary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guest-login-btn {
|
||||||
|
font-size: $fs-sm;
|
||||||
|
font-weight: $fw-bold;
|
||||||
|
color: $text-on-amber;
|
||||||
|
background: linear-gradient(135deg, $amber-light, $amber-deep);
|
||||||
|
padding: $sp-xs $sp-lg;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* === 沉浸式头部 === */
|
/* === 沉浸式头部 === */
|
||||||
.hero-header {
|
.hero-header {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
+21
-1
@@ -346,7 +346,7 @@ import {
|
|||||||
FEELINGS, VISIBILITY_OPTIONS
|
FEELINGS, VISIBILITY_OPTIONS
|
||||||
} from '../../common/constants'
|
} from '../../common/constants'
|
||||||
import { calcStandardCups, unitToMl, formatDate, getCatIcon, isIconPath } from '../../common/utils'
|
import { calcStandardCups, unitToMl, formatDate, getCatIcon, isIconPath } from '../../common/utils'
|
||||||
import client from '../../common/api'
|
import client, { isLoggedIn } from '../../common/api'
|
||||||
import themeMixin from '../../common/theme-mixin'
|
import themeMixin from '../../common/theme-mixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -445,6 +445,26 @@ export default {
|
|||||||
if (options && options.date) {
|
if (options && options.date) {
|
||||||
this.backfillDate = options.date
|
this.backfillDate = options.date
|
||||||
}
|
}
|
||||||
|
// 登录守卫:记录功能需要登录(首页入口已拦截,此处兜底处理直接进入的场景)
|
||||||
|
if (!isLoggedIn()) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '登录提示',
|
||||||
|
content: '记录饮酒需要登录后使用,是否立即登录?',
|
||||||
|
confirmText: '去登录',
|
||||||
|
cancelText: '再看看',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
uni.navigateTo({ url: '/pages/login/login' })
|
||||||
|
} else {
|
||||||
|
uni.navigateBack({
|
||||||
|
fail: () => {
|
||||||
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onShareAppMessage() {
|
onShareAppMessage() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -180,7 +180,13 @@ export default {
|
|||||||
if (isLoggedIn === 'true') {
|
if (isLoggedIn === 'true') {
|
||||||
uni.switchTab({ url: '/pages/index/index' })
|
uni.switchTab({ url: '/pages/index/index' })
|
||||||
} else {
|
} else {
|
||||||
uni.reLaunch({ url: '/pages/login/login' })
|
// 未登录以游客身份进入首页浏览,不强制跳登录页
|
||||||
|
uni.setStorageSync('is_first_launch', 'false')
|
||||||
|
uni.setStorageSync('is_guest', 'true')
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/index/index',
|
||||||
|
fail: () => uni.reLaunch({ url: '/pages/index/index' })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user