refactor(im): 重构聊天面板UI组件并修复多处交互问题

- 将头像组件从 dicebear 外链改为本地首字+底色生成,新增 avatarColor 工具函数
- 重构订单卡片(footPrint.vue)布局,优化商品与订单信息展示结构
- 重构店铺详情卡片(storeDetail.vue),统一信息行与评分行样式
- 移除消息气泡中的昵称时间行,调整气泡背景色与头像内边距
- 修复 face 变量名与全局组件 <face> 冲突导致头像URL被当作标签渲染
- 将 unload 事件监听替换为 pagehide,兼容 Chrome 弃用策略
- 修复搜索关键词未转义正则元字符导致输入特殊字符时抛异常
- 修复 WebSocket onMessage 对无 text 字段的推送消息误调用 JSON.parse
- 将 setup 中同步调用全局 mixin 方法移至 onMounted,避免代理未就绪
- 商品/订单图片统一添加 onerror 默认图兜底
- 聊天列表消息预览支持 emoji 图片渲染(textReplaceEmoji)
- 搜索框增加 clearable 属性及"没有找到相关好友"空态提示
- 锁定 element-plus 版本为 2.14.1 防止自动升级引入兼容问题
- 日期格式化分隔符由斜杠改为横杠
- 提现设置页新增提现规则说明字段,满足微信审核公示要求
This commit is contained in:
pikachu1995@126.com
2026-10-29 10:56:28 +08:00
parent 68dfae9a62
commit 97e611c072
14 changed files with 473 additions and 246 deletions

View File

@@ -43,7 +43,7 @@
</aside>
<aside class="avatar-column">
<div class="avatar-box" v-if="item.float == 'right'">
<face :text="face" v-if="face"></face>
<face :text="userFace" v-if="userFace"></face>
<face-null :text="name" v-else></face-null>
</div>
<div class="avatar-box" v-if="item.float == 'left'">
@@ -53,14 +53,10 @@
</aside>
<main class="main-column">
<div class="talk-content">
<span class="nickname">
{{ item.float == "right" ? name : toUser.name }} |
{{ unixToDate(item.createTime, "MM月dd日 hh:mm") }}
</span>
<div class="flex flex-a-c">
<legacy-el-icon name="el-icon-refresh-left" class="again main-color" @click="againSendMessage(item)" v-if="item.webSocketStatus" />
<!-- 文本消息 -->
<div v-if="item.messageType == 'MESSAGE'" style="background-color: #d0e9ff;color: black;"
<div v-if="item.messageType == 'MESSAGE'"
class="text-message" :class="{
left: item.float == 'left',
right: item.float == 'right',
@@ -79,7 +75,7 @@
}">
<div class="base" @click="linkToGoods(item.text.goodsId, item.text.id)">
<div>
<img :src="item.text.thumbnail" class="image" />
<img :src="item.text.thumbnail" :onerror="defaultAvatar" class="image" />
</div>
<div>
<div class="goods_name">
@@ -106,7 +102,7 @@
<div class="goods-shared-box">
<div class="goods-item" v-for="(order,orderIndex) in item.text.orderItems" :key="orderIndex">
<img :src="order.image" style="height: 100px;width: 100px;" />
<img :src="order.image" :onerror="defaultAvatar" style="height: 100px;width: 100px;" />
<div>
<span class="orderGoodsName">{{ order.name }}</span>
<div class="goods-item-price">
@@ -212,6 +208,7 @@ import SocketInstance from "@/im-server/socket-instance";
import { SvgMentionDown } from "@/core/icons";
import { formatTime, parseTime, copyTextToClipboard } from "@/utils/functions";
import { useUserStore } from "@/stores/user";
import { useAppStore } from "@/stores/app";
import { useTalkStore } from "@/stores/talk";
import { useNotifyStore } from "@/stores/notify";
import { useSettingsStore } from "@/stores/settings";
@@ -259,6 +256,7 @@ const emit = defineEmits(["close-talk"]);
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const appStore = useAppStore();
const talkStore = useTalkStore();
const notifyStore = useNotifyStore();
const settingsStore = useSettingsStore();
@@ -306,13 +304,16 @@ const panelHeader = ref(null);
const talkItems = computed(() => talkStore.talkItems);
const name = computed(() => userStore.name);
const face = computed(() => userStore.face);
// 不能命名为 face:会遮蔽 <face> 组件解析,头像 URL 会被当作标签名渲染
const userFace = computed(() => userStore.face);
const unreadMessage = computed(() => talkStore.unreadMessage);
const inputEvent = computed(() => notifyStore.inputEvent);
const id = computed(() => userStore.id);
const records = computed(() => dialogueStore.records);
const index_name = computed(() => dialogueStore.index_name);
const toUser = computed(() => userStore.toUser);
// 商品/订单图片加载失败时的默认图(onerror 属性值)
const defaultAvatar = computed(() => appStore.defaultAvatar);
const sendTime = formatTime;
@@ -1147,7 +1148,7 @@ function talkPanelScrollBottom() {
flex-shrink: 0;
order: 1;
user-select: none;
padding-top: 25px;
padding-top: 8px;
i {
color: #ccc;
@@ -1168,7 +1169,7 @@ function talkPanelScrollBottom() {
align-items: center;
order: 2;
user-select: none;
padding-top: 22px;
padding-top: 5px;
flex-direction: column;
}
@@ -1206,13 +1207,6 @@ function talkPanelScrollBottom() {
align-items: flex-start;
box-sizing: border-box;
width: 100%;
.nickname {
font-size: 12px;
color: #a7a0a0;
margin: -4px 0 4px -8px;
transform: scale(0.9);
}
}
&:hover {
@@ -1250,8 +1244,8 @@ function talkPanelScrollBottom() {
}
}
@bg-left-color: #f5f5f5;
@bg-right-color: #ffffff;
@bg-left-color: #f2f2f2;
@bg-right-color: #409eff;
.text-message {
position: relative;