Files
lingji-work-fe/src/utils/tools.ts

283 lines
7.6 KiB
TypeScript
Raw Normal View History

2025-06-27 18:37:42 +08:00
/*
* @Author: RenXiaoDong
* @Date: 2025-06-27 17:36:31
*/
import dayjs from 'dayjs';
2025-07-16 10:14:04 +08:00
2025-06-27 18:37:42 +08:00
export function toFixed(num: number | string, n: number): number {
return parseFloat(parseFloat(num.toString()).toFixed(n));
}
export function isNotData(n: number): boolean {
if (n === undefined) {
return true;
}
return n === -2147483648;
}
export function splitNumber(num: number): string | number {
if (!num) {
return num;
}
const parts = num.toString().split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return parts.join('.');
}
export function formatNumberShow(...args: any[]): string | number {
const [_args] = args;
const { value, len = 2, split = true, showExactValue = false } = typeof _args === 'object' ? _args : { value: _args };
const getNumber = (value: number) => {
return split ? splitNumber(value) : value;
};
if (isNotData(value)) {
return '-';
}
if (value < 0) {
return `-${formatNumberShow({
value: -value,
len,
split,
showExactValue,
})}`;
}
if (showExactValue) {
return getNumber(toFixed(value, len));
}
if (value < 10000) {
return getNumber(toFixed(value, len));
} else if (value < 100000000) {
const _n = Math.round((value / 10000) * 100) / 100;
return split ? `${splitNumber(_n)}w` : `${toFixed(_n, len)}w`;
} else {
const _n = Math.round((value / 100000000) * 100) / 100;
return split ? `${splitNumber(_n)}亿` : `${toFixed(_n, len)}亿`;
}
}
export function formatTableField(fieldItem: any, rowValue: any, showExactValue = false) {
// 获取嵌套属性值的函数
const getNestedValue = (obj: any, path: string) => {
if (!obj || !path) return undefined;
// 如果路径包含点号,说明是链式取值
if (path.includes('.')) {
return path.split('.').reduce((current, key) => {
return current && current[key] !== undefined ? current[key] : undefined;
}, obj);
}
// 普通属性取值
return obj[path];
};
const _getValue = (value: any) => {
2025-07-02 17:55:20 +08:00
if (!isNumber(value)) return value || '-';
return formatNumberShow({ value, showExactValue });
};
// 使用链式取值获取数据
const rawValue = getNestedValue(rowValue, fieldItem.dataIndex);
const value = _getValue(rawValue ?? '-');
return `${fieldItem.prefix || ''}${value}${fieldItem.suffix || ''}`;
}
2025-07-21 12:01:32 +08:00
export function exactFormatTime(val: number, curYearFmt = 'MM-DD HH:mm:ss', otherYearFmt = 'YYYY-MM-DD HH:mm:ss') {
if (!val) return '-';
const year = dayjs(val * 1000).year();
const currYear = dayjs().year();
const diff = year - currYear;
const fmt = diff === 0 ? curYearFmt : otherYearFmt;
return dayjs(val * 1000).format(fmt);
}
// 导出文件
export function downloadByUrl(url: string, filename?: string) {
const a = document.createElement('a');
a.href = url;
if (filename) {
a.download = filename;
}
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
2025-07-17 17:23:40 +08:00
2025-07-21 15:10:26 +08:00
export function genRandomId() {
return `id_${Date.now()}_${Math.floor(Math.random() * 10000)}`;
}
export function getImageMainColor(imageUrl: string): Promise<string> {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'Anonymous'; // 处理跨域图片
img.src = imageUrl;
img.onload = () => {
// 创建画布缩小图片尺寸以提高性能
const canvas = document.createElement('canvas');
const maxDimension = 100; // 最大尺寸为100px
let width = img.width;
let height = img.height;
// 按比例缩小图片
if (width > height) {
if (width > maxDimension) {
height *= maxDimension / width;
width = maxDimension;
}
} else {
if (height > maxDimension) {
width *= maxDimension / height;
height = maxDimension;
}
}
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
if (!ctx) {
reject(new Error('Canvas context not available'));
return;
}
// 绘制缩小后的图片
ctx.drawImage(img, 0, 0, width, height);
// 获取图片数据
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
// 使用中位数切分法提取主色调
const colorGroups = medianCut(data, 8); // 分成8组
// 找出最大的颜色组
let maxGroup = colorGroups[0];
for (let i = 1; i < colorGroups.length; i++) {
if (colorGroups[i].count > maxGroup.count) {
maxGroup = colorGroups[i];
}
}
// 计算组内平均颜色
const avgColor = {
r: Math.round(maxGroup.sumR / maxGroup.count),
g: Math.round(maxGroup.sumG / maxGroup.count),
b: Math.round(maxGroup.sumB / maxGroup.count)
};
resolve(`rgb(${avgColor.r},${avgColor.g},${avgColor.b})`);
};
img.onerror = () => {
reject(new Error('Failed to load image'));
};
});
}
/**
*
* @param data
* @param levels
* @returns
*/
function medianCut(data: Uint8ClampedArray, levels: number): any[] {
const colors = [];
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
const a = data[i + 3];
// 跳过透明像素
if (a < 128) continue;
colors.push({
r, g, b,
count: 1,
sumR: r, sumG: g, sumB: b
});
}
// 如果没有颜色数据,返回默认白色
if (colors.length === 0) {
return [{
count: 1,
sumR: 255, sumG: 255, sumB: 255
}];
}
// 开始中位数切分
let colorGroups = [{
colors,
count: colors.length,
sumR: colors.reduce((sum, c) => sum + c.r, 0),
sumG: colors.reduce((sum, c) => sum + c.g, 0),
sumB: colors.reduce((sum, c) => sum + c.b, 0)
}];
for (let i = 0; i < levels; i++) {
const newGroups = [];
for (const group of colorGroups) {
if (group.colors.length <= 1) {
newGroups.push(group);
continue;
}
// 找出颜色范围最大的通道
const rMin = Math.min(...group.colors.map(c => c.r));
const rMax = Math.max(...group.colors.map(c => c.r));
const gMin = Math.min(...group.colors.map(c => c.g));
const gMax = Math.max(...group.colors.map(c => c.g));
const bMin = Math.min(...group.colors.map(c => c.b));
const bMax = Math.max(...group.colors.map(c => c.b));
const rRange = rMax - rMin;
const gRange = gMax - gMin;
const bRange = bMax - bMin;
let sortChannel = 'r';
if (gRange > rRange && gRange > bRange) {
sortChannel = 'g';
} else if (bRange > rRange && bRange > gRange) {
sortChannel = 'b';
}
// 按最大范围通道排序
group.colors.sort((a, b) => a[sortChannel] - b[sortChannel]);
// 切分中位数
const mid = Math.floor(group.colors.length / 2);
const group1 = group.colors.slice(0, mid);
const group2 = group.colors.slice(mid);
// 添加新组
newGroups.push({
colors: group1,
count: group1.length,
sumR: group1.reduce((sum, c) => sum + c.r, 0),
sumG: group1.reduce((sum, c) => sum + c.g, 0),
sumB: group1.reduce((sum, c) => sum + c.b, 0)
});
newGroups.push({
colors: group2,
count: group2.length,
sumR: group2.reduce((sum, c) => sum + c.r, 0),
sumG: group2.reduce((sum, c) => sum + c.g, 0),
sumB: group2.reduce((sum, c) => sum + c.b, 0)
});
}
colorGroups = newGroups;
}
return colorGroups;
}