From b94f34c67dc77d1eefe174b48915b92f6f090aed Mon Sep 17 00:00:00 2001 From: jawe <532159638@qq.com> Date: Mon, 3 Nov 2025 16:42:13 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8tailwindcss?= =?UTF-8?q?=E7=AE=80=E5=8C=96style,=E7=BB=9F=E4=B8=80=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/.env.development | 2 +- .../src/components/card-title/CardTitle.vue | 36 -- .../src/components/card-title/index.ts | 1 - .../promotion/components/diy-editor/index.vue | 2 +- .../promotion/components/draggable/index.vue | 2 +- .../kefu/components/KeFuMessageList.vue | 574 ------------------ .../mall/promotion/kefu/components/index.ts | 6 - .../kefu/components/message/OrderItem.vue | 206 ------- .../src/views/mall/promotion/kefu/index.vue | 54 +- .../conversation-list.vue} | 103 +--- .../mall/promotion/kefu/modules/index.ts | 3 + .../member/member-info.vue} | 186 ++---- .../member/order-browsing-history.vue} | 11 +- .../member/product-browsing-history.vue} | 4 +- .../promotion/kefu/modules/message-list.vue | 425 +++++++++++++ .../message/message-item.vue} | 1 - .../kefu/modules/message/order-item.vue | 130 ++++ .../message/product-item.vue} | 68 +-- .../tools/constants.ts | 0 .../tools/emoji-select-popover.vue} | 6 +- .../{components => modules}/tools/emoji.ts | 0 .../tools/picture-select-upload.vue} | 25 +- apps/web-antd/vite.config.mts | 2 +- .../promotion/components/diy-editor/index.vue | 2 +- packages/locales/src/langs/zh-CN/ui.json | 3 +- 25 files changed, 694 insertions(+), 1158 deletions(-) delete mode 100644 apps/web-antd/src/components/card-title/CardTitle.vue delete mode 100644 apps/web-antd/src/components/card-title/index.ts delete mode 100644 apps/web-antd/src/views/mall/promotion/kefu/components/KeFuMessageList.vue delete mode 100644 apps/web-antd/src/views/mall/promotion/kefu/components/index.ts delete mode 100644 apps/web-antd/src/views/mall/promotion/kefu/components/message/OrderItem.vue rename apps/web-antd/src/views/mall/promotion/kefu/{components/KeFuConversationList.vue => modules/conversation-list.vue} (73%) create mode 100644 apps/web-antd/src/views/mall/promotion/kefu/modules/index.ts rename apps/web-antd/src/views/mall/promotion/kefu/{components/member/MemberInfo.vue => modules/member/member-info.vue} (51%) rename apps/web-antd/src/views/mall/promotion/kefu/{components/member/OrderBrowsingHistory.vue => modules/member/order-browsing-history.vue} (83%) rename apps/web-antd/src/views/mall/promotion/kefu/{components/member/ProductBrowsingHistory.vue => modules/member/product-browsing-history.vue} (91%) create mode 100644 apps/web-antd/src/views/mall/promotion/kefu/modules/message-list.vue rename apps/web-antd/src/views/mall/promotion/kefu/{components/message/MessageItem.vue => modules/message/message-item.vue} (92%) create mode 100644 apps/web-antd/src/views/mall/promotion/kefu/modules/message/order-item.vue rename apps/web-antd/src/views/mall/promotion/kefu/{components/message/ProductItem.vue => modules/message/product-item.vue} (51%) rename apps/web-antd/src/views/mall/promotion/kefu/{components => modules}/tools/constants.ts (100%) rename apps/web-antd/src/views/mall/promotion/kefu/{components/tools/EmojiSelectPopover.vue => modules/tools/emoji-select-popover.vue} (91%) rename apps/web-antd/src/views/mall/promotion/kefu/{components => modules}/tools/emoji.ts (100%) rename apps/web-antd/src/views/mall/promotion/kefu/{components/tools/PictureSelectUpload.vue => modules/tools/picture-select-upload.vue} (76%) diff --git a/apps/web-antd/.env.development b/apps/web-antd/.env.development index cff255764..18433b6b5 100644 --- a/apps/web-antd/.env.development +++ b/apps/web-antd/.env.development @@ -4,7 +4,7 @@ VITE_PORT=5666 VITE_BASE=/ # 请求路径 -VITE_BASE_URL=http://127.0.0.1:48080 +VITE_BASE_URL=http://47.103.66.220:48080 # 接口地址 VITE_GLOB_API_URL=/admin-api # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 diff --git a/apps/web-antd/src/components/card-title/CardTitle.vue b/apps/web-antd/src/components/card-title/CardTitle.vue deleted file mode 100644 index b59ed966c..000000000 --- a/apps/web-antd/src/components/card-title/CardTitle.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - - - diff --git a/apps/web-antd/src/components/card-title/index.ts b/apps/web-antd/src/components/card-title/index.ts deleted file mode 100644 index 4ebdb4494..000000000 --- a/apps/web-antd/src/components/card-title/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as CardTitle } from './CardTitle.vue'; diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue index 1ae7934ea..6180b67ba 100644 --- a/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/index.vue @@ -556,7 +556,7 @@ $phone-width: 375px; width: 100%; margin: 16px 0 0; overflow: hidden; - background-color: var(--app-content-bg-color); + background-color: var(--background); /* 手机顶部 */ .editor-design-top { diff --git a/apps/web-antd/src/views/mall/promotion/components/draggable/index.vue b/apps/web-antd/src/views/mall/promotion/components/draggable/index.vue index 8bb352329..75295662a 100644 --- a/apps/web-antd/src/views/mall/promotion/components/draggable/index.vue +++ b/apps/web-antd/src/views/mall/promotion/components/draggable/index.vue @@ -59,7 +59,7 @@ const handleDelete = function (index: number) {
-import type { UseScrollReturn } from '@vueuse/core'; - -import type { Emoji } from './tools/emoji'; - -import type { MallKefuConversationApi } from '#/api/mall/promotion/kefu/conversation'; -import type { MallKefuMessageApi } from '#/api/mall/promotion/kefu/message'; - -import { computed, nextTick, reactive, ref, unref } from 'vue'; - -import { UserTypeEnum } from '@vben/constants'; -import { IconifyIcon } from '@vben/icons'; -import { formatDate, isEmpty, jsonParse } from '@vben/utils'; - -import { vScroll } from '@vueuse/components'; -import { useDebounceFn, useScroll } from '@vueuse/core'; -import { - Avatar, - Empty, - Image, - Layout, - notification, - Textarea, -} from 'ant-design-vue'; -import dayjs from 'dayjs'; -import relativeTime from 'dayjs/plugin/relativeTime'; - -import { - getKeFuMessageList, - sendKeFuMessage, - updateKeFuMessageReadStatus, -} from '#/api/mall/promotion/kefu/message'; -import { useMallKefuStore } from '#/store/mall/kefu'; - -import MessageItem from './message/MessageItem.vue'; -import OrderItem from './message/OrderItem.vue'; -import ProductItem from './message/ProductItem.vue'; -import { KeFuMessageContentTypeEnum } from './tools/constants'; -import { useEmoji } from './tools/emoji'; -import EmojiSelectPopover from './tools/EmojiSelectPopover.vue'; -import PictureSelectUpload from './tools/PictureSelectUpload.vue'; - -defineOptions({ name: 'KeFuMessageList' }); - -dayjs.extend(relativeTime); - -const message = ref(''); // 消息弹窗 -const { replaceEmoji } = useEmoji(); -const messageList = ref([]); // 消息列表 -const conversation = ref( - {} as MallKefuConversationApi.Conversation, -); // 用户会话 -const showNewMessageTip = ref(false); // 显示有新消息提示 -const queryParams = reactive({ - conversationId: 0, - createTime: undefined, -}); -const total = ref(0); // 消息总条数 -const refreshContent = ref(false); // 内容刷新,主要解决会话消息页面高度不一致导致的滚动功能精度失效 -const kefuStore = useMallKefuStore(); // 客服缓存 - -/** 获悉消息内容 */ -const getMessageContent = computed( - () => (item: any) => jsonParse(item.content), -); - -/** 获得消息列表 */ -// TODO @jave:idea 的 linter 报错,处理下; -async function getMessageList() { - const res: any = await getKeFuMessageList(queryParams as any); - if (isEmpty(res)) { - // 当返回的是空列表说明没有消息或者已经查询完了历史消息 - skipGetMessageList.value = true; - return; - } - queryParams.createTime = formatDate((res as any).at(-1).createTime) as any; - - // 情况一:加载最新消息 - if (queryParams.createTime) { - // 情况二:加载历史消息 - for (const item of res as any) { - pushMessage(item); - } - } else { - messageList.value = res; - } - refreshContent.value = true; -} - -/** 添加消息 */ -function pushMessage(message: any) { - if (messageList.value.some((val) => val.id === message.id)) { - return; - } - messageList.value.push(message); -} - -/** 按照时间倒序,获取消息列表 */ -const getMessageList0 = computed(() => { - // 使用展开运算符创建新数组,避免直接修改原数组 - return [...messageList.value].sort( - (a: any, b: any) => a.createTime - b.createTime, - ); -}); - -/** 刷新消息列表 */ -async function refreshMessageList(message?: any) { - if (!conversation.value) { - return; - } - - if (message === undefined) { - queryParams.createTime = undefined; - await getMessageList(); - } else { - // 当前查询会话与消息所属会话不一致则不做处理 - if (message.conversationId !== conversation.value.id) { - return; - } - pushMessage(message); - } - - if (loadHistory.value) { - // 右下角显示有新消息提示 - showNewMessageTip.value = true; - } else { - // 滚动到最新消息处 - await handleToNewMessage(); - } -} - -/** 获得新会话的消息列表, 点击切换时,读取缓存;然后异步获取新消息,merge 下; */ -async function getNewMessageList(val: MallKefuMessageApi.Message) { - // 1. 缓存当前会话消息列表 - kefuStore.saveMessageList(conversation.value.id, messageList.value); - // 2.1 会话切换,重置相关参数 - messageList.value = kefuStore.getConversationMessageList(val.id) || []; - total.value = messageList.value.length || 0; - loadHistory.value = false; - refreshContent.value = false; - skipGetMessageList.value = false; - // 2.2 设置会话相关属性 - conversation.value = val; - queryParams.conversationId = val.id; - queryParams.createTime = undefined; - // 3. 获取消息 - await refreshMessageList(); -} -defineExpose({ getNewMessageList, refreshMessageList }); - -/** 是否显示聊天区域 */ -function showKeFuMessageList() { - return !isEmpty(conversation.value); -} - -const skipGetMessageList = ref(false); // 跳过消息获取 - -/** 处理表情选择 */ -function handleEmojiSelect(item: Emoji) { - message.value += item.name; -} - -/** 处理图片发送 */ -async function handleSendPicture(picUrl: string) { - // 组织发送消息 - const msg = { - conversationId: conversation.value.id, - contentType: KeFuMessageContentTypeEnum.IMAGE, - content: JSON.stringify({ picUrl }), - }; - await sendMessage(msg); -} - -/** 发送文本消息 */ -async function handleSendMessage(event: any) { - // shift 不发送 - if (event.shiftKey) { - return; - } - // 1. 校验消息是否为空 - if (isEmpty(unref(message.value)?.trim())) { - notification.warning({ message: '请输入消息后再发送哦!' }); - message.value = ''; - return; - } - // 2. 组织发送消息 - const msg = { - conversationId: conversation.value.id, - contentType: KeFuMessageContentTypeEnum.TEXT, - content: JSON.stringify({ text: message.value }), - }; - await sendMessage(msg); -} - -/** 真正发送消息 【共用】*/ -async function sendMessage(msg: MallKefuMessageApi.MessageSend) { - // 发送消息 - await sendKeFuMessage(msg); - message.value = ''; - // 加载消息列表 - await refreshMessageList(); - // 更新会话缓存 - await kefuStore.updateConversation(conversation.value.id); -} - -/** 滚动到底部 */ -const innerRef = ref(); -const scrollbarRef = ref(null); -const { y } = useScroll(scrollbarRef); - -async function scrollToBottom() { - if (!scrollbarRef.value) return; - // 1. 首次加载时滚动到最新消息,如果加载的是历史消息则不滚动 - if (loadHistory.value) { - return; - } - // 2.1 滚动到最新消息,关闭新消息提示 - await nextTick(); - // 使用 useScroll 监听滚动容器 - - y.value = scrollbarRef.value.scrollHeight - innerRef.value!.clientHeight; - // scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight) - showNewMessageTip.value = false; - // 2.2 消息已读 - await updateKeFuMessageReadStatus(conversation.value.id); -} - -/** 查看新消息 */ -async function handleToNewMessage() { - loadHistory.value = false; - await scrollToBottom(); -} - -const loadHistory = ref(false); // 加载历史消息 -/** 处理消息列表滚动事件(debounce 限流) */ -const handleScroll = useDebounceFn((state: UseScrollReturn) => { - const { arrivedState } = state; - if (skipGetMessageList.value) { - return; - } - // 滚动到底部了 - if (arrivedState.bottom) { - loadHistory.value = false; - refreshMessageList(); - } - - // 触顶自动加载下一页数据 - if (arrivedState.top) { - handleOldMessage(); - } -}, 200); -/** 加载历史消息 */ -async function handleOldMessage() { - // 记录已有页面高度 - const oldPageHeight = innerRef.value?.clientHeight; - if (!oldPageHeight) { - return; - } - loadHistory.value = true; - await getMessageList(); - // 等页面加载完后,获得上一页最后一条消息的位置,控制滚动到它所在位置 - // scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight - oldPageHeight) - y.value = - scrollbarRef.value.scrollHeight - - innerRef.value!.clientHeight - - oldPageHeight; -} - -/** 是否显示时间 */ -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; -} - - -