2025-11-07 09:56:20 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view>
|
2025-12-09 09:27:29 +08:00
|
|
|
|
<view class="chat_footer">
|
|
|
|
|
|
<!-- 语音信息 -->
|
|
|
|
|
|
<image v-if="1==2" v-show="!isAudio" @click.prevent="isAudio=!isAudio" src="@/static/images/chating_footer_audio.png" alt="" srcset="" />
|
|
|
|
|
|
<image v-if="1==2" v-show="isAudio" @click.prevent="isAudio=!isAudio" src="@/static/images/chating_footer_audio_recording.png" alt="" srcset="" />
|
|
|
|
|
|
<view class="input_content">
|
|
|
|
|
|
<!-- #ifdef APP-PLUS -->
|
|
|
|
|
|
<view v-if="isAudio" class="voice_title" @touchstart.stop.prevent="startVoice"
|
|
|
|
|
|
@touchmove.stop.prevent="moveVoice" @touchend.stop="endVoice"
|
|
|
|
|
|
@touchcancel.stop="cancelVoice" :style="{ background: recording ? '#c7c6c6' : '#FFFFFF' }">
|
|
|
|
|
|
<text>{{ voiceTitle }}</text>
|
2025-11-07 09:56:20 +08:00
|
|
|
|
</view>
|
2025-12-09 09:27:29 +08:00
|
|
|
|
<!-- #endif -->
|
|
|
|
|
|
<!-- 使用 SimpleEditor 替代 CustomEditor,更简单可靠 -->
|
|
|
|
|
|
<SimpleEditor
|
|
|
|
|
|
v-if="!isAudio"
|
|
|
|
|
|
class="custom_editor"
|
|
|
|
|
|
ref="customEditor"
|
|
|
|
|
|
:value="inputHtml"
|
|
|
|
|
|
@focus="editorFocus"
|
|
|
|
|
|
@blur="editorBlur"
|
|
|
|
|
|
@input="editorInput" />
|
|
|
|
|
|
</view>
|
2025-11-07 09:56:20 +08:00
|
|
|
|
|
2025-12-09 09:27:29 +08:00
|
|
|
|
<view class="footer_action_area" v-show="!isAudio">
|
|
|
|
|
|
<image class="emoji_action" @click.prevent="updateActionBar(true)" src="@/static/images/chating_footer_emoji.png" alt="" srcset="" />
|
|
|
|
|
|
<image v-show="!hasContent" @click.prevent="updateActionBar(false)" src="@/static/images/chating_footer_add.png" alt="" srcset="" />
|
|
|
|
|
|
<button class="send_btn" type="primary" v-show="hasContent" @touchend.prevent="sendTextMessage">发送</button>
|
2025-11-07 09:56:20 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-12-11 22:33:31 +08:00
|
|
|
|
<chating-action-bar
|
|
|
|
|
|
:isEmoji="isEmoji"
|
2025-12-09 09:27:29 +08:00
|
|
|
|
@onUserEvent="onUserEvent"
|
|
|
|
|
|
v-show="actionBarVisible" />
|
|
|
|
|
|
<u-action-sheet :safeAreaInsetBottom="true" round="12" :actions="actionSheetMenu" @select="selectClick"
|
|
|
|
|
|
:closeOnClickOverlay="true" :closeOnClickAction="true" :show="showActionSheet"
|
|
|
|
|
|
@close="showActionSheet = false">
|
|
|
|
|
|
</u-action-sheet>
|
2025-12-02 03:05:52 +08:00
|
|
|
|
<!-- 录音动画 -->
|
|
|
|
|
|
<!-- #ifdef APP-PLUS -->
|
|
|
|
|
|
<view class="voice_an" v-if="recording">
|
|
|
|
|
|
<view class="voice_an_icon">
|
|
|
|
|
|
<view id="one" class="wave"></view>
|
|
|
|
|
|
<view id="two" class="wave"></view>
|
|
|
|
|
|
<view id="three" class="wave"></view>
|
|
|
|
|
|
<view id="four" class="wave"></view>
|
|
|
|
|
|
<view id="five" class="wave"></view>
|
|
|
|
|
|
<view id="six" class="wave"></view>
|
|
|
|
|
|
<view id="seven" class="wave"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="text">
|
|
|
|
|
|
<text>{{voiceIconText}}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- #endif -->
|
2025-11-07 09:56:20 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2025-11-25 05:36:02 +08:00
|
|
|
|
import {mapGetters,mapActions} from "vuex";
|
2025-12-11 22:33:31 +08:00
|
|
|
|
import {getPurePath,html2Text,getVideoCover,getVideoInfo} from "@/util/common";
|
2025-11-25 05:36:02 +08:00
|
|
|
|
import {offlinePushInfo} from "@/util/imCommon";
|
|
|
|
|
|
import {ChatingFooterActionTypes,UpdateMessageTypes,} from "@/constant";
|
|
|
|
|
|
import IMSDK, {IMMethods,MessageStatus,MessageType,} from "openim-uniapp-polyfill";
|
2025-12-09 09:27:29 +08:00
|
|
|
|
//import UParse from "@/components/gaoyia-parse/parse.vue";
|
2025-12-08 18:10:51 +08:00
|
|
|
|
import CustomEditor from "./CustomEditor";
|
2025-12-09 09:27:29 +08:00
|
|
|
|
import SimpleEditor from "./SimpleEditor";
|
2025-12-08 18:10:51 +08:00
|
|
|
|
import ChatingActionBar from "./ChatingActionBar";
|
2025-11-07 09:56:20 +08:00
|
|
|
|
|
|
|
|
|
|
const needClearTypes = [MessageType.TextMessage];
|
|
|
|
|
|
|
2025-11-25 05:36:02 +08:00
|
|
|
|
const rtcChoose = [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "视频通话",
|
2025-12-11 22:33:31 +08:00
|
|
|
|
type: 'video',
|
2025-11-07 09:56:20 +08:00
|
|
|
|
idx: 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
2025-11-25 05:36:02 +08:00
|
|
|
|
name: "语言通话",
|
2025-12-11 22:33:31 +08:00
|
|
|
|
type: 'voice',
|
2025-11-07 09:56:20 +08:00
|
|
|
|
idx: 1,
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
components: {
|
|
|
|
|
|
CustomEditor,
|
2025-12-09 09:27:29 +08:00
|
|
|
|
SimpleEditor,
|
2025-11-07 09:56:20 +08:00
|
|
|
|
ChatingActionBar,
|
2025-12-09 09:27:29 +08:00
|
|
|
|
//UParse,
|
2025-11-07 09:56:20 +08:00
|
|
|
|
},
|
|
|
|
|
|
props: {
|
|
|
|
|
|
footerOutsideFlag: Number,
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
2025-12-02 03:05:52 +08:00
|
|
|
|
recording:false,
|
|
|
|
|
|
sendMsgTimmer: null, //发送时间定时器
|
|
|
|
|
|
sendDuring: 0, //发送时间计数器 1分钟以内的信息不显示时间
|
|
|
|
|
|
sendTimeBetween: 60, //发送信息显示的间隔,60秒以内信息不显示发送时间
|
|
|
|
|
|
isEmoji:false,
|
|
|
|
|
|
isAudio:false,
|
2025-11-07 09:56:20 +08:00
|
|
|
|
inputHtml: "",
|
|
|
|
|
|
actionBarVisible: false,
|
|
|
|
|
|
isInputFocus: false,
|
|
|
|
|
|
actionSheetMenu: [],
|
|
|
|
|
|
showActionSheet: false,
|
2025-12-09 09:27:29 +08:00
|
|
|
|
isInsertingEmoji: false, // 标记是否正在插入表情
|
2025-12-11 22:33:31 +08:00
|
|
|
|
|
|
|
|
|
|
fileSelectedArray:[]
|
2025-11-07 09:56:20 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
|
|
|
|
|
...mapGetters([
|
|
|
|
|
|
"storeCurrentConversation",
|
|
|
|
|
|
"storeCurrentGroup",
|
|
|
|
|
|
"storeBlackList",
|
|
|
|
|
|
]),
|
|
|
|
|
|
hasContent() {
|
|
|
|
|
|
return html2Text(this.inputHtml) !== "";
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
footerOutsideFlag(newVal) {
|
|
|
|
|
|
this.onClickActionBarOutside();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
|
|
|
this.setKeyboardListener();
|
|
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
this.disposeKeyboardListener();
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
...mapActions("message", ["pushNewMessage", "updateOneMessage"]),
|
|
|
|
|
|
async createTextMessage() {
|
|
|
|
|
|
let message = "";
|
|
|
|
|
|
const text = html2Text(this.inputHtml);
|
|
|
|
|
|
message = await IMSDK.asyncApi(
|
|
|
|
|
|
IMMethods.CreateTextMessage,
|
|
|
|
|
|
IMSDK.uuid(),
|
|
|
|
|
|
text
|
|
|
|
|
|
);
|
|
|
|
|
|
console.log(message);
|
|
|
|
|
|
return message;
|
|
|
|
|
|
},
|
|
|
|
|
|
async sendTextMessage() {
|
|
|
|
|
|
if (!this.hasContent) return;
|
|
|
|
|
|
const message = await this.createTextMessage();
|
2025-12-05 16:10:52 +08:00
|
|
|
|
this.sendMessage(message,this.storeCurrentConversation.userID,this.storeCurrentConversation.groupID);
|
2025-11-07 09:56:20 +08:00
|
|
|
|
},
|
2025-12-05 16:10:52 +08:00
|
|
|
|
sendMessage(message,user_id,group_id) {
|
2025-11-07 09:56:20 +08:00
|
|
|
|
this.pushNewMessage(message);
|
|
|
|
|
|
if (needClearTypes.includes(message.contentType)) {
|
2025-12-09 09:27:29 +08:00
|
|
|
|
this.$refs.customEditor.clear();
|
2025-11-07 09:56:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
this.$emit("scrollToBottom");
|
|
|
|
|
|
IMSDK.asyncApi(IMMethods.SendMessage, IMSDK.uuid(), {
|
2025-12-05 16:10:52 +08:00
|
|
|
|
recvID: user_id,
|
|
|
|
|
|
groupID: group_id,
|
2025-11-07 09:56:20 +08:00
|
|
|
|
message,
|
|
|
|
|
|
offlinePushInfo,
|
|
|
|
|
|
})
|
2025-11-25 05:36:02 +08:00
|
|
|
|
.then(({data}) => {
|
2025-12-11 22:33:31 +08:00
|
|
|
|
console.log(data);
|
2025-11-07 09:56:20 +08:00
|
|
|
|
this.updateOneMessage({
|
|
|
|
|
|
message: data,
|
|
|
|
|
|
isSuccess: true,
|
|
|
|
|
|
});
|
|
|
|
|
|
})
|
2025-11-25 05:36:02 +08:00
|
|
|
|
.catch(({data,errCode,errMsg}) => {
|
2025-12-11 22:33:31 +08:00
|
|
|
|
console.log(errCode,errMsg);
|
2025-11-25 05:36:02 +08:00
|
|
|
|
uni.$u.toast(errMsg);
|
2025-11-07 09:56:20 +08:00
|
|
|
|
this.updateOneMessage({
|
|
|
|
|
|
message: data,
|
|
|
|
|
|
type: UpdateMessageTypes.KeyWords,
|
2025-11-25 05:36:02 +08:00
|
|
|
|
keyWords: [
|
|
|
|
|
|
{
|
2025-11-07 09:56:20 +08:00
|
|
|
|
key: "status",
|
|
|
|
|
|
value: MessageStatus.Failed,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: "errCode",
|
|
|
|
|
|
value: errCode,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2025-12-02 03:05:52 +08:00
|
|
|
|
recordAudioMsg(){
|
|
|
|
|
|
|
|
|
|
|
|
if (uni.getSystemInfoSync().platform == "android") {
|
|
|
|
|
|
permission.requestAndroid("android.permission.RECORD_AUDIO"); //Android请求录音权限
|
|
|
|
|
|
} else {
|
|
|
|
|
|
permission.requestIOS("record"); //ios请求录音权限
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-07 09:56:20 +08:00
|
|
|
|
// action
|
|
|
|
|
|
onClickActionBarOutside() {
|
2025-12-09 09:27:29 +08:00
|
|
|
|
// 如果正在插入表情,不隐藏表情栏
|
|
|
|
|
|
if (this.isInsertingEmoji) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-07 09:56:20 +08:00
|
|
|
|
if (this.actionBarVisible) {
|
|
|
|
|
|
this.actionBarVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-12-02 03:05:52 +08:00
|
|
|
|
updateActionBar(isEmoji) {
|
2025-12-09 09:27:29 +08:00
|
|
|
|
if(this.actionBarVisible){
|
|
|
|
|
|
if(this.isEmoji!== !!isEmoji){
|
|
|
|
|
|
this.isEmoji = !!isEmoji;
|
|
|
|
|
|
}else{
|
|
|
|
|
|
this.actionBarVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
this.actionBarVisible = true;
|
|
|
|
|
|
this.isEmoji = !!isEmoji;
|
|
|
|
|
|
}
|
2025-11-07 09:56:20 +08:00
|
|
|
|
},
|
|
|
|
|
|
editorFocus() {
|
|
|
|
|
|
this.isInputFocus = true;
|
|
|
|
|
|
this.$emit("scrollToBottom");
|
|
|
|
|
|
},
|
|
|
|
|
|
editorBlur() {
|
|
|
|
|
|
this.isInputFocus = false;
|
|
|
|
|
|
},
|
|
|
|
|
|
editorInput(e) {
|
2025-12-09 09:27:29 +08:00
|
|
|
|
// SimpleEditor 返回的是纯文本,直接使用
|
|
|
|
|
|
this.inputHtml = e.detail.value || e.detail.text || e.detail.html || "";
|
2025-11-07 09:56:20 +08:00
|
|
|
|
},
|
2025-12-11 22:33:31 +08:00
|
|
|
|
// from comp
|
|
|
|
|
|
sendMediaMesage(paths) {
|
|
|
|
|
|
const _this = this;
|
|
|
|
|
|
paths.forEach(async (item) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
let message = null;
|
|
|
|
|
|
if(item.search('.mp4')>0){
|
|
|
|
|
|
const realVideoPath = await getPurePath(item);
|
|
|
|
|
|
console.log('处理后的可用路径', realVideoPath);
|
|
|
|
|
|
const info = await getVideoInfo(realVideoPath);
|
|
|
|
|
|
const cover = await getVideoCover(item);
|
|
|
|
|
|
const videoParams = {
|
|
|
|
|
|
videoPath: realVideoPath,
|
|
|
|
|
|
videoType: "mp4",
|
|
|
|
|
|
duration: info.duration,
|
|
|
|
|
|
snapshotPath: getPurePath(cover),
|
|
|
|
|
|
};
|
|
|
|
|
|
console.log('videoParams', videoParams);
|
|
|
|
|
|
message = await IMSDK.asyncApi(
|
|
|
|
|
|
IMMethods.CreateVideoMessageFromFullPath,
|
|
|
|
|
|
IMSDK.uuid(),
|
|
|
|
|
|
videoParams
|
|
|
|
|
|
);
|
|
|
|
|
|
}else{
|
|
|
|
|
|
message = await IMSDK.asyncApi(
|
|
|
|
|
|
IMMethods.CreateImageMessageFromFullPath,
|
|
|
|
|
|
IMSDK.uuid(),
|
|
|
|
|
|
getPurePath(item)
|
|
|
|
|
|
);
|
2025-12-09 09:27:29 +08:00
|
|
|
|
}
|
2025-12-11 22:33:31 +08:00
|
|
|
|
console.log(message);
|
|
|
|
|
|
if(message){
|
|
|
|
|
|
_this.sendMessage(message,_this.storeCurrentConversation.userID,_this.storeCurrentConversation.groupID);
|
2025-12-02 03:05:52 +08:00
|
|
|
|
}
|
2025-12-11 22:33:31 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.log(error);
|
2025-12-09 09:27:29 +08:00
|
|
|
|
}
|
2025-11-07 09:56:20 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
2025-11-25 05:36:02 +08:00
|
|
|
|
selectClick({idx}) {
|
2025-11-07 09:56:20 +08:00
|
|
|
|
if (idx === 0) {
|
2025-11-25 05:36:02 +08:00
|
|
|
|
uni.$u.toast('根据相关政策,暂时禁用视频通话');
|
|
|
|
|
|
//发送视频通话
|
2025-11-07 09:56:20 +08:00
|
|
|
|
} else {
|
2025-11-25 05:36:02 +08:00
|
|
|
|
uni.$u.toast('根据相关政策,暂时禁用音频通话');
|
|
|
|
|
|
//发送音频通话
|
2025-11-07 09:56:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
// keyboard
|
2025-11-25 05:36:02 +08:00
|
|
|
|
keyboardChangeHander({height}) {
|
2025-12-09 09:27:29 +08:00
|
|
|
|
//console.log(height);
|
|
|
|
|
|
// 如果正在插入表情,不隐藏表情栏
|
|
|
|
|
|
if (this.isInsertingEmoji) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-07 09:56:20 +08:00
|
|
|
|
if (height > 0) {
|
|
|
|
|
|
if (this.actionBarVisible) {
|
|
|
|
|
|
this.actionBarVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
setKeyboardListener() {
|
|
|
|
|
|
uni.onKeyboardHeightChange(this.keyboardChangeHander);
|
|
|
|
|
|
},
|
|
|
|
|
|
disposeKeyboardListener() {
|
|
|
|
|
|
uni.offKeyboardHeightChange(this.keyboardChangeHander);
|
|
|
|
|
|
},
|
2025-12-02 03:05:52 +08:00
|
|
|
|
/*----------------------------------------------------(H5不支持)录音相关 start-------------------------------------- */
|
|
|
|
|
|
//准备开始录音
|
|
|
|
|
|
startVoice(e) {
|
|
|
|
|
|
if (!this.Audio.paused) {
|
|
|
|
|
|
//如果音频正在播放 先暂停。
|
|
|
|
|
|
this.stopAudio(this.AudioExam)
|
|
|
|
|
|
}
|
|
|
|
|
|
this.recording = true;
|
|
|
|
|
|
this.isStopVoice = false;
|
|
|
|
|
|
this.voiceCanSend = true;
|
|
|
|
|
|
this.voiceIconText = "正在录音..."
|
|
|
|
|
|
this.PointY = e.touches[0].clientY;
|
|
|
|
|
|
this.Recorder.start({
|
|
|
|
|
|
format: 'mp3'
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
|
|
|
|
|
//录音已经开始
|
|
|
|
|
|
beginVoice() {
|
|
|
|
|
|
let that = this;
|
|
|
|
|
|
if (that.isStopVoice) {
|
|
|
|
|
|
that.Recorder.stop();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
that.voiceTitle = '松开 结束'
|
|
|
|
|
|
that.voiceInterval = setInterval(() => {
|
|
|
|
|
|
console.log("that.voiceTime", that.voiceTime);
|
|
|
|
|
|
if (that.voiceTime > 49) {
|
|
|
|
|
|
that.voiceIconText = "录音结束倒计时[" + (60 - that.voiceTime) + "]s";
|
|
|
|
|
|
};
|
|
|
|
|
|
if (that.voiceTime == 60) {
|
|
|
|
|
|
clearInterval(that.voiceInterval);
|
|
|
|
|
|
that.endVoice();
|
|
|
|
|
|
}
|
|
|
|
|
|
that.voiceTime++;
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
},
|
|
|
|
|
|
//move 正在录音中
|
|
|
|
|
|
moveVoice(e) {
|
|
|
|
|
|
const PointY = e.touches[0].clientY;
|
|
|
|
|
|
const slideY = this.PointY - PointY;
|
|
|
|
|
|
if (slideY > uni.upx2px(120)) {
|
|
|
|
|
|
this.voiceCanSend = false;
|
|
|
|
|
|
this.voiceIconText = '松开手指 取消发送 '
|
|
|
|
|
|
} else if (slideY > uni.upx2px(60)) {
|
|
|
|
|
|
this.voiceCanSend = true;
|
|
|
|
|
|
this.voiceIconText = '手指上滑 取消发送 '
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.voiceIconText = '正在录音... '
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
//结束录音
|
|
|
|
|
|
endVoice() {
|
|
|
|
|
|
this.isStopVoice = true; //加锁 确保已经结束录音并不会录制
|
|
|
|
|
|
this.Recorder.stop();
|
|
|
|
|
|
this.voiceTitle = '按住 说话'
|
|
|
|
|
|
},
|
|
|
|
|
|
//录音被打断
|
|
|
|
|
|
cancelVoice(e) {
|
|
|
|
|
|
console.log("路由被打断", e);
|
|
|
|
|
|
this.voiceTime = 0;
|
|
|
|
|
|
this.voiceTitle = '按住 说话';
|
|
|
|
|
|
this.voiceCanSend = false;
|
|
|
|
|
|
this.Recorder.stop();
|
|
|
|
|
|
},
|
|
|
|
|
|
//处理录音文件
|
|
|
|
|
|
handleRecorder({tempFilePath,duration }) {
|
|
|
|
|
|
if (this.voiceTime < 1) {
|
|
|
|
|
|
this.voiceIconText = "说话时间过短";
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.recording = false;
|
|
|
|
|
|
}, 500)
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let contentDuration = this.voiceTime;
|
|
|
|
|
|
this.voiceTime = 0;
|
|
|
|
|
|
this.recording = false;
|
|
|
|
|
|
clearInterval(this.voiceInterval);
|
|
|
|
|
|
console.log("录音文件", tempFilePath);
|
|
|
|
|
|
console.log("是否发送语音信息", this.voiceCanSend);
|
|
|
|
|
|
let voiceFile = {
|
|
|
|
|
|
tempFilePath: tempFilePath,
|
|
|
|
|
|
contentDuration: Math.ceil(contentDuration),
|
|
|
|
|
|
anmitionPlay: false,
|
|
|
|
|
|
};
|
|
|
|
|
|
if (this.voiceCanSend) {
|
|
|
|
|
|
console.log("=====上传语音文件,并发送语音信息====");
|
|
|
|
|
|
let audioType = this.messageApi.CONTENT_TYPE.AUDIO_CONTENT_TYPE;
|
|
|
|
|
|
this.uploadFile(voiceFile, audioType);
|
|
|
|
|
|
return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log("=====已经取消发送语音信息====")
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
//控制播放还是暂停音频文件
|
|
|
|
|
|
handleAudio(item) {
|
|
|
|
|
|
this.AudioExam = item;
|
|
|
|
|
|
this.Audio.paused ? this.playAudio(item) : this.stopAudio(item);
|
|
|
|
|
|
},
|
|
|
|
|
|
//播放音频
|
|
|
|
|
|
playAudio(item) {
|
|
|
|
|
|
let target = item.content.fileSaveTarget;
|
|
|
|
|
|
let src = item.content.fullPath;
|
|
|
|
|
|
if (target == "local") {
|
|
|
|
|
|
src = this.$u.api.multipartAddress.getFileByPath + src;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.Audio.src = src;
|
|
|
|
|
|
this.Audio.hasBeenSentId = item.id;
|
|
|
|
|
|
this.Audio.play();
|
|
|
|
|
|
let currentAudioMsg = this.messageList.find(it => it.id == item.id);
|
|
|
|
|
|
currentAudioMsg.content.anmitionPlay = true;
|
|
|
|
|
|
},
|
|
|
|
|
|
//停止音频
|
|
|
|
|
|
stopAudio(item) {
|
|
|
|
|
|
let currentAudioMsg = this.messageList.find(it => it.id == item.id);
|
|
|
|
|
|
currentAudioMsg.content.anmitionPlay = false;
|
|
|
|
|
|
this.Audio.src = '';
|
|
|
|
|
|
this.Audio.stop();
|
|
|
|
|
|
},
|
|
|
|
|
|
//关闭动画
|
|
|
|
|
|
closeAnmition() {
|
|
|
|
|
|
const hasBeenSentId = this.Audio.hasBeenSentId;
|
|
|
|
|
|
let item = this.messageList.find(it => it.id == hasBeenSentId);
|
|
|
|
|
|
item.content.anmitionPlay = false;
|
|
|
|
|
|
},
|
|
|
|
|
|
/*-------------------------------------录音相关方法块 end---------------------------------------------------*/
|
2025-12-09 09:27:29 +08:00
|
|
|
|
onUserEvent(e){
|
2025-12-11 22:33:31 +08:00
|
|
|
|
const _this = this;
|
2025-12-09 09:27:29 +08:00
|
|
|
|
switch(e.type){
|
|
|
|
|
|
case "clearSendStr":
|
|
|
|
|
|
this.$refs.customEditor.clear();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "delSendStr":
|
|
|
|
|
|
this.$refs.customEditor.delete();
|
|
|
|
|
|
break;
|
2025-12-11 22:33:31 +08:00
|
|
|
|
case "insertEmoji":
|
|
|
|
|
|
//TODO 在光标处插入文字extra
|
|
|
|
|
|
//editorContext.insertImage(
|
|
|
|
|
|
// 标记正在插入表情(先设置标志,保护表情栏不被隐藏)
|
|
|
|
|
|
this.isInsertingEmoji = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保表情栏显示(只在真正需要时才更新状态,避免不必要的响应式触发)
|
|
|
|
|
|
const wasVisible = this.actionBarVisible;
|
|
|
|
|
|
const wasEmoji = this.isEmoji;
|
|
|
|
|
|
|
|
|
|
|
|
if (!wasVisible || !wasEmoji) {
|
|
|
|
|
|
// 只有在需要时才更新状态,减少响应式触发
|
|
|
|
|
|
if (!wasVisible) {
|
|
|
|
|
|
this.actionBarVisible = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!wasEmoji) {
|
|
|
|
|
|
this.isEmoji = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 直接插入文本,不等待 nextTick,减少延迟
|
|
|
|
|
|
this.$refs.customEditor.insertText(e.emoji,() =>{
|
|
|
|
|
|
console.log("插入文字成功");
|
|
|
|
|
|
// 延迟重置标志,确保其他事件不会隐藏表情栏
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.isInsertingEmoji = false;
|
|
|
|
|
|
}, 300);
|
|
|
|
|
|
},(err) => {
|
|
|
|
|
|
console.log("插入文字失败", err);
|
|
|
|
|
|
this.isInsertingEmoji = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "prepend_image_message":
|
|
|
|
|
|
if(e.source == "camera"){
|
|
|
|
|
|
var cmr = plus.camera.getCamera();
|
|
|
|
|
|
cmr.captureImage((src) =>{
|
|
|
|
|
|
_this.sendMediaMesage([plus.io.convertLocalFileSystemURL(src)]);
|
|
|
|
|
|
}, (err) =>{
|
|
|
|
|
|
console.log(err);
|
|
|
|
|
|
}, {
|
|
|
|
|
|
filename:"_doc/camera/"
|
|
|
|
|
|
});
|
|
|
|
|
|
return ;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(e.source == "album"){
|
|
|
|
|
|
plus.gallery.pick(({files})=>{
|
|
|
|
|
|
_this.sendMediaMesage(files);
|
|
|
|
|
|
}, (error )=>{
|
|
|
|
|
|
reject(error);
|
|
|
|
|
|
}, {
|
|
|
|
|
|
animation:true,
|
|
|
|
|
|
confirmText:"确定",
|
|
|
|
|
|
//crop:null,
|
|
|
|
|
|
editable:true,
|
|
|
|
|
|
filename:"_doc/",
|
|
|
|
|
|
filter:"none",
|
|
|
|
|
|
maximum:9,
|
|
|
|
|
|
multiple:true,
|
|
|
|
|
|
permissionAlert:true,
|
|
|
|
|
|
//popover:{},
|
|
|
|
|
|
//selected:[""],
|
|
|
|
|
|
onmaxed(){
|
|
|
|
|
|
console.log("超出最大选择数");
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "prepend_call_message":
|
|
|
|
|
|
this.actionSheetMenu = [...rtcChoose];
|
|
|
|
|
|
this.showActionSheet = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "prepend_file_message":
|
|
|
|
|
|
uni.chooseFile({
|
|
|
|
|
|
count:9,
|
|
|
|
|
|
multiple: true,
|
|
|
|
|
|
success: (res) => {
|
|
|
|
|
|
console.log('选择文件成功', res);
|
|
|
|
|
|
//const filePaths = res.tempFiles.map(file => file.path);
|
|
|
|
|
|
//_this.sendMediaMesage(filePaths);
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
console.log('选择文件失败', err);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "prepend_location_message":
|
|
|
|
|
|
uni.chooseLocation({
|
|
|
|
|
|
complete(res) {
|
|
|
|
|
|
console.log(res);
|
|
|
|
|
|
},
|
|
|
|
|
|
fail(res) {
|
|
|
|
|
|
console.log(res);
|
|
|
|
|
|
}
|
|
|
|
|
|
//latitude:1,
|
|
|
|
|
|
//longitude:1,
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
console.log(e);
|
|
|
|
|
|
break;
|
2025-12-09 09:27:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-07 09:56:20 +08:00
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.custom_editor {
|
|
|
|
|
|
img {
|
|
|
|
|
|
vertical-align: sub;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.forbidden_footer {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 112rpx;
|
|
|
|
|
|
color: #8e9ab0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
background: #f0f2f6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chat_footer {
|
|
|
|
|
|
display: flex;
|
2025-12-02 03:05:52 +08:00
|
|
|
|
align-items: flex-end;
|
2025-11-07 09:56:20 +08:00
|
|
|
|
// background-color: #e9f4ff;
|
2025-12-02 03:05:52 +08:00
|
|
|
|
background: #f6f6f6;
|
2025-11-07 09:56:20 +08:00
|
|
|
|
// height: 50px;
|
|
|
|
|
|
max-height: 120px;
|
|
|
|
|
|
padding: 24rpx 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.input_content {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-height: 30px;
|
|
|
|
|
|
max-height: 120px;
|
|
|
|
|
|
margin: 0 24rpx;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
.record_btn {
|
|
|
|
|
|
// background-color: #3c9cff;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
color: black;
|
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.quote_message {
|
|
|
|
|
|
@include vCenterBox();
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
margin-top: 12rpx;
|
|
|
|
|
|
padding: 8rpx;
|
|
|
|
|
|
// padding-top: 20rpx;
|
|
|
|
|
|
border-radius: 6rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
|
|
|
|
|
|
.content {
|
|
|
|
|
|
::v-deep uni-view {
|
|
|
|
|
|
@include ellipsisWithLine(2);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer_action_area {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.emoji_action {
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
}
|
2025-12-08 18:10:51 +08:00
|
|
|
|
|
2025-11-07 09:56:20 +08:00
|
|
|
|
image {
|
|
|
|
|
|
width: 26px;
|
|
|
|
|
|
height: 26px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.send_btn {
|
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
line-height: 30px;
|
2025-12-02 03:05:52 +08:00
|
|
|
|
background-color: $uni-color-success;
|
2025-12-08 18:10:51 +08:00
|
|
|
|
padding: 0 8px;
|
2025-11-07 09:56:20 +08:00
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|