2025-09-29

聊天图片上传
录音修改
This commit is contained in:
2025-09-29 14:42:41 +08:00
parent 08c54797b6
commit 22c4b5d4d5
5 changed files with 231 additions and 103 deletions

View File

@@ -18,7 +18,9 @@
},
/* */
"modules" : {
"Payment" : {}
"Payment" : {},
"Record" : {},
"Camera" : {}
},
/* */
"distribute" : {

View File

@@ -27,12 +27,13 @@
<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">
<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">
@@ -42,7 +43,7 @@
</view>
</view>
<view class="mp3-content" v-if="item.type=='mp3'">
<view class="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>
@@ -50,8 +51,14 @@
点击播放
</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 style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
mode="">
</image>
</view>
</view>
@@ -59,7 +66,8 @@
<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 style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
mode="">
</image>
</view>
<view class="msg-content">
@@ -70,8 +78,8 @@
</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();
// start方法无法被及时调用的处理方法
while (!showMask.value) {
recorderManager.start(options);
recorderManager.onStart(() => {
console.log('录音开始');
});
recorderManager.onError((err) => {
console.error('录音错误', err);
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,25 +373,64 @@
})
}
const uploadImages = (value) => {
console.log(value);
// 上传图片
const uploadImages = (imgList : any) => {
const token = uni.getStorageSync("token")
imgList.forEach((item : string) => {
uni.uploadFile({
// url: 'http://192.168.0.4:3005/upload/image',
url: 'http://192.168.0.15:3007/upload/files',
filePath: value,
// 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',
name: "file",
success: (uploadFileRes) => {
console.log(uploadFileRes);
// console.log(JSON.stringify(uploadFileRes.data));
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(JSON.stringify(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()
@@ -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>

View File

@@ -208,7 +208,7 @@
background-color: transparent;
.search {
padding: 60rpx 42rpx 0;
padding: 80rpx 42rpx 0;
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB