2025-09-29
聊天图片上传 录音修改
This commit is contained in:
@@ -18,7 +18,9 @@
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {
|
||||
"Payment" : {}
|
||||
"Payment" : {},
|
||||
"Record" : {},
|
||||
"Camera" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
|
||||
@@ -27,51 +27,59 @@
|
||||
<image src="/static/icon/Camera.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||
</view>
|
||||
<!-- 文本发送 -->
|
||||
<view v-show="text!=null && text!=''" class="icon u-m-r-10 u-m-l-10" @click="handleSend">
|
||||
<view v-show="text!=null && text!=''" class="icon u-m-r-10 u-m-l-10" @click="handleSendText">
|
||||
<image src="/static/icon/send.png" mode="" style="width: 100%;height: 100%;"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view :style="'height:'+scrollHeight+'px'" scroll-y="true" class="scroll-main">
|
||||
<view v-for="(item, index) in dataList">
|
||||
<view v-if="item.createId==userId" class="my-message">
|
||||
<view class="msg-main">
|
||||
<view class="msg-content" v-if="item.type=='text'">
|
||||
<view class="text">
|
||||
{{item.content}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="mp3-content" v-if="item.type=='mp3'">
|
||||
<view class="mp3">
|
||||
<view class="mp3-icon">
|
||||
<image style="width: 100%;height: 100%;" src="/static/icon/listen.png" mode="">
|
||||
</image>
|
||||
<scroll-view :style="'height:'+scrollHeight+'px'" scroll-y="true" class="scroll-main" :scroll-top="scrollTop"
|
||||
:scroll-with-animation="true">
|
||||
<view id="scroll-main">
|
||||
<view v-for="(item, index) in dataList">
|
||||
<view v-if="item.createId==userId" class="my-message">
|
||||
<view class="msg-main">
|
||||
<view class="msg-content" v-if="item.type=='text'">
|
||||
<view class="text">
|
||||
{{item.content}}
|
||||
</view>
|
||||
点击播放
|
||||
</view>
|
||||
</view>
|
||||
<view class="msg-avatar">
|
||||
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)" mode="">
|
||||
</image>
|
||||
<view class="mp3-content" v-if="item.type=='mp3'">
|
||||
<view class="mp3" @click="handlePlayMp3(item.content)">
|
||||
<view class="mp3-icon">
|
||||
<image style="width: 100%;height: 100%;" src="/static/icon/listen.png" mode="">
|
||||
</image>
|
||||
</view>
|
||||
点击播放
|
||||
</view>
|
||||
</view>
|
||||
<view class="img-content" v-if="item.type=='img'">
|
||||
<u-image @click="handlePreView(item.content)" height="100%" :src="item.content"
|
||||
:lazy-load="true" mode="heightFix"></u-image>
|
||||
</view>
|
||||
<!-- 头像 -->
|
||||
<view class="msg-avatar">
|
||||
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
|
||||
mode="">
|
||||
</image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="other-message">
|
||||
<view class="msg-main">
|
||||
<view class="msg-avatar">
|
||||
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)" mode="">
|
||||
</image>
|
||||
</view>
|
||||
<view class="msg-content">
|
||||
<view class="text">
|
||||
{{item.content}}
|
||||
<view v-else class="other-message">
|
||||
<view class="msg-main">
|
||||
<view class="msg-avatar">
|
||||
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
|
||||
mode="">
|
||||
</image>
|
||||
</view>
|
||||
<view class="msg-content">
|
||||
<view class="text">
|
||||
{{item.content}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<u-popup v-model="showLongText" mode="bottom" height="80%">
|
||||
<view class="long-text">
|
||||
<u-input v-model="text" type="textarea" maxlength="3000" />
|
||||
@@ -82,7 +90,14 @@
|
||||
<u-mask :show="showMask" @click="handleStopMic" blur="10">
|
||||
<view class="mask-warp">
|
||||
<view class="mask-text">
|
||||
{{!showMaskBtn?'正在说话...点击结束': '点击播放录音'}}
|
||||
<template v-if="!showMaskBtn">
|
||||
正在说话...点击结束
|
||||
</template>
|
||||
<template v-else>
|
||||
<u-image :fade="false" width="50" height="50"
|
||||
:src="isPlayRecord?'/static/icon/record_ing.png':'/static/icon/record_play.png'"
|
||||
:show-loading="false"></u-image>{{isPlayRecord?'播放中...':'点击播放录音'}}
|
||||
</template>
|
||||
</view>
|
||||
<view v-if="showMaskBtn" class="mask-btn">
|
||||
<u-button class="btn" @click.stop="handleCancel">取消</u-button>
|
||||
@@ -91,13 +106,18 @@
|
||||
</view>
|
||||
</u-mask>
|
||||
|
||||
|
||||
<u-mask :show="showPreMask" @click="showPreMask=false" blur="10">
|
||||
<u-image width="100%" class="mask-pre-img" :src="preImg" :lazy-load="true" mode="aspectFit"></u-image>
|
||||
</u-mask>
|
||||
|
||||
<u-toast ref="msgToast" duration="6000" />
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, getCurrentInstance, onBeforeMount } from 'vue';
|
||||
import { onMounted, ref, getCurrentInstance, onBeforeMount, nextTick } from 'vue';
|
||||
import {
|
||||
onLoad, onLaunch
|
||||
} from "@dcloudio/uni-app";
|
||||
@@ -105,16 +125,27 @@
|
||||
import { getImageUrl } from '../../util/common';
|
||||
import { permissionUtil } from '@/uni_modules/colorful-uni-perm';
|
||||
|
||||
|
||||
const text = ref('')
|
||||
|
||||
const socket = ref()
|
||||
|
||||
const navBarRef = ref()
|
||||
const instance = getCurrentInstance();
|
||||
const scrollHeight = ref(0)
|
||||
const loadHeight = () => {
|
||||
uni.getSystemInfo({
|
||||
success(res) {
|
||||
let screenHeight = res.screenHeight
|
||||
uni.createSelectorQuery().in(instance.proxy).select("#navBarId").boundingClientRect((data : any) => {
|
||||
scrollHeight.value = screenHeight - data.height
|
||||
}).exec()
|
||||
uni.createSelectorQuery().in(instance.proxy).select("#bottomId").boundingClientRect((data : any) => {
|
||||
scrollHeight.value = scrollHeight.value - data.height
|
||||
}).exec()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const dataList = ref([])
|
||||
|
||||
const mockData = () => {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
for (var i = 0; i < 5; i++) {
|
||||
if (i % 2 == 0) {
|
||||
dataList.value.push({
|
||||
"createId": 3641,
|
||||
@@ -165,19 +196,47 @@
|
||||
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
||||
}
|
||||
})
|
||||
|
||||
dataList.value.push(
|
||||
{
|
||||
"createId": 3641,
|
||||
"groupId": "5",
|
||||
"content": "http://114.55.111.44:9000/jurongquan/app_records/1759110192420_Screenshot_20250929_084636_com.bilibili.star.bili.jpg",
|
||||
"type": "img",
|
||||
"messageId": 62,
|
||||
"createTime": "2025-09-28T17:43:13.000Z",
|
||||
"userInfo": {
|
||||
"id": 3641,
|
||||
"username": "15867461617",
|
||||
"userType": "agent",
|
||||
"isSystemAccount": 0,
|
||||
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleSend = () => {
|
||||
// 发送消息
|
||||
const text = ref('')
|
||||
const showLongText = ref(false)
|
||||
|
||||
const handleSendText = () => {
|
||||
uni.hideKeyboard()
|
||||
socket.value.emit('clientMsg', {
|
||||
createId: userId.value,
|
||||
groupId: groupId.value,
|
||||
content: text.value,
|
||||
type: "text"
|
||||
})
|
||||
text.value = ''
|
||||
}
|
||||
|
||||
const showLongText = ref(false)
|
||||
// 文本放大
|
||||
const handleMagnify = () => {
|
||||
showLongText.value = true
|
||||
}
|
||||
|
||||
// 录音
|
||||
const showMic = ref(false)
|
||||
const showMask = ref(false)
|
||||
const showMaskBtn = ref(false)
|
||||
@@ -186,9 +245,15 @@
|
||||
|
||||
const voicePath = ref('')
|
||||
|
||||
const recorderManager = uni.getRecorderManager();
|
||||
const innerAudioContext = uni.createInnerAudioContext();
|
||||
innerAudioContext.autoplay = true;
|
||||
const recorderManager = uni.getRecorderManager(); // 录音管理器
|
||||
const innerAudioContext = uni.createInnerAudioContext(); // 音频管理器
|
||||
const options = {
|
||||
duration: 60000, // 录音时长,单位为毫秒
|
||||
sampleRate: 44100, // 采样率
|
||||
numberOfChannels: 2, // 通道数
|
||||
format: 'mp3', // 音频格式
|
||||
};
|
||||
const isPlayRecord = ref(false)
|
||||
|
||||
// 选择麦克风
|
||||
const handleChangeMic = () => {
|
||||
@@ -197,35 +262,43 @@
|
||||
|
||||
// 开始录音
|
||||
const handleSay = () => {
|
||||
permissionUtil.requestAndroidPermission('android.permission.READ_MEDIA_AUDIO').then((status) => {
|
||||
permissionUtil.requestAndroidPermission('android.permission.RECORD_AUDIO').then((status) => {
|
||||
// status 为 1 表示用户已授权,0 表示用户已拒绝, -1 表示用户永久拒绝
|
||||
console.log('权限申请结果:', status);
|
||||
if (status == -1) {
|
||||
// 弹窗提示开启权限
|
||||
msgToast.value.show({
|
||||
title: '您已关闭录音权限,请在设置开启应用录音权限',
|
||||
type: 'warning'
|
||||
})
|
||||
msgErrorRcord()
|
||||
} else if (status == 1) {
|
||||
showMask.value = true
|
||||
recorderManager.start();
|
||||
recorderManager.onStart(() => {
|
||||
console.log('录音开始');
|
||||
});
|
||||
recorderManager.onError((err) => {
|
||||
console.error('录音错误', err);
|
||||
});
|
||||
// start方法无法被及时调用的处理方法
|
||||
while (!showMask.value) {
|
||||
recorderManager.start(options);
|
||||
recorderManager.onStart(() => {
|
||||
console.log('录音开始');
|
||||
showMask.value = true
|
||||
});
|
||||
}
|
||||
} else if (status == 0) {
|
||||
msgErrorRcord()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const msgErrorRcord = () => {
|
||||
msgToast.value.show({
|
||||
title: '请确认您的麦克风权限是否开启',
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
|
||||
// 停止录音
|
||||
const handleStopMic = () => {
|
||||
showMaskBtn.value = true
|
||||
if (voicePath.value) {
|
||||
console.log("播放录音");
|
||||
isPlayRecord.value = true
|
||||
innerAudioContext.src = voicePath.value
|
||||
innerAudioContext.play();
|
||||
innerAudioContext.onEnded(() => {
|
||||
isPlayRecord.value = false
|
||||
})
|
||||
} else {
|
||||
recorderManager.stop()
|
||||
// showMask.value = false
|
||||
@@ -241,10 +314,12 @@
|
||||
showMask.value = false
|
||||
showMaskBtn.value = false
|
||||
voicePath.value = ''
|
||||
innerAudioContext.stop()
|
||||
}
|
||||
|
||||
// 发送录音文件
|
||||
const handleSendMp3 = () => {
|
||||
innerAudioContext.stop()
|
||||
const token = uni.getStorageSync("token")
|
||||
uni.uploadFile({
|
||||
// url: 'http://192.168.0.4:3005/upload',
|
||||
@@ -275,11 +350,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
// 文本放大
|
||||
const handleMagnify = () => {
|
||||
showLongText.value = true
|
||||
}
|
||||
|
||||
// 打开相册
|
||||
const handleCamera = () => {
|
||||
permissionUtil.requestAndroidPermission('android.permission.READ_EXTERNAL_STORAGE').then((status) => {
|
||||
console.log('相册权限申请结果:', status);
|
||||
@@ -302,27 +373,66 @@
|
||||
})
|
||||
}
|
||||
|
||||
const uploadImages = (value) => {
|
||||
console.log(value);
|
||||
// 上传图片
|
||||
const uploadImages = (imgList : any) => {
|
||||
const token = uni.getStorageSync("token")
|
||||
uni.uploadFile({
|
||||
// url: 'http://192.168.0.4:3005/upload/image',
|
||||
url: 'http://192.168.0.15:3007/upload/files',
|
||||
filePath: value,
|
||||
header: {
|
||||
"Authorization": "Bearer " + token
|
||||
},
|
||||
name: 'file',
|
||||
success: (uploadFileRes) => {
|
||||
console.log(uploadFileRes);
|
||||
// console.log(JSON.stringify(uploadFileRes.data));
|
||||
},
|
||||
fail: (res) => {
|
||||
console.log(JSON.stringify(res));
|
||||
}
|
||||
imgList.forEach((item : string) => {
|
||||
uni.uploadFile({
|
||||
// url: 'http://192.168.0.4:3005/upload',
|
||||
url: 'http://192.168.0.15:3007/upload/file',
|
||||
filePath: item,
|
||||
header: {
|
||||
"Authorization": "Bearer " + token
|
||||
},
|
||||
name: "file",
|
||||
success: (uploadFileRes) => {
|
||||
let result = JSON.parse(uploadFileRes.data)
|
||||
if (result.data.fileUrl) {
|
||||
// 上传文件成功,添加消息记录
|
||||
socket.value.emit('clientMsg', {
|
||||
createId: userId.value,
|
||||
groupId: groupId.value,
|
||||
content: result.data.fileUrl,
|
||||
type: "img"
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: (res) => {
|
||||
console.log(res);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 图片预览
|
||||
const showPreMask = ref(false)
|
||||
const preImg = ref('')
|
||||
|
||||
const handlePreView = (value) => {
|
||||
preImg.value = value
|
||||
showPreMask.value = true
|
||||
}
|
||||
|
||||
const playError = () => {
|
||||
msgToast.value.show({
|
||||
title: '音频错误,无法播放',
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
|
||||
// 播放录音
|
||||
const handlePlayMp3 = (value) => {
|
||||
innerAudioContext.src = value
|
||||
innerAudioContext.play()
|
||||
innerAudioContext.onPlay(() => {
|
||||
// 正在播放录音
|
||||
});
|
||||
innerAudioContext.onError((res) => {
|
||||
playError()
|
||||
});
|
||||
}
|
||||
|
||||
const groupId = ref()
|
||||
const userId = ref()
|
||||
|
||||
@@ -330,22 +440,9 @@
|
||||
groupId.value = val.groupId
|
||||
});
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
const scrollHeight = ref(0)
|
||||
const loadHeight = () => {
|
||||
uni.getSystemInfo({
|
||||
success(res) {
|
||||
let screenHeight = res.screenHeight
|
||||
uni.createSelectorQuery().in(instance.proxy).select("#navBarId").boundingClientRect((data : any) => {
|
||||
scrollHeight.value = screenHeight - data.height
|
||||
}).exec()
|
||||
uni.createSelectorQuery().in(instance.proxy).select("#bottomId").boundingClientRect((data : any) => {
|
||||
scrollHeight.value = scrollHeight.value - data.height
|
||||
}).exec()
|
||||
}
|
||||
})
|
||||
}
|
||||
const socket = ref()
|
||||
|
||||
// 通信连接
|
||||
const connection = () => {
|
||||
socket.value = io('http://192.168.0.15:3007', {
|
||||
query: {},
|
||||
@@ -358,18 +455,32 @@
|
||||
socket.value.emit('addGroup', {
|
||||
groupId: groupId.value,
|
||||
})
|
||||
socket.value.on('serverMsg', async (message) => {
|
||||
socket.value.on('serverMsg', async (message:any) => {
|
||||
dataList.value.push(message)
|
||||
console.log(dataList.value);
|
||||
// console.log(dataList.value);
|
||||
setTimeout(()=>{
|
||||
scrollToBottom()
|
||||
}, 500)
|
||||
})
|
||||
}
|
||||
|
||||
const scrollTop = ref(0)
|
||||
|
||||
const scrollToBottom = () => {
|
||||
uni.createSelectorQuery().in(this).select("#scroll-main").boundingClientRect((res : any) => {
|
||||
let top = res.height - scrollHeight.value;
|
||||
if (top > 0) {
|
||||
scrollTop.value = top;
|
||||
}
|
||||
}).exec()
|
||||
}
|
||||
|
||||
const loadData = () => {
|
||||
userId.value = uni.getStorageSync("user").id
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
mockData()
|
||||
// mockData()
|
||||
loadData()
|
||||
|
||||
loadHeight()
|
||||
@@ -415,6 +526,7 @@
|
||||
}
|
||||
|
||||
.btn-mic {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -460,13 +572,18 @@
|
||||
align-items: center;
|
||||
|
||||
.mp3-icon {
|
||||
margin-left: 10rpx;
|
||||
margin: 0 10rpx;
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.img-content {
|
||||
margin-right: 10rpx;
|
||||
height: 200rpx;
|
||||
}
|
||||
|
||||
.msg-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
@@ -517,6 +634,8 @@
|
||||
.mask-text {
|
||||
font-size: 36rpx;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mask-btn {
|
||||
@@ -531,5 +650,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
.mask-pre-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -208,7 +208,7 @@
|
||||
background-color: transparent;
|
||||
|
||||
.search {
|
||||
padding: 60rpx 42rpx 0;
|
||||
padding: 80rpx 42rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
static/icon/record_ing.png
Normal file
BIN
static/icon/record_ing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/icon/record_play.png
Normal file
BIN
static/icon/record_play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Reference in New Issue
Block a user