添加客服配置
This commit is contained in:
parent
9690df6930
commit
2fa158d3ff
@ -0,0 +1,44 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
// 客服配置 VO
|
||||
export interface ConfigurationVO {
|
||||
id: number // id
|
||||
type: string // 客服类型
|
||||
feedback: string // 客服反馈
|
||||
phone: string // 客服电话
|
||||
link: string // 客服链接
|
||||
enterpriseID: string // 企业ID
|
||||
}
|
||||
|
||||
// 客服配置 API
|
||||
export const ConfigurationApi = {
|
||||
// 查询客服配置分页
|
||||
getConfigurationPage: async (params: any) => {
|
||||
return await request.get({ url: `/promotion/ke-fu-configuration/page`, params })
|
||||
},
|
||||
|
||||
// 查询客服配置详情
|
||||
getConfiguration: async (id: number) => {
|
||||
return await request.get({ url: `/promotion/ke-fu-configuration/get?id=` + id })
|
||||
},
|
||||
|
||||
// 新增客服配置
|
||||
createConfiguration: async (data: ConfigurationVO) => {
|
||||
return await request.post({ url: `/promotion/ke-fu-configuration/create`, data })
|
||||
},
|
||||
|
||||
// 修改客服配置
|
||||
updateConfiguration: async (data: ConfigurationVO) => {
|
||||
return await request.put({ url: `/promotion/ke-fu-configuration/update`, data })
|
||||
},
|
||||
|
||||
// 删除客服配置
|
||||
deleteConfiguration: async (id: number) => {
|
||||
return await request.delete({ url: `/promotion/ke-fu-configuration/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 导出客服配置 Excel
|
||||
exportConfiguration: async (params) => {
|
||||
return await request.download({ url: `/promotion/ke-fu-configuration/export-excel`, params })
|
||||
}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<doc-alert title="上传下载" url="https://doc.iocoder.cn/file/" />
|
||||
<doc-alert title="上传下载" url="https://doc.iocoder.cn/file/"/>
|
||||
|
||||
<div class="flex-container">
|
||||
<!-- 菜单区域 -->
|
||||
<div class="menu-area">
|
||||
|
||||
<el-button type="primary" plain @click="createType" style="width: 90;font-size: 12px;">
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增分类
|
||||
<Icon icon="ep:plus" class="mr-5px"/>
|
||||
新增分类
|
||||
</el-button>
|
||||
|
||||
<el-menu :default-active="targetMenuId" style="width:182px">
|
||||
<el-menu :default-active="targetMenuId" style="width:200px">
|
||||
<el-menu-item :index="targetMenuId" :key="targetMenuId" @click="clickMenu(targetMenuId)">
|
||||
全部类型
|
||||
</el-menu-item>
|
||||
@ -18,10 +19,10 @@
|
||||
{{ item.label }}
|
||||
<el-icon style="margin-left: 60px;width: 10px;" @mouseover="showActions = item.value"
|
||||
@mouseleave="showActions = null">
|
||||
<MoreFilled />
|
||||
<MoreFilled/>
|
||||
<div v-if="showActions === item.value" class="action-buttons">
|
||||
<el-button size="small" @click.stop="editItem(item.id,item.label)">编辑</el-button>
|
||||
<br />
|
||||
<br/>
|
||||
<el-button size="small" @click.stop="deleteItem(item.id)">删除</el-button>
|
||||
</div>
|
||||
</el-icon>
|
||||
@ -32,98 +33,123 @@
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrap">
|
||||
<ContentWrap>
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
|
||||
<div style="margin-top: 25px;margin-left: 20px;">
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true"
|
||||
label-width="68px">
|
||||
<el-form-item label="文件类型" prop="type" width="80">
|
||||
<el-input v-model="queryParams.type" placeholder="请输入文件类型" clearable
|
||||
@keyup.enter="handleQuery" />
|
||||
@keyup.enter="handleQuery"/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
|
||||
</el-form-item> -->
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||
<Icon icon="ep:search" class="mr-5px"/>
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">
|
||||
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||
<Icon icon="ep:refresh" class="mr-5px"/>
|
||||
重置
|
||||
</el-button>
|
||||
<el-button type="primary" plain @click="openForm">
|
||||
<Icon icon="ep:upload" class="mr-5px" /> 上传文件
|
||||
<Icon icon="ep:upload" class="mr-5px"/>
|
||||
上传文件
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<span><img @click="liebiao" style="cursor: pointer;" class="mr-10px h-30px w-30px" src="@/assets/imgs/liebiao.png" /></span>
|
||||
<span><img @click="tubiao" style="cursor: pointer;" class="mr-10px h-30px w-30px" src="@/assets/imgs/tubiao.png" /></span>
|
||||
<span><img @click="liebiao" style="cursor: pointer;" class="mr-10px h-30px w-30px"
|
||||
src="@/assets/imgs/liebiao.png"/></span>
|
||||
<span><img @click="tubiao" style="cursor: pointer;" class="mr-10px h-30px w-30px"
|
||||
src="@/assets/imgs/tubiao.png"/></span>
|
||||
</el-form>
|
||||
|
||||
</ContentWrap>
|
||||
|
||||
|
||||
|
||||
<el-table v-loading="loading" :data="list" v-show="panduan == '1'">
|
||||
<el-table-column label="文件内容" align="center" prop="url" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-image v-if="row.type.includes('image')" class="h-80px w-80px" lazy :src="row.url"
|
||||
:preview-src-list="[row.url]" preview-teleported fit="cover" />
|
||||
<el-link v-else-if="row.type.includes('pdf')" type="primary" :href="row.url"
|
||||
:underline="false" target="_blank">预览</el-link>
|
||||
<el-link v-else type="primary" download :href="row.url" :underline="false"
|
||||
target="_blank">下载</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件名" align="center" prop="name" :show-overflow-tooltip="true" />
|
||||
<!-- <el-table-column label="文件路径" align="center" prop="path" :show-overflow-tooltip="true" /> -->
|
||||
<el-table-column label="URL" align="center" prop="url" :show-overflow-tooltip="true" />
|
||||
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180"
|
||||
:formatter="dateFormatter" />
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary"
|
||||
@click="updateForm('update', scope.row.id , scope.row.picType)">
|
||||
更改类型
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['infra:file:delete']">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-show="panduan == '2'">
|
||||
<!-- 图片展示区域 -->
|
||||
<div class="image-container">
|
||||
<div v-for="item in tubiaoData" :key="item.id" class="image-item">
|
||||
<img :src="item.url" alt="图表" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="margin-top: 10px;" >
|
||||
<el-table v-loading="loading" :data="list" v-show="panduan == '1'">
|
||||
<el-table-column label="文件内容" align="center" prop="url" width="110px">
|
||||
<template #default="{ row }">
|
||||
<el-image v-if="row.type.includes('image')" class="h-40px w-40px" lazy :src="row.url"
|
||||
:preview-src-list="[row.url]" preview-teleported fit="cover"/>
|
||||
<el-link v-else-if="row.type.includes('pdf')" type="primary" :href="row.url"
|
||||
:underline="false" target="_blank">预览
|
||||
</el-link>
|
||||
<el-link v-else type="primary" download :href="row.url" :underline="false"
|
||||
target="_blank">下载
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件名" align="center" prop="name" :show-overflow-tooltip="true"/>
|
||||
<!-- <el-table-column label="文件路径" align="center" prop="path" :show-overflow-tooltip="true" /> -->
|
||||
<el-table-column label="URL" align="center" prop="url" :show-overflow-tooltip="true"/>
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="180"
|
||||
:formatter="dateFormatter"/>
|
||||
<el-table-column label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary"
|
||||
@click="updateForm('update', scope.row.id , scope.row.picType)">
|
||||
更改类型
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)"
|
||||
v-hasPermi="['infra:file:delete']">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-show="panduan == '2'">
|
||||
<!-- 图片展示区域 -->
|
||||
<div class="image-container">
|
||||
<div
|
||||
v-for="item in tubiaoData"
|
||||
:key="item.id"
|
||||
class="image-item"
|
||||
@mouseover="hover(item.id, true)"
|
||||
@mouseleave="hover(item.id, false)"
|
||||
>
|
||||
<img :src="item.url" alt="图表"/>
|
||||
<div class="image-name">{{ item.name }}</div>
|
||||
<div v-show="hoveredIndex === item.id" class="button-container">
|
||||
<button class="button">按钮1</button>
|
||||
<button class="button">按钮2</button>
|
||||
<button class="button">按钮3</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表单弹窗:添加/修改 -->
|
||||
<FileForm ref="formRef" @success="getList" />
|
||||
<FileForm ref="formRef" @success="getList"/>
|
||||
|
||||
<UpdateForm ref="forRef" @success="getList" />
|
||||
<UpdateForm ref="forRef" @success="getList"/>
|
||||
|
||||
<Dialog v-model="dialogVisibles" :title="dialogTitles">
|
||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules" label-width="80px">
|
||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" :rules="formRules"
|
||||
label-width="80px">
|
||||
|
||||
<el-form-item label="数据标签" prop="label">
|
||||
<el-input v-model="formData.label" placeholder="请输入数据标签" />
|
||||
<el-input v-model="formData.label" placeholder="请输入数据标签"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="sort">
|
||||
<el-input-number v-model="formData.sort" :min="0" controls-position="right" />
|
||||
<el-input-number v-model="formData.sort" :min="0" controls-position="right"/>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
@ -136,7 +162,7 @@
|
||||
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
|
||||
<el-form-item label="数据标签" prop="label">
|
||||
<el-input v-model="updateLabel" placeholder="请输入数据标签" />
|
||||
<el-input v-model="updateLabel" placeholder="请输入数据标签"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -149,18 +175,19 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
||||
import { fileSizeFormatter } from '@/utils'
|
||||
import { Search, MoreFilled } from '@element-plus/icons-vue';
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import {getIntDictOptions, DICT_TYPE} from '@/utils/dict'
|
||||
import {fileSizeFormatter} from '@/utils'
|
||||
import {Search, MoreFilled} from '@element-plus/icons-vue';
|
||||
import {dateFormatter} from '@/utils/formatTime'
|
||||
// import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import * as FileApi from '@/api/infra/file'
|
||||
import FileForm from './FileForm.vue'
|
||||
import UpdateForm from './updateForm.vue'
|
||||
import * as DictDataApi from '@/api/system/dict/dict.data'
|
||||
|
||||
const typeMenu = ref<DictDataApi.DictDataVO[]>([]) //
|
||||
const targetMenuId = ref('0')
|
||||
defineOptions({ name: 'InfraFile' })
|
||||
defineOptions({name: 'InfraFile'})
|
||||
const showActions = ref(null);
|
||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||
const dialogTitle = ref('') // 弹窗的标题
|
||||
@ -181,12 +208,12 @@
|
||||
remark: ''
|
||||
})
|
||||
const formRules = reactive({
|
||||
label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
|
||||
sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }],
|
||||
label: [{required: true, message: '数据标签不能为空', trigger: 'blur'}],
|
||||
sort: [{required: true, message: '数据顺序不能为空', trigger: 'blur'}],
|
||||
})
|
||||
const updateLabel = ref('')
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
const {t} = useI18n() // 国际化
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
const total = ref(0) // 列表的总页数
|
||||
@ -203,7 +230,17 @@
|
||||
createTime: [],
|
||||
})
|
||||
const queryFormRef = ref() // 搜索的表单
|
||||
|
||||
|
||||
// const hoveredIndex = ref(null);
|
||||
|
||||
// const hover = (index: string, status: boolean) => {
|
||||
// if (status) {
|
||||
// hoveredIndex.value = index; // 鼠标悬停时显示按钮
|
||||
// } else {
|
||||
// hoveredIndex.value = ''; // 鼠标离开时隐藏按钮
|
||||
// }
|
||||
// }
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
@ -211,12 +248,13 @@
|
||||
const data = await FileApi.getFilePage(queryParams)
|
||||
list.value = data.list
|
||||
tubiaoData.value = data.list
|
||||
console.log('111111',tubiaoData)
|
||||
console.log('111111', tubiaoData)
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
interface FileDataVO {
|
||||
id: string
|
||||
configId: string
|
||||
@ -289,7 +327,7 @@
|
||||
}
|
||||
|
||||
//分类菜单修改按钮
|
||||
const editItem = (id : number | undefined, lable : string) => {
|
||||
const editItem = (id: number | undefined, lable: string) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = '菜单编辑'
|
||||
menuId.value = id
|
||||
@ -298,7 +336,7 @@
|
||||
console.log('编辑:',);
|
||||
};
|
||||
//分类菜单删除按钮
|
||||
const deleteItem = async (id : number | undefined) => {
|
||||
const deleteItem = async (id: number | undefined) => {
|
||||
// 处理删除事件
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
@ -315,7 +353,7 @@
|
||||
|
||||
|
||||
/** */
|
||||
const clickMenu = (id : string) => {
|
||||
const clickMenu = (id: string) => {
|
||||
queryParams.picType = id
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
@ -341,14 +379,13 @@
|
||||
|
||||
const forRef = ref()
|
||||
/** 修改操作 */
|
||||
const updateForm = (type : string, id : number, picType : number) => {
|
||||
const updateForm = (type: string, id: number, picType: number) => {
|
||||
forRef.value.open(type, id, picType)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (id : number) => {
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
// 删除的二次确认
|
||||
await message.delConfirm()
|
||||
@ -357,7 +394,8 @@
|
||||
message.success(t('common.delSuccess'))
|
||||
// 刷新列表
|
||||
await getList()
|
||||
} catch { }
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 **/
|
||||
@ -378,7 +416,7 @@
|
||||
padding: 25px;
|
||||
background-color: white;
|
||||
width: 180px;
|
||||
height: 1000px;
|
||||
height: 700px;
|
||||
/* 固定高度 */
|
||||
overflow-y: hidden;
|
||||
/* 禁止滚动 */
|
||||
@ -387,9 +425,10 @@
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
background-color: white;
|
||||
flex-grow: 1;
|
||||
/* 使内容区域占据剩余空间 */
|
||||
overflow-y: auto;
|
||||
/* overflow-y: auto; */
|
||||
/* 允许内容区域滚动 */
|
||||
}
|
||||
|
||||
@ -398,23 +437,34 @@
|
||||
.image-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px; /* 设置图片之间的间距 */
|
||||
gap: 10px; /* 设置图片之间的间距 */
|
||||
justify-content: flex-start; /* 如果图片少于5张,会平均分布 */
|
||||
max-width: 1000px; /* 设置外部容器的最大宽度 */
|
||||
margin: 0 auto; /* 居中显示 */
|
||||
margin: 0 auto; /* 居中显示 */
|
||||
}
|
||||
|
||||
/* 每张图片占用的宽度,使每行显示5张 */
|
||||
.image-item {
|
||||
width: calc(20% - 8px); /* 宽度设为容器的20%,减去间距 */
|
||||
width: calc(20% - 8px); /* 宽度设为容器的20%,减去间距 */
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 设置图片的最大宽度 */
|
||||
.image-item img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px; /* 图片边缘圆角(可选) */
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
/* border-radius: 8px; /* 图片边缘圆角(可选) */
|
||||
border: 3px solid #f3f3f3;
|
||||
}
|
||||
|
||||
.image-name {
|
||||
margin-top: 5 px; /* 图片和名称之间的间距 */
|
||||
font-size: 14px; /* 文字大小 */
|
||||
color: #333; /* 文字颜色 */
|
||||
word-wrap: break-word; /* 如果名称很长,自动换行 */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
@ -67,7 +67,7 @@
|
||||
@click="openForm('create')"
|
||||
v-hasPermi="['promotion:auto-response:create']"
|
||||
>
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增自动恢复
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增自动回复
|
||||
</el-button>
|
||||
<!-- <el-button
|
||||
type="success"
|
||||
|
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<span>客服配置</span>
|
||||
<el-divider />
|
||||
<div style="height:380px;width:650px;padding: 20px;">
|
||||
<span>客服类型:</span>
|
||||
<span>
|
||||
<el-radio-group v-model="radios" @change="handleRadioChange">
|
||||
<el-radio value="1" size="large">系统客服</el-radio>
|
||||
<el-radio value="2" size="large">拨打电话</el-radio>
|
||||
<el-radio value="3" size="large">跳转链接</el-radio>
|
||||
</el-radio-group>
|
||||
</span>
|
||||
<p style="margin-left: 80px;color:#bcbaba;font-size:13px">系统客服:点击联系客服使用系统的自带客服;拨打电话:点击联系客服拨打客服电话;跳转链接:跳转外部链接联系客服</p>
|
||||
|
||||
<div v-show="radios == 1">
|
||||
<span style="margin-top: 60px; vertical-align: middle;">客服反馈:</span>
|
||||
<span style="vertical-align: middle;">
|
||||
<el-input
|
||||
v-model="formData.feedback"
|
||||
placeholder="请输入客服反馈"
|
||||
style="width:550px"
|
||||
:rows="5"
|
||||
type="textarea"
|
||||
|
||||
/>
|
||||
</span>
|
||||
<p style="margin-left: 80px;color:#bcbaba;font-size:13px">暂无客服在线是,联系客服跳转的客服反馈页面的显示文字</p>
|
||||
</div>
|
||||
|
||||
<div v-show="radios == 2">
|
||||
<span style="margin-top: 60px; vertical-align: middle;">客服电话:</span>
|
||||
<span style="vertical-align: middle;">
|
||||
<el-input
|
||||
v-model="formData.phone"
|
||||
placeholder="请输入客服电话"
|
||||
style="width:550px"
|
||||
/>
|
||||
</span>
|
||||
<p style="margin-left: 80px;color:#bcbaba;font-size:13px">客服类型选择拨打电话时,用户点击联系客服的联系电话</p>
|
||||
</div>
|
||||
|
||||
<div v-show="radios == 3">
|
||||
<span style="margin-top: 60px; vertical-align: middle;">客服链接:</span>
|
||||
<span style="vertical-align: middle;">
|
||||
<el-input
|
||||
v-model="formData.link"
|
||||
placeholder="请输入客服链接"
|
||||
style="width:550px"
|
||||
/>
|
||||
</span>
|
||||
<p style="margin-left: 80px;color:#bcbaba;font-size:13px">客服类型选择跳转链接时,跳转的链接地址</p>
|
||||
|
||||
<span style="margin-top: 60px; vertical-align: middle;"> 企业ID:</span>
|
||||
<span style="vertical-align: middle;">
|
||||
<el-input
|
||||
v-model="formData.enterpriseID"
|
||||
placeholder="请输入企业ID"
|
||||
style="width:550px"
|
||||
/>
|
||||
</span>
|
||||
<p style="margin-left: 80px;color:#bcbaba;font-size:13px">如果客服链接填写企业微信客服,小程序需要跳转企业微信客服的话需要配置此项,并且在小程序客服中绑定企业ID</p>
|
||||
|
||||
</div>
|
||||
|
||||
<el-button style="margin-left: 80px;" type="primary" @click="submit">提交</el-button>
|
||||
|
||||
</div>
|
||||
</ContentWrap>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
import { ConfigurationApi, ConfigurationVO } from '@/api/mall/promotion/configuration'
|
||||
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const { t } = useI18n() // 国际化
|
||||
|
||||
const loading = ref(true) // 列表的加载中
|
||||
|
||||
const radios = ref('1')
|
||||
|
||||
const formData = ref({
|
||||
id: undefined,
|
||||
type: undefined,
|
||||
feedback: undefined,
|
||||
phone: undefined,
|
||||
link: undefined,
|
||||
enterpriseID: undefined
|
||||
})
|
||||
|
||||
|
||||
/** 查询列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
|
||||
formData.value = await ConfigurationApi.getConfiguration(Number(radios.value))
|
||||
// radios.value = formData.value.id
|
||||
console.log('11111',radios.value)
|
||||
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const handleRadioChange = async (value) =>{
|
||||
formData.value = await ConfigurationApi.getConfiguration(value)
|
||||
|
||||
|
||||
console.log("选中的值是: ", radios.value); // 输出选中的值
|
||||
|
||||
}
|
||||
|
||||
|
||||
const submit = async () => {
|
||||
const data = formData.value as unknown as ConfigurationVO
|
||||
await ConfigurationApi.updateConfiguration(data)
|
||||
message.success('提交成功')
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 初始化 **/
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
@ -7,7 +7,7 @@
|
||||
label-width="100px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="分类" prop="type">
|
||||
<el-form-item label="话术分类" prop="type">
|
||||
<el-select v-model="formData.type" placeholder="请选择分类">
|
||||
<el-option
|
||||
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_VERBAL_TRICK_TYPE)"
|
||||
@ -17,10 +17,10 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-form-item label="话术标题" prop="title">
|
||||
<el-input v-model="formData.title" placeholder="请输入标题" />
|
||||
</el-form-item>
|
||||
<el-form-item label="详情" prop="details">
|
||||
<el-form-item label="话术内容" prop="details">
|
||||
<el-input v-model="formData.details" type="textarea" placeholder="请输入详情" :rows="6" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<el-button type="primary" plain @click="createType" style="width: 90;font-size: 12px;">
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增分类
|
||||
</el-button>
|
||||
<el-menu :default-active="targetMenuId" style="width:183px">
|
||||
<el-menu :default-active="targetMenuId" style="width:209px">
|
||||
<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>
|
||||
@ -14,9 +14,7 @@
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content-wrap">
|
||||
|
||||
|
||||
<ContentWrap>
|
||||
<div style="margin-top: 25px;margin-left:20px">
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<!-- <el-form-item label="分类" prop="type">
|
||||
@ -51,10 +49,12 @@
|
||||
</el-button> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- 列表 -->
|
||||
<ContentWrap>
|
||||
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
||||
<el-table-column label="ID" align="center" prop="id" />
|
||||
<el-table-column label="分类" align="center" prop="type">
|
||||
@ -80,7 +80,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 分页 -->
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList" />
|
||||
@ -281,7 +281,7 @@
|
||||
padding: 25px;
|
||||
background-color: white;
|
||||
width: 180px;
|
||||
height: 1000px;
|
||||
height: 700px;
|
||||
/* 固定高度 */
|
||||
overflow-y: hidden;
|
||||
/* 禁止滚动 */
|
||||
@ -293,6 +293,7 @@
|
||||
flex-grow: 1;
|
||||
/* 使内容区域占据剩余空间 */
|
||||
overflow-y: auto;
|
||||
background-color: #ffffff;
|
||||
/* 允许内容区域滚动 */
|
||||
}
|
||||
</style>
|
@ -76,7 +76,8 @@ public class SecurityFrameworkUtils {
|
||||
if (authentication == null) {
|
||||
return null;
|
||||
}
|
||||
return authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||
LoginUser loginUser = authentication.getPrincipal() instanceof LoginUser ? (LoginUser) authentication.getPrincipal() : null;
|
||||
return loginUser;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,7 +38,12 @@ public abstract class AbstractWebSocketMessageSender implements WebSocketMessage
|
||||
|
||||
@Override
|
||||
public void send(String sessionId, String messageType, String messageContent) {
|
||||
send(sessionId, null, null, messageType, messageContent);
|
||||
send(sessionId, (Integer) null,null, messageType, messageContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String sessionId, Long userId, Integer userType,String messageType, String messageContent) {
|
||||
send(sessionId, userType,userId, messageType, messageContent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,11 @@ public interface WebSocketMessageSender {
|
||||
*/
|
||||
void send(String sessionId, String messageType, String messageContent);
|
||||
|
||||
|
||||
void send(String sessionId, Long userId, Integer userType,String messageType, String messageContent);
|
||||
|
||||
|
||||
|
||||
default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) {
|
||||
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
@ -49,4 +54,8 @@ public interface WebSocketMessageSender {
|
||||
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
|
||||
default void sendObject(String sessionId, Long userId, Integer userType,String messageType, String messageContent) {
|
||||
send(sessionId,userId,userType, messageType, JsonUtils.toJsonString(messageContent));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
package cn.iocoder.yudao.framework.websocket.core.sender.redis;
|
||||
|
||||
import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.framework.websocket.core.sender.AbstractWebSocketMessageSender;
|
||||
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
||||
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* 基于 Redis 的 {@link WebSocketMessageSender} 实现类
|
||||
@ -16,6 +22,10 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
||||
|
||||
private final RedisMQTemplate redisMQTemplate;
|
||||
|
||||
@Resource
|
||||
private WebSocketSessionManager webSocketSessionManager;
|
||||
|
||||
|
||||
public RedisWebSocketMessageSender(WebSocketSessionManager sessionManager,
|
||||
RedisMQTemplate redisMQTemplate) {
|
||||
super(sessionManager);
|
||||
@ -27,6 +37,7 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
||||
sendRedisMessage(null, userId, userType, messageType, messageContent);
|
||||
}
|
||||
|
||||
//用户发
|
||||
@Override
|
||||
public void send(Integer userType, String messageType, String messageContent) {
|
||||
sendRedisMessage(null, null, userType, messageType, messageContent);
|
||||
@ -37,6 +48,11 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
||||
sendRedisMessage(sessionId, null, null, messageType, messageContent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String sessionId, Long userId, Integer userType,String messageType, String messageContent) {
|
||||
sendRedisMessage(sessionId, userId, userType, messageType, messageContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 Redis 广播消息
|
||||
*
|
||||
@ -48,6 +64,25 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
||||
*/
|
||||
private void sendRedisMessage(String sessionId, Long userId, Integer userType,
|
||||
String messageType, String messageContent) {
|
||||
|
||||
|
||||
if (userType == 2){
|
||||
ConcurrentMap<String, WebSocketSession> stringWebSocketSessionConcurrentMap = webSocketSessionManager.idSessions();
|
||||
for (Map.Entry<String, WebSocketSession> entry : stringWebSocketSessionConcurrentMap.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
WebSocketSession session = entry.getValue();
|
||||
|
||||
Map<String, Object> attributes = session.getAttributes();
|
||||
LoginUser loginUser = (LoginUser) attributes.get("LOGIN_USER");
|
||||
if(loginUser.getId() == 1 && loginUser.getUserType() == 2){
|
||||
sessionId = key;
|
||||
break;
|
||||
}
|
||||
// 处理每个 WebSocketSession
|
||||
System.out.println("Key: " + key + ", Session: " + session);
|
||||
}
|
||||
}
|
||||
|
||||
RedisWebSocketMessage mqMessage = new RedisWebSocketMessage()
|
||||
.setSessionId(sessionId).setUserId(userId).setUserType(userType)
|
||||
.setMessageType(messageType).setMessageContent(messageContent);
|
||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.websocket.core.session;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* {@link WebSocketSession} 管理器的接口
|
||||
@ -18,6 +19,7 @@ public interface WebSocketSessionManager {
|
||||
*/
|
||||
void addSession(WebSocketSession session);
|
||||
|
||||
ConcurrentMap<String, WebSocketSession> idSessions();
|
||||
/**
|
||||
* 移除 Session
|
||||
*
|
||||
@ -25,6 +27,8 @@ public interface WebSocketSessionManager {
|
||||
*/
|
||||
void removeSession(WebSocketSession session);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获得指定编号的 Session
|
||||
*
|
||||
|
@ -4,12 +4,12 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.net.URI;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@ -19,6 +19,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
|
||||
/**
|
||||
@ -28,6 +29,8 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
*/
|
||||
private final ConcurrentMap<String, WebSocketSession> idSessions = new ConcurrentHashMap<>();
|
||||
|
||||
private HttpSession httpSession;
|
||||
|
||||
/**
|
||||
* user 与 WebSocketSession 映射
|
||||
*
|
||||
@ -39,6 +42,7 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
|
||||
@Override
|
||||
public void addSession(WebSocketSession session) {
|
||||
|
||||
// 添加到 idSessions 中
|
||||
idSessions.put(session.getId(), session);
|
||||
// 添加到 userSessions 中
|
||||
@ -60,7 +64,18 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||
sessions = userSessionsMap.get(user.getId());
|
||||
}
|
||||
}
|
||||
System.out.println("---------sessions---------: " + session);
|
||||
sessions.add(session);
|
||||
String uri = session.getUri().toString();
|
||||
System.out.println(uri);
|
||||
|
||||
Map<String, Object> attributes = session.getAttributes();
|
||||
System.out.println("---------sessions---------: " + attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConcurrentMap<String, WebSocketSession> idSessions() {
|
||||
return idSessions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,8 @@ public interface ErrorCodeConstants {
|
||||
// ========== 兑换记录 TODO 补充编号 ==========
|
||||
ErrorCode POINT_ORDER_NOT_EXISTS = new ErrorCode(11111, "兑换记录不存在");
|
||||
|
||||
|
||||
ErrorCode KE_FU_CONFIGURATION_NOT_EXISTS = new ErrorCode(22222222, "客服配置不存在");
|
||||
// ========== Banner 相关 1-013-002-000 ============
|
||||
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在");
|
||||
|
||||
|
@ -0,0 +1,95 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.configuration;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import javax.validation.*;
|
||||
import javax.servlet.http.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
|
||||
|
||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
|
||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo.*;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.configuration.KeFuConfigurationDO;
|
||||
import cn.iocoder.yudao.module.promotion.service.configuration.KeFuConfigurationService;
|
||||
|
||||
@Tag(name = "管理后台 - 客服配置")
|
||||
@RestController
|
||||
@RequestMapping("/promotion/ke-fu-configuration")
|
||||
@Validated
|
||||
public class KeFuConfigurationController {
|
||||
|
||||
@Resource
|
||||
private KeFuConfigurationService keFuConfigurationService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建客服配置")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:create')")
|
||||
public CommonResult<Long> createKeFuConfiguration(@Valid @RequestBody KeFuConfigurationSaveReqVO createReqVO) {
|
||||
return success(keFuConfigurationService.createKeFuConfiguration(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新客服配置")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:update')")
|
||||
public CommonResult<Boolean> updateKeFuConfiguration(@Valid @RequestBody KeFuConfigurationSaveReqVO updateReqVO) {
|
||||
keFuConfigurationService.updateKeFuConfiguration(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除客服配置")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:delete')")
|
||||
public CommonResult<Boolean> deleteKeFuConfiguration(@RequestParam("id") Long id) {
|
||||
keFuConfigurationService.deleteKeFuConfiguration(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得客服配置")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:query')")
|
||||
public CommonResult<KeFuConfigurationRespVO> getKeFuConfiguration(@RequestParam("id") Long id) {
|
||||
KeFuConfigurationDO keFuConfiguration = keFuConfigurationService.getKeFuConfiguration(id);
|
||||
return success(BeanUtils.toBean(keFuConfiguration, KeFuConfigurationRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得客服配置分页")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:query')")
|
||||
public CommonResult<PageResult<KeFuConfigurationRespVO>> getKeFuConfigurationPage(@Valid KeFuConfigurationPageReqVO pageReqVO) {
|
||||
PageResult<KeFuConfigurationDO> pageResult = keFuConfigurationService.getKeFuConfigurationPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, KeFuConfigurationRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出客服配置 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('promotion:ke-fu-configuration:export')")
|
||||
@ApiAccessLog(operateType = EXPORT)
|
||||
public void exportKeFuConfigurationExcel(@Valid KeFuConfigurationPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<KeFuConfigurationDO> list = keFuConfigurationService.getKeFuConfigurationPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "客服配置.xls", "数据", KeFuConfigurationRespVO.class,
|
||||
BeanUtils.toBean(list, KeFuConfigurationRespVO.class));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 客服配置分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class KeFuConfigurationPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "客服类型", example = "1")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "客服反馈")
|
||||
private String feedback;
|
||||
|
||||
@Schema(description = "客服电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "客服链接")
|
||||
private String link;
|
||||
|
||||
@Schema(description = "企业ID", example = "20474")
|
||||
private String enterpriseID;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
import com.alibaba.excel.annotation.*;
|
||||
|
||||
@Schema(description = "管理后台 - 客服配置 Response VO")
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class KeFuConfigurationRespVO {
|
||||
|
||||
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5189")
|
||||
@ExcelProperty("id")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客服类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@ExcelProperty("客服类型")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "客服反馈")
|
||||
@ExcelProperty("客服反馈")
|
||||
private String feedback;
|
||||
|
||||
@Schema(description = "客服电话")
|
||||
@ExcelProperty("客服电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "客服链接")
|
||||
@ExcelProperty("客服链接")
|
||||
private String link;
|
||||
|
||||
@Schema(description = "企业ID", example = "20474")
|
||||
@ExcelProperty("企业ID")
|
||||
private String enterpriseID;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@ExcelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
@Schema(description = "管理后台 - 客服配置新增/修改 Request VO")
|
||||
@Data
|
||||
public class KeFuConfigurationSaveReqVO {
|
||||
|
||||
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5189")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "客服类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotEmpty(message = "客服类型不能为空")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "客服反馈")
|
||||
private String feedback;
|
||||
|
||||
@Schema(description = "客服电话")
|
||||
private String phone;
|
||||
|
||||
@Schema(description = "客服链接")
|
||||
private String link;
|
||||
|
||||
@Schema(description = "企业ID", example = "20474")
|
||||
private String enterpriseID;
|
||||
|
||||
}
|
@ -42,4 +42,6 @@ public class KeFuMessageRespVO {
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private String kefuName;
|
||||
|
||||
}
|
@ -10,7 +10,11 @@ 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.app.kefu.vo.message.AppKeFuMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.app.kefu.vo.message.AppKeFuMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.kefu.KeFuConversationDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.kefu.KeFuMessageDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.supportstaff.SupportStaffDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.kefu.KeFuConversationMapper;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.supportstaff.SupportStaffMapper;
|
||||
import cn.iocoder.yudao.module.promotion.service.kefu.KeFuMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
@ -33,9 +37,15 @@ public class AppKeFuMessageController {
|
||||
@Resource
|
||||
private KeFuMessageService kefuMessageService;
|
||||
|
||||
@Resource
|
||||
KeFuConversationMapper keFuConversationMapper;
|
||||
|
||||
@Resource
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@Resource
|
||||
private SupportStaffMapper supportStaffMapper;
|
||||
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "发送客服消息")
|
||||
@ -70,11 +80,16 @@ public class AppKeFuMessageController {
|
||||
String systemUserAvatar = kefuMessageService.findSystemUserAvatar(keFuMessageDO.getSenderId());
|
||||
keFuMessageDO.setSenderAvatar(systemUserAvatar);
|
||||
}
|
||||
|
||||
KeFuConversationDO user_di = keFuConversationMapper.selectOne("user_id", getLoginUserId());
|
||||
SupportStaffDO supportStaffDO = supportStaffMapper.selectOne("id", user_di.getKefuId());
|
||||
keFuMessageDO.setKefuName(supportStaffDO.getName());
|
||||
}
|
||||
|
||||
|
||||
return success(BeanUtils.toBean(pageResult, KeFuMessageRespVO.class));
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/test")
|
||||
@Operation(summary = "获得客服消息分页")
|
||||
@PreAuthenticated
|
||||
|
@ -0,0 +1,52 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.dataobject.configuration;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
|
||||
/**
|
||||
* 客服配置 DO
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
@TableName("promotion_kefu_configuration")
|
||||
@KeySequence("promotion_kefu_configuration_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class KeFuConfigurationDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 客服类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 客服反馈
|
||||
*/
|
||||
private String feedback;
|
||||
/**
|
||||
* 客服电话
|
||||
*/
|
||||
private String phone;
|
||||
/**
|
||||
* 客服链接
|
||||
*/
|
||||
private String link;
|
||||
/**
|
||||
* 企业ID
|
||||
*/
|
||||
@TableField("enterpriseID")
|
||||
private String enterpriseID;
|
||||
|
||||
}
|
@ -82,4 +82,8 @@ public class KeFuMessageDO extends BaseDO {
|
||||
|
||||
@TableField(exist = false)
|
||||
private String senderAvatar;
|
||||
|
||||
|
||||
@TableField(exist = false)
|
||||
private String kefuName;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.configuration;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.configuration.KeFuConfigurationDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo.*;
|
||||
|
||||
/**
|
||||
* 客服配置 Mapper
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
@Mapper
|
||||
public interface KeFuConfigurationMapper extends BaseMapperX<KeFuConfigurationDO> {
|
||||
|
||||
default PageResult<KeFuConfigurationDO> selectPage(KeFuConfigurationPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<KeFuConfigurationDO>()
|
||||
.eqIfPresent(KeFuConfigurationDO::getType, reqVO.getType())
|
||||
.eqIfPresent(KeFuConfigurationDO::getFeedback, reqVO.getFeedback())
|
||||
.eqIfPresent(KeFuConfigurationDO::getPhone, reqVO.getPhone())
|
||||
.eqIfPresent(KeFuConfigurationDO::getLink, reqVO.getLink())
|
||||
.eqIfPresent(KeFuConfigurationDO::getEnterpriseID, reqVO.getEnterpriseID())
|
||||
.betweenIfPresent(KeFuConfigurationDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(KeFuConfigurationDO::getId));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.configuration;
|
||||
|
||||
import java.util.*;
|
||||
import javax.validation.*;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo.*;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.configuration.KeFuConfigurationDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
|
||||
/**
|
||||
* 客服配置 Service 接口
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
public interface KeFuConfigurationService {
|
||||
|
||||
/**
|
||||
* 创建客服配置
|
||||
*
|
||||
* @param createReqVO 创建信息
|
||||
* @return 编号
|
||||
*/
|
||||
Long createKeFuConfiguration(@Valid KeFuConfigurationSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 更新客服配置
|
||||
*
|
||||
* @param updateReqVO 更新信息
|
||||
*/
|
||||
void updateKeFuConfiguration(@Valid KeFuConfigurationSaveReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 删除客服配置
|
||||
*
|
||||
* @param id 编号
|
||||
*/
|
||||
void deleteKeFuConfiguration(Long id);
|
||||
|
||||
/**
|
||||
* 获得客服配置
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 客服配置
|
||||
*/
|
||||
KeFuConfigurationDO getKeFuConfiguration(Long id);
|
||||
|
||||
/**
|
||||
* 获得客服配置分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 客服配置分页
|
||||
*/
|
||||
PageResult<KeFuConfigurationDO> getKeFuConfigurationPage(KeFuConfigurationPageReqVO pageReqVO);
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package cn.iocoder.yudao.module.promotion.service.configuration;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.configuration.vo.*;
|
||||
import cn.iocoder.yudao.module.promotion.dal.dataobject.configuration.KeFuConfigurationDO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.configuration.KeFuConfigurationMapper;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 客服配置 Service 实现类
|
||||
*
|
||||
* @author 管理员
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class KeFuConfigurationServiceImpl implements KeFuConfigurationService {
|
||||
|
||||
@Resource
|
||||
private KeFuConfigurationMapper keFuConfigurationMapper;
|
||||
|
||||
@Override
|
||||
public Long createKeFuConfiguration(KeFuConfigurationSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
KeFuConfigurationDO keFuConfiguration = BeanUtils.toBean(createReqVO, KeFuConfigurationDO.class);
|
||||
keFuConfigurationMapper.insert(keFuConfiguration);
|
||||
// 返回
|
||||
return keFuConfiguration.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateKeFuConfiguration(KeFuConfigurationSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
validateKeFuConfigurationExists(updateReqVO.getId());
|
||||
// 更新
|
||||
KeFuConfigurationDO updateObj = BeanUtils.toBean(updateReqVO, KeFuConfigurationDO.class);
|
||||
keFuConfigurationMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteKeFuConfiguration(Long id) {
|
||||
// 校验存在
|
||||
validateKeFuConfigurationExists(id);
|
||||
// 删除
|
||||
keFuConfigurationMapper.deleteById(id);
|
||||
}
|
||||
|
||||
private void validateKeFuConfigurationExists(Long id) {
|
||||
if (keFuConfigurationMapper.selectById(id) == null) {
|
||||
throw exception(KE_FU_CONFIGURATION_NOT_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeFuConfigurationDO getKeFuConfiguration(Long id) {
|
||||
return keFuConfigurationMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<KeFuConfigurationDO> getKeFuConfigurationPage(KeFuConfigurationPageReqVO pageReqVO) {
|
||||
return keFuConfigurationMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
@ -26,8 +27,10 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
@ -95,6 +98,7 @@ public class KeFuMessageServiceImpl implements KeFuMessageService {
|
||||
|
||||
getSelf().sendAsyncMessageToMembers(conversation.getKefuId(), KEFU_MESSAGE_TYPE, kefuMessage);
|
||||
|
||||
|
||||
// 3. 通知所有管理员更新对话
|
||||
getSelf().sendAsyncMessageToAdmins(KEFU_MESSAGE_TYPE, kefuMessage);
|
||||
return kefuMessage.getId();
|
||||
@ -165,7 +169,7 @@ public class KeFuMessageServiceImpl implements KeFuMessageService {
|
||||
|
||||
@Async
|
||||
public void sendAsyncMessageToMembers(Long userId, String messageType, Object content) {
|
||||
webSocketSenderApi.sendObject(UserTypeEnum.MEMBER.getValue(), userId, messageType, content);
|
||||
webSocketSenderApi.sendObject("",userId, UserTypeEnum.ADMIN.getValue(), messageType, content);
|
||||
}
|
||||
|
||||
@Async
|
||||
|
@ -225,9 +225,12 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
||||
//获取用户头像和昵称
|
||||
PayWalletDO payWalletDO = payWalletMapper.selectById(payWalletRechargeDO.getWalletId());
|
||||
MemberUserRespDTO user = memberUserApi.getUser(payWalletDO.getUserId());
|
||||
|
||||
payWalletRechargeDO.setName(user.getNickname());
|
||||
payWalletRechargeDO.setAvatar(user.getAvatar());
|
||||
if(user.getLevelId() != null){
|
||||
payWalletRechargeDO.setName(user.getNickname());
|
||||
}
|
||||
if (user.getAvatar() != null) {
|
||||
payWalletRechargeDO.setAvatar(user.getAvatar());
|
||||
}
|
||||
|
||||
}
|
||||
return payWalletRechargeDOPageResult;
|
||||
|
Loading…
Reference in New Issue
Block a user