import pagesJson from '../pages.json' // 引入uni-parse-pages import pagesJsonToRoutes from 'uni-parse-pages' import { colorPanel } from './constants' import tip from './tip' import { platform, isH5, isApp, isMp, isMpWeixin, isMpAplipay, isMpToutiao } from '@/utils/platform' import { isString } from './is' /** * 缓存,默认有效期2小时 * @param key 缓存key * @param value 缓存值 * @param seconds 缓存时间(秒) * @returns {*} */ export function cache(key, value = null, seconds = 2 * 3600) { const timestamp = +new Date() / 1000 if (key && value === null) { // 获取缓存 const val = uni.getStorageSync(key) if (val && val.length > 0) { const tmp = val.split('|') if (!tmp[2] || timestamp >= tmp[2]) { console.log('key已失效') // 删除缓存 uni.removeStorageSync(key) return '' } else { console.log('key未失效') if (tmp[1] == 'json') { return JSON.parse(tmp[0]) } return tmp[0] } } } else if (key && value) { // 设置缓存 const expire = timestamp + seconds console.log('typeof value', typeof value) if (typeof value === 'object') { value = JSON.stringify(value) + '|json|' + expire } else { value = value + '|string|' + expire } uni.setStorageSync(key, value) } else { console.log('key不能空') } } // 获取静态文件地址 export const getStaticDomainURL = () => { return import.meta.env.VITE_SERVER_BASEURL + '/sys/common/static' } export const getFileAccessHttpUrl = function (avatar, subStr?) { if (!avatar) return '' if (!subStr) subStr = 'http' if (avatar) { avatar = avatar.replace(/user_imgs\\/, 'user_imgs/') } if (avatar && avatar.startsWith(subStr)) { return avatar } else { return getStaticDomainURL() + '/' + avatar } } interface hasRouteType { name?: string path?: string routeList?: any } // 判断路由是否存在 export const hasRoute = ({ name, path, routeList }: hasRouteType) => { routeList = routeList ?? pagesJsonToRoutes(pagesJson) if (path) { return !!routeList.find((item) => item.path === path) } if (name) { return !!routeList.find((item) => item.path.split('/').pop() === name) } } /** * 人性化显示时间 * * @param {Object} datetime */ export function beautifyTime(datetime = '') { if (datetime == null) { return '' } datetime = datetime.toString().replace(/-/g, '/') const time = new Date() let outTime = new Date(datetime) if (/^[1-9]\d*$/.test(datetime)) { outTime = new Date(parseInt(datetime)) } if (time.getTime() < outTime.getTime()) { return parseTime(outTime, '{y}/{m}/{d}') } if (time.getFullYear() != outTime.getFullYear()) { return parseTime(outTime, '{y}/{m}/{d}') } if (time.getMonth() != outTime.getMonth()) { return parseTime(outTime, '{m}/{d}') } if (time.getDate() != outTime.getDate()) { const day = outTime.getDate() - time.getDate() if (day == -1) { return parseTime(outTime, '昨天 {h}:{i}') } if (day == -2) { return parseTime(outTime, '前天 {h}:{i}') } return parseTime(outTime, '{m}-{d}') } if (time.getHours() != outTime.getHours()) { return parseTime(outTime, '{h}:{i}') } let minutes = outTime.getMinutes() - time.getMinutes() if (minutes == 0) { return '刚刚' } minutes = Math.abs(minutes) return `${minutes}分钟前` } /** * 格式化时间 * @param {Object} time * @param {Object} cFormat */ export function parseTime(time, cFormat) { if (arguments.length === 0) { return null } let date const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' if (typeof time === 'object') { date = time } else { if (typeof time === 'string' && /^[0-9]+$/.test(time)) { time = parseInt(time) } else { time = new Date(time) } date = new Date(time.toString().replace(/-/g, '/')) } const formatObj = { y: date.getFullYear(), m: date.getMonth() + 1, d: date.getDate(), h: date.getHours(), i: date.getMinutes(), s: date.getSeconds(), a: date.getDay(), } const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => { const value = formatObj[key] // Note: getDay() returns 0 on Sunday if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } return value.toString().padStart(2, '0') }) return time_str } /** * 随机生成字符串 * @param length 字符串的长度 * @param chats 可选字符串区间(只会生成传入的字符串中的字符) * @return string 生成的字符串 */ export function randomString(length, chats?) { if (!length) length = 1 if (!chats) chats = '0123456789qwertyuioplkjhgfdsazxcvbnm' let str = '' for (let i = 0; i < length; i++) { // @ts-ignore const num = randomNumber(0, chats.length - 1) str += chats[num] } return str } /** * 随机生成数字 * * 示例:生成长度为 12 的随机数:randomNumber(12) * 示例:生成 3~23 之间的随机数:randomNumber(3, 23) * * @param1 最小值 | 长度 * @param2 最大值 * @return int 生成后的数字 */ export function randomNumber() { // 生成 最小值 到 最大值 区间的随机数 const random = (min, max) => { return Math.floor(Math.random() * (max - min + 1) + min) } if (arguments.length === 1) { // @ts-ignore const [length] = arguments // 生成指定长度的随机数字,首位一定不是 0 // @ts-ignore const nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9))) return parseInt(nums.join('')) } else if (arguments.length >= 2) { // @ts-ignore const [min, max] = arguments return random(min, max) } else { return Number.NaN } } /** * 时间格式化 * @param value * @param fmt * @returns {*} */ export function formatDate(value, fmt) { const regPos = /^\d+(\.\d+)?$/ if (regPos.test(value)) { // 如果是数字 const getDate = new Date(value) const o = { 'M+': getDate.getMonth() + 1, 'd+': getDate.getDate(), 'h+': getDate.getHours(), 'H+': getDate.getHours(), 'm+': getDate.getMinutes(), 's+': getDate.getSeconds(), 'q+': Math.floor((getDate.getMonth() + 3) / 3), S: getDate.getMilliseconds(), } if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length)) } for (const 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 } else { // TODO if (value && value.length > 0) { value = value.trim() return value.substr(0, fmt.length) } return value } } // 通过时间或者时间戳获取对应antd的年、月、周、季度。 export function getWeekMonthQuarterYear(date) { // 获取 ISO 周数的函数 const getISOWeek = (date) => { const jan4 = new Date(date.getFullYear(), 0, 4) const oneDay = 86400000 // 一天的毫秒数 return Math.ceil(((date - jan4.getTime()) / oneDay + jan4.getDay() + 1) / 7) } // 将时间戳转换为日期对象 const dateObj = new Date(date) // 计算周 const week = getISOWeek(dateObj) // 计算月 const month = dateObj.getMonth() + 1 // 月份是从0开始的,所以要加1 // 计算季度 const quarter = Math.floor(dateObj.getMonth() / 3) + 1 // 计算年 const year = dateObj.getFullYear() return { year: `${year}`, month: `${year}-${month.toString().padStart(2, '0')}`, week: `${year}-${week}周`, quarter: `${year}-Q${quarter}`, } } // 生成 1 到 10 之间的随机整数 export function getRandomIntBetweenOneAndTen() { return Math.floor(Math.random() * 10) + 1 } /** * 获取随机颜色 * @param {any} color * 颜色板 * classic:经典 * technology:科技 * business:商务 * botany:植物 * natural:自然 * colour:彩色 * @return */ export function getRandomColor() { const colorType = ['classic', 'technology', 'business', 'botany', 'natural', 'colour'] // 生成一个随机索引,范围是从 0 到数组长度减 1 const randomIndex = Math.floor(Math.random() * colorType.length) // 根据随机索引从数组中获取一个随机类型 const randomColorType = colorType[randomIndex] return colorPanel.natural[getRandomIntBetweenOneAndTen()] || '#00bcd4' } // 消除后缀: export const getPlaceholder = (attrs: any = {}) => { let label = attrs.label if (label.endsWith(':') || label.endsWith(':')) { label = label.substr(0, label.length - 1) } return `请选择${label}` } /** * 日期格式化 * @param text */ export function getFormatDate(text, column) { if (!text) { return '' } let a = text if (a.length > 10) { a = a.substring(0, 10) } let fieldExtendJson = column?.fieldExtendJson console.log('getFormat Datetext', text) console.log('getFormatDate fieldExtendJson', fieldExtendJson) if (fieldExtendJson) { fieldExtendJson = JSON.parse(fieldExtendJson) if (fieldExtendJson.picker && fieldExtendJson.picker != 'default') { const result = getWeekMonthQuarterYear(a) return result[fieldExtendJson.picker] } } return a } /** * 字典值替换文本通用方法(多选) * @param dictOptions 字典数组 * @param text 字典值 * @return String */ export function filterMultiDictText(dictOptions, text) { // js “!text” 认为0为空,所以做提前处理 if (text === 0 || text === '0') { if (dictOptions) { for (const dictItem of dictOptions) { if (text == dictItem.value) { return dictItem.text } } } } if (!text || text == 'undefined' || text == 'null' || !dictOptions || dictOptions.length == 0) { return '' } let re = '' text = text.toString() const arr = text.split(',') dictOptions.forEach(function (option) { if (option) { for (let i = 0; i < arr.length; i++) { if (arr[i] === option.value) { re += option.text + ',' break } } } }) if (re == '') { return text } return re.substring(0, re.length - 1) } /** 获取url参数 * @param {Object} url */ export function getQueryVariable(url) { if (!url) return let t let n let r const i = url.split('?')[1] const s = {} ;(t = i.split('&')), (r = null), (n = null) for (const o in t) { const u = t[o].indexOf('=') u !== -1 && ((r = t[o].substr(0, u)), (n = t[o].substr(u + 1)), (s[r] = n)) } return s } /** * 是否oauth环境 */ export function isOAuth2AppEnv() { let isOAuthEnv = false // #ifdef H5 isOAuthEnv = /wxwork|dingtalk/i.test(navigator.userAgent) // #endif return isOAuthEnv } /** * 获取url中的参数 * @param url */ export const getUrlParams = (url) => { const result = { url: '', params: {}, } const list = url.split('?') result.url = list[0] const params = list[1] if (params) { const list = params.split('&') list.forEach((ele) => { const dic = ele.split('=') const label = dic[0] const value = dic[1] result.params[label] = value }) } return result } /** * 判断文件地址是否支持存在 * @param url * @returns {Promise} */ export function downloadAbled(url) { return new Promise((resolve, reject) => { let xmlHttp if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest() // 其他浏览器 } else if ((window as any).ActiveXObject) { // try { // xmlHttp = new window.ActiveXObject("Microsoft.XMLHTTP");//IE // }catch (e) { // console.log('创建xmlHttp失败',e) // } } if (!xmlHttp) { reject('创建xmlHttp失败') } xmlHttp.open('GET', url, false) xmlHttp.send() if (xmlHttp.readyState == 4) { if (xmlHttp.status == 200) { resolve(true) } else if (xmlHttp.status == 404) { reject('文件不存在!') } else { reject('请求失败,status:' + xmlHttp.status) } } else { reject('请求失败,readyState:' + xmlHttp.readyState) } }) } /** * app获取url地址的传参问题 * @param url * @returns {Object} */ export function appGetUrlParams(url) { const theRequest = new Object() const index = url.indexOf('?') if (index != -1) { const str = url.substring(index + 1) const strs = str.split('&') for (let i = 0; i < strs.length; i++) { theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]) } } return theRequest } /** * * @param lat1 纬度1 * @param lng1 经度1 * @param lat2 纬度2 * @param lng2 经度2 * 返回 米 */ export function geoDistance(lng1, lat1, lng2, lat2) { let radLat1 = rad(lat1) let radLat2 = rad(lat2) let a = radLat1 - radLat2 let b = rad(lng1) - rad(lng2) let s = 2 * Math.asin( Math.sqrt( Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2), ), ) s = s * 6378.137 // EARTH_RADIUS; s = Math.round(s * 10000) / 10 return s } //经纬度转换成三角函数中度分表形式。 function rad(d) { return (d * Math.PI) / 180.0 } export function downloadFile(obj) { let url = '' if (isMp) { if (obj.currentTarget) { url = encodeURI(obj.currentTarget.dataset.url) downloadNH5(url) } else if (isString(obj)) { // 为字符串类型时,可认为就是url url = getFileAccessHttpUrl(obj) downloadNH5(url) } } else if (isApp) { url = encodeURI(obj) downloadNH5(url) } else if (isH5) { url = getFileAccessHttpUrl(obj) window.open(url) } } /** * 非H5文件下载地址 * @param 文件路径 url */ function downloadNH5(url) { const image_arr = ['png', 'jpg', 'jpeg'] const fileType = url.split('.').pop() uni.downloadFile({ url, success: (res) => { if (res.statusCode == 200) { let filePath = res.tempFilePath const system = uni.getSystemInfoSync().platform if (system == 'ios') { filePath = encodeURI(filePath) } if (isMp) { const suffix = getSuffix(url).toLowerCase() if (image_arr.indexOf(suffix) != -1) { // 预览图片 uni.previewImage({ urls: [filePath], }) } else { uni.openDocument({ filePath, fileType, success: (res) => { console.log('打开文档成功') }, fail: (res) => { console.log('打开文档失败') tip.error('不支持打开此格式', true) }, }) } } else if (isApp) { const suffix = getSuffix(url).toLowerCase() if (image_arr.indexOf(suffix) != -1) { // 预览图片 uni.previewImage({ urls: [filePath], }) } else { uni.saveFile({ tempFilePath: filePath, success: (res) => { // 保存成功并打开文件 tip.success('保存成功') uni.openDocument({ filePath: res.savedFilePath, success: function (res) { console.log('openDocument', res) }, fail() { uni.showToast({ title: '暂不支持打开此类型', duration: 2000, }) }, }) }, fail: () => tip.alert('保存失败'), }) } } } else { tip.alert('文件异常') } }, fail: (err) => { tip.alert('下载失败') }, }) } // 获取后缀 export function getSuffix(text) { if (text) { const arr = text.split('.') const suffix = arr[arr.length - 1] return suffix } return text } /** * 获取后缀图标 * @param {Object} doctype */ export function getFileIcon(doctype) { const file_doc_type_arr = ['doc', 'excel', 'file', 'folder', 'image', 'pdf', 'video'] if (file_doc_type_arr.indexOf(doctype) >= 0) { return `/static/${doctype}.png` } else { return '/static/file.png' } } /** * 获取uuid */ export function uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) } export const queryString = (params) => { return Object.entries(params) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value as string)}`) .join('&') } /** * 将任意日期转换为对应季度的首日 * @param {Date|string} date - 日期对象或日期字符串 * @returns {string} 格式为'YYYY-MM-DD'的季度首日 */ export function dateToQuarterStart(date) { if (!date){ return '' } // 如果传入的是字符串,转换为Date对象 if (typeof date === 'string') { date = new Date(date) } const year = date.getFullYear() const month = date.getMonth() // 0-11 // 计算季度 const quarter = Math.floor(month / 3) // 确定季度首月的月份 (0=1月, 3=4月, 6=7月, 9=10月) const quarterStartMonth = quarter * 3 // 格式化为'YYYY-MM-DD' return `${year}-${String(quarterStartMonth + 1).padStart(2, '0')}-01` } //时间数组 export function timeData(startTime = '08:00', endTime = '18:30', timeInterval = 0.5) { const time = [] const date = timeStamp(Date.now()).allDate const startDate = `${date} ${startTime}` const endDate = `${date} ${endTime}` const startTimeStamp = new Date(startDate).getTime() const endTimeStamp = new Date(endDate).getTime() const timeStr = 3600 * 1000 * timeInterval console.log(startTimeStamp) for (let i = startTimeStamp; i <= endTimeStamp; i = i + timeStr) { const timeObj:any = {} timeObj.time = timeStamp(i).hour timeObj.disable = 0 time.push(timeObj) } return time } //字符串拼接 function strFormat(str) { return str < 10 ? `0${str}` : str } //时间戳转字符串 export function timeStamp(time) { const dates = new Date(time) const year = dates.getFullYear() const month = dates.getMonth() + 1 const date = dates.getDate() const day = dates.getDay() const hour = dates.getHours() const min = dates.getMinutes() const days = ['日', '一', '二', '三', '四', '五', '六'] return { allDate: `${year}/${strFormat(month)}/${strFormat(date)}`, date: `${strFormat(month)}-${strFormat(date)}`, //返回的日期 07-01 day: `星期${days[day]}`, //返回的礼拜天数 星期一 hour: strFormat(hour) + ':' + strFormat(min) //返回的时钟 08:00 } } /** * 字符串转时间 * @param {Object} dateString */ export function stringToDate(dateString) { var newDate = new Date(); var yearNum = Number(dateString.substr(0,4)); var monthNum = Number(dateString.substr(5,2))-1; var dayNum = Number(dateString.substr(8,2)); var hourNum = Number(dateString.substr(11,2)); var minuteNum = Number(dateString.substr(14,2)); //var secondNum = Number(dateString.substr(12,2)); newDate.setFullYear(yearNum); newDate.setMonth(monthNum); newDate.setDate(dayNum); newDate.setHours(hourNum); newDate.setMinutes(minuteNum); //newDate.setSeconds(secondNum); return newDate; }