@@ -9,7 +9,10 @@ | |||
"dependencies": { | |||
"axios": "0.18.1", | |||
"element-ui": "^2.15.12", | |||
"install": "^0.13.0", | |||
"lib-flexible": "^0.3.2", | |||
"mic-recorder-to-mp3": "^2.2.2", | |||
"npm": "^9.6.2", | |||
"postcss-px2rem": "^0.3.0", | |||
"register-service-worker": "^1.7.1", | |||
"sass-loader": "^7.0.0", | |||
@@ -20,12 +23,12 @@ | |||
"vuex": "^3.4.0" | |||
}, | |||
"devDependencies": { | |||
"uglifyjs-webpack-plugin": "^2.2.0", | |||
"@vue/cli-plugin-pwa": "~4.5.13", | |||
"@vue/cli-plugin-router": "~4.5.13", | |||
"@vue/cli-plugin-vuex": "~4.5.13", | |||
"@vue/cli-service": "~4.5.13", | |||
"node-sass": "^4.14.1", | |||
"uglifyjs-webpack-plugin": "^2.2.0", | |||
"vue-template-compiler": "^2.6.11" | |||
} | |||
} | |||
} |
@@ -1,12 +1,14 @@ | |||
<template> | |||
<div class="showBody-bottom-speakDiv"> | |||
<!-- 没点麦克风 --> | |||
<div v-show="!speakingAction" class="showBody-bottom-speakDiv-text">点击语音按钮,快来跟我对话吧!</div> | |||
<!-- <div v-show="!speakingAction" class="showBody-bottom-speakDiv-text">点击语音按钮,快来跟我对话吧!</div> --> | |||
<el-input rows="1" type="textarea" :autosize="{minRows:1,maxRows:6}" maxlength="150" v-show="!speakingAction" class="" placeholder="点击语音按钮,快来跟我对话吧" v-model="chatInputContent" @change="addMessageToFather()"></el-input> | |||
<div @click="speakingAction=!speakingAction" v-show="!speakingAction" class="defaultBtn buleBtn"> | |||
<img src="@/assets/icon/icon-microphone2.png" alt=""> | |||
</div> | |||
<!-- 点了麦克风 --> | |||
<div v-show="speakingAction" class="showBody-bottom-speakDiv-text">按住说话</div> | |||
<div v-show="speakingAction" class="showBody-bottom-speakDiv-text" @mousedown="startRecording" @mouseup="stopRecording">按住说话</div> | |||
<div @click="speakingAction=!speakingAction" v-show="speakingAction" class="defaultBtn buleBtn"> | |||
<img src="@/assets/icon/icon-speaking.png" alt=""> | |||
</div> | |||
@@ -14,26 +16,78 @@ | |||
</template> | |||
<script> | |||
import MicRecorder from 'mic-recorder-to-mp3'; | |||
export default { | |||
name: 'HomeWapLanguageToText', | |||
data() { | |||
return { | |||
recorder: null, | |||
isRecording: false, | |||
audioUrl: null, | |||
speakingAction: false, // 底部是否说话按钮状态 | |||
chatInputContent:'',// 输入框内容 | |||
}; | |||
}, | |||
mounted() { | |||
this.recorder = new MicRecorder({ | |||
bitRate: 128 | |||
}); | |||
}, | |||
methods: { | |||
// 开始录音 | |||
startRecording() { | |||
if (!this.isRecording) { | |||
this.isRecording = true; | |||
this.recorder.start().then(() => { | |||
console.log('Recording started'); | |||
}).catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 停止录音 | |||
stopRecording() { | |||
if (this.isRecording) { | |||
this.isRecording = false; | |||
this.recorder.stop().getMp3().then(([buffer, blob]) => { | |||
this.audioUrl = URL.createObjectURL(blob); | |||
}).catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 添加信息 | |||
addMessageToFather() { | |||
this.$emit('getSonMessage', { | |||
form: 'me', | |||
message:this.chatInputContent | |||
}) | |||
console.log(this.chatInputContent); | |||
this.chatInputContent = '' | |||
console.log(222); | |||
} | |||
}, | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
::v-deep .el-textarea { | |||
padding-top: 5px; | |||
margin-right: 10px; | |||
width: 286px; | |||
.el-textarea__inner { | |||
width: 286px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #666666; | |||
font-size: 14px; | |||
white-space: pre-line | |||
} | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
@@ -50,11 +104,13 @@ export default { | |||
} | |||
.contnet { | |||
.showBody { | |||
position: relative; | |||
width: 100%; | |||
height: calc(100vh - 44px) ; | |||
background-color: red; | |||
&-bottom { | |||
position: absolute; | |||
bottom: 0; | |||
@@ -62,56 +118,7 @@ export default { | |||
// height: 150px; | |||
padding-bottom: 33px; | |||
background: linear-gradient(180deg, rgba(0,0,0,0) 0%, #000000 100%); | |||
&-buttons { | |||
display: flex; | |||
justify-content: space-evenly; | |||
padding: 0 20px; | |||
color: #fff; | |||
font-size: 10px; | |||
&-item { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
p { | |||
margin-top: 4px; | |||
} | |||
} | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0,0,0,0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
&-speakDiv { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 20px; | |||
padding: 0 15px; | |||
&-text { | |||
margin-top: 4px; | |||
width: 290px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #FFFFFF; | |||
font-size: 14px; | |||
color: #FFFFFF; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
.whiteDiv { | |||
background-color: #ececec; | |||
color: #000; | |||
} | |||
} | |||
} | |||
&-modelList { | |||
position: relative; | |||
@@ -273,6 +280,27 @@ export default { | |||
} | |||
} | |||
} | |||
&-speakDiv { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 20px; | |||
padding: 0 15px; | |||
&-text { | |||
margin-top: 4px; | |||
width: 290px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #FFFFFF; | |||
font-size: 14px; | |||
color: #FFFFFF; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
.whiteDiv { | |||
background-color: #ececec; | |||
color: #000; | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -62,6 +62,20 @@ const routes = [ | |||
name: 'chat', | |||
component: () => import("@/views/chat/chat"), | |||
}, | |||
, | |||
// 聊天首页new | |||
{ | |||
path: '/chatgpt', | |||
name: 'chatgpt', | |||
component: () => import("@/views/chatgpt/chatgpt"), | |||
}, | |||
, | |||
// 音频new | |||
{ | |||
path: '/audio', | |||
name: 'audio', | |||
component: () => import("@/views/audio/audio"), | |||
}, | |||
// 录入文案 | |||
{ | |||
path: '/getPaper', | |||
@@ -18,4 +18,7 @@ img { | |||
//按钮选中颜色 | |||
.buleBtn { | |||
background: #24A9FF!important; | |||
} | |||
.bgcWhite { | |||
background: #fff!important; | |||
} |
@@ -0,0 +1,58 @@ | |||
<template> | |||
<div> | |||
<button @click="startRecording">开始录音</button> | |||
<button @click="stopRecording">停止录音</button> | |||
<button @click="playRecording">播放录音</button> | |||
<audio controls :src="audioUrl"></audio> | |||
</div> | |||
</template> | |||
<script> | |||
import MicRecorder from 'mic-recorder-to-mp3'; | |||
export default { | |||
data() { | |||
return { | |||
recorder: null, | |||
isRecording: false, | |||
audioUrl: null | |||
}; | |||
}, | |||
mounted() { | |||
this.recorder = new MicRecorder({ | |||
bitRate: 128 | |||
}); | |||
}, | |||
methods: { | |||
// 开始录音 | |||
startRecording() { | |||
if (!this.isRecording) { | |||
this.isRecording = true; | |||
this.recorder.start().then(() => { | |||
console.log('Recording started'); | |||
}).catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 停止录音 | |||
stopRecording() { | |||
if (this.isRecording) { | |||
this.isRecording = false; | |||
this.recorder.stop().getMp3().then(([buffer, blob]) => { | |||
this.audioUrl = URL.createObjectURL(blob); | |||
}).catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 播放录音 | |||
playRecording() { | |||
if (this.audioUrl) { | |||
const audio = new Audio(this.audioUrl); | |||
audio.play(); | |||
} | |||
} | |||
} | |||
} | |||
</script> |
@@ -0,0 +1,440 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<!-- 主体内容 --> | |||
<div class="contnet"> | |||
<!-- 头部 --> | |||
<div class="head"> | |||
<img src="../../assets/icon/icon-loginout.png" alt=""> | |||
<div class="head-exit"> | |||
<img src="../../assets/icon/icon-loginoutwhite.png" alt=""> | |||
退出聊天 | |||
</div> | |||
</div> | |||
<!-- 显示模板区 --> | |||
<div class="showBody"> | |||
<!-- 底部渐变区 --> | |||
<div class="showBody-bottom"> | |||
<!-- 更换人物模板列表 --> | |||
<div v-show="PersonButtonAction" class="showBody-modelList"> | |||
<div v-for="item,index in modelList" :key="item.name" class="showBody-modelList-item" @click="modelItemAction=index"> | |||
<div class="modelName">{{ item.name }} | |||
<div v-show="modelItemAction==index" class="showBody-modelList-item-boxBorder"></div> | |||
</div> | |||
<img :src="item.url" alt=""> | |||
</div> | |||
</div> | |||
<!-- 四大按钮 --> | |||
<div class="showBody-bottom-buttons"> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':PersonButtonAction}" class="defaultBtn" @click="clickPersonButton"> | |||
<img src="@/assets/icon/icon-person.png" alt=""> | |||
</div> | |||
<p>更换人物模板</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':CameraAction}" class="defaultBtn" @click="clickCameraButton"> | |||
<img src="@/assets/icon/icon-openCamera.png" alt=""> | |||
</div> | |||
<p>摄像头开启</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':CloseChatAction}" class="defaultBtn" @click="clickCloseChatButton"> | |||
<img src="@/assets/icon/icon-closeChat.png" alt=""> | |||
</div> | |||
<p>对话框关闭</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':GlobalAction}" class="defaultBtn" @click="clickGlobalButton"> | |||
<img src="@/assets/icon/icon-global.png" alt=""> | |||
</div> | |||
<p>选择对话语言</p> | |||
</div> | |||
</div> | |||
<!-- 语音说话 --> | |||
<LanguageToText></LanguageToText> | |||
</div> | |||
<!-- 摄像头窗口 --> | |||
<div v-show="CameraAction" class="showBody-myCamera"></div> | |||
<!-- 聊天框 --> | |||
<div v-show="CloseChatAction" class="showBody-chatBox"> | |||
<!-- 关闭 --> | |||
<div class="showBody-chatBox-close"> | |||
<i @click="CloseChatAction=false" class="el-icon-close"></i> | |||
</div> | |||
<!-- 聊天记录 --> | |||
<div class="showBody-chatBox-record"> | |||
<div class="showBody-chatBox-record-my" :class="{'others':item.form!='me'}" v-for="item,index in chatRecordList" :key="index"> | |||
<span>{{ item.message }}</span> | |||
</div> | |||
</div> | |||
<!-- 底部说话按钮 --> | |||
<LanguageToText @getSonMessage="addMessageRecord(data)"></LanguageToText> | |||
</div> | |||
<!-- 选择语言 --> | |||
<div v-show="GlobalAction" class="showBody-global"> | |||
<!-- --> | |||
<div class="showBody-global-choose"> | |||
<div class="showBody-global-choose-language"> | |||
<div class="showBody-global-choose-language-item" v-for="item in languageList" :key="item.type"> | |||
{{ item.type }} | |||
</div> | |||
</div> | |||
<div class="showBody-global-choose-btn"> | |||
<div @click="GlobalAction=false" class="showBody-global-choose-btn-no">取消</div> | |||
<div class="showBody-global-choose-btn-yes">确定</div> | |||
</div> | |||
</div> | |||
<!-- 底部说话按钮 --> | |||
<LanguageToText></LanguageToText> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import LanguageToText from '@/components/languageToText.vue' | |||
// 组件 | |||
import Vue from "vue"; | |||
import { Toast } from "vant"; | |||
import { mapState, mapActions } from "vuex"; | |||
// 工具 | |||
import { scrollToID } from "../../utils"; | |||
Vue.use(Toast); | |||
export default { | |||
components: { | |||
LanguageToText | |||
}, | |||
data() { | |||
return { | |||
inPage: false, | |||
PersonButtonAction: false,//个人按钮状态 | |||
CameraAction:false,// 摄像头按钮状态 | |||
CloseChatAction:false,// 聊天框按钮状态 | |||
GlobalAction:false,// 语音按钮状态 | |||
// speakingAction: false, // 底部是否说话按钮状态 | |||
modelList: [ | |||
{ name:'甘雨',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'莫甘娜',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'达尔文',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'雨果',url:require('../../assets/img/module_3_1.png')}, | |||
],// 人物模板列表 | |||
modelItemAction: -1,// 人物模板列表选中高亮 | |||
chatRecordList: [ | |||
{ form: 'me', message: '生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1' }, | |||
{ form: 'you', message: '生于忧患死于安乐2' }, | |||
{ form: 'me', message: '生于忧患死于安乐3' }, | |||
{ form: 'you', message: '生于忧患死于安乐4' }, | |||
{ form: 'me', message: '生于忧患死于安乐5' }, | |||
{ form: 'me', message: '生于忧患死于安乐6' }, | |||
{ form: 'me', message: '生于忧患死于安乐7' }, | |||
],// 聊天记录列表 | |||
languageList: [ | |||
{type:'AUTO'}, | |||
{type:'璃月语'}, | |||
{type:'JP语'}, | |||
{type:'english'}, | |||
{type:'中国话'}, | |||
{type:'四川话'}, | |||
{type:'东百话'}, | |||
{type:'阿拉伯语'}, | |||
{type:'朝鲜语'}, | |||
], //语种列表 | |||
}; | |||
}, | |||
computed: { | |||
...mapState({ | |||
characters: (state) => state.publicObj.characters, | |||
}), | |||
}, | |||
methods: { | |||
...mapActions(["setCharacters"]), | |||
// 点击个人按钮事件 | |||
clickPersonButton() { | |||
this.PersonButtonAction=!this.PersonButtonAction | |||
}, | |||
// 点击摄像头按钮事件 | |||
clickCameraButton() { | |||
this.CameraAction=!this.CameraAction | |||
}, | |||
// 点击聊天框按钮事件 | |||
clickCloseChatButton() { | |||
this.CloseChatAction=!this.CloseChatAction | |||
}, | |||
// 点击语音按钮事件 | |||
clickGlobalButton() { | |||
this.GlobalAction=!this.GlobalAction | |||
}, | |||
// 往聊天记录里添加内容 | |||
addMessageRecord(data) { | |||
console.log(data); | |||
this.chatRecordList.push(data) | |||
}, | |||
go(url) { | |||
this.$router.push(url); | |||
}, | |||
}, | |||
created() {}, | |||
mounted() { | |||
this.inPage = true; | |||
scrollToID("top"); | |||
}, | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
transition: all 0.5s; // global-transition | |||
&.active { | |||
opacity: 1; | |||
transform: translateX(0); | |||
} | |||
} | |||
.contnet { | |||
.head { | |||
display: flex; | |||
justify-content: space-between; | |||
padding: 4px 10px; | |||
>img { | |||
width: 36px; | |||
height: 36px; | |||
} | |||
&-exit { | |||
margin-top: 4px; | |||
width: 97px; | |||
height: 28px; | |||
text-align: center; | |||
line-height: 28px; | |||
background: #24A9FF; | |||
color: #fff; | |||
box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.2); | |||
border-radius: 33px; | |||
>img { | |||
margin-top: -2px; | |||
margin-right: 4px; | |||
} | |||
} | |||
} | |||
.showBody { | |||
position: relative; | |||
width: 100%; | |||
height: calc(100vh - 44px) ; | |||
background-color: red; | |||
&-bottom { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
// height: 150px; | |||
padding-bottom: 33px; | |||
background: linear-gradient(180deg, rgba(0,0,0,0) 0%, #000000 100%); | |||
&-buttons { | |||
display: flex; | |||
justify-content: space-evenly; | |||
padding: 0 20px; | |||
color: #fff; | |||
font-size: 10px; | |||
&-item { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
p { | |||
margin-top: 4px; | |||
} | |||
} | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0,0,0,0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
} | |||
&-modelList { | |||
position: relative; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
height: 200px; | |||
padding-left: 15px; | |||
overflow-x: scroll; | |||
&-item { | |||
position: relative; | |||
margin-right: 15px; | |||
&-boxBorder { | |||
position: absolute; | |||
top: -2px; | |||
width: 123px; | |||
height: 183px; | |||
border-radius: 8px; | |||
transition: all 0.5s; // | |||
border: 3px solid #00ffe1; | |||
} | |||
.modelName { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 48px; | |||
height: 28px; | |||
background: rgba(0,0,0,0.5); | |||
border-radius: 8px 0px 8px 0px; | |||
color: #fff; | |||
font-size: 13px; | |||
line-height: 28px; | |||
text-align: center; | |||
} | |||
img { | |||
width: 120px; | |||
height: 180px; | |||
border-radius:8px 5px 5px 8px; | |||
} | |||
} | |||
} | |||
&-myCamera { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
width: 96px; | |||
height: 180px; | |||
background-image:url(../../assets/img/bg.png); | |||
background-size: contain; | |||
} | |||
&-chatBox { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
height: 375px; | |||
background-color: #ECECEC; | |||
&-close { | |||
padding: 10px 15px; | |||
height: 35px; | |||
i { | |||
float: right; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 16px; | |||
font-weight: 600; | |||
} | |||
} | |||
&-record { | |||
padding: 5px 10px 0; | |||
height: 255px; | |||
overflow-y: scroll; | |||
font-size: 15px; | |||
color: #333333; | |||
line-height: 21px; | |||
&-my { | |||
float: right; | |||
padding: 10px 20px; | |||
margin-bottom: 15px; | |||
background: #9EE445; | |||
border-radius: 20px 20px 2px 20px; | |||
clear: both; | |||
} | |||
.others { | |||
float: left; | |||
background: #FFFFFF; | |||
border-radius: 20px 20px 20px 2px; | |||
} | |||
} | |||
} | |||
&-global { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
height: 385px; | |||
background-color: #ECECEC; | |||
&-choose { | |||
padding: 20px 36px 0; | |||
height: 304px; | |||
overflow-y: scroll; | |||
font-size: 15px; | |||
color: #333333; | |||
line-height: 21px; | |||
&-language { | |||
display: flex; | |||
justify-content: start; | |||
flex-wrap: wrap; | |||
width: 300px; | |||
height: 210px; | |||
background-color: #fff; | |||
overflow: hidden; | |||
border: none; | |||
border-radius: 15px; | |||
&-item { | |||
width: 100px; | |||
height: 70px; | |||
text-align: center; | |||
line-height: 70px; | |||
font-size: 14px; | |||
color: #333; | |||
border: 1px solid #ECECEC; | |||
} | |||
} | |||
&-btn { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 20px; | |||
>div { | |||
width: 139px; | |||
height: 37px; | |||
border-radius: 31px; | |||
text-align: center; | |||
line-height: 37px; | |||
font-size: 15px; | |||
font-weight: 600; | |||
} | |||
&-no { | |||
color: #333333; | |||
background: #FFFFFF; | |||
} | |||
&-yes { | |||
color: #FFFFFF; | |||
background: #24A9FF; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.showBody-modelList::-webkit-scrollbar { | |||
width:0; | |||
} | |||
.showBody-chatBox-record::-webkit-scrollbar { | |||
width:0; | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0,0,0,0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
</style> |
@@ -1,13 +1,13 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<!-- 主体内容 --> | |||
<!-- 页面内容 --> | |||
<div class="contnet"> | |||
<!-- 头部 --> | |||
<div class="head"> | |||
<img src="../../assets/icon/icon-loginout.png" alt=""> | |||
<img src="../../assets/icon/icon-loginout.png" alt="" /> | |||
<div class="head-exit"> | |||
<img src="../../assets/icon/icon-loginoutwhite.png" alt=""> | |||
<img src="../../assets/icon/icon-loginoutwhite.png" alt="" /> | |||
退出聊天 | |||
</div> | |||
</div> | |||
@@ -17,89 +17,162 @@ | |||
<div class="showBody-bottom"> | |||
<!-- 更换人物模板列表 --> | |||
<div v-show="PersonButtonAction" class="showBody-modelList"> | |||
<div v-for="item,index in modelList" :key="item.name" class="showBody-modelList-item" @click="modelItemAction=index"> | |||
<div class="modelName">{{ item.name }} | |||
<div v-show="modelItemAction==index" class="showBody-modelList-item-boxBorder"></div> | |||
<div | |||
v-for="(item, index) in modelList" | |||
:key="item.name" | |||
class="showBody-modelList-item" | |||
@click="modelItemAction = index" | |||
> | |||
<div class="modelName"> | |||
{{ item.name }} | |||
<div | |||
v-show="modelItemAction == index" | |||
class="showBody-modelList-item-boxBorder" | |||
></div> | |||
</div> | |||
<img :src="item.url" alt="" /> | |||
</div> | |||
<img :src="item.url" alt=""> | |||
</div> | |||
</div> | |||
<!-- 四大按钮 --> | |||
<div class="showBody-bottom-buttons"> | |||
<div v-show="!CloseChatAction&&!GlobalAction" class="showBody-bottom-buttons"> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':PersonButtonAction}" class="defaultBtn" @click="clickPersonButton"> | |||
<img src="@/assets/icon/icon-person.png" alt=""> | |||
<div | |||
:class="{ buleBtn: PersonButtonAction }" | |||
class="defaultBtn" | |||
@click="clickPersonButton" | |||
> | |||
<img src="@/assets/icon/icon-person.png" alt="" /> | |||
</div> | |||
<p>更换人物模板</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':CameraAction}" class="defaultBtn" @click="clickCameraButton"> | |||
<img src="@/assets/icon/icon-openCamera.png" alt=""> | |||
<div | |||
:class="{ buleBtn: CameraAction }" | |||
class="defaultBtn" | |||
@click="clickCameraButton" | |||
> | |||
<img src="@/assets/icon/icon-openCamera.png" alt="" /> | |||
</div> | |||
<p>摄像头开启</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':CloseChatAction}" class="defaultBtn" @click="clickCloseChatButton"> | |||
<img src="@/assets/icon/icon-closeChat.png" alt=""> | |||
<div | |||
:class="{ buleBtn: CloseChatAction }" | |||
class="defaultBtn" | |||
@click="clickCloseChatButton" | |||
> | |||
<img src="@/assets/icon/icon-closeChat.png" alt="" /> | |||
</div> | |||
<p>对话框关闭</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div :class="{'buleBtn':GlobalAction}" class="defaultBtn" @click="clickGlobalButton"> | |||
<img src="@/assets/icon/icon-global.png" alt=""> | |||
<div | |||
:class="{ buleBtn: GlobalAction }" | |||
class="defaultBtn" | |||
@click="clickGlobalButton" | |||
> | |||
<img src="@/assets/icon/icon-global.png" alt="" /> | |||
</div> | |||
<p>选择对话语言</p> | |||
</div> | |||
</div> | |||
<!-- 语音说话 --> | |||
<LanguageToText></LanguageToText> | |||
</div> | |||
<!-- 摄像头窗口 --> | |||
<div v-show="CameraAction" class="showBody-myCamera"></div> | |||
<!-- 聊天框 --> | |||
<div v-show="CloseChatAction" class="showBody-chatBox"> | |||
<!-- 关闭 --> | |||
<div class="showBody-chatBox-close"> | |||
<i @click="CloseChatAction=false" class="el-icon-close"></i> | |||
</div> | |||
<!-- 聊天记录 --> | |||
<div class="showBody-chatBox-record"> | |||
<div class="showBody-chatBox-record-my" :class="{'others':item.form!='me'}" v-for="item,index in chatRecordList" :key="index"> | |||
<span>{{ item.message }}</span> | |||
<!-- 聊天框 --> | |||
<div v-show="CloseChatAction" class="showBody-chatBox"> | |||
<!-- 关闭 --> | |||
<div class="showBody-chatBox-close"> | |||
<i @click="CloseChatAction = false" class="el-icon-close"></i> | |||
</div> | |||
<!-- 聊天记录 --> | |||
<div ref="recordBox" class="showBody-chatBox-record"> | |||
<div | |||
class="showBody-chatBox-record-my" | |||
:class="{ others: item.form != 'me' }" | |||
v-for="(item, index) in chatRecordList" | |||
:key="index" | |||
> | |||
<span>{{ item.message }}</span> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 底部说话按钮 --> | |||
<LanguageToText></LanguageToText> | |||
</div> | |||
<!-- 选择语言 --> | |||
<div v-show="GlobalAction" class="showBody-global"> | |||
<!-- --> | |||
<div class="showBody-global-choose"> | |||
<div class="showBody-global-choose-language"> | |||
<div class="showBody-global-choose-language-item" v-for="item in languageList" :key="item.type"> | |||
{{ item.type }} | |||
<!-- 选择语言 --> | |||
<div v-show="GlobalAction" class="showBody-global"> | |||
<!-- --> | |||
<div class="showBody-global-choose"> | |||
<div class="showBody-global-choose-language"> | |||
<div | |||
class="showBody-global-choose-language-item" | |||
v-for="item in languageList" | |||
:key="item.type" | |||
> | |||
{{ item.type }} | |||
</div> | |||
</div> | |||
<div class="showBody-global-choose-btn"> | |||
<div | |||
@click="GlobalAction = false" | |||
class="showBody-global-choose-btn-no" | |||
> | |||
取消 | |||
</div> | |||
<div class="showBody-global-choose-btn-yes">确定</div> | |||
</div> | |||
</div> | |||
<div class="showBody-global-choose-btn"> | |||
<div @click="GlobalAction=false" class="showBody-global-choose-btn-no">取消</div> | |||
<div class="showBody-global-choose-btn-yes">确定</div> | |||
</div> | |||
<!-- 开麦和聊天输入 --> | |||
<div | |||
:class="{ chatBoxAction: CloseChatAction || GlobalAction }" | |||
class="showBody-bottom-speakDiv" | |||
> | |||
<!-- 没点麦克风 --> | |||
<el-input | |||
rows="1" | |||
type="textarea" | |||
:autosize="{ minRows: 1, maxRows: 4 }" | |||
maxlength="150" | |||
v-show="!speakingAction" | |||
class="" | |||
placeholder="点击语音按钮,快来跟我对话吧" | |||
v-model="chatInputContent" | |||
@keydown.enter.native="addMessageRecord()" | |||
></el-input> | |||
<div | |||
@click="speakingAction = !speakingAction" | |||
v-show="!speakingAction" | |||
class="defaultBtn buleBtn" | |||
> | |||
<img src="@/assets/icon/icon-microphone2.png" alt="" /> | |||
</div> | |||
<!-- 点了麦克风 --> | |||
<div | |||
v-show="speakingAction" | |||
class="showBody-bottom-speakDiv-text" | |||
@mousedown="startRecording" | |||
@mouseup="stopRecording" | |||
> | |||
按住说话 | |||
</div> | |||
</div> | |||
<!-- 底部说话按钮 --> | |||
<LanguageToText></LanguageToText> | |||
<div | |||
@click="speakingAction = !speakingAction" | |||
v-show="speakingAction" | |||
class="defaultBtn buleBtn" | |||
> | |||
<img src="@/assets/icon/icon-speaking.png" alt="" /> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 摄像头窗口 --> | |||
<div v-show="CameraAction" class="showBody-myCamera"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import LanguageToText from '@/components/languageToText.vue' | |||
// 组件 | |||
import Vue from "vue"; | |||
import { Toast } from "vant"; | |||
@@ -109,44 +182,50 @@ import { scrollToID } from "../../utils"; | |||
Vue.use(Toast); | |||
export default { | |||
components: { | |||
LanguageToText | |||
}, | |||
data() { | |||
return { | |||
inPage: false, | |||
PersonButtonAction: false,//个人按钮状态 | |||
CameraAction:false,// 摄像头按钮状态 | |||
CloseChatAction:false,// 聊天框按钮状态 | |||
GlobalAction:false,// 语音按钮状态 | |||
PersonButtonAction: false, //个人按钮状态 | |||
CameraAction: false, // 摄像头按钮状态 | |||
CloseChatAction: false, // 聊天框按钮状态 | |||
GlobalAction: false, // 选择语言按钮状态 | |||
// speakingAction: false, // 底部是否说话按钮状态 | |||
modelList: [ | |||
{ name:'甘雨',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'莫甘娜',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'达尔文',url:require('../../assets/img/module_3_1.png')}, | |||
{ name:'雨果',url:require('../../assets/img/module_3_1.png')}, | |||
],// 人物模板列表 | |||
modelItemAction: -1,// 人物模板列表选中高亮 | |||
{ name: "甘雨", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "莫甘娜", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "达尔文", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "雨果", url: require("../../assets/img/module_3_1.png") }, | |||
], // 人物模板列表 | |||
modelItemAction: -1, // 人物模板列表选中高亮 | |||
chatRecordList: [ | |||
{ form: 'me', message: '生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1' }, | |||
{ form: 'you', message: '生于忧患死于安乐2' }, | |||
{ form: 'me', message: '生于忧患死于安乐3' }, | |||
{ form: 'you', message: '生于忧患死于安乐4' }, | |||
{ form: 'me', message: '生于忧患死于安乐5' }, | |||
{ form: 'me', message: '生于忧患死于安乐6' }, | |||
{ form: 'me', message: '生于忧患死于安乐7' }, | |||
],// 聊天记录列表 | |||
{ | |||
form: "me", | |||
message: | |||
"生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1", | |||
}, | |||
{ form: "you", message: "生于忧患死于安乐2" }, | |||
{ form: "me", message: "生于忧患死于安乐3" }, | |||
{ form: "you", message: "生于忧患死于安乐4" }, | |||
{ form: "me", message: "生于忧患死于安乐5" }, | |||
{ form: "me", message: "生于忧患死于安乐6" }, | |||
{ form: "me", message: " " }, | |||
], // 聊天记录列表 | |||
languageList: [ | |||
{type:'AUTO'}, | |||
{type:'璃月语'}, | |||
{type:'JP语'}, | |||
{type:'english'}, | |||
{type:'中国话'}, | |||
{type:'四川话'}, | |||
{type:'东百话'}, | |||
{type:'阿拉伯语'}, | |||
{type:'朝鲜语'}, | |||
{ type: "AUTO" }, | |||
{ type: "璃月语" }, | |||
{ type: "JP语" }, | |||
{ type: "english" }, | |||
{ type: "中国话" }, | |||
{ type: "四川话" }, | |||
{ type: "东百话" }, | |||
{ type: "阿拉伯语" }, | |||
{ type: "朝鲜语" }, | |||
], //语种列表 | |||
recorder: null, | |||
isRecording: false, | |||
audioUrl: null, | |||
speakingAction: false, // 底部是否说话按钮状态 | |||
chatInputContent: "", // 输入框内容 | |||
}; | |||
}, | |||
computed: { | |||
@@ -159,20 +238,75 @@ export default { | |||
...mapActions(["setCharacters"]), | |||
// 点击个人按钮事件 | |||
clickPersonButton() { | |||
this.PersonButtonAction=!this.PersonButtonAction | |||
this.PersonButtonAction = !this.PersonButtonAction; | |||
}, | |||
// 点击摄像头按钮事件 | |||
clickCameraButton() { | |||
this.CameraAction=!this.CameraAction | |||
this.CameraAction = !this.CameraAction; | |||
}, | |||
// 点击聊天框按钮事件 | |||
clickCloseChatButton() { | |||
this.CloseChatAction=!this.CloseChatAction | |||
this.CloseChatAction = !this.CloseChatAction; | |||
}, | |||
// 点击语音按钮事件 | |||
clickGlobalButton() { | |||
this.GlobalAction=!this.GlobalAction | |||
}, | |||
this.GlobalAction = !this.GlobalAction; | |||
}, | |||
// 往聊天记录里添加内容 | |||
addMessageRecord() { | |||
if (this.chatInputContent) { | |||
console.log(this.chatInputContent); | |||
this.chatRecordList.push({ | |||
form: "me", | |||
message: this.chatInputContent, | |||
}); | |||
this.chatInputContent = ""; | |||
this.scrollToBottom(); | |||
} | |||
}, | |||
// 聊天页面滚动到页面最底端 | |||
scrollToBottom() { | |||
this.$nextTick(() => { | |||
// dom 元素更新后执行滚动条到底部 否则不生效 | |||
let scrollElem = this.$refs.recordBox; | |||
scrollElem.scrollTo({ | |||
top: scrollElem.scrollHeight, | |||
behavior: "smooth", | |||
}); | |||
}); | |||
}, | |||
// 开始录音 | |||
startRecording() { | |||
if (!this.isRecording) { | |||
this.isRecording = true; | |||
this.recorder | |||
.start() | |||
.then(() => { | |||
console.log("Recording started"); | |||
}) | |||
.catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 停止录音 | |||
stopRecording() { | |||
if (this.isRecording) { | |||
this.isRecording = false; | |||
this.recorder | |||
.stop() | |||
.getMp3() | |||
.then(([buffer, blob]) => { | |||
this.audioUrl = URL.createObjectURL(blob); | |||
console.log(this.audioUrl); | |||
}) | |||
.catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
go(url) { | |||
this.$router.push(url); | |||
}, | |||
@@ -181,11 +315,70 @@ export default { | |||
mounted() { | |||
this.inPage = true; | |||
scrollToID("top"); | |||
this.scrollToBottom(); | |||
}, | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.chatBoxAction { | |||
background-color: #fff; | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 0; | |||
padding: 15px 15px 33px 15px; | |||
// background-color: #fff; | |||
.showBody-bottom-speakDiv-text { | |||
margin-top: 4px; | |||
width: 286px; | |||
height: 34px; | |||
border-radius: 18px; | |||
background-color: #fff; | |||
border: 1px solid #666 !important; | |||
font-size: 14px; | |||
color: #999; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
::v-deep .el-textarea { | |||
padding-top: 5px; | |||
margin-right: 10px; | |||
width: 286px; | |||
.el-textarea__inner { | |||
resize: none; | |||
width: 286px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #666; | |||
background-color: transparent; | |||
font-size: 14px; | |||
white-space: pre-line; | |||
&::placeholder { | |||
color: #999; | |||
} | |||
} | |||
} | |||
} | |||
::v-deep .el-textarea { | |||
padding-top: 5px; | |||
margin-right: 10px; | |||
width: 286px; | |||
.el-textarea__inner { | |||
width: 286px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #fff; | |||
background-color: transparent; | |||
font-size: 14px; | |||
white-space: pre-line; | |||
&::placeholder { | |||
color: #fff; | |||
} | |||
} | |||
} | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
@@ -196,12 +389,11 @@ export default { | |||
} | |||
} | |||
.contnet { | |||
.head { | |||
display: flex; | |||
justify-content: space-between; | |||
padding: 4px 10px; | |||
>img { | |||
> img { | |||
width: 36px; | |||
height: 36px; | |||
} | |||
@@ -211,11 +403,11 @@ export default { | |||
height: 28px; | |||
text-align: center; | |||
line-height: 28px; | |||
background: #24A9FF; | |||
background: #24a9ff; | |||
color: #fff; | |||
box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.2); | |||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2); | |||
border-radius: 33px; | |||
>img { | |||
> img { | |||
margin-top: -2px; | |||
margin-right: 4px; | |||
} | |||
@@ -224,15 +416,17 @@ export default { | |||
.showBody { | |||
position: relative; | |||
width: 100%; | |||
height: calc(100vh - 44px) ; | |||
height: calc(100vh - 44px); | |||
background-color: red; | |||
&-bottom { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
display: flex; | |||
flex-direction: column; | |||
// height: 150px; | |||
padding-bottom: 33px; | |||
background: linear-gradient(180deg, rgba(0,0,0,0) 0%, #000000 100%); | |||
// padding-bottom: 33px; | |||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%); | |||
&-buttons { | |||
display: flex; | |||
justify-content: space-evenly; | |||
@@ -255,14 +449,34 @@ export default { | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0,0,0,0.3); | |||
background: rgba(0, 0, 0, 0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
&-speakDiv { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 0; | |||
padding: 15px 15px 33px 15px; | |||
// background-color: #fff; | |||
&-text { | |||
margin-top: 4px; | |||
width: 286px; | |||
height: 34px; | |||
border-radius: 18px; | |||
background-color: #fff; | |||
border: 1px solid #fff; | |||
font-size: 14px; | |||
color: #333; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
} | |||
} | |||
&-modelList { | |||
position: relative; | |||
display: flex; | |||
@@ -280,7 +494,7 @@ export default { | |||
width: 123px; | |||
height: 183px; | |||
border-radius: 8px; | |||
transition: all 0.5s; // | |||
transition: all 0.5s; // | |||
border: 3px solid #00ffe1; | |||
} | |||
.modelName { | |||
@@ -289,7 +503,7 @@ export default { | |||
left: 0; | |||
width: 48px; | |||
height: 28px; | |||
background: rgba(0,0,0,0.5); | |||
background: rgba(0, 0, 0, 0.5); | |||
border-radius: 8px 0px 8px 0px; | |||
color: #fff; | |||
font-size: 13px; | |||
@@ -299,10 +513,9 @@ export default { | |||
img { | |||
width: 120px; | |||
height: 180px; | |||
border-radius:8px 5px 5px 8px; | |||
border-radius: 8px 5px 5px 8px; | |||
} | |||
} | |||
} | |||
&-myCamera { | |||
position: absolute; | |||
@@ -310,15 +523,16 @@ export default { | |||
right: 0; | |||
width: 96px; | |||
height: 180px; | |||
background-image:url(../../assets/img/bg.png); | |||
background-image: url(../../assets/img/bg.png); | |||
background-size: contain; | |||
} | |||
&-chatBox { | |||
position: absolute; | |||
bottom: 0; | |||
// position: absolute; | |||
// bottom: 85px; | |||
width: 100%; | |||
height: 375px; | |||
background-color: #ECECEC; | |||
// height: 290px; | |||
background-color: #ececec; | |||
&-close { | |||
padding: 10px 15px; | |||
height: 35px; | |||
@@ -333,7 +547,8 @@ export default { | |||
} | |||
&-record { | |||
padding: 5px 10px 0; | |||
height: 255px; | |||
max-height: 255px; | |||
// height: 255px; | |||
overflow-y: scroll; | |||
font-size: 15px; | |||
color: #333333; | |||
@@ -342,23 +557,23 @@ export default { | |||
float: right; | |||
padding: 10px 20px; | |||
margin-bottom: 15px; | |||
background: #9EE445; | |||
background: #9ee445; | |||
border-radius: 20px 20px 2px 20px; | |||
clear: both; | |||
} | |||
.others { | |||
float: left; | |||
background: #FFFFFF; | |||
background: #ffffff; | |||
border-radius: 20px 20px 20px 2px; | |||
} | |||
} | |||
} | |||
&-global { | |||
position: absolute; | |||
bottom: 0; | |||
// position: absolute; | |||
// bottom: 85px; | |||
width: 100%; | |||
height: 385px; | |||
background-color: #ECECEC; | |||
height: 300px; | |||
background-color: #ececec; | |||
&-choose { | |||
padding: 20px 36px 0; | |||
height: 304px; | |||
@@ -383,14 +598,14 @@ export default { | |||
line-height: 70px; | |||
font-size: 14px; | |||
color: #333; | |||
border: 1px solid #ECECEC; | |||
border: 1px solid #ececec; | |||
} | |||
} | |||
&-btn { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 20px; | |||
>div { | |||
> div { | |||
width: 139px; | |||
height: 37px; | |||
border-radius: 31px; | |||
@@ -401,11 +616,11 @@ export default { | |||
} | |||
&-no { | |||
color: #333333; | |||
background: #FFFFFF; | |||
background: #ffffff; | |||
} | |||
&-yes { | |||
color: #FFFFFF; | |||
background: #24A9FF; | |||
color: #ffffff; | |||
background: #24a9ff; | |||
} | |||
} | |||
} | |||
@@ -413,10 +628,10 @@ export default { | |||
} | |||
} | |||
.showBody-modelList::-webkit-scrollbar { | |||
width:0; | |||
width: 0; | |||
} | |||
.showBody-chatBox-record::-webkit-scrollbar { | |||
width:0; | |||
width: 0; | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
@@ -425,7 +640,7 @@ export default { | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0,0,0,0.3); | |||
background: rgba(0, 0, 0, 0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
@@ -0,0 +1,648 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<!-- 页面内容 --> | |||
<div class="contnet"> | |||
<!-- 头部 --> | |||
<div class="head"> | |||
<img src="../../assets/icon/icon-loginout.png" alt="" /> | |||
<div class="head-exit"> | |||
<img src="../../assets/icon/icon-loginoutwhite.png" alt="" /> | |||
退出聊天 | |||
</div> | |||
</div> | |||
<!-- 显示模板区 --> | |||
<div class="showBody"> | |||
<!-- 底部渐变区 --> | |||
<div class="showBody-bottom"> | |||
<!-- 更换人物模板列表 --> | |||
<div v-show="PersonButtonAction" class="showBody-modelList"> | |||
<div | |||
v-for="(item, index) in modelList" | |||
:key="item.name" | |||
class="showBody-modelList-item" | |||
@click="modelItemAction = index" | |||
> | |||
<div class="modelName"> | |||
{{ item.name }} | |||
<div | |||
v-show="modelItemAction == index" | |||
class="showBody-modelList-item-boxBorder" | |||
></div> | |||
</div> | |||
<img :src="item.url" alt="" /> | |||
</div> | |||
</div> | |||
<!-- 四大按钮 --> | |||
<div v-show="!CloseChatAction&&!GlobalAction" class="showBody-bottom-buttons"> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div | |||
:class="{ buleBtn: PersonButtonAction }" | |||
class="defaultBtn" | |||
@click="clickPersonButton" | |||
> | |||
<img src="@/assets/icon/icon-person.png" alt="" /> | |||
</div> | |||
<p>更换人物模板</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div | |||
:class="{ buleBtn: CameraAction }" | |||
class="defaultBtn" | |||
@click="clickCameraButton" | |||
> | |||
<img src="@/assets/icon/icon-openCamera.png" alt="" /> | |||
</div> | |||
<p>摄像头开启</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div | |||
:class="{ buleBtn: CloseChatAction }" | |||
class="defaultBtn" | |||
@click="clickCloseChatButton" | |||
> | |||
<img src="@/assets/icon/icon-closeChat.png" alt="" /> | |||
</div> | |||
<p>对话框关闭</p> | |||
</div> | |||
<!-- --> | |||
<div class="showBody-bottom-buttons-item"> | |||
<div | |||
:class="{ buleBtn: GlobalAction }" | |||
class="defaultBtn" | |||
@click="clickGlobalButton" | |||
> | |||
<img src="@/assets/icon/icon-global.png" alt="" /> | |||
</div> | |||
<p>选择对话语言</p> | |||
</div> | |||
</div> | |||
<!-- 聊天框 --> | |||
<div v-show="CloseChatAction" class="showBody-chatBox"> | |||
<!-- 关闭 --> | |||
<div class="showBody-chatBox-close"> | |||
<i @click="CloseChatAction = false" class="el-icon-close"></i> | |||
</div> | |||
<!-- 聊天记录 --> | |||
<div ref="recordBox" class="showBody-chatBox-record"> | |||
<div | |||
class="showBody-chatBox-record-my" | |||
:class="{ others: item.form != 'me' }" | |||
v-for="(item, index) in chatRecordList" | |||
:key="index" | |||
> | |||
<span>{{ item.message }}</span> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 选择语言 --> | |||
<div v-show="GlobalAction" class="showBody-global"> | |||
<!-- --> | |||
<div class="showBody-global-choose"> | |||
<div class="showBody-global-choose-language"> | |||
<div | |||
class="showBody-global-choose-language-item" | |||
v-for="item in languageList" | |||
:key="item.type" | |||
> | |||
{{ item.type }} | |||
</div> | |||
</div> | |||
<div class="showBody-global-choose-btn"> | |||
<div | |||
@click="GlobalAction = false" | |||
class="showBody-global-choose-btn-no" | |||
> | |||
取消 | |||
</div> | |||
<div class="showBody-global-choose-btn-yes">确定</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 开麦和聊天输入 --> | |||
<div | |||
:class="{ chatBoxAction: CloseChatAction || GlobalAction }" | |||
class="showBody-bottom-speakDiv" | |||
> | |||
<!-- 没点麦克风 --> | |||
<el-input | |||
rows="1" | |||
type="textarea" | |||
:autosize="{ minRows: 1, maxRows: 4 }" | |||
maxlength="150" | |||
v-show="!speakingAction" | |||
class="" | |||
placeholder="点击语音按钮,快来跟我对话吧" | |||
v-model="chatInputContent" | |||
@keydown.enter.native="addMessageRecord()" | |||
></el-input> | |||
<div | |||
@click="speakingAction = !speakingAction" | |||
v-show="!speakingAction" | |||
class="defaultBtn buleBtn" | |||
> | |||
<img src="@/assets/icon/icon-microphone2.png" alt="" /> | |||
</div> | |||
<!-- 点了麦克风 --> | |||
<div | |||
v-show="speakingAction" | |||
class="showBody-bottom-speakDiv-text" | |||
@mousedown="startRecording" | |||
@mouseup="stopRecording" | |||
> | |||
按住说话 | |||
</div> | |||
<div | |||
@click="speakingAction = !speakingAction" | |||
v-show="speakingAction" | |||
class="defaultBtn buleBtn" | |||
> | |||
<img src="@/assets/icon/icon-speaking.png" alt="" /> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- 摄像头窗口 --> | |||
<div v-show="CameraAction" class="showBody-myCamera"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
// 组件 | |||
import Vue from "vue"; | |||
import { Toast } from "vant"; | |||
import { mapState, mapActions } from "vuex"; | |||
// 工具 | |||
import { scrollToID } from "../../utils"; | |||
Vue.use(Toast); | |||
export default { | |||
data() { | |||
return { | |||
inPage: false, | |||
PersonButtonAction: false, //个人按钮状态 | |||
CameraAction: false, // 摄像头按钮状态 | |||
CloseChatAction: false, // 聊天框按钮状态 | |||
GlobalAction: false, // 选择语言按钮状态 | |||
// speakingAction: false, // 底部是否说话按钮状态 | |||
modelList: [ | |||
{ name: "甘雨", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "莫甘娜", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "达尔文", url: require("../../assets/img/module_3_1.png") }, | |||
{ name: "雨果", url: require("../../assets/img/module_3_1.png") }, | |||
], // 人物模板列表 | |||
modelItemAction: -1, // 人物模板列表选中高亮 | |||
chatRecordList: [ | |||
{ | |||
form: "me", | |||
message: | |||
"生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1生于忧患死于安乐1", | |||
}, | |||
{ form: "you", message: "生于忧患死于安乐2" }, | |||
{ form: "me", message: "生于忧患死于安乐3" }, | |||
{ form: "you", message: "生于忧患死于安乐4" }, | |||
{ form: "me", message: "生于忧患死于安乐5" }, | |||
{ form: "me", message: "生于忧患死于安乐6" }, | |||
{ form: "me", message: " " }, | |||
], // 聊天记录列表 | |||
languageList: [ | |||
{ type: "AUTO" }, | |||
{ type: "璃月语" }, | |||
{ type: "JP语" }, | |||
{ type: "english" }, | |||
{ type: "中国话" }, | |||
{ type: "四川话" }, | |||
{ type: "东百话" }, | |||
{ type: "阿拉伯语" }, | |||
{ type: "朝鲜语" }, | |||
], //语种列表 | |||
recorder: null, | |||
isRecording: false, | |||
audioUrl: null, | |||
speakingAction: false, // 底部是否说话按钮状态 | |||
chatInputContent: "", // 输入框内容 | |||
}; | |||
}, | |||
computed: { | |||
...mapState({ | |||
characters: (state) => state.publicObj.characters, | |||
}), | |||
}, | |||
methods: { | |||
...mapActions(["setCharacters"]), | |||
// 点击个人按钮事件 | |||
clickPersonButton() { | |||
this.PersonButtonAction = !this.PersonButtonAction; | |||
}, | |||
// 点击摄像头按钮事件 | |||
clickCameraButton() { | |||
this.CameraAction = !this.CameraAction; | |||
}, | |||
// 点击聊天框按钮事件 | |||
clickCloseChatButton() { | |||
this.CloseChatAction = !this.CloseChatAction; | |||
}, | |||
// 点击语音按钮事件 | |||
clickGlobalButton() { | |||
this.GlobalAction = !this.GlobalAction; | |||
}, | |||
// 往聊天记录里添加内容 | |||
addMessageRecord() { | |||
if (this.chatInputContent) { | |||
console.log(this.chatInputContent); | |||
this.chatRecordList.push({ | |||
form: "me", | |||
message: this.chatInputContent, | |||
}); | |||
this.chatInputContent = ""; | |||
this.scrollToBottom(); | |||
} | |||
}, | |||
// 聊天页面滚动到页面最底端 | |||
scrollToBottom() { | |||
this.$nextTick(() => { | |||
// dom 元素更新后执行滚动条到底部 否则不生效 | |||
let scrollElem = this.$refs.recordBox; | |||
scrollElem.scrollTo({ | |||
top: scrollElem.scrollHeight, | |||
behavior: "smooth", | |||
}); | |||
}); | |||
}, | |||
// 开始录音 | |||
startRecording() { | |||
if (!this.isRecording) { | |||
this.isRecording = true; | |||
this.recorder | |||
.start() | |||
.then(() => { | |||
console.log("Recording started"); | |||
}) | |||
.catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
// 停止录音 | |||
stopRecording() { | |||
if (this.isRecording) { | |||
this.isRecording = false; | |||
this.recorder | |||
.stop() | |||
.getMp3() | |||
.then(([buffer, blob]) => { | |||
this.audioUrl = URL.createObjectURL(blob); | |||
console.log(this.audioUrl); | |||
}) | |||
.catch((err) => { | |||
console.log(err); | |||
}); | |||
} | |||
}, | |||
go(url) { | |||
this.$router.push(url); | |||
}, | |||
}, | |||
created() {}, | |||
mounted() { | |||
this.inPage = true; | |||
scrollToID("top"); | |||
this.scrollToBottom(); | |||
}, | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.chatBoxAction { | |||
background-color: #fff; | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 0; | |||
padding: 15px 15px 33px 15px; | |||
// background-color: #fff; | |||
.showBody-bottom-speakDiv-text { | |||
margin-top: 4px; | |||
width: 286px; | |||
height: 34px; | |||
border-radius: 18px; | |||
background-color: #fff; | |||
border: 1px solid #666 !important; | |||
font-size: 14px; | |||
color: #999; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
::v-deep .el-textarea { | |||
padding-top: 5px; | |||
margin-right: 10px; | |||
width: 286px; | |||
.el-textarea__inner { | |||
resize: none; | |||
width: 286px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #666; | |||
background-color: transparent; | |||
font-size: 14px; | |||
white-space: pre-line; | |||
&::placeholder { | |||
color: #999; | |||
} | |||
} | |||
} | |||
} | |||
::v-deep .el-textarea { | |||
padding-top: 5px; | |||
margin-right: 10px; | |||
width: 286px; | |||
.el-textarea__inner { | |||
width: 286px; | |||
height: 36px; | |||
border-radius: 18px; | |||
border: 1px solid #fff; | |||
background-color: transparent; | |||
font-size: 14px; | |||
white-space: pre-line; | |||
&::placeholder { | |||
color: #fff; | |||
} | |||
} | |||
} | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
transition: all 0.5s; // global-transition | |||
&.active { | |||
opacity: 1; | |||
transform: translateX(0); | |||
} | |||
} | |||
.contnet { | |||
.head { | |||
display: flex; | |||
justify-content: space-between; | |||
padding: 4px 10px; | |||
> img { | |||
width: 36px; | |||
height: 36px; | |||
} | |||
&-exit { | |||
margin-top: 4px; | |||
width: 97px; | |||
height: 28px; | |||
text-align: center; | |||
line-height: 28px; | |||
background: #24a9ff; | |||
color: #fff; | |||
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.2); | |||
border-radius: 33px; | |||
> img { | |||
margin-top: -2px; | |||
margin-right: 4px; | |||
} | |||
} | |||
} | |||
.showBody { | |||
position: relative; | |||
width: 100%; | |||
height: calc(100vh - 44px); | |||
background-color: red; | |||
&-bottom { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
display: flex; | |||
flex-direction: column; | |||
// height: 150px; | |||
// padding-bottom: 33px; | |||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%); | |||
&-buttons { | |||
display: flex; | |||
justify-content: space-evenly; | |||
padding: 0 20px; | |||
color: #fff; | |||
font-size: 10px; | |||
&-item { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
p { | |||
margin-top: 4px; | |||
} | |||
} | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0, 0, 0, 0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
&-speakDiv { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 0; | |||
padding: 15px 15px 33px 15px; | |||
// background-color: #fff; | |||
&-text { | |||
margin-top: 4px; | |||
width: 286px; | |||
height: 34px; | |||
border-radius: 18px; | |||
background-color: #fff; | |||
border: 1px solid #fff; | |||
font-size: 14px; | |||
color: #333; | |||
text-align: center; | |||
line-height: 34px; | |||
} | |||
} | |||
} | |||
&-modelList { | |||
position: relative; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
height: 200px; | |||
padding-left: 15px; | |||
overflow-x: scroll; | |||
&-item { | |||
position: relative; | |||
margin-right: 15px; | |||
&-boxBorder { | |||
position: absolute; | |||
top: -2px; | |||
width: 123px; | |||
height: 183px; | |||
border-radius: 8px; | |||
transition: all 0.5s; // | |||
border: 3px solid #00ffe1; | |||
} | |||
.modelName { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 48px; | |||
height: 28px; | |||
background: rgba(0, 0, 0, 0.5); | |||
border-radius: 8px 0px 8px 0px; | |||
color: #fff; | |||
font-size: 13px; | |||
line-height: 28px; | |||
text-align: center; | |||
} | |||
img { | |||
width: 120px; | |||
height: 180px; | |||
border-radius: 8px 5px 5px 8px; | |||
} | |||
} | |||
} | |||
&-myCamera { | |||
position: absolute; | |||
top: 0; | |||
right: 0; | |||
width: 96px; | |||
height: 180px; | |||
background-image: url(../../assets/img/bg.png); | |||
background-size: contain; | |||
} | |||
&-chatBox { | |||
position: absolute; | |||
bottom: 85px; | |||
width: 100%; | |||
height: 290px; | |||
background-color: #ececec; | |||
&-close { | |||
padding: 10px 15px; | |||
height: 35px; | |||
i { | |||
float: right; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
font-size: 16px; | |||
font-weight: 600; | |||
} | |||
} | |||
&-record { | |||
padding: 5px 10px 0; | |||
height: 255px; | |||
overflow-y: scroll; | |||
font-size: 15px; | |||
color: #333333; | |||
line-height: 21px; | |||
&-my { | |||
float: right; | |||
padding: 10px 20px; | |||
margin-bottom: 15px; | |||
background: #9ee445; | |||
border-radius: 20px 20px 2px 20px; | |||
clear: both; | |||
} | |||
.others { | |||
float: left; | |||
background: #ffffff; | |||
border-radius: 20px 20px 20px 2px; | |||
} | |||
} | |||
} | |||
&-global { | |||
position: absolute; | |||
bottom: 85px; | |||
width: 100%; | |||
height: 300px; | |||
background-color: #ececec; | |||
&-choose { | |||
padding: 20px 36px 0; | |||
height: 304px; | |||
overflow-y: scroll; | |||
font-size: 15px; | |||
color: #333333; | |||
line-height: 21px; | |||
&-language { | |||
display: flex; | |||
justify-content: start; | |||
flex-wrap: wrap; | |||
width: 300px; | |||
height: 210px; | |||
background-color: #fff; | |||
overflow: hidden; | |||
border: none; | |||
border-radius: 15px; | |||
&-item { | |||
width: 100px; | |||
height: 70px; | |||
text-align: center; | |||
line-height: 70px; | |||
font-size: 14px; | |||
color: #333; | |||
border: 1px solid #ececec; | |||
} | |||
} | |||
&-btn { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-top: 20px; | |||
> div { | |||
width: 139px; | |||
height: 37px; | |||
border-radius: 31px; | |||
text-align: center; | |||
line-height: 37px; | |||
font-size: 15px; | |||
font-weight: 600; | |||
} | |||
&-no { | |||
color: #333333; | |||
background: #ffffff; | |||
} | |||
&-yes { | |||
color: #ffffff; | |||
background: #24a9ff; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.showBody-modelList::-webkit-scrollbar { | |||
width: 0; | |||
} | |||
.showBody-chatBox-record::-webkit-scrollbar { | |||
width: 0; | |||
} | |||
.defaultBtn { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: center; | |||
align-items: center; | |||
width: 44px; | |||
height: 44px; | |||
background: rgba(0, 0, 0, 0.3); | |||
border-radius: 22px; | |||
img { | |||
width: 24px; | |||
height: 24px; | |||
} | |||
} | |||
</style> |