Files
dvcp_v2_wxcp_app/src/project/biaopin/AppVillageHead/AppVillageHead.vue
liuye 13ca5516ef bug
2024-01-09 15:23:44 +08:00

475 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="AppVillageHead">
<!-- <div class="statistics-content">
<div class="title">2024年1月12日居民群日报</div>
<div class="mini-title">
<span></span>宣发情况
</div>
<div class="info">宣发数据<span>4</span></div>
<div class="info">宣发内容燃气安全交通安全天气情況春节倒计时信息</div>
<div class="flex-info">
<div class="info">触达居民群数<span>821</span></div>
<div class="info">触达居民<span>8762</span></div>
</div>
<div class="mini-title">
<span></span>AI问答
</div>
<div class="flex-info">
<div class="info">居民累计提问<span>2456</span></div>
<div class="info">群提问数<span>8</span>/</div>
</div>
<div class="flex-info">
<div class="info">最活跃群提问<span>821</span></div>
<div class="info">活跃居民<span>21</span></div>
</div>
<div class="info">居民热点话题交通天气红包吃什么活动拜年</div>
</div> -->
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scroll="scroll" v-if="messageList.length" :style="{height: scrollHeight+'px'}">
<div class="list-content">
<div :class="item.userType == 1 ? 'item-left' : 'item-right'" v-for="(item, index) in messageList" :key="index">
<div class="item" :class="'item'+index">
<div class="img-div" v-if="item.sdkFileUrl">
<u-icon name="play-circle" :color="item.userType == 0 ? '#fff' : '#A8ADAE'" size="52" v-if="!item.isPlay" @click="play(item.sdkFileUrl, index)"></u-icon>
<u-icon name="pause-circle" :color="item.userType == 0 ? '#fff' : '#A8ADAE'" size="52" v-else @click="playStop(index)"></u-icon>
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/recording-white.png" alt="" v-if="item.userType == 0">
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/recording-gray.png" alt="" v-else>
</div>
<p>{{item.content || ''}}</p>
</div>
</div>
</div>
</scroll-view>
<AiEmpty description="暂无数据" v-if="!messageList.length"/>
<div class="fixed-bottom">
<div class="type-text" v-if="type == 'text'">
<u-input type="text" placeholder="输入您的问题…" height="80" input-align="left" :clearable="false" :border="true" placeholder-style="color:#666;" v-model="content"></u-input>
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/send.png" alt="" v-if="content.length" @click="sendMsg">
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/microphone-btn.png" alt="" v-else @click="microPhone">
</div>
<div class="type-record" v-else>
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/keyboard-btn.png" alt="" class="keyboard-btn" @click="keyboardClick">
<div v-if="!isStart" @click="startRecord">
<p>点击开始录音</p>
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/record-btn.png" alt="" class="record-btn">
</div>
<div v-else @click="endRecord">
<p>正在录音中</p>
<div class="tips-text">点击下方停止录音</div>
<img src="https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/shengbo.gif" alt="" class="recording">
</div>
</div>
</div>
</div>
</template>
<script>
import {mapState} from "vuex";
import Recorder from 'recorder-core'
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'
const innerAudioContext = uni.createInnerAudioContext();
export default {
name: 'AppVillageHead',
appName: '村长coplite',
data() {
return {
recorder: null,
type: 'text',
isStart: false,
content: '',
isFlag: false,
voiceUrl: 'http://test87ftp.cunwuyun.cn/20240109/filename-20240109111547.mp3',
voiceId: '0678a73c50b74bdcb8398e14ffbb35e5',
messageList: [
// {
// userType: 0,
// sdkFileUrl: 'http://test87ftp.cunwuyun.cn/20240104/output.mp3',
// isPlay: false
// }
],
current: 1,
pages: 2,
scrollTop: 0,
scrollHeight: '',
preveHeight: '',
}
},
computed: {
...mapState(['user']),
},
onLoad() {
this.scrollHeight = uni.getSystemInfoSync().windowHeight
this.getHistoryList()
// var res = ["http://test87ftp.cunwuyun.cn/20240109/filename-20240109111547.mp3;0678a73c50b74bdcb8398e14ffbb35e5"]
// this.voiceUrl = res[0].split(';')[0]
// this.voiceId = res[0].split(';')[1]
// this.sendVoice()
},
onShow() {
document.title = '村长copilot'
},
methods: {
startRecord() {
this.isStart = true
this.recorder = Recorder({
type: 'mp3',
sampleRate: 16000,
bitRate: 16
})
this.recorder.open(() => {
this.recorder.start()
})
},
endRecord() {
this.recorder.stop((blob) => {
var formData = new FormData();
formData.append('file', blob, 'filename.mp3');
this.$http.post('/admin/file/add', formData, {
withoutToken: true,
}).then((res) => {
uni.hideLoading()
if (res?.data) {
this.voiceUrl = res.data[0].split(';')[0]
this.voiceId = res.data[0].split(';')[1]
this.isStart = false
this.sendVoice()
}
}).catch(res => {
this.$u.toast(res)
uni.hideLoading()
})
this.recorder.close()
this.recorder = null
}, msg => {
console.log('录音失败:' + msg)
this.recorder.close()
this.recorder = null
})
},
microPhone() {
this.type = 'voice'
this.isStart = false
},
keyboardClick() {
if(this.isStart) return
this.type = 'text'
this.content = ''
},
scroll(e) {
if(e.detail.scrollTop == 0) {
if(this.current > this.pages) {
return this.$u.toast('已加载完成,没有更多数据')
}else {
this.current ++
this.getHistoryList()
}
}
},
sendMsg() {
this.$loading()
this.$http.post("/app/appaigccopilotinfo/add", {content: this.content, appType: 1}).then(res => {
if(res.code == 0) {
this.content = ''
this.messageList.push(res.data[0])
this.messageList.push(res.data[1])
this.$nextTick(() => {
uni.createSelectorQuery().select(".list-content").boundingClientRect((res) => {
this.scrollTop = res.height - this.scrollHeight
}).exec();
})
this.$hideLoading()
}
})
},
sendVoice() {
this.$loading()
this.$http.post("/app/appaigccopilotinfo/add", {sdkFileUrl: this.voiceUrl, fileId: this.voiceId, appType: 1}).then(res => {
if(res.code == 0) {
this.voiceUrl = ''
this.voiceId = ''
res.data.map((item) => {
if(item.sdkFileUrl) {
item.isPlay = false
}
})
this.messageList.push(res.data[0])
this.messageList.push(res.data[1])
this.$nextTick(() => {
uni.createSelectorQuery().select(".list-content").boundingClientRect((res) => {
this.scrollTop = res.height - this.scrollHeight
}).exec();
})
this.$hideLoading()
}
})
},
getHistoryList() {
this.$loading()
uni.createSelectorQuery().select(".list-content").boundingClientRect((res) => {
this.preveHeight = res.height
}).exec();
this.$http.post(`/app/appaigccopilotinfo/list?current=${this.current}&size=10`).then(res => {
if(res.code == 0 && res.data.records.length) {
res.data.records.map((item) => {
if(item.sdkFileUrl) {
item.isPlay = false
}
})
this.messageList = this.current == 1 ? res.data.records : [...res.data.records, ...this.messageList]
this.pages = res.data.pages
this.$nextTick(() => {
uni.createSelectorQuery().select(".list-content").boundingClientRect((res) => {
if(this.current == 1) {
this.scrollTop = res.height - this.scrollHeight
}else {
this.scrollTop = res.height - this.preveHeight
}
}).exec();
})
this.$hideLoading()
}
})
},
play(src, index) {
innerAudioContext.stop();
this.messageList.map((item) => {
if(item.sdkFileUrl) {
item.isPlay = false
}
})
this.messageList[index].isPlay = true
innerAudioContext.src = src;
this.$nextTick(() => {
innerAudioContext.play();
})
innerAudioContext.onEnded(() => {
this.messageList[index].isPlay = false
})
},
playStop(index) {
innerAudioContext.stop();
innerAudioContext.onStop(() => {
this.messageList[index].isPlay = false
})
}
},
}
</script>
<style lang="scss" scoped>
.AppVillageHead {
height: 100vh;
// padding-top: 32px;
background-color: #fff;
.service-content {
width: 100%;
height: 420px;
background-image: url("https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/content-top-bg.png");
background-size: 100vw;
background-repeat: no-repeat;
padding-top: 20px;
box-sizing: border-box;
.text-content {
margin: 0 0 0 32px;
width: 686px;
height: 260px;
background-image: url("https://cdn.cunwuyun.cn/wechat/biaopin/residentAssistant/service-content-bg.png");
background-size: 100vw;
background-repeat: no-repeat;
padding: 32px;
box-sizing: border-box;
border-radius: 32px;
display: flex;
justify-content: space-between;
.text-left {
width: calc(100% - 192px);
div {
line-height: 54px;
font-family: SourceHanSansCN-Bold;
font-weight: 700;
font-size: 36px;
background: linear-gradient(to bottom, #2A6EE9, #58A5F7);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 16px;
}
p {
color: #222;
font-size: 28px;
font-family: SourceHanSansCN;
line-height: 44px;
span {
display: inline-block;
font-weight: 700;
}
}
}
.service-img {
display: inline-block;
width: 192px;
height: 170px;
}
}
}
.statistics-content {
width: 686px;
background: #F1F4F8;
border-radius: 12px 12px 12px 0;
padding: 32px;
box-sizing: border-box;
color: #222;
margin: 0 0 32px 32px;
.title {
line-height: 44px;
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 32px;
margin-bottom: 24px;
}
.mini-title {
line-height: 44px;
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 32px;
margin-bottom: 16px;
span {
display: inline-block;
width: 8px;
height: 32px;
background: #3975C6;
border-radius: 4px;
margin-right: 16px;
vertical-align: middle;
}
}
.info {
font-size: 28px;
font-family: PingFangSC;
line-height: 40px;
margin-bottom: 18px;
span {
color: #0D63F2;
}
}
.flex-info {
display: flex;
justify-content: space-between;
}
}
.list-content {
padding: 32px 32px 364px;
overflow: hidden;
background-color: #fff;
.item {
max-width: 600px;
border-radius: 24px 24px 0 24px;
padding: 24px 32px;
box-sizing: border-box;
margin-bottom: 32px;
.img-div {
margin-bottom: 4px;
img {
width: 136px;
height: 28px;
margin-left: 26px;
}
}
p {
word-break: break-all;
line-height: 48px;
font-family: SourceHanSansCN-Regular;
font-size: 32px;
}
}
.item-right {
display: flex;
justify-content: flex-end;
.item {
background-image: linear-gradient(-76deg, #569EF0 0%, #276FEC 100%);
}
p {
color: #fff;
}
}
.item-left {
.item {
background-color: #F1F4F8;
}
p {
color: #222;
}
}
}
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding-bottom: 64px;
border-top: 1px solid #eee;
background-color: #fff;
.type-text {
padding: 24px 0 24px 32px;
display: flex;
.u-input {
width: calc(100% - 112px);
height: 80px;
background: #F4F6FA;
border-radius: 40px;
padding-left: 32px;
border-radius: 40px;
box-sizing: border-box;
}
img {
width: 80px;
height: 80px;
padding: 0 16px;
}
}
.type-record {
position: relative;
text-align: center;
padding-top: 36px;
.keyboard-btn {
width: 48px;
height: 36px;
position: absolute;
top: 32px;
right: 32px;
}
p {
line-height: 58px;
font-family: SourceHanSansCN-Medium;
font-weight: 500;
font-size: 40px;
color: #222;
}
.record-btn {
width: 156px;
height: 156px;
margin-top: 24px;
}
.tips-text {
line-height: 40px;
font-family: SourceHanSansCN-Regular;
font-size: 28px;
color: #999;
margin-top: 16px;
}
.recording {
padding-top: 48px;
width: 204px;
height: 96px;
}
}
}
}
</style>