feat:更新core 和首页代码
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 展示层格式化(无 i18n 框架依赖,供 UI / Canvas 文案使用)
|
||||
*/
|
||||
|
||||
/** 适龄文案,如 3-5岁 */
|
||||
export function formatAgeRangeLabel(minAge: number, maxAge: number): string {
|
||||
return `${minAge}-${maxAge}岁`;
|
||||
}
|
||||
|
||||
/** 比较符号(全角,与现有比大小题型一致) */
|
||||
export function formatCompareSymbol(
|
||||
relation: 'gt' | 'lt' | 'eq',
|
||||
): '>' | '<' | '=' {
|
||||
switch (relation) {
|
||||
case 'gt':
|
||||
return '>';
|
||||
case 'lt':
|
||||
return '<';
|
||||
default:
|
||||
return '=';
|
||||
}
|
||||
}
|
||||
|
||||
/** 数字左侧补零,如 padLeadingZero(3, 2) => "03" */
|
||||
export function padLeadingZero(num: number, width: number): string {
|
||||
const s = String(Math.trunc(Math.abs(num)));
|
||||
if (s.length >= width) return num < 0 ? `-${s}` : s;
|
||||
const pad = '0'.repeat(width - s.length);
|
||||
return num < 0 ? `-${pad}${s}` : `${pad}${s}`;
|
||||
}
|
||||
|
||||
/** 截断过长字符串 */
|
||||
export function truncateText(
|
||||
text: string,
|
||||
maxChars: number,
|
||||
ellipsis = '…',
|
||||
): string {
|
||||
if (text.length <= maxChars) return text;
|
||||
const cut = Math.max(0, maxChars - ellipsis.length);
|
||||
return text.slice(0, cut) + ellipsis;
|
||||
}
|
||||
|
||||
/** 非负整数千分位(中文场景常用逗号或空格,此处用半角逗号) */
|
||||
export function formatThousands(n: number): string {
|
||||
const i = Math.trunc(n);
|
||||
if (i < 0) return `-${formatThousands(-i)}`;
|
||||
return String(i).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 纯数学工具(无随机、无平台依赖),供 generators / 模板引擎使用
|
||||
*/
|
||||
|
||||
/** 将数值限制在 [min, max] */
|
||||
export function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
/** 最大公约数(非负整数) */
|
||||
export function gcd(a: number, b: number): number {
|
||||
let x = Math.abs(Math.trunc(a));
|
||||
let y = Math.abs(Math.trunc(b));
|
||||
while (y !== 0) {
|
||||
const t = y;
|
||||
y = x % y;
|
||||
x = t;
|
||||
}
|
||||
return x || 1;
|
||||
}
|
||||
|
||||
/** 最小公倍数 */
|
||||
export function lcm(a: number, b: number): number {
|
||||
const g = gcd(a, b);
|
||||
return Math.abs(Math.trunc(a) * Math.trunc(b)) / g;
|
||||
}
|
||||
|
||||
/** 闭区间 [min, max] 上的整数列表 */
|
||||
export function integerRangeInclusive(min: number, max: number): number[] {
|
||||
const lo = Math.min(min, max);
|
||||
const hi = Math.max(min, max);
|
||||
const out: number[] = [];
|
||||
for (let i = lo; i <= hi; i += 1) {
|
||||
out.push(i);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 数组求和 */
|
||||
export function sum(numbers: readonly number[]): number {
|
||||
let s = 0;
|
||||
for (let i = 0; i < numbers.length; i += 1) {
|
||||
s += numbers[i];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/** 算术平均(空数组为 0) */
|
||||
export function mean(numbers: readonly number[]): number {
|
||||
if (numbers.length === 0) return 0;
|
||||
return sum(numbers) / numbers.length;
|
||||
}
|
||||
|
||||
/** 各位数字之和(十进制,忽略负号) */
|
||||
export function digitSum(n: number): number {
|
||||
let v = Math.abs(Math.trunc(n));
|
||||
let s = 0;
|
||||
while (v > 0) {
|
||||
s += v % 10;
|
||||
v = Math.floor(v / 10);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
export function isEven(n: number): boolean {
|
||||
return n % 2 === 0;
|
||||
}
|
||||
|
||||
export function isOdd(n: number): boolean {
|
||||
return !isEven(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将浮点数舍入到指定小数位(避免 0.1+0.2 展示问题)
|
||||
*/
|
||||
export function roundToDecimals(value: number, decimals: number): number {
|
||||
const p = 10 ** decimals;
|
||||
return Math.round(value * p) / p;
|
||||
}
|
||||
@@ -13,11 +13,20 @@ export function randomPick<T>(arr: T[]): T {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数组中随机选取 n 个不重复元素
|
||||
* 从数组中随机选取 n 个不重复元素(Fisher-Yates,无 sort 偏置)
|
||||
*/
|
||||
export function randomPickN<T>(arr: T[], n: number): T[] {
|
||||
const shuffled = [...arr].sort(() => Math.random() - 0.5);
|
||||
return shuffled.slice(0, Math.min(n, arr.length));
|
||||
export function randomPickN<T>(arr: readonly T[], n: number): T[] {
|
||||
return sampleWithoutReplacement(arr, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* 无放回抽样,不改变入参数组
|
||||
*/
|
||||
export function sampleWithoutReplacement<T>(
|
||||
arr: readonly T[],
|
||||
n: number,
|
||||
): T[] {
|
||||
return shuffle([...arr]).slice(0, Math.min(n, arr.length));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user