Files
2025-04-30 14:04:34 +08:00

641 lines
18 KiB
JavaScript
Raw Permalink 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.

import { LOGIN_PAGE_URL, needLoginPages } from '../config.js';
import { Router } from '@/common/utils/index.js';
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
let throttleTimer, throttleFlag;
export function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!throttleFlag) {
throttleFlag = true;
// 如果是立即执行则在wait毫秒内开始时执行
typeof func === 'function' && func();
throttleTimer = setTimeout(() => {
throttleFlag = false;
}, wait);
}
} else {
if (!throttleFlag) {
throttleFlag = true
// 如果是非立即执行则在wait毫秒内的结束处执行
throttleTimer = setTimeout(() => {
throttleFlag = false
typeof func === 'function' && func();
}, wait);
}
}
};
/**
* 时间戳转为多久之前
* @param String timestamp 时间戳
* @param String | Boolean format 如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
* 如果为布尔值false无论什么时间都返回多久以前的格式
*/
export function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
if (timestamp == null) timestamp = Number(new Date());
timestamp = parseInt(timestamp);
// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
if (timestamp.toString().length == 10) timestamp *= 1000;
var timer = (new Date()).getTime() - timestamp;
timer = parseInt(timer / 1000);
// 如果小于5分钟,则返回"刚刚",其他以此类推
let tips = '';
switch (true) {
case timer < 300:
tips = global.i18n.t('刚刚');
break;
case timer >= 300 && timer < 3600:
tips = parseInt(timer / 60) + global.i18n.t('分钟前');
break;
case timer >= 3600 && timer < 86400:
tips = parseInt(timer / 3600) + global.i18n.t('小时前');
break;
case timer >= 86400 && timer < 2592000:
tips = parseInt(timer / 86400) + global.i18n.t('天前');
break;
default:
// 如果format为false则无论什么时间戳都显示xx之前
if (format === false) {
if (timer >= 2592000 && timer < 365 * 86400) {
tips = parseInt(timer / (86400 * 30)) + global.i18n.t('个月前');
} else {
tips = parseInt(timer / (86400 * 365)) + global.i18n.t('年前');
}
} else {
tips = timeFormat(timestamp, format);
}
}
return tips;
}
// 判断arr是否为一个数组返回一个bool值
export function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
// 深度克隆
export function deepClone(obj) {
// 对常见的“非”值,直接返回原来值
if ([null, undefined, NaN, false].includes(obj)) return obj;
if (typeof obj !== "object" && typeof obj !== 'function') {
//原始类型直接返回
return obj;
}
var o = isArray(obj) ? [] : {};
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
}
}
return o;
}
export function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') {
// padStart 的 polyfill因为某些机型或情况还无法支持es7的padStart比如电脑版的微信小程序
// 所以这里做一个兼容polyfill的兼容处理
if (!String.prototype.padStart) {
// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
String.prototype.padStart = function (maxLength, fillString = ' ') {
if (Object.prototype.toString.call(fillString) !== "[object String]") throw new TypeError(
'fillString must be String')
let str = this
// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
if (str.length >= maxLength) return String(str)
let fillLength = maxLength - str.length,
times = Math.ceil(fillLength / fillString.length)
while (times >>= 1) {
fillString += fillString
if (times === 1) {
fillString += fillString
}
}
return fillString.slice(0, fillLength) + str;
}
}
// 其他更多是格式化有如下:
// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
timestamp = parseInt(timestamp);
// 如果为null,则格式化当前时间
if (!timestamp) timestamp = Number(new Date());
// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
if (timestamp.toString().length == 10) timestamp *= 1000;
console.log('timestamp', timestamp)
let date = new Date(timestamp);
console.log(date);
let ret;
let opt = {
"y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"h+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"s+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
/**
* 防抖原理一定时间内只有最后一次操作再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
let timeout = null;
export function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function () {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器当最后一次操作后timeout不会再被清除所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function () {
typeof func === 'function' && func();
}, wait);
}
}
//1都不支持 2安卓指纹 3 苹果指纹 4 苹果人脸 5 苹果人脸加指纹
export function biometrics() {
return new Promise((resolve) => {
//#ifdef APP-PLUS || MP-WEIXIN
uni.checkIsSupportSoterAuthentication({
success(res) {
// console.log('检测支持的认证方式', res);
if (res.errMsg === 'checkIsSupportSoterAuthentication:ok') {
let support = 1;
let supportMode = res.supportMode;
let platform = uni.getSystemInfoSync().platform;
// "facial" 人脸 "fingerPrint" 指纹识别
console.log('supportMode', supportMode);
// 如果都不支持 隐藏该选项
if (supportMode.length === 0) {
support = 1;
}
// 如果是安卓机 只让用指纹识别
if (platform === 'android' && supportMode.findIndex(item => item === 'fingerPrint') !== -1) {
support = 2;
}
// 如果是苹果机 看是否是支持人脸还是指纹
if (platform === 'ios') {
// 指纹
if (supportMode.findIndex(item => item === 'fingerPrint') !== -1) {
support = 3;
}
// 人脸
if (supportMode.findIndex(item => item === 'facial') !== -1) {
support = 4;
}
// 指纹人脸同时存在
if (supportMode.findIndex(item => item === 'facial') !== -1 && supportMode.findIndex(item => item === 'fingerPrint') !== -1) {
support = 5;
}
}
resolve(support);
}
},
fail(err) {
console.log(err);
resolve(1);
},
})
// #endif
//#ifndef APP-PLUS || MP-WEIXIN
return 1;
// #endif
})
}
const router = new Router({ needLoginPages });
/**
* @description showModal 弹窗封装
* @param {Object} options = 参数同 uni-app 官方用法
* */
export function showModal(options) {
// #ifndef APP-PLUS
uni.showModal(options);
// #endif
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform === 'android') {
global.$showModal(options)
.then(res => {
console.log('RES', res);
//确认
}).catch(err => {
//取消
console.log('ERR', err);
})
} else {
uni.showModal(options);
}
// #endif
}
/**
* @description 验证登录权限,接受一个回调函数,登录则执行回调函数,非登录状态则跳转登录页
* @param {Function} cb = 回调函数
* */
export function actionAuth(cb) {
if (global.token) {
cb && cb();
} else {
navigateToLogin();
}
}
/**
* @description 判断是app端还是小程序端登录
* */
let timer = null; // 登录页跳转防抖
export function navigateToLogin() {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
const pages = getCurrentPages();
if (pages.length != 0) {
const lastPage = '/' + pages.pop().route;
let url = LOGIN_PAGE_URL;
if (lastPage == url) return;
uni.navigateTo({
url
});
} else {
uni.switchTab({
url: '/pages/tab/home/shopindex'
})
}
}, 200)
}
/**
* @description 倒计时计算
* */
export function downTime(time) {
var days = parseInt(time / (1000 * 60 * 60 * 24));
var hours = parseInt(time / (1000 * 60 * 60) % 24);
var minutes = parseInt(time / (1000 * 60) % 60);
var seconds = parseInt(time / 1000 % 60);
return {
days,
hours: hours < 10 ? '0' + hours : hours,
minutes: minutes < 10 ? '0' + minutes : minutes,
seconds: seconds < 10 ? '0' + seconds : seconds,
}
}
/**
* @description 参数序列化
* */
export function serialize(data) {
let str = '';
Object.keys(data).forEach(key => {
str += key + '=' + data[key] + '&'
})
str = str.substr(0, str.length - 1);
return str;
}
/**
* @description 设置状态栏颜色
* @param {String} color dark or light
* @example this.$util.setNavigationBarColor('dark');
* */
export function setNavigationBarColor(color) {
if (color == 'dark') {
// #ifdef APP-PLUS
plus.navigator.setStatusBarStyle('dark');
// #endif
// #ifdef MP-WEIXIN
wx.setNavigationBarColor({
frontColor: '#000000',
backgroundColor: '#FFFFFF'
})
// #endif
} else if (color == 'light') {
// #ifdef APP-PLUS
plus.navigator.setStatusBarStyle('light');
// #endif
// #ifdef MP-WEIXIN
wx.setNavigationBarColor({
frontColor: '#FFFFFF',
backgroundColor: '#000000'
})
// #endif
}
}
/**
* base64图片缓存到本地,返回本地路径
* */
export function base64ToPath(base64) {
return new Promise(function (resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
base64 = base64.split(',')
var type = base64[0].match(/:(.*?);/)[1]
var str = atob(base64[1])
var n = str.length
var array = new Uint8Array(n)
while (n--) {
array[n] = str.charCodeAt(n)
}
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], {
type: type
})))
}
var extName = base64.match(/data\:\S+\/(\S+);/)
if (extName) {
extName = extName[1]
} else {
reject(new Error('base64 error'))
}
var fileName = Date.now() + '.' + extName
if (typeof plus === 'object') {
var bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
bitmap.loadBase64Data(base64, function () {
var filePath = '_doc/uniapp_temp/' + fileName
bitmap.save(filePath, {}, function () {
bitmap.clear()
resolve(filePath)
}, function (error) {
bitmap.clear()
reject(error)
})
}, function (error) {
bitmap.clear()
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
var filePath = wx.env.USER_DATA_PATH + '/' + fileName
wx.getFileSystemManager().writeFile({
filePath: filePath,
data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
encoding: 'base64',
success: function () {
resolve(filePath)
},
fail: function (error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
export function postMsgToParent(message) {
console.log('postMsgToParent', message);
window.parent.postMessage(message, '*');
}
/**
*
* @param {*} type 点击类型 navigateTo
* @param {*} data
*/
export function handleAllFn(type, data) {
// 无点击事件
if (type == 'niente') {
return false
}
/**
* 转页面类型
* navigateTo
* data结构
* {
* url: String 路径,
* auth: Boolean (选填)是否验证登录状态true 验证
* params: Object (选填) 携带的参数
* }
*/
if (type == 'navigate') {
router[data.type]('/' + data.url)
return false
}
/**
*
* type: back
* 返回
* data(选填) 不填返回一页
*/
if (type == 'back') {
uni.navigateBack({
delta: data.delta || 1
});
}
/**
*
* type: backReference
* 返回页面携带参数
* data{
* name:String 目标页面接受参数名
* params: 参数
* }
*/
if (type == "backReference") {
if (!data.name) {
return false
}
let pages = getCurrentPages(); //获取当前页面js里面的pages里的所有信息。
let prevPage = pages[pages.length - 2];
//prevPage 是获取上一个页面的js里面的pages的所有信息。 -2 是上一个页面,-3是上上个页面以此类推。
prevPage.backWithParams({
[data.name]: data.params
})
uni.navigateBack({
delta: 1 // 返回上一级页面。
})
return false
}
/**
* type showModal 弹窗封装
* data 参数同 uni-app 官方用法
* */
if (type == 'showModal') {
// #ifndef APP-PLUS
uni.showModal(data);
// #endif
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform === 'android') {
global.$showModal(options)
.then(res => {
console.log('RES', res);
//确认
}).catch(err => {
//取消
console.log('ERR', err);
})
} else {
uni.showModal(data);
}
// #endif
return false
}
// 打开指定弹窗
if (type == 'showModalDiy') {
let pages = getCurrentPages(); //获取当前页面js里面的pages里的所有信息。
let prevPage = pages[pages.length - 1];
prevPage['popupShow' + data.showCancel] = true
return false
}
/**
*
* type: downloadFile
* 下载文件
* data 下载路径
* .then(res=>{}) 接收下载成功回调
* .catch(res=>{}) 接收下载失败回调
*/
if (type == 'downloadFile') {
return new Promise((resolve, reject) => {
const downloadTask = uni.downloadFile({
url: data.url,
success: (res) => {
uni.showToast({
title: '下载成功',
icon: 'success',
mask: true
})
// resolve(res)
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function () {
console.log('save success');
}
});
},
fail: (err) => {
uni.showToast({
title: '下载失败',
icon: 'fail',
mask: true
})
reject(err)
},
complete: () => { }
})
// 中断下载
// downloadTask.abort();
// 监听下载进度
// downloadTask.onProgressUpdate(res => {
// console.log('下载进度' + res.progress);
// console.log('已经下载的数据长度' + res.totalBytesWritten);
// console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
// })
})
}
/**
*
* type: uploadFile
* 上传文件
* data{
* url:String 上传路径
* files: 仅app与h5支持该选项
* ffileType: 仅支付宝小程序支持且必填 images/video/audio
* filePath: 文件路径
* name: 后台接收key
* header: 选填
* formData: 选填 携带参数
* progressCallback: 选填 监听上传载进度
* }
*/
if (type == 'uploadFile') {
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: config.baseUrl + data.url,
// #ifdef APP-PLUS || H5
files: data.files || [],
// #endif
// #ifdef MP-ALIPAY
fileType: data.fileType,
// #endif
// #ifdef H5
file: data.file || null,
// #endif
filePath: data.filePath,
name: data.name,
header: data.header ? data.header : {},
formData: data.formData ? data.formData : {},
complete: (response) => {
if (response.statusCode == 200) {
resolve(response)
} else {
reject(response)
}
}
})
if (data.progressCallback && typeof (data.progressCallback) == 'function') {
uploadTask.onProgressUpdate(res => {
data.progressCallback(res.progress + '%');
})
}
})
}
/**
*
* type: getLoaction
* 获取定位
*
**/
if (type == 'getLoaction') {
console.log('我要获取定位');
return new Promise((resolve, reject) => {
uni.getLocation({
type: 'wgs84',
success: function (res) {
console.log('当前位置的经度:' + res.longitude);
console.log('当前位置的纬度:' + res.latitude);
uni.showToast({
title: JSON.stringify(res),
icon: "none"
})
resolve(res)
},
fail: function (err) {
reject(err)
}
});
})
}
/**
*
* type: richiesta
* 点赞 收藏
* data{
* url:String 上传路径
* files: 仅app与h5支持该选项
* ffileType: 仅支付宝小程序支持且必填 images/video/audio
* filePath: 文件路径
* name: 后台接收key
* header: 选填
* formData: 选填 携带参数
* progressCallback: 选填 监听上传载进度
* }
*/
if (type == 'richiesta') {
}
}