完成短信(苹果,华为,小米,vivo)各个机型发送图片功能,预览图片页面及图片信息列表展示样式

This commit is contained in:
tangxinyue 2026-06-04 09:55:08 +08:00
parent 1cd2226f2b
commit 6569f821e8
11 changed files with 1581 additions and 1050 deletions

File diff suppressed because it is too large Load Diff

View File

@ -34,24 +34,45 @@
</image>
</view>
<view class="chat-box" :id="'msg-' + index" :class="{
'tail-right': shouldApplyTailRight(index) && !isImageMsg(message),
'tail-right': (shouldApplyTailRight(index) || isLastMeMessage(index)) && !isImageMsg(message),
'tail-left': shouldApplyTailLeft(index) && !isImageMsg(message),
'image-tail-left': shouldApplyTailLeft(index) && isImageMsg(message),
'delivered': isLastMeMessage(index)
}" @longpress="!sortMode && onMessageLongPress(index, message)">
<text v-if="message.isMe && phone == 'mi'" class="send-text">送达</text>
<view class="chat-bubble" :class="{ 'image-bubble': isImageMsg(message) }">
<image v-if="isImageMsg(message)" :src="getImageSrc(message)" mode="aspectFill"
class="chat-image" :style="getImageStyle(message)" @tap.stop="handleImageClick(message)">
</image>
<view v-if="isImageMsg(message)" class="image-wrap" :class="{
'image-wrap-left': phone == 'iphone' && shouldApplyTailLeft(index) && isImageMsg(message),
'image-wrap-right': phone == 'iphone' && shouldApplyTailRight(index) && isImageMsg(message)
}">
<image :src="getImageSrc(message)" :mode="getImageMode(message, phone)"
class="chat-image" :class="{
'chat-image-left': phone == 'iphone' && shouldApplyTailLeft(index) && isImageMsg(message),
'chat-image-right': phone == 'iphone' && shouldApplyTailRight(index) && isImageMsg(message)
}" :style="phone == 'iphone' ? '' : getImageStyle(message)"
@tap.stop="handleImageClick(message)">
</image>
<image v-if="phone == 'iphone'" :class="{
'mask-left-bottom': phone == 'iphone' && shouldApplyTailLeft(index) && isImageMsg(message),
'mask-right-bottom': phone == 'iphone' && shouldApplyTailRight(index) && isImageMsg(message)
}" style="width: 46rpx;height:10rpx;"
src="/static/image/phone-message/iphone/iphone-mask.png"></image>
</view>
<rich-text v-else :nodes="formatMessageContent(message.content, message.isMe)"></rich-text>
</view>
<image v-if="shouldApplyTailLeft(index) && isImageMsg(message) && phone == 'iphone'"
style="width: 68rpx;height: 68rpx;" src="/static/image/phone-message/iphone/save.png">
</image>
<!-- <text v-if="message.isMe && phone == 'iphone' && isLastMeMessage(index)"
class="send-text">已送达</text> -->
</view>
<view v-if="phone == 'huawei'" class="second-info">
<text>{{ formatHuaweiBottomTime(message.time) }}</text>
<image :src="`/static/image/phone-message/huawei/chat-ka${message.simIndex}.png`"></image>
</view>
<view v-if="(phone == 'oppo' || phone == 'vivo') && message.isMe" class="second-info">
<text v-if="message.isMe" class="delivered">已送达</text>
<text v-if="message.isMe" class="delivered">{{ phone == 'vivo' ? '已发送' : '已送达' }}</text>
</view>
</view>
</view>
@ -68,6 +89,7 @@ const handleImageClick = (message) => {
if (!src) return;
const allImages = [];
const allTimes = [];
let clickIndex = 0;
displayList.value.forEach(msg => {
@ -78,12 +100,13 @@ const handleImageClick = (message) => {
clickIndex = allImages.length;
}
allImages.push(imgSrc);
allTimes.push(msg.time);
}
}
});
if (props.phone === 'oppo') {
emit('previewImage', { images: allImages, index: clickIndex });
if (props.phone === 'oppo' || props.phone === 'mi') {
emit('previewImage', { images: allImages, index: clickIndex, times: allTimes });
} else {
uni.previewImage({ urls: allImages, current: clickIndex });
}
@ -136,9 +159,9 @@ let sortItemRects = []
watch(() => props.sortMode, (val) => {
if (val) {
let list = props.messageList;
if (props.phone !== 'oppo') {
list = list.filter(msg => !isImageMsg(msg));
}
// if (props.phone !== 'oppo') {
// list = list.filter(msg => !isImageMsg(msg));
// }
localSortList.value = list.map(item => ({ ...item }))
} else {
dragIndex.value = -1
@ -154,9 +177,9 @@ const displayList = computed(() => {
if (props.sortMode) return localSortList.value
let list = props.messageList;
if (props.phone !== 'oppo') {
list = list.filter(msg => !isImageMsg(msg));
}
// if (props.phone !== 'oppo') {
// list = list.filter(msg => !isImageMsg(msg));
// }
return list;
})
@ -200,12 +223,8 @@ const shouldApplyTailRight = (index) => {
// c: isMe == false ()
if (!nextMsg.isMe) return true;
// a: (180000 ) - 线
const currentMsgTime = new Date(currentMsg.time.replace(/-/g, '/')).getTime();
const nextMsgTime = new Date(nextMsg.time.replace(/-/g, '/')).getTime();
if (!isNaN(currentMsgTime) && !isNaN(nextMsgTime) && (nextMsgTime - currentMsgTime > 180000)) {
return true;
}
//
if (shouldShowTime(index + 1)) return true;
//
return false;
@ -224,21 +243,11 @@ const shouldApplyTailLeft = (index) => {
// c: isMe == true
if (nextMsg.isMe) return true;
// a: (180000 )
const currentMsgTime = new Date(currentMsg.time.replace(/-/g, '/')).getTime();
const nextMsgTime = new Date(nextMsg.time.replace(/-/g, '/')).getTime();
if (!isNaN(currentMsgTime) && !isNaN(nextMsgTime) && (nextMsgTime - currentMsgTime > 180000)) {
return true;
}
//
if (shouldShowTime(index + 1)) return true;
// b: isMe == false
for (let i = index + 1; i < displayList.value.length; i++) {
if (!displayList.value[i].isMe) {
return false; // isMe==false
}
}
return true;
//
return false;
}
//
@ -392,9 +401,55 @@ const getImageSrc = (message) => {
return '';
}
//
const getImageMode = (message, phone) => {
if (phone === 'iphone') return 'widthFix';
if (phone === 'huawei') {
const w = parseInt(message.imgWidth);
const h = parseInt(message.imgHeight);
if (!isNaN(w) && !isNaN(h)) {
if (h > w) return 'heightFix';
return 'widthFix';
}
return 'widthFix';
}
return 'aspectFill';
}
//
const getImageStyle = (message) => {
if (message.imgWidth && message.imgHeight) {
if (props.phone === 'mi') {
const w = parseInt(message.imgWidth);
const h = parseInt(message.imgHeight);
if (!isNaN(w) && !isNaN(h)) {
if (h > w) {
return { width: '214rpx', height: '256rpx' };
} else {
return { width: '256rpx', height: '214rpx' };
}
}
} else if (props.phone === 'vivo') {
const w = parseInt(message.imgWidth);
const h = parseInt(message.imgHeight);
if (!isNaN(w) && !isNaN(h)) {
if (h > w) {
return { width: '284rpx', height: '400rpx' };
} else {
return { width: '400rpx', height: '284rpx' };
}
}
} else if (props.phone === 'huawei') {
const w = parseInt(message.imgWidth);
const h = parseInt(message.imgHeight);
if (!isNaN(w) && !isNaN(h)) {
if (h > w) {
return { height: '500rpx', 'max-height': '500rpx' };
} else {
return { width: '500rpx', 'max-width': '500rpx' };
}
}
}
return {
width: message.imgWidth,
height: message.imgHeight
@ -550,7 +605,7 @@ const onSortTouchEnd = () => {
background-color: transparent !important;
padding: 0 !important;
border: none !important;
border-radius: 16rpx !important;
// border-radius: 16rpx !important;
overflow: hidden;
}
@ -597,6 +652,85 @@ const onSortTouchEnd = () => {
margin: 4rpx 30rpx 0;
word-break: break-all;
}
.image-bubble {
border-radius: 0 !important;
margin-left: 10rpx;
}
.image-wrap-left {
position: relative;
&::before {
content: "";
position: absolute;
z-index: 10;
top: 0;
left: 10px;
width: 17px;
height: 17px;
/* 使用径向渐变画出反向圆角中心点在右下角34rpx以内透明以外纯白 */
background: radial-gradient(circle at bottom right, transparent 16.5px, #FFFFFF 17px);
}
&::after {
content: "";
position: absolute;
z-index: 10;
height: 100%;
width: 10px;
background-color: #FFFFFF !important;
left: 0px;
top: 0;
bottom: 0;
border-radius: 0 0 10px 0;
}
}
.image-wrap-right {
position: relative;
&::before {
content: "";
position: absolute;
z-index: 10;
top: 0;
right: 10px;
width: 17px;
height: 17px;
/* 使用径向渐变画出反向圆角中心点在右下角34rpx以内透明以外纯白 */
background: radial-gradient(circle at bottom left, transparent 16.5px, #FFFFFF 17px);
}
&::after {
content: "";
position: absolute;
z-index: 10;
height: 100%;
width: 10px;
background-color: #FFFFFF !important;
right: 0px;
top: 0;
bottom: 0;
border-radius: 0 0 0 10px;
}
}
.mask-left-bottom {
position: absolute;
left: 7px;
bottom: 0px;
}
.mask-right-bottom {
position: absolute;
right: 7px;
bottom: 0px;
transform: scaleX(-1);
}
}
@ -615,6 +749,14 @@ const onSortTouchEnd = () => {
position: relative;
}
.image-tail-left {
align-items: center;
::v-deep.image-bubble {
margin-right: 24rpx !important;
}
}
.tail-left::after {
position: absolute;
left: 18rpx;
@ -630,6 +772,23 @@ const onSortTouchEnd = () => {
position: relative;
}
.delivered {
display: flex;
flex-direction: column;
align-items: flex-end;
position: relative;
margin-bottom: 70rpx;
.send-text {
margin-right: 32rpx;
font-weight: 400;
font-size: 20rpx;
color: #8B8B8B;
line-height: 20rpx;
margin-top: 12rpx;
}
}
.delivered::before {
position: absolute;
right: 18rpx;
@ -651,10 +810,28 @@ const onSortTouchEnd = () => {
width: 28rpx;
height: 36rpx;
}
.chat-image {
width: 516rpx;
max-width: 516rpx !important;
}
.chat-image-left {
border-radius: 0 34rpx 34rpx 0;
}
.chat-image-right {
border-radius: 34rpx 0 0 34rpx;
}
}
//
.mi-style {
.chat-image {
border-radius: 40rpx;
}
.top-text {
text-align: center;
font-size: 20rpx;
@ -888,6 +1065,10 @@ const onSortTouchEnd = () => {
margin-top: 24rpx !important;
}
.chat-image {
border-radius: 32rpx;
}
.time {
color: #ACACAC;
font-size: 24rpx;

View File

@ -1,20 +1,51 @@
<template>
<view class="preview-container" v-if="show">
<view class="header" @tap.stop :style="{ 'padding-top': statusBarHeight }">
<image class="icon-back" src="/static/image/phone-message/oppo/back-white.png" @tap="close"></image>
<image class="icon-download" src="/static/image/phone-message/oppo/save-white.png"></image>
</view>
<!-- 图片显示 -->
<swiper class="preview-swiper" :current="current" @change="onChange">
<swiper-item v-for="(imgSrc, index) in images" :key="index">
<image class="preview-img" :src="imgSrc" mode="aspectFit"></image>
</swiper-item>
</swiper>
<view class="preview-container" :class="phone === 'mi' ? 'mi-bg' : 'oppo-bg'" v-if="show">
<template v-if="phone === 'oppo' || !phone || phone === 'iphone' || phone === 'huawei' || phone === 'vivo'">
<view class="header" @tap.stop :style="{ 'padding-top': statusBarHeight }">
<image class="icon-back" src="/static/image/phone-message/oppo/back-white.png" @tap="close"></image>
<image class="icon-download" src="/static/image/phone-message/oppo/save-white.png"></image>
</view>
<!-- 图片显示 -->
<swiper class="preview-swiper" :current="current" @change="onChange">
<swiper-item v-for="(imgSrc, index) in images" :key="index">
<image class="preview-img" :src="imgSrc" mode="aspectFit"></image>
</swiper-item>
</swiper>
</template>
<template v-else-if="phone === 'mi'">
<view class="mi-header" @tap.stop :style="{ 'padding-top': statusBarHeight }">
<!-- 复用现有返回图标并通过滤镜反色 -->
<image class="mi-icon-back" src="/static/image/phone-message/oppo/back-white.png" @tap="close"></image>
<view class="mi-header-center">
<view class="mi-date">{{ currentFormatDate }}</view>
<view class="mi-time">{{ currentFormatTime }}</view>
</view>
<view class="mi-icon-right"></view> <!-- 占位符以居中 -->
</view>
<swiper class="preview-swiper mi-swiper" :current="current" @change="onChange">
<swiper-item v-for="(imgSrc, index) in images" :key="index">
<view class="mi-img-container">
<image class="mi-preview-img" :src="imgSrc" mode="aspectFill"></image>
</view>
</swiper-item>
</swiper>
<view class="mi-footer">
<view class="mi-footer-item">
<image class="mi-footer-icon" src="/static/image/phone-message/mi/baocun.png"></image>
<view class="mi-footer-text">保存</view>
</view>
<view class="mi-footer-item">
<view class="mi-more-icon"></view>
<view class="mi-footer-text">更多</view>
</view>
</view>
</template>
</view>
</template>
<script setup>
import { ref, watch } from 'vue';
import { ref, watch, computed } from 'vue';
const statusBarHeight = (uni.getSystemInfoSync().statusBarHeight || 44) + 'px';
@ -24,9 +55,17 @@ const props = defineProps({
type: Array,
default: () => []
},
times: {
type: Array,
default: () => []
},
currentIndex: {
type: Number,
default: 0
},
phone: {
type: String,
default: ''
}
});
const emit = defineEmits(['update:show']);
@ -41,6 +80,53 @@ const onChange = (e) => {
current.value = e.detail.current;
};
const currentFormatDate = computed(() => {
if (props.times && props.times.length > current.value) {
const timeVal = props.times[current.value];
if (timeVal) {
if (typeof timeVal === 'string' && timeVal.includes('-')) {
const parts = timeVal.split(' ');
if (parts.length > 0) {
const dateParts = parts[0].split('-');
if (dateParts.length === 3) {
return `${dateParts[0]}${parseInt(dateParts[1])}${parseInt(dateParts[2])}`;
}
}
}
// Fallback
const safeTimeStr = String(timeVal).replace(/-/g, '/');
const d = new Date(safeTimeStr);
if (!isNaN(d.getTime())) {
return `${d.getFullYear()}${d.getMonth() + 1}${d.getDate()}`;
}
}
}
return '';
});
const currentFormatTime = computed(() => {
if (props.times && props.times.length > current.value) {
const timeVal = props.times[current.value];
if (timeVal) {
if (typeof timeVal === 'string' && timeVal.includes(':')) {
const parts = timeVal.split(' ');
if (parts.length > 1) {
return parts[1];
}
}
// Fallback
const safeTimeStr = String(timeVal).replace(/-/g, '/');
const d = new Date(safeTimeStr);
if (!isNaN(d.getTime())) {
const h = d.getHours().toString().padStart(2, '0');
const m = d.getMinutes().toString().padStart(2, '0');
return `${h}:${m}`;
}
}
}
return '';
});
const close = () => {
emit('update:show', false);
};
@ -75,12 +161,19 @@ const close = () => {
left: 0;
width: 100vw;
height: 100vh;
background-color: #000000;
z-index: 999999;
display: flex;
flex-direction: column;
}
.oppo-bg {
background-color: #000000;
}
.mi-bg {
background-color: #FFFFFF;
}
.header {
box-sizing: content-box;
width: 100%;
@ -122,4 +215,113 @@ const close = () => {
height: 100%;
display: block;
}
/* ================= 小米样式 ================= */
.mi-header {
box-sizing: content-box;
width: 100%;
height: 98rpx;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
top: 0;
left: 0;
z-index: 2;
background-color: #FFFFFF;
}
.mi-icon-back {
width: 48rpx;
height: 48rpx;
margin: 0 34rpx;
filter: invert(1);
/* 白变黑 */
}
.mi-icon-right {
width: 48rpx;
height: 48rpx;
margin: 0 34rpx;
}
.mi-header-center {
display: flex;
flex-direction: column;
align-items: center;
}
.mi-date {
font-size: 32rpx;
color: #333333;
font-weight: 500;
}
.mi-time {
font-size: 24rpx;
color: #999999;
margin-top: 4rpx;
}
.mi-swiper {
z-index: 1;
display: flex;
align-items: center;
}
.mi-img-container {
width: 100vw;
height: 100vw;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.mi-preview-img {
width: 100%;
height: 100%;
display: block;
}
.mi-footer {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 160rpx;
background-color: #FFFFFF;
display: flex;
justify-content: space-around;
align-items: flex-start;
padding-top: 20rpx;
z-index: 2;
}
.mi-footer-item {
display: flex;
flex-direction: column;
align-items: center;
}
.mi-footer-icon {
width: 48rpx;
height: 48rpx;
margin-bottom: 8rpx;
}
.mi-more-icon {
width: 48rpx;
height: 48rpx;
line-height: 38rpx;
font-size: 40rpx;
text-align: center;
color: #000;
margin-bottom: 8rpx;
font-weight: bold;
}
.mi-footer-text {
font-size: 24rpx;
color: #666666;
}
</style>

View File

@ -21,14 +21,25 @@
<view class="title-box flex-between">
<text class="title">{{ displayTitle(item.title) }}</text>
<text class="time">{{ formatDate(getLastMessage(item.chatList)?.time || item.time)
}}</text>
}}</text>
</view>
<view class="content">
<view v-if="isImageMsg(getLastMessage(item.chatList))"
class="flex flex-align-center">
<image style="width: 24rpx;height: 24rpx;margin-right: 16rpx;"
src="/static/image/phone-message/oppo/link.png"></image>
<text>[图片]</text>
<template v-if="phone === 'iphone'">
<text>附件: 1张照片</text>
</template>
<template v-else-if="phone === 'huawei'">
<text>您的好友给您发了一个图片</text>
</template>
<template v-else-if="phone == 'oppo'">
<image style="width: 24rpx;height: 24rpx;margin-right: 16rpx;"
src="/static/image/phone-message/oppo/link.png"></image>
<text>[图片]</text>
</template>
<template v-else>
<text>[图片]</text>
</template>
</view>
<rich-text v-else :nodes="getLastMessage(item.chatList)?.content || ''"></rich-text>
</view>
@ -37,7 +48,8 @@
<image v-if="phone == 'iphone'" src="/static/image/phone-message/iphone/right.png">
</image>
<image v-if="item.noNotice && phone == 'iphone'" class="m-t-8"
src="/static/image/phone-message/iphone/notice.png"></image>
src="/static/image/phone-message/iphone/notice.png">
</image>
</view>
</view>
</view>
@ -133,20 +145,11 @@ const isImageMsg = (message) => {
}
/**
* 获取最新一条有效消息 oppo 屏蔽图片消息
* 获取最新一条有效消息
*/
const getLastMessage = (chatList) => {
if (!chatList || chatList.length === 0) return null;
if (props.phone === 'oppo') {
return chatList[chatList.length - 1];
}
// oppo
for (let i = chatList.length - 1; i >= 0; i--) {
if (!isImageMsg(chatList[i])) {
return chatList[i];
}
}
return null;
return chatList[chatList.length - 1];
}
/**

View File

@ -1,4 +1,4 @@
<template>
<template>
<!-- 水印 -->
<view v-if="$isVip()">
<watermark dark="light" source="uni_alipay_other_message" />
@ -88,7 +88,14 @@
<view class="edit-row">
<text class="edit-label">内容</text>
</view>
<editor id="editor" class="edit-textarea" placeholder="请输入消息内容..." @ready="onEditorReady">
<template v-if="editingMessage && editingMessage.type === 'image'">
<view class="edit-image-replace-box" @tap="replaceEditImage">
<image :src="editingNewImg || editingMessage.imgUrl" mode="aspectFit" class="replace-img">
</image>
<view class="replace-tip">点击替换图片</view>
</view>
</template>
<editor v-else id="editor" class="edit-textarea" placeholder="请输入消息内容..." @ready="onEditorReady">
</editor>
</view>
<view class="edit-footer">
@ -161,7 +168,8 @@
</view>
</view>
</view>
<ImagePreview v-model:show="showPreview" :images="previewImages" :currentIndex="previewIndex" />
<ImagePreview v-model:show="showPreview" :images="previewImages" :times="previewTimes"
:currentIndex="previewIndex" :phone="data.phone" />
</view>
</template>
@ -199,13 +207,26 @@ const selectedMessage = ref(null)
const showEditPopup = ref(false)
const editingMessage = ref(null)
const editingNewImg = ref("")
const replaceEditImage = () => {
uni.chooseImage({
count: 1,
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
editingNewImg.value = res.tempFilePaths[0];
}
}
})
}
const showPreview = ref(false)
const previewImages = ref([])
const previewTimes = ref([])
const previewIndex = ref(0)
const handlePreviewImage = (data) => {
previewImages.value = data.images
previewIndex.value = data.index
previewTimes.value = data.times || []
showPreview.value = true
}
@ -251,7 +272,7 @@ const saveChatList = () => {
const onEditorReady = () => {
uni.createSelectorQuery().select('#editor').context((res) => {
editorCtx = res.context
if (editingMessage.value && editingMessage.value.content) {
if (editingMessage.value && editingMessage.value.content && editingMessage.value.type !== 'image') {
editorCtx.setContents({
html: editingMessage.value.content
})
@ -296,6 +317,7 @@ const closeActionPopup = () => {
*/
const handleEdit = () => {
editingMessage.value = selectedMessage.value;
editingNewImg.value = "";
editingTime.value = selectedMessage.value.time || "";
//
const parts = (selectedMessage.value.time || "").split(' ')
@ -308,7 +330,7 @@ const handleEdit = () => {
closeActionPopup();
//
if (editorCtx) {
if (editorCtx && editingMessage.value.type !== 'image') {
setTimeout(() => {
editorCtx.setContents({
html: editingMessage.value.content
@ -320,6 +342,7 @@ const handleEdit = () => {
const closeEditPopup = () => {
showEditPopup.value = false;
editingMessage.value = null;
editingNewImg.value = "";
}
/**
@ -346,32 +369,121 @@ const onSimKaChange = (value) => {
editingSimKa.value = value
}
const confirmEdit = () => {
if (editingMessage.value && editorCtx) {
editorCtx.getContents({
success: (res) => {
const index = messageList.value.findIndex(item => item.id === editingMessage.value.id)
if (index > -1) {
messageList.value[index].content = res.html;
messageList.value[index].time = editingTime.value;
// timeMode: 'auto'|'show'|'hide'
if (editingTimeMode.value === 'auto') {
delete messageList.value[index].timeMode;
} else {
messageList.value[index].timeMode = editingTimeMode.value;
}
// hideTime
delete messageList.value[index].hideTime;
if (editingSimKa.value) {
messageList.value[index].simIndex = Number(editingSimKa.value);
} else {
delete messageList.value[index].simIndex;
const confirmEdit = async () => {
if (editingMessage.value) {
const index = messageList.value.findIndex(item => item.id === editingMessage.value.id)
if (index > -1) {
if (editingMessage.value.type === 'image') {
let finalImgPath = editingMessage.value.imgUrl;
let oldImgUrl = '';
if (editingNewImg.value) {
try {
// #ifdef APP-PLUS
const saveRes = await new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath: editingNewImg.value,
success: resolve,
fail: reject
});
});
finalImgPath = saveRes.savedFilePath;
// #endif
// #ifndef APP-PLUS
finalImgPath = editingNewImg.value;
// #endif
oldImgUrl = messageList.value[index].imgUrl;
const imgInfo = await new Promise((resolve, reject) => {
uni.getImageInfo({
src: finalImgPath,
success: resolve,
fail: reject
});
});
let w = imgInfo.width;
let h = imgInfo.height;
let width = '100%';
let height = 'auto';
if (w && h) {
if (w > h) {
let scale = w / 200;
width = '200px';
height = (h / scale) + 'px';
} else {
let scale = h / 200;
height = '200px';
width = (w / scale) + 'px';
}
}
const newHtml = `<img src="${finalImgPath}" style="width: ${width}; height: ${height}; border-radius: 16rpx; display: block;" />`;
messageList.value[index].content = newHtml;
messageList.value[index].imgUrl = finalImgPath;
messageList.value[index].imgWidth = width;
messageList.value[index].imgHeight = height;
} catch (e) {
console.error('保存替换图片失败', e);
uni.showToast({ title: '保存图片失败', icon: 'none' });
return;
}
}
messageList.value[index].time = editingTime.value;
if (editingTimeMode.value === 'auto') {
delete messageList.value[index].timeMode;
} else {
messageList.value[index].timeMode = editingTimeMode.value;
}
delete messageList.value[index].hideTime;
if (editingSimKa.value) {
messageList.value[index].simIndex = Number(editingSimKa.value);
} else {
delete messageList.value[index].simIndex;
}
closeEditPopup();
saveChatList();
if (oldImgUrl && oldImgUrl.includes('_doc/')) {
// #ifdef APP-PLUS
uni.removeSavedFile({
filePath: oldImgUrl,
success: () => console.log('替换旧图片,删除成功:', oldImgUrl),
fail: (err) => console.warn('替换旧图片,删除失败:', oldImgUrl, err)
})
// #endif
}
return;
}
})
if (editorCtx) {
editorCtx.getContents({
success: (res) => {
messageList.value[index].content = res.html;
messageList.value[index].time = editingTime.value;
// timeMode: 'auto'|'show'|'hide'
if (editingTimeMode.value === 'auto') {
delete messageList.value[index].timeMode;
} else {
messageList.value[index].timeMode = editingTimeMode.value;
}
// hideTime
delete messageList.value[index].hideTime;
if (editingSimKa.value) {
messageList.value[index].simIndex = Number(editingSimKa.value);
} else {
delete messageList.value[index].simIndex;
}
closeEditPopup();
saveChatList();
}
})
} else {
closeEditPopup();
}
}
} else {
closeEditPopup();
}
@ -1052,4 +1164,28 @@ const confirmAdd = async () => {
padding-bottom: 2rpx;
z-index: 2;
}
.edit-image-replace-box {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #f7f7f7;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 20rpx;
min-height: 200rpx;
}
.replace-img {
max-width: 100%;
max-height: 300rpx;
}
.replace-tip {
margin-top: 16rpx;
font-size: 24rpx;
color: #007AFF;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB