- bcrypt password hashing with auto-migration from SHA-256 - BLE command retry (3 attempts, 500ms delay, skip on disconnect) - BLE auto-reconnect with service re-discovery on disconnect - Treatment page disconnect/reconnect event handling - Token refresh endpoint with 3-day grace period - Client-side token auto-refresh when <24h remaining - Single treatment record detail API with ownership check
116 行
3.4 KiB
JavaScript
116 行
3.4 KiB
JavaScript
var config = require('../config/env')
|
|
var API_BASE = config.API_BASE
|
|
var _refreshing = false
|
|
var _refreshQueue = []
|
|
|
|
function getTokenExpiry() {
|
|
return parseInt(wx.getStorageSync('token_expiry') || '0', 10)
|
|
}
|
|
|
|
function shouldRefresh() {
|
|
var expiry = getTokenExpiry()
|
|
if (!expiry) return false
|
|
var remaining = expiry - Math.floor(Date.now() / 1000)
|
|
return remaining > 0 && remaining < 86400
|
|
}
|
|
|
|
function refreshToken() {
|
|
if (_refreshing) {
|
|
return new Promise(function (resolve, reject) {
|
|
_refreshQueue.push({ resolve: resolve, reject: reject })
|
|
})
|
|
}
|
|
_refreshing = true
|
|
return new Promise(function (resolve, reject) {
|
|
var token = wx.getStorageSync('token')
|
|
wx.request({
|
|
url: API_BASE + '/api/v1/auth/refresh',
|
|
method: 'POST',
|
|
header: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'application/json' },
|
|
data: {},
|
|
success: function (res) {
|
|
if (res.data && res.data.code === 0 && res.data.data && res.data.data.token) {
|
|
wx.setStorageSync('token', res.data.data.token)
|
|
wx.setStorageSync('token_expiry', String(Math.floor(Date.now() / 1000) + (res.data.data.expires_in || 604800)))
|
|
resolve(res.data.data.token)
|
|
_refreshQueue.forEach(function (q) { q.resolve(res.data.data.token) })
|
|
} else {
|
|
resolve(null)
|
|
_refreshQueue.forEach(function (q) { q.resolve(null) })
|
|
}
|
|
_refreshing = false
|
|
_refreshQueue = []
|
|
},
|
|
fail: function () {
|
|
resolve(null)
|
|
_refreshQueue.forEach(function (q) { q.resolve(null) })
|
|
_refreshing = false
|
|
_refreshQueue = []
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
function httpRequest(options) {
|
|
var doRequest = function () {
|
|
var token = wx.getStorageSync('token')
|
|
return new Promise(function (resolve, reject) {
|
|
wx.request({
|
|
url: API_BASE + options.path,
|
|
method: options.method || 'GET',
|
|
data: options.data || {},
|
|
header: Object.assign({
|
|
'Authorization': token ? 'Bearer ' + token : '',
|
|
'Content-Type': 'application/json',
|
|
'X-App-Version': '1.0.0',
|
|
'X-Platform': 'wechat'
|
|
}, options.header || {}),
|
|
success: function (res) {
|
|
if (res.data && res.data.code === 0) {
|
|
resolve(res.data.data)
|
|
} else if (res.data && res.data.code === 1001 || res.data && res.data.code === 1002) {
|
|
wx.removeStorageSync('token')
|
|
wx.removeStorageSync('token_expiry')
|
|
wx.reLaunch({ url: '/pages/login/login' })
|
|
reject(res.data)
|
|
} else {
|
|
reject(res.data || { code: -1, message: '请求失败' })
|
|
}
|
|
},
|
|
fail: function (err) {
|
|
reject({ code: 2002, message: err.errMsg || '网络异常' })
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
if (shouldRefresh() && options.path !== '/api/v1/auth/refresh') {
|
|
return refreshToken().then(function () { return doRequest() })
|
|
}
|
|
return doRequest()
|
|
}
|
|
|
|
function request(options) {
|
|
return httpRequest(options)
|
|
}
|
|
|
|
function get(path, data) {
|
|
return request({ path: path, method: 'GET', data: data })
|
|
}
|
|
|
|
function post(path, data) {
|
|
return request({ path: path, method: 'POST', data: data })
|
|
}
|
|
|
|
function put(path, data) {
|
|
return request({ path: path, method: 'PUT', data: data })
|
|
}
|
|
|
|
module.exports = {
|
|
request: request,
|
|
get: get,
|
|
post: post,
|
|
put: put,
|
|
API_BASE: API_BASE
|
|
}
|