From 44243a6bb7cbc2d4bee70c2a79a2c2d252c5719d Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Fri, 7 Aug 2026 16:01:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E9=9F=B3=E9=A2=91=E5=BC=B9=E7=AA=97=E8=A7=86=E8=A7=89=20(#1257?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/package-lock.json | 102 +----------------- .../voices/components/UploadVoiceModal.tsx | 4 +- .../upload-voice-modal/ActionButtons.tsx | 38 +++---- .../upload-voice-modal/FileInfoCard.tsx | 37 ++++++- .../upload-voice-modal/FileUploadZone.tsx | 82 +++++++++++--- .../upload-voice-modal/FormFields.tsx | 37 +++++-- .../upload-voice-modal/UploadProgress.tsx | 27 +++-- 7 files changed, 167 insertions(+), 160 deletions(-) diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index f189ba94a..dbfb18f95 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -1845,27 +1845,6 @@ "react": "^18 || ^19" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", @@ -1935,14 +1914,6 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2009,14 +1980,14 @@ "version": "15.7.15", "resolved": "https://registry.npmmirror.com/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.31", "resolved": "https://registry.npmmirror.com/@types/react/-/react-18.3.31.tgz", "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3110,14 +3081,6 @@ "node": ">=6.0.0" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4028,18 +3991,6 @@ "node": ">= 4" } }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "optional": true, - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -4466,17 +4417,6 @@ "yallist": "^3.0.2" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -5008,44 +4948,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/proxy-from-env": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", diff --git a/apps/web/src/pages/voices/components/UploadVoiceModal.tsx b/apps/web/src/pages/voices/components/UploadVoiceModal.tsx index 58a051e17..3ee873418 100755 --- a/apps/web/src/pages/voices/components/UploadVoiceModal.tsx +++ b/apps/web/src/pages/voices/components/UploadVoiceModal.tsx @@ -28,7 +28,7 @@ const UploadVoiceModal: React.FC = ({ return ( 上传配音素材} open={open} onCancel={() => { if (uploading) return // 上传中不可关闭 @@ -43,7 +43,7 @@ const UploadVoiceModal: React.FC = ({ display: "flex", flexDirection: "column", gap: 16, - padding: "8px 0", + padding: "12px 0 4px", }} > {/* 拖拽上传区 */} diff --git a/apps/web/src/pages/voices/components/upload-voice-modal/ActionButtons.tsx b/apps/web/src/pages/voices/components/upload-voice-modal/ActionButtons.tsx index 99020e4a0..141398f3a 100755 --- a/apps/web/src/pages/voices/components/upload-voice-modal/ActionButtons.tsx +++ b/apps/web/src/pages/voices/components/upload-voice-modal/ActionButtons.tsx @@ -1,4 +1,5 @@ import React from "react" +import { Button } from "antd" interface ActionButtonsProps { uploading: boolean @@ -13,12 +14,6 @@ const ActionButtons: React.FC = ({ onCancel, onUpload, }) => { - const disabled = uploading || !canUpload - - const handleUpload = () => { - onUpload() - } - return (
= ({ paddingTop: 4, }} > - - + {uploading ? "上传中" : "开始上传"} +
) } diff --git a/apps/web/src/pages/voices/components/upload-voice-modal/FileInfoCard.tsx b/apps/web/src/pages/voices/components/upload-voice-modal/FileInfoCard.tsx index a48123dda..43b8b0b81 100755 --- a/apps/web/src/pages/voices/components/upload-voice-modal/FileInfoCard.tsx +++ b/apps/web/src/pages/voices/components/upload-voice-modal/FileInfoCard.tsx @@ -10,28 +10,55 @@ const FileInfoCard: React.FC = ({ file }) => { return (
- + {/* 文件图标圆形底托 */} +
+ +
+ + {/* 文件信息 */}
{file.name}
-
+
{formatFileSize(file.size)}
diff --git a/apps/web/src/pages/voices/components/upload-voice-modal/FileUploadZone.tsx b/apps/web/src/pages/voices/components/upload-voice-modal/FileUploadZone.tsx index 201be9b1b..70114eb16 100755 --- a/apps/web/src/pages/voices/components/upload-voice-modal/FileUploadZone.tsx +++ b/apps/web/src/pages/voices/components/upload-voice-modal/FileUploadZone.tsx @@ -14,6 +14,8 @@ const FileUploadZone: React.FC = ({ onFileSelect, onFileRemove, }) => { + const [isHovered, setIsHovered] = React.useState(false) + return ( = ({ showUploadList={false} disabled={disabled} > -

setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} > - -

-

点击或拖拽音频文件到此处

-

- 支持 MP3、WAV、AAC、FLAC 等格式,最大 {UPLOAD_CONFIG.maxSizeMB}MB -

+ {/* 图标圆形底托 */} +
+ +
+ + {/* 主文案 */} +

+ 点击或拖拽音频文件到此处 +

+ + {/* 副文案 */} +

+ 支持 MP3、WAV、AAC、FLAC 等格式,最大 {UPLOAD_CONFIG.maxSizeMB}MB +

+
) } diff --git a/apps/web/src/pages/voices/components/upload-voice-modal/FormFields.tsx b/apps/web/src/pages/voices/components/upload-voice-modal/FormFields.tsx index 38c6c44de..42c56322e 100755 --- a/apps/web/src/pages/voices/components/upload-voice-modal/FormFields.tsx +++ b/apps/web/src/pages/voices/components/upload-voice-modal/FormFields.tsx @@ -10,22 +10,32 @@ interface FormFieldsProps { } const labelStyle: React.CSSProperties = { - fontSize: 13, - color: "var(--text-secondary)", + fontSize: 12, + fontWeight: 600, + color: "var(--text-primary, #333)", marginBottom: 6, + letterSpacing: "0.02em", } -const inputStyle: React.CSSProperties = { +const baseInputStyle: React.CSSProperties = { width: "100%", - padding: "8px 12px", + padding: "10px 12px", border: "1px solid var(--border-color)", borderRadius: 8, fontSize: 13, background: "var(--bg-primary)", color: "var(--text-primary)", outline: "none", + transition: "border-color 0.2s ease, box-shadow 0.2s ease", + lineHeight: 1.5, } +const focusStyle: React.CSSProperties = { + borderColor: "var(--primary-color)", + boxShadow: "0 0 0 2px var(--primary-soft, rgba(22, 119, 255, 0.12))", +} + + const FormFields: React.FC = ({ name, desc, @@ -44,7 +54,14 @@ const FormFields: React.FC = ({ placeholder="输入配音名称" maxLength={UPLOAD_CONFIG.maxNameLength} disabled={disabled} - style={inputStyle} + style={baseInputStyle} + onFocus={(e) => { + Object.assign(e.target.style, focusStyle) + }} + onBlur={(e) => { + e.target.style.borderColor = "var(--border-color)" + e.target.style.boxShadow = "none" + }} />
@@ -59,9 +76,17 @@ const FormFields: React.FC = ({ rows={2} disabled={disabled} style={{ - ...inputStyle, + ...baseInputStyle, resize: "vertical", fontFamily: "inherit", + minHeight: 56, + }} + onFocus={(e) => { + Object.assign(e.target.style, focusStyle) + }} + onBlur={(e) => { + e.target.style.borderColor = "var(--border-color)" + e.target.style.boxShadow = "none" }} /> diff --git a/apps/web/src/pages/voices/components/upload-voice-modal/UploadProgress.tsx b/apps/web/src/pages/voices/components/upload-voice-modal/UploadProgress.tsx index 9f47c3aaa..fa29226ed 100755 --- a/apps/web/src/pages/voices/components/upload-voice-modal/UploadProgress.tsx +++ b/apps/web/src/pages/voices/components/upload-voice-modal/UploadProgress.tsx @@ -6,25 +6,40 @@ interface UploadProgressProps { const UploadProgress: React.FC = ({ progress }) => { return ( -
+
{progress}%
-
+
{progress < 100 ? "上传中..." : "处理中..."}
@@ -32,7 +47,7 @@ const UploadProgress: React.FC = ({ progress }) => { style={{ height: "100%", width: `${progress}%`, - background: "var(--primary-color)", + background: progress < 100 ? "var(--primary-color)" : "var(--success-color, #52c41a)", borderRadius: 2, transition: "width 0.3s ease", }}