480 lines
11 KiB
JavaScript
Executable File
480 lines
11 KiB
JavaScript
Executable File
import md5 from 'js-md5';
|
||
import {
|
||
fileUrl
|
||
} from '@/config.js';
|
||
/**
|
||
* 格式化日期格式 (用于兼容ios Date对象)
|
||
*/
|
||
export const formatDate = (time) => {
|
||
// 将xxxx-xx-xx的时间格式,转换为 xxxx/xx/xx的格式
|
||
return time.replace(/\-/g, "/");
|
||
}
|
||
|
||
/**
|
||
* 对象转URL参数
|
||
* @param {object} obj
|
||
* @return {string}
|
||
*/
|
||
export const urlEncode = (obj = {}) => {
|
||
const result = []
|
||
for (const key in obj) {
|
||
const item = obj[key]
|
||
if (!item) {
|
||
continue
|
||
}
|
||
if (isArray(item)) {
|
||
item.forEach(val => {
|
||
result.push(key + '=' + val)
|
||
})
|
||
} else {
|
||
result.push(key + '=' + item)
|
||
}
|
||
}
|
||
return result.join('&')
|
||
}
|
||
|
||
/**
|
||
* URL参数转对象
|
||
* @param {string} queryStr
|
||
* @return {object}
|
||
*/
|
||
export const urlDecode = (queryStr = '') => {
|
||
var newObj = new Object()
|
||
if (queryStr) {
|
||
var strs = queryStr.split("&")
|
||
for (var i = 0; i < strs.length; i++) {
|
||
newObj[strs[i].split("=")[0]] = (strs[i].split("=")[1]) || ''
|
||
}
|
||
}
|
||
return newObj
|
||
}
|
||
|
||
/**
|
||
* 遍历对象
|
||
*/
|
||
export const objForEach = (obj, callback) => {
|
||
Object.keys(obj).forEach((key) => {
|
||
callback(obj[key], key)
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 是否在数组内
|
||
*/
|
||
export const inArray = (search, array) => {
|
||
for (var i in array) {
|
||
if (array[i] == search) return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 对Date的扩展,将 Date 转化为指定格式的String
|
||
* 月(Y)、月(m)、日(d)、小时(H)、分(M)、秒(S) 可以用 1-2 个占位符,
|
||
* 例子:
|
||
* dateFormat('YYYY-mm-dd HH:MM:SS', new Date()) ==> 2020-01-01 08:00:00
|
||
*/
|
||
export const dateFormat = (fmt, date) => {
|
||
const 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() // 秒
|
||
// 有其他格式化字符需求可以继续添加,必须转化成字符串
|
||
};
|
||
let ret
|
||
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
|
||
}
|
||
|
||
/**
|
||
* 判断是否为空对象
|
||
* @param {*} object 源对象
|
||
*/
|
||
export const isEmptyObject = (object) => {
|
||
return Object.keys(object).length === 0
|
||
}
|
||
|
||
/**
|
||
* 判断是否为对象
|
||
* @param {*} object
|
||
*/
|
||
export const isObject = (object) => {
|
||
return Object.prototype.toString.call(object) === '[object Object]'
|
||
}
|
||
|
||
/**
|
||
* 判断是否为数组
|
||
* @param {*} array
|
||
*/
|
||
export const isArray = (array) => {
|
||
return Object.prototype.toString.call(array) === '[object Array]'
|
||
}
|
||
|
||
/**
|
||
* 判断是否为空
|
||
* @param {*} object 源对象
|
||
*/
|
||
export const isEmpty = (value) => {
|
||
if (isArray(value)) {
|
||
return value.length === 0
|
||
}
|
||
if (isObject(value)) {
|
||
return isEmptyObject(value)
|
||
}
|
||
return !value
|
||
}
|
||
|
||
/**
|
||
* 对象深拷贝
|
||
* @param {*} obj 源对象
|
||
*/
|
||
export const cloneObj = (obj) => {
|
||
let newObj = isArray(obj) ? [] : {};
|
||
if (typeof obj !== 'object') {
|
||
return;
|
||
}
|
||
for (let i in obj) {
|
||
newObj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
|
||
}
|
||
return newObj
|
||
}
|
||
|
||
// 节流函数
|
||
// 思路: 第一次先设定一个变量true,
|
||
// 第二次执行这个函数时,会判断变量是否true,
|
||
// 是则返回。当第一次的定时器执行完函数最后会设定变量为flase。
|
||
// 那么下次判断变量时则为flase,函数会依次运行。
|
||
export function throttle(fn, delay = 100) {
|
||
// 首先设定一个变量,在没有执行我们的定时器时为null
|
||
var timer = null
|
||
return function() {
|
||
// 当我们发现这个定时器存在时,则表示定时器已经在运行中,需要返回
|
||
if (timer) return
|
||
timer = setTimeout(() => {
|
||
fn.apply(this, arguments)
|
||
timer = null
|
||
}, delay)
|
||
}
|
||
}
|
||
|
||
// 防抖函数
|
||
// 首次运行时把定时器赋值给一个变量, 第二次执行时,
|
||
// 如果间隔没超过定时器设定的时间则会清除掉定时器,
|
||
// 重新设定定时器, 依次反复, 当我们停止下来时,
|
||
// 没有执行清除定时器, 超过一定时间后触发回调函数。
|
||
// 参考文档:https://segmentfault.com/q/1010000021145192
|
||
export function debounce(fn, delay = 100) {
|
||
let timer
|
||
return function() {
|
||
const that = this
|
||
const _args = arguments // 存一下传入的参数
|
||
if (timer) {
|
||
clearTimeout(timer)
|
||
}
|
||
timer = setTimeout(function() {
|
||
fn.apply(that, _args)
|
||
}, delay)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 数组交集
|
||
* @param {Array} 数组1
|
||
* @param {Array} 数组2
|
||
* @return {Array}
|
||
*/
|
||
export const arrayIntersect = (array1, array2) => {
|
||
return array1.filter(val => array2.indexOf(val) > -1)
|
||
}
|
||
|
||
/**
|
||
* 获取当前客户端的rpx比值
|
||
* @return {Number}
|
||
*/
|
||
export const rpx = () => {
|
||
const {
|
||
windowWidth
|
||
} = uni.getSystemInfoSync()
|
||
// #ifdef H5
|
||
// 与pages.json文件中的 rpxCalcMaxDeviceWidth参数对应, 请勿修改
|
||
const rpxCalcMaxDeviceWidth = 750
|
||
// 与pages.json文件中的 rpxCalcBaseDeviceWidth参数对应, 请勿修改
|
||
const rpxCalcBaseDeviceWidth = 560
|
||
const calcWindowWidth = windowWidth > rpxCalcMaxDeviceWidth ? rpxCalcBaseDeviceWidth : windowWidth
|
||
return calcWindowWidth / 750
|
||
// #endif
|
||
// #ifndef H5
|
||
return windowWidth / 750
|
||
// #endif
|
||
}
|
||
|
||
/**
|
||
* 获取当前客户端的rpx比值
|
||
* @return {Number}
|
||
*/
|
||
export const rpx2px = (num) => {
|
||
return num * rpx()
|
||
}
|
||
|
||
// 生成订单编号
|
||
export function createOrderNo() {
|
||
const data = new Date();
|
||
return `${data.getFullYear()}${data.getMonth()}${data.getDate()}${data.getHours()}${data.getMilliseconds()}${uni.$u.random(800, 12000)}`;
|
||
}
|
||
|
||
|
||
// 封装签名
|
||
export function getSign(form, appSecret) {
|
||
if (form == null) {
|
||
return false;
|
||
}
|
||
let sign = '';
|
||
form.timestamp = new Date().getTime();
|
||
// form.version = 'v3';
|
||
const arr = objKeySort(form);
|
||
Object.keys(arr).forEach((k) => {
|
||
if (form[k] != null && form[k] != '') {
|
||
sign = sign.concat(form[k]).concat('-');
|
||
}
|
||
});
|
||
sign = sign.concat(appSecret);
|
||
console.log("md5加密前的字符串: ", sign);
|
||
return md5(sign);
|
||
}
|
||
|
||
// 参数按照字母顺序排序
|
||
export const objKeySort = (obj) => {
|
||
//排序的函数
|
||
const newkey = Object.keys(obj).sort();
|
||
//先用Object内置类的keys方法获取要排序对象的属性名,再利用Array原型上的sort方法对获取的属性名进行排序,newkey是一个数组
|
||
const newObj = {}; //创建一个新的对象,用于存放排好序的键值对
|
||
for (let i = 0; i < newkey.length; i++) {
|
||
//遍历newkey数组
|
||
newObj[newkey[i]] = obj[newkey[i]]; //向新创建的对象中按照排好的顺序依次增加键值对
|
||
}
|
||
return newObj; //返回排好序的新对象
|
||
};
|
||
|
||
export const getWeek = (text) => {
|
||
const week = [
|
||
'星期日',
|
||
'星期一',
|
||
'星期二',
|
||
'星期三',
|
||
'星期四',
|
||
'星期五',
|
||
'星期六'
|
||
];
|
||
return week[text];
|
||
};
|
||
|
||
/**
|
||
* 获取输入内容的长度
|
||
* @param value
|
||
* @return 内容的长度
|
||
*/
|
||
export const getInputSize = (value) => {
|
||
if (!value) {
|
||
return 0
|
||
}
|
||
const charCount = value.split('').reduce((prev, curr) => {
|
||
// 英文字母和数字等算一个字符;这个暂时还不完善;
|
||
if (/[a-z]|[0-9]|[,;.!@#-+/\\$%^*()<>?:"'{}~]/i.test(curr)) {
|
||
return prev + 1
|
||
}
|
||
// 其他的算是2个字符
|
||
return prev + 2
|
||
}, 0)
|
||
|
||
// 向上取整,防止出现半个字的情况
|
||
const count = Math.ceil(charCount / 2)
|
||
// 省略超出部分,显示’… 详情>>’
|
||
if (count < 25) {
|
||
return value
|
||
}
|
||
return value
|
||
|
||
// return Math.ceil(charCount / 2)
|
||
}
|
||
|
||
/* 获取缩列图地址 */
|
||
export const thumbnail = (url) => {
|
||
if (url.indexOf('/thumbnail/') < 0) {
|
||
return url.replace(fileUrl, fileUrl + '/thumbnail');
|
||
}
|
||
return url;
|
||
}
|
||
|
||
/* 获取预览图地址 */
|
||
export const thumb = (url) => {
|
||
if (url.indexOf('/thumb/') < 0) {
|
||
return url.replace(fileUrl, fileUrl + '/thumb');
|
||
}
|
||
return url;
|
||
}
|
||
|
||
/* 获取原图地址 */
|
||
export const original = (url) => {
|
||
if (url.indexOf('/thumbnail/') > -1) {
|
||
return url.replace('/thumbnail/', '/');
|
||
}
|
||
return url;
|
||
};
|
||
|
||
/**
|
||
* 下载图片到相册
|
||
* @param {string} imageUrl 图片地址
|
||
* @param {function} successCallback 成功回调
|
||
* @param {function} failCallback 失败回调
|
||
*/
|
||
export const downloadImage = (imageUrl, successCallback, failCallback) => {
|
||
if (!imageUrl) {
|
||
uni.showToast({
|
||
title: '图片地址无效',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '下载中...',
|
||
mask: true
|
||
});
|
||
|
||
// 下载图片
|
||
uni.downloadFile({
|
||
url: imageUrl,
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
// 保存到相册
|
||
uni.saveImageToPhotosAlbum({
|
||
filePath: res.tempFilePath,
|
||
success: () => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '保存成功',
|
||
icon: 'success'
|
||
});
|
||
successCallback && successCallback();
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.log('保存图片失败:', err);
|
||
if (err.errMsg.includes('auth deny')) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '请允许访问相册后重试\n(右上角菜单 - 设置 - 相册)',
|
||
showCancel: false
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '保存失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
failCallback && failCallback(err);
|
||
}
|
||
});
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
});
|
||
failCallback && failCallback();
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.log('下载图片失败:', err);
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
});
|
||
failCallback && failCallback(err);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* 下载视频到相册
|
||
* @param {string} videoUrl 视频地址
|
||
* @param {function} successCallback 成功回调
|
||
* @param {function} failCallback 失败回调
|
||
*/
|
||
export const downloadVideo = (videoUrl, successCallback, failCallback) => {
|
||
if (!videoUrl) {
|
||
uni.showToast({
|
||
title: '视频地址无效',
|
||
icon: 'none'
|
||
});
|
||
return;
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '下载中...',
|
||
mask: true
|
||
});
|
||
|
||
// 下载视频
|
||
uni.downloadFile({
|
||
url: videoUrl,
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
// 保存到相册
|
||
uni.saveVideoToPhotosAlbum({
|
||
filePath: res.tempFilePath,
|
||
success: () => {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '保存成功',
|
||
icon: 'success'
|
||
});
|
||
successCallback && successCallback();
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.log('保存视频失败:', err);
|
||
if (err.errMsg.includes('auth deny')) {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '请允许访问相册后重试\n(右上角菜单 - 设置 - 相册)',
|
||
showCancel: false
|
||
});
|
||
} else {
|
||
uni.showToast({
|
||
title: '保存失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
failCallback && failCallback(err);
|
||
}
|
||
});
|
||
} else {
|
||
uni.hideLoading();
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
});
|
||
failCallback && failCallback();
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading();
|
||
console.log('下载视频失败:', err);
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
});
|
||
failCallback && failCallback(err);
|
||
}
|
||
});
|
||
}; |