Files
jjx-web/uni_modules/vk-unicloud/vk_modules/vk-unicloud-page/libs/vk-unicloud/vk-unicloud-callFunctionUtil.js
T
2023-11-07 17:11:57 +08:00

1041 lines
34 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.
var vk = {};
var counterNum = 0;
var uniCloudEnvs = {}; // uniCloud 环境列表
var lastToLoginTime = 0;
class CallFunctionUtil {
constructor() {
this.config = {
// 是否开启测试环境的云函数,true:使用测试环境,false:使用正式环境,默认true
isTest: false,
// 设为false可关闭打印日志
debug: true,
// 云函数路由(主函数名)
functionName: "router",
// 云函数路由(开发测试函数名)
testFunctionName: "router-test",
// 云函数url化后对应的url地址
functionNameToUrl: {
"router": "https://xxxxxxx.bspapp.com/http/router",
"router-test": "https://xxxxxxx.bspapp.com/http/router"
},
// vk.callFunction的isRequest的默认值
isRequestDefault: false,
// 默认时区(中国为8)
targetTimezone: 8,
// 客户端登录页面地址
login: {
url: '/pages_template/uni-id/login/index/index'
},
// 请求配置
request: {
// 公共请求参数(每次请求都会带上的参数)
dataParam: {}
},
// 日志风格
logger: {
colorArr: [
"#0095ff",
"#67C23A"
]
},
// 缓存键名 - token(请勿修改)
uniIdTokenKeyName: "uni_id_token",
// 缓存键名 - token过期时间(请勿修改)
uniIdTokenExpiredKeyName: "uni_id_token_expired",
// 缓存键名 - 当前登录用户信息(请勿修改)
uniIdUserInfoKeyName: "uni_id_user_info",
// 缓存键名 - 公共请求参数(请勿修改)
requestGlobalParamKeyName: "vk_request_global_param",
// 监听token刷新事件的事件名
onRefreshTokenEventName: "onRefreshToken",
// 自定义组件配置
components: {}
}
/**
* 获取我的token
* vk.getToken();
*/
this.getToken = (res = {}) => {
let config = this.config;
return vk.getStorageSync(config.uniIdTokenKeyName);
}
/**
* 保存新的token
* 可通过下方的代码监听token的改变(写在app.vue的onLaunch内)
vk.$on('onRefreshToken',(data) => {
console.log('token改变监听:', data);
});
*/
this.saveToken = (res = {}) => {
let config = this.config;
vk.setStorageSync(config.uniIdTokenKeyName, res.token);
vk.setStorageSync(config.uniIdTokenExpiredKeyName, res.tokenExpired);
this.emitRefreshToken(res); // 触发token刷新事件
if (this.config.debug) console.log("--------【token已更新】--------");
}
// 删除token,并删除userInfo缓存
this.deleteToken = () => {
let config = this.config;
vk.removeStorageSync(config.uniIdTokenKeyName);
vk.removeStorageSync(config.uniIdTokenExpiredKeyName);
this.deleteUserInfo();
this.emitRefreshToken(); // 触发token刷新事件
if (this.config.debug) console.log("--------【token已删除】--------");
}
// 更新userInfo缓存
this.updateUserInfo = (res = {}) => {
let config = this.config;
let {
userInfo = {}
} = res;
if (typeof vk.setVuex === "function") {
// 有安装vuex则使用vuex
vk.setVuex('$user.userInfo', userInfo);
} else {
// 否则使用本地缓存
vk.setStorageSync(config.uniIdUserInfoKeyName, userInfo);
}
//if (this.config.debug) console.log("--------【用户信息已更新】--------");
}
// 删除userInfo缓存
this.deleteUserInfo = (res = {}) => {
let {
log = true
} = res;
let config = this.config;
if (typeof vk.setVuex === "function") {
// 有安装vuex则使用vuex
vk.setVuex('$user.userInfo', {});
vk.setVuex('$user.permission', []);
vk.removeStorageSync(config.uniIdUserInfoKeyName);
} else {
// 否则使用本地缓存
vk.removeStorageSync(config.uniIdUserInfoKeyName);
}
if (this.config.debug && log) console.log("--------【用户信息已删除】--------");
}
// 检查token是否有效(本地版)
// let valid = vk.callFunctionUtil.checkToken();
this.checkToken = (res = {}) => {
let config = this.config;
let token = uni.getStorageSync(config.uniIdTokenKeyName);
let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName);
let valid = false;
if (token && tokenExpired && tokenExpired > Date.now()) {
valid = true;
}
return valid;
}
/**
* 触发监听token更新事件
*/
this.emitRefreshToken = (data = {}) => {
let config = this.config;
return vk.$emit(config.onRefreshTokenEventName, data); // 触发token刷新事件
}
/**
* 监听token更新事件
*/
this.onRefreshToken = (callback) => {
let config = this.config;
return vk.$on(config.onRefreshTokenEventName, callback);
}
/**
* 移除token更新事件
*/
this.offRefreshToken = (callback) => {
let config = this.config;
return vk.$off(config.onRefreshTokenEventName, callback);
}
/**
* 修改请求配置中的公共请求参数
* 若把shop-manage改成*则代表全局
vk.callFunctionUtil.updateRequestGlobalParam({
"shop-manage":{
regExp:"^xxx/kh/",
data:{
shop_id : shop_id
}
}
});
对应的callFunction中增加参数globalParamName:"shop-manage"
vk.callFunction({
url: 'xxx/xxxxxx',
title: '请求中...',
globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数
data: {},
success(data) {
}
});
*/
this.updateRequestGlobalParam = (data = {}, setKey) => {
let config = this.config;
if (setKey) {
// 覆盖对象
config.request.dataParam = data;
} else {
// 覆盖参数(有就覆盖,没有则新增)
let dataParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
config.request.dataParam = Object.assign(dataParam, data);
}
vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam);
}
/**
* 获取请求配置中的公共请求参数
vk.callFunctionUtil.getRequestGlobalParam();
*/
this.getRequestGlobalParam = (globalParamName = "*") => {
let config = this.config;
let data = config.request.dataParam;
if (!data || JSON.stringify(data) === "{}") {
data = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
config.request.dataParam = data;
}
let param = data[globalParamName] || {};
return JSON.parse(JSON.stringify(param));
}
/**
* 删除请求配置中的公共请求参数
* globalParamName 不传代表删除所有
vk.callFunctionUtil.deleteRequestGlobalParam(globalParamName);
*/
this.deleteRequestGlobalParam = (globalParamName) => {
let config = this.config;
let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
if (globalParamName) {
delete globalParam[globalParamName];
} else {
globalParam = {};
}
config.request.dataParam = globalParam;
vk.setStorageSync(config.requestGlobalParamKeyName, globalParam);
}
// 拦截器
this.interceptor = {
// 拦截1301、1302错误码(非法token和token失效)
login: (obj = {}) => {
let nowTime = Date.now();
if (nowTime - lastToLoginTime < 300) {
return false;
}
lastToLoginTime = nowTime;
let {
params,
res
} = obj;
let config = this.config;
let callFunction = this.callFunction;
if (config.debug) console.log("跳登录页面");
let { tokenExpiredAutoDelete = true } = config;
if (tokenExpiredAutoDelete) this.deleteToken();
setTimeout(() => {
if (config.login.url) {
let currentPage = getCurrentPages()[getCurrentPages().length - 1];
if (currentPage && currentPage.route && "/" + currentPage.route === config.login.url) {
return false;
}
// 此处代码是为了防止首页启动时检测和正常检测冲突-----------------------------------------------------------
if (vk.navigate.isOnLaunchToLogin) {
setTimeout(() => {
vk.navigate.isOnLaunchToLogin = false;
}, 500);
return false;
}
// 此处代码是为了防止首页启动时检测和正常检测冲突-----------------------------------------------------------
uni.navigateTo({
url: config.login.url,
events: {
// 监听登录成功后的事件
loginSuccess: function(data) {
let num = 2;
let pages = getCurrentPages();
if (pages.length >= num) {
let that = pages[pages.length - num];
if (typeof that.onLoad == "function") {
// 重新执行页面onLoad函数
that.onLoad(that.options);
} else if (typeof that.init == "function") {
// 重新执行页面初始化函数
that.init(that.options);
} else {
// 重新执行一次云函数调用
callFunction(params);
}
} else {
// 重新执行一次云函数调用
callFunction(params);
}
}
}
});
} else {
if (params.needAlert) {
vk.alert(res.result.msg);
}
}
}, 0);
},
// 全局请求失败拦截器
fail: (obj = {}) => {
return true;
}
}
/**
* 云函数请求封装 - 统一入口
* @description 通过云函数路由,1个云函数实现多个云函数的效果。
* @param {String} name 大云函数名称(默认router)
* @param {String} url 请求路径
* @param {Object} data 请求参数,如 { a:1, b:"2" } 云函数内可通过 let { a, b } = data; 获取参数
* @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。
* @param {Boolean|Object} loading 若设置为false,即使title有值也不显示遮罩层
* @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false
* @param {String} env 云空间环境 文档:https://vkdoc.fsq.pub/client/question/q9.html#%E5%89%8D%E7%AB%AF%E8%AF%B7%E6%B1%82%E5%A4%9A%E6%9C%8D%E5%8A%A1%E7%A9%BA%E9%97%B4
* @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示,默认为true
* @param {Number} retryCount 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中)
* @param {Function} success 请求成功时,执行的回调函数
* @param {Function} fail 请求失败时,执行的回调函数
* @param {Function} complete 无论请求成功与否,都会执行的回调函数
*/
this.callFunction = (obj = {}) => {
let that = this;
let { config } = that;
let {
url,
data = {},
globalParamName
} = obj;
if (!url) {
vk.toast('vk.callFunction的url参数不能为空');
return;
}
if (obj.retryCount) {
// 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中)
return that.callFunctionRetry(obj);
}
// 去除值为 undefined 的参数
if (typeof data === "object") {
obj.data = vk.pubfn.copyObject(data);
}
// 注入自定义全局参数开始-----------------------------------------------------------
let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
// 根据正则规格自动匹配全局请求参数
for (let i in globalParam) {
let customDate = globalParam[i];
if (customDate.regExp) {
if (typeof customDate.regExp === "object") {
// 数组形式
for (let i = 0; i < customDate.regExp.length; i++) {
let regExp = new RegExp(customDate.regExp[i]);
if (regExp.test(url)) {
obj.data = Object.assign(customDate.data, obj.data);
break;
}
}
} else {
// 字符串形式
let regExp = new RegExp(customDate.regExp);
if (regExp.test(url)) {
obj.data = Object.assign(customDate.data, obj.data);
}
}
}
}
// 根据指定globalParamName匹配全局请求参数
let customDate = that.getRequestGlobalParam(globalParamName);
if (customDate && JSON.stringify(customDate) !== "{}") {
if (customDate.regExp) {
obj.data = Object.assign(customDate.data, obj.data); // 新版本
} else {
obj.data = Object.assign(customDate, obj.data); // 兼容旧版本
}
}
// 注入自定义全局参数结束-----------------------------------------------------------
// 若执行的函数不是pub类型函数,则先本地判断下token,可以提高效率。
// if (url.indexOf("/pub/") == -1 && url.indexOf("/pub_") == -1) {
// 若执行的函数是kh或sys类型函数,先本地判断下token,可以提高效率。
if (url.indexOf("/kh/") > -1 || url.indexOf("/sys/") > -1 || (url.indexOf(".") > -1 && url.indexOf("pub_") == -1 && url.indexOf("/pub/") == -1 && url.indexOf(
"/pub.") == -1 && url.indexOf("pub.") !== 0 && url.indexOf("pub_") !== 0)) {
if (!vk.checkToken()) {
// 若本地token校验未通过,则直接执行 login 拦截器函数
return new Promise((resolve, reject) => {
// 执行 login 拦截器函数(跳转到页面页面)
let res = { code: 30204, msg: "本地token校验未通过" };
let params = obj;
if (typeof that.interceptor.login === "function") {
that.interceptor.login({
res,
params,
vk
});
}
reject(res);
});
}
}
if (typeof obj.isRequest === "undefined") {
obj.isRequest = config.isRequestDefault;
}
// 执行请求
if (obj.isRequest) {
return that.runRequest(obj);
} else {
return that.runCallFunction(obj);
}
}
// 设置全局默认配置
this.setConfig = (customConfig = {}) => {
for (let key in customConfig) {
if (key === "vk") {
vk = customConfig[key];
} else if (key === "interceptor") {
this.interceptor = Object.assign(this.interceptor, customConfig[key]);
this.config.interceptor = customConfig[key];
} else if (key === "myfn") {
vk.myfn = customConfig[key];
} else if (key === "loginPagePath") {
// 兼容老版本
this.config.login.url = customConfig[key];
} else if (key === "uniCloud") {
let uniCloudConfig = customConfig[key];
if (uniCloudConfig && uniCloudConfig.envs) {
for (let envKey in uniCloudConfig.envs) {
let envItem = uniCloudConfig.envs[envKey];
if (envItem && envItem.provider && envItem.spaceId) {
let initConifg = {
provider: envItem.provider,
spaceId: envItem.spaceId
};
if (envItem.clientSecret) initConifg.clientSecret = envItem.clientSecret;
if (envItem.endpoint) initConifg.endpoint = envItem.endpoint;
uniCloudEnvs[envKey] = uniCloud.init(initConifg);
}
}
}
} else if (typeof customConfig[key] === "object" && typeof this.config[key] === "object") {
this.config[key] = Object.assign(this.config[key], customConfig[key]);
} else if (typeof customConfig[key] !== "undefined") {
this.config[key] = customConfig[key];
}
}
}
/**
* 获取vk前端配置
* 示例
* vk.callFunctionUtil.getConfig();
* vk.callFunctionUtil.getConfig("login.url");
*/
this.getConfig = (key) => {
let config = this.config;
if (key) {
return vk.pubfn.getData(config, key);
} else {
return config;
}
}
// 初始化
this.init = (obj = {}) => {
vk = obj.vk;
}
/**
* 云函数上传图片
* @param {String} title 上传时的loading提示语
* @param {String} file 要上传的文件对象,file与filePath二选一即可
* @param {String} filePath 要上传的文件路径,file与filePath二选一即可
* @param {String} suffix 指定上传后的文件后缀,如果传了file 参数,则此参数可不传
* @param {String} provider 云存储供应商,支持:unicloud、aliyun
* @param {String} cloudPath 指定上传后的云端文件路径(不指定会自动生成)cloudPath优先级大于cloudDirectory
* @param {String} cloudDirectory 指定上传后的云端文件目录(不指定会自动生成)
* @param {String} needSave 是否需要将图片信息保存到admin素材库
* @param {String} category_id 素材库分类id,当needSave为true时生效
* @param {String} uniCloud 上传到其他空间时使用,uniCloud和env二选一即可
* @param {String} env 上传到其他空间时使用,uniCloud和env二选一即可
* @param {String} cloudPathAsRealPath 阿里云目录支持,需HBX3.8.5以上版本才支持
* @param {String} cloudPathRemoveChinese 删除文件名中的中文
* @param {String} fileType 文件类型,可选image、video、audio 不用传,会自动识别
* @param {Function} onUploadProgress 上传进度回调
* @param {Function} success 上传成功时,执行的回调函数
* @param {Function} fail 上传失败时,执行的回调函数
* @param {Function} complete 无论上传成功与否,都会执行的回调函数
* vk.callFunctionUtil.uploadFile
*/
this.uploadFile = (obj = {}) => {
let that = this;
let config = that.config;
if (!obj.filePath && obj.file && obj.file.path) obj.filePath = obj.file.path;
let {
filePath,
cloudPath,
title,
errorToast,
needAlert,
success,
fail,
complete,
type,
provider,
file = {},
needSave = false,
category_id,
uniCloud: myCloud,
env = "default",
cloudPathAsRealPath = true, // 阿里云目录支持,需HBX3.8.5以上版本才支持
cloudPathRemoveChinese = true, // 删除文件名中的中文
cloudDirectory,
} = obj;
// 获取文件类型(image:图片 video:视频 other:其他)
let fileType = this.getFileType(obj);
obj.fileType = fileType;
if (type && !provider) provider = type;
if (!provider) {
let aliyunOSS = vk.pubfn.getData(config, "service.aliyunOSS");
if (aliyunOSS && aliyunOSS.isDefault) {
provider = "aliyun";
} else {
provider = "unicloud";
}
}
if (provider === "aliyun") {
return vk.aliyunOSSUtil.uploadFile(obj);
}
if (title) vk.showLoading(title);
if (errorToast) needAlert = false;
// 生成文件名
if (!cloudPath) cloudPath = this.createFileName(obj);
let Logger = {};
if (config.debug) Logger.filePath = filePath;
if (config.debug) Logger.startTime = Date.now();
let runCloud = myCloud || uniCloudEnvs[env] || uniCloud;
return new Promise((resolve, reject) => {
runCloud.uploadFile({
filePath: filePath,
cloudPath: cloudPath,
fileType: fileType,
cloudPathAsRealPath,
onUploadProgress: function(progressEvent) {
let percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
if (typeof obj.onUploadProgress == "function") {
obj.onUploadProgress({
progressEvent,
percentCompleted,
progress: percentCompleted
});
}
},
success(res) {
if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res;
if (title) vk.hideLoading();
uniCloud.getTempFileURL({
fileList: [res.fileID],
success(data) {
let { fileID, tempFileURL } = data.fileList[0];
res.fileID = tempFileURL;
res.url = tempFileURL;
res.file_id = fileID;
if (config.debug) Logger.result.url = tempFileURL;
if (typeof success == "function") success(res);
resolve(res);
if (needSave) {
// 保存文件记录到数据库
vk.userCenter.addUploadRecord({
data: {
url: res.url,
name: file.name,
size: file.size,
file_id: res.file_id,
provider,
category_id,
},
filePath,
fileType,
success: function() {
if (typeof obj.addSuccess == "function") obj.addSuccess(res);
},
fail: function(res) {
if (typeof obj.addFail === "function") obj.addFail(res);
}
});
}
}
});
},
fail(err) {
if (title) vk.hideLoading();
if (config.debug) Logger.error = err;
if (errorToast) vk.toast(JSON.stringify(err), "none");
if (needAlert) {
if (config.debug) vk.alert(JSON.stringify(err));
}
if (typeof fail == "function") fail(err);
reject(err);
},
complete() {
if (config.debug) {
Logger.endTime = Date.now();
Logger.runTime = (Logger.endTime - Logger.startTime);
let colorArr = config.logger.colorArr;
let colorStr = colorArr[counterNum % colorArr.length];
counterNum++;
console.log("%c--------【开始】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
console.log("【本地文件】: ", Logger.filePath);
console.log("【返回数据】: ", Logger.result);
console.log("【预览地址】: ", Logger.result.fileID);
console.log("【上传耗时】: ", Logger.runTime, "毫秒");
console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss"));
if (Logger.error) console.error("【error】:", Logger.error);
console.log("%c--------【结束】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
}
if (typeof complete == "function") complete();
}
});
});
}
}
// 云函数普通请求
runCallFunction(obj = {}) {
let that = this;
let config = that.config;
let {
url,
data,
title,
loading,
isRequest,
name,
complete,
uniCloud: myCloud,
env = "default"
} = obj;
if (title) vk.showLoading(title);
if (loading) vk.setLoading(true, loading);
if (!name) name = config.isTest ? config.testFunctionName : config.functionName;
obj.name = name;
let Logger = {};
if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data;
let promiseAction = new Promise(function(resolve, reject) {
if (config.debug) Logger.startTime = Date.now();
let runCloud = myCloud || uniCloudEnvs[env] || uniCloud;
runCloud.callFunction({
name: name,
data: {
$url: url,
data: data
},
success(res = {}) {
that.callFunctionSuccess({
res: res.result,
params: obj,
Logger,
resolve,
reject
});
},
fail(res) {
that.callFunctionFail({
res,
params: obj,
Logger,
reject,
sysFail: true
});
},
complete(res) {
that.callFunctionComplete({
res,
params: obj,
Logger
});
}
});
});
promiseAction.catch(error => {});
return promiseAction;
}
// 云函数url化请求
runRequest(obj = {}) {
let that = this;
let config = that.config;
let {
url,
data,
title,
loading,
name,
complete
} = obj;
if (typeof obj.needAlert === "undefined") obj.needAlert = true;
if (!name) name = config.isTest ? config.testFunctionName : config.functionName;
obj.name = name;
let requestUrl = config.functionNameToUrl[name];
let Logger = {};
if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data;
let uniIdToken = uni.getStorageSync(config.uniIdTokenKeyName);
let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName);
if (title) vk.showLoading(title);
if (loading) vk.setLoading(true, loading);
let promiseAction = new Promise(function(resolve, reject) {
if (config.debug) Logger.startTime = Date.now();
uni.request({
method: "POST",
url: requestUrl,
data: {
$url: url,
data: data,
uniIdToken: uniIdToken
},
success(res = {}) {
that.callFunctionSuccess({
res: res.data,
params: obj,
Logger,
resolve,
reject
});
},
fail(res) {
that.callFunctionFail({
res,
params: obj,
Logger,
reject,
sysFail: true
});
},
complete(res) {
that.callFunctionComplete({
res,
params: obj,
Logger
});
}
});
});
promiseAction.catch(error => {});
return promiseAction;
}
// 云函数请求成功时执行
callFunctionSuccess(obj) {
let that = this;
let config = that.config;
let {
res = {},
params,
Logger,
resolve,
reject
} = obj;
let {
title,
loading,
success
} = params;
if (title) vk.hideLoading();
if (loading) vk.setLoading(false, loading);
if (typeof res.code === "undefined" && typeof res.errCode !== "undefined") res.code = res.errCode;
let code = res.code;
if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res;
if (code == 0 || res.key == 1 || (code == undefined && res.uid)) {
if (res.vk_uni_token) that.saveToken(res.vk_uni_token);
if (res.userInfo && res.needUpdateUserInfo) that.updateUserInfo(res);
if (typeof success == "function") success(res);
resolve(res);
} else if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(code) > -1 && res.msg.indexOf("token") > -1) {
// 执行 login 拦截器函数(跳转到页面页面)
if (typeof that.interceptor.login === "function") {
that.interceptor.login({
res,
params,
vk
});
}
reject(res);
} else {
that.callFunctionFail({
res,
params,
Logger,
reject
});
}
}
// 云函数请求失败时执行
callFunctionFail(obj) {
let that = this;
let config = that.config;
let { globalErrorCode = {} } = config;
let {
res = {},
params,
Logger,
reject,
sysFail
} = obj;
let {
title,
loading,
errorToast,
noAlert,
needAlert,
fail,
} = params;
// 只有是系统异常时才进行重试
if (params.needRetry) {
if (sysFail || (res.code && [90001].indexOf(res.code) > -1)) {
if (!obj.hookResult || (typeof obj.hookResult === "function" && !obj.hookResult(err))) {
Logger.sysFail = true;
if (typeof params.retry == "function") params.retry(res, params);
return false;
}
}
}
if (typeof noAlert !== "undefined") needAlert = !noAlert;
if (typeof needAlert === "undefined") {
needAlert = (typeof fail === "function") ? false : true;
}
if (errorToast) needAlert = false;
if (title) vk.hideLoading();
if (loading) vk.setLoading(false, loading);
let errMsg = "";
let sysErr = false;
if (typeof res.code !== "undefined") {
if (res.msg) {
errMsg = res.msg;
} else if (res.errMsg) {
errMsg = res.errMsg;
} else if (res.message) {
errMsg = res.message;
}
} else {
sysErr = true;
errMsg = JSON.stringify(res);
}
if (typeof errMsg !== "string") errMsg = JSON.stringify(errMsg);
if (!errMsg) errMsg = "";
if (res.code >= 90001 && errMsg.indexOf("数据库") > -1) {
sysErr = true;
} else if ([404, 500].indexOf(res.code) > -1 && errMsg.indexOf("云函数") > -1) {
sysErr = true;
} else if ((res.code === 501 && errMsg.indexOf("timeout for 10000ms") > -1) || (res.code === "SYS_ERR" && errMsg.indexOf(": request:ok") > -1)) {
errMsg = globalErrorCode["cloudfunction-unusual-timeout"] || "请求超时,但请求还在执行,请重新进入页面。";
} else if (typeof errMsg.toLowerCase === "function" && (errMsg.toLowerCase().indexOf("timeout") > -1 || errMsg.toLowerCase().indexOf("etimedout") > -1)) {
sysErr = true;
errMsg = globalErrorCode["cloudfunction-timeout"] || "请求超时,请重试!";
} else if (errMsg.indexOf("reaches burst limit") > -1) {
errMsg = globalErrorCode["cloudfunction-reaches-burst-limit"] || "系统繁忙,请稍后再试。";
} else if (res.code === "InternalServerError") {
sysErr = true;
}
let runKey = true;
if (typeof that.interceptor.fail == "function") {
runKey = that.interceptor.fail({
vk,
res: res,
params: params
});
if (runKey === undefined) runKey = true;
}
if (runKey) {
Logger.error = res;
if (errorToast) vk.toast(errMsg, "none");
if (needAlert && vk.pubfn.isNotNull(errMsg)) {
if (sysErr) {
let toastMsg = globalErrorCode["cloudfunction-system-error"] || "网络开小差了!";
vk.toast(toastMsg, "none");
} else {
vk.alert(errMsg);
}
}
if (typeof fail == "function") fail(res);
}
if (typeof reject == "function") reject(res);
}
// 云函数请求完成后执行
callFunctionComplete(obj) {
let that = this;
let config = that.config;
let {
res = {},
params,
Logger
} = obj;
let {
name,
url,
isRequest,
complete,
debug: debugLog
} = params;
if (params.needRetry && Logger.sysFail) {
return false;
}
if (typeof debugLog === "undefined") debugLog = config.debug;
if (debugLog) {
Logger.endTime = Date.now();
if (isRequest) {
Logger.label = "【url化】";
} else {
Logger.label = "";
}
Logger.runTime = (Logger.endTime - Logger.startTime);
let colorArr = config.logger.colorArr;
let colorStr = colorArr[counterNum % colorArr.length];
counterNum++;
let functionType = url.indexOf(".") > -1 ? "云对象" : "云函数";
console.log(`%c--------【开始】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`);
console.log("【请求参数】: ", Logger.params);
console.log("【返回数据】: ", Logger.result);
console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】");
console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss"));
if (Logger.error) {
let errorLog = console.warn || console.error;
if (Logger.error.err && Logger.error.err.stack) {
console.error("【Error】: ", Logger.error);
console.error("【Stack】: ", Logger.error.err.stack);
} else {
errorLog("【Error】: ", Logger.error);
}
}
console.log(`%c--------【结束】${Logger.label}【${functionType}请求】【${name}】【${url}】--------`, `color: ${colorStr};font-size: 12px;font-weight: bold;`);
}
if (typeof complete == "function") complete(res);
}
// 生成文件名
createFileName(obj = {}) {
let {
file,
filePath,
index = 0,
cloudPathRemoveChinese = true,
cloudDirectory
} = obj;
let suffix = this.getFileSuffix(obj);
let oldName = index + "." + suffix;
// 注意:小程序无法获取到 file.name
if (file && file.name) {
let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1);
if (suffixName && suffixName.length < 5) oldName = file.name;
// 只保留["数字","英文",".","-"]
if (cloudPathRemoveChinese) {
oldName = oldName.replace(/[^a-zA-Z.-d]/g, '');
}
if (oldName.indexOf(".") == 0) oldName = "0" + oldName;
}
let date = new Date();
let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd");
let dateTime = date.getTime().toString(); // 时间戳
// 时间戳后8位
let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length);
let randomNumber = vk.pubfn.random(8); // 8位随机数
// 文件路径
let newFilePath = "";
if (cloudDirectory) {
// 如果自定义了上传目录,则使用自定义的上传目录
if (cloudDirectory.lastIndexOf("/") !== cloudDirectory.length-1) {
cloudDirectory = cloudDirectory + "/";
}
newFilePath = cloudDirectory;
} else {
// 否则,使用年月日作为上传目录
newFilePath = dateYYYYMMDD + "/";
}
// 文件名 = 时间戳后8位 - 随机数8位 + 原本文件名
let fileNickName = dateTimeEnd8 + "-" + randomNumber + "-" + oldName;
// 文件名全称(包含文件路径) = 文件路径 + 文件名
let fileFullName = newFilePath + fileNickName;
return fileFullName;
}
getFileSuffix(obj = {}) {
let {
file,
filePath,
suffix = "png"
} = obj;
if (filePath) {
let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1);
if (suffixName && suffixName.length < 5) suffix = suffixName;
}
if (file) {
if (file.path) {
let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1);
if (suffixName && suffixName.length < 5) suffix = suffixName;
}
if (file.name) {
let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1);
if (suffixName && suffixName.length < 5) suffix = suffixName;
}
}
return suffix;
}
getFileType(obj = {}) {
let {
file,
filePath
} = obj;
let fileType = "other";
let suffix = this.getFileSuffix(obj);
if (["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"].indexOf(suffix) > -1) {
fileType = "image";
} else if (["avi", "mp3", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"].indexOf(suffix) > -1) {
fileType = "video";
}
return fileType;
}
// 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中)
callFunctionRetry(obj = {}) {
let { retryCount } = obj;
delete obj.retryCount;
return new Promise((resolve, reject) => {
this.callRetryFn(obj, resolve, reject, retryCount);
});
}
// 重试实现
callRetryFn(obj, resolve, reject, retryCount) {
let that = this;
let debug = that.config.debug;
that.callFunction({
...obj,
needRetry: retryCount ? true : false, // 判断是否需要重试
retry: function(err) {
obj.runCount = obj.runCount ? obj.runCount + 1 : 1;
obj.needRetry = retryCount > obj.runCount ? true : false; // 判断是否需要重试
let errorMsg = err.message ? `异常信息:${err.message}` : "";
if (debug) console.log(`【请求失败】正在第【${obj.runCount}】次重试:${obj.url}`);
if (obj.retryInterval) {
setTimeout(function() {
that._callRetryFn(obj, resolve, reject, retryCount);
}, obj.retryInterval);
} else {
// 如果无延迟,则不写setTimeout,因为setTimeout 即使time为0,也有一定延迟。
that._callRetryFn(obj, resolve, reject, retryCount);
}
}
});
}
_callRetryFn(obj, resolve, reject, retryCount) {
if (obj.runCount < retryCount) {
this.callRetryFn(obj, resolve, reject, retryCount);
} else {
this.callFunction(obj).catch((err) => {
reject();
});
}
}
}
export default new CallFunctionUtil