vk-unicloud-callFunctionUtil.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. var vk = {};
  2. var counterNum = 0;
  3. var uniCloudEnvs = {};
  4. class CallFunctionUtil {
  5. constructor() {
  6. this.config = {
  7. // 是否开启测试环境的云函数,true:使用测试环境,false:使用正式环境,默认true
  8. isTest: false,
  9. // 设为false可关闭打印日志
  10. debug: true,
  11. // 云函数路由(主函数名)
  12. functionName: "router",
  13. // 云函数路由(开发测试函数名)
  14. testFunctionName: "router-test",
  15. // 云函数url化后对应的url地址
  16. functionNameToUrl: {
  17. "router": "https://xxxxxxx.bspapp.com/http/router",
  18. "router-test": "https://xxxxxxx.bspapp.com/http/router"
  19. },
  20. // vk.callFunction的isRequest的默认值
  21. isRequestDefault:false,
  22. // 默认时区(中国为8)
  23. targetTimezone:8,
  24. // 客户端登录页面地址
  25. login: {
  26. url: '/pages_template/uni-id/login/index/index'
  27. },
  28. // 请求配置
  29. request: {
  30. // 公共请求参数(每次请求都会带上的参数)
  31. dataParam: {}
  32. },
  33. // 日志风格
  34. logger: {
  35. colorArr: [
  36. "#0095ff",
  37. "#67C23A"
  38. ]
  39. },
  40. // 缓存键名 - token(请勿修改)
  41. uniIdTokenKeyName: "uni_id_token",
  42. // 缓存键名 - token过期时间(请勿修改)
  43. uniIdTokenExpiredKeyName: "uni_id_token_expired",
  44. // 缓存键名 - 当前登录用户信息(请勿修改)
  45. uniIdUserInfoKeyName: "uni_id_user_info",
  46. // 缓存键名 - 公共请求参数(请勿修改)
  47. requestGlobalParamKeyName: "vk_request_global_param",
  48. // 自定义组件配置
  49. components: {}
  50. }
  51. // 保存新的token
  52. this.saveToken = (res = {}) => {
  53. let config = this.config;
  54. vk.setStorageSync(config.uniIdTokenKeyName, res.token);
  55. vk.setStorageSync(config.uniIdTokenExpiredKeyName, res.tokenExpired);
  56. if (this.config.debug) console.log("--------【token已更新】--------");
  57. }
  58. // 删除token,并删除userInfo缓存
  59. this.deleteToken = () => {
  60. let config = this.config;
  61. vk.removeStorageSync(config.uniIdTokenKeyName);
  62. vk.removeStorageSync(config.uniIdTokenExpiredKeyName);
  63. this.deleteUserInfo();
  64. if (this.config.debug) console.log("--------【token已删除】--------");
  65. }
  66. // 更新userInfo缓存
  67. this.updateUserInfo = (res = {}) => {
  68. let config = this.config;
  69. let {
  70. userInfo = {}
  71. } = res;
  72. if (typeof vk.setVuex === "function") {
  73. // 有安装vuex则使用vuex
  74. vk.setVuex('$user.userInfo', userInfo);
  75. } else {
  76. // 否则使用本地缓存
  77. vk.setStorageSync(config.uniIdUserInfoKeyName, userInfo);
  78. }
  79. if (this.config.debug) console.log("--------【用户信息已更新】--------");
  80. }
  81. // 删除userInfo缓存
  82. this.deleteUserInfo = (res = {}) => {
  83. let config = this.config;
  84. if (typeof vk.setVuex === "function") {
  85. // 有安装vuex则使用vuex
  86. vk.setVuex('$user.userInfo', {});
  87. vk.setVuex('$user.permission', []);
  88. vk.removeStorageSync(config.uniIdUserInfoKeyName);
  89. } else {
  90. // 否则使用本地缓存
  91. vk.removeStorageSync(config.uniIdUserInfoKeyName);
  92. }
  93. if (this.config.debug) console.log("--------【用户信息已删除】--------");
  94. }
  95. // 检查token是否有效(本地版)
  96. // let valid = vk.callFunctionUtil.checkToken();
  97. this.checkToken = (res = {}) => {
  98. let config = this.config;
  99. let token = uni.getStorageSync(config.uniIdTokenKeyName);
  100. let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName);
  101. let valid = false;
  102. if (token && tokenExpired && tokenExpired > Date.now()) {
  103. valid = true;
  104. }
  105. return valid;
  106. }
  107. /**
  108. * 修改请求配置中的公共请求参数
  109. * 若把shop-manage改成*则代表全局
  110. vk.callFunctionUtil.updateRequestGlobalParam({
  111. "shop-manage":{
  112. regExp:"^xxx/kh/",
  113. data:{
  114. shop_id : shop_id
  115. }
  116. }
  117. });
  118. 对应的callFunction中增加参数globalParamName:"shop-manage"
  119. vk.callFunction({
  120. url: 'xxx/xxxxxx',
  121. title: '请求中...',
  122. globalParamName:"shop-manage",// 如果设置了正则规则,则不需要此参数
  123. data: {},
  124. success(data) {
  125. }
  126. });
  127. */
  128. this.updateRequestGlobalParam = (data = {}, setKey) => {
  129. let config = this.config;
  130. if (setKey) {
  131. // 覆盖对象
  132. config.request.dataParam = data;
  133. } else {
  134. // 覆盖参数(有就覆盖,没有则新增)
  135. let dataParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
  136. config.request.dataParam = Object.assign(dataParam, data);
  137. }
  138. vk.setStorageSync(config.requestGlobalParamKeyName, config.request.dataParam);
  139. }
  140. /**
  141. * 获取请求配置中的公共请求参数
  142. vk.callFunctionUtil.getRequestGlobalParam();
  143. */
  144. this.getRequestGlobalParam = (globalParamName = "*") => {
  145. let config = this.config;
  146. let data = config.request.dataParam;
  147. if (!data || JSON.stringify(data) === "{}") {
  148. data = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
  149. config.request.dataParam = data;
  150. }
  151. let param = data[globalParamName] || {};
  152. return JSON.parse(JSON.stringify(param));
  153. }
  154. /**
  155. * 删除请求配置中的公共请求参数
  156. * globalParamName 不传代表删除所有
  157. vk.callFunctionUtil.deleteRequestGlobalParam(globalParamName);
  158. */
  159. this.deleteRequestGlobalParam = (globalParamName) => {
  160. let config = this.config;
  161. let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
  162. if (globalParamName) {
  163. delete globalParam[globalParamName];
  164. } else {
  165. globalParam = {};
  166. }
  167. config.request.dataParam = globalParam;
  168. vk.setStorageSync(config.requestGlobalParamKeyName, globalParam);
  169. }
  170. // 拦截器
  171. this.interceptor = {
  172. // 拦截1301、1302错误码(非法token和token失效)
  173. login: (obj = {}) => {
  174. let {
  175. params,
  176. res
  177. } = obj;
  178. let config = this.config;
  179. let callFunction = this.callFunction;
  180. if (config.debug) console.log("跳登录页面");
  181. let { tokenExpiredAutoDelete = true } = config;
  182. if (tokenExpiredAutoDelete) this.deleteToken();
  183. setTimeout(() => {
  184. if (config.login.url) {
  185. let currentPage = getCurrentPages()[getCurrentPages().length - 1];
  186. if (currentPage && currentPage.route && "/" + currentPage.route === config.login.url) {
  187. return false;
  188. }
  189. // 此处代码是为了防止首页启动时检测和正常检测冲突-----------------------------------------------------------
  190. if (vk.navigate.isOnLaunchToLogin) {
  191. setTimeout(() => {
  192. vk.navigate.isOnLaunchToLogin = false;
  193. }, 500);
  194. return false;
  195. }
  196. // 此处代码是为了防止首页启动时检测和正常检测冲突-----------------------------------------------------------
  197. uni.navigateTo({
  198. url: config.login.url,
  199. events: {
  200. // 监听登录成功后的事件
  201. loginSuccess: function(data) {
  202. let num = 2;
  203. let pages = getCurrentPages();
  204. if (pages.length >= num) {
  205. let that = pages[pages.length - num];
  206. if (typeof that.onLoad == "function") {
  207. // 重新执行页面onLoad函数
  208. that.onLoad(that.options);
  209. } else if (typeof that.init == "function") {
  210. // 重新执行页面初始化函数
  211. that.init(that.options);
  212. } else {
  213. // 重新执行一次云函数调用
  214. callFunction(params);
  215. }
  216. } else {
  217. // 重新执行一次云函数调用
  218. callFunction(params);
  219. }
  220. }
  221. }
  222. });
  223. } else {
  224. if (params.needAlert) {
  225. vk.alert(res.result.msg);
  226. }
  227. }
  228. }, 0);
  229. },
  230. // 全局请求失败拦截器
  231. fail: (obj = {}) => {
  232. return true;
  233. }
  234. }
  235. /**
  236. * 云函数请求封装 - 统一入口
  237. * @description 通过云函数路由,1个云函数实现多个云函数的效果。
  238. * @param {String} url 请求路径
  239. * @param {Object} data 请求参数,如 { a:1, b:"2" } 云函数内可通过 let { a, b } = data; 获取参数
  240. * @param {String} title 遮罩层提示语,为空或不传则代表不显示遮罩层。
  241. * @param {Boolean} isRequest 是否使用云函数url化地址访问云函数,默认false
  242. * @param {Boolean} needAlert 为true代表请求错误时,会有弹窗提示,默认为true
  243. * @param {Function} success 请求成功时,执行的回调函数
  244. * @param {Function} fail 请求失败时,执行的回调函数
  245. * @param {Function} complete 无论请求成功与否,都会执行的回调函数
  246. */
  247. this.callFunction = (obj = {}) => {
  248. let that = this;
  249. let { config } = that;
  250. let {
  251. url,
  252. data = {},
  253. globalParamName
  254. } = obj;
  255. if (obj.retryCount) {
  256. // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中)
  257. return that.callFunctionRetry(obj);
  258. }
  259. // 去除值为 undefined 的参数
  260. if (typeof data === "object") {
  261. obj.data = vk.pubfn.copyObject(data);
  262. }
  263. // 注入自定义全局参数开始-----------------------------------------------------------
  264. let globalParam = uni.getStorageSync(config.requestGlobalParamKeyName) || {};
  265. // 根据正则规格自动匹配全局请求参数
  266. for (let i in globalParam) {
  267. let customDate = globalParam[i];
  268. if (customDate.regExp) {
  269. if (typeof customDate.regExp === "object") {
  270. // 数组形式
  271. for (let i = 0; i < customDate.regExp.length; i++) {
  272. let regExp = new RegExp(customDate.regExp[i]);
  273. if (regExp.test(url)) {
  274. obj.data = Object.assign(customDate.data, obj.data);
  275. break;
  276. }
  277. }
  278. } else {
  279. // 字符串形式
  280. let regExp = new RegExp(customDate.regExp);
  281. if (regExp.test(url)) {
  282. obj.data = Object.assign(customDate.data, obj.data);
  283. }
  284. }
  285. }
  286. }
  287. // 根据指定globalParamName匹配全局请求参数
  288. let customDate = that.getRequestGlobalParam(globalParamName);
  289. if (customDate && JSON.stringify(customDate) !== "{}") {
  290. if (customDate.regExp) {
  291. obj.data = Object.assign(customDate.data, obj.data); // 新版本
  292. } else {
  293. obj.data = Object.assign(customDate, obj.data); // 兼容旧版本
  294. }
  295. }
  296. // 注入自定义全局参数结束-----------------------------------------------------------
  297. // 若执行的函数不是pub类型函数,则先本地判断下token,可以提高效率。
  298. // if (url.indexOf("/pub/") == -1 && url.indexOf("/pub_") == -1) {
  299. // 若执行的函数是kh或sys类型函数,先本地判断下token,可以提高效率。
  300. if (url.indexOf("/kh/") > -1 || url.indexOf("/sys/") > -1 || (url.indexOf(".") > -1 && url.indexOf("pub_") == -1 && url.indexOf("/pub/") == -1 && url.indexOf("/pub.") == -1)) {
  301. if (!vk.checkToken()) {
  302. // 若本地token校验未通过,则直接执行 login 拦截器函数
  303. return new Promise((resolve, reject) => {
  304. // 执行 login 拦截器函数(跳转到页面页面)
  305. let res = { code: 30204, msg: "本地token校验未通过" };
  306. let params = obj;
  307. if (typeof that.interceptor.login === "function") {
  308. that.interceptor.login({
  309. res,
  310. params,
  311. vk
  312. });
  313. }
  314. reject(res);
  315. });
  316. }
  317. }
  318. if (typeof obj.isRequest === "undefined"){
  319. obj.isRequest = config.isRequestDefault;
  320. }
  321. // 执行请求
  322. if (obj.isRequest) {
  323. return that.runRequest(obj);
  324. } else {
  325. return that.runCallFunction(obj);
  326. }
  327. }
  328. // 设置全局默认配置
  329. this.setConfig = (customConfig = {}) => {
  330. for (let key in customConfig) {
  331. if (key === "vk") {
  332. vk = customConfig[key];
  333. } else if (key === "interceptor") {
  334. this.interceptor = Object.assign(this.interceptor, customConfig[key]);
  335. this.config.interceptor = customConfig[key];
  336. } else if (key === "myfn") {
  337. vk.myfn = customConfig[key];
  338. } else if (key === "loginPagePath") {
  339. // 兼容老版本
  340. this.config.login.url = customConfig[key];
  341. } else if (key === "uniCloud") {
  342. let uniCloudConfig = customConfig[key];
  343. if (uniCloudConfig && uniCloudConfig.envs) {
  344. for (let envKey in uniCloudConfig.envs) {
  345. let envItem = uniCloudConfig.envs[envKey];
  346. if (envItem && envItem.provider && envItem.spaceId) {
  347. let initConifg = {
  348. provider: envItem.provider,
  349. spaceId: envItem.spaceId
  350. };
  351. if (envItem.clientSecret) initConifg.clientSecret = envItem.clientSecret;
  352. if (envItem.endpoint) initConifg.endpoint = envItem.endpoint;
  353. uniCloudEnvs[envKey] = uniCloud.init(initConifg);
  354. }
  355. }
  356. }
  357. } else if (typeof customConfig[key] === "object" && typeof this.config[key] === "object") {
  358. this.config[key] = Object.assign(this.config[key], customConfig[key]);
  359. } else if (typeof customConfig[key] !== "undefined") {
  360. this.config[key] = customConfig[key];
  361. }
  362. }
  363. }
  364. // 获取全局默认配置
  365. this.getConfig = () => {
  366. return this.config;
  367. }
  368. // 初始化
  369. this.init = (obj = {}) => {
  370. vk = obj.vk;
  371. }
  372. /**
  373. * 云函数上传图片
  374. * @param {String} filePath 要上传的文件对象
  375. * @param {String} cloudPath 文件的绝对路径,包含文件名(若不传,会自动生成文件名)
  376. * @param {String} fileType 文件类型,可选image、video、audio 默认image
  377. * @param {Function} onUploadProgress 上传进度回调
  378. * @param {Function} success 请求成功时,执行的回调函数
  379. * @param {Function} fail 请求失败时,执行的回调函数
  380. * @param {Function} complete 无论请求成功与否,都会执行的回调函数
  381. * vk.callFunctionUtil.uploadFile
  382. */
  383. this.uploadFile = (obj = {}) => {
  384. let that = this;
  385. let config = that.config;
  386. let {
  387. filePath,
  388. cloudPath,
  389. title,
  390. errorToast,
  391. needAlert,
  392. success,
  393. fail,
  394. complete,
  395. type,
  396. provider,
  397. file = {},
  398. needSave = false,
  399. category_id,
  400. uniCloud: myCloud,
  401. env = "default"
  402. } = obj;
  403. // 获取文件类型(image:图片 video:视频 other:其他)
  404. let fileType = this.getFileType(obj);
  405. obj.fileType = fileType;
  406. if (type && !provider) provider = type;
  407. if (!provider) {
  408. let aliyunOSS = vk.pubfn.getData(config, "service.aliyunOSS");
  409. if (aliyunOSS && aliyunOSS.isDefault) {
  410. provider = "aliyun";
  411. } else {
  412. provider = "unicloud";
  413. }
  414. }
  415. if (provider === "aliyun") {
  416. return vk.aliyunOSSUtil.uploadFile(obj);
  417. }
  418. if (title) vk.showLoading(title);
  419. if (errorToast) needAlert = false;
  420. // 生成文件名
  421. if (!cloudPath) cloudPath = this.createFileName(obj);
  422. let Logger = {};
  423. if (config.debug) Logger.filePath = filePath;
  424. if (config.debug) Logger.startTime = Date.now();
  425. let runCloud = myCloud || uniCloudEnvs[env] || uniCloud;
  426. return new Promise((resolve, reject) => {
  427. runCloud.uploadFile({
  428. filePath: filePath,
  429. cloudPath: cloudPath,
  430. fileType: fileType,
  431. onUploadProgress: function(progressEvent) {
  432. let percentCompleted = Math.round(
  433. (progressEvent.loaded * 100) / progressEvent.total
  434. );
  435. if (typeof obj.onUploadProgress == "function") {
  436. obj.onUploadProgress({
  437. progressEvent,
  438. percentCompleted,
  439. progress: percentCompleted
  440. });
  441. }
  442. },
  443. success(res) {
  444. if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res;
  445. if (title) vk.hideLoading();
  446. uniCloud.getTempFileURL({
  447. fileList: [res.fileID],
  448. success(data) {
  449. let { fileID, tempFileURL } = data.fileList[0];
  450. res.fileID = tempFileURL;
  451. res.url = tempFileURL;
  452. res.file_id = fileID;
  453. if (config.debug) Logger.result.url = tempFileURL;
  454. if (typeof success == "function") success(res);
  455. resolve(res);
  456. if (needSave) {
  457. // 保存文件记录到数据库
  458. vk.userCenter.addUploadRecord({
  459. data: {
  460. url: res.url,
  461. name: file.name,
  462. size: file.size,
  463. file_id: res.file_id,
  464. provider,
  465. category_id,
  466. },
  467. filePath,
  468. fileType,
  469. success: function() {
  470. if (typeof obj.addSuccess == "function") obj.addSuccess(res);
  471. },
  472. fail: function(res) {
  473. if (typeof obj.addFail === "function") obj.addFail(res);
  474. }
  475. });
  476. }
  477. }
  478. });
  479. },
  480. fail(err) {
  481. if (title) vk.hideLoading();
  482. if (config.debug) Logger.error = err;
  483. if (errorToast) vk.toast(JSON.stringify(err), "none");
  484. if (needAlert) {
  485. if (config.debug) vk.alert(JSON.stringify(err));
  486. }
  487. if (typeof fail == "function") fail(err);
  488. reject(err);
  489. },
  490. complete() {
  491. if (config.debug) {
  492. Logger.endTime = Date.now();
  493. Logger.runTime = (Logger.endTime - Logger.startTime);
  494. let colorArr = config.logger.colorArr;
  495. let colorStr = colorArr[counterNum % colorArr.length];
  496. counterNum++;
  497. console.log("%c--------【开始】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
  498. console.log("【本地文件】: ", Logger.filePath);
  499. console.log("【返回数据】: ", Logger.result);
  500. console.log("【预览地址】: ", Logger.result.fileID);
  501. console.log("【上传耗时】: ", Logger.runTime, "毫秒");
  502. console.log("【上传时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss"));
  503. if (Logger.error) console.error("【error】:", Logger.error);
  504. console.log("%c--------【结束】【文件上传】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
  505. }
  506. if (typeof complete == "function") complete();
  507. }
  508. });
  509. });
  510. }
  511. }
  512. // 云函数普通请求
  513. runCallFunction(obj = {}) {
  514. let that = this;
  515. let config = that.config;
  516. let {
  517. url,
  518. data,
  519. title,
  520. loading,
  521. isRequest,
  522. name,
  523. complete,
  524. uniCloud: myCloud,
  525. env = "default"
  526. } = obj;
  527. if (title) vk.showLoading(title);
  528. if (loading) vk.setLoading(true, loading);
  529. if (!name) name = config.isTest ? config.testFunctionName : config.functionName;
  530. obj.name = name;
  531. let Logger = {};
  532. if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data;
  533. let promiseAction = new Promise(function(resolve, reject) {
  534. if (config.debug) Logger.startTime = Date.now();
  535. let runCloud = myCloud || uniCloudEnvs[env] || uniCloud;
  536. runCloud.callFunction({
  537. name: name,
  538. data: {
  539. $url: url,
  540. data: data
  541. },
  542. success(res = {}) {
  543. that.callFunctionSuccess({
  544. res: res.result,
  545. params: obj,
  546. Logger,
  547. resolve,
  548. reject
  549. });
  550. },
  551. fail(res) {
  552. that.callFunctionFail({
  553. res,
  554. params: obj,
  555. Logger,
  556. reject,
  557. sysFail: true
  558. });
  559. },
  560. complete(res) {
  561. that.callFunctionComplete({
  562. res,
  563. params: obj,
  564. Logger
  565. });
  566. }
  567. });
  568. });
  569. promiseAction.catch(error => {});
  570. return promiseAction;
  571. }
  572. // 云函数url化请求
  573. runRequest(obj = {}) {
  574. let that = this;
  575. let config = that.config;
  576. let {
  577. url,
  578. data,
  579. title,
  580. loading,
  581. name,
  582. complete
  583. } = obj;
  584. if (typeof obj.needAlert === "undefined") obj.needAlert = true;
  585. if (!name) name = config.isTest ? config.testFunctionName : config.functionName;
  586. obj.name = name;
  587. let requestUrl = config.functionNameToUrl[name];
  588. let Logger = {};
  589. if (config.debug) Logger.params = typeof data == "object" ? JSON.parse(JSON.stringify(data)) : data;
  590. let uniIdToken = uni.getStorageSync(config.uniIdTokenKeyName);
  591. let tokenExpired = uni.getStorageSync(config.uniIdTokenExpiredKeyName);
  592. if (title) vk.showLoading(title);
  593. if (loading) vk.setLoading(true, loading);
  594. let promiseAction = new Promise(function(resolve, reject) {
  595. if (config.debug) Logger.startTime = Date.now();
  596. uni.request({
  597. method: "POST",
  598. url: requestUrl,
  599. data: {
  600. $url: url,
  601. data: data,
  602. uniIdToken: uniIdToken
  603. },
  604. success(res = {}) {
  605. that.callFunctionSuccess({
  606. res: res.data,
  607. params: obj,
  608. Logger,
  609. resolve,
  610. reject
  611. });
  612. },
  613. fail(res) {
  614. that.callFunctionFail({
  615. res,
  616. params: obj,
  617. Logger,
  618. reject,
  619. sysFail: true
  620. });
  621. },
  622. complete(res) {
  623. that.callFunctionComplete({
  624. res,
  625. params: obj,
  626. Logger
  627. });
  628. }
  629. });
  630. });
  631. promiseAction.catch(error => {});
  632. return promiseAction;
  633. }
  634. // 云函数请求成功时执行
  635. callFunctionSuccess(obj) {
  636. let that = this;
  637. let config = that.config;
  638. let {
  639. res = {},
  640. params,
  641. Logger,
  642. resolve,
  643. reject
  644. } = obj;
  645. let {
  646. title,
  647. loading,
  648. success
  649. } = params;
  650. if (title) vk.hideLoading();
  651. if (loading) vk.setLoading(false, loading);
  652. if (typeof res.code === "undefined" && typeof res.errCode !== "undefined") res.code = res.errCode;
  653. let code = res.code;
  654. if (config.debug) Logger.result = typeof res == "object" ? JSON.parse(JSON.stringify(res)) : res;
  655. if (code == 0 || res.key == 1 || (code == undefined && res.uid)) {
  656. if (res.vk_uni_token) that.saveToken(res.vk_uni_token);
  657. if (res.userInfo && res.needUpdateUserInfo) that.updateUserInfo(res);
  658. if (typeof success == "function") success(res);
  659. resolve(res);
  660. } else if ([1301, 1302, 30201, 30202, 30203, 30204].indexOf(code) > -1 && res.msg.indexOf("token") > -1) {
  661. // 执行 login 拦截器函数(跳转到页面页面)
  662. if (typeof that.interceptor.login === "function") {
  663. that.interceptor.login({
  664. res,
  665. params,
  666. vk
  667. });
  668. }
  669. reject(res);
  670. } else {
  671. that.callFunctionFail({
  672. res,
  673. params,
  674. Logger,
  675. reject
  676. });
  677. }
  678. }
  679. // 云函数请求失败时执行
  680. callFunctionFail(obj) {
  681. let that = this;
  682. let config = that.config;
  683. let { globalErrorCode = {} } = config;
  684. let {
  685. res = {},
  686. params,
  687. Logger,
  688. reject,
  689. sysFail
  690. } = obj;
  691. let {
  692. title,
  693. loading,
  694. errorToast,
  695. noAlert,
  696. needAlert,
  697. fail,
  698. } = params;
  699. // 只有是系统异常时才进行重试
  700. if (params.needRetry) {
  701. if (sysFail || (res.code && [90001].indexOf(res.code) > -1)) {
  702. if (!obj.hookResult || (typeof obj.hookResult === "function" && !obj.hookResult(err))) {
  703. Logger.sysFail = true;
  704. if (typeof params.retry == "function") params.retry(res, params);
  705. return false;
  706. }
  707. }
  708. }
  709. if (typeof noAlert !== "undefined") needAlert = !noAlert;
  710. if (typeof needAlert === "undefined") {
  711. needAlert = (typeof fail === "function") ? false : true;
  712. }
  713. if (errorToast) needAlert = false;
  714. if (title) vk.hideLoading();
  715. if (loading) vk.setLoading(false, loading);
  716. let errMsg = "";
  717. let sysErr = false;
  718. if (typeof res.code !== "undefined") {
  719. if (res.msg) {
  720. errMsg = res.msg;
  721. } else if (res.errMsg) {
  722. errMsg = res.errMsg;
  723. } else if (res.message) {
  724. errMsg = res.message;
  725. }
  726. } else {
  727. sysErr = true;
  728. errMsg = JSON.stringify(res);
  729. }
  730. if (errMsg.indexOf("timeout") > -1) {
  731. sysErr = true;
  732. errMsg = globalErrorCode["cloudfunction-timeout"] || "请求超时,请重试!";
  733. }
  734. if (res.code >= 90001 && errMsg.indexOf("数据库") > -1) {
  735. sysErr = true;
  736. } else if ([404, 500].indexOf(res.code) > -1 && errMsg.indexOf("云函数") > -1) {
  737. sysErr = true;
  738. } else if (res.code === "SYS_ERR" && errMsg.indexOf(": request:ok") > -1) {
  739. errMsg = globalErrorCode["cloudfunction-unusual-timeout"] || "请求超时,但请求还在执行,请重新进入页面。";
  740. } else if (errMsg.indexOf("reaches burst limit") > -1) {
  741. errMsg = globalErrorCode["cloudfunction-reaches-burst-limit"] || "系统繁忙,请稍后再试。";
  742. }
  743. let runKey = true;
  744. if (typeof that.interceptor.fail == "function") {
  745. runKey = that.interceptor.fail({
  746. vk,
  747. res: res,
  748. params: params
  749. });
  750. if (runKey === undefined) runKey = true;
  751. }
  752. if (runKey) {
  753. Logger.error = res;
  754. if (errorToast) vk.toast(errMsg, "none");
  755. if (needAlert && vk.pubfn.isNotNull(errMsg)) {
  756. if (sysErr) {
  757. let toastMsg = globalErrorCode["cloudfunction-system-error"] || "网络开小差了!";
  758. vk.toast(toastMsg, "none");
  759. } else {
  760. vk.alert(errMsg);
  761. }
  762. }
  763. if (typeof fail == "function") fail(res);
  764. }
  765. if (typeof reject == "function") reject(res);
  766. }
  767. // 云函数请求完成后执行
  768. callFunctionComplete(obj) {
  769. let that = this;
  770. let config = that.config;
  771. let {
  772. res = {},
  773. params,
  774. Logger
  775. } = obj;
  776. let {
  777. name,
  778. url,
  779. isRequest,
  780. complete,
  781. debug: debugLog
  782. } = params;
  783. if (params.needRetry && Logger.sysFail) {
  784. return false;
  785. }
  786. if (typeof debugLog === "undefined") debugLog = config.debug;
  787. if (debugLog) {
  788. Logger.endTime = Date.now();
  789. if (isRequest) {
  790. Logger.label = "【url化】";
  791. } else {
  792. Logger.label = "";
  793. }
  794. Logger.runTime = (Logger.endTime - Logger.startTime);
  795. let colorArr = config.logger.colorArr;
  796. let colorStr = colorArr[counterNum % colorArr.length];
  797. counterNum++;
  798. console.log("%c--------【开始】" + Logger.label + "【云函数请求】【" + name + "】【" + url + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
  799. console.log("【请求参数】: ", Logger.params);
  800. console.log("【返回数据】: ", Logger.result);
  801. console.log("【总体耗时】: ", Logger.runTime, "毫秒【含页面渲染】");
  802. console.log("【请求时间】: ", vk.pubfn.timeFormat(Logger.startTime, "yyyy-MM-dd hh:mm:ss"));
  803. if (Logger.error) {
  804. console.error("【Error】: ", Logger.error);
  805. if (Logger.error.err && Logger.error.err.stack) {
  806. console.error("【Stack】: ", Logger.error.err.stack);
  807. }
  808. }
  809. console.log("%c--------【结束】" + Logger.label + "【云函数请求】【" + name + "】【" + url + "】--------", 'color: ' + colorStr + ';font-size: 12px;font-weight: bold;');
  810. }
  811. if (typeof complete == "function") complete(res);
  812. }
  813. // 生成文件名
  814. createFileName(obj = {}) {
  815. let {
  816. index = 0,
  817. file,
  818. filePath
  819. } = obj;
  820. let suffix = this.getFileSuffix(obj);
  821. let oldName = index + "." + suffix;
  822. if (file && file.name) {
  823. let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1);
  824. if (suffixName && suffixName.length < 5) oldName = file.name;
  825. // 只保留["数字","英文",".","-"]
  826. oldName = oldName.replace(/[^a-zA-Z.-d]/g, '');
  827. if (oldName.indexOf(".") == 0) oldName = "0" + oldName;
  828. }
  829. let date = new Date();
  830. let dateYYYYMMDD = vk.pubfn.timeFormat(date, "yyyy/MM/dd");
  831. let dateTime = date.getTime().toString(); // 时间戳
  832. // 时间戳后8位
  833. let dateTimeEnd8 = dateTime.substring(dateTime.length - 8, dateTime.length);
  834. let randomNumber = vk.pubfn.random(8); // 8位随机数
  835. // 文件路径
  836. let newFilePath = dateYYYYMMDD + "/";
  837. // 文件名 = 时间戳 - 随机数32位 + 后缀名
  838. let fileNickName = dateTimeEnd8 + "-" + randomNumber + "-" + oldName;
  839. // 文件名全称(包含文件路径) = 外网域名 + 文件路径 + 文件名
  840. let fileFullName = newFilePath + fileNickName;
  841. return fileFullName;
  842. }
  843. getFileSuffix(obj = {}) {
  844. let {
  845. file,
  846. filePath
  847. } = obj;
  848. let suffix = "png";
  849. if (filePath) {
  850. let suffixName = filePath.substring(filePath.lastIndexOf(".") + 1);
  851. if (suffixName && suffixName.length < 5) suffix = suffixName;
  852. }
  853. if (file) {
  854. if (file.path) {
  855. let suffixName = file.path.substring(file.path.lastIndexOf(".") + 1);
  856. if (suffixName && suffixName.length < 5) suffix = suffixName;
  857. }
  858. if (file.name) {
  859. let suffixName = file.name.substring(file.name.lastIndexOf(".") + 1);
  860. if (suffixName && suffixName.length < 5) suffix = suffixName;
  861. }
  862. }
  863. return suffix;
  864. }
  865. getFileType(obj = {}) {
  866. let {
  867. file,
  868. filePath
  869. } = obj;
  870. let fileType = "other";
  871. let suffix = this.getFileSuffix(obj);
  872. if (["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"].indexOf(suffix) > -1) {
  873. fileType = "image";
  874. } else if (["avi", "mp3", "mp4", "3gp", "mov", "rmvb", "rm", "flv", "mkv"].indexOf(suffix) > -1) {
  875. fileType = "video";
  876. }
  877. return fileType;
  878. }
  879. // 系统异常重试机制(表单提交时慎用,建议只用在查询请求中,即无任何数据库修改的请求中)
  880. callFunctionRetry(obj = {}) {
  881. let { retryCount } = obj;
  882. delete obj.retryCount;
  883. return new Promise((resolve, reject) => {
  884. this.callRetryFn(obj, resolve, reject, retryCount);
  885. });
  886. }
  887. // 重试实现
  888. callRetryFn(obj, resolve, reject, retryCount) {
  889. let that = this;
  890. let debug = that.config.debug;
  891. that.callFunction({
  892. ...obj,
  893. needRetry: retryCount ? true : false, // 判断是否需要重试
  894. retry: function(err) {
  895. obj.runCount = obj.runCount ? obj.runCount + 1 : 1;
  896. obj.needRetry = retryCount > obj.runCount ? true : false; // 判断是否需要重试
  897. let errorMsg = err.message ? `异常信息:${err.message}` : "";
  898. if (debug) console.log(`【请求失败】正在第【${obj.runCount}】次重试:${obj.url}`);
  899. if (obj.retryInterval) {
  900. setTimeout(function() {
  901. that._callRetryFn(obj, resolve, reject, retryCount);
  902. }, obj.retryInterval);
  903. } else {
  904. // 如果无延迟,则不写setTimeout,因为setTimeout 即使time为0,也有一定延迟。
  905. that._callRetryFn(obj, resolve, reject, retryCount);
  906. }
  907. }
  908. });
  909. }
  910. _callRetryFn(obj, resolve, reject, retryCount) {
  911. if (obj.runCount < retryCount) {
  912. this.callRetryFn(obj, resolve, reject, retryCount);
  913. } else {
  914. this.callFunction(obj).catch((err) => {
  915. reject();
  916. });
  917. }
  918. }
  919. }
  920. export default new CallFunctionUtil