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); } }); };