Files
hejiu/common/api.js
T
cg dd3c670021 feat: add guest mode and optimize login experience
针对微信审核要求新增游客浏览模式,用户可无需登录直接浏览应用内容,仅在使用发布、点赞、记录等需要身份的功能时才弹窗引导登录。具体修改包括:
1. 新增游客态判断工具函数与登录守卫逻辑
2. 为登录页添加游客直接进入入口
3. 为首页、酒友圈、个人页、动态页、记录页添加游客适配逻辑
4. 优化登录态失效处理逻辑,不再强制跳转登录页
5. 调整部分页面的返回逻辑适配分享直接进入场景
6. 为各页面添加游客引导UI与交互
2026-09-10 21:43:46 +08:00

385 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 碰盏日记 - 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 }
}