Подготовить HY2XS к production-сборке
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 格式化字节大小
|
||||
* @param bytes 字节数
|
||||
* @param decimals 小数位数,默认为 2
|
||||
* @returns 格式化后的字节大小字符串
|
||||
*/
|
||||
export const formatBytes = (bytes: number, decimals = 2): string => {
|
||||
// 检查是否为特殊值
|
||||
if (bytes === -1) {
|
||||
return "Unlimited";
|
||||
}
|
||||
if (bytes === 0) {
|
||||
return "0 Bytes";
|
||||
}
|
||||
|
||||
// 计算单位和大小
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
// 返回格式化后的字符串
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||
};
|
||||
|
||||
export const calculateBytes = (value = 0, unit = "Bytes"): number => {
|
||||
// 将单位转换为大写,并去除空格
|
||||
const formattedUnit = unit.toUpperCase().trim();
|
||||
|
||||
// 定义存储单位和对应的字节数的映射关系
|
||||
const unitToBytes: Record<string, number> = {
|
||||
BYTES: 1,
|
||||
KB: 1024 ** 1,
|
||||
MB: 1024 ** 2,
|
||||
GB: 1024 ** 3,
|
||||
TB: 1024 ** 4,
|
||||
PB: 1024 ** 5,
|
||||
EB: 1024 ** 6,
|
||||
ZB: 1024 ** 7,
|
||||
YB: 1024 ** 8,
|
||||
};
|
||||
|
||||
// 检查传入的单位是否存在于映射关系中
|
||||
if (!Object.prototype.hasOwnProperty.call(unitToBytes, formattedUnit)) {
|
||||
throw new Error("Invalid unit");
|
||||
}
|
||||
|
||||
if (value == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 计算并返回字节数
|
||||
return value * unitToBytes[formattedUnit];
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化存储容量单位
|
||||
* @param bytes 存储容量(字节数)
|
||||
* @param decimals 小数位数,默认为 2
|
||||
* @returns 格式化后的存储容量值
|
||||
*/
|
||||
export const formatStorageCapacity = (bytes: number, decimals = 2): number => {
|
||||
// 检查输入是否有效
|
||||
if (!bytes || bytes <= 0) {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// 计算存储单位
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
// 格式化存储容量值并返回
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化存储容量单位
|
||||
* @param bytes 存储容量(字节数)
|
||||
* @returns 格式化后的存储单位
|
||||
*/
|
||||
export const formatStorageUnit = (bytes: number): string => {
|
||||
// 检查输入是否有效
|
||||
if (!bytes || bytes <= 0) {
|
||||
return "Bytes";
|
||||
}
|
||||
|
||||
// 计算存储单位
|
||||
const k = 1024;
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
// 返回格式化后的存储单位
|
||||
return sizes[i];
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 浅拷贝,忽略 null,支持嵌套对象
|
||||
* @param target
|
||||
* @param source
|
||||
*/
|
||||
export const assignWith = <T>(target: T, source: Partial<T>): void => {
|
||||
if (source === null || typeof source !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in source) {
|
||||
if (source[key] !== null) {
|
||||
if (typeof source[key] === "object") {
|
||||
if (!target[key]) {
|
||||
target[key] = (Array.isArray(source[key]) ? [] : {}) as T[Extract<
|
||||
keyof T,
|
||||
string
|
||||
>];
|
||||
}
|
||||
assignWith(target[key] as any, source[key] as any);
|
||||
} else {
|
||||
target[key] = source[key] as T[Extract<keyof T, string>];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 深拷贝,忽略 null,支持嵌套对象
|
||||
* @param source
|
||||
*/
|
||||
export const deepCopy = <T>(source: Partial<T>): T => {
|
||||
if (source === null || typeof source !== "object") {
|
||||
return source;
|
||||
}
|
||||
|
||||
if (Array.isArray(source)) {
|
||||
const arrCopy = [] as any[];
|
||||
source.forEach((item, index) => {
|
||||
arrCopy[index] = deepCopy(item);
|
||||
});
|
||||
return arrCopy as any;
|
||||
}
|
||||
|
||||
const objCopy = {} as { [key: string]: any };
|
||||
Object.keys(source).forEach((key) => {
|
||||
objCopy[key] = deepCopy((source as { [key: string]: any })[key]);
|
||||
});
|
||||
|
||||
return objCopy as T;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
// translate router.meta.title, be used in breadcrumb sidebar tagsview
|
||||
import i18n from "@/lang/index";
|
||||
|
||||
export function translateRouteTitleI18n(title: any) {
|
||||
// 判断是否存在国际化配置,如果没有原生返回
|
||||
const hasKey = i18n.global.te("route." + title);
|
||||
if (hasKey) {
|
||||
const translatedTitle = i18n.global.t("route." + title);
|
||||
return translatedTitle;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Check if an element has a class
|
||||
* @param {HTMLElement} ele
|
||||
* @param {string} cls
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function hasClass(ele: HTMLElement, cls: string) {
|
||||
return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add class to element
|
||||
* @param {HTMLElement} ele
|
||||
* @param {string} cls
|
||||
*/
|
||||
export function addClass(ele: HTMLElement, cls: string) {
|
||||
if (!hasClass(ele, cls)) ele.className += " " + cls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove class from element
|
||||
* @param {HTMLElement} ele
|
||||
* @param {string} cls
|
||||
*/
|
||||
export function removeClass(ele: HTMLElement, cls: string) {
|
||||
if (hasClass(ele, cls)) {
|
||||
const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
|
||||
ele.className = ele.className.replace(reg, " ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isExternal(path: string) {
|
||||
const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path);
|
||||
return isExternal;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import axios, { InternalAxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import { useAccountStoreHook } from "@/store/modules/account";
|
||||
|
||||
const dynamicBase = (window as any).__dynamic_base__ || "";
|
||||
// 创建 axios 实例
|
||||
const service = axios.create({
|
||||
baseURL: `${dynamicBase}${import.meta.env.VITE_APP_BASE_API}`,
|
||||
timeout: 50000,
|
||||
headers: { "Content-Type": "application/json;charset=utf-8" },
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
const accountStore = useAccountStoreHook();
|
||||
if (accountStore.token) {
|
||||
config.headers.Authorization = accountStore.token;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error: any) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
const { code, message } = response.data;
|
||||
if (code === 20000) {
|
||||
return response.data;
|
||||
}
|
||||
// 响应数据为二进制流处理(文件导出)
|
||||
if (response.data instanceof ArrayBuffer || response.data instanceof Blob) {
|
||||
return response;
|
||||
}
|
||||
|
||||
ElMessage.error(message || "系统出错");
|
||||
return Promise.reject(new Error(message || "Error"));
|
||||
},
|
||||
(error: any) => {
|
||||
if (error.response.data) {
|
||||
const { code, msg } = error.response.data;
|
||||
// token 过期,重新登录
|
||||
if (code === "A0230") {
|
||||
ElMessageBox.confirm("当前页面已失效,请重新登录", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
localStorage.clear();
|
||||
window.location.href = "/";
|
||||
});
|
||||
} else {
|
||||
ElMessage.error(msg || "系统出错");
|
||||
}
|
||||
}
|
||||
return Promise.reject(error.message);
|
||||
}
|
||||
);
|
||||
|
||||
// 导出 axios 实例
|
||||
export default service;
|
||||
@@ -0,0 +1,69 @@
|
||||
const easeInOutQuad = (t: number, b: number, c: number, d: number) => {
|
||||
t /= d / 2;
|
||||
if (t < 1) {
|
||||
return (c / 2) * t * t + b;
|
||||
}
|
||||
t--;
|
||||
return (-c / 2) * (t * (t - 2) - 1) + b;
|
||||
};
|
||||
|
||||
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
|
||||
const requestAnimFrame = (function () {
|
||||
return (
|
||||
window.requestAnimationFrame ||
|
||||
(window as any).webkitRequestAnimationFrame ||
|
||||
(window as any).mozRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
/**
|
||||
* Because it's so fucking difficult to detect the scrolling element, just move them all
|
||||
* @param {number} amount
|
||||
*/
|
||||
const move = (amount: number) => {
|
||||
document.documentElement.scrollTop = amount;
|
||||
(document.body.parentNode as HTMLElement).scrollTop = amount;
|
||||
document.body.scrollTop = amount;
|
||||
};
|
||||
|
||||
const position = () => {
|
||||
return (
|
||||
document.documentElement.scrollTop ||
|
||||
(document.body.parentNode as HTMLElement).scrollTop ||
|
||||
document.body.scrollTop
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} to
|
||||
* @param {number} duration
|
||||
* @param {Function} callback
|
||||
*/
|
||||
export const scrollTo = (to: number, duration: number, callback?: any) => {
|
||||
const start = position();
|
||||
const change = to - start;
|
||||
const increment = 20;
|
||||
let currentTime = 0;
|
||||
duration = typeof duration === "undefined" ? 500 : duration;
|
||||
const animateScroll = function () {
|
||||
// increment the time
|
||||
currentTime += increment;
|
||||
// find the value with the quadratic in-out easing function
|
||||
const val = easeInOutQuad(currentTime, start, change, duration);
|
||||
// move the document.body
|
||||
move(val);
|
||||
// do the animation unless its over
|
||||
if (currentTime < duration) {
|
||||
requestAnimFrame(animateScroll);
|
||||
} else {
|
||||
if (callback && typeof callback === "function") {
|
||||
// the animation is done so lets callback
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
animateScroll();
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* 将时间戳转换为格式化日期时间字符串(YYYY-MM-DD HH:mm:ss)
|
||||
* @param timestamp 时间戳
|
||||
* @returns 格式化日期时间字符串
|
||||
*/
|
||||
export const timestampToDateTime = (timestamp: number): string => {
|
||||
const date = new Date(timestamp);
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
const hours = date.getHours().toString().padStart(2, "0");
|
||||
const minutes = date.getMinutes().toString().padStart(2, "0");
|
||||
const seconds = date.getSeconds().toString().padStart(2, "0");
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
};
|
||||
|
||||
export const calculateTimeDifference = (timestamp: number): string => {
|
||||
const now = Date.now();
|
||||
const diff = timestamp - now;
|
||||
|
||||
if (diff <= 0) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const seconds = Math.floor(diff / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
|
||||
const remainingHours = hours % 24;
|
||||
const remainingMinutes = minutes % 60;
|
||||
const remainingSeconds = seconds % 60;
|
||||
|
||||
const parts: string[] = [];
|
||||
|
||||
if (days > 0) {
|
||||
parts.push(`${days}天`);
|
||||
}
|
||||
if (remainingHours > 0) {
|
||||
parts.push(`${remainingHours}小时`);
|
||||
}
|
||||
if (remainingMinutes > 0) {
|
||||
parts.push(`${remainingMinutes}分钟`);
|
||||
}
|
||||
if (remainingSeconds > 0) {
|
||||
parts.push(`${remainingSeconds}秒`);
|
||||
}
|
||||
|
||||
return parts.join(" ");
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取一小时后的时间戳
|
||||
* @returns 一周后的时间戳
|
||||
*/
|
||||
export const getHourLater = (): number => {
|
||||
const date = new Date();
|
||||
date.setHours(date.getHours() + 1);
|
||||
return date.getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取一天后的时间戳
|
||||
* @returns 一周后的时间戳
|
||||
*/
|
||||
export const getDayLater = (): number => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 1);
|
||||
return date.getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取一周后的时间戳
|
||||
* @returns 一周后的时间戳
|
||||
*/
|
||||
export const getWeekLater = (): number => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 7);
|
||||
return date.getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取一个月后的时间戳
|
||||
* @returns 一个月后的时间戳
|
||||
*/
|
||||
export const getMonthLater = (): number => {
|
||||
const date = new Date();
|
||||
date.setMonth(date.getMonth() + 1);
|
||||
return date.getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取一年后的时间戳
|
||||
* @returns 一年后的时间戳
|
||||
*/
|
||||
export const getYearLater = (): number => {
|
||||
const date = new Date();
|
||||
date.setFullYear(date.getFullYear() + 1);
|
||||
return date.getTime();
|
||||
};
|
||||
Reference in New Issue
Block a user