diff --git a/public/logo.png b/public/logo.png index 13be521..10373bd 100644 Binary files a/public/logo.png and b/public/logo.png differ diff --git a/src/App.js b/src/App.js index fc1b609..9b7cbe5 100644 --- a/src/App.js +++ b/src/App.js @@ -1,12 +1,32 @@ import { useEffect } from 'react'; import { Routes, Route, Navigate, useNavigate } from 'react-router-dom' import { useDispatch } from 'react-redux' +import { createTheme, ThemeProvider } from '@mui/material/styles'; import { setAccessToken, setUserInfo, setSelectInfo } from "./business/userSlice.js" import { useCookies } from 'react-cookie'; import LoginPage from './LoginPage'; import MainPage from './MainPage'; import yzs from "./business/request.js"; +const theme = createTheme({ + status: { + danger: '#e53e3e', + }, + palette: { + primary: { + main: '#FF595A', + darker: '#FF595A', + }, + neutral: { + main: '#64748B', + contrastText: '#fff', + }, + black: { + main: "#222222", + } + }, +}); + function App() { const dispatch = useDispatch(); const navigate = useNavigate(); @@ -32,10 +52,12 @@ function App() { return (
- - : } /> - } /> - + + + : } /> + } /> + +
); } diff --git a/src/AppBar.js b/src/AppBar.js index fe55427..96160c6 100644 --- a/src/AppBar.js +++ b/src/AppBar.js @@ -9,7 +9,7 @@ import MenuItem from '@mui/material/MenuItem'; import IconButton from '@mui/material/IconButton'; import Toolbar from '@mui/material/Toolbar'; import Typography from '@mui/material/Typography'; -import logo from './assets/logo.png'; +import appbar_logo from './assets/appbar_logo.png'; import { Stack, CssBaseline } from '@mui/material'; import { useCookies } from 'react-cookie'; import { useNavigate } from "react-router-dom"; @@ -40,11 +40,11 @@ export default function () { - - + 纽曼AI语记 diff --git a/src/LoginPage.js b/src/LoginPage.js index 36033c9..0a0adcb 100644 --- a/src/LoginPage.js +++ b/src/LoginPage.js @@ -16,23 +16,6 @@ import TabContext from '@mui/lab/TabContext'; import DynamicCodeForm from './components/DynamicCodeForm.js'; import PasswordForm from './components/PasswordForm.js'; import { useCookies } from 'react-cookie'; -import { createTheme, ThemeProvider } from '@mui/material/styles'; - -const theme = createTheme({ - status: { - danger: '#e53e3e', - }, - palette: { - primary: { - main: '#FF595A', - darker: '#FF595A', - }, - neutral: { - main: '#64748B', - contrastText: '#fff', - }, - }, -}); export default function () { const navigate = useNavigate(); @@ -116,48 +99,45 @@ export default function () {

纽曼AI语记

-
- - - - - - - - - + }} + > + + + + + + + - - - - - - - - - + + + + + + + + {/* */}
blob.text() - ).then(text => { - // console.log("type", record.type, text); - let payload = null; - if (record.type === 1 || record.type === 3) { - payload = JSON.parse(text) - } else { - payload = text; - } - store.dispatch(setCurrentLyric(payload)); - }); - } - - yzs.download(accessToken, record.audioUrl).then(blob => { - store.dispatch(setCurrentBlob(URL.createObjectURL(blob))); - }); -} - const ClickHanlde = styled('div', { shouldForwardProp: (prop) => prop !== 'open' })( ({ theme, open }) => ({ width: 18, @@ -105,15 +65,43 @@ const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })( }), ); -const RecordPlayer = ({ loading, playerBarWidth, currentTime, hasLyric, currentLyric }) => { +const LyricItem = ({ empty, hasLyric, lyricsBrowserStyle, currentLyric, currentTime }) => { + if (empty) { + return
+
+ + 这里空空如也,添加些东西吧 +
+
+ } else { + return hasLyric ? : +
+ } +} + +const RecordPlayer = ({ loading, empty, playerBarWidth, currentTime, hasLyric, currentLyric }) => { if (loading) { - return + return theme.zIndex.drawer + 1, + // marginLeft: "240px", + marginTop: "45px", + }} + open > + + } else { return
- - {hasLyric ? : -
} + +
} }; @@ -135,7 +123,7 @@ export default function () { yzs.get_record_list(accessToken, passportId).then(list => { dispatch(setList(list)); if (list.length > 0) { - fetchRecord(accessToken, list.at(0)); + dispatch(fetchRecord(accessToken, 0, list.at(0))); } }).catch(error => { console.log("get list failed", error); @@ -156,7 +144,7 @@ export default function () { } const handleResize = () => { - // console.log("innerWidth", document.documentElement.clientWidth, document.documentElement.clientWidth - (open ? 240 : 0) - 48) + // let scrollBarWidth = window.innerWidth - document.documentElement.clientWidth; setPlayerBarWidth(document.documentElement.clientWidth - (open ? 240 : 0) - 48); } @@ -172,20 +160,20 @@ export default function () { }; }, []); - useEffect(() => { handleResize(); }, [currentLyric]); + useEffect(() => { + if (!loading) handleResize(); + }, [loading]); return - - - - - -
- -
-
+ + + + +
+ +
} \ No newline at end of file diff --git a/src/MainSkeleton.js b/src/MainSkeleton.js deleted file mode 100644 index 4a34c4d..0000000 --- a/src/MainSkeleton.js +++ /dev/null @@ -1,34 +0,0 @@ -import Stack from '@mui/material/Stack'; -import Box from '@mui/material/Box'; -import Skeleton from '@mui/material/Skeleton'; -import { Container } from '@mui/material'; - -export default function () { - return ( - - - - - - - {/* For variant="text", adjust the height via font-size */} - - {/* For other variants, adjust the size with `width` and `height` */} - - - - - ); -} \ No newline at end of file diff --git a/src/PlayerBar.js b/src/PlayerBar.js index fd96309..11492e6 100644 --- a/src/PlayerBar.js +++ b/src/PlayerBar.js @@ -5,7 +5,7 @@ import pauseIcon from "./assets/play.png"; import playIcon from "./assets/pause.png"; import downloadIcon from "./assets/download.png"; import { setCurrentTime, setPauseState, togglePauseState, setCurrentWaveData } from "./business/recorderSlice.js" -import { audioWaveData, sampleInterval } from "./business/utilities" +import { audioWaveData, sampleInterval, exportRecordLyric } from "./business/utilities" import ProgressBar from "./components/ProgressBar"; const durationFormat = (time) => { @@ -17,7 +17,7 @@ const durationFormat = (time) => { return hour.toString().padStart(2, '0') + ":" + minute.toString().padStart(2, '0') + ":" + second.toString().padStart(2, '0'); } -export default function ({ width, currentTime }) { +export default function ({ width, lyric, currentTime }) { const dispatch = useDispatch(); const [duration, setDuration] = useState(0); // 秒,有小数点 const [playbackRate, setPlaybackRate] = useState(1.0); @@ -54,6 +54,7 @@ export default function ({ width, currentTime }) { link.href = currentBlob; link.download = recordList.at(currentIndex).name; link.click(); + exportRecordLyric(recordList.at(currentIndex).type, lyric, recordList.at(currentIndex).editName + ".txt"); }; const onDurationChange = (event) => { @@ -86,7 +87,7 @@ export default function ({ width, currentTime }) { display: "flex", alignItems: "center", }}> - {recordList.length > 0 ? recordList.at(currentIndex).editName : ""} + {recordList.length > 0 ? recordList.at(currentIndex).editName : "暂无内容"} diff --git a/src/RecordLyrics.js b/src/RecordLyrics.js index e591507..224a2f9 100644 --- a/src/RecordLyrics.js +++ b/src/RecordLyrics.js @@ -13,10 +13,12 @@ function isHighlight(currentTime, { start, end }) { // type: 3 --> 双语对话 const PlainText = ({ lyrics }) => { + if (typeof lyrics !== "string") return ; return
{lyrics}
} const ImportAudio = ({ lyrics, currentTime }) => { // 导入音频 + if (typeof lyrics !== "object") return ; const onClick = (index) => { console.log("onClick", index); } @@ -29,6 +31,7 @@ const ImportAudio = ({ lyrics, currentTime }) => { // 导入音频 }; const BilingualDialogue = ({ lyrics }) => { // 双语对话 + if (typeof lyrics !== "object") return ; return
{lyrics.map((lyric, index) => { return
{lyric.asr} diff --git a/src/assets/appbar_logo.png b/src/assets/appbar_logo.png new file mode 100644 index 0000000..10373bd Binary files /dev/null and b/src/assets/appbar_logo.png differ diff --git a/src/assets/empty_hint.png b/src/assets/empty_hint.png new file mode 100644 index 0000000..9248aec Binary files /dev/null and b/src/assets/empty_hint.png differ diff --git a/src/assets/logo.png b/src/assets/logo.png index 13be521..e0e300d 100644 Binary files a/src/assets/logo.png and b/src/assets/logo.png differ diff --git a/src/assets/logo@2x.png b/src/assets/logo@2x.png index 902c038..c03468d 100644 Binary files a/src/assets/logo@2x.png and b/src/assets/logo@2x.png differ diff --git a/src/business/recorderSlice.js b/src/business/recorderSlice.js index 436e0aa..a8ba5de 100644 --- a/src/business/recorderSlice.js +++ b/src/business/recorderSlice.js @@ -1,4 +1,5 @@ import { createSlice } from '@reduxjs/toolkit' +import yzs from "./request.js"; // type: 0 --> 声文速记 纯文本,已适配 // type: 1 --> 导入音频 @@ -62,15 +63,35 @@ export const { export default recorderSlice.reducer -const fecthRecord = (index) => { - console.log("begin fetch record item", index); +const fetchRecord = (accessToken, index, record) => { return (dispatch) => { dispatch(setLoading()); - // testPromiseLoading(2000, true).then(e => { - // console.log("end fetch record item", index); - // dispatch(setLoadFinished()); - // }); + let promises = []; + if (record.transResultUrl) { + let promise1 = yzs.download(accessToken, record.transResultUrl).then( + blob => blob.text() + ).then(text => { + // console.log("type", record.type, text); + let payload = null; + if (record.type === 1 || record.type === 3) { + payload = JSON.parse(text) + } else { + payload = text; + } + dispatch(setCurrentLyric(payload)); + }); + promises.push(promise1); + } + + let promise2 = yzs.download(accessToken, record.audioUrl).then(blob => { + dispatch(setCurrentBlob(URL.createObjectURL(blob))); + }); + + promises.push(promise2); + Promise.all(promises).then(() => { + dispatch(setLoadFinished()); + }); }; } -export { fecthRecord }; \ No newline at end of file +export { fetchRecord }; \ No newline at end of file diff --git a/src/business/request.js b/src/business/request.js index 27a3fdc..7268dd3 100644 --- a/src/business/request.js +++ b/src/business/request.js @@ -15,6 +15,7 @@ const appSecret = "c5eccccfec16d46fe9ac678d69198415"; function constructParameter(body) { let params = []; for (let key in body) { + if (key === "smsTemplateId") continue; params.push(body[key].toString()); } params.sort(); @@ -222,6 +223,7 @@ const yzs = { body.clientId = udid; body.timestamp = Math.round(new Date().getTime() / 1000); body.userCell = userCell; + body.smsTemplateId = 316; return fetch("/rest/v2/phone/send_phone_code", { method: "POST", body: constructParameter(body), diff --git a/src/business/utilities.js b/src/business/utilities.js index 8ca6a83..f202787 100644 --- a/src/business/utilities.js +++ b/src/business/utilities.js @@ -33,6 +33,35 @@ function audioWaveData(url, interval) { }); } +// type: 0 --> 声文速记 纯文本,已适配 +// type: 1 --> 导入音频 +// type: 2 --> 同传翻译 纯文本,已适配 +// type: 3 --> 双语对话 +function exportRecordLyric(type, lyric, filename) { + let element = document.createElement('a'); + + let text = ""; + if (type === 0 || type === 2) { + text = lyric; + } else if (type === 1) { + text = lyric.reduce((accumulator, currentValue) => accumulator + currentValue.text, text); + } else if (type === 3) { + text = lyric.reduce((accumulator, currentValue) => { + if (currentValue.head) return accumulator; + return accumulator + currentValue.asr + "\n" + currentValue.translate + "\n\n"; + }, text); + } + + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + document.body.removeChild(element); +} + function validatePhoneNumber(phoneNumber) { if (phoneNumber.length !== 11) { return false; @@ -47,4 +76,4 @@ function textHintOfValidatePhoneNumber(phoneNumber) { return "请输入正确的手机号码"; } -export { sampleInterval, audioWaveData, validatePhoneNumber, textHintOfValidatePhoneNumber }; \ No newline at end of file +export { sampleInterval, audioWaveData, validatePhoneNumber, textHintOfValidatePhoneNumber, exportRecordLyric }; \ No newline at end of file diff --git a/src/components/RecordList.js b/src/components/RecordList.js index 138d6b7..baea35e 100644 --- a/src/components/RecordList.js +++ b/src/components/RecordList.js @@ -8,19 +8,18 @@ import ListItemButton from '@mui/material/ListItemButton'; import ListItemText from '@mui/material/ListItemText'; import Typography from '@mui/material/Typography'; import Toolbar from '@mui/material/Toolbar'; -import { setCurrentIndex, fecthRecord } from "../business/recorderSlice.js" +import { setCurrentIndex, fetchRecord } from "../business/recorderSlice.js" import AccessTimeFilledIcon from '@mui/icons-material/AccessTimeFilled'; const drawerWidth = 240; -export default function ({ open, recordList, currentIndex, fetchRecord }) { +export default function ({ open, recordList, currentIndex }) { const dispatch = useDispatch(); const accessToken = useSelector(state => state.user.accessToken); const onSelected = (event, index) => { console.log("onSelected", index, recordList.at(index).transResultUrl) dispatch(setCurrentIndex(index)); - fetchRecord(accessToken, recordList.at(index)); - dispatch(fecthRecord(index)); + dispatch(fetchRecord(accessToken, index, recordList.at(index))); } return