From 60c28c229756cc1609e253c889bd3e5fbb70eba2 Mon Sep 17 00:00:00 2001 From: wuxichen <17301714657@163.com> Date: Sat, 27 Sep 2025 15:14:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- pnpm-lock.yaml | 44 +++++++++----- projects/translate-h5/package.json | 1 - projects/translate-h5/src/api/translate.ts | 40 +++++++++++++ .../translate-h5/src/http/axios-instance.ts | 60 ++++++++++--------- .../home/translate/component/voice/index.tsx | 28 ++++++++- projects/translate-h5/vite.config.ts | 10 +++- 7 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 projects/translate-h5/src/api/translate.ts diff --git a/package.json b/package.json index 86ee127..74ee95e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "dev:translate-h5": "pnpm --filter translate-h5 dev", "build:translate-h5": "pnpm --filter translate-h5 build", "dev": "vite", - "dev:https": "vite --https", "build": "tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" @@ -34,6 +33,7 @@ "react-router-dom": "^6.20.0", "react-slick": "^0.29.0", "slick-carousel": "^1.8.1", + "vconsole": "^3.15.1", "weixin-js-sdk": "^1.6.5", "zustand": "^4.4.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2e33840..d0469c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: slick-carousel: specifier: ^1.8.1 version: 1.8.1(jquery@3.7.1) + vconsole: + specifier: ^3.15.1 + version: 3.15.1 weixin-js-sdk: specifier: ^1.6.5 version: 1.6.5 @@ -616,67 +619,56 @@ packages: resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.50.0': resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.50.0': resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.50.0': resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.50.0': resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.50.0': resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.50.0': resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.50.0': resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.50.0': resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.50.0': resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.50.0': resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openharmony-arm64@4.50.0': resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==} @@ -721,28 +713,24 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [glibc] '@swc/core-linux-arm64-musl@1.13.5': resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - libc: [musl] '@swc/core-linux-x64-gnu@1.13.5': resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [glibc] '@swc/core-linux-x64-musl@1.13.5': resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==} engines: {node: '>=10'} cpu: [x64] os: [linux] - libc: [musl] '@swc/core-win32-arm64-msvc@1.13.5': resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==} @@ -1151,6 +1139,13 @@ packages: copy-anything@2.0.6: resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + copy-text-to-clipboard@3.2.2: + resolution: {integrity: sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==} + engines: {node: '>=12'} + + core-js@3.45.1: + resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==} + cosmiconfig@6.0.0: resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} engines: {node: '>=8'} @@ -1857,6 +1852,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mutation-observer@1.0.3: + resolution: {integrity: sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==} + nano-memoize@3.0.16: resolution: {integrity: sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==} @@ -2359,6 +2357,9 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + vconsole@3.15.1: + resolution: {integrity: sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==} + vite-plugin-checker@0.8.0: resolution: {integrity: sha512-UA5uzOGm97UvZRTdZHiQVYFnd86AVn8EVaD4L3PoVzxH+IZSfaAw14WGFwX9QS23UW3lV/5bVKZn6l0w+q9P0g==} engines: {node: '>=14.16'} @@ -3594,6 +3595,10 @@ snapshots: dependencies: is-what: 3.14.1 + copy-text-to-clipboard@3.2.2: {} + + core-js@3.45.1: {} + cosmiconfig@6.0.0: dependencies: '@types/parse-json': 4.0.2 @@ -4344,6 +4349,8 @@ snapshots: ms@2.1.3: {} + mutation-observer@1.0.3: {} + nano-memoize@3.0.16: {} nanoid@3.3.11: {} @@ -4837,6 +4844,13 @@ snapshots: dependencies: react: 18.3.1 + vconsole@3.15.1: + dependencies: + '@babel/runtime': 7.28.3 + copy-text-to-clipboard: 3.2.2 + core-js: 3.45.1 + mutation-observer: 1.0.3 + vite-plugin-checker@0.8.0(eslint@9.34.0)(optionator@0.9.4)(typescript@5.9.2)(vite@6.3.5(@types/node@20.19.12)(less@4.4.1)(terser@5.44.0)): dependencies: '@babel/code-frame': 7.27.1 diff --git a/projects/translate-h5/package.json b/projects/translate-h5/package.json index f4d9164..3798f00 100644 --- a/projects/translate-h5/package.json +++ b/projects/translate-h5/package.json @@ -4,7 +4,6 @@ "type": "module", "scripts": { "dev": "vite", - "dev:https": "vite --https", "build": "tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" diff --git a/projects/translate-h5/src/api/translate.ts b/projects/translate-h5/src/api/translate.ts new file mode 100644 index 0000000..ac54f64 --- /dev/null +++ b/projects/translate-h5/src/api/translate.ts @@ -0,0 +1,40 @@ +import useAxios from "axios-hooks"; +import { Page, Result } from "@/types/http"; + +export interface MockResult { + id: number; +} + +export interface MockPage { + id: number; +} + +/** + * fetch the data + * 详细使用可以查看 useAxios 的文档 + */ +export const useUploadAudio = () => { + const url = `/app-api/ai/sample/translate`; + + const [{ data, loading, error }, execute] = useAxios>( + { + url, + method: "POST", + headers: { + "Content-Type": "multipart/form-data", + }, + }, + { manual: true } // 手动触发 + ); + + const uploadAudio = (formData: FormData) => { + return execute({ + data: formData, + headers: { + "Content-Type": "multipart/form-data", + }, + }); + }; + + return { data, loading, error, uploadAudio }; +}; diff --git a/projects/translate-h5/src/http/axios-instance.ts b/projects/translate-h5/src/http/axios-instance.ts index 2bef525..b28dd2e 100644 --- a/projects/translate-h5/src/http/axios-instance.ts +++ b/projects/translate-h5/src/http/axios-instance.ts @@ -1,49 +1,51 @@ import Axios, { - AxiosError, - AxiosInstance as AxiosType, - AxiosResponse, - InternalAxiosRequestConfig -} from 'axios'; -import {STORAGE_AUTHORIZE_KEY} from "@/composables/authorization.ts"; + AxiosError, + AxiosInstance as AxiosType, + AxiosResponse, + InternalAxiosRequestConfig, +} from "axios"; +import { STORAGE_AUTHORIZE_KEY } from "@/composables/authorization.ts"; export interface ResponseBody { - code: number; - data?: T; - msg: string; + code: number; + data?: T; + msg: string; } -async function requestHandler(config: InternalAxiosRequestConfig): Promise { - const token = localStorage.getItem(STORAGE_AUTHORIZE_KEY); - if (token) { - config.headers[STORAGE_AUTHORIZE_KEY] = token; - } - return config; +async function requestHandler( + config: InternalAxiosRequestConfig +): Promise { + const token = localStorage.getItem(STORAGE_AUTHORIZE_KEY); + if (token) { + config.headers[STORAGE_AUTHORIZE_KEY] = token; + } + return config; } function responseHandler(response: AxiosResponse): AxiosResponse { - // 响应拦截器逻辑... - return response; + // 响应拦截器逻辑... + return response; } function errorHandler(error: AxiosError): Promise> { - // 错误处理逻辑... - return Promise.reject(error); + // 错误处理逻辑... + return Promise.reject(error); } class AxiosInstance { - private readonly instance: AxiosType; + private readonly instance: AxiosType; - constructor(baseURL: string) { - this.instance = Axios.create({baseURL}); + constructor(baseURL: string) { + this.instance = Axios.create({ baseURL }); - this.instance.interceptors.request.use(requestHandler, errorHandler); - this.instance.interceptors.response.use(responseHandler, errorHandler); - } + this.instance.interceptors.request.use(requestHandler, errorHandler); + this.instance.interceptors.response.use(responseHandler, errorHandler); + } - public getInstance(): AxiosType { - return this.instance; - } + public getInstance(): AxiosType { + return this.instance; + } } -const baseURL = import.meta.env.VITE_BASE_URL || 'http://127.0.0.1:8080'; +const baseURL = import.meta.env.VITE_BASE_URL || "http://192.168.1.231:48080"; export const axiosInstance = new AxiosInstance(baseURL).getInstance(); diff --git a/projects/translate-h5/src/view/home/translate/component/voice/index.tsx b/projects/translate-h5/src/view/home/translate/component/voice/index.tsx index 218ed3b..6dc83e8 100644 --- a/projects/translate-h5/src/view/home/translate/component/voice/index.tsx +++ b/projects/translate-h5/src/view/home/translate/component/voice/index.tsx @@ -5,7 +5,8 @@ import microphoneSvg from "@/assets/translate/microphone.svg"; import microphoneDisabledSvg from "@/assets/translate/microphoneDisabledSvg.svg"; import { createStartRecordSound, createSendSound } from "@/utils/voice"; import "./index.less"; - +import { useUploadAudio } from "@/api/translate"; +import VConsole from "vconsole"; interface DefinedProps { onRecordingComplete: (url: string, finalDuration: number) => void; isRecording: boolean; @@ -13,6 +14,7 @@ interface DefinedProps { } function Index(props: DefinedProps) { const { isRecording } = props; + const { loading: uploadLoading, error: uploadError, uploadAudio } = useUploadAudio(); const [hasPermission, setHasPermission] = useState(false); //是否有权限 const [isPermissioning, setIsPermissioning] = useState(true); //获取权限中 const [recordingDuration, setRecordingDuration] = useState(0); //录音时长进度 @@ -23,6 +25,12 @@ function Index(props: DefinedProps) { // 音效相关 const sendSoundRef = useRef(null); const startRecordSoundRef = useRef(null); + useEffect(() => { + // 只在开发环境启用 + if (process.env.NODE_ENV === "development") { + new VConsole(); + } + }, []); useEffect(() => { initializeSounds(); checkMicrophonePermission(); @@ -59,7 +67,17 @@ function Index(props: DefinedProps) { console.error("音效初始化失败:", error); } }; + const handleUploadAudio = async (formData: FormData) => { + // 打印FormData内容 + console.log(formData); + try { + const response = await uploadAudio(formData); + console.log("上传成功:", response.data); + } catch (error) { + console.error("上传失败:", error); + } + }; const renderBtn = useCallback(() => { if (!hasPermission) { //没有权限 @@ -210,7 +228,7 @@ function Index(props: DefinedProps) { //录音完成 // 在发送时检查录音时长 const onRecordingComplete = useCallback( - (blob: Blob) => { + async (blob: Blob) => { if (isCancelledRef.current) { Toast.show("已取消"); return; @@ -221,6 +239,10 @@ function Index(props: DefinedProps) { return; } + const formData = new FormData(); + formData.append("file", blob); + + await handleUploadAudio(formData); const audioUrl = URL.createObjectURL(blob); const audio = new Audio(); audio.src = audioUrl; @@ -231,7 +253,7 @@ function Index(props: DefinedProps) { Toast.show("录音时间太短,请重新录音"); return; } - alert(audio.duration); + // alert(audio.duration); playSound(sendSoundRef); props.onRecordingComplete?.(audioUrl, Math.floor(audio.duration)); }); diff --git a/projects/translate-h5/vite.config.ts b/projects/translate-h5/vite.config.ts index 83aa847..3d393c7 100644 --- a/projects/translate-h5/vite.config.ts +++ b/projects/translate-h5/vite.config.ts @@ -4,12 +4,18 @@ import path, { resolve } from "path"; import { inspectorServer } from "@react-dev-inspector/vite-plugin"; import basicSsl from "@vitejs/plugin-basic-ssl"; export default defineConfig({ - plugins: [react(), basicSsl()], + // basicSsl() + plugins: [react()], server: { - https: {}, port: 3000, host: "0.0.0.0", open: true, + proxy: { + "/app-api": { + target: "http://192.168.1.231:48080", + changeOrigin: true, + }, + }, }, css: { modules: {},