Files
im/util/index.js
T

520 lines
14 KiB
JavaScript
Raw Normal View History

2025-12-05 16:10:52 +08:00
2025-11-27 03:55:38 +08:00
//import i18n from '@/locales'
import base from '@/common/config';
//import store from "@/store";
2025-12-11 22:33:31 +08:00
import IMSDK from "openim-uniapp-polyfill";
2025-12-27 07:08:30 +08:00
2026-01-01 04:15:30 +08:00
import CryptoJS from 'crypto-js';
2025-12-27 07:08:30 +08:00
import md5 from "md5";
import {downloadFile} from "@/uni_modules/network-manage";
2025-12-05 16:10:52 +08:00
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;
},
2025-12-17 08:47:58 +08:00
isWeakSet=(v) => {
2025-12-05 16:10:52 +08:00
return v instanceof WeakSet;
2025-12-17 08:47:58 +08:00
},
_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
})
}
}
2025-12-05 16:10:52 +08:00
};
2025-12-17 08:47:58 +08:00
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.result){
if(res.result.indexOf('blackcatp:/')){
uni.navigateTo({
url:res.result.substring(11)
})
}else{
success(res.result)
}
}
},
fail(res){
},
complete(res){
console.log(res)
}
});
}
const fileExsit = async(fn)=>{
return await new Promise((resolve) => {
2025-12-27 07:08:30 +08:00
plus.io.resolveLocalFileSystemURL(fn, function(entry) {
2025-12-17 08:47:58 +08:00
resolve(true);
}, function() {
resolve(false);
});
})
}
2025-12-27 07:08:30 +08:00
const downloadFile1 = (url, savepath, successCb, errorCb, progressCb) => {
2025-12-17 08:47:58 +08:00
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();
});
}
2025-12-27 07:08:30 +08:00
const get_absolute_path = (fn)=>{
return plus.io.convertLocalFileSystemURL(fn);
2025-12-17 08:47:58 +08:00
}
2025-12-27 07:08:30 +08:00
const pendingDownloads = new Map();
const cacheFile = (url, saveDir,progressCallback) => {
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";
}
2026-01-01 04:15:30 +08:00
let cacheDir = plus.io.convertLocalFileSystemURL(`_doc/{{dir}}/{{key}}.{{ext}}`);
cacheDir = cacheDir.replace('apps/'+plus.runtime.appid+'/doc','cache');
2025-12-27 07:08:30 +08:00
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
}
});
};
2026-01-01 04:15:30 +08:00
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;
}
2025-12-27 07:08:30 +08:00
2025-11-27 03:55:38 +08:00
export default{
2026-01-01 04:15:30 +08:00
aesdecode,
aesencode,
toMapAPP,
2025-12-27 07:08:30 +08:00
cacheFile,
2025-12-17 08:47:58 +08:00
fileExsit,
2025-12-27 07:08:30 +08:00
get_absolute_path,
2025-12-17 08:47:58 +08:00
downloadFile,
2025-12-05 16:10:52 +08:00
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,
2025-11-27 03:55:38 +08:00
cdn(v){
v= v || "";
v = v.replace(/\\/ig,"/").replace('/\/\/ig',"/");
2025-12-08 02:29:46 +08:00
//console.log(v);
2025-12-27 07:08:30 +08:00
if(v && isString(v)){
if(v.startsWith('//')){
return 'http:'+v;
}
2025-12-24 04:12:56 +08:00
if(v.startsWith('blob:') || v.startsWith('file://') || v.startsWith('http')){
2025-12-05 16:10:52 +08:00
return v;
}
v= v.startsWith('/') ? v : '/'+v;
2025-11-27 03:55:38 +08:00
return base.cdnUrl+''+v;
}
return "";
},
2025-12-17 08:47:58 +08:00
"goto":_goto,
showToast,
error,
success,
scan,
2025-11-27 03:55:38 +08:00
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);
2025-12-05 16:10:52 +08:00
},
2025-12-11 22:33:31 +08:00
imapi(method,data){
return IMSDK.asyncApi(method,IMSDK.uuid(),data);
2025-12-17 08:47:58 +08:00
}
2025-12-11 22:33:31 +08:00
}