针对微信审核要求新增游客浏览模式,用户可无需登录直接浏览应用内容,仅在使用发布、点赞、记录等需要身份的功能时才弹窗引导登录。具体修改包括: 1. 新增游客态判断工具函数与登录守卫逻辑 2. 为登录页添加游客直接进入入口 3. 为首页、酒友圈、个人页、动态页、记录页添加游客适配逻辑 4. 优化登录态失效处理逻辑,不再强制跳转登录页 5. 调整部分页面的返回逻辑适配分享直接进入场景 6. 为各页面添加游客引导UI与交互
385 lines
12 KiB
JavaScript
385 lines
12 KiB
JavaScript
/* 碰盏日记 - API 服务层
|
||
* 基于 HaveADrink SDK 封装后端接口
|
||
*/
|
||
import HaveADrink, { GetAchievementsReq } from 'HaveADrink'
|
||
import UniAppWebSocket from './uni-websocket'
|
||
|
||
// ==========================================
|
||
// 后端服务地址(切换环境只需改这里)
|
||
// ==========================================
|
||
export const API_HOST = 'https://dev.wash-painting.cn'
|
||
|
||
// ==========================================
|
||
// 登录态工具(微信审核要求:不得在浏览时强制登录)
|
||
// 游客可直接浏览首页/酒友圈等公开内容,仅在用户主动使用
|
||
// 记录、发布、点赞等需要身份的功能时,才弹窗由其自行选择是否登录。
|
||
// ==========================================
|
||
|
||
/** 判断当前是否已登录(本地降级登录也算登录态) */
|
||
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
|
||
}
|
||
|
||
// ==========================================
|
||
// HTTP 请求函数(供 SDK 内部调用)
|
||
// 参考 goodBooth 项目的 fetchsomething
|
||
// ==========================================
|
||
function httpRequest(url, params) {
|
||
// 支持静默模式(如后台刷新token),不弹 toast 不跳转
|
||
const silent = params.silent === true
|
||
return new Promise((resolve, reject) => {
|
||
// 自动注入 Authorization token
|
||
const headers = Object.assign({}, params.headers || {})
|
||
const token = uni.getStorageSync('auth_token')
|
||
if (token) {
|
||
headers['Authorization'] = `Bearer ${token}`
|
||
}
|
||
|
||
uni.request({
|
||
url: url,
|
||
method: params.method,
|
||
params: params.query || undefined,
|
||
data: params.data,
|
||
header: headers,
|
||
success: (res) => {
|
||
const code = res.statusCode
|
||
if (code === 200 || code === 201 || code === 204) {
|
||
// 业务级错误:HTTP 200 但 fail:true
|
||
if (res.data && res.data.fail === true) {
|
||
const bizMsg = res.data.msg || '操作失败'
|
||
if (!silent) {
|
||
uni.showToast({ title: bizMsg, icon: 'none', duration: 2500 })
|
||
}
|
||
reject({ msg: bizMsg, code })
|
||
return
|
||
}
|
||
resolve(res.data)
|
||
} else if (code === 401 ) {
|
||
// token/refresh_token 过期或无效:仅静默清除登录态并 reject,
|
||
// 不强制跳转登录页(游客可继续浏览),后续写操作由 requireLogin 引导
|
||
uni.removeStorageSync('auth_token')
|
||
uni.removeStorageSync('refresh_token')
|
||
uni.removeStorageSync('is_logged_in')
|
||
reject({ msg: '登录已过期,请重新登录', code })
|
||
} else {
|
||
const rawMsg = (res.data && res.data.msg) || (res.data && res.data.errmsg) || '请求失败'
|
||
const errMsg = `[${code}] ${rawMsg}`
|
||
if (!silent) {
|
||
uni.showToast({ title: errMsg, icon: 'none', duration: 2500 })
|
||
}
|
||
reject({ msg: errMsg, code })
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
const msg = (err && err.errMsg) || '网络请求失败'
|
||
if (!silent) {
|
||
uni.showToast({ title: msg, icon: 'none', duration: 2500 })
|
||
}
|
||
reject({ msg })
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// ==========================================
|
||
// 文件上传函数(供 SDK 内部调用)
|
||
// ==========================================
|
||
function uploadRequest(url, params) {
|
||
return new Promise((resolve, reject) => {
|
||
const headers = Object.assign({}, params.headers || {})
|
||
const token = uni.getStorageSync('auth_token')
|
||
if (token) {
|
||
headers['Authorization'] = `Bearer ${token}`
|
||
}
|
||
|
||
uni.uploadFile({
|
||
url: url,
|
||
filePath: params.data.image || params.data.fileName || params.data.filePath,
|
||
name: params.data.name || 'image',
|
||
header: headers,
|
||
formData: params.data.formData || {},
|
||
success: (uploadRes) => {
|
||
try {
|
||
const data = typeof uploadRes.data === 'string'
|
||
? JSON.parse(uploadRes.data)
|
||
: uploadRes.data
|
||
resolve(data)
|
||
} catch (e) {
|
||
resolve(uploadRes.data)
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
reject({ msg: err.errMsg || '上传失败' })
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// ==========================================
|
||
// 初始化 SDK 实例
|
||
// (WebSocket 适配器使用 common/uni-websocket.js,已修复 wx.connectSocket 降级问题)
|
||
// ==========================================
|
||
const client = new HaveADrink({
|
||
host: API_HOST,
|
||
http_request: httpRequest,
|
||
upload: uploadRequest,
|
||
websocket: UniAppWebSocket,
|
||
token: uni.getStorageSync('auth_token') || ''
|
||
})
|
||
|
||
// ==========================================
|
||
// 导出 SDK 实例(各页面直接 import 使用)
|
||
// ==========================================
|
||
export default client
|
||
|
||
// ==========================================
|
||
// Token 管理辅助函数
|
||
// ==========================================
|
||
|
||
/** 登录成功后保存 token 并同步到 SDK */
|
||
export function saveAuthTokens(data) {
|
||
if (data.token) {
|
||
uni.setStorageSync('auth_token', data.token)
|
||
client.setToken(data.token)
|
||
}
|
||
if (data.refresh_token) {
|
||
uni.setStorageSync('refresh_token', data.refresh_token)
|
||
}
|
||
}
|
||
|
||
/** 清除所有认证信息 */
|
||
export function clearAuth() {
|
||
uni.removeStorageSync('auth_token')
|
||
uni.removeStorageSync('refresh_token')
|
||
uni.removeStorageSync('is_logged_in')
|
||
uni.removeStorageSync('is_guest')
|
||
uni.removeStorageSync('user_info')
|
||
client.setToken('')
|
||
}
|
||
|
||
/** 尝试用 refresh_token 刷新 token(静默,不弹提示不跳转) */
|
||
export async function refreshAuthToken() {
|
||
const refreshToken = uni.getStorageSync('refresh_token')
|
||
if (!refreshToken) return false
|
||
try {
|
||
const res = await client.RefreshToken({ refresh_token: refreshToken, silent: true })
|
||
if (res && res.token) {
|
||
saveAuthTokens(res)
|
||
return true
|
||
}
|
||
return false
|
||
} catch (e) {
|
||
// 静默失败:refresh token 无效时清除残留凭证
|
||
uni.removeStorageSync('refresh_token')
|
||
return false
|
||
}
|
||
}
|
||
|
||
// ==========================================
|
||
// 酒友圈 API(基于 HaveADrink SDK 真实接口)
|
||
// ==========================================
|
||
|
||
/** 获取动态信息流(游标分页) */
|
||
export async function GetCircleFeeds({ lastId = 0, pageSize = 10 } = {}) {
|
||
const res = await client.GetFeeds({ lastId, pageSize })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 点赞动态 */
|
||
export async function LikeFeed({ feedId }) {
|
||
const res = await client.LikeFeed({ id: feedId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 取消点赞 */
|
||
export async function UnlikeFeed({ feedId }) {
|
||
const res = await client.UnlikeFeed({ id: feedId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 删除动态(仅本人可删,后端会校验归属) */
|
||
export async function DeleteFeed({ feedId }) {
|
||
const res = await client.DeleteFeed({ id: feedId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取动态评论 */
|
||
export async function GetFeedComments({ feedId }) {
|
||
const res = await client.GetFeedComments({ id: feedId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 发表评论 */
|
||
export async function AddComment({ feedId, content }) {
|
||
const res = await client.AddComment({ id: feedId, content })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 发布动态 */
|
||
export async function PublishFeed({ text, images, recordId, visibility }) {
|
||
const res = await client.PublishFeed({ text, images, recordId, visibility })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取酒友列表 */
|
||
export async function GetFriends({ keyword = '' } = {}) {
|
||
const res = await client.GetFriends({ keyword })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取好友请求(支持关键词搜索) */
|
||
export async function GetFriendRequests({ keyword = '' } = {}) {
|
||
const res = await client.GetFriendRequests({ keyword })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 发送好友请求(创建邀请,SDK v1.0.12:无需 userId,响应返回 inviteCode 邀请码) */
|
||
export async function SendFriendRequest({ message = '' } = {}) {
|
||
const res = await client.SendFriendRequest({ message })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 接受好友请求(id 为好友请求ID,即邀请码 inviteCode) */
|
||
export async function AcceptFriendRequest({ requestId }) {
|
||
const res = await client.AcceptFriendRequest({ id: requestId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 删除酒友 */
|
||
export async function RemoveFriend({ userId }) {
|
||
const res = await client.RemoveFriend({ userId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取酒局列表 */
|
||
export async function GetEvents({ status = '' } = {}) {
|
||
const res = await client.GetEvents({ status })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取酒局详情 */
|
||
export async function GetEventDetail({ eventId }) {
|
||
const res = await client.GetEventDetail({ id: eventId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 发起酒局 */
|
||
export async function CreateEvent({ title, time, location, maxPeople, note, latitude, longitude }) {
|
||
const geo = (latitude != null && longitude != null) ? { latitude, longitude } : undefined
|
||
const res = await client.CreateEvent({ title, time, location, maxPeople, geo, note })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 修改酒局(仅发起人可改,后端会校验归属) */
|
||
export async function UpdateEvent({ eventId, title, time, location, maxPeople, note, latitude, longitude }) {
|
||
const geo = (latitude != null && longitude != null) ? { latitude, longitude } : undefined
|
||
const res = await client.UpdateEvent({ id: eventId, title, time, location, maxPeople, geo, note })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 删除酒局(仅发起人可删,后端会校验归属) */
|
||
export async function DeleteEvent({ eventId }) {
|
||
const res = await client.DeleteEvent({ id: eventId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 报名酒局 */
|
||
export async function JoinEvent({ eventId }) {
|
||
const res = await client.JoinEvent({ id: eventId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 取消报名 */
|
||
export async function QuitEvent({ eventId }) {
|
||
const res = await client.QuitEvent({ id: eventId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 酒局签到 */
|
||
export async function CheckInEvent({ eventId }) {
|
||
const res = await client.CheckInEvent({ id: eventId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 审核报名(仅发起人可操作;approve: 1=待审核 2=通过 3=拒绝) */
|
||
export async function ApproveEvent({ eventId, userId, approve }) {
|
||
const res = await client.ApproveEvent({ id: eventId, userId, approve })
|
||
return { data: res }
|
||
}
|
||
|
||
// ==========================================
|
||
// 私信 API(基于 HaveADrink SDK 真实接口)
|
||
// ==========================================
|
||
|
||
/** 获取会话列表 */
|
||
export async function GetConversations() {
|
||
const res = await client.GetConversations({})
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取历史消息(游标分页) */
|
||
export async function GetMessages({ conversationId, lastID = 0, pageSize = 20 } = {}) {
|
||
const res = await client.GetMessages({ conversationId, lastID, pageSize })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 标记会话已读 */
|
||
export async function MarkRead({ conversationId }) {
|
||
const res = await client.MarkRead({ id: conversationId })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 获取未读消息总数 */
|
||
export async function GetUnreadCount() {
|
||
const res = await client.GetUnreadCount({})
|
||
return { data: res }
|
||
}
|
||
|
||
// ==========================================
|
||
// 成就 API
|
||
// ==========================================
|
||
|
||
/** 获取成就列表(使用 SDK GetAchievementsReq 请求实例) */
|
||
export async function GetAchievements() {
|
||
const req = new GetAchievementsReq()
|
||
const res = await client.GetAchievements(req)
|
||
return { data: res }
|
||
}
|
||
|
||
// ==========================================
|
||
// 文件上传 API
|
||
// ==========================================
|
||
|
||
/** 上传图片(返回 url) */
|
||
export async function UploadImage({ filePath }) {
|
||
const res = await client.UploadImage({ image: filePath })
|
||
return { data: res }
|
||
}
|
||
|
||
/** 更新当前用户头像(avatar 必须是上传后的 http(s) 远程地址,需 token) */
|
||
export async function UpdateUserAvatar({ avatar }) {
|
||
const res = await client.UpdateUserAvatar({ avatar })
|
||
return { data: res }
|
||
}
|