Files
qhmes/JeecgUniapp-master/src/common/uitls.ts
2026-07-20 14:10:39 +08:00

757 lines
19 KiB
Vue
Raw 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 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<any>}
*/
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;
}