Files
moc/src/utils/common.ts
T
2026-09-23 15:24:49 +08:00

272 lines
6.9 KiB
TypeScript

import { $t } from '@/locales';
/**
* Transform record to option
*
* @example
* ```ts
* const record = {
* key1: 'label1',
* key2: 'label2'
* };
* const options = transformRecordToOption(record);
* // [
* // { value: 'key1', label: 'label1' },
* // { value: 'key2', label: 'label2' }
* // ]
* ```;
*
* @param record
*/
export function transformRecordToOption<T extends Record<string, string>>(record: T) {
return Object.entries(record).map(([value, label]) => ({
value,
label
})) as CommonType.Option<keyof T, T[keyof T]>[];
}
/**
* Translate options
*
* @param options
*/
export function translateOptions(options: CommonType.Option<string, App.I18n.I18nKey>[]) {
return options.map(option => ({
...option,
label: $t(option.label)
}));
}
/**
* Toggle html class
*
* @param className
*/
export function toggleHtmlClass(className: string) {
function add() {
document.documentElement.classList.add(className);
}
function remove() {
document.documentElement.classList.remove(className);
}
return {
add,
remove
};
}
// 辅助函数:将 hex 转为 rgba
export function hexToRgba(hex: string, alpha: number) {
// 去掉 # 号
hex = hex.replace('#', '');
// 处理缩写形式 #RGB
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
export const getColorWithOpacity = (color: string, opacity: number) => {
// 如果 color 本身已经是 rgba 或 hsl 等,可自行扩展判断
// 这里仅处理 hex
return hexToRgba(color, opacity);
};
// 时间戳转换成年月日时分秒
export function formatTimestamp(timestamp: number | string | Date | null,format: string = 'yyyy-MM-dd HH:mm:ss') {
if(!timestamp) {
return '';
}
const date = new Date(Number(timestamp));
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
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');
if(format === 'yyyy-MM-dd') {
return `${year}-${month}-${day}`;
}
if(format === 'yyyy-MM-dd HH:mm') {
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
/**
* 任意时间格式 → 时间戳(支持 只有小时)
* @param {string|number|Date} input
* @param {'ms'|'s'} unit 默认毫秒
*/
export function anyToTimestamp(input: string | number | Date | null | undefined, unit = 'ms') {
if (input == null || input === '') return null;
const toResult = (ms: number) =>
Number.isNaN(ms) ? null : unit === 's' ? Math.floor(ms / 1000) : ms;
// 1. 数字
if (typeof input === 'number') return toResult(input);
// 2. Date
if (input instanceof Date) return toResult(input.getTime());
let str = String(input).trim();
// 3. 纯数字字符串
if (/^\d+$/.test(str)) return toResult(Number(str));
// 4. 统一分隔符
str = str
.replace(/[年月]/g, '-')
.replace(/[日号]/g, '')
.replace(/[时分]/g, ':')
.replace(/秒/g, '')
.replace(/[./]/g, '-')
.replace(/\s+/g, ' ')
.trim();
// 5. 手动解析:小时、分钟、秒、毫秒全部可选
const m = str.match(
/^(\d{4})-(\d{1,2})-(\d{1,2})(?:[ T](\d{1,2}))?(?::(\d{1,2}))?(?::(\d{1,2}))?(?:\.(\d{1,3}))?/
);
if (m) {
const [, y, mo, d, h = '0', mi = '0', s = '0', ms = '0'] = m;
const t = new Date(
+y,
+mo - 1,
+d,
+h,
+mi,
+s,
+ms.padEnd(3, '0')
).getTime();
if (!Number.isNaN(t)) return toResult(t);
}
// 6. 兜底
let t = new Date(str.replace(' ', 'T')).getTime();
if (!Number.isNaN(t)) return toResult(t);
t = Date.parse(str);
if (!Number.isNaN(t)) return toResult(t);
return null;
};
// 辅助函数:Fisher-Yates 洗牌算法
function shuffle(arr:any) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
// 辅助函数:从字符串中随机获取字符
function getRandomChar(str:any) {
return str[Math.floor(Math.random() * str.length)];
}
// 生成至少12位,包含四类字符中的至少三种的随机密码
export function generateSecurePassword(passwordLength:number) {
// 定义字符池
const charSets:any = {
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
lowercase: 'abcdefghijklmnopqrstuvwxyz',
numbers: '0123456789',
symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?'
};
// 随机选择三种字符类型(保证至少三类)
const requiredTypes = shuffle(Object.keys(charSets)).slice(0, 3);
// 生成必选字符(每类至少1个)
let password = requiredTypes
.map((type:any) => getRandomChar(charSets[type]))
.join('');
// 生成剩余字符(允许包含所有四类)
const remainingLength = passwordLength - password.length;
const allChars = Object.values(charSets).join('');
for (let i = 0; i < remainingLength; i++) {
password += getRandomChar(allChars);
}
// 打乱字符顺序
return shuffle(password.split('')).join('');
}
// 根据当前时间,获取指定的时间范围(返回时间戳)
export function getTimeRangeStamp(timeRange: string){
const endTime = anyToTimestamp(new Date());
if(!endTime) {
return null;
}
// 近7天
if(timeRange === 'week'){
return {
from: endTime - (7 * 24 * 60 * 60 * 1000),
to: endTime
}
}
// 近一个月
if(timeRange === 'month'){
return {
from: endTime - (30 * 24 * 60 * 60 * 1000),
to: endTime
}
}
// 近三个月
if(timeRange === 'quarter'){
return {
from: endTime - (90 * 24 * 60 * 60 * 1000),
to: endTime
}
}
// 近半年
if(timeRange === 'half_year'){
return {
from: endTime - (180 * 24 * 60 * 60 * 1000),
to: endTime
}
}
// 近一年
if(timeRange === 'year'){
return {
from: endTime - (365 * 24 * 60 * 60 * 1000),
to: endTime
}
}
}
// 下载文件
export function downloadFileFun(url: string, name: string) {
const a = document.createElement('a');
a.href = url;
a.download = name;
a.style.display = 'none';
document.body.appendChild(a)
a.click()
document.body.removeChild(a);
}
// 获取 token
export const getToken = () => {
return localStorage.getItem('token');
};
// tag自定义样式颜色
// 文字颜色
export const tagTextColor = (color: string) => {
return color || '#333';
}
// 背景颜色
export const tagBgColor = (color: string) => {
return getColorWithOpacity((color || '#333'), 0.08);
}
// 边框颜色
export const tagBorderColor = (color: string) => {
return getColorWithOpacity((color || '#333'), 0.3);
}