From d3614cbbac961d86f00f15024c89df10f548f377 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 1 Jul 2024 11:36:07 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91?= =?UTF-8?q?=EF=BC=9Amall=20=E5=AE=A2=E6=9C=8D=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.local | 3 + .../mall/promotion/kefu/conversation/index.ts | 71 +++++++++++++++ src/views/infra/webSocket/index.vue | 4 +- .../kefu/components/KeFuConversationBox.vue | 89 ++++++++++++++++++ .../promotion/kefu/components/KefuChatBox.vue | 77 ++++++++++++++++ .../promotion/kefu/components/constants.ts | 14 +++ .../mall/promotion/kefu/components/emoji.ts | 91 +++++++++++++++++++ .../mall/promotion/kefu/components/index.ts | 5 + src/views/mall/promotion/kefu/index.vue | 55 +++++++++++ types/env.d.ts | 1 + 10 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 src/api/mall/promotion/kefu/conversation/index.ts create mode 100644 src/views/mall/promotion/kefu/components/KeFuConversationBox.vue create mode 100644 src/views/mall/promotion/kefu/components/KefuChatBox.vue create mode 100644 src/views/mall/promotion/kefu/components/constants.ts create mode 100644 src/views/mall/promotion/kefu/components/emoji.ts create mode 100644 src/views/mall/promotion/kefu/components/index.ts create mode 100644 src/views/mall/promotion/kefu/index.vue diff --git a/.env.local b/.env.local index 005d2f0d..71530cc6 100644 --- a/.env.local +++ b/.env.local @@ -29,5 +29,8 @@ VITE_BASE_PATH=/ # 商城H5会员端域名 VITE_MALL_H5_DOMAIN='http://localhost:3000' +# 客户端静态资源地址 空=默认使用服务端指定的CDN资源地址前缀 | local=本地 | http(s)://xxx.xxx=自定义静态资源地址前缀 +VITE_STATIC_URL = https://file.sheepjs.com + # 验证码的开关 VITE_APP_CAPTCHA_ENABLE=false diff --git a/src/api/mall/promotion/kefu/conversation/index.ts b/src/api/mall/promotion/kefu/conversation/index.ts new file mode 100644 index 00000000..17432b35 --- /dev/null +++ b/src/api/mall/promotion/kefu/conversation/index.ts @@ -0,0 +1,71 @@ +import request from '@/config/axios' + +export interface KeFuConversationRespVO { + /** + * 编号 + */ + id: number + /** + * 会话所属用户 + */ + userId: number + /** + * 会话所属用户头像 + */ + userAvatar: string + /** + * 会话所属用户昵称 + */ + nickname: string + /** + * 最后聊天时间 + */ + lastMessageTime: Date + /** + * 最后聊天内容 + */ + lastMessageContent: string + /** + * 最后发送的消息类型 + */ + lastMessageContentType: number + /** + * 管理端置顶 + */ + adminPinned: boolean + /** + * 用户是否可见 + */ + userDeleted: boolean + /** + * 管理员是否可见 + */ + adminDeleted: boolean + /** + * 管理员未读消息数 + */ + adminUnreadMessageCount: number + /** + * 创建时间 + */ + createTime?: string +} + +// 客服会话 API +export const KeFuConversationApi = { + // 获得客服会话列表 + getConversationList: async () => { + return await request.get({ url: '/promotion/kefu-conversation/list' }) + }, + // 客服会话置顶 + updateConversationPinned: async (data: any) => { + return await request.put({ + url: '/promotion/kefu-conversation/update-conversation-pinned', + data + }) + }, + // 删除客服会话 + deleteConversation: async (id: number) => { + return await request.get({ url: '/promotion/kefu-conversation/delete?id' + id }) + } +} diff --git a/src/views/infra/webSocket/index.vue b/src/views/infra/webSocket/index.vue index 0f0e351f..300f6d92 100644 --- a/src/views/infra/webSocket/index.vue +++ b/src/views/infra/webSocket/index.vue @@ -29,8 +29,8 @@ :autosize="{ minRows: 2, maxRows: 4 }" :disabled="!getIsOpen" clearable - type="textarea" placeholder="请输入你要发送的消息" + type="textarea" /> @@ -71,7 +71,7 @@ + + diff --git a/src/views/mall/promotion/kefu/components/KefuChatBox.vue b/src/views/mall/promotion/kefu/components/KefuChatBox.vue new file mode 100644 index 00000000..394c8424 --- /dev/null +++ b/src/views/mall/promotion/kefu/components/KefuChatBox.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/src/views/mall/promotion/kefu/components/constants.ts b/src/views/mall/promotion/kefu/components/constants.ts new file mode 100644 index 00000000..015b46a7 --- /dev/null +++ b/src/views/mall/promotion/kefu/components/constants.ts @@ -0,0 +1,14 @@ +export const KeFuMessageContentTypeEnum = { + TEXT: 1, // 文本消息 + IMAGE: 2, // 图片消息 + VOICE: 3, // 语音消息 + VIDEO: 4, // 视频消息 + SYSTEM: 5, // 系统消息 + // ========== 商城特殊消息 ========== + PRODUCT: 10, // 商品消息 + ORDER: 11 // 订单消息" +} +export const UserTypeEnum = { + MEMBER: 1, // 会员 面向 c 端,普通用户 + ADMIN: 2 // 管理员 面向 b 端,管理后台 +} diff --git a/src/views/mall/promotion/kefu/components/emoji.ts b/src/views/mall/promotion/kefu/components/emoji.ts new file mode 100644 index 00000000..6ccd0cff --- /dev/null +++ b/src/views/mall/promotion/kefu/components/emoji.ts @@ -0,0 +1,91 @@ +export const emojiList = [ + { name: '[笑掉牙]', file: 'xiaodiaoya.png' }, + { name: '[可爱]', file: 'keai.png' }, + { name: '[冷酷]', file: 'lengku.png' }, + { name: '[闭嘴]', file: 'bizui.png' }, + { name: '[生气]', file: 'shengqi.png' }, + { name: '[惊恐]', file: 'jingkong.png' }, + { name: '[瞌睡]', file: 'keshui.png' }, + { name: '[大笑]', file: 'daxiao.png' }, + { name: '[爱心]', file: 'aixin.png' }, + { name: '[坏笑]', file: 'huaixiao.png' }, + { name: '[飞吻]', file: 'feiwen.png' }, + { name: '[疑问]', file: 'yiwen.png' }, + { name: '[开心]', file: 'kaixin.png' }, + { name: '[发呆]', file: 'fadai.png' }, + { name: '[流泪]', file: 'liulei.png' }, + { name: '[汗颜]', file: 'hanyan.png' }, + { name: '[惊悚]', file: 'jingshu.png' }, + { name: '[困~]', file: 'kun.png' }, + { name: '[心碎]', file: 'xinsui.png' }, + { name: '[天使]', file: 'tianshi.png' }, + { name: '[晕]', file: 'yun.png' }, + { name: '[啊]', file: 'a.png' }, + { name: '[愤怒]', file: 'fennu.png' }, + { name: '[睡着]', file: 'shuizhuo.png' }, + { name: '[面无表情]', file: 'mianwubiaoqing.png' }, + { name: '[难过]', file: 'nanguo.png' }, + { name: '[犯困]', file: 'fankun.png' }, + { name: '[好吃]', file: 'haochi.png' }, + { name: '[呕吐]', file: 'outu.png' }, + { name: '[龇牙]', file: 'ziya.png' }, + { name: '[懵比]', file: 'mengbi.png' }, + { name: '[白眼]', file: 'baiyan.png' }, + { name: '[饿死]', file: 'esi.png' }, + { name: '[凶]', file: 'xiong.png' }, + { name: '[感冒]', file: 'ganmao.png' }, + { name: '[流汗]', file: 'liuhan.png' }, + { name: '[笑哭]', file: 'xiaoku.png' }, + { name: '[流口水]', file: 'liukoushui.png' }, + { name: '[尴尬]', file: 'ganga.png' }, + { name: '[惊讶]', file: 'jingya.png' }, + { name: '[大惊]', file: 'dajing.png' }, + { name: '[不好意思]', file: 'buhaoyisi.png' }, + { name: '[大闹]', file: 'danao.png' }, + { name: '[不可思议]', file: 'bukesiyi.png' }, + { name: '[爱你]', file: 'aini.png' }, + { name: '[红心]', file: 'hongxin.png' }, + { name: '[点赞]', file: 'dianzan.png' }, + { name: '[恶魔]', file: 'emo.png' } +] + +export const emojiPage = {} +emojiList.forEach((item, index) => { + if (!emojiPage[Math.floor(index / 30) + 1]) { + emojiPage[Math.floor(index / 30) + 1] = [] + } + emojiPage[Math.floor(index / 30) + 1].push(item) +}) + +// 后端上传地址 +const staticUrl = import.meta.env.VITE_STATIC_URL + +// 处理表情 +export function replaceEmoji(data: string) { + let newData = data + if (typeof newData !== 'object') { + const reg = /\[(.+?)\]/g // [] 中括号 + const zhEmojiName = newData.match(reg) + if (zhEmojiName) { + zhEmojiName.forEach((item) => { + const emojiFile = selEmojiFile(item) + newData = newData.replace( + item, + `` + ) + }) + } + } + return newData +} + +function selEmojiFile(name: string) { + for (const index in emojiList) { + if (emojiList[index].name === name) { + return emojiList[index].file + } + } + return false +} diff --git a/src/views/mall/promotion/kefu/components/index.ts b/src/views/mall/promotion/kefu/components/index.ts new file mode 100644 index 00000000..afd2fd76 --- /dev/null +++ b/src/views/mall/promotion/kefu/components/index.ts @@ -0,0 +1,5 @@ +import KeFuConversationBox from './KeFuConversationBox.vue' +import KeFuChatBox from './KefuChatBox.vue' +import * as Constants from './constants' + +export { KeFuConversationBox, KeFuChatBox, Constants } diff --git a/src/views/mall/promotion/kefu/index.vue b/src/views/mall/promotion/kefu/index.vue new file mode 100644 index 00000000..52c6f2ba --- /dev/null +++ b/src/views/mall/promotion/kefu/index.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/types/env.d.ts b/types/env.d.ts index 057b5268..63d9c3ee 100644 --- a/types/env.d.ts +++ b/types/env.d.ts @@ -19,6 +19,7 @@ interface ImportMetaEnv { readonly VITE_UPLOAD_URL: string readonly VITE_API_URL: string readonly VITE_BASE_PATH: string + readonly VITE_STATIC_URL: string readonly VITE_DROP_DEBUGGER: string readonly VITE_DROP_CONSOLE: string readonly VITE_SOURCEMAP: string From d3b4063b94b159dc8d2256fd11c5fc409e79d7c1 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 1 Jul 2024 16:15:27 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91?= =?UTF-8?q?=EF=BC=9Amall=20=E5=AE=A2=E6=9C=8D=E6=B6=88=E6=81=AF=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/promotion/kefu/conversation/index.ts | 2 +- src/api/mall/promotion/kefu/message/index.ts | 70 ++++++++ .../promotion/kefu/components/KeFuChatBox.vue | 167 ++++++++++++++++++ .../kefu/components/KeFuConversationBox.vue | 8 +- .../promotion/kefu/components/KefuChatBox.vue | 77 -------- .../promotion/kefu/components/constants.ts | 4 - .../mall/promotion/kefu/components/index.ts | 2 +- src/views/mall/promotion/kefu/index.vue | 7 +- 8 files changed, 249 insertions(+), 88 deletions(-) create mode 100644 src/api/mall/promotion/kefu/message/index.ts create mode 100644 src/views/mall/promotion/kefu/components/KeFuChatBox.vue delete mode 100644 src/views/mall/promotion/kefu/components/KefuChatBox.vue diff --git a/src/api/mall/promotion/kefu/conversation/index.ts b/src/api/mall/promotion/kefu/conversation/index.ts index 17432b35..96a23706 100644 --- a/src/api/mall/promotion/kefu/conversation/index.ts +++ b/src/api/mall/promotion/kefu/conversation/index.ts @@ -16,7 +16,7 @@ export interface KeFuConversationRespVO { /** * 会话所属用户昵称 */ - nickname: string + userNickname: string /** * 最后聊天时间 */ diff --git a/src/api/mall/promotion/kefu/message/index.ts b/src/api/mall/promotion/kefu/message/index.ts new file mode 100644 index 00000000..3408f1e0 --- /dev/null +++ b/src/api/mall/promotion/kefu/message/index.ts @@ -0,0 +1,70 @@ +import request from '@/config/axios' + +export interface KeFuMessageRespVO { + /** + * 编号 + */ + id: number + /** + * 会话编号 + */ + conversationId: number + /** + * 发送人编号 + */ + senderId: number + /** + * 发送人头像 + */ + senderAvatar: string + /** + * 发送人类型 + */ + senderType: number + /** + * 接收人编号 + */ + receiverId: number + /** + * 接收人类型 + */ + receiverType: number + /** + * 消息类型 + */ + contentType: number + /** + * 消息 + */ + content: string + /** + * 是否已读 + */ + readStatus: boolean + /** + * 创建时间 + */ + createTime: Date +} + +// 客服会话 API +export const KeFuMessageApi = { + // 发送客服消息 + sendKeFuMessage: async (data: any) => { + return await request.put({ + url: '/promotion/kefu-message/send', + data + }) + }, + // 更新客服消息已读状态 + updateKeFuMessageReadStatus: async (data: any) => { + return await request.put({ + url: '/promotion/kefu-message/update-read-status', + data + }) + }, + // 获得消息分页数据 + getKeFuMessagePage: async (params: any) => { + return await request.get({ url: '/promotion/kefu-message/page', params }) + } +} diff --git a/src/views/mall/promotion/kefu/components/KeFuChatBox.vue b/src/views/mall/promotion/kefu/components/KeFuChatBox.vue new file mode 100644 index 00000000..ee41564b --- /dev/null +++ b/src/views/mall/promotion/kefu/components/KeFuChatBox.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/src/views/mall/promotion/kefu/components/KeFuConversationBox.vue b/src/views/mall/promotion/kefu/components/KeFuConversationBox.vue index c94c01c3..595475be 100644 --- a/src/views/mall/promotion/kefu/components/KeFuConversationBox.vue +++ b/src/views/mall/promotion/kefu/components/KeFuConversationBox.vue @@ -10,7 +10,7 @@
-
{{ item.nickname }}
+
{{ item.userNickname }}
{ userId: 283, userAvatar: 'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKMezSxtOImrC9lbhwHiazYwck3xwrEcO7VJfG6WQo260whaeVNoByE5RreiaGsGfOMlIiaDhSaA991w/132', - nickname: '辉辉鸭' + i, + userNickname: '辉辉鸭' + i, lastMessageTime: getNowDateTime(), lastMessageContent: '[爱心][爱心]你好哇', lastMessageContentType: 1, @@ -54,12 +54,12 @@ const getConversationList = async () => { } defineExpose({ getConversationList }) const emits = defineEmits<{ - (e: 'change', v: number): void + (e: 'change', v: KeFuConversationRespVO): void }>() // 打开右侧消息 const openRightMessage = (item: KeFuConversationRespVO, index: number) => { activeConversationIndex.value = index - emits('change', item.id) + emits('change', item) } diff --git a/src/views/mall/promotion/kefu/components/KefuChatBox.vue b/src/views/mall/promotion/kefu/components/KefuChatBox.vue deleted file mode 100644 index 394c8424..00000000 --- a/src/views/mall/promotion/kefu/components/KefuChatBox.vue +++ /dev/null @@ -1,77 +0,0 @@ - - - - - diff --git a/src/views/mall/promotion/kefu/components/constants.ts b/src/views/mall/promotion/kefu/components/constants.ts index 015b46a7..f8599160 100644 --- a/src/views/mall/promotion/kefu/components/constants.ts +++ b/src/views/mall/promotion/kefu/components/constants.ts @@ -8,7 +8,3 @@ export const KeFuMessageContentTypeEnum = { PRODUCT: 10, // 商品消息 ORDER: 11 // 订单消息" } -export const UserTypeEnum = { - MEMBER: 1, // 会员 面向 c 端,普通用户 - ADMIN: 2 // 管理员 面向 b 端,管理后台 -} diff --git a/src/views/mall/promotion/kefu/components/index.ts b/src/views/mall/promotion/kefu/components/index.ts index afd2fd76..fcf6bd5b 100644 --- a/src/views/mall/promotion/kefu/components/index.ts +++ b/src/views/mall/promotion/kefu/components/index.ts @@ -1,5 +1,5 @@ import KeFuConversationBox from './KeFuConversationBox.vue' -import KeFuChatBox from './KefuChatBox.vue' +import KeFuChatBox from './KeFuChatBox.vue' import * as Constants from './constants' export { KeFuConversationBox, KeFuChatBox, Constants } diff --git a/src/views/mall/promotion/kefu/index.vue b/src/views/mall/promotion/kefu/index.vue index 52c6f2ba..1204b8dc 100644 --- a/src/views/mall/promotion/kefu/index.vue +++ b/src/views/mall/promotion/kefu/index.vue @@ -15,12 +15,17 @@