Commit 1b6b2a08 by haojie

创建音色页面重复请求的问题

parent 13b6278a
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { liveDefaultVolume } from '@/constants/token';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'; import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
...@@ -148,7 +149,7 @@ const showActionEndVideo = ref(false); ...@@ -148,7 +149,7 @@ const showActionEndVideo = ref(false);
const actionEndVideo = ref(''); const actionEndVideo = ref('');
// 初始音量 // 初始音量
const initVolume = 1; const initVolume = liveDefaultVolume;
// 第一个视频的音量 // 第一个视频的音量
const firstVideoVolume = ref(initVolume); const firstVideoVolume = ref(initVolume);
// 第二个视频的音量 // 第二个视频的音量
......
...@@ -146,6 +146,9 @@ export const videoAccept = 'mp4'; ...@@ -146,6 +146,9 @@ export const videoAccept = 'mp4';
// 音频切割间隔时长 // 音频切割间隔时长
export const audioSplitDuration = 300; export const audioSplitDuration = 300;
// 直播页面音视频默认音量
export const liveDefaultVolume = 1;
// 是否使用测试uuid // 是否使用测试uuid
export const getTestUuid = () => { export const getTestUuid = () => {
let isTest = false; let isTest = false;
......
<template>
<div class="start-live-audio-box">
<div class="start-live-audio-content">
<div class="label">音频脚本</div>
<div class="play-audio-box">
<div class="line">
<PlayAudioSvg></PlayAudioSvg>
<Button theme="opacity" style="color: #fff" v-if="true" @click="showTextarea">查看文字脚本</Button>
</div>
<div class="custom-video-progress">
<CustomProgress :value="modelValue"></CustomProgress>
</div>
</div>
<div v-if="textareaStatus">
<CustomTextarea :disabled="true" class="reset-live-audio-textarea" v-model="textareaValue"></CustomTextarea>
</div>
</div>
<div class="start-live-audio-footer">
<div class="live-status">
<div class="live-icon">
<LiveSvg></LiveSvg>
</div>
<span>
<template v-if="route.query.is_live == '1'"> 直播中 </template>
<template v-else> 未开播 </template>
</span>
</div>
<div class="stop" v-if="route.query.is_live == '1'">
<!-- <span class="start-time">00:52:20</span> -->
<Button theme="opacity" @click="closeLive">关闭直播</Button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import CustomProgress from '@/components/Progress.vue';
import CustomTextarea from '@/components/textarea.vue';
import Button from '@/components/Button.vue';
import LiveSvg from '@/assets/svg/home/live.svg';
import PlayAudioSvg from '@/assets/svg/home/playAudio.svg';
import { closeLiveTask } from '@/utils/api/userApi';
import { ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import routerConfig from '@/router/tool';
import { show_message } from '@/utils/tool';
import { useStore } from 'vuex';
import { callPyjsInWindow } from '@/utils/pyqt';
const props = withDefaults(
defineProps<{
url: string;
value?: string;
modelValue: number;
}>(),
{
value: '',
},
);
const store = useStore();
const route = useRoute();
const router = useRouter();
const canPlay = ref(false);
watch(
() => props.url,
(v) => {
if (v) {
canPlay.value = true;
}
},
);
watch(
() => props.value,
(v) => {
if (v) {
textareaValue.value = v;
} else {
textareaValue.value = '';
}
},
);
const textareaStatus = ref(false);
const textareaValue = ref(props.value);
const changeRouteQuery = () => {
router.replace({
path: routerConfig.startLive.path,
name: routerConfig.startLive.name,
query: {
...route.query,
is_live: '0',
},
});
};
const showTextarea = () => {
textareaStatus.value = true;
};
const closeLive = async () => {
try {
let res: any = await closeLiveTask(route.query.id);
if (res.code == 0) {
show_message('关播成功', 'success');
// 通知视频暂停播放
store.commit('live/setLiveVideoStatus', {
play: false,
});
changeRouteQuery();
// 通知python刷新所有首页的直播列表
callPyjsInWindow('reloadLiveTaskList');
}
} catch (e) {
console.log(e);
}
};
</script>
<style lang="less">
@import '@/style/variables.less';
.start-live-audio-box {
display: flex;
flex-direction: column;
padding: 0 4px;
.start-live-audio-content {
flex: 1;
margin-top: 40px;
border-radius: 0px 3px 3px 3px;
border: 1px solid #464646;
background: #1e1e1e;
padding: 12px;
.label {
font-size: @size-15;
color: #fff;
margin-bottom: 12px;
}
.play-audio-box {
border-radius: 8px;
background: linear-gradient(355deg, #00b58f 0%, rgba(255, 255, 255, 0.8) 100%, rgba(255, 255, 255, 0.9) 100%);
height: 120px;
padding: 12px;
.dj(space-around);
flex-direction: column;
.line {
.dja(space-between);
}
}
.reset-live-audio-textarea {
margin-top: 12px;
.t-textarea__inner {
border-radius: 8px;
background: #454545;
font-size: @size-14;
}
}
}
.start-live-audio-footer {
font-size: @size-15;
color: #00cca2;
padding: 20px 0;
.dja(space-between);
.stop {
.dja();
.start-time {
font-size: @size-14;
color: #bababa;
font-weight: 600;
margin-right: 12px;
}
}
.live-status {
.da();
.live-icon {
background: #04ae8a;
border-radius: 50%;
width: 40px;
height: 40px;
.dja();
}
& > :last-child {
margin-left: 8px;
}
}
}
}
</style>
...@@ -97,9 +97,9 @@ import Button from '@/components/Button.vue'; ...@@ -97,9 +97,9 @@ import Button from '@/components/Button.vue';
import Textarea from '@/components/textarea.vue'; import Textarea from '@/components/textarea.vue';
import SelectionPopup from '@/components/SelectionPopup.vue'; import SelectionPopup from '@/components/SelectionPopup.vue';
import { show_message } from '@/utils/tool'; import { show_message } from '@/utils/tool';
import { onMounted, reactive, ref, watch } from 'vue'; import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import { getTonesList } from '@/service/Common'; import { getTonesList } from '@/service/Common';
import { liveInteractionReply, closeLiveTask } from '@/utils/api/userApi'; import { liveInteractionReply, closeLiveTask, getHumanReplyCallback } from '@/utils/api/userApi';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import routerConfig from '@/router/tool'; import routerConfig from '@/router/tool';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
...@@ -109,6 +109,8 @@ const store = useStore(); ...@@ -109,6 +109,8 @@ const store = useStore();
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
let interval = null;
const lists = reactive({ const lists = reactive({
tones: [], tones: [],
soundColor: [], soundColor: [],
...@@ -146,6 +148,11 @@ const changeRouteQuery = () => { ...@@ -146,6 +148,11 @@ const changeRouteQuery = () => {
}); });
}; };
// 播放音频
const submiAudio = (url: string) => {
emit('createAudio', url);
};
// 关闭直播 // 关闭直播
const closeLive = async () => { const closeLive = async () => {
try { try {
...@@ -167,7 +174,40 @@ const closeLive = async () => { ...@@ -167,7 +174,40 @@ const closeLive = async () => {
} }
}; };
// 获取人工回复回调
const getCallback = async () => {
try {
const res: any = await getHumanReplyCallback(route.query.id);
if (res.code == 0 && res.data.url) {
// 播放
submiAudio(res.data.url);
closeInterval();
loading.value = false;
}
} catch (e) {
console.log(e);
}
};
// 打开定时器
const openInterval = () => {
interval = window.setInterval(() => {
getCallback();
}, 3000);
};
// 关闭
const closeInterval = () => {
window.clearInterval(interval);
clearInterval(interval);
interval = null;
};
const submit = async () => { const submit = async () => {
if (loading.value) {
show_message('请等待上一条回复完成');
return;
}
if (!textTonesValue.value) { if (!textTonesValue.value) {
show_message('音调必选'); show_message('音调必选');
return; return;
...@@ -180,17 +220,13 @@ const submit = async () => { ...@@ -180,17 +220,13 @@ const submit = async () => {
tone_id: textTonesValue.value, tone_id: textTonesValue.value,
}; };
let res: any = await liveInteractionReply(route.query.id, params); let res: any = await liveInteractionReply(route.query.id, params);
if (res.code == 0 && res.data.status) { if (res.code == 0) {
console.log('播放音频'); // 开启轮询
// 播放音频 openInterval();
emit('createAudio', res.data.status);
} else {
console.log('没有音频', res.data);
console.log(route.query.id, params);
} }
loading.value = false;
} catch (e) { } catch (e) {
loading.value = false; loading.value = false;
closeInterval();
console.log(e); console.log(e);
} }
}; };
...@@ -224,6 +260,10 @@ onMounted(async () => { ...@@ -224,6 +260,10 @@ onMounted(async () => {
lists.tones = res.tones; lists.tones = res.tones;
lists.soundColor = res.soundColor; lists.soundColor = res.soundColor;
}); });
onBeforeUnmount(() => {
closeInterval();
});
</script> </script>
<style lang="less"> <style lang="less">
......
...@@ -2,12 +2,19 @@ ...@@ -2,12 +2,19 @@
<div class="custom-interactive-response-page"> <div class="custom-interactive-response-page">
<Human @createAudio="createAudio"></Human> <Human @createAudio="createAudio"></Human>
<div v-show="false"> <div v-show="false">
<audio :src="audioFile" ref="audioRef" @canplay="audioCanplay" @ended="audioEnded"></audio> <audio
:volume="liveDefaultVolume"
:src="audioFile"
ref="audioRef"
@canplay="audioCanplay"
@ended="audioEnded"
></audio>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { liveDefaultVolume } from '@/constants/token';
import { onBeforeUnmount, onMounted, ref } from 'vue'; import { onBeforeUnmount, onMounted, ref } from 'vue';
import Human from './components/human.vue'; import Human from './components/human.vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
......
...@@ -236,14 +236,22 @@ export default function () { ...@@ -236,14 +236,22 @@ export default function () {
const changeVideo = (url: string, index: number | boolean = false) => { const changeVideo = (url: string, index: number | boolean = false) => {
hideVideo.play = false; hideVideo.play = false;
hideVideo.playEnd = false; hideVideo.playEnd = false;
hideVideo.url = url; if (hideVideo.url !== url) {
hideVideo.url = url;
}
if (index !== false) { if (index !== false) {
hideVideo.videoIndex = index; hideVideo.videoIndex = index;
} }
}; };
// 找到所有已经播放完毕的主视频 // 找到所有已经播放完毕的主视频
let playEndVideos = realVideoList.value.filter((row: any, index: number) => { let playEndVideos = realVideoList.value.map((row: any, index: number) => {
if (row.remove && row.result && row.status) { if (row.remove && row.result && row.status && typeof index === 'number') {
return index;
}
});
// 再次过滤
playEndVideos = playEndVideos.map((row: any, index: number) => {
if (typeof index === 'number') {
return index; return index;
} }
}); });
...@@ -637,7 +645,6 @@ export default function () { ...@@ -637,7 +645,6 @@ export default function () {
// 最后一个不是主视频,才有uuid // 最后一个不是主视频,才有uuid
uuid = lastRow.uuid; uuid = lastRow.uuid;
} }
console.log(actionUrl, '动作列表');
realVideoList.value.push({ realVideoList.value.push({
// 主视频列表 // 主视频列表
url: mainUrl, url: mainUrl,
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="image-custom-my-person-box"> <div class="image-custom-my-person-box">
<Loading v-show="loading"></Loading> <Loading v-show="loading"></Loading>
<div class="my-vocal-items"> <div class="my-vocal-items">
<template v-for="item in personList.list" :key="item.id"> <template v-for="item in list" :key="item.id">
<template v-if="item.audit_status == LIVE_AUDIT_STATUS.LIVE_AUDIT_STATUS_FINISH || true"> <template v-if="item.audit_status == LIVE_AUDIT_STATUS.LIVE_AUDIT_STATUS_FINISH || true">
<div class="my-person-loading-item"> <div class="my-person-loading-item">
<Audio <Audio
...@@ -36,8 +36,8 @@ ...@@ -36,8 +36,8 @@
</div> </div>
</template> </template>
</template> </template>
<template v-for="(item, index) in personList.list" :key="item.id"> <template v-for="(item, index) in list" :key="item.id">
<i v-if="index != personList.list.length - 1"></i> <i v-if="index != list.length - 1"></i>
</template> </template>
</div> </div>
<ConfirmDialog v-model="confirmDialog" title="确认删除吗?" @confirm="confirm"></ConfirmDialog> <ConfirmDialog v-model="confirmDialog" title="确认删除吗?" @confirm="confirm"></ConfirmDialog>
...@@ -49,56 +49,29 @@ import ChangeName from '@/components/changeName.vue'; ...@@ -49,56 +49,29 @@ import ChangeName from '@/components/changeName.vue';
import Audio from '@/components/Audio.vue'; import Audio from '@/components/Audio.vue';
import ConfirmDialog from '@/components/ConfirmDialog.vue'; import ConfirmDialog from '@/components/ConfirmDialog.vue';
import Loading from '@/components/loading.vue'; import Loading from '@/components/loading.vue';
import { onActivated, reactive, ref } from 'vue'; import { ref } from 'vue';
import { getTonesList } from '@/service/Common';
import { LIVE_AUDIT_STATUS } from '@/service/Live'; import { LIVE_AUDIT_STATUS } from '@/service/Live';
const personList = reactive({ const props = withDefaults(
list: [], defineProps<{
}); list: any[];
loading: boolean;
}>(),
{},
);
const emit = defineEmits(['playAudio']);
const confirmDialog = ref(false); const confirmDialog = ref(false);
const loading = ref(false);
const isFirstRequest = ref(true);
// 音频开始直播 // 音频开始播放
const startPlay = (id: number) => { const startPlay = (id: number) => {
// 修改play状态 emit('playAudio', id);
personList.list.forEach((item: any) => {
if (item.id == id) {
item.play_status = true;
} else {
item.play_status = false;
}
});
}; };
// 确认删除 // 确认删除
const confirm = () => { const confirm = () => {
// //
}; };
// 获取我的数字人列表
const getList = async () => {
try {
loading.value = true;
let res: any = await getTonesList(false);
res.soundColor.forEach((item: any) => {
item.play_status = false;
});
personList.list = res.soundColor;
loading.value = false;
} catch (e) {
loading.value = false;
console.log(e);
}
};
onActivated(() => {
if (isFirstRequest.value) {
getList();
}
});
</script> </script>
<style lang="less"> <style lang="less">
......
<template> <template>
<div class="image-custom-record"> <div class="image-custom-record">
<div class="record-items" v-for="item in recordList.list" :key="item.id"> <div class="record-items" v-for="item in list" :key="item.id">
<div class="left"> <div class="left">
<Audio <Audio
:url="item.audio_url" :url="item.audio_url"
...@@ -29,46 +29,22 @@ ...@@ -29,46 +29,22 @@
<script lang="tsx" setup> <script lang="tsx" setup>
import Audio from '@/components/Audio.vue'; import Audio from '@/components/Audio.vue';
import { onMounted, reactive, ref } from 'vue'; import { ref } from 'vue';
import { getTonesList } from '@/service/Common';
import CustomizationStatus from '@/components/CustomizationStatus'; import CustomizationStatus from '@/components/CustomizationStatus';
const recordList = reactive({ const props = withDefaults(
list: [], defineProps<{
}); list: any[];
const loading = ref(false); loading: boolean;
}>(),
// 获取我的数字人列表 {},
const getList = async () => { );
try { const emit = defineEmits(['playAudio']);
loading.value = true;
let res: any = await getTonesList(false);
res.soundColor.forEach((item: any) => {
item.play_status = false;
});
recordList.list = res.soundColor;
loading.value = false;
} catch (e) {
loading.value = false;
console.log(e);
}
};
// 音频开始播放 // 音频开始播放
const startPlay = (id: number) => { const startPlay = (id: number) => {
// 修改play状态 emit('playAudio', id);
recordList.list.forEach((item: any) => {
if (item.id == id) {
item.play_status = true;
} else {
item.play_status = false;
}
});
}; };
onMounted(() => {
getList();
});
</script> </script>
<style lang="less"> <style lang="less">
......
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
> >
<CustomTabs v-model="currentTab" theme="dark2"> <CustomTabs v-model="currentTab" theme="dark2">
<CustomTabPanel name="1" label="我的音色"> <CustomTabPanel name="1" label="我的音色">
<MyDigitalPerson></MyDigitalPerson> <MyDigitalPerson :list="personList.list" :loading="loading" @playAudio="myAudioPlay"></MyDigitalPerson>
</CustomTabPanel> </CustomTabPanel>
<CustomTabPanel name="2" label="生成记录"> <CustomTabPanel name="2" label="生成记录">
<Record></Record> <Record :list="personList.record" :loading="loading" @playAudio="recordAudioPlay"></Record>
</CustomTabPanel> </CustomTabPanel>
</CustomTabs> </CustomTabs>
</Customizable> </Customizable>
...@@ -34,11 +34,12 @@ import MyDigitalPerson from './components/MyDigitalPerson.vue'; ...@@ -34,11 +34,12 @@ import MyDigitalPerson from './components/MyDigitalPerson.vue';
import CustomTabs from '@/components/CustomTabs'; import CustomTabs from '@/components/CustomTabs';
import CustomTabPanel from '@/components/CustomTabPanel'; import CustomTabPanel from '@/components/CustomTabPanel';
import Customizable from '@/components/Customizable'; import Customizable from '@/components/Customizable';
import { ref, onMounted, onActivated } from 'vue'; import { ref, onMounted, onActivated, reactive } from 'vue';
import { customizedPhoneticSubmission } from '@/utils/api/userApi'; import { customizedPhoneticSubmission } from '@/utils/api/userApi';
import { show_message } from '@/utils/tool'; import { dimensionalConvert, show_message } from '@/utils/tool';
import { useStore } from 'vuex'; import { useStore } from 'vuex';
import routerConfig from '@/router/tool'; import routerConfig from '@/router/tool';
import { getTonesList } from '@/service/Common';
const store = useStore(); const store = useStore();
...@@ -48,6 +49,11 @@ const imgs = { ...@@ -48,6 +49,11 @@ const imgs = {
}; };
const currentTab = ref('1'); const currentTab = ref('1');
const personList = reactive({
list: [],
record: [],
});
const loading = ref(false);
const getIcon = () => { const getIcon = () => {
return <img src={imgs.speak} style="" />; return <img src={imgs.speak} style="" />;
...@@ -79,6 +85,47 @@ const submit = async (params: any) => { ...@@ -79,6 +85,47 @@ const submit = async (params: any) => {
} }
}; };
// 获取我的数字人列表
const getList = async () => {
try {
loading.value = true;
let res: any = await getTonesList(false);
res.soundColor.forEach((item: any) => {
item.play_status = false;
});
personList.list = res.soundColor;
// 复制一份给记录列表
personList.record = dimensionalConvert(res.soundColor);
loading.value = false;
} catch (e) {
loading.value = false;
console.log(e);
}
};
// 我的音色开始播放
const myAudioPlay = (id: number) => {
// 修改play状态
personList.list.forEach((item: any) => {
if (item.id == id) {
item.play_status = true;
} else {
item.play_status = false;
}
});
};
// 音色记录开始播放
const recordAudioPlay = (id: number) => {
personList.record.forEach((item: any) => {
if (item.id == id) {
item.play_status = true;
} else {
item.play_status = false;
}
});
};
onMounted(() => { onMounted(() => {
store.commit('navbar/setNavbar', { store.commit('navbar/setNavbar', {
path: routerConfig.VocalCustomization.path, path: routerConfig.VocalCustomization.path,
...@@ -86,6 +133,7 @@ onMounted(() => { ...@@ -86,6 +133,7 @@ onMounted(() => {
}); });
onActivated(() => { onActivated(() => {
getList();
store.commit('navbar/setNavbar', { store.commit('navbar/setNavbar', {
path: routerConfig.VocalCustomization.path, path: routerConfig.VocalCustomization.path,
}); });
......
...@@ -258,6 +258,16 @@ export const liveInteractionReply = (id: string | number, data) => { ...@@ -258,6 +258,16 @@ export const liveInteractionReply = (id: string | number, data) => {
}); });
}; };
// 获取人工回复回调
export const getHumanReplyCallback = (id: any) => {
const header = getHeader();
return request.get(`/api/live/interaction/${id}/reply`, {
headers: {
...header,
},
});
};
// 形象定制提交 // 形象定制提交
export const customizedImageSubmission = (data: any) => { export const customizedImageSubmission = (data: any) => {
const header = getHeader(); const header = getHeader();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment