import useUserStore from "../stores/useUserStore"; import { request, createRequest, uploadFile } from "../utils/request"; import streamRequest, { chatRequest } from "../utils/streamRequest.js"; export const CloneDeep = (props) => { if (typeof props !== 'object' || props === null) { return props } let result if (props) { result = [] } else { result = {} } for (let key in props) { if (props.hasOwnProperty(key)) { result[key] = CloneDeep(props[key]) } } return result } export const msg = (title, duration = 1500, mask = false, icon = 'none', image) => { if (Boolean(title) === false) { return; } uni.showToast({ title, duration, mask, icon, image }); } const prePage = () => { let pages = getCurrentPages(); let prePage = pages[pages.length - 2]; return prePage.$vm; } const navTo = function(url, needLogin) { if (needLogin && useUserStore().hasLogin) { uni.navigateTo({ url: '/pages/login/login' }); return } uni.navigateTo({ url }); } function getdeviceInfo() { const globalData = { statusBarHeight: 0, // 状态导航栏高度 topHeight: 0, // 距离顶部高度 navHeight: 0, // 总体高度 windowHeight: 0, // 可使用窗口高度 tabBarHight: 0, //底部导航栏高度 }; let systemInfo = uni.getSystemInfoSync() globalData.windowHeight = systemInfo.screenHeight // 底部导航栏 globalData.tabBarHight = systemInfo.screenHeight - systemInfo.safeArea.bottom // 状态栏高度 globalData.statusBarHeight = systemInfo.statusBarHeight // #ifdef MP-MP-WEIXIN let menuButtonInfo = uni.getMenuButtonBoundingClientRect() // 胶囊距离顶部高度 globalData.topHeight = menuButtonInfo.top // 胶囊高度 globalData.navHeight = menuButtonInfo.height​ // #endif return { ...globalData } } function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)) } const cloneDeep = (obj) => { // 1.1 判断是否是对象 const isObject = (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj !== 'null' if (!isObject(obj)) { throw new Error('参数不是对象') } // 1.3 如果参数为数组,则复制数组各元素,否则复制对象属性 const newObject = Array.isArray(obj) ? [...obj] : { ...obj } // 1.4 迭代 Object.keys(newObject).forEach((key) => { // 1.5 判断如果遍历到的属性值为对象,则继续递归cloneDeep if (isObject(newObject[key])) { newObject[key] = cloneDeep(newObject[key]) } }) return newObject } const CopyText = (text) => { let input = document.createElement('textarea'); input.value = text; document.body.appendChild(input); input.select(); let flag = document.execCommand('copy') if (flag) { message.success('成功复制到剪贴板') } else { message.success('复制失败') } document.body.removeChild(input) } // 柯里化 降低使用范围,提高适用性 function Exp(regExp) { return (str) => { return regExp.test(str) } } const checkingPhoneRegExp = Exp(/^1[3-9]{1}\d{9}/) // 手机号校验 checkingPhoneRegExp(phone) const checkingEmailRegExp = Exp(/^[a-z0-9_\.-]+@[a-z0-9_\.-]+[a-z0-9]{2,6}$/i) // 邮箱校验 checkingEmailRegExp(email) function throttle(fn, delay = 300) { let valid = true let savedArgs = null // 参数存储器 let savedContext = null // 上下文存储器 return function(...args) { // 保存当前参数和上下文 savedArgs = args savedContext = this if (!valid) return false valid = false setTimeout(() => { fn.apply(savedContext, savedArgs) valid = true savedArgs = null // 清空存储 savedContext = null }, delay) } } function debounce(fun, delay) { return function(args) { let that = this let _args = args clearTimeout(fun.id) fun.id = setTimeout(function() { fun.call(that, _args) }, delay) } } function toRad(degree) { return degree * Math.PI / 180; } function haversine(lat1, lon1, lat2, lon2) { const R = 6371; // 地球半径,单位为公里 const a1 = toRad(lat1); const a2 = toRad(lat2); const b1 = toRad(lat2 - lat1); const b2 = toRad(lon2 - lon1); const a = Math.sin(b1 / 2) * Math.sin(b1 / 2) + Math.cos(a1) * Math.cos(a2) * Math.sin(b2 / 2) * Math.sin(b2 / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const distance = R * c; // 计算得到的距离,单位为公里 return distance; } export function getDistanceFromLatLonInKm(lat1, lon1, lat2, lon2) { const R = 6371; // 地球平均半径,单位为公里 const dLat = deg2rad(lat2 - lat1); const dLon = deg2rad(lon2 - lon1); const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); const d = R * c; return { km: d, m: d * 1000 }; } // 将角度转换为弧度 function deg2rad(deg) { return deg * (Math.PI / 180); } function vacanciesTo(vacancies) { if (vacancies >= 0) { return vacancies + "人" } else { return '不限人数' } } function salaryGlobal(type = 'min') { const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80]; const salaymax = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100]; const salarys = salay.map((item, index) => ({ label: item + 'k', value: item * 1000, children: CloneDeep(salaymax).splice(index).map((vItem) => ({ label: vItem + 'k', value: vItem * 1000, })) })) return salarys } class CustomSystem { constructor() { const systemInfo = uni.getSystemInfoSync(); this.systemInfo = systemInfo } } const customSystem = new CustomSystem() function setCheckedNodes(nodes, ids) { // 处理每个第一层节点 nodes.forEach((firstLayer) => { // 初始化或重置计数器 firstLayer.checkednumber = 0; // 递归处理子树 const traverse = (node) => { // 设置当前节点选中状态 const shouldCheck = ids.includes(node.id); if (shouldCheck) node.checked = true; // 统计后代节点(排除首层自身) if (node !== firstLayer && node.checked) { firstLayer.checkednumber++; } // 递归子节点 if (node.children) { node.children.forEach((child) => traverse(child)); } }; // 启动当前首层节点的遍历 traverse(firstLayer); }); } const formatTotal = (total) => { if (total < 10) return total.toString(); // 直接返回小于 10 的数 const magnitude = Math.pow(10, Math.floor(Math.log10(total))); // 计算数量级 const roundedTotal = Math.floor(total / magnitude) * magnitude; // 去掉零头 return `${roundedTotal}+`; }; export function formatDate(isoString) { const date = new Date(isoString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,需要 +1 const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } export function insertSortData(data, attribute = 'createTime') { const sortedData = data.sort((a, b) => new Date(b[attribute]) - new Date(a[attribute])); // 按时间降序排序 const result = []; let lastDate = ''; let lastTitle = '' const now = new Date(); const todayStr = now.toISOString().split('T')[0]; // 获取今天的日期字符串 const yesterday = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取昨天的日期字符串 const twoDaysAgo = new Date(now.setDate(now.getDate() - 1)).toISOString().split('T')[0]; // 获取前天的日期字符串 sortedData.forEach(item => { const itemAttribute = item[attribute].replace('T', ' ') const itemDate = itemAttribute.split(' ')[0]; // 提取日期部分 let title = itemDate; if (itemDate === todayStr) { title = '今天'; } else if (itemDate === yesterday) { title = '昨天'; } else if (itemDate === twoDaysAgo) { title = '前天'; } if (lastDate !== itemDate) { result.push({ title, isTitle: true }); lastDate = itemDate; lastTitle = title; } result.push({ ...item, isTitle: false }); }); return [result, lastTitle]; } function getWeeksOfMonth(year, month) { const firstDay = new Date(year, month - 1, 1); // 当月第一天 const lastDay = new Date(year, month, 0); // 当月最后一天 const weeks = []; let week = []; for (let d = new Date(firstDay); d <= lastDay; d.setDate(d.getDate() + 1)) { // 补充第一周的上个月日期 if (week.length === 0 && d.getDay() !== 1) { let prevMonday = new Date(d); prevMonday.setDate(d.getDate() - (d.getDay() === 0 ? 6 : d.getDay() - 1)); while (prevMonday < d) { week.push({ year: prevMonday.getFullYear(), month: prevMonday.getMonth() + 1, day: prevMonday.getDate(), fullDate: getLocalYYYYMMDD(prevMonday), // 修正 weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][prevMonday.getDay()], isCurrent: false // 上个月日期 }); prevMonday.setDate(prevMonday.getDate() + 1); } } // 添加当前月份的日期 week.push({ year: d.getFullYear(), month: d.getMonth() + 1, day: d.getDate(), fullDate: getLocalYYYYMMDD(d), // 修正 weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][d.getDay()], isCurrent: true // 当前月的日期 }); // 如果到了月末但当前周未满7天,需要补足到周日 if (d.getTime() === lastDay.getTime() && week.length < 7) { let nextDay = new Date(d); nextDay.setDate(d.getDate() + 1); while (week.length < 7) { week.push({ year: nextDay.getFullYear(), month: nextDay.getMonth() + 1, day: nextDay.getDate(), fullDate: getLocalYYYYMMDD(nextDay), // 修正 weekday: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"][nextDay.getDay()], isCurrent: false // 下个月日期 }); nextDay.setDate(nextDay.getDate() + 1); } } // 如果本周满了(7天)或者到了月末 if (week.length === 7 || d.getTime() === lastDay.getTime()) { weeks.push([...week]); // 存入当前周 week = []; // 清空,准备下一周 } } return weeks; } // 新增工具函数:将日期格式化为本地 YYYY-MM-DD 字符串 function getLocalYYYYMMDD(date) { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); const d = String(date.getDate()).padStart(2, '0'); return `${y}-${m}-${d}`; } function isFutureDate(dateStr) { const inputDate = new Date(dateStr); const today = new Date(); // 只比较年月日,不考虑具体时间 today.setHours(0, 0, 0, 0); inputDate.setHours(0, 0, 0, 0); return inputDate > today; } function parseQueryParams(url = window.location.href) { const queryString = url.split('?')[1]?.split('#')[0]; const params = {}; if (!queryString) return params; queryString.split('&').forEach(param => { const [key, value] = param.split('='); if (key) { params[decodeURIComponent(key)] = decodeURIComponent(value || ''); } }); return params; } export const $api = { msg, prePage, sleep, request, createRequest, streamRequest, chatRequest, insertSortData, uploadFile } export default { $api, navTo, cloneDeep, formatDate, getdeviceInfo, checkingPhoneRegExp, checkingEmailRegExp, throttle, debounce, haversine, getDistanceFromLatLonInKm, vacanciesTo, salaryGlobal, customSystem, setCheckedNodes, formatTotal, getWeeksOfMonth, isFutureDate, parseQueryParams }