Files
mayfly-go/frontend/src/common/utils/string.ts

257 lines
7.6 KiB
TypeScript
Raw Normal View History

2026-05-19 21:25:28 +08:00
import { Msg } from '@/hooks/useI18n';
import { i18n } from '@/i18n';
import { v1 as uuidv1 } from 'uuid';
/**
* template = 'hahaha{name}_{id}' ,param = {name: 'hh', id: 1}
* hahahahh_1
* @param template
* @param param
* @returns
*/
export function templateResolve(template: string, param: any) {
return template.replace(/\{\w+\}/g, (word) => {
const key = word.substring(1, word.length - 1);
2025-09-06 21:32:48 +08:00
let value;
// 兼容FormData类型的参数
if (param instanceof FormData) {
value = param.get(key);
} else {
value = param[key];
}
if (value != null || value != undefined) {
return value;
}
return '';
});
}
2021-06-09 16:58:57 +08:00
// 首字符头像
export function letterAvatar(name: string, size = 60, color = '') {
name = name || '';
size = size || 60;
var colours = [
'#1abc9c',
'#2ecc71',
'#3498db',
'#9b59b6',
'#34495e',
'#16a085',
'#27ae60',
'#2980b9',
'#8e44ad',
'#2c3e50',
'#f1c40f',
'#e67e22',
'#e74c3c',
'#00bcd4',
'#95a5a6',
'#f39c12',
'#d35400',
'#c0392b',
'#bdc3c7',
'#7f8c8d',
],
nameSplit = String(name).split(' '),
initials,
charIndex,
colourIndex,
canvas,
context,
dataURI;
2021-06-09 16:58:57 +08:00
if (nameSplit.length == 1) {
initials = nameSplit[0] ? nameSplit[0].charAt(0) : '?';
} else {
initials = nameSplit[0].charAt(0) + nameSplit[1].charAt(0);
}
if (window.devicePixelRatio) {
size = size * window.devicePixelRatio;
}
initials = initials.toLocaleUpperCase();
charIndex = (initials == '?' ? 72 : initials.charCodeAt(0)) - 64;
colourIndex = charIndex % 20;
canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
context = canvas.getContext('2d') as any;
context.fillStyle = color ? color : colours[colourIndex - 1];
context.fillRect(0, 0, canvas.width, canvas.height);
context.font = Math.round(canvas.width / 2) + "px 'Microsoft Yahei'";
context.textAlign = 'center';
context.fillStyle = '#FFF';
context.fillText(initials, size / 2, size / 1.5);
dataURI = canvas.toDataURL();
canvas = null;
return dataURI;
}
/**
* px ->
* 使span标签包裹内容span的宽度 width px
* @param str
*/
export function getTextWidth(str: string) {
let width = 0;
let html = document.createElement('span');
html.innerText = str;
html.className = 'getTextWidth';
document?.querySelector('body')?.appendChild(html);
width = (document?.querySelector('.getTextWidth') as any).offsetWidth;
document?.querySelector('.getTextWidth')?.remove();
return width;
}
/**
*
* @returns uuid
*/
export function randomUuid() {
return uuidv1();
}
2026-05-19 21:25:28 +08:00
/**
*
* @returns Promise<string>
* @throws Error 访
*/
export async function pasteFromClipboard(): Promise<string> {
// navigator clipboard 需要https等安全上下文
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard 从剪贴板读文本
try {
const text = await navigator.clipboard.readText();
return text;
} catch (e: any) {
throw new Error(i18n.global.t('common.pasteFailed'));
}
}
// 非安全上下文HTTP 环境),无法读取剪贴板
throw new Error(i18n.global.t('common.pasteNotSupported'));
}
/**
*
* @param txt
*/
2026-05-19 21:25:28 +08:00
export async function copyToClipboard(txt: string) {
// navigator clipboard 需要https等安全上下文
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard 向剪贴板写文本
try {
await navigator.clipboard.writeText(txt);
2026-05-19 21:25:28 +08:00
Msg.success('common.copySuccess');
} catch (e: any) {
2026-05-19 21:25:28 +08:00
Msg.error('common.copyFailed');
}
return;
}
2026-05-19 21:25:28 +08:00
// 非安全上下文HTTP 环境),无法使用 Clipboard API
// 降级方案:创建临时 textarea 并使用 execCommand('copy')
try {
const textarea = document.createElement('textarea');
textarea.value = txt;
textarea.style.position = 'fixed';
textarea.style.left = '-9999px';
textarea.style.top = '-9999px';
document.body.appendChild(textarea);
textarea.focus();
textarea.select();
const success = document.execCommand('copy');
document.body.removeChild(textarea);
if (success) {
Msg.success('common.copySuccess');
} else {
Msg.error('common.copyFailed');
}
} catch (e: any) {
Msg.error('common.copyNotSupported');
}
}
export function fuzzyMatchField(keyword: string, fields: any[], ...valueExtractFuncs: Function[]) {
keyword = keyword?.toLowerCase();
return fields.filter((field) => {
for (let valueExtractFunc of valueExtractFuncs) {
const value = valueExtractFunc(field)?.toLowerCase();
if (isPrefixSubsequence(keyword, value)) {
return true;
}
}
return false;
});
}
/**
* targetTemplate=username prefix=uname -> trueprefix=uname2 -> false
* @param prefix ,
* @param targetTemplate
* @returns
*/
export function isPrefixSubsequence(prefix: string, targetTemplate: string) {
let i = 0; // 指向prefix的索引
let j = 0; // 指向targetTemplate的索引
while (i < prefix.length && j < targetTemplate.length) {
if (prefix[i] === targetTemplate[j]) {
// 字符匹配,两个指针都向前移动
i++;
}
j++; // 目标字符串指针始终向前移动
}
// 如果prefix的所有字符都被找到返回true
return i === prefix.length;
}
2024-11-20 22:43:53 +08:00
/**
*
* @param length
*/
export function randomPassword(length = 10) {
const lowerCase = 'abcdefghijklmnopqrstuvwxyz';
const upperCase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';
const specialChars = '!@#$%^&*()-_=+[]{}|;:,.<>?';
// 确保每个类别至少包含一个字符
let password = [getRandomChar(lowerCase), getRandomChar(upperCase), getRandomChar(numbers), getRandomChar(specialChars)];
// 剩余字符从所有字符集中随机选择
const allChars = lowerCase + upperCase + numbers + specialChars;
for (let i = 4; i < length; i++) {
password.push(getRandomChar(allChars));
}
// 打乱数组顺序以增加随机性
shuffleArray(password);
return password.join('');
}
export function randomString(length = 8) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < length; i++) {
result += getRandomChar(chars);
}
return result;
}
2024-11-20 22:43:53 +08:00
function getRandomChar(charSet: string) {
const randomIndex = Math.floor(Math.random() * charSet.length);
return charSet[randomIndex];
}
function shuffleArray(array: string[]) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}