You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

622 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view>
<view class="submit" :style="{ bottom: keyboardHeight + 'px' }">
<view class="submit-chat">
<view class="bt-img" @tap="records">
<image :src="toc"></image>
</view>
<!-- 文本框 -->
<textarea :maxlength="-1" :auto-height="true" :adjust-position="false" confirm-type="send" :cursor-spacing="10"
:selection-start="selectionStart" :selection-end="selectionEnd" class="chat-send btnt" :class="{displaynone:isrecord}"
@confirm="sendMsg" @input="inputs" @focus="focus" v-model="msg"></textarea>
<view class="record btn":class="{displaynone:!isrecord}" @touchstart="touchstart" @touchend="touchend"
@touchmove="touchmove">
按住说话
</view>
<!-- <view class="bt-img" @tap="emoji">-->
<!-- <image src="../../static/icon/emote.png"></image>-->
<!-- </view>-->
<view v-if="ifmore" class="bt-img" @tap="more">
<image src="../../static/icon/more.png"></image>
</view>
<u-button v-if="!ifmore" @tap="sendMsg" style="background-color: #00a89b; width: 88rpx;color: #fff;border-radius: 10rpx;">发送</u-button>
</view>
<!-- 表情框 -->
<view class="emoji" :class="{displaynone:!isemoji}">
<view class="emoji-send">
<!-- <view class="emoji-send-det" @tap="emojiBack">
<image src="../../static/icon/emote.png"></image>
</view> -->
<view class="emoji-send-bt" @tap="emojiSend">发送</view>
</view>
<emoji @emotion="emotion" :height="260"></emoji>
</view>
<!-- -->
<view class="more" :class="{displaynone:!ismore}">
<view class="more-list" @tap="sendImg('album')">
<image src="../../static/icon/image.png"></image>
<view class="more-list-title">图片</view>
</view>
<view class="more-list" @tap="sendImg('camera')">
<image src="../../static/icon/photo.png"></image>
<view class="more-list-title">拍照</view>
</view>
<!-- <view class="more-list" @click="choseProduct('cart')">-->
<!-- <image src="../../static/icon/shopping_bag.png"></image>-->
<!-- <view class="more-list-title">商品</view>-->
<!-- </view>-->
<!-- <view class="more-list" @click="choseProduct('order')">-->
<!-- <image src="../../static/icon/order.png"></image>-->
<!-- <view class="more-list-title">订单</view>-->
<!-- </view>-->
<!-- <view class="more-list" @tap="choseLocation">
<image src="../../static/icon/location.png"></image>
<view class="more-list-title">定位</view>
</view> -->
<view class="more-list" @click="chooseVideo()">
<image src="../../static/icon/video.png"></image>
<view class="more-list-title">拍摄视频</view>
</view>
<!-- <view class="more-list">
<image src="../../static/icon/file.png"></image>
<view class="more-list-title">文件</view>
</view> -->
</view>
</view>
<view class="voice-bg" :class="{displaynone:!voicebg}">
<view class="voice-bg-len">
<view class="voice-bg-time" :style="{width:vlength/0.6+'%'}">
{{vlength<=50?60-vlength:60-vlength+'秒后自动发送'}}
</view>
<view class="voice-del">上滑取消录音</view>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
// 引入表情组件
import emoji from '../emoji/emoji.vue'
// 录音
const recorderManager = uni.getRecorderManager();
export default {
components: {
emoji,
},
data() {
return {
isrecord: false,
isemoji: false,
ismore: false,
ifmore: true,
voicebg: false,
pageY: 0,
keyboardHeight:0,
msg: "",
// 直接引用地址可能出不来需要用require
toc: require('../../static/icon/voice.png'),
timer: '', //计时器
vlength: 0,
selectionStart: 0,
selectionEnd: 0
};
},
methods: {
//获取高度方法
getElementHeight() {
// if (this.heightTimer ) clearTimeout(this.heightTimer);
// this.heightTimer = setTimeout(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.submit').boundingClientRect(data => {
if (data) {
this.$emit('heights', data.height);
}
}).exec();
// }, 30);
},
//切换音频
records() {
//切换的时候关闭其他界面
this.ismore = false
this.isemoji = false
//切换高度
setTimeout(() => {
this.getElementHeight();
})
if (this.isrecord) {
this.isrecord = false;
this.toc = require("../../static/icon/voice.png");
} else {
this.isrecord = true;
this.toc = require("../../static/icon/keyboard.png");
}
},
// 表情
emoji() {
console.log('emoji')
this.isemoji = !this.isemoji;
//切换的时候关闭其功能
this.ismore = false
this.isrecord = false;
this.toc = require("../../static/icon/voice.png");
//切换高度
setTimeout(() => {
this.getElementHeight();
})
},
//接收表情
emotion(e) {
console.log(e),
this.msg = this.msg + e
},
//文字发送
sendMsg(e) {
// 若为键盘事件,可忽略 e.detail.value直接使用 this.msg
if (this.msg.trim().length > 0) {
// 发送文本消息事件,供父组件处理
this.$emit('send-message', {
content: this.msg,
type: 'txt'
});
// 清空输入框
this.msg = '';
this.ifmore = true;
// 同时保留原 inputs 事件以兼容旧页面(可选)
// this.$emit('inputs', { message: this.msg, type: 'txt' });
}
},
inputs(e) {
var chatm = e.detail.value;
if (chatm.length > 0) {
this.ifmore=false;
}
else{
this.ifmore=true;
}
},
updateCursor() {
// 当 text 改变时,将光标移动到最后
this.selectionStart = this.msg.length;
this.selectionEnd = this.msg.length;
},
// 输入框聚焦
focus() {
console.log('focus');
//关闭其他项
// this.isemoji = false;
if (this.ismore){
this.ismore = false;
}
},
// 表情内发送
emojiSend() {
if (this.msg.trim().length > 0) {
this.$emit('send-message', {
content: this.msg,
type: 'txt'
});
this.msg = '';
}
},
// 表格退格
emojiBack() {
if (this.msg.length > 0) {
this.msg = this.msg.substring(0, this.msg.length - 1);
}
},
//更多功能
more() {
console.log('more')
this.ismore = !this.ismore;
//切换的时候关闭其他界面
this.isemoji = false
this.isrecord = false;
this.toc = require("../../static/icon/voice.png");
this.$nextTick(() => {
this.getElementHeight();
})
},
choseProduct(type){
if (type==='order'){
//订单
}else {
//购物车商品
}
},
// 视频录像
chooseVideo(){
var that =this;
uni.chooseVideo({
sourceType: ['camera', 'album'],
maxDuration: 60, // 最大视频录制时长(秒)
success: function (res) {
console.log('选择视频成功,返回的参数:', res);
// 可以使用 res.tempFilePath 获取视频的本地路径
const filePath = res.tempFilePath;
console.log(filePath);
that.checkImageSize(filePath,2);
},
fail: function (err) {
console.error('选择视频失败:', err);
}
});
},
//图片发送
sendImg(e) {
var that =this;
let count = 9;
if (e == 'album') {
count = 9;
} else {
count = 1;
}
uni.chooseImage({
count: count, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: [e], //从相册选择
// success: function (res) { //用function的方式会找不到send方法
success: (res) => {
console.log(JSON.stringify(res.tempFilePaths));
const filePaths = res.tempFilePaths;
for (let i = 0; i < filePaths.length; i++) {
that.checkImageSize(filePaths[i],1);
}
}
});
},
checkImageSize(filePath,type) {
var that = this;
uni.getFileInfo({
filePath: filePath,
success: function (res) {
console.log('文件大小(字节):', res.size);
if(type==1){
// 图片
if (res.size > 2*1024*1024) { // 例如这里检查文件大小是否超过20MB
console.log('文件过大');
// 可以根据需要处理文件过大的情况,比如提示用户
that.$refs.uToast.show({
title: "图片大小不能超过2M...",
type: "error",
duration: 2000,
});
} else {
console.log('文件大小合适');
// 处理正常的文件大小情况
that.send(filePath, 'image');
}
}
else if(type==2){
// 视频
if (res.size > 10*1024*1024) { // 例如这里检查文件大小是否超过20MB
console.log('文件过大');
// 可以根据需要处理文件过大的情况,比如提示用户
that.$refs.uToast.show({
title: "视频大小不能超过10M...",
type: "error",
duration: 2000,
});
} else {
console.log('文件大小合适');
// 处理正常的文件大小情况
that.send(filePath, 'video');
}
}
},
fail: function (err) {
console.error('获取文件信息失败:', err);
if(type==1){
that.$refs.uToast.show({
title: "图片大小不能超过2M...",
type: "error",
duration: 2000,
});
}
else if(type==1){
that.$refs.uToast.show({
title: "视频大小不能超过10M...",
type: "error",
duration: 2000,
});
}
}
});
},
//音频处理
//开始录音
touchstart(e) {
console.log("开始录音")
console.log("点击产生数据", e)
this.pageY = e.changedTouches[0].pageY;
this.voicebg = true;
let i = 1;
this.timer = setInterval(() => {
this.vlength = i;
i++;
//结束计时
if (i >= 60) {
this.touchend();
}
}, 1000)
if (!recorderManager || typeof recorderManager.start !== 'function') {
uni.showToast({ title: '当前环境不支持录音', icon: 'none' });
return;
}
recorderManager.start();
},
//删除录音
touchmove(e) {
// console.log("滑动到的y轴高度",e.changedTouches[0].pageY);
if (this.pageY - e.changedTouches[0].pageY > 100) {
// 关闭录音界面
this.voicebg = false;
}
},
// 结束录音
touchend() {
console.log("结束录音")
clearInterval(this.timer);
recorderManager.stop();
// recorderManager.onStop(function(res) {
recorderManager.onStop((res) => {
if(this.vlength<1){
this.$refs.uToast.show({
title: "...",
type: "warning",
duration: 2000,
});
}
else{
let data = {
voice: res.tempFilePath,
time: this.vlength
}
if (this.voicebg) {
this.send(data, 'audio');
}
}
// //
this.vlength = 0;
this.voicebg = false;
console.log('recorder stop' + JSON.stringify(res));
// self.voicePath = res.tempFilePath;
});
},
//
choseLocation() {
uni.chooseLocation({
// success: function(res) {
success: res => {
let data = {
name: res.name,
address: res.address,
latitude: res.latitude,
longitude: res.longitude
}
this.send(data, 3);
// console.log('位置名称:' + res.name);
// console.log('详细地址:' + res.address);
// console.log('纬度:' + res.latitude);
// console.log('经度:' + res.longitude);
}
});
},
//发送
send(data, type) {
// 对于图片/视频data 为文件路径对于音频data 为 { voice, time }
this.$emit('send-message', {
content: data,
type: type // 'image', 'video', 'audio', 'location' 等
});
// 如果还需保留旧的 inputs 事件(兼容其他页面),可保留:
// this.$emit('inputs', { message: data, type: type });
},
/**
* 关闭所有弹出面板(表情、更多),并收起键盘
*/
closeAll() {
var flag =this.ismore || this.isrecord;
this.ismore = false;
this.isrecord = false; // 如果录音面板开着,也关闭
this.toc = require("../../static/icon/voice.png");
uni.hideKeyboard(); // 强制收起键盘
// 重新计算高度(通知父组件)
if (flag){
this.$nextTick(() => {
this.getElementHeight(); // 确保 DOM 更新后测量
});
}
}
}
};
</script>
<style lang="scss" scoped>
.submit {
background: rgba(244, 244, 244, 0.96);
border-top: 1px solid rgba(39, 40, 50, 0.1);
width: 100%;
position: fixed;
bottom: 0;
z-index: 999;
//padding-bottom: var(--status-bar-height);
padding-bottom: env(safe-area-inset-bottom);
}
.displaynone {
display: none;
}
.submit-chat {
width: 100%;
display: flex;
align-items: flex-end;
box-sizing: border-box;
padding: 14rpx;
image {
width: 60rpx;
height: 60rpx;
margin: 0 8rpx;
flex: auto;
}
.btnt {
flex: auto;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
max-height: 240rpx;
margin: 0 10rpx;
overflow-y: auto;
}
.btn {
flex: auto;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
max-height: 160rpx;
margin: 0 10rpx;
}
.chat-send {
line-height: 44rpx;
}
.record {
line-height: 44rpx;
text-align: center;
font-size: 24rpx;
color: rgba(39, 40, 50, 0.6);
}
}
.emoji {
width: 100%;
height: 460rpx;
background: rgba(236, 237, 238, 1);
box-shadow: 0px 11rpx 0px 0px rgba(0, 0, 0, 0.1);
.emoji-send {
width: 150rpx;
height: 104rpx;
padding-top: 24rpx;
background-color: rgba(236, 237, 238, 0.8);
position: fixed;
// bottom: 0;
bottom: env(safe-area-inset-bottom);
right: 0;
display: flex;
.emoji-send-bt {
flex: 1;
margin: 0 32rpx 0 20rpx;
height: 80rpx;
background: rgba(255, 228, 49, 1);
font-size: 32rpx;
text-align: center;
line-height: 80rpx;
border-radius: 12rpx;
}
.emoji-send-det {
flex: 1;
margin-left: 24rpx;
height: 80rpx;
background: #fff;
font-size: 32rpx;
text-align: center;
line-height: 80rpx;
border-radius: 12rpx;
image {
width: 42rpx;
height: 32rpx;
}
}
}
}
.more {
width: 100%;
min-height: 220rpx;
background: rgba(236, 237, 238, 1);
box-shadow: 0px 11rpx 0px 0px rgba(0, 0, 0, 0.1);
bottom: env(safe-area-inset-bottom);
padding: 8rpx 20rpx;
box-sizing: border-box;
.more-list {
width: 25%;
text-align: center;
float: left;
padding-top: 32rpx;
image {
width: 90rpx;
height: 90rpx;
padding: 24rpx;
background: rgba(255, 255, 255, 1);
border-radius: 24rpx;
}
.more-list-title {
font-size: 24rpx;
color: rgba(39, 40, 50, 0.5);
line-height: 34rpx;
}
}
}
.voice-bg {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
bottom: 0;
z-index: 1001;
.voice-bg-len {
height: 84rpx;
width: 600rpx;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 42rpx;
text-align: center;
}
.voice-bg-time {
display: inline-block;
min-width: 120rpx;
line-height: 84rpx;
background-color: #00a89b;
border-radius: 42rpx;
color:#ffffff;
}
.voice-del {
position: absolute;
bottom: -480rpx;
width: 100%;
text-align: center;
color: #fff;
font-size: 28rpx;
}
}
</style>