Compare commits

...

5 Commits

Author SHA1 Message Date
f0a74916c7 java脚本报错修改 2024-11-04 14:43:28 +08:00
7cb178dcc9 Merge pull request '小程序二维码改成正式版,小程序聊天头像恢复' (#101) from sjy-two into master
All checks were successful
continuous-integration/drone Build is passing
Reviewed-on: #101
2024-11-04 13:28:47 +08:00
262b098be8 优化后台客服界面 2024-11-04 13:26:06 +08:00
ef9ebbfaba 小程序二维码改成正式版,小程序聊天头像恢复 2024-11-04 13:12:27 +08:00
9443f4959a Merge pull request 'java脚本报错修改' (#100) from cxw into master
Reviewed-on: #100
2024-11-03 18:29:13 +08:00
12 changed files with 190 additions and 85 deletions

View File

@ -6,6 +6,7 @@ clone:
disable: true disable: true
steps: # 定义流水线执行步骤,这些步骤将顺序执行 steps: # 定义流水线执行步骤,这些步骤将顺序执行
- name: build-java
- image: appleboy/drone-ssh # SSH工具镜像 - image: appleboy/drone-ssh # SSH工具镜像
settings: settings:
host: 1.14.205.126 # 远程连接地址 host: 1.14.205.126 # 远程连接地址

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="kefu"> <div class="kefu">
<div <div
v-for="item in conversationList" v-for="item in conversationList"
:key="item.id" :key="item.id"
@ -9,7 +10,7 @@
@contextmenu.prevent="rightClick($event as PointerEvent, item)" @contextmenu.prevent="rightClick($event as PointerEvent, item)"
> >
<div class="flex justify-center items-center w-100%"> <div class="flex justify-center items-center w-100%">
<div class="flex justify-center items-center w-50px h-50px"> <div class="flex justify-center items-center w-40px h-40px">
<!-- 头像 + 未读 --> <!-- 头像 + 未读 -->
<el-badge <el-badge
:hidden="item.adminUnreadMessageCount === 0" :hidden="item.adminUnreadMessageCount === 0"
@ -19,10 +20,10 @@
<el-avatar :src="item.userAvatar" alt="avatar" /> <el-avatar :src="item.userAvatar" alt="avatar" />
</el-badge> </el-badge>
</div> </div>
<div class="ml-10px w-100%"> <div class="ml-3px w-full">
<div class="flex justify-between items-center w-100%"> <div class="flex justify-between items-center w-full">
<span class="username">{{ item.userNickname }}</span> <span class="username">{{ item.userNickname }}</span>
<span class="color-[var(--left-menu-text-color)]" style="font-size: 13px"> <span class="color-[var(--left-menu-text-color)]" style="font-size: 12px">
{{ formatPast(item.lastMessageTime, 'YYYY-MM-DD') }} {{ formatPast(item.lastMessageTime, 'YYYY-MM-DD') }}
</span> </span>
</div> </div>
@ -182,12 +183,13 @@ watch(showRightMenu, (val) => {
<style lang="scss" scoped> <style lang="scss" scoped>
.kefu { .kefu {
&-conversation { &-conversation {
height: 60px; height: 55px;
padding: 10px; padding: 8px;
//background-color: #fff; //background-color: #fff;
transition: border-left 0.05s ease-in-out; /* 设置过渡效果 */ transition: border-left 0.05s ease-in-out; /* 设置过渡效果 */
.username { .username {
font-size: 20%;
min-width: 0; min-width: 0;
max-width: 60%; max-width: 60%;
overflow: hidden; overflow: hidden;
@ -198,7 +200,7 @@ watch(showRightMenu, (val) => {
} }
.last-message { .last-message {
font-size: 13px; font-size: 15px;
width: 200px; width: 200px;
overflow: hidden; // overflow: hidden; //
white-space: nowrap; // white-space: nowrap; //

View File

@ -10,8 +10,7 @@
<div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]"> <div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]">
<div class="flex justify-center items-center mb-20px"> <div class="flex justify-center items-center mb-20px">
<!-- 日期 --> <!-- 日期 -->
<div <div v-if="
v-if="
item.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(item, index) item.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(item, index)
" class="date-message"> " class="date-message">
{{ formatDate(item.createTime) }} {{ formatDate(item.createTime) }}
@ -21,19 +20,16 @@ v-if="
{{ item.content }} {{ item.content }}
</div> </div>
</div> </div>
<div <div :class="[
:class="[
item.senderType === UserTypeEnum.MEMBER item.senderType === UserTypeEnum.MEMBER
? `ss-row-left` ? `ss-row-left`
: item.senderType === UserTypeEnum.ADMIN : item.senderType === UserTypeEnum.ADMIN
? `ss-row-right` ? `ss-row-right`
: '' : ''
]" class="flex mb-20px w-[100%]"> ]" class="flex mb-20px w-[100%]">
<el-avatar <el-avatar v-if="item.senderType === UserTypeEnum.MEMBER" :src="conversation.userAvatar"
v-if="item.senderType === UserTypeEnum.MEMBER" :src="conversation.userAvatar"
alt="avatar" class="w-60px h-60px" /> alt="avatar" class="w-60px h-60px" />
<div <div :class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
:class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
class="p-10px"> class="p-10px">
<!-- 文本消息 --> <!-- 文本消息 -->
<MessageItem :message="item"> <MessageItem :message="item">
@ -44,15 +40,13 @@ v-if="item.senderType === UserTypeEnum.MEMBER" :src="conversation.userAvatar"
</MessageItem> </MessageItem>
<!-- 图片消息 --> <!-- 图片消息 -->
<MessageItem :message="item"> <MessageItem :message="item">
<el-image <el-image v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
:initial-index="0" :preview-src-list="[item.content]" :src="item.content" :initial-index="0" :preview-src-list="[item.content]" :src="item.content"
class="w-200px" fit="contain" preview-teleported /> class="w-200px" fit="contain" preview-teleported />
</MessageItem> </MessageItem>
<!-- 商品消息 --> <!-- 商品消息 -->
<MessageItem :message="item"> <MessageItem :message="item">
<ProductItem <ProductItem v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
:spuId="getMessageContent(item).spuId" :picUrl="getMessageContent(item).picUrl" :spuId="getMessageContent(item).spuId" :picUrl="getMessageContent(item).picUrl"
:price="getMessageContent(item).price" :price="getMessageContent(item).price"
:skuText="getMessageContent(item).introduction" :skuText="getMessageContent(item).introduction"
@ -61,20 +55,17 @@ v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
</MessageItem> </MessageItem>
<!-- 订单消息 --> <!-- 订单消息 -->
<MessageItem :message="item"> <MessageItem :message="item">
<OrderItem <OrderItem v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
:message="item" class="max-w-100%" /> :message="item" class="max-w-100%" />
</MessageItem> </MessageItem>
</div> </div>
<el-avatar <el-avatar v-if="item.senderType === UserTypeEnum.ADMIN" :src="item.senderAvatar"
v-if="item.senderType === UserTypeEnum.ADMIN" :src="item.senderAvatar"
alt="avatar" /> alt="avatar" />
</div> </div>
</div> </div>
</div> </div>
</el-scrollbar> </el-scrollbar>
<div <div v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer"
v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer"
@click="handleToNewMessage"> @click="handleToNewMessage">
<span>有新消息</span> <span>有新消息</span>
<Icon class="ml-5px" icon="ep:bottom" /> <Icon class="ml-5px" icon="ep:bottom" />
@ -91,18 +82,21 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
<img :src="Picture" class="w-32px h-32px" @click="huashu" /> <img :src="Picture" class="w-32px h-32px" @click="huashu" />
</div> </div>
<!-- 转接按钮 --> <!-- 转接按钮 -->
<el-dropdown placement="top" style="margin-left: auto;margin-right: 15px; margin-top:5px;margin-top:5px;cursor: pointer;" ref="dropdown1" trigger="contextmenu"> <el-dropdown placement="top"
style="margin-left: auto;margin-right: 15px; margin-top:5px;margin-top:5px;cursor: pointer;"
ref="dropdown1" trigger="contextmenu">
<div> <div>
<img :src="Picture2" class="w-27px h-27px" @click="getOnlineStaffList" title="转接"/> <img :src="Picture2" class="w-27px h-27px" @click="getOnlineStaffList" title="转接" />
</div> </div>
<template #dropdown> <template #dropdown>
<el-dropdown-item v-for="staff in onlineStaffList" :key="staff.id" :disabled="staff.id===getStaffToken()" @click="transferConversion(staff.id)"> <el-dropdown-item v-for="staff in onlineStaffList" :key="staff.id"
:disabled="staff.id===getStaffToken()" @click="transferConversion(staff.id)">
{{ staff.name }} {{ staff.name }}
</el-dropdown-item> </el-dropdown-item>
</template> </template>
</el-dropdown> </el-dropdown>
</div> </div>
<el-input v-model="message" :rows="6" style="border-style: none" type="textarea" /> <el-input v-model="message" :rows="6" style="border-style: none" type="textarea" />
<div class="h-45px flex justify-end"> <div class="h-45px flex justify-end">
@ -120,12 +114,15 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
<!-- 左边占 30% --> <!-- 左边占 30% -->
<div style="flex: 0 0 20%; padding: 10px;"> <div style="flex: 0 0 20%; padding: 10px;">
<el-menu :default-active="targetMenuId"> <el-menu :default-active="targetMenuId">
<el-menu-item v-for="item in huashuType" :index="item.value" :key="item.value" @click="clickMenu(item.value)">{{item.label}}</el-menu-item> <el-menu-item v-for="item in huashuType" :index="item.value" :key="item.value"
@click="clickMenu(item.value)">{{item.label}}</el-menu-item>
</el-menu> </el-menu>
</div> </div>
<!-- 右边占 70% --> <!-- 右边占 70% -->
<div style="flex: 1; padding: 5px; overflow-y: auto; max-height: 400px;"> <div style="flex: 1; padding: 5px; overflow-y: auto; max-height: 400px;">
<p v-for="item in verbalTrickList" :key="item.id" style="font-size: 12px;cursor: pointer;transition: background-color 0.3s;" class="hover-shadow" @click="huashuClick(item.details)"> <p v-for="item in verbalTrickList" :key="item.id"
style="font-size: 12px;cursor: pointer;transition: background-color 0.3s;" class="hover-shadow"
@click="huashuClick(item.details)">
{{item.details}} {{item.details}}
</p> </p>
</div> </div>
@ -155,11 +152,11 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
import relativeTime from 'dayjs/plugin/relativeTime' import relativeTime from 'dayjs/plugin/relativeTime'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import { jsonParse } from '@/utils' import { jsonParse } from '@/utils'
import { getStaffToken, setStaffToken} from '@/utils/auth' import { getStaffToken, setStaffToken } from '@/utils/auth'
import type { DropdownInstance } from 'element-plus' import type { DropdownInstance } from 'element-plus'
import { ref } from 'vue' import { ref } from 'vue'
import * as DictDataApi from '@/api/system/dict/dict.data' import * as DictDataApi from '@/api/system/dict/dict.data'
const huashuType = ref<DictDataApi.DictDataVO[]>([]) // const huashuType = ref<DictDataApi.DictDataVO[]>([]) //
const targetMenuId = ref('0') const targetMenuId = ref('0')
@ -170,7 +167,7 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
let dialogVisible = ref(false) // let dialogVisible = ref(false) //
const dialogTitle = ref('客服话术') // const dialogTitle = ref('客服话术') //
// //
const verbalTrickList = ref<VerbalTrickVO[]>([]) const verbalTrickList = ref<VerbalTrickVO[]>([])
const message = ref('') // const message = ref('') //
const { replaceEmoji } = useEmoji() const { replaceEmoji } = useEmoji()
const messageTool = useMessage() const messageTool = useMessage()
@ -178,10 +175,10 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) // const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) //
const showNewMessageTip = ref(false) // const showNewMessageTip = ref(false) //
import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff' // import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff' //
import { KeFuConversationApi} from '@/api/mall/promotion/kefu/conversation' import { KeFuConversationApi } from '@/api/mall/promotion/kefu/conversation'
import { number } from 'vue-types' import { number } from 'vue-types'
const onlineStaffList = ref<SupportStaffVO[]>([]) // 线 const onlineStaffList = ref<SupportStaffVO[]>([]) // 线
const queryParams = reactive({ const queryParams = reactive({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
@ -297,25 +294,25 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
// //
const getHuaShuTypeList = async () => { const getHuaShuTypeList = async () => {
const data = await DictDataApi.getHuaShuTypeList() const data = await DictDataApi.getHuaShuTypeList()
huashuType.value = data huashuType.value = data
} }
// //
const getVerbalTrickList = async (id: string) => { const getVerbalTrickList = async (id : string) => {
const response = await VerbalTrickApi.getVerbalTrickList(id); const response = await VerbalTrickApi.getVerbalTrickList(id);
verbalTrickList.value = response; // verbalTrickList verbalTrickList.value = response; // verbalTrickList
} }
/*选择话术库内容*/ /*选择话术库内容*/
const huashuClick = (content: string) => { const huashuClick = (content : string) => {
message.value = content; message.value = content;
dialogVisible.value = false; dialogVisible.value = false;
} }
const clickMenu = (id: string) => { const clickMenu = (id : string) => {
console.log('1111111111',id) console.log('1111111111', id)
getVerbalTrickList(id) getVerbalTrickList(id)
} }
/** 发送文本消息 */ /** 发送文本消息 */
const handleSendMessage = async () => { const handleSendMessage = async () => {
@ -423,9 +420,9 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
} finally { } finally {
} }
} }
/** 转接客服人员列表 id会话id kefuId客服人员id */ /** 转接客服人员列表 id会话id kefuId客服人员id */
const transferConversion = async (kefuId: number) => { const transferConversion = async (kefuId : number) => {
try { try {
await KeFuConversationApi.transferConversion(queryParams.conversationId, kefuId) await KeFuConversationApi.transferConversion(queryParams.conversationId, kefuId)
} finally { } finally {
@ -435,15 +432,17 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
/** 初始化 **/ /** 初始化 **/
onMounted(() => { onMounted(() => {
getHuaShuTypeList() getHuaShuTypeList()
getVerbalTrickList(targetMenuId.value) getVerbalTrickList(targetMenuId.value)
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.hover-shadow:hover { .hover-shadow:hover {
background-color: lightgray; /* 可根据需要调整颜色 */ background-color: lightgray;
/* 可根据需要调整颜色 */
} }
.kefu { .kefu {
&-title { &-title {
border-bottom: #e4e0e0 solid 1px; border-bottom: #e4e0e0 solid 1px;
@ -487,8 +486,8 @@ v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer
} }
} }
} }
.ss-row-right { .ss-row-right {
justify-content: flex-end; justify-content: flex-end;

View File

@ -1,7 +1,7 @@
<!-- 目录是不是叫 member 好点然后这个组件是 MemberInfo里面有浏览足迹 --> <!-- 目录是不是叫 member 好点然后这个组件是 MemberInfo里面有浏览足迹 -->
<template> <template>
<div v-show="!isEmpty(conversation)" class="kefu"> <div v-show="!isEmpty(conversation)" class="kefu">
<div class="header-title h-60px flex justify-center items-center">他的足迹</div> <!-- <div class="header-title h-60px flex justify-center items-center">他的足迹</div> -->
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
<el-tab-pane label="最近浏览" name="a" /> <el-tab-pane label="最近浏览" name="a" />
<el-tab-pane label="订单列表" name="b" /> <el-tab-pane label="订单列表" name="b" />

View File

@ -1,35 +1,99 @@
<template> <template>
<el-row :gutter="10" style="display: flex; justify-content: center;"> <div>
<!-- 会话列表 --> <!-- 新区域放在头部 -->
<el-col :span="5" > <el-row style="display: flex; justify-content: center;">
<ContentWrap>
<KeFuConversationList ref="keFuConversationRef" @change="handleChange" /> <el-col :span="24">
</ContentWrap> <div style="width:100%;height:70px;background-color:#3c80ff;">
</el-col> <el-row>
<!-- 会话详情选中会话的消息列表 --> <el-col :span="6">
<el-col :span="10"> <el-input
<ContentWrap> style="width: 80%;margin-top: 20px;margin-left:10px;"
<KeFuMessageList ref="keFuChatBoxRef" @change="getConversationList" /> :suffix-icon="Search"
</ContentWrap> />
</el-col> </el-col>
<!-- 会员足迹选中会话的会员足迹 -->
<el-col :span="5"> <el-col :span="6">
<ContentWrap> <span style="display: flex; margin-top: 15px;">
<MemberBrowsingHistory ref="memberBrowsingHistoryRef" /> <el-avatar
</ContentWrap> src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"
</el-col> />
</el-row> <span style="margin-left:5px;margin-top: 9px;">客服桃子</span>
<el-switch
style="margin-top: 4px;--el-switch-on-color: #13ce66; --el-switch-off-color: #b6bac1;"
v-model="value6"
class="ml-2"
width="60"
inline-prompt
active-text="在线"
inactive-text="下线"
/>
</span>
</el-col>
<el-col :span="6">
<el-button size="small" round style="margin-top:23px;margin-left:75%">退出登录</el-button>
</el-col>
<el-col :span="6">
<el-menu
background-color="#3c80ff"
text-color="white"
active-text-color="white"
style="width:100%;display: flex;"
>
<el-menu-item style="width:33%;height:70px" index="1">客户信息</el-menu-item>
<el-menu-item style="width:33%;height:70px" index="2">交易订单</el-menu-item>
<el-menu-item style="width:34%;height:70px" index="3">商品信息</el-menu-item>
</el-menu>
<!-- <div style="color: #ffffff;" class="header-title h-60px flex justify-center items-center">他的足迹</div> -->
</el-col>
</el-row>
</div>
</el-col>
</el-row>
<!-- 原有的三个区域 -->
<el-row style="display: flex; justify-content: center;">
<!-- 会话列表 -->
<el-col :span="6">
<ContentWrap>
<KeFuConversationList ref="keFuConversationRef" @change="handleChange"/>
</ContentWrap>
</el-col>
<!-- 会话详情选中会话的消息列表 -->
<el-col :span="12">
<ContentWrap>
<KeFuMessageList ref="keFuChatBoxRef" @change="getConversationList"/>
</ContentWrap>
</el-col>
<!-- 会员足迹选中会话的会员足迹 -->
<el-col :span="6">
<ContentWrap>
<MemberBrowsingHistory ref="memberBrowsingHistoryRef"/>
</ContentWrap>
</el-col>
</el-row>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } from './components' import {KeFuConversationList, KeFuMessageList, MemberBrowsingHistory} from './components'
import { WebSocketMessageTypeConstants } from './components/tools/constants' import {WebSocketMessageTypeConstants} from './components/tools/constants'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation' import {KeFuConversationRespVO} from '@/api/mall/promotion/kefu/conversation'
import { getRefreshToken, getAccessToken } from '@/utils/auth' import {getRefreshToken, getAccessToken} from '@/utils/auth'
import { useWebSocket } from '@vueuse/core' import {useWebSocket} from '@vueuse/core'
import {Search} from '@element-plus/icons-vue'
defineOptions({ name: 'KeFu' }) defineOptions({name: 'KeFu'})
const value6 = ref(true)
const message = useMessage() // const message = useMessage() //
@ -41,7 +105,7 @@
) // WebSocket ) // WebSocket
/** 发起 WebSocket 连接 */ /** 发起 WebSocket 连接 */
const { data, close, open } = useWebSocket(server.value, { const {data, close, open} = useWebSocket(server.value, {
autoReconnect: false, autoReconnect: false,
heartbeat: true heartbeat: true
}) })
@ -116,6 +180,7 @@
.kefu { .kefu {
height: calc(100vh - 165px); height: calc(100vh - 165px);
overflow: auto; /* 确保内容可滚动 */ overflow: auto; /* 确保内容可滚动 */
} }
/* 定义滚动条样式 */ /* 定义滚动条样式 */
@ -133,8 +198,10 @@
/* 定义滑块 内阴影+圆角 */ /* 定义滑块 内阴影+圆角 */
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
border-radius: 10px; border-radius: 10px;
box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5); box-shadow: inset 0 0 0 rgba(240, 240, 240, 0.5);
background-color: rgba(240, 240, 240, 0.5); background-color: rgba(240, 240, 240, 0.5);
} }
</style> </style>

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.kefu.vo.message.KeFuMessageRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.kefu.vo.message.KeFuMessageRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessagePageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessagePageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessageSendReqVO; import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessageSendReqVO;
@ -31,6 +33,10 @@ public class AppKeFuMessageController {
@Resource @Resource
private KeFuMessageService kefuMessageService; private KeFuMessageService kefuMessageService;
@Resource
private MemberUserApi memberUserApi;
@PostMapping("/send") @PostMapping("/send")
@Operation(summary = "发送客服消息") @Operation(summary = "发送客服消息")
@PreAuthenticated @PreAuthenticated
@ -53,6 +59,19 @@ public class AppKeFuMessageController {
@PreAuthenticated @PreAuthenticated
public CommonResult<PageResult<KeFuMessageRespVO>> getKefuMessagePage(@Valid AppKeFuMessagePageReqVO pageReqVO) { public CommonResult<PageResult<KeFuMessageRespVO>> getKefuMessagePage(@Valid AppKeFuMessagePageReqVO pageReqVO) {
PageResult<KeFuMessageDO> pageResult = kefuMessageService.getKeFuMessagePage(pageReqVO, getLoginUserId()); PageResult<KeFuMessageDO> pageResult = kefuMessageService.getKeFuMessagePage(pageReqVO, getLoginUserId());
for (int i = 0; i < pageResult.getList().size(); i++) {
KeFuMessageDO keFuMessageDO = pageResult.getList().get(i);
if (keFuMessageDO.getSenderType() == 1){
MemberUserRespDTO user = memberUserApi.getUser(keFuMessageDO.getSenderId());
keFuMessageDO.setSenderAvatar(user.getAvatar());
}
if (keFuMessageDO.getSenderType() == 2){
String systemUserAvatar = kefuMessageService.findSystemUserAvatar(keFuMessageDO.getSenderId());
keFuMessageDO.setSenderAvatar(systemUserAvatar);
}
}
return success(BeanUtils.toBean(pageResult, KeFuMessageRespVO.class)); return success(BeanUtils.toBean(pageResult, KeFuMessageRespVO.class));
} }

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.promotion.enums.kefu.KeFuMessageContentTypeEnum; import cn.iocoder.yudao.module.promotion.enums.kefu.KeFuMessageContentTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*; import lombok.*;
@ -78,4 +79,7 @@ public class KeFuMessageDO extends BaseDO {
*/ */
private Boolean readStatus; private Boolean readStatus;
@TableField(exist = false)
private String senderAvatar;
} }

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.kefu.KeFuMessageDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -46,4 +47,8 @@ public interface KeFuMessageMapper extends BaseMapperX<KeFuMessageDO> {
.orderByDesc(KeFuMessageDO::getCreateTime)); .orderByDesc(KeFuMessageDO::getCreateTime));
} }
@Select(" SELECT avatar FROM system_users where id = #{id} ")
String findSystemUserAvatar(Long id);
} }

View File

@ -59,4 +59,6 @@ public interface KeFuMessageService {
*/ */
PageResult<KeFuMessageDO> getKeFuMessagePage(AppKeFuMessagePageReqVO pageReqVO, Long userId); PageResult<KeFuMessageDO> getKeFuMessagePage(AppKeFuMessagePageReqVO pageReqVO, Long userId);
String findSystemUserAvatar(Long id);
} }

View File

@ -159,6 +159,11 @@ public class KeFuMessageServiceImpl implements KeFuMessageService {
return keFuMessageMapper.selectPage(pageReqVO); return keFuMessageMapper.selectPage(pageReqVO);
} }
@Override
public String findSystemUserAvatar(Long id) {
return keFuMessageMapper.findSystemUserAvatar(id);
}
private KeFuMessageServiceImpl getSelf() { private KeFuMessageServiceImpl getSelf() {
return SpringUtil.getBean(getClass()); return SpringUtil.getBean(getClass());
} }

View File

@ -254,6 +254,7 @@ public class SocialClientServiceImpl implements SocialClientService {
ObjUtil.defaultIfNull(reqVO.getAutoColor(), SocialWxQrcodeReqDTO.AUTO_COLOR), ObjUtil.defaultIfNull(reqVO.getAutoColor(), SocialWxQrcodeReqDTO.AUTO_COLOR),
null, null,
ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE)); ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE));
} catch (WxErrorException e) { } catch (WxErrorException e) {
log.error("[getWxQrcode][reqVO({})) 获得小程序码失败]", reqVO, e); log.error("[getWxQrcode][reqVO({})) 获得小程序码失败]", reqVO, e);
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR); throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR);

View File

@ -57,7 +57,7 @@ spring:
# url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例
# url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例
username: root username: root
# password: 123456 # password: 123456
password: xpower1234 password: xpower1234
# username: sa # SQL Server 连接的示例 # username: sa # SQL Server 连接的示例
# password: Yudao@2024 # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例
@ -228,7 +228,7 @@ yudao:
enable: false enable: false
demo: false # 关闭演示模式 demo: false # 关闭演示模式
wxa-code: wxa-code:
env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop" env-version: release # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop"
tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc tencent-lbs-key: TVDBZ-TDILD-4ON4B-PFDZA-RNLKH-VVF6E # QQ 地图的密钥 https://lbs.qq.com/service/staticV2/staticGuide/staticDoc
justauth: justauth: