diff --git a/apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx b/apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx index 9530bd7e1..748b3900c 100644 --- a/apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx +++ b/apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx @@ -5,9 +5,9 @@ import type { import { EDITOR_MODEL3D_ENDPOINT_SECTIONS, editorModel3dAddOnLabel, - parsePositiveInteger, updateEditorModel3dEndpointPricing, } from './adminEditorGenerationPricing'; +import { parsePositiveInteger } from './pageUtils'; /** * 一个模型版本的两个底价字段。两栏只有字段键与展示名不同,用描述表驱动渲染, diff --git a/apps/admin-web/src/pages/AdminEditorGenerationPricingPage.tsx b/apps/admin-web/src/pages/AdminEditorGenerationPricingPage.tsx index 2733688cd..14633d578 100644 --- a/apps/admin-web/src/pages/AdminEditorGenerationPricingPage.tsx +++ b/apps/admin-web/src/pages/AdminEditorGenerationPricingPage.tsx @@ -17,9 +17,8 @@ import { AdminEditorGenerationModel3dPricingSection } from './AdminEditorGenerat import { buildAdminEditorGenerationPricingRequest, collectInvalidEditorGenerationPricingLabels, - parsePositiveInteger, } from './adminEditorGenerationPricing'; -import { handlePageError } from './pageUtils'; +import { handlePageError, parsePositiveInteger } from './pageUtils'; interface AdminEditorGenerationPricingPageProps { token: string; diff --git a/apps/admin-web/src/pages/AdminProfileWalletConfigPage.tsx b/apps/admin-web/src/pages/AdminProfileWalletConfigPage.tsx index bfc01d5f0..c6f2ffa56 100644 --- a/apps/admin-web/src/pages/AdminProfileWalletConfigPage.tsx +++ b/apps/admin-web/src/pages/AdminProfileWalletConfigPage.tsx @@ -7,7 +7,7 @@ import { } from '../api/adminApiClient'; import type { ProfileWalletConfigAdminResponse } from '../api/adminApiTypes'; import { useAdminWriteConfirm } from '../components/useAdminWriteConfirm'; -import { handlePageError } from './pageUtils'; +import { handlePageError, parsePositiveInteger } from './pageUtils'; interface AdminProfileWalletConfigPageProps { token: string; @@ -197,8 +197,3 @@ export function AdminProfileWalletConfigPage({ ); } - -function parsePositiveInteger(value: string) { - const parsed = Number(value); - return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 0; -} diff --git a/apps/admin-web/src/pages/AdminRechargeProductPage.tsx b/apps/admin-web/src/pages/AdminRechargeProductPage.tsx index 67eb38b88..3e2d06551 100644 --- a/apps/admin-web/src/pages/AdminRechargeProductPage.tsx +++ b/apps/admin-web/src/pages/AdminRechargeProductPage.tsx @@ -11,7 +11,7 @@ import type { ProfileRechargeProductKind, } from '../api/adminApiTypes'; import { useAdminWriteConfirm } from '../components/useAdminWriteConfirm'; -import { handlePageError } from './pageUtils'; +import { handlePageError, parsePositiveInteger } from './pageUtils'; interface AdminRechargeProductPageProps { token: string; @@ -546,11 +546,6 @@ function formatPrice(priceCents: number) { return `¥${(priceCents / 100).toFixed(2)}`; } -function parsePositiveInteger(value: string) { - const parsed = parseInteger(value); - return parsed > 0 ? parsed : 0; -} - function parseNonNegativeInteger(value: string) { const parsed = parseInteger(value); return parsed > 0 ? parsed : 0; diff --git a/apps/admin-web/src/pages/AdminRedeemCodePage.tsx b/apps/admin-web/src/pages/AdminRedeemCodePage.tsx index 1519bb867..6c586fb28 100644 --- a/apps/admin-web/src/pages/AdminRedeemCodePage.tsx +++ b/apps/admin-web/src/pages/AdminRedeemCodePage.tsx @@ -12,7 +12,7 @@ import type { ProfileRedeemCodeMode, } from '../api/adminApiTypes'; import { useAdminWriteConfirm } from '../components/useAdminWriteConfirm'; -import { handlePageError, splitLines } from './pageUtils'; +import { handlePageError, parsePositiveInteger, splitLines } from './pageUtils'; interface AdminRedeemCodePageProps { token: string; @@ -422,11 +422,6 @@ export function AdminRedeemCodePage({ ); } -function parsePositiveInteger(value: string) { - const parsed = Number.parseInt(value, 10); - return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; -} - function redeemModeLabel(value: ProfileRedeemCodeMode) { return redeemModes.find((item) => item.value === value)?.label ?? value; } diff --git a/apps/admin-web/src/pages/AdminTaskConfigPage.tsx b/apps/admin-web/src/pages/AdminTaskConfigPage.tsx index 33026ce0a..febcbeced 100644 --- a/apps/admin-web/src/pages/AdminTaskConfigPage.tsx +++ b/apps/admin-web/src/pages/AdminTaskConfigPage.tsx @@ -19,7 +19,7 @@ import { filterAdminTrackingEventKeyOptions, findAdminTrackingEventDefinition, } from '../config/trackingEventDefinitions'; -import { handlePageError } from './pageUtils'; +import { handlePageError, parsePositiveInteger } from './pageUtils'; interface AdminTaskConfigPageProps { token: string; @@ -571,11 +571,6 @@ export function AdminTaskConfigPage({ ); } -function parsePositiveInteger(value: string) { - const parsed = Number.parseInt(value, 10); - return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; -} - function parseInteger(value: string) { const parsed = Number.parseInt(value, 10); return Number.isFinite(parsed) ? parsed : 0; diff --git a/apps/admin-web/src/pages/adminEditorGenerationPricing.test.ts b/apps/admin-web/src/pages/adminEditorGenerationPricing.test.ts index f0b62b7e2..028136244 100644 --- a/apps/admin-web/src/pages/adminEditorGenerationPricing.test.ts +++ b/apps/admin-web/src/pages/adminEditorGenerationPricing.test.ts @@ -5,8 +5,8 @@ import { buildAdminEditorGenerationPricingRequest, collectInvalidEditorGenerationPricingLabels, editorModel3dAddOnLabel, - parsePositiveInteger, } from './adminEditorGenerationPricing'; +import { parsePositiveInteger } from './pageUtils'; function pricingFixture(): EditorGenerationPricingConfigPayload { return { diff --git a/apps/admin-web/src/pages/adminEditorGenerationPricing.ts b/apps/admin-web/src/pages/adminEditorGenerationPricing.ts index 69f0b0054..b25f4c777 100644 --- a/apps/admin-web/src/pages/adminEditorGenerationPricing.ts +++ b/apps/admin-web/src/pages/adminEditorGenerationPricing.ts @@ -31,14 +31,6 @@ export function editorModel3dAddOnLabel(addOn: string) { return EDITOR_MODEL3D_ADD_ON_LABELS[addOn] ?? addOn; } -/** 输入框文本转整数;空串、非数字、小数、0 与负数一律收敛成 0,交给提交前校验拦住。 */ -export function parsePositiveInteger(value: string) { - // 用 Number 而不是 parseInt:parseInt 会把 `3.9` 截成 3、`12abc` 截成 12, - // 等于把编辑中的半截输入静默当成合法值存下去。 - const parsed = Number(value); - return Number.isInteger(parsed) && parsed > 0 ? parsed : 0; -} - export function isPositiveMudPoints(value: number | null | undefined) { return typeof value === 'number' && Number.isInteger(value) && value >= 1; } diff --git a/apps/admin-web/src/pages/pageUtils.ts b/apps/admin-web/src/pages/pageUtils.ts index bea44fd7e..51a61cd3d 100644 --- a/apps/admin-web/src/pages/pageUtils.ts +++ b/apps/admin-web/src/pages/pageUtils.ts @@ -1,5 +1,18 @@ import { formatAdminApiError, isAdminApiError } from '../api/adminApiClient'; +/** + * 泥点 / 积分类输入框文本转正整数:空串、非数字、小数、0 与负数一律收敛成 0, + * 由各页的提交前校验拦住。 + * + * 用 `Number` 而不是 `parseInt`:`parseInt` 会把 `3.9` 截成 3、`12abc` 截成 12, + * 等于把编辑中的半截输入静默当成合法值存下去;再用 `isSafeInteger` 挡掉超出安全整数 + * 范围的值(那种值在别处会被静默改写)。后台各页统一用这一份,不再各写一遍。 + */ +export function parsePositiveInteger(value: string) { + const parsed = Number(value); + return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : 0; +} + export function handlePageError( error: unknown, onUnauthorized: (message?: string) => void,