flat:AI+
This commit is contained in:
@@ -1,6 +1,36 @@
|
||||
import useUserStore from "../stores/useUserStore";
|
||||
import {
|
||||
request,
|
||||
createRequest,
|
||||
uploadFile
|
||||
} from "../utils/request";
|
||||
import streamRequest, {
|
||||
chatRequest
|
||||
} from "../utils/streamRequest.js";
|
||||
|
||||
const msg = (title, duration = 1500, mask = false, icon = 'none', image) => {
|
||||
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;
|
||||
}
|
||||
@@ -63,14 +93,376 @@ function getdeviceInfo() {
|
||||
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': {
|
||||
msg,
|
||||
prePage,
|
||||
sleep
|
||||
},
|
||||
$api,
|
||||
navTo,
|
||||
getdeviceInfo
|
||||
cloneDeep,
|
||||
formatDate,
|
||||
getdeviceInfo,
|
||||
checkingPhoneRegExp,
|
||||
checkingEmailRegExp,
|
||||
throttle,
|
||||
debounce,
|
||||
haversine,
|
||||
getDistanceFromLatLonInKm,
|
||||
vacanciesTo,
|
||||
salaryGlobal,
|
||||
customSystem,
|
||||
setCheckedNodes,
|
||||
formatTotal,
|
||||
getWeeksOfMonth,
|
||||
isFutureDate,
|
||||
parseQueryParams
|
||||
}
|
Reference in New Issue
Block a user