2025-09-28 17:30:20 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="chat-container">
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<u-navbar :title="chatTitle" id="navBarId" :background="{background: 'transparent' }" :border-bottom="false"
|
2025-09-28 17:30:20 +08:00
|
|
|
|
back-icon-color="#000" title-color="#000">
|
|
|
|
|
|
<template v-slot:right>
|
2025-10-11 17:30:07 +08:00
|
|
|
|
<image class="collection" @click="handleinformation" src="/static/icon/More horizontal.png" mode="">
|
|
|
|
|
|
</image>
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
</u-navbar>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="bottom-view" id="bottomId">
|
|
|
|
|
|
<!-- 麦克风/文本切换 -->
|
|
|
|
|
|
<view class="icon u-m-r-10" @click="handleChangeMic">
|
|
|
|
|
|
<image src="/static/icon/Mic.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<textarea v-if="!showMic" name="" v-model="text" class="text" maxlength="3000"></textarea>
|
|
|
|
|
|
<u-button v-else class="btn-mic" @click="handleSay">点击说话</u-button>
|
|
|
|
|
|
<!-- 表情包 -->
|
|
|
|
|
|
<view v-show="text==null || text==''" class="icon u-m-r-10 u-m-l-10">
|
|
|
|
|
|
<image src="/static/icon/expression.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="handleMagnify">
|
|
|
|
|
|
<image src="/static/icon/big.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 相机 -->
|
|
|
|
|
|
<view v-show="text==null || text==''" class="icon" @click="handleCamera">
|
|
|
|
|
|
<image src="/static/icon/Camera.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 文本发送 -->
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<view v-show="text!=null && text!=''" class="icon u-m-r-10 u-m-l-10" @click="handleSendText">
|
2025-09-28 17:30:20 +08:00
|
|
|
|
<image src="/static/icon/send.png" mode="" style="width: 100%;height: 100%;"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<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">
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<!-- 消息内容 -->
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<view class="msg-content" v-if="item.type=='text'">
|
|
|
|
|
|
<view class="text">
|
|
|
|
|
|
{{item.content}}
|
|
|
|
|
|
</view>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<view>
|
|
|
|
|
|
{{handleFormatDate(item.createTime)}}
|
|
|
|
|
|
</view>
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</view>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<!-- 录音内容 -->
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
点击播放
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<!-- 图片内容 -->
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<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>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<view>
|
|
|
|
|
|
{{handleFormatDate(item.createTime)}}
|
|
|
|
|
|
</view>
|
2025-09-29 14:42:41 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 头像 -->
|
|
|
|
|
|
<view class="msg-avatar">
|
|
|
|
|
|
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
|
|
|
|
|
|
mode="">
|
|
|
|
|
|
</image>
|
|
|
|
|
|
</view>
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<view v-else class="other-message">
|
|
|
|
|
|
<view class="msg-main">
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<!-- 对方头像 -->
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<view class="msg-avatar">
|
|
|
|
|
|
<image style="width: 100%;height: 100%;" :src="getImageUrl(item.userInfo.avatar)"
|
|
|
|
|
|
mode="">
|
|
|
|
|
|
</image>
|
|
|
|
|
|
</view>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<!-- 对方文本 -->
|
|
|
|
|
|
<view class="msg-content" v-if="item.type=='text'">
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<view class="text">
|
|
|
|
|
|
{{item.content}}
|
|
|
|
|
|
</view>
|
2025-10-09 15:13:48 +08:00
|
|
|
|
<view>
|
|
|
|
|
|
{{handleFormatDate(item.createTime)}}
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<!-- 对方录音-->
|
|
|
|
|
|
<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>
|
|
|
|
|
|
{{handleFormatDate(item.createTime)}}
|
|
|
|
|
|
</view>
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</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" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</u-popup>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<u-mask :show="showMask" @click="handleStopMic" blur="10">
|
|
|
|
|
|
<view class="mask-warp">
|
|
|
|
|
|
<view class="mask-text">
|
2025-09-29 14:42:41 +08:00
|
|
|
|
<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>
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
<view v-if="showMaskBtn" class="mask-btn">
|
|
|
|
|
|
<u-button class="btn" @click.stop="handleCancel">取消</u-button>
|
|
|
|
|
|
<u-button class="btn" @click.stop="handleSendMp3">发送</u-button>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</u-mask>
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
<u-toast ref="msgToast" duration="6000" />
|
|
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2025-09-29 14:42:41 +08:00
|
|
|
|
import { onMounted, ref, getCurrentInstance, onBeforeMount, nextTick } from 'vue';
|
2025-09-28 17:30:20 +08:00
|
|
|
|
import {
|
2025-10-09 15:13:48 +08:00
|
|
|
|
onLoad, onLaunch, onReady, onUnload, onPullDownRefresh
|
2025-09-28 17:30:20 +08:00
|
|
|
|
} from "@dcloudio/uni-app";
|
|
|
|
|
|
import io from '@hyoga/uni-socket.io';
|
|
|
|
|
|
import { getImageUrl } from '../../util/common';
|
|
|
|
|
|
import { permissionUtil } from '@/uni_modules/colorful-uni-perm';
|
2025-10-09 15:13:48 +08:00
|
|
|
|
import { messageAPI } from '../../api/message';
|
|
|
|
|
|
import { groupAPI } from '../../api/group';
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
|
|
|
|
|
const navBarRef = ref()
|
2025-09-29 14:42:41 +08:00
|
|
|
|
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()
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const handleFormatDate = (date) => {
|
|
|
|
|
|
const inputDate = new Date(date.replace(/-/g, '/'));
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算日期差(天)
|
|
|
|
|
|
const diffDays = Math.floor((now - inputDate) / (1000 * 60 * 60 * 24));
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间
|
|
|
|
|
|
const hours = inputDate.getHours().toString().padStart(2, '0');
|
|
|
|
|
|
const minutes = inputDate.getMinutes().toString().padStart(2, '0');
|
|
|
|
|
|
const year = inputDate.getFullYear();
|
|
|
|
|
|
const month = (inputDate.getMonth() + 1).toString().padStart(2, '0');
|
|
|
|
|
|
const day = inputDate.getDate().toString().padStart(2, '0');
|
|
|
|
|
|
|
|
|
|
|
|
if (diffDays === 0) {
|
|
|
|
|
|
return `今天 ${hours}:${minutes}`;
|
|
|
|
|
|
} else if (diffDays === 1) {
|
|
|
|
|
|
return '昨天';
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return `${year}-${month}-${day}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 14:42:41 +08:00
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const dataList = ref([])
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
// 模拟聊天数据
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const mockData = () => {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
for (var i = 0; i < 5; i++) {
|
2025-09-28 17:30:20 +08:00
|
|
|
|
if (i % 2 == 0) {
|
|
|
|
|
|
dataList.value.push({
|
|
|
|
|
|
"createId": 3641,
|
|
|
|
|
|
"groupId": "1",
|
2025-10-09 15:13:48 +08:00
|
|
|
|
"content": "即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方也即使在没有空格的地方",
|
2025-09-28 17:30:20 +08:00
|
|
|
|
"type": "text",
|
|
|
|
|
|
"messageId": 44,
|
|
|
|
|
|
"createTime": "2025-09-27T18:32:42.000Z",
|
|
|
|
|
|
"userInfo": {
|
|
|
|
|
|
"id": 9958,
|
|
|
|
|
|
"username": "15867461647",
|
|
|
|
|
|
"userType": "user",
|
|
|
|
|
|
"isSystemAccount": 0,
|
|
|
|
|
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
dataList.value.push({
|
2025-10-09 15:13:48 +08:00
|
|
|
|
"createId": 3641,
|
2025-09-28 17:30:20 +08:00
|
|
|
|
"groupId": "1",
|
2025-10-09 15:13:48 +08:00
|
|
|
|
"content": "即使在没有空格的地方也即使在没",
|
2025-09-28 17:30:20 +08:00
|
|
|
|
"type": "text",
|
|
|
|
|
|
"messageId": 44,
|
|
|
|
|
|
"createTime": "2025-09-27T18:32:42.000Z",
|
|
|
|
|
|
"userInfo": {
|
|
|
|
|
|
"id": 9958,
|
|
|
|
|
|
"username": "15867461647",
|
|
|
|
|
|
"userType": "user",
|
|
|
|
|
|
"isSystemAccount": 0,
|
|
|
|
|
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-10-09 15:13:48 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
dataList.value.push({
|
|
|
|
|
|
"createId": 9955,
|
|
|
|
|
|
"groupId": "1",
|
|
|
|
|
|
"content": "2222",
|
|
|
|
|
|
"type": "text",
|
|
|
|
|
|
"messageId": 44,
|
|
|
|
|
|
"createTime": "2025-09-27T18:32:42.000Z",
|
2025-09-29 14:42:41 +08:00
|
|
|
|
"userInfo": {
|
2025-10-09 15:13:48 +08:00
|
|
|
|
"id": 9958,
|
|
|
|
|
|
"username": "15867461647",
|
|
|
|
|
|
"userType": "user",
|
2025-09-29 14:42:41 +08:00
|
|
|
|
"isSystemAccount": 0,
|
|
|
|
|
|
"avatar": "/uploads/documents/1753833656669_524106424.jpg"
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-10-09 15:13:48 +08:00
|
|
|
|
}
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dataList.value.push(
|
|
|
|
|
|
{
|
|
|
|
|
|
"createId": 3641,
|
|
|
|
|
|
"groupId": "5",
|
|
|
|
|
|
"content": "http://114.55.111.44:9000/jurongquan/app_records/1759049412254.mp3",
|
|
|
|
|
|
"type": "mp3",
|
|
|
|
|
|
"messageId": 56,
|
|
|
|
|
|
"createTime": "2025-09-28T00:50:16.000Z",
|
|
|
|
|
|
"userInfo": {
|
|
|
|
|
|
"id": 3641,
|
|
|
|
|
|
"username": "15867461617",
|
|
|
|
|
|
"userType": "agent",
|
|
|
|
|
|
"isSystemAccount": 0,
|
|
|
|
|
|
"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"
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// 发送消息
|
|
|
|
|
|
const text = ref('')
|
|
|
|
|
|
const showLongText = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
const handleSendText = () => {
|
|
|
|
|
|
uni.hideKeyboard()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
socket.value.emit('clientMsg', {
|
|
|
|
|
|
createId: userId.value,
|
|
|
|
|
|
groupId: groupId.value,
|
|
|
|
|
|
content: text.value,
|
|
|
|
|
|
type: "text"
|
|
|
|
|
|
})
|
2025-09-29 14:42:41 +08:00
|
|
|
|
text.value = ''
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-11 17:30:07 +08:00
|
|
|
|
const handleinformation = () => {
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: '/pages/message/information'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// 文本放大
|
|
|
|
|
|
const handleMagnify = () => {
|
|
|
|
|
|
showLongText.value = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 录音
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const showMic = ref(false)
|
|
|
|
|
|
const showMask = ref(false)
|
|
|
|
|
|
const showMaskBtn = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
const msgToast = ref(null)
|
|
|
|
|
|
|
|
|
|
|
|
const voicePath = ref('')
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
const recorderManager = uni.getRecorderManager(); // 录音管理器
|
|
|
|
|
|
const innerAudioContext = uni.createInnerAudioContext(); // 音频管理器
|
|
|
|
|
|
const options = {
|
|
|
|
|
|
duration: 60000, // 录音时长,单位为毫秒
|
|
|
|
|
|
sampleRate: 44100, // 采样率
|
|
|
|
|
|
numberOfChannels: 2, // 通道数
|
|
|
|
|
|
format: 'mp3', // 音频格式
|
|
|
|
|
|
};
|
|
|
|
|
|
const isPlayRecord = ref(false)
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
|
|
|
|
|
// 选择麦克风
|
|
|
|
|
|
const handleChangeMic = () => {
|
|
|
|
|
|
showMic.value = !showMic.value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 开始录音
|
|
|
|
|
|
const handleSay = () => {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
permissionUtil.requestAndroidPermission('android.permission.RECORD_AUDIO').then((status) => {
|
2025-09-28 17:30:20 +08:00
|
|
|
|
// status 为 1 表示用户已授权,0 表示用户已拒绝, -1 表示用户永久拒绝
|
|
|
|
|
|
console.log('权限申请结果:', status);
|
|
|
|
|
|
if (status == -1) {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
msgErrorRcord()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
} else if (status == 1) {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// start方法无法被及时调用的处理方法
|
|
|
|
|
|
while (!showMask.value) {
|
|
|
|
|
|
recorderManager.start(options);
|
|
|
|
|
|
recorderManager.onStart(() => {
|
|
|
|
|
|
console.log('录音开始');
|
|
|
|
|
|
showMask.value = true
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (status == 0) {
|
|
|
|
|
|
msgErrorRcord()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
const msgErrorRcord = () => {
|
|
|
|
|
|
msgToast.value.show({
|
|
|
|
|
|
title: '请确认您的麦克风权限是否开启',
|
|
|
|
|
|
type: 'error'
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
// 停止录音
|
|
|
|
|
|
const handleStopMic = () => {
|
|
|
|
|
|
showMaskBtn.value = true
|
|
|
|
|
|
if (voicePath.value) {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
isPlayRecord.value = true
|
2025-09-28 17:30:20 +08:00
|
|
|
|
innerAudioContext.src = voicePath.value
|
|
|
|
|
|
innerAudioContext.play();
|
2025-09-29 14:42:41 +08:00
|
|
|
|
innerAudioContext.onEnded(() => {
|
|
|
|
|
|
isPlayRecord.value = false
|
|
|
|
|
|
})
|
2025-09-28 17:30:20 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
recorderManager.stop()
|
|
|
|
|
|
// showMask.value = false
|
|
|
|
|
|
recorderManager.onStop(function (res) {
|
|
|
|
|
|
console.log('recorder stop' + JSON.stringify(res));
|
|
|
|
|
|
voicePath.value = res.tempFilePath;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 取消发送录音
|
|
|
|
|
|
const handleCancel = () => {
|
|
|
|
|
|
showMask.value = false
|
|
|
|
|
|
showMaskBtn.value = false
|
|
|
|
|
|
voicePath.value = ''
|
2025-09-29 14:42:41 +08:00
|
|
|
|
innerAudioContext.stop()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送录音文件
|
|
|
|
|
|
const handleSendMp3 = () => {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
innerAudioContext.stop()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const token = uni.getStorageSync("token")
|
|
|
|
|
|
uni.uploadFile({
|
|
|
|
|
|
// url: 'http://192.168.0.4:3005/upload',
|
|
|
|
|
|
url: 'http://192.168.0.15:3007/upload/file',
|
|
|
|
|
|
filePath: voicePath.value,
|
|
|
|
|
|
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: "mp3"
|
|
|
|
|
|
})
|
|
|
|
|
|
showMask.value = false
|
|
|
|
|
|
showMaskBtn.value = false
|
|
|
|
|
|
voicePath.value = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (res) => {
|
|
|
|
|
|
console.log(JSON.stringify(res));
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// 打开相册
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const handleCamera = () => {
|
|
|
|
|
|
permissionUtil.requestAndroidPermission('android.permission.READ_EXTERNAL_STORAGE').then((status) => {
|
|
|
|
|
|
console.log('相册权限申请结果:', status);
|
|
|
|
|
|
if (status == -1) {
|
|
|
|
|
|
// 弹窗提示开启权限
|
|
|
|
|
|
msgToast.value.show({
|
|
|
|
|
|
title: '您已关闭读取相册权限,请在设置开启应用相册权限',
|
|
|
|
|
|
type: 'warning'
|
|
|
|
|
|
})
|
|
|
|
|
|
} else if (status == 1) {
|
|
|
|
|
|
uni.chooseImage({
|
|
|
|
|
|
count: 10, //默认9
|
|
|
|
|
|
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
|
|
|
|
|
sourceType: ['album'], //从相册选择
|
|
|
|
|
|
success: function (res) {
|
|
|
|
|
|
uploadImages(res.tempFilePaths)
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// 上传图片
|
|
|
|
|
|
const uploadImages = (imgList : any) => {
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const token = uni.getStorageSync("token")
|
2025-09-29 14:42:41 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2025-09-28 17:30:20 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
|
|
|
|
|
|
// 图片预览
|
|
|
|
|
|
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()
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
// 初始化
|
2025-09-28 17:30:20 +08:00
|
|
|
|
const groupId = ref()
|
|
|
|
|
|
const userId = ref()
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const chatTitle = ref()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const scrollTop = ref(0)
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// 通信连接
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const socket = ref()
|
|
|
|
|
|
|
|
|
|
|
|
const connection = async () => {
|
|
|
|
|
|
console.log("连接服务器");
|
|
|
|
|
|
socket.value = io(`http://192.168.0.15:3007?userId=${userId.value}`, {
|
2025-09-28 17:30:20 +08:00
|
|
|
|
query: {},
|
|
|
|
|
|
transports: ['websocket', 'polling'],
|
|
|
|
|
|
timeout: 5000,
|
|
|
|
|
|
});
|
2025-10-09 15:13:48 +08:00
|
|
|
|
socket.value.on('connect', () => {
|
2025-09-28 17:30:20 +08:00
|
|
|
|
console.log("连接成功");
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
|
|
|
|
|
// socket.value.emit('cleanup')
|
|
|
|
|
|
socket.value.emit('addGroup', {
|
|
|
|
|
|
groupId: groupId.value
|
|
|
|
|
|
})
|
|
|
|
|
|
socket.value.on('serverMsg', async (message : any) => {
|
|
|
|
|
|
dataList.value.push(message)
|
|
|
|
|
|
// console.log(dataList.value);
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
scrollToBottom()
|
|
|
|
|
|
}, 500)
|
|
|
|
|
|
})
|
2025-09-28 17:30:20 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const disConnection = () => {
|
|
|
|
|
|
console.log("disConnection");
|
|
|
|
|
|
socket.value.emit('leaveGroup', {
|
|
|
|
|
|
groupId: groupId.value
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-09-29 14:42:41 +08:00
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const loadUnReadData = () => {
|
|
|
|
|
|
// 获取用户ID
|
2025-09-28 17:30:20 +08:00
|
|
|
|
userId.value = uni.getStorageSync("user").id
|
2025-10-09 15:13:48 +08:00
|
|
|
|
// 获取标题
|
|
|
|
|
|
groupAPI.getById(groupId.value).then(res => {
|
2025-10-15 17:22:54 +08:00
|
|
|
|
// chatTitle.value = res.data.program.linkman.username + "(" + res.data.program.name + ")"
|
|
|
|
|
|
chatTitle.value = res.data.program.name
|
2025-10-09 15:13:48 +08:00
|
|
|
|
})
|
2025-10-15 17:22:54 +08:00
|
|
|
|
loadHistoryData() // 最近10条
|
|
|
|
|
|
setTimeout(()=>{
|
|
|
|
|
|
scrollToBottom()
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
// 未读变已读
|
2025-10-15 17:22:54 +08:00
|
|
|
|
// let data = { groupId: groupId.value, userId: userId.value }
|
|
|
|
|
|
// messageAPI.unread(data).then(res => {
|
|
|
|
|
|
// if (res.code == 200) {
|
|
|
|
|
|
// dataList.value = dataList.value.concat(res.data)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// })
|
2025-10-09 15:13:48 +08:00
|
|
|
|
messageAPI.read({ groupId: groupId.value, userId: userId.value })
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
const params = ref({
|
|
|
|
|
|
page: 1,
|
|
|
|
|
|
size: 10,
|
|
|
|
|
|
groupId: null
|
|
|
|
|
|
})
|
|
|
|
|
|
const loadFix = ref(true)
|
|
|
|
|
|
|
|
|
|
|
|
// 历史记录
|
2025-10-15 17:22:54 +08:00
|
|
|
|
const loadHistoryData = async () => {
|
2025-10-09 15:13:48 +08:00
|
|
|
|
params.value.groupId = groupId.value
|
2025-10-15 17:22:54 +08:00
|
|
|
|
await messageAPI.list(params.value).then(res => {
|
|
|
|
|
|
// console.log(res);
|
2025-10-09 15:13:48 +08:00
|
|
|
|
if (res.data.list.length != 0) {
|
|
|
|
|
|
res.data.list.forEach(item => {
|
|
|
|
|
|
dataList.value.unshift(item)
|
|
|
|
|
|
})
|
|
|
|
|
|
params.value.page++
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onPullDownRefresh(() => {
|
|
|
|
|
|
loadHistoryData()
|
|
|
|
|
|
uni.stopPullDownRefresh()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
onLoad((val) => {
|
|
|
|
|
|
groupId.value = val.groupId
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onReady(() => {
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
onMounted(() => {
|
2025-10-09 15:13:48 +08:00
|
|
|
|
loadHeight()
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
// mockData()
|
2025-10-09 15:13:48 +08:00
|
|
|
|
loadUnReadData()
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
|
|
|
|
|
connection()
|
|
|
|
|
|
})
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
|
|
|
|
|
onUnload(() => {
|
|
|
|
|
|
disConnection()
|
|
|
|
|
|
})
|
2025-09-28 17:30:20 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.chat-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
background: linear-gradient(180deg, #E3E8FF 0%, #FFFFFF 100%);
|
|
|
|
|
|
background-blend-mode: lighten;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.collection {
|
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bottom-view {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100rpx;
|
|
|
|
|
|
// background-color: #aaffff;
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 10rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.icon {
|
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
|
height: 60rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.text {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 96%;
|
|
|
|
|
|
border: 2rpx solid #DEEFFF;
|
|
|
|
|
|
border-radius: 10rpx;
|
|
|
|
|
|
padding: 0 10rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.btn-mic {
|
2025-09-29 14:42:41 +08:00
|
|
|
|
flex: 1;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.scroll-main {
|
|
|
|
|
|
.my-message {
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.msg-main {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
padding: 0 10rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.msg-content {
|
|
|
|
|
|
// background-color: #00ffff;
|
|
|
|
|
|
padding: 2rpx;
|
|
|
|
|
|
width: 70%;
|
|
|
|
|
|
margin-right: 10rpx;
|
|
|
|
|
|
// border: 1rpx solid #c7c7c7;
|
|
|
|
|
|
box-sizing: content-box;
|
|
|
|
|
|
|
|
|
|
|
|
.text {
|
|
|
|
|
|
overflow-wrap: break-word;
|
|
|
|
|
|
text-align: right;
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
|
|
|
|
|
background-color: #4873FF;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
padding: 10rpx;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
|
|
|
|
|
|
box-shadow: 0rpx 4rpx 8rpx 0rpx #00000040;
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mp3-content {
|
|
|
|
|
|
padding: 2rpx;
|
|
|
|
|
|
// width: 70%;
|
|
|
|
|
|
margin-right: 10rpx;
|
|
|
|
|
|
box-sizing: content-box;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.mp3 {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
// border: 1rpx solid #000;
|
|
|
|
|
|
padding: 15rpx 10rpx;
|
|
|
|
|
|
background-color: #55ff7f;
|
2025-10-09 15:13:48 +08:00
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
// align-items: center;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
|
|
|
|
|
|
.mp3-icon {
|
2025-10-09 15:13:48 +08:00
|
|
|
|
// margin: 0 10rpx;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
width: 25rpx;
|
|
|
|
|
|
height: 25rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-29 14:42:41 +08:00
|
|
|
|
.img-content {
|
|
|
|
|
|
margin-right: 10rpx;
|
|
|
|
|
|
height: 200rpx;
|
2025-10-09 15:13:48 +08:00
|
|
|
|
margin-bottom: 30rpx;
|
2025-09-29 14:42:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
.msg-avatar {
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.other-message {
|
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.msg-main {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
padding: 0 10rpx;
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
.msg-avatar {
|
|
|
|
|
|
width: 80rpx;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
.msg-content {
|
|
|
|
|
|
// background-color: #00ffff;
|
|
|
|
|
|
padding: 2rpx;
|
|
|
|
|
|
width: 70%;
|
2025-10-09 15:13:48 +08:00
|
|
|
|
margin-left: 10rpx;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
// border: 1rpx solid #c7c7c7;
|
|
|
|
|
|
box-sizing: content-box;
|
|
|
|
|
|
|
|
|
|
|
|
.text {
|
|
|
|
|
|
overflow-wrap: break-word;
|
|
|
|
|
|
text-align: left;
|
2025-10-09 15:13:48 +08:00
|
|
|
|
background-color: #F0F3FF;
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
padding: 10rpx;
|
|
|
|
|
|
|
|
|
|
|
|
box-shadow: 0rpx 4rpx 8rpx 0rpx #00000040;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-09 15:13:48 +08:00
|
|
|
|
.mp3-content {
|
|
|
|
|
|
padding: 2rpx;
|
|
|
|
|
|
// width: 70%;
|
|
|
|
|
|
margin-left: 10rpx;
|
|
|
|
|
|
box-sizing: content-box;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.mp3 {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
// border: 1rpx solid #000;
|
|
|
|
|
|
padding: 15rpx 10rpx;
|
|
|
|
|
|
background-color: #55ff7f;
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.mp3-icon {
|
|
|
|
|
|
margin: 0 10rpx;
|
|
|
|
|
|
width: 25rpx;
|
|
|
|
|
|
height: 25rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.img-content {
|
|
|
|
|
|
margin-left: 10rpx;
|
|
|
|
|
|
height: 200rpx;
|
2025-10-15 17:22:54 +08:00
|
|
|
|
margin-bottom: 30rpx;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
2025-10-09 15:13:48 +08:00
|
|
|
|
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.long-text {
|
|
|
|
|
|
padding: 40rpx 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mask-warp {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
|
|
|
|
.mask-text {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
color: #fff;
|
2025-09-29 14:42:41 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mask-btn {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
|
|
width: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-29 14:42:41 +08:00
|
|
|
|
|
|
|
|
|
|
// 图片预览
|
|
|
|
|
|
.mask-pre-img {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
}
|
2025-09-28 17:30:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|