UNPKG

@mirari/mp-common

Version:

小程序公共库

309 lines (281 loc) 8.88 kB
import utils from './utils' import throttle from '../lib/lodash/throttle' const DEFAULTS = { debug: false, autoLogin: true, // token过期时自动尝试一次登录 withCredentials: true, // 是否附带用户登录信息凭据 baseURL: '', method: 'GET', // 请求方式 showLoading: false, // 是否遮罩 showError: true, // 显示错误信息 resultHandler: null // 查询结果处理 } class APIError extends Error { constructor (result) { super(result.errmsg) this.name = 'APIError' this.code = result.code this.data = result.data } } const methodsWithData = ['POST', 'PUT', 'PATCH'] const methodsNoData = ['DELETE', 'GET', 'HEAD', 'OPTIONS'] // 将相对URL与baseURL合并 function combineURLs (baseURL, relativeURL) { return relativeURL ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL } // 是否绝对URL function isAbsoluteURL (url) { // A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL). // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed // by any combination of letters, digits, plus, period, or hyphen. return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url) } function encode (val) { return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$').replace(/%2C/gi, ',').replace(/%20/g, '+').replace(/%5B/gi, '[').replace(/%5D/gi, ']') } function buildURL (url, params, paramsSerializer) { /*eslint no-param-reassign:0*/ if (!params) { return url } var serializedParams if (paramsSerializer) { serializedParams = paramsSerializer(params) } else if (utils.isURLSearchParams(params)) { serializedParams = params.toString() } else { var parts = [] utils.forEach(params, function serialize (val, key) { if (val === null || typeof val === 'undefined') { return } if (utils.isArray(val)) { key = key + '[]' } if (!utils.isArray(val)) { val = [val] } utils.forEach(val, function parseValue (v) { if (utils.isDate(v)) { v = v.toISOString() } else if (utils.isObject(v)) { v = JSON.stringify(v) } parts.push(encode(key) + '=' + encode(v)) }) }) serializedParams = parts.join('&') } if (serializedParams) { url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams } return url } // 删除空参数 function deleteEmptyData (data) { if (data) { for (const key in data) { const val = data[key] if ((typeof val === 'undefined') || val === '' || val === null) { delete data[key] } } } return data } class API { constructor ({config, auth}) { this.defaults = Object.assign({}, DEFAULTS, config) this.auth = auth // 鉴权实例 // 节流封装,避免重复跳转 this.showLogin = throttle(() => { auth.showLogin() }, 1000) } // 添加通用参数 appendData (config) { if (!config.params) { config.params = {} } if (config.withCredentials) { if (!config.params.userId) { config.params.userId = this.auth.userId } if (!config.params.token) { config.params.token = this.auth.token } } return config } action (config) { config = Object.assign({}, this.defaults, config) // 删除空参数 deleteEmptyData(config.params) deleteEmptyData(config.data) // 添加公共参数 this.appendData(config) let {url, baseURL, params, data, method, header} = config // 拼接完整URL if (baseURL && !isAbsoluteURL(url)) { url = combineURLs(baseURL, url) } // POST方法时,需要将params拼到URL里 // if (methodsWithData.includes(method) && params) { if (methodsWithData.indexOf(method) > -1 && params) { url = buildURL(url, params, config.paramsSerializer) } // GET方法时,需要将params改成data // if (methodsNoData.includes(method) && params) { if (methodsNoData.indexOf(method) > -1 && params) { data = params params = null } if (config.showLoading) { const {title='请稍候...', mask=true} = config.showLoading wx.showLoading({ title, mask }) } return new Promise((resolve, reject) => { wx.request({ url, data, method, header, success: res => { if (config.showLoading) { wx.hideLoading() } if (res.statusCode >= 400) { console.error('wx.request fail [business]', config, res.statusCode, res.data) res.message = '网络貌似不给力~请检查你的网络后重试' reject(res) } else { let result = res.data const {code} = result if (code === '00') { resolve(result) } else { const e = new APIError(result) if (code === '01') { if (config.autoLogin) { config.autoLogin = false // 先尝试一次登录 this.auth.relogin().then(() => { resolve(this.action(config)) }) } else { this.showLogin() reject(e) } } else { if (config.showError) { wx.showToast({ icon: 'none', title: e.message }) } reject(e) } } } }, fail: e => { if (config.showLoading) { wx.hideLoading() } // 格式化成标准error,便于异常处理 if (e.errMsg) { e = new Error(e.errMsg) } console.error('wx.request fail [network]', config, e) if (config.showError) { wx.showToast({ icon: 'none', title: e.message }) } reject(e) }, complete: () => { } }) }) } request (config) { return new Promise((resolve, reject) => { this.action(config).then(result => { let data = result.data if (config.resultHandler) { data = config.resultHandler(data) } resolve(data) }).catch(error => { reject(error) }) }) } paginationQuery (config, {pageSize, pageNum}) { return new Promise((resolve, reject) => { config.params = Object.assign({}, { pageSize: pageSize || 10, pageNum: pageNum || 1 }, config.params) this.action(config).then((result) => { const {data, pagination} = result // 后端分页属性解耦 let paging if (pagination) { paging = { list: data, // 分页数据(required) total: pagination.totalSize, // 总数(required) pageNum: pagination.pageNum || 1, // 当前页码(required) element分页插件的页码不允许为0,否则会无限触发跳页动作 pageSize: pagination.pageSize, // 分页数设定值 length: data.length, // 分页数实际值(比如设定pageSize为10,但最后一页只有7条记录,size为7) pages: pagination.pages || 1, // 总页数 startRow: pagination.startRow, // 当前起始索引 endRow: pagination.endRow // 当前结尾索引 } } else { paging = { list: data, // 分页数据(required) total: 0, // 总数(required) pageNum: 1, // 当前页码(required) element分页插件的页码不允许为0,否则会无限触发跳页动作 pageSize: 0, // 分页数设定值 length: 0, // 分页数实际值(比如设定pageSize为10,但最后一页只有7条记录,size为7) pages: 1, // 总页数 startRow: 0, // 当前起始索引 endRow: 0 // 当前结尾索引 } } if (config.resultHandler) { paging.list = config.resultHandler(paging.list) } resolve(paging) }).catch(error => { reject(error) }) }) } getUrl (config) { config = Object.assign({}, this.defaults, config) // 删除空参数 deleteEmptyData(config.params) // 添加公共参数 this.appendData(config) let {url, baseURL, params, paramsSerializer} = config // 拼接完整URL if (baseURL && !isAbsoluteURL(url)) { url = combineURLs(baseURL, url) } // 将params拼到URL里 url = buildURL(url, params, paramsSerializer) return url } } API.buildURL = buildURL export default API