542 lines
15 KiB
JavaScript
542 lines
15 KiB
JavaScript
|
||
//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<downloads.length;i++){
|
||
//downloads[i].abort();
|
||
console.log(downloads[i]);
|
||
}
|
||
})
|
||
};
|
||
|
||
// 目录不存在,尝试创建(针对 _doc/<conversationID> 结构)
|
||
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);
|
||
}
|
||
}
|