//import i18n from '@/locales' import base from '@/common/config'; import store from "@/store"; import IMSDK from "openim-uniapp-polyfill"; import CryptoJS from 'crypto-js'; import md5 from "md5"; // #ifdef APP import {downloadFile} from "@/uni_modules/network-manage"; // #endif const isString = (v)=> { return typeof v === 'string' || v instanceof String; }, isNumber=(v) =>{ return typeof v === 'number' && !isNaN(v); }, isInteger=(v) =>{ return typeof v === 'number' && isFinite(v) && Math.floor(v) === v; }, isBoolean=(v) =>{ return typeof v === 'boolean'; }, isArray=(v) =>{ return Array.isArray(v); }, isObject=(v) =>{ return v !== null && typeof v === 'object' && !Array.isArray(v); }, isFunction=(v) =>{ return typeof v === 'function'; }, isNull=(v) =>{ return v === null; }, isUndefined=(v) =>{ return typeof v === 'undefined'; }, isSymbol=(v) =>{ return typeof v === 'symbol'; }, isDate=(v) =>{ return Object.prototype.toString.call(v) === '[object Date]'; }, isRegExp=(v) =>{ return Object.prototype.toString.call(v) === '[object RegExp]'; }, isError=(v) =>{ return v instanceof Error; }, isMap=(v) =>{ return v instanceof Map; }, isSet=(v) =>{ return v instanceof Set; }, isWeakMap=(v) =>{ return v instanceof WeakMap; }, isWeakSet=(v) => { return v instanceof WeakSet; }, _goto = (url,type) => { //console.log(url); type = type || '0'; //0 navigateTo 1 redirectTo if(url){ if(isInteger(url)){ uni.navigateBack({ delta:url, }) }else{ url+=""; if(url.substr(0,6) != '/pages'){ url='/pages'+url } if(type == '1'){ return uni.redirectTo({ url:url }); } if(type == '2'){ return uni.switchTab({ url:url }); } uni.navigateTo({ url:url }) } } }; const showToast = (msg,url,icon) => { //msg = i18n.t(msg); // #ifdef APP plus.nativeUI.closeToast(); plus.nativeUI.toast(msg,{ align:'center', verticalAlign:"center", style:"inline", icon:icon=='error' ? '/static/img/common/error.png' : '/static/img/common/success.png', iconWidth:24, iconHeight:24 }); if(url){ setTimeout(()=>{ _goto(url); },3000) } // #endif // #ifndef APP uni.showToast({ //image:icon=='error' ? '/static/img/common/error.png' : '/static/img/common/success.png', icon:icon=='error' ? icon : 'success', title:msg, showToast:3000, complete:()=>{ if(url){ setTimeout(()=>{ _goto(url); },3000) } } }); // #endif } const error = (msg,url) => { showToast(msg,url,'error'); } const success = (msg,url) => { showToast(msg,url,'success'); } const scan = ()=>{ uni.scanCode({ success(res){ /** * result 所扫码的内容 scanType 所扫码的类型 App、微信小程序、百度小程序、QQ小程序、京东小程序、支付宝小程序 charSet 所扫码的字符集 App、微信小程序、百度小程序(所扫码的字符集,仅支持 Android 系统)、QQ小程序、京东小程序 path 当所扫的码为当前应用的合法二维码时,会返回此字段,内容为二维码携带的 path。 微信小程序、QQ小程序、京东小程序 rawData 原始数据,base64 编码 微信小程序、QQ小程序、京东小程序、支付宝小程序 code 扫码所得数据 支付宝小程序 qrCode 扫描二维码时返回二维码数据 支付宝小程序 barCode 扫描条形码时返回条形码数据 支付宝小程序 imageChannel 来源 支付宝小程序 */ if(res.scanType == "QR_CODE"){ const user_prefix = `${store.getters.config.website}/u/`; console.log(res.result,user_prefix) if(res.result.startsWith(user_prefix)){ return uni.navigateTo({ url:"/pages/common/userCard/index?sourceID="+res.result.replace(user_prefix,'') }); } const group_prefix = `${store.getters.config.website}/g/`; console.log(res.result,group_prefix) if(res.result.startsWith(group_prefix)){ return uni.navigateTo({ url:"/pages/common/groupCard/index?sourceID="+res.result.replace(group_prefix,'') }); } if(res.result.startsWith("http")){ uni.navigateTo({ url:"/pages/common/webview?url="+encodeURIComponent(res.result) }); //res.result; return ; } } }, fail(res){ console.log(res) } }); } const fileExsit = async(fn)=>{ return await new Promise((resolve) => { plus.io.resolveLocalFileSystemURL(fn, function(entry) { resolve(true); }, function() { resolve(false); }); }) } const downloadFile1 = (url, savepath, successCb, errorCb, progressCb) => { const root_dir = "_doc/"; if (!url) { errorCb && errorCb.call(this,new Error('empty url')); return; } const startDownload = () => { console.log(33333333333333,root_dir+savepath); const task = plus.downloader.createDownload(url, { filename: root_dir+savepath, timeout: 2 }, function(d, status) { console.log('completedCB'); console.log(d); console.log(status); if (status === 200) { const local = d && d.filename ? d.filename : root_dir+savepath; successCb && successCb.call(this,local); } else { errorCb && errorCb.call(this,new Error('download status ' + status)); } }); task.addEventListener('statechanged', function(t, status) { console.log('statechanged',d,status); if (t.state === 3) { var downloaded = t.downloadedSize || t.downloaded || 0; var total = t.totalSize || t.total || 0; var prog = 0; if (total > 0) prog = Math.min(100, Math.floor(downloaded / total * 100)); progressCb && progressCb.call(this,prog); } }); try{ task.start(); plus.downloader.startAll(); }catch(e){ console.log('e',e); } plus.downloader.enumerate((downloads )=>{ for(var i =0;i 结构) const fns = savepath.split('/'); plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function(fs) { fs.root.getDirectory(fns[0], { create: true }, function(entry) { startDownload(); }, function(e) { // 创建失败也尝试下载,可能运行时会自动创建 startDownload(); }); }, function(e) { startDownload(); }); } const get_absolute_path = (fn)=>{ return plus.io.convertLocalFileSystemURL(fn); } const pendingDownloads = new Map(); const cacheFile = (url, saveDir,progressCallback) => { //console.log(url); // #ifndef APP return new Promise(async (resolve, reject) => { resolve(url); }); // #endif return new Promise(async (resolve, reject) => { try { if(!url || !url.startsWith('http')){ resolve(url); return; } const key = md5(url); var ext = "png" if(url.toLowerCase().indexOf('.mp4')!==-1){ ext = "mp4"; } let cacheDir = plus.io.convertLocalFileSystemURL(`_doc/{{dir}}/{{key}}.{{ext}}`); if(uni.getSystemInfoSync().osName == 'android'){ cacheDir = cacheDir.replace('apps/'+plus.runtime.appid+'/doc','cache'); } const cacheFilePath = cacheDir.replace('{{dir}}',saveDir) .replace('{{key}}',key) .replace('{{ext}}',ext); //console.error('cacheDir:',cacheDir); // 如果缓存存在且文件存在,直接返回缓存路径 if (cacheFilePath) { //console.error('cacheFilePath:', cacheFilePath); const coverExists = await fileExsit(cacheFilePath); //console.log("coverExists:" ,coverExists); if (coverExists) { //console.log("已缓存为:" , cacheFilePath,url); resolve(cacheFilePath); return; } } // 2. 检查是否已经有相同的 URL 正在下载 if (pendingDownloads.has(url)) { // 如果已经有相同的下载在进行,则添加到等待列表 pendingDownloads.get(url).promises.push({ resolve, reject }); return; } // 3. 如果没有正在下载,则创建新的下载任务 pendingDownloads.set(url, { promises: [{ resolve, reject }], completed: false, savedPath: saveDir }); // 4. 开始下载文件 const task = downloadFile({ url:url, timeout: 30000, filePath:cacheFilePath, success(res) { // 下载成功,解决所有等待的 Promise const info = pendingDownloads.get(url); if (info) { info.completed = true; info.promises.forEach(p => p.resolve(res.tempFilePath)); pendingDownloads.delete(url); } }, fail(e){ // 下载失败,拒绝所有等待的 Promise const info = pendingDownloads.get(url); if (info) { info.promises.forEach(p => p.reject(error)); pendingDownloads.delete(url); } }, complate(){ task = null; } }); //console.error('task:', task); task.onProgressUpdate(({progress,totalBytesWritten,totalBytesExpectedToWrite})=>{ //console.error('pres:', progress,totalBytesWritten,totalBytesExpectedToWrite); progressCallback && progressCallback.call(this,progress,totalBytesWritten,totalBytesExpectedToWrite) }); } catch (error) { console.error('cacheFile 发生错误:', error); resolve(url); // 返回原始URL作为fallback } }); }; const toMapAPP = (latitude,longitude,name) =>{ let url = ""; if (plus.os.name == "Android") {//判断是安卓端 plus.nativeUI.actionSheet({//选择菜单 title: "选择地图应用", cancel: "取消", buttons: [{title: "腾讯地图"},{title: "百度地图"}, {title: "高德地图"}] }, function(e) { switch (e.index) { //下面是拼接url,不同系统以及不同地图都有不同的拼接字段 case 1: //注意referer=xxx的xxx替换成你在腾讯地图开发平台申请的key url = `qqmap://map/geocoder?coord=${latitude},${longitude}&referer=xxx`; break; case 2: url = `baidumap://map/marker?location=${latitude},${longitude}&title=${name}&coord_type=gcj02&src=andr.baidu.openAPIdemo`; break; case 3: url = `androidamap://viewMap?sourceApplication=appname&poiname=${name}&lat=${latitude}&lon=${longitude}&dev=0`; break; default: break; } if (url != "") { url = encodeURI(url); //plus.runtime.openURL(url,function(e){})调起手机APP应用 plus.runtime.openURL(url, function(e) { plus.nativeUI.alert("本机未安装指定的地图应用"); }); } }) } else { // iOS上获取本机是否安装了百度高德地图,需要在manifest里配置 // 在manifest.json文件app-plus->distribute->apple->urlschemewhitelist节点下添加 //(如urlschemewhitelist:["iosamap","baidumap"]) plus.nativeUI.actionSheet({ title: "选择地图应用", cancel: "取消", buttons: [{title: "腾讯地图"},{title: "百度地图"}, {title: "高德地图"}] }, function(e) { switch (e.index) { case 1: url = `qqmap://map/geocoder?coord=${latitude},${longitude}&referer=xxx`; break; case 2: url = `baidumap://map/marker?location=${latitude},${longitude}&title=${name}&content=${name}&src=ios.baidu.openAPIdemo&coord_type=gcj02`; break; case 3: url = `iosamap://viewMap?sourceApplication=applicationName&poiname=${name}&lat=${latitude}&lon=${longitude}&dev=0`; break; default: break; } if (url != "") { url = encodeURI(url); plus.runtime.openURL(url, function(e) { plus.nativeUI.alert("本机未安装指定的地图应用"); }); } }) } } /** * AES 加密函数 * @param {String|Object|Array} str 要加密的内容 * @param {String} key 加密密钥 * @returns {String} 加密后的Base64字符串 */ const aesencode = (str, key = 'muNcJyt0XXV6faCGe41VSIaf0ecZeW2jXmgpL0Ak93Kbwjyr')=> { // 如果是对象或数组,转为JSON字符串 if (typeof str === 'object') { str = JSON.stringify(str); } // 使用SHA-256哈希处理密钥 const hashedKey = CryptoJS.SHA256(key); // 生成IV(前16字节) const iv = CryptoJS.lib.WordArray.create(hashedKey.words.slice(0, 4)); // 加密 const encrypted = CryptoJS.AES.encrypt(str,hashedKey,{ iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 返回Base64编码结果 const _str = encrypted.toString(); return _str.replace(/\+/ig,'%2b'); } /** * AES 解密函数 * @param {String} str 要解密的Base64字符串 * @param {String} key 解密密钥 * @returns {String} 解密后的原始字符串 */ const aesdecode = (str, key = 'muNcJyt0XXV6faCGe41VSIaf0ecZeW2jXmgpL0Ak93Kbwjyr') => { // 使用SHA-256哈希处理密钥 const hashedKey = CryptoJS.SHA256(key); // 生成IV(前16字节) const iv = CryptoJS.lib.WordArray.create(hashedKey.words.slice(0, 4)); str = str.replace(/\%2b/ig,'+'); // 解密 const decrypted = CryptoJS.AES.decrypt(str,hashedKey,{ iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 转为UTF-8字符串 let _str = decrypted.toString(CryptoJS.enc.Utf8); console.log(_str); const obj = _str.startsWith('{') || _str.startsWith('[') ? JSON.parse(_str) : _str; return obj; } export default{ aesdecode, aesencode, toMapAPP, cacheFile, fileExsit, get_absolute_path, // #ifdef APP downloadFile, // #endif isString :isString, isNumber :isNumber, isInteger :isInteger, isBoolean :isBoolean, isArray :isArray, isObject :isObject, isFunction :isFunction, isNull :isNull, isUndefined :isUndefined, isSymbol :isSymbol, isDate :isDate, isRegExp :isRegExp, isError :isError, isMap :isMap, isSet :isSet, isWeakMap :isWeakMap, isWeakSet :isWeakSet, cdn(v){ v= v || ""; v = v.replace(/\\/ig,"/").replace('/\/\/ig',"/"); //console.log(v); if(v && isString(v)){ if(v.startsWith('//')){ return 'http:'+v; } if(v.startsWith('blob:') || v.startsWith('file://') || v.startsWith('http')){ return v; } v= v.startsWith('/') ? v : '/'+v; return base.cdnUrl+''+v; } return ""; }, "goto":_goto, showToast, error, success, scan, copy(v){ let that = this; uni.setClipboardData({ data:v+'', success() { that.success('复制成功'); } }) }, toDate(time) { var date = new Date(time * 1000); var fmt = 'yyyy-MM-dd hh:mm:ss'; var o = { 'M+': date.getMonth() + 1, //月份 'd+': date.getDate(), //日 'h+': date.getHours(), //小时 'm+': date.getMinutes(), //分 's+': date.getSeconds(), //秒 'q+': Math.floor((date.getMonth() + 3) / 3), //季度 S: date.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)); return fmt; }, formatAmount(v,wei){ if(!v){return 0.00;} v=v+""; v = parseFloat(v).toFixed(wei || 2); return parseFloat(v); }, imapi(method,data){ return IMSDK.asyncApi(method,IMSDK.uuid(),data); } }