Files
blind-select/frontend-app/api/index.js
T
admin 06488f0237 Initial commit: 帮我选盲选应用
功能:
- Go后端 (Gin + GORM + PostgreSQL)
- UniApp用户端 (iOS/Android/小程序)
- DaisyUI5后台管理
- JWT认证 + 微信登录
- 盲选加权算法
- 会员系统 + 优惠券
- 打分评价 + 偏好学习
2026-06-08 20:18:31 +00:00

123 lines
3.8 KiB
JavaScript

// API 配置
// 开发环境: 指向本地后端
// 小程序生产: 指向你的 HTTPS 域名
// #ifdef MP-WEIXIN
// 微信小程序环境 → 生产域名 (替换为你自己的域名)
const BASE_URL = 'https://api.yourdomain.com/api/v1'
// #endif
// #ifdef H5
// H5 环境 → 本地或生产
const BASE_URL = 'http://localhost:8080/api/v1'
// #endif
// #ifndef MP-WEIXIN && !H5
// 其他平台 (APP等)
const BASE_URL = 'http://localhost:8080/api/v1'
// #endif
// 请求封装
function request(url, method = 'GET', data = null) {
const token = uni.getStorageSync('token')
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + url,
method,
data,
header: {
'Content-Type': 'application/json',
'Authorization': token ? `Bearer ${token}` : ''
},
success: (res) => {
if (res.statusCode === 200 && res.data.code === 2) {
resolve(res.data.data)
} else if (res.statusCode === 401) {
// Token 过期 → 尝试刷新
refreshAndRetry(url, method, data).then(resolve).catch(reject)
} else {
uni.showToast({
title: res.data.message || '请求失败',
icon: 'none',
duration: 1500
})
reject(new Error(res.data.message || 'request failed'))
}
},
fail: (err) => {
uni.showToast({ title: '网络错误', icon: 'none' })
reject(err)
}
})
})
}
// Token 刷新后重试
async function refreshAndRetry(url, method, data) {
const refreshToken = uni.getStorageSync('refresh_token')
if (!refreshToken) {
// 没有 refresh token → 跳转登录
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
uni.showToast({ title: '请重新登录', icon: 'none' })
uni.reLaunch({ url: '/pages/login/login' })
throw new Error('unauthorized')
}
try {
const authApi = (await import('@/api/index.js')).authApi
const res = await authApi.refreshToken({ refresh_token: refreshToken })
uni.setStorageSync('token', res.token)
// 重试原请求
return request(url, method, data)
} catch (e) {
// 刷新也失败 → 跳转登录
uni.removeStorageSync('token')
uni.removeStorageSync('refresh_token')
uni.removeStorageSync('userInfo')
uni.reLaunch({ url: '/pages/login/login' })
throw e
}
}
// ============== Auth ==============
export const authApi = {
register: (data) => request('/auth/register', 'POST', data),
login: (data) => request('/auth/login', 'POST', data),
wechatLogin: (data) => request('/auth/wechat/login', 'POST', data),
refreshToken: (data) => request('/auth/refresh', 'POST', data),
getProfile: () => request('/user/profile', 'GET'),
updateProfile: (data) => request('/user/profile', 'PUT', data),
}
// ============== Blind Selection ==============
export const blindApi = {
getCategories: () => request('/blind/categories', 'GET'),
getPool: (params) => request('/blind/pool?' + new URLSearchParams(params).toString(), 'GET'),
choose: (data) => request('/blind/choose', 'POST', data),
getResult: (id) => request(`/blind/result/${id}`, 'GET'),
getHistory: () => request('/blind/history', 'GET'),
}
// ============== Review ==============
export const reviewApi = {
submit: (data) => request('/review/submit', 'POST', data),
getStats: () => request('/review/stats', 'GET'),
}
// ============== Coupon ==============
export const couponApi = {
getMyCoupons: () => request('/coupon/list', 'GET'),
getAvailable: () => request('/coupon/available', 'GET'),
claim: (data) => request('/coupon/claim', 'POST', data),
}
// ============== Member ==============
export const memberApi = {
getStatus: () => request('/member/status', 'GET'),
getPlans: () => request('/member/plans', 'GET'),
subscribe: (data) => request('/member/subscribe', 'POST', data),
}