Files
ks-app-employment-service/common/globalFunction.js
2025-06-10 09:36:04 +08:00

588 lines
17 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 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;
}
/**
* 页面跳转封装,支持 query 参数传递和返回回调
* @param {string} url - 跳转路径
* @param {object} options
* @param {boolean} options.needLogin - 是否需要登录
* @param {object} options.query - 携带参数
* @param {function} options.onBack - 页面返回时的回调(目标页调用 uni.navigateBack 时传递数据)
*/
export const navTo = function(url, {
needLogin = false,
query = {},
onBack = null
} = {}) {
const userStore = useUserStore();
if (needLogin && !userStore.hasLogin) {
uni.navigateTo({
url: '/pages/login/login'
});
return;
}
const queryStr = Object.entries(query)
.map(([key, val]) => `${key}=${encodeURIComponent(val)}`)
.join('&');
const finalUrl = queryStr ? `${url}?${queryStr}` : url;
if (onBack) {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
currentPage.__onBackCallback__ = onBack;
}
uni.navigateTo({
url: finalUrl
});
};
export const navBack = function({
delta = 1,
data = null,
fallbackUrl = '/pages/index/index'
} = {}) {
const pages = getCurrentPages();
if (pages.length > 1) {
const prevPage = pages[pages.length - 1 - delta];
// 如果上一页存在回调函数,调用
if (data && prevPage?.__onBackCallback__) {
prevPage.__onBackCallback__(data);
}
uni.navigateBack({
delta
});
} else {
// 没有可返回的页面,直接跳转 fallback 页面
uni.reLaunch({
url: fallbackUrl
});
}
};
// // 默认返回上一页
// navBack();
// // 返回上两层
// navBack(2);
// // 没有历史页面时跳转首页
// navBack(1, '/pages/home/home');
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) {
const isClear = ids.length === 0;
nodes.forEach((firstLayer) => {
// 每次处理都先重置
firstLayer.checkednumber = 0;
const traverse = (node) => {
if (isClear) {
node.checked = false;
} else {
node.checked = ids.includes(node.id);
}
if (node !== firstLayer && node.checked) {
firstLayer.checkednumber++;
}
if (node.children && node.children.length) {
node.children.forEach(child => traverse(child));
}
};
traverse(firstLayer);
});
return nodes;
}
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;
}
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + ' B'
else if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'
else if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
else return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB'
}
function sendingMiniProgramMessage(data = {
text: 'hello'
}, action = 'defalut') {
jWeixin.miniProgram.postMessage({
data,
action
});
}
function copyText(text) {
uni.setClipboardData({
data: text,
showToast: false,
success(res) {
msg('复制成功')
},
});
}
function appendScriptTagElement(src) {
if (!src) return null;
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => {
resolve()
};
script.onerror = () => {
reject()
};
document.body.appendChild(script);
})
}
function isInWechatMiniProgramWebview() {
const ua = navigator.userAgent.toLowerCase()
return ua.includes('miniprogram') || window.__wxjs_environment === 'miniprogram'
}
function isEmptyObject(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length === 0;
}
export const $api = {
msg,
prePage,
sleep,
request,
createRequest,
streamRequest,
chatRequest,
insertSortData,
uploadFile,
formatFileSize,
sendingMiniProgramMessage,
copyText
}
export default {
$api,
navTo,
navBack,
cloneDeep,
formatDate,
getdeviceInfo,
checkingPhoneRegExp,
checkingEmailRegExp,
throttle,
debounce,
haversine,
getDistanceFromLatLonInKm,
vacanciesTo,
salaryGlobal,
customSystem,
setCheckedNodes,
formatTotal,
getWeeksOfMonth,
isFutureDate,
parseQueryParams,
appendScriptTagElement,
insertSortData,
isInWechatMiniProgramWebview,
isEmptyObject
}