mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-13 04:18:55 +08:00
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:
@@ -6,7 +6,7 @@
|
||||
<el-header height="118px" class="logo-header">
|
||||
<div class="user-login" v-popover:usercard>
|
||||
<div class="user-box">
|
||||
<face :text="face"></face>
|
||||
<face :text="userFace"></face>
|
||||
</div>
|
||||
</div>
|
||||
<p class="user-status">
|
||||
@@ -66,7 +66,8 @@ const userStore = useUserStore();
|
||||
const notifyStore = useNotifyStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const face = computed(() => userStore.face);
|
||||
// 不能命名为 face:会遮蔽 <face> 组件解析,头像 URL 会被当作标签名渲染
|
||||
const userFace = computed(() => userStore.face);
|
||||
const name = computed(() => userStore.name);
|
||||
const id = computed(() => userStore.id);
|
||||
const defaultAvatar = computed(() => appStore.defaultAvatar);
|
||||
@@ -107,8 +108,8 @@ function setApplyNum () {
|
||||
<style lang="less" >
|
||||
.main-layout {
|
||||
position: fixed;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
width: 88%;
|
||||
height: 92%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
@@ -119,8 +120,8 @@ function setApplyNum () {
|
||||
border-radius: 5px;
|
||||
|
||||
&.full-mode {
|
||||
width: 1200px;
|
||||
height: 85%;
|
||||
width: 92%;
|
||||
height: 96%;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<el-header height="60px" class="header">
|
||||
<div class="user-login">
|
||||
<div class="user-box">
|
||||
<face :text="face" :name="name" class="user-face"></face>
|
||||
<face :text="userFace" :name="name" class="user-face"></face>
|
||||
</div>
|
||||
</div>
|
||||
<p class="user-status">
|
||||
@@ -20,7 +20,7 @@
|
||||
</el-header>
|
||||
<el-header height="60px" class="header">
|
||||
<div class="from-search">
|
||||
<el-input v-model="input" :prefix-icon="$legacyIcon('el-icon-search')" placeholder="搜索好友" size="small" />
|
||||
<el-input v-model="input" :prefix-icon="$legacyIcon('el-icon-search')" placeholder="搜索好友" size="small" clearable />
|
||||
</div>
|
||||
</el-header>
|
||||
<!-- <el-header height="118px" class="logo-header">
|
||||
@@ -58,6 +58,10 @@
|
||||
暂无聊天消息
|
||||
</p>
|
||||
|
||||
<p v-show="loadStatus === 1 && talkNum > 0 && userTalkItem.length === 0" class="empty-data">
|
||||
没有找到相关好友
|
||||
</p>
|
||||
|
||||
<p v-show="loadStatus === 1 && talkNum > 0" class="main-menu">
|
||||
<span class="title">对话记录({{ talkNum }})</span>
|
||||
|
||||
@@ -108,7 +112,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="talk-message">
|
||||
<span v-if="item.lastMessageType === 'MESSAGE'">{{ item.lastTalkMessage }}</span>
|
||||
<span v-if="item.lastMessageType === 'MESSAGE'" v-html="textReplaceEmoji(item.lastTalkMessage)"></span>
|
||||
<span v-if="item.lastMessageType === 'GOODS'">[商品链接]</span>
|
||||
<span v-if="item.lastMessageType === 'ORDER'">[订单链接]</span>
|
||||
</div>
|
||||
@@ -156,6 +160,7 @@ import {
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
ref,
|
||||
watch,
|
||||
} from "vue";
|
||||
@@ -174,6 +179,7 @@ import {
|
||||
} from "@/api/chat";
|
||||
import { ServeDeleteContact, ServeEditContactRemark } from "@/api/contacts";
|
||||
import { beautifyTime } from "@/utils/functions";
|
||||
import { textReplaceEmoji } from "@/utils/emojis";
|
||||
import { formatTalkItem, findTalkIndex, getCacheIndexName } from "@/utils/talk";
|
||||
import { setToken } from "@/utils/auth";
|
||||
import { syncImTokenFromRoute } from "@/utils/im-mode";
|
||||
@@ -243,7 +249,9 @@ const unreadNum = computed(() => talkStore.unreadNum);
|
||||
const talkNum = computed(() => talkStore.talkNum);
|
||||
|
||||
// 原 vuex mapState
|
||||
const face = computed(() => userStore.face);
|
||||
// 注意:不能命名为 face——会与全局注册的 <face> 组件绑定冲突,
|
||||
// 模板里的 <face> 标签会被解析成这个 computed 的值(头像 base64 字符串)当作标签名渲染
|
||||
const userFace = computed(() => userStore.face);
|
||||
const name = computed(() => userStore.name);
|
||||
const talks = computed(() => talkStore.items);
|
||||
const id = computed(() => userStore.id);
|
||||
@@ -655,10 +663,11 @@ watch(talkItems, (val) => {
|
||||
});
|
||||
|
||||
// 搜索用户的时候 根据当前用户表进行模糊搜索
|
||||
watch(input, (val, oldVal) => {
|
||||
console.log(val, oldVal);
|
||||
watch(input, (val) => {
|
||||
if (val) {
|
||||
let str = ["", ...val, ""].join(".*");
|
||||
// 转义正则元字符,避免输入 [ 等字符时构造 RegExp 抛异常
|
||||
const keyword = val.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
let str = ["", ...keyword, ""].join(".*");
|
||||
let reg = new RegExp(str);
|
||||
userTalkItem.value = talkItems.value.filter((item) =>
|
||||
reg.test(item.name)
|
||||
@@ -703,8 +712,10 @@ onBeforeRouteUpdate((to, from, next) => {
|
||||
// 原 beforeCreate
|
||||
syncImTokenFromRoute(route, setToken);
|
||||
|
||||
// 原 async created(保持 await 顺序,但用 IIFE 避免 setup 变为异步)
|
||||
(async () => {
|
||||
// 原 async created。不能在 setup 同步执行:全局 mixin 的方法(initialize/
|
||||
// loadUserSetting)在 finishComponentSetup 的 applyOptions 阶段才挂到公共代理上,
|
||||
// 即 setup() 返回之后。故放到 onMounted 里执行。
|
||||
onMounted(async () => {
|
||||
await proxy.initialize();
|
||||
await proxy.loadUserSetting();
|
||||
// 初始化商品参数
|
||||
@@ -714,7 +725,7 @@ syncImTokenFromRoute(route, setToken);
|
||||
* 所以创建会话 并请求用户列表
|
||||
* 如果没有id说明当前商家登录 直接请求用户列表
|
||||
*/
|
||||
})();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.title = title;
|
||||
@@ -747,8 +758,20 @@ onBeforeUnmount(() => {
|
||||
flex-shrink: 0;
|
||||
height: 40px;
|
||||
|
||||
:deep(.el-input .el-input__inner ) {
|
||||
border-radius: 20px;
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 16px;
|
||||
background-color: #f5f6f7;
|
||||
box-shadow: none;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
&.is-focus {
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 1px #409eff inset;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1058,6 +1081,12 @@ onBeforeUnmount(() => {
|
||||
.talk-message {
|
||||
font-size: 12px;
|
||||
color: #8f959e;
|
||||
|
||||
:deep(img) {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.user-face {
|
||||
|
||||
Reference in New Issue
Block a user