Files
hejiu/common/api.js
T
2026-07-29 20:46:26 +08:00

448 lines
13 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 from 'HaveADrink'
// ==========================================
// 后端服务地址(切换环境只需改这里)
// ==========================================
const API_HOST = 'https://dev.wash-painting.cn'
// ==========================================
// 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 过期或无效,清除登录态
uni.removeStorageSync('auth_token')
uni.removeStorageSync('refresh_token')
uni.removeStorageSync('is_logged_in')
if (!silent) {
uni.reLaunch({ url: '/pages/login/login' })
uni.showToast({ title: '登录已过期,请重新登录', icon: 'none', duration: 2500 })
}
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 || '上传失败' })
}
})
})
}
/**
* 使用 uni-app WebSocket API 实现的 WebSocket 类
* 符合之前定义的 WebsocketInterface(无类型约束)
*/
class UniAppWebSocket {
/**
* 构造函数:传入 WebSocket 服务器地址
* @param {string} host - 完整的 WebSocket URL,例如 'wss://example.com/ws'
*/
constructor(host) {
this.host = host;
// 事件回调属性(外部可赋值)
this.close = null; // 可赋值为函数,同时也可用主动关闭连接
this.onopen = null;
this.onmessage = null;
// 内部 SocketTask 实例
this.socketTask = null;
// 初始化连接
this._initSocket();
}
/**
* 初始化 WebSocket 连接(私有方法,约定以 _ 开头)
*/
_initSocket() {
const self = this;
// 创建 SocketTask
this.socketTask = uni.connectSocket({
url: this.host,
success() {
// 连接创建成功(但尚未打开)
},
fail(err) {
// 连接创建失败,触发错误事件
const errorEvent = { type: 'error', error: err, target: self };
self.onerror(errorEvent);
}
});
// 监听打开事件
this.socketTask.onOpen((res) => {
if (self.onopen) {
// 构造一个简单的事件对象
const event = { type: 'open', target: self, ...res };
self.onopen(event);
}
});
// 监听消息事件
this.socketTask.onMessage((res) => {
if (self.onmessage) {
// res.data 是消息数据
const event = {
type: 'message',
data: res.data,
target: self
};
self.onmessage(event);
}
});
// 监听关闭事件
this.socketTask.onClose((res) => {
// 构造关闭事件
const event = {
type: 'close',
code: res.code,
reason: res.reason,
wasClean: res.wasClean,
target: self
};
// 调用 onclose 方法(可被重写)
self.onclose(event);
});
// 监听错误事件
this.socketTask.onError((err) => {
const errorEvent = { type: 'error', error: err, target: self };
self.onerror(errorEvent);
});
// 将 close 属性设置为一个可调用函数,用于主动断开连接
// 同时也满足接口的 “回调类型” 定义
this.close = function(ev) {
if (self.socketTask) {
const code = ev && ev.code ? ev.code : 1000;
const reason = ev && ev.reason ? ev.reason : '';
self.socketTask.close({ code, reason });
}
// 如果作为回调函数,返回 null 即可(无实际意义)
return null;
};
}
/**
* 关闭事件处理方法(可被外部重写)
* @param {Object} event - 关闭事件对象
*/
onclose(event) {
// 默认空实现,你可以在外部覆盖此方法
// console.log('连接已关闭', event);
}
/**
* 错误事件处理方法(可被外部重写)
* @param {Object} event - 错误事件对象
*/
onerror(event) {
// 默认空实现
// console.error('连接错误', event);
}
/**
* 发送数据
* @param {string|ArrayBuffer|Blob} data - 要发送的数据
* @throws {Error} 如果 WebSocket 未初始化
*/
send(data) {
if (!this.socketTask) {
throw new Error('WebSocket 未初始化,无法发送数据');
}
this.socketTask.send({
data: data,
success() {
// 发送成功,可添加日志
},
fail(err) {
// 发送失败,触发错误事件
const errorEvent = { type: 'error', error: err, target: this };
this.onerror(errorEvent);
}
});
}
}
// ==========================================
// 初始化 SDK 实例
// ==========================================
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 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() {
const res = await client.GetFriendRequests({})
return { data: res }
}
/** 发送好友请求 */
export async function SendFriendRequest({ userId, message = '' }) {
const res = await client.SendFriendRequest({ userId, message })
return { data: res }
}
/** 接受好友请求 */
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 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 }
}
// ==========================================
// 私信 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
// ==========================================
/** 上传图片(返回 url */
export async function UploadImage({ filePath }) {
const res = await client.UploadImage({ image: filePath })
return { data: res }
}