fix: 上传音频弹窗修复4个问题
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 33s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 56s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 1m6s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m34s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m40s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 1m27s
AI Code Review / AI Code Review (pull_request) Successful in 2m9s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 1m46s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m24s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m49s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Failing after 962h0m37s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 962h1m11s
CI/CD Pipeline / PR Build API Image (pull_request) Failing after 962h0m39s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 962h1m11s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 962h0m41s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 962h1m15s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 962h1m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 962h1m13s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 962h34m30s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 962h34m34s

1. 去掉音色性别选择 - 上传的是真实配音素材,不需要选择性别
2. 弹窗标题改为'上传配音素材',表单标签改为'配音名称'/'配音描述'
3. 上传错误提示优化 - 502时显示'服务器暂时不可用'
4. 上传成功后弹窗自动关闭(原逻辑已正确,确认无误)

涉及文件:
- useVoiceUpload.ts: 移除gender状态/参数,优化错误提示
- UploadVoiceModal.tsx: 移除gender props,更新标题
- FormFields.tsx: 删除性别选择区域,更新标签文案
- types.ts: 移除GENDER_OPTIONS和gender类型
- VoiceModals.tsx: 移除gender相关props透传
- VoiceLibrary.tsx: 移除gender相关状态传递
This commit is contained in:
xiaoxia
2026-08-07 13:25:48 +08:00
parent 6c70056a12
commit c6b3b86522
6 changed files with 17 additions and 74 deletions
@@ -117,11 +117,9 @@ const VoiceLibrary: React.FC = () => {
uploadOpen,
uploadFile,
uploadName,
uploadGender,
uploadDesc,
uploadProgress,
setUploadName,
setUploadGender,
setUploadDesc,
setUploadOpen,
handleFileSelect,
@@ -252,14 +250,12 @@ const VoiceLibrary: React.FC = () => {
uploadOpen={uploadOpen}
uploadFile={uploadFile}
uploadName={uploadName}
uploadGender={uploadGender}
uploadDesc={uploadDesc}
uploadProgress={uploadProgress}
onUploadClose={handleUploadClose}
onFileSelect={handleFileSelect}
onFileRemove={handleFileRemove}
onNameChange={setUploadName}
onGenderChange={setUploadGender}
onDescChange={setUploadDesc}
onUpload={handleUpload}
ttsOpen={ttsOpen}
@@ -14,14 +14,12 @@ const UploadVoiceModal: React.FC<UploadVoiceModalProps> = ({
open,
uploadFile,
uploadName,
uploadGender,
uploadDesc,
uploadProgress,
onClose,
onFileSelect,
onFileRemove,
onNameChange,
onGenderChange,
onDescChange,
onUpload,
}) => {
@@ -30,7 +28,7 @@ const UploadVoiceModal: React.FC<UploadVoiceModalProps> = ({
return (
<Modal
title="上传音频"
title="上传配音素材"
open={open}
onCancel={() => {
if (uploading) return // 上传中不可关闭
@@ -64,11 +62,9 @@ const UploadVoiceModal: React.FC<UploadVoiceModalProps> = ({
{/* 表单字段 */}
<FormFields
name={uploadName}
gender={uploadGender}
desc={uploadDesc}
disabled={uploading}
onNameChange={onNameChange}
onGenderChange={onGenderChange}
onDescChange={onDescChange}
/>
@@ -2,7 +2,7 @@
* VoiceLibrary 弹窗集合
*/
import React from "react"
import type { ClonedVoiceDisplay, PresetVoiceDisplay, VoiceGender } from "../types"
import type { ClonedVoiceDisplay, PresetVoiceDisplay } from "../types"
import type { VoiceClone } from "@/api/voice-clone"
import type { TtsStatus } from "./TtsModal"
import CloneModal from "@/components/voice/CloneModal"
@@ -27,14 +27,12 @@ export interface VoiceModalsProps {
uploadOpen: boolean
uploadFile: File | null
uploadName: string
uploadGender: VoiceGender
uploadDesc: string
uploadProgress: number | null
onUploadClose: () => void
onFileSelect: (file: File) => void
onFileRemove: () => void
onNameChange: (name: string) => void
onGenderChange: (gender: VoiceGender) => void
onDescChange: (desc: string) => void
onUpload: () => void
@@ -67,14 +65,12 @@ export const VoiceModals: React.FC<VoiceModalsProps> = ({
uploadOpen,
uploadFile,
uploadName,
uploadGender,
uploadDesc,
uploadProgress,
onUploadClose,
onFileSelect,
onFileRemove,
onNameChange,
onGenderChange,
onDescChange,
onUpload,
ttsOpen,
@@ -113,14 +109,12 @@ export const VoiceModals: React.FC<VoiceModalsProps> = ({
open={uploadOpen}
uploadFile={uploadFile}
uploadName={uploadName}
uploadGender={uploadGender}
uploadDesc={uploadDesc}
uploadProgress={uploadProgress}
onClose={onUploadClose}
onFileSelect={onFileSelect}
onFileRemove={onFileRemove}
onNameChange={onNameChange}
onGenderChange={onGenderChange}
onDescChange={onDescChange}
onUpload={onUpload}
/>
@@ -1,14 +1,11 @@
import React from "react"
import type { VoiceGender } from "@/pages/voices/types"
import { GENDER_OPTIONS, UPLOAD_CONFIG } from "./types"
import { UPLOAD_CONFIG } from "./types"
interface FormFieldsProps {
name: string
gender: VoiceGender
desc: string
disabled: boolean
onNameChange: (name: string) => void
onGenderChange: (gender: VoiceGender) => void
onDescChange: (desc: string) => void
}
@@ -31,64 +28,33 @@ const inputStyle: React.CSSProperties = {
const FormFields: React.FC<FormFieldsProps> = ({
name,
gender,
desc,
disabled,
onNameChange,
onGenderChange,
onDescChange,
}) => {
return (
<>
{/* 名称 */}
<div>
<div style={labelStyle}>素材名称</div>
<div style={labelStyle}>配音名称</div>
<input
value={name}
onChange={(e) => onNameChange(e.target.value)}
placeholder="输入素材名称"
placeholder="输入配音名称"
maxLength={UPLOAD_CONFIG.maxNameLength}
disabled={disabled}
style={inputStyle}
/>
</div>
{/* 性别选择 */}
<div>
<div style={labelStyle}>音色性别</div>
<div style={{ display: "flex", gap: 8 }}>
{GENDER_OPTIONS.map((opt) => (
<button
key={opt.value}
type="button"
onClick={() => onGenderChange(opt.value)}
disabled={disabled}
style={{
flex: 1,
padding: "6px 0",
borderRadius: 8,
border: `1px solid ${gender === opt.value ? "var(--primary-color)" : "var(--border-color)"}`,
background: gender === opt.value ? "var(--primary-soft)" : "transparent",
color: gender === opt.value ? "var(--primary-color)" : "var(--text-secondary)",
fontSize: 13,
fontWeight: gender === opt.value ? 600 : 400,
cursor: disabled ? "not-allowed" : "pointer",
transition: "all 0.2s",
}}
>
{opt.label}
</button>
))}
</div>
</div>
{/* 描述 */}
<div>
<div style={labelStyle}>音色描述(可选)</div>
<div style={labelStyle}>配音描述(可选)</div>
<textarea
value={desc}
onChange={(e) => onDescChange(e.target.value)}
placeholder="描述这个音色的特点..."
placeholder="描述这段配音的内容..."
maxLength={UPLOAD_CONFIG.maxDescLength}
rows={2}
disabled={disabled}
@@ -1,27 +1,18 @@
import type { VoiceGender } from "@/pages/voices/types"
export interface UploadVoiceModalProps {
open: boolean
uploadFile: File | null
uploadName: string
uploadGender: VoiceGender
uploadDesc: string
uploadProgress: number | null
onClose: () => void
onFileSelect: (file: File) => void
onFileRemove: () => void
onNameChange: (name: string) => void
onGenderChange: (gender: VoiceGender) => void
onDescChange: (desc: string) => void
onUpload: () => void
}
export const GENDER_OPTIONS: { value: VoiceGender; label: string }[] = [
{ value: "female", label: "女声" },
{ value: "male", label: "男声" },
{ value: "child", label: "童声" },
]
export const UPLOAD_CONFIG = {
maxSizeMB: 200,
maxNameLength: 100,
@@ -1,6 +1,5 @@
import { useState, useCallback } from "react"
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { type VoiceGender } from "../types"
import { uploadAssetDirect, getAssetLibraries, createAsset } from "@/api/assets"
import { getAudioDuration } from "../utils/audio"
import { buildVoiceMetadata } from "../types"
@@ -19,7 +18,6 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
const [uploadOpen, setUploadOpen] = useState(false)
const [uploadFile, setUploadFile] = useState<File | null>(null)
const [uploadName, setUploadName] = useState("")
const [uploadGender, setUploadGender] = useState<VoiceGender>("female")
const [uploadDesc, setUploadDesc] = useState("")
const [uploadProgress, setUploadProgress] = useState<number | null>(null)
@@ -27,7 +25,6 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
mutationFn: async (data: {
file: File
name: string
gender: VoiceGender
description: string
}) => {
setUploadProgress(0)
@@ -57,7 +54,6 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
storage_key,
mime_type: data.file.type || "audio/mpeg",
metadata: buildVoiceMetadata({
gender: data.gender,
description: data.description,
duration,
}),
@@ -71,8 +67,15 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
showToast("上传成功", "success")
handleUploadClose()
},
onError: (err: Error) => {
showToast(err.message || "上传失败,请重试", "error")
onError: (err: Error & { response?: { status?: number } }) => {
const status = err?.response?.status
let msg = "上传失败,请重试"
if (status && status >= 500) {
msg = "服务器暂时不可用,请稍后重试"
} else if (err?.message) {
msg = err.message
}
showToast(msg, "error")
},
})
@@ -102,10 +105,9 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
uploadMutation.mutate({
file: uploadFile,
name: uploadName.trim(),
gender: uploadGender,
description: uploadDesc.trim(),
})
}, [uploadFile, uploadName, uploadGender, uploadDesc, uploadMutation])
}, [uploadFile, uploadName, uploadDesc, uploadMutation])
return {
// 弹窗状态
@@ -114,13 +116,11 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
// 表单状态
uploadFile,
uploadName,
uploadGender,
uploadDesc,
uploadProgress,
isUploading: uploadMutation.isPending,
// Setters
setUploadName,
setUploadGender,
setUploadDesc,
// Handlers
handleFileSelect,