feat: improve application access and money precision
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
export async function copyText(text: string) {
|
||||
if (!text) throw new Error('没有可复制的内容');
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return;
|
||||
} catch {
|
||||
// HTTP deployments and restrictive browser policies may reject Clipboard API.
|
||||
}
|
||||
}
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.setAttribute('readonly', '');
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.left = '-9999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
textarea.setSelectionRange(0, textarea.value.length);
|
||||
const copied = document.execCommand('copy');
|
||||
textarea.remove();
|
||||
if (!copied) throw new Error('浏览器未允许写入剪贴板,请手工选择参数复制');
|
||||
}
|
||||
+21
-3
@@ -1,14 +1,32 @@
|
||||
export const MONEY_UNITS_PER_YUAN = 10_000;
|
||||
|
||||
export function formatAmount(value: number) {
|
||||
return value.toLocaleString('zh-CN', {
|
||||
minimumFractionDigits: 3,
|
||||
maximumFractionDigits: 3,
|
||||
minimumFractionDigits: 4,
|
||||
maximumFractionDigits: 4,
|
||||
});
|
||||
}
|
||||
|
||||
export function formatCents(cents?: number | null) {
|
||||
return formatAmount((cents ?? 0) / 100);
|
||||
return formatAmount((cents ?? 0) / MONEY_UNITS_PER_YUAN);
|
||||
}
|
||||
|
||||
export function formatYuan(cents?: number | null) {
|
||||
return `¥${formatCents(cents)}`;
|
||||
}
|
||||
|
||||
export function yuanToMoneyUnits(value: number | string | null | undefined) {
|
||||
const amount = typeof value === 'string' ? Number(value) : (value ?? 0);
|
||||
return Math.round(amount * MONEY_UNITS_PER_YUAN);
|
||||
}
|
||||
|
||||
export function isValidMoneyInput(value: string, options: { allowNegative?: boolean; allowZero?: boolean } = {}) {
|
||||
const normalized = value.trim();
|
||||
const pattern = options.allowNegative ? /^-?\d+(?:\.\d{1,4})?$/ : /^\d+(?:\.\d{1,4})?$/;
|
||||
if (!pattern.test(normalized)) return false;
|
||||
return options.allowZero !== false || Number(normalized) !== 0;
|
||||
}
|
||||
|
||||
export function moneyUnitsToYuan(value?: number | null) {
|
||||
return (value ?? 0) / MONEY_UNITS_PER_YUAN;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { HttpApiConfigResponse } from '@/api/adminApi';
|
||||
|
||||
const capabilityLabels = [
|
||||
['sendEnabled', '单条发送'],
|
||||
['messageQueryEnabled', '状态查询'],
|
||||
['uplinkQueryEnabled', '上行查询'],
|
||||
['receiptWebhookEnabled', '回执回调'],
|
||||
['uplinkWebhookEnabled', '上行回调'],
|
||||
] as const;
|
||||
|
||||
export function formatHttpApiParams(response: HttpApiConfigResponse, origin: string) {
|
||||
const config = response.config;
|
||||
const baseUrl = `${origin.replace(/\/$/, '')}/api/openapi/v1`;
|
||||
return [
|
||||
`应用名称: ${response.applicationName ?? response.applicationId}`,
|
||||
`HTTP接口: ${config?.enabled ? '开通' : '关闭'}`,
|
||||
`基础地址: ${baseUrl}`,
|
||||
`接口文档: ${origin.replace(/\/$/, '')}/api/client-docs`,
|
||||
`接口能力: ${capabilityLabels.filter(([key]) => config?.[key]).map(([, label]) => label).join('、') || '无'}`,
|
||||
`QPS限制: ${config?.qpsLimit ?? '-'}`,
|
||||
`签名时间容差: ${config?.timestampToleranceSeconds ?? '-'}秒`,
|
||||
`HTTP IP白名单: ${response.ipAllowlist.join('、') || '未限制'}`,
|
||||
`回执投递方式: ${config?.receiptDeliveryMode ?? '-'}`,
|
||||
`上行投递方式: ${config?.uplinkDeliveryMode ?? '-'}`,
|
||||
].join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user