feat: [mall] kefu 客服模块迁移 代码风格统一
This commit is contained in:
@@ -27,24 +27,24 @@ const collapse = ref(false); // 折叠菜单
|
||||
|
||||
/** 计算消息最后发送时间距离现在过去了多久 */
|
||||
const lastMessageTimeMap = ref<Map<number, string>>(new Map<number, string>());
|
||||
const calculationLastMessageTime = () => {
|
||||
function calculationLastMessageTime() {
|
||||
kefuStore.getConversationList?.forEach((item) => {
|
||||
lastMessageTimeMap.value.set(
|
||||
item.id,
|
||||
formatPast(item.lastMessageTime, 'YYYY-MM-DD'),
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
defineExpose({ calculationLastMessageTime });
|
||||
|
||||
const openRightMessage = (item: MallKefuConversationApi.Conversation) => {
|
||||
function openRightMessage(item: MallKefuConversationApi.Conversation) {
|
||||
// 同一个会话则不处理
|
||||
if (activeConversationId.value === item.id) {
|
||||
return;
|
||||
}
|
||||
activeConversationId.value = item.id;
|
||||
emits('change', item);
|
||||
};
|
||||
}
|
||||
|
||||
/** 获得消息类型 */
|
||||
const getConversationDisplayText = computed(
|
||||
@@ -88,10 +88,10 @@ const rightClickConversation = ref<MallKefuConversationApi.Conversation>(
|
||||
); // 右键选中的会话对象
|
||||
|
||||
/** 打开右键菜单 */
|
||||
const rightClick = (
|
||||
function rightClick(
|
||||
mouseEvent: PointerEvent,
|
||||
item: MallKefuConversationApi.Conversation,
|
||||
) => {
|
||||
) {
|
||||
rightClickConversation.value = item;
|
||||
// 显示右键菜单
|
||||
showRightMenu.value = true;
|
||||
@@ -101,14 +101,14 @@ const rightClick = (
|
||||
? `${mouseEvent.clientX - 80}px`
|
||||
: `${mouseEvent.clientX - 210}px`,
|
||||
};
|
||||
};
|
||||
}
|
||||
/** 关闭右键菜单 */
|
||||
const closeRightMenu = () => {
|
||||
function closeRightMenu() {
|
||||
showRightMenu.value = false;
|
||||
};
|
||||
}
|
||||
|
||||
/** 置顶会话 */
|
||||
const updateConversationPinned = async (adminPinned: boolean) => {
|
||||
async function updateConversationPinned(adminPinned: boolean) {
|
||||
// 1. 会话置顶/取消置顶
|
||||
await KeFuConversationApi.updateConversationPinned({
|
||||
id: rightClickConversation.value.id,
|
||||
@@ -118,17 +118,17 @@ const updateConversationPinned = async (adminPinned: boolean) => {
|
||||
// 2. 关闭右键菜单,更新会话列表
|
||||
closeRightMenu();
|
||||
await kefuStore.updateConversation(rightClickConversation.value.id);
|
||||
};
|
||||
}
|
||||
|
||||
/** 删除会话 */
|
||||
const deleteConversation = async () => {
|
||||
async function deleteConversation() {
|
||||
// 1. 删除会话
|
||||
await message.confirm('您确定要删除该会话吗?');
|
||||
await KeFuConversationApi.deleteConversation(rightClickConversation.value.id);
|
||||
// 2. 关闭右键菜单,更新会话列表
|
||||
closeRightMenu();
|
||||
kefuStore.deleteConversation(rightClickConversation.value.id);
|
||||
};
|
||||
}
|
||||
|
||||
/** 监听右键菜单的显示状态,添加点击事件监听器 */
|
||||
watch(showRightMenu, (val) => {
|
||||
|
||||
@@ -53,7 +53,7 @@ const getMessageContent = computed(
|
||||
() => (item: any) => jsonParse(item.content),
|
||||
);
|
||||
/** 获得消息列表 */
|
||||
const getMessageList = async () => {
|
||||
async function getMessageList() {
|
||||
const res = await KeFuMessageApi.getKeFuMessageList(queryParams);
|
||||
if (isEmpty(res)) {
|
||||
// 当返回的是空列表说明没有消息或者已经查询完了历史消息
|
||||
@@ -72,15 +72,15 @@ const getMessageList = async () => {
|
||||
messageList.value = res;
|
||||
}
|
||||
refreshContent.value = true;
|
||||
};
|
||||
}
|
||||
|
||||
/** 添加消息 */
|
||||
const pushMessage = (message: any) => {
|
||||
function pushMessage(message: any) {
|
||||
if (messageList.value.some((val) => val.id === message.id)) {
|
||||
return;
|
||||
}
|
||||
messageList.value.push(message);
|
||||
};
|
||||
}
|
||||
|
||||
/** 按照时间倒序,获取消息列表 */
|
||||
const getMessageList0 = computed(() => {
|
||||
@@ -91,7 +91,7 @@ const getMessageList0 = computed(() => {
|
||||
});
|
||||
|
||||
/** 刷新消息列表 */
|
||||
const refreshMessageList = async (message?: any) => {
|
||||
async function refreshMessageList(message?: any) {
|
||||
if (!conversation.value) {
|
||||
return;
|
||||
}
|
||||
@@ -114,10 +114,10 @@ const refreshMessageList = async (message?: any) => {
|
||||
// 滚动到最新消息处
|
||||
await handleToNewMessage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 获得新会话的消息列表, 点击切换时,读取缓存;然后异步获取新消息,merge 下; */
|
||||
const getNewMessageList = async (val: MallKefuMessageApi.Message) => {
|
||||
async function getNewMessageList(val: MallKefuMessageApi.Message) {
|
||||
// 1. 缓存当前会话消息列表
|
||||
kefuStore.saveMessageList(conversation.value.id, messageList.value);
|
||||
// 2.1 会话切换,重置相关参数
|
||||
@@ -132,19 +132,23 @@ const getNewMessageList = async (val: MallKefuMessageApi.Message) => {
|
||||
queryParams.createTime = undefined;
|
||||
// 3. 获取消息
|
||||
await refreshMessageList();
|
||||
};
|
||||
}
|
||||
defineExpose({ getNewMessageList, refreshMessageList });
|
||||
|
||||
const showKeFuMessageList = computed(() => !isEmpty(conversation.value)); // 是否显示聊天区域
|
||||
// 是否显示聊天区域
|
||||
function showKeFuMessageList() {
|
||||
return !isEmpty(conversation.value);
|
||||
}
|
||||
|
||||
const skipGetMessageList = ref(false); // 跳过消息获取
|
||||
|
||||
/** 处理表情选择 */
|
||||
const handleEmojiSelect = (item: Emoji) => {
|
||||
function handleEmojiSelect(item: Emoji) {
|
||||
message.value += item.name;
|
||||
};
|
||||
}
|
||||
|
||||
/** 处理图片发送 */
|
||||
const handleSendPicture = async (picUrl: string) => {
|
||||
async function handleSendPicture(picUrl: string) {
|
||||
// 组织发送消息
|
||||
const msg = {
|
||||
conversationId: conversation.value.id,
|
||||
@@ -152,10 +156,10 @@ const handleSendPicture = async (picUrl: string) => {
|
||||
content: JSON.stringify({ picUrl }),
|
||||
};
|
||||
await sendMessage(msg);
|
||||
};
|
||||
}
|
||||
|
||||
/** 发送文本消息 */
|
||||
const handleSendMessage = async (event: any) => {
|
||||
async function handleSendMessage(event: any) {
|
||||
// shift 不发送
|
||||
if (event.shiftKey) {
|
||||
return;
|
||||
@@ -173,10 +177,10 @@ const handleSendMessage = async (event: any) => {
|
||||
content: JSON.stringify({ text: message.value }),
|
||||
};
|
||||
await sendMessage(msg);
|
||||
};
|
||||
}
|
||||
|
||||
/** 真正发送消息 【共用】*/
|
||||
const sendMessage = async (msg: MallKefuMessageApi.MessageSend) => {
|
||||
async function sendMessage(msg: MallKefuMessageApi.MessageSend) {
|
||||
// 发送消息
|
||||
await KeFuMessageApi.sendKeFuMessage(msg);
|
||||
message.value = '';
|
||||
@@ -184,14 +188,14 @@ const sendMessage = async (msg: MallKefuMessageApi.MessageSend) => {
|
||||
await refreshMessageList();
|
||||
// 更新会话缓存
|
||||
await kefuStore.updateConversation(conversation.value.id);
|
||||
};
|
||||
}
|
||||
|
||||
/** 滚动到底部 */
|
||||
const innerRef = ref<HTMLDivElement>();
|
||||
const scrollbarRef = ref<HTMLElement | null>(null);
|
||||
const { y } = useScroll(scrollbarRef);
|
||||
|
||||
const scrollToBottom = async () => {
|
||||
async function scrollToBottom() {
|
||||
if (!scrollbarRef.value) return;
|
||||
// 1. 首次加载时滚动到最新消息,如果加载的是历史消息则不滚动
|
||||
if (loadHistory.value) {
|
||||
@@ -206,13 +210,13 @@ const scrollToBottom = async () => {
|
||||
showNewMessageTip.value = false;
|
||||
// 2.2 消息已读
|
||||
await KeFuMessageApi.updateKeFuMessageReadStatus(conversation.value.id);
|
||||
};
|
||||
}
|
||||
|
||||
/** 查看新消息 */
|
||||
const handleToNewMessage = async () => {
|
||||
async function handleToNewMessage() {
|
||||
loadHistory.value = false;
|
||||
await scrollToBottom();
|
||||
};
|
||||
}
|
||||
|
||||
const loadHistory = ref(false); // 加载历史消息
|
||||
/** 处理消息列表滚动事件(debounce 限流) */
|
||||
@@ -233,7 +237,7 @@ const handleScroll = useDebounceFn((state: UseScrollReturn) => {
|
||||
}
|
||||
}, 200);
|
||||
/** 加载历史消息 */
|
||||
const handleOldMessage = async () => {
|
||||
async function handleOldMessage() {
|
||||
// 记录已有页面高度
|
||||
const oldPageHeight = innerRef.value?.clientHeight;
|
||||
if (!oldPageHeight) {
|
||||
@@ -247,7 +251,7 @@ const handleOldMessage = async () => {
|
||||
scrollbarRef.value.scrollHeight -
|
||||
innerRef.value!.clientHeight -
|
||||
oldPageHeight;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示时间
|
||||
@@ -255,17 +259,15 @@ const handleOldMessage = async () => {
|
||||
* @param {*} item - 数据
|
||||
* @param {*} index - 索引
|
||||
*/
|
||||
const showTime = computed(
|
||||
() => (item: MallKefuMessageApi.Message, index: number) => {
|
||||
if (unref(messageList.value)[index + 1]) {
|
||||
const dateString = dayjs(
|
||||
unref(messageList.value)[index + 1].createTime,
|
||||
).fromNow();
|
||||
return dateString !== dayjs(unref(item).createTime).fromNow();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
);
|
||||
function showTime(item: MallKefuMessageApi.Message, index: number) {
|
||||
if (unref(messageList.value)[index + 1]) {
|
||||
const dateString = dayjs(
|
||||
unref(messageList.value)[index + 1].createTime,
|
||||
).fromNow();
|
||||
return dateString !== dayjs(unref(item).createTime).fromNow();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -417,7 +419,7 @@ const showTime = computed(
|
||||
</a-layout>
|
||||
<a-layout v-else class="kefu">
|
||||
<a-layout-content>
|
||||
<Empty description="请选择左侧的一个会话后开始" class="mt-[50px]"/>
|
||||
<Empty description="请选择左侧的一个会话后开始" class="mt-[50px]" />
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</template>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { isEmpty } from '@vben/utils';
|
||||
|
||||
// import { debounce } from 'lodash-es'
|
||||
import { useDebounceFn } from '@vueuse/core';
|
||||
import { Card, Empty,message } from 'ant-design-vue';
|
||||
import { Card, Empty, message } from 'ant-design-vue';
|
||||
|
||||
import * as UserApi from '#/api/member/user';
|
||||
import * as WalletApi from '#/api/pay/wallet/balance';
|
||||
@@ -29,14 +29,14 @@ const productBrowsingHistoryRef =
|
||||
ref<InstanceType<typeof ProductBrowsingHistory>>();
|
||||
const orderBrowsingHistoryRef =
|
||||
ref<InstanceType<typeof OrderBrowsingHistory>>();
|
||||
const handleClick = async (tab: string) => {
|
||||
async function handleClick(tab: string) {
|
||||
activeTab.value = tab;
|
||||
await nextTick();
|
||||
await getHistoryList();
|
||||
};
|
||||
}
|
||||
|
||||
/** 获得历史数据 */
|
||||
const getHistoryList = async () => {
|
||||
async function getHistoryList() {
|
||||
switch (activeTab.value) {
|
||||
case '交易订单': {
|
||||
await orderBrowsingHistoryRef.value?.getHistoryList(conversation.value);
|
||||
@@ -55,10 +55,10 @@ const getHistoryList = async () => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 加载下一页数据 */
|
||||
const loadMore = async () => {
|
||||
async function loadMore() {
|
||||
switch (activeTab.value) {
|
||||
case '交易订单': {
|
||||
await orderBrowsingHistoryRef.value?.loadMore();
|
||||
@@ -75,18 +75,18 @@ const loadMore = async () => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 浏览历史初始化 */
|
||||
const conversation = ref<MallKefuConversationApi.Conversation>(
|
||||
{} as MallKefuConversationApi.Conversation,
|
||||
); // 用户会话
|
||||
const initHistory = async (val: MallKefuConversationApi.Conversation) => {
|
||||
async function initHistory(val: MallKefuConversationApi.Conversation) {
|
||||
activeTab.value = '会员信息';
|
||||
conversation.value = val;
|
||||
await nextTick();
|
||||
await getHistoryList();
|
||||
};
|
||||
}
|
||||
defineExpose({ initHistory });
|
||||
|
||||
/** 处理消息列表滚动事件(debounce 限流) */
|
||||
@@ -106,7 +106,8 @@ const WALLET_INIT_DATA = {
|
||||
totalRecharge: 0,
|
||||
} as WalletApi.WalletVO; // 钱包初始化数据
|
||||
const wallet = ref<WalletApi.WalletVO>(WALLET_INIT_DATA); // 钱包信息
|
||||
const getUserWallet = async () => {
|
||||
|
||||
async function getUserWallet() {
|
||||
if (!conversation.value.userId) {
|
||||
wallet.value = WALLET_INIT_DATA;
|
||||
return;
|
||||
@@ -114,12 +115,12 @@ const getUserWallet = async () => {
|
||||
wallet.value =
|
||||
(await WalletApi.getWallet({ userId: conversation.value.userId })) ||
|
||||
WALLET_INIT_DATA;
|
||||
};
|
||||
}
|
||||
|
||||
/** 获得用户 */
|
||||
const loading = ref(true); // 加载中
|
||||
const user = ref<UserApi.UserVO>({} as UserApi.UserVO);
|
||||
const getUserData = async () => {
|
||||
async function getUserData() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await UserApi.getUser(conversation.value.userId);
|
||||
@@ -132,7 +133,7 @@ const getUserData = async () => {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -24,15 +24,15 @@ const skipGetMessageList = computed(() => {
|
||||
}); // 跳过消息获取
|
||||
|
||||
/** 获得浏览记录 */
|
||||
const getHistoryList = async (val: MallKefuConversationApi.Conversation) => {
|
||||
async function getHistoryList(val: MallKefuConversationApi.Conversation) {
|
||||
queryParams.userId = val.userId;
|
||||
const res = await getOrderPage(queryParams);
|
||||
total.value = res.total;
|
||||
list.value = res.list;
|
||||
};
|
||||
}
|
||||
|
||||
/** 加载下一页数据 */
|
||||
const loadMore = async () => {
|
||||
async function loadMore() {
|
||||
if (skipGetMessageList.value) {
|
||||
return;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ const loadMore = async () => {
|
||||
total.value = res.total;
|
||||
// 使用展开运算符替代 concat 方法
|
||||
list.value = [...list.value, ...res.list];
|
||||
};
|
||||
}
|
||||
defineExpose({ getHistoryList, loadMore });
|
||||
</script>
|
||||
|
||||
|
||||
@@ -26,15 +26,15 @@ const skipGetMessageList = computed(() => {
|
||||
}); // 跳过消息获取
|
||||
|
||||
/** 获得浏览记录 */
|
||||
const getHistoryList = async (val: MallKefuConversationApi.Conversation) => {
|
||||
async function getHistoryList(val: MallKefuConversationApi.Conversation) {
|
||||
queryParams.userId = val.userId;
|
||||
const res = await getBrowseHistoryPage(queryParams);
|
||||
total.value = res.total;
|
||||
list.value = res.list;
|
||||
};
|
||||
}
|
||||
|
||||
/** 加载下一页数据 */
|
||||
const loadMore = async () => {
|
||||
async function loadMore() {
|
||||
if (skipGetMessageList.value) {
|
||||
return;
|
||||
}
|
||||
@@ -43,7 +43,7 @@ const loadMore = async () => {
|
||||
total.value = res.total;
|
||||
// 使用展开运算符替代 concat 方法
|
||||
list.value = [...list.value, ...res.list];
|
||||
};
|
||||
}
|
||||
defineExpose({ getHistoryList, loadMore });
|
||||
</script>
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ const getMessageContent = computed(() =>
|
||||
);
|
||||
|
||||
/** 查看订单详情 */
|
||||
const openDetail = (id: number) => {
|
||||
function openDetail(id: number) {
|
||||
push({ name: 'TradeOrderDetail', params: { id } });
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化订单状态的颜色
|
||||
|
||||
@@ -37,9 +37,9 @@ defineProps({
|
||||
const { push } = useRouter();
|
||||
|
||||
/** 查看商品详情 */
|
||||
const openDetail = (spuId: number) => {
|
||||
function openDetail(spuId: number) {
|
||||
push({ name: 'ProductSpuDetail', params: { id: spuId } });
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -89,10 +89,10 @@ const openDetail = (spuId: number) => {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
background-color: rgb(128 128 128 / 30%);
|
||||
border: 1px solid var(--el-border-color);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&-left {
|
||||
width: 70px;
|
||||
|
||||
@@ -19,10 +19,10 @@ const emits = defineEmits<{
|
||||
const { getEmojiList } = useEmoji();
|
||||
const emojiList = computed(() => getEmojiList());
|
||||
|
||||
const handleSelect = (item: Emoji) => {
|
||||
function handleSelect(item: Emoji) {
|
||||
// 整个 emoji 数据传递出去,方便以后输入框直接显示表情
|
||||
emits('selectEmoji', item);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user