后台 3D 定价两栏底价输入改为描述表驱动

- apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx:抽出 VERSION_PRICE_FIELDS 描述表,无贴图 / 带贴图两栏共用一段 JSX,字段键与展示名只有一处来源,避免两栏后续改动走偏
This commit is contained in:
2026-09-24 17:20:42 +08:00
parent 84c5129225
commit 62e6bfc52f
@@ -1,4 +1,7 @@
import type { EditorGenerationModel3dPricingPayload } from '../api/adminApiTypes';
import type {
EditorGenerationModel3dPricingPayload,
EditorGenerationModel3dVersionPricePayload,
} from '../api/adminApiTypes';
import {
EDITOR_MODEL3D_ENDPOINT_SECTIONS,
editorModel3dAddOnLabel,
@@ -6,6 +9,18 @@ import {
updateEditorModel3dEndpointPricing,
} from './adminEditorGenerationPricing';
/**
* 一个模型版本的两个底价字段。两栏只有字段键与展示名不同,用描述表驱动渲染,
* 避免两段近乎相同的 JSX 各自演化。
*/
const VERSION_PRICE_FIELDS = [
{ key: 'noTexture', label: '无贴图' },
{ key: 'texture', label: '带贴图' },
] as const satisfies ReadonlyArray<{
key: keyof EditorGenerationModel3dVersionPricePayload;
label: string;
}>;
interface AdminEditorGenerationModel3dPricingSectionProps {
model3d: EditorGenerationModel3dPricingPayload;
onChange: (next: EditorGenerationModel3dPricingPayload) => void;
@@ -51,54 +66,34 @@ export function AdminEditorGenerationModel3dPricingSection({
<span className="admin-pricing-model3d-row-label">
{version}
</span>
<label className="admin-field">
<span></span>
<input
aria-label={`${label} ${version} 无贴图`}
min={1}
step={1}
type="number"
value={price.noTexture}
onChange={(event) =>
updateEndpoint(key, (current) => ({
...current,
versionPrices: {
...current.versionPrices,
[version]: {
...price,
noTexture: parsePositiveInteger(
event.target.value,
),
},
},
}))
}
/>
</label>
<label className="admin-field">
<span></span>
<input
aria-label={`${label} ${version} 带贴图`}
min={1}
step={1}
type="number"
value={price.texture}
onChange={(event) =>
updateEndpoint(key, (current) => ({
...current,
versionPrices: {
...current.versionPrices,
[version]: {
...price,
texture: parsePositiveInteger(
event.target.value,
),
},
},
}))
}
/>
</label>
{VERSION_PRICE_FIELDS.map(
({ key: field, label: fieldLabel }) => (
<label className="admin-field" key={field}>
<span>{fieldLabel}</span>
<input
aria-label={`${label} ${version} ${fieldLabel}`}
min={1}
step={1}
type="number"
value={price[field]}
onChange={(event) =>
updateEndpoint(key, (current) => ({
...current,
versionPrices: {
...current.versionPrices,
[version]: {
...price,
[field]: parsePositiveInteger(
event.target.value,
),
},
},
}))
}
/>
</label>
),
)}
</div>
),
)}