Files
Genarrative/src/components/image-editor/ImageCanvasEditGenerationModalView.tsx
T
JenkenB 7830d201c4 Server-side billing for editor generation
Move editor generation pricing to backend: remove priceMudPoints from public request schemas and docs, require backend to compute model prices and perform pre-charge via execute_billable_asset_operation_with_cost. Update character animation and video handlers to use authenticated owner IDs and wrap generation requests in billing; remove client-side price validation. Adjust OpenAPI, project-memory docs, pricing management docs, and related tests to reflect that front-end only displays prices and must not submit priceMudPoints. Also document new user registration reward and wallet refund outbox behavior. Code and test changes applied across api-server handlers, shared contracts, and image-editor client/tests.
2026-06-22 23:11:23 +08:00

111 lines
3.7 KiB
TypeScript

import { type Dispatch, type SetStateAction } from 'react';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformTextField } from '../common/PlatformTextField';
import { UnifiedModal } from '../common/UnifiedModal';
import {
calculateEditorImageGenerationPrice,
IMAGE_MODEL_GPT_IMAGE_2,
} from './ImageCanvasGenerationModel';
import type { GenerateDialogState } from './ImageCanvasEditorTypes';
type ImageCanvasEditGenerationModalViewProps = {
dialog: GenerateDialogState | null;
setGenerateDialog: Dispatch<SetStateAction<GenerateDialogState | null>>;
onSubmit: (dialog: GenerateDialogState) => void;
};
export function ImageCanvasEditGenerationModalView({
dialog,
setGenerateDialog,
onSubmit,
}: ImageCanvasEditGenerationModalViewProps) {
const isOpen = dialog?.mode === 'edit' && dialog.status !== 'generating';
const editPrice = calculateEditorImageGenerationPrice({
kind: 'quick-edit',
model: IMAGE_MODEL_GPT_IMAGE_2,
imageSize: '1K',
});
return (
<UnifiedModal
open={isOpen}
title={dialog?.mode === 'edit' ? '修改图片' : '生成图片'}
size="sm"
closeLabel={dialog?.mode === 'edit' ? '关闭修改图片' : '关闭生成图片'}
closeDisabled={dialog?.status === 'generating'}
onClose={() => setGenerateDialog(null)}
panelClassName="image-canvas-editor__generate-dialog"
bodyClassName="image-canvas-editor__generate-dialog-body"
>
{dialog?.mode === 'edit' ? (
<form
className="image-canvas-editor__generate-form"
onSubmit={(event) => {
event.preventDefault();
if (dialog.status !== 'generating') {
onSubmit(dialog);
}
}}
>
<div className="image-canvas-editor__generate-body">
<PlatformTextField
variant="textarea"
aria-label="生成提示词"
value={dialog.prompt}
disabled={dialog.status === 'generating'}
size="sm"
density="roomy"
className="image-canvas-editor__generate-prompt"
placeholder="描述你想如何修改这张图片"
onChange={(event) =>
setGenerateDialog((currentDialog) =>
currentDialog
? {
...currentDialog,
prompt: event.target.value,
}
: currentDialog,
)
}
/>
{dialog.status === 'generating' ? (
<PlatformStatusMessage
tone="info"
surface="platform"
size="xs"
className="image-canvas-editor__generate-status"
role="status"
>
修改中
</PlatformStatusMessage>
) : null}
{dialog.status === 'failed' ? (
<PlatformStatusMessage
tone="error"
surface="platform"
size="xs"
className="image-canvas-editor__generate-status"
role="alert"
>
{dialog.errorMessage}
</PlatformStatusMessage>
) : null}
<PlatformActionButton
type="submit"
size="sm"
className="image-canvas-editor__generate-submit"
disabled={dialog.status === 'generating'}
>
{dialog.status === 'generating'
? '修改中'
: `修改${editPrice}泥点`}
</PlatformActionButton>
</div>
</form>
) : null}
</UnifiedModal>
);
}