Compare commits
3 Commits
8d77b9855c
...
912e23ad44
Author | SHA1 | Date | |
---|---|---|---|
912e23ad44 | |||
5d5dadf0d5 | |||
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>
|
<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="flex-container">
|
||||||
<!-- 菜单区域 -->
|
<!-- 菜单区域 -->
|
||||||
<div class="menu-area">
|
<div class="menu-area">
|
||||||
|
|
||||||
<el-button type="primary" plain @click="createType" style="width: 90;font-size: 12px;">
|
<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-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 :index="targetMenuId" :key="targetMenuId" @click="clickMenu(targetMenuId)">
|
||||||
全部类型
|
全部类型
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
@ -18,10 +19,10 @@
|
|||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
<el-icon style="margin-left: 60px;width: 10px;" @mouseover="showActions = item.value"
|
<el-icon style="margin-left: 60px;width: 10px;" @mouseover="showActions = item.value"
|
||||||
@mouseleave="showActions = null">
|
@mouseleave="showActions = null">
|
||||||
<MoreFilled />
|
<MoreFilled/>
|
||||||
<div v-if="showActions === item.value" class="action-buttons">
|
<div v-if="showActions === item.value" class="action-buttons">
|
||||||
<el-button size="small" @click.stop="editItem(item.id,item.label)">编辑</el-button>
|
<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>
|
<el-button size="small" @click.stop="deleteItem(item.id)">删除</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -32,98 +33,123 @@
|
|||||||
|
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<div class="content-wrap">
|
<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-form-item label="文件类型" prop="type" width="80">
|
||||||
<el-input v-model="queryParams.type" placeholder="请输入文件类型" clearable
|
<el-input v-model="queryParams.type" placeholder="请输入文件类型" clearable
|
||||||
@keyup.enter="handleQuery" />
|
@keyup.enter="handleQuery"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="创建时间" prop="createTime">
|
<!-- <el-form-item label="创建时间" prop="createTime">
|
||||||
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss"
|
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
|
type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
|
||||||
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" />
|
||||||
</el-form-item>
|
</el-form-item> -->
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click="handleQuery">
|
<el-button @click="handleQuery">
|
||||||
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
<Icon icon="ep:search" class="mr-5px"/>
|
||||||
|
搜索
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="resetQuery">
|
<el-button @click="resetQuery">
|
||||||
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
<Icon icon="ep:refresh" class="mr-5px"/>
|
||||||
|
重置
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" plain @click="openForm">
|
<el-button type="primary" plain @click="openForm">
|
||||||
<Icon icon="ep:upload" class="mr-5px" /> 上传文件
|
<Icon icon="ep:upload" class="mr-5px"/>
|
||||||
|
上传文件
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</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="liebiao" style="cursor: pointer;" class="mr-10px h-30px w-30px"
|
||||||
<span><img @click="tubiao" style="cursor: pointer;" class="mr-10px h-30px w-30px" src="@/assets/imgs/tubiao.png" /></span>
|
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>
|
</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>
|
||||||
|
|
||||||
|
|
||||||
|
<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"/>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<el-table-column label="上传时间" align="center" prop="createTime" width="180"
|
||||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
:formatter="dateFormatter"/>
|
||||||
@pagination="getList" />
|
<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>
|
||||||
</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">
|
<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-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>
|
||||||
<el-form-item label="显示排序" prop="sort">
|
<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-item>
|
||||||
|
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -136,7 +162,7 @@
|
|||||||
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
<Dialog v-model="dialogVisible" :title="dialogTitle">
|
||||||
<el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
|
<el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
|
||||||
<el-form-item label="数据标签" prop="label">
|
<el-form-item label="数据标签" prop="label">
|
||||||
<el-input v-model="updateLabel" placeholder="请输入数据标签" />
|
<el-input v-model="updateLabel" placeholder="请输入数据标签"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -149,18 +175,19 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
|
import {getIntDictOptions, DICT_TYPE} from '@/utils/dict'
|
||||||
import { fileSizeFormatter } from '@/utils'
|
import {fileSizeFormatter} from '@/utils'
|
||||||
import { Search, MoreFilled } from '@element-plus/icons-vue';
|
import {Search, MoreFilled} from '@element-plus/icons-vue';
|
||||||
import { dateFormatter } from '@/utils/formatTime'
|
import {dateFormatter} from '@/utils/formatTime'
|
||||||
// import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
// import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||||
import * as FileApi from '@/api/infra/file'
|
import * as FileApi from '@/api/infra/file'
|
||||||
import FileForm from './FileForm.vue'
|
import FileForm from './FileForm.vue'
|
||||||
import UpdateForm from './updateForm.vue'
|
import UpdateForm from './updateForm.vue'
|
||||||
import * as DictDataApi from '@/api/system/dict/dict.data'
|
import * as DictDataApi from '@/api/system/dict/dict.data'
|
||||||
|
|
||||||
const typeMenu = ref<DictDataApi.DictDataVO[]>([]) //
|
const typeMenu = ref<DictDataApi.DictDataVO[]>([]) //
|
||||||
const targetMenuId = ref('0')
|
const targetMenuId = ref('0')
|
||||||
defineOptions({ name: 'InfraFile' })
|
defineOptions({name: 'InfraFile'})
|
||||||
const showActions = ref(null);
|
const showActions = ref(null);
|
||||||
const dialogVisible = ref(false) // 弹窗的是否展示
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
||||||
const dialogTitle = ref('') // 弹窗的标题
|
const dialogTitle = ref('') // 弹窗的标题
|
||||||
@ -181,12 +208,12 @@
|
|||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
|
label: [{required: true, message: '数据标签不能为空', trigger: 'blur'}],
|
||||||
sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }],
|
sort: [{required: true, message: '数据顺序不能为空', trigger: 'blur'}],
|
||||||
})
|
})
|
||||||
const updateLabel = ref('')
|
const updateLabel = ref('')
|
||||||
const message = useMessage() // 消息弹窗
|
const message = useMessage() // 消息弹窗
|
||||||
const { t } = useI18n() // 国际化
|
const {t} = useI18n() // 国际化
|
||||||
|
|
||||||
const loading = ref(true) // 列表的加载中
|
const loading = ref(true) // 列表的加载中
|
||||||
const total = ref(0) // 列表的总页数
|
const total = ref(0) // 列表的总页数
|
||||||
@ -203,7 +230,17 @@
|
|||||||
createTime: [],
|
createTime: [],
|
||||||
})
|
})
|
||||||
const queryFormRef = ref() // 搜索的表单
|
const queryFormRef = ref() // 搜索的表单
|
||||||
|
|
||||||
|
|
||||||
|
// const hoveredIndex = ref(null);
|
||||||
|
|
||||||
|
// const hover = (index: string, status: boolean) => {
|
||||||
|
// if (status) {
|
||||||
|
// hoveredIndex.value = index; // 鼠标悬停时显示按钮
|
||||||
|
// } else {
|
||||||
|
// hoveredIndex.value = ''; // 鼠标离开时隐藏按钮
|
||||||
|
// }
|
||||||
|
// }
|
||||||
/** 查询列表 */
|
/** 查询列表 */
|
||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@ -211,12 +248,13 @@
|
|||||||
const data = await FileApi.getFilePage(queryParams)
|
const data = await FileApi.getFilePage(queryParams)
|
||||||
list.value = data.list
|
list.value = data.list
|
||||||
tubiaoData.value = data.list
|
tubiaoData.value = data.list
|
||||||
console.log('111111',tubiaoData)
|
console.log('111111', tubiaoData)
|
||||||
total.value = data.total
|
total.value = data.total
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FileDataVO {
|
interface FileDataVO {
|
||||||
id: string
|
id: string
|
||||||
configId: string
|
configId: string
|
||||||
@ -289,7 +327,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//分类菜单修改按钮
|
//分类菜单修改按钮
|
||||||
const editItem = (id : number | undefined, lable : string) => {
|
const editItem = (id: number | undefined, lable: string) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
dialogTitle.value = '菜单编辑'
|
dialogTitle.value = '菜单编辑'
|
||||||
menuId.value = id
|
menuId.value = id
|
||||||
@ -298,7 +336,7 @@
|
|||||||
console.log('编辑:',);
|
console.log('编辑:',);
|
||||||
};
|
};
|
||||||
//分类菜单删除按钮
|
//分类菜单删除按钮
|
||||||
const deleteItem = async (id : number | undefined) => {
|
const deleteItem = async (id: number | undefined) => {
|
||||||
// 处理删除事件
|
// 处理删除事件
|
||||||
// 删除的二次确认
|
// 删除的二次确认
|
||||||
await message.delConfirm()
|
await message.delConfirm()
|
||||||
@ -315,7 +353,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
const clickMenu = (id : string) => {
|
const clickMenu = (id: string) => {
|
||||||
queryParams.picType = id
|
queryParams.picType = id
|
||||||
queryParams.pageNo = 1
|
queryParams.pageNo = 1
|
||||||
getList()
|
getList()
|
||||||
@ -341,14 +379,13 @@
|
|||||||
|
|
||||||
const forRef = ref()
|
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)
|
forRef.value.open(type, id, picType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 删除按钮操作 */
|
/** 删除按钮操作 */
|
||||||
const handleDelete = async (id : number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
// 删除的二次确认
|
// 删除的二次确认
|
||||||
await message.delConfirm()
|
await message.delConfirm()
|
||||||
@ -357,7 +394,8 @@
|
|||||||
message.success(t('common.delSuccess'))
|
message.success(t('common.delSuccess'))
|
||||||
// 刷新列表
|
// 刷新列表
|
||||||
await getList()
|
await getList()
|
||||||
} catch { }
|
} catch {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 初始化 **/
|
/** 初始化 **/
|
||||||
@ -378,7 +416,7 @@
|
|||||||
padding: 25px;
|
padding: 25px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
height: 1000px;
|
height: 700px;
|
||||||
/* 固定高度 */
|
/* 固定高度 */
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
/* 禁止滚动 */
|
/* 禁止滚动 */
|
||||||
@ -387,9 +425,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-wrap {
|
.content-wrap {
|
||||||
|
background-color: white;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
/* 使内容区域占据剩余空间 */
|
/* 使内容区域占据剩余空间 */
|
||||||
overflow-y: auto;
|
/* overflow-y: auto; */
|
||||||
/* 允许内容区域滚动 */
|
/* 允许内容区域滚动 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,23 +437,34 @@
|
|||||||
.image-container {
|
.image-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 10px; /* 设置图片之间的间距 */
|
gap: 10px; /* 设置图片之间的间距 */
|
||||||
justify-content: flex-start; /* 如果图片少于5张,会平均分布 */
|
justify-content: flex-start; /* 如果图片少于5张,会平均分布 */
|
||||||
max-width: 1000px; /* 设置外部容器的最大宽度 */
|
max-width: 1000px; /* 设置外部容器的最大宽度 */
|
||||||
margin: 0 auto; /* 居中显示 */
|
margin: 0 auto; /* 居中显示 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 每张图片占用的宽度,使每行显示5张 */
|
/* 每张图片占用的宽度,使每行显示5张 */
|
||||||
.image-item {
|
.image-item {
|
||||||
width: calc(20% - 8px); /* 宽度设为容器的20%,减去间距 */
|
width: calc(20% - 8px); /* 宽度设为容器的20%,减去间距 */
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 设置图片的最大宽度 */
|
/* 设置图片的最大宽度 */
|
||||||
.image-item img {
|
.image-item img {
|
||||||
width: 100%;
|
width: 80%;
|
||||||
height: auto;
|
height: 80%;
|
||||||
border-radius: 8px; /* 图片边缘圆角(可选) */
|
/* border-radius: 8px; /* 图片边缘圆角(可选) */
|
||||||
|
border: 3px solid #f3f3f3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-name {
|
||||||
|
margin-top: 5 px; /* 图片和名称之间的间距 */
|
||||||
|
font-size: 14px; /* 文字大小 */
|
||||||
|
color: #333; /* 文字颜色 */
|
||||||
|
word-wrap: break-word; /* 如果名称很长,自动换行 */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
@click="openForm('create')"
|
@click="openForm('create')"
|
||||||
v-hasPermi="['promotion:auto-response: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>
|
||||||
<!-- <el-button
|
<!-- <el-button
|
||||||
type="success"
|
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"
|
label-width="100px"
|
||||||
v-loading="formLoading"
|
v-loading="formLoading"
|
||||||
>
|
>
|
||||||
<el-form-item label="分类" prop="type">
|
<el-form-item label="话术分类" prop="type">
|
||||||
<el-select v-model="formData.type" placeholder="请选择分类">
|
<el-select v-model="formData.type" placeholder="请选择分类">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_VERBAL_TRICK_TYPE)"
|
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_VERBAL_TRICK_TYPE)"
|
||||||
@ -17,10 +17,10 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="标题" prop="title">
|
<el-form-item label="话术标题" prop="title">
|
||||||
<el-input v-model="formData.title" placeholder="请输入标题" />
|
<el-input v-model="formData.title" placeholder="请输入标题" />
|
||||||
</el-form-item>
|
</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-input v-model="formData.details" type="textarea" placeholder="请输入详情" :rows="6" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<el-button type="primary" plain @click="createType" style="width: 90;font-size: 12px;">
|
<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-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"
|
<el-menu-item v-for="item in huashuType" :index="item.value" :key="item.value"
|
||||||
@click="clickMenu(item.value)">{{item.label}}</el-menu-item>
|
@click="clickMenu(item.value)">{{item.label}}</el-menu-item>
|
||||||
</el-menu>
|
</el-menu>
|
||||||
@ -14,9 +14,7 @@
|
|||||||
|
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<div class="content-wrap">
|
<div class="content-wrap">
|
||||||
|
<div style="margin-top: 25px;margin-left:20px">
|
||||||
|
|
||||||
<ContentWrap>
|
|
||||||
<!-- 搜索工作栏 -->
|
<!-- 搜索工作栏 -->
|
||||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||||
<!-- <el-form-item label="分类" prop="type">
|
<!-- <el-form-item label="分类" prop="type">
|
||||||
@ -51,10 +49,12 @@
|
|||||||
</el-button> -->
|
</el-button> -->
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</ContentWrap>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<ContentWrap>
|
|
||||||
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
<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="ID" align="center" prop="id" />
|
||||||
<el-table-column label="分类" align="center" prop="type">
|
<el-table-column label="分类" align="center" prop="type">
|
||||||
@ -80,7 +80,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
</ContentWrap>
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
|
||||||
@pagination="getList" />
|
@pagination="getList" />
|
||||||
@ -281,7 +281,7 @@
|
|||||||
padding: 25px;
|
padding: 25px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
height: 1000px;
|
height: 700px;
|
||||||
/* 固定高度 */
|
/* 固定高度 */
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
/* 禁止滚动 */
|
/* 禁止滚动 */
|
||||||
@ -293,6 +293,7 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
/* 使内容区域占据剩余空间 */
|
/* 使内容区域占据剩余空间 */
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
background-color: #ffffff;
|
||||||
/* 允许内容区域滚动 */
|
/* 允许内容区域滚动 */
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -76,7 +76,8 @@ public class SecurityFrameworkUtils {
|
|||||||
if (authentication == null) {
|
if (authentication == null) {
|
||||||
return 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
|
@Override
|
||||||
public void send(String sessionId, String messageType, String messageContent) {
|
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, 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) {
|
default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) {
|
||||||
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
||||||
}
|
}
|
||||||
@ -49,4 +54,8 @@ public interface WebSocketMessageSender {
|
|||||||
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
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;
|
package cn.iocoder.yudao.framework.websocket.core.sender.redis;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mq.redis.core.RedisMQTemplate;
|
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.AbstractWebSocketMessageSender;
|
||||||
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
|
||||||
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
|
import cn.iocoder.yudao.framework.websocket.core.session.WebSocketSessionManager;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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} 实现类
|
* 基于 Redis 的 {@link WebSocketMessageSender} 实现类
|
||||||
@ -16,6 +22,10 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
|||||||
|
|
||||||
private final RedisMQTemplate redisMQTemplate;
|
private final RedisMQTemplate redisMQTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WebSocketSessionManager webSocketSessionManager;
|
||||||
|
|
||||||
|
|
||||||
public RedisWebSocketMessageSender(WebSocketSessionManager sessionManager,
|
public RedisWebSocketMessageSender(WebSocketSessionManager sessionManager,
|
||||||
RedisMQTemplate redisMQTemplate) {
|
RedisMQTemplate redisMQTemplate) {
|
||||||
super(sessionManager);
|
super(sessionManager);
|
||||||
@ -27,6 +37,7 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
|||||||
sendRedisMessage(null, userId, userType, messageType, messageContent);
|
sendRedisMessage(null, userId, userType, messageType, messageContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//用户发
|
||||||
@Override
|
@Override
|
||||||
public void send(Integer userType, String messageType, String messageContent) {
|
public void send(Integer userType, String messageType, String messageContent) {
|
||||||
sendRedisMessage(null, null, userType, messageType, messageContent);
|
sendRedisMessage(null, null, userType, messageType, messageContent);
|
||||||
@ -37,6 +48,11 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
|||||||
sendRedisMessage(sessionId, null, null, messageType, messageContent);
|
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 广播消息
|
* 通过 Redis 广播消息
|
||||||
*
|
*
|
||||||
@ -48,6 +64,25 @@ public class RedisWebSocketMessageSender extends AbstractWebSocketMessageSender
|
|||||||
*/
|
*/
|
||||||
private void sendRedisMessage(String sessionId, Long userId, Integer userType,
|
private void sendRedisMessage(String sessionId, Long userId, Integer userType,
|
||||||
String messageType, String messageContent) {
|
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()
|
RedisWebSocketMessage mqMessage = new RedisWebSocketMessage()
|
||||||
.setSessionId(sessionId).setUserId(userId).setUserType(userType)
|
.setSessionId(sessionId).setUserId(userId).setUserType(userType)
|
||||||
.setMessageType(messageType).setMessageContent(messageContent);
|
.setMessageType(messageType).setMessageContent(messageContent);
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.websocket.core.session;
|
|||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link WebSocketSession} 管理器的接口
|
* {@link WebSocketSession} 管理器的接口
|
||||||
@ -18,6 +19,7 @@ public interface WebSocketSessionManager {
|
|||||||
*/
|
*/
|
||||||
void addSession(WebSocketSession session);
|
void addSession(WebSocketSession session);
|
||||||
|
|
||||||
|
ConcurrentMap<String, WebSocketSession> idSessions();
|
||||||
/**
|
/**
|
||||||
* 移除 Session
|
* 移除 Session
|
||||||
*
|
*
|
||||||
@ -25,6 +27,8 @@ public interface WebSocketSessionManager {
|
|||||||
*/
|
*/
|
||||||
void removeSession(WebSocketSession session);
|
void removeSession(WebSocketSession session);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得指定编号的 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.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||||
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
import cn.iocoder.yudao.framework.websocket.core.util.WebSocketFrameworkUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.socket.WebSocketSession;
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import javax.servlet.http.HttpSession;
|
||||||
import java.util.Collection;
|
import java.net.URI;
|
||||||
import java.util.LinkedList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
@ -19,6 +19,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
|
@Service
|
||||||
public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,6 +29,8 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
|||||||
*/
|
*/
|
||||||
private final ConcurrentMap<String, WebSocketSession> idSessions = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, WebSocketSession> idSessions = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private HttpSession httpSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user 与 WebSocketSession 映射
|
* user 与 WebSocketSession 映射
|
||||||
*
|
*
|
||||||
@ -39,6 +42,7 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSession(WebSocketSession session) {
|
public void addSession(WebSocketSession session) {
|
||||||
|
|
||||||
// 添加到 idSessions 中
|
// 添加到 idSessions 中
|
||||||
idSessions.put(session.getId(), session);
|
idSessions.put(session.getId(), session);
|
||||||
// 添加到 userSessions 中
|
// 添加到 userSessions 中
|
||||||
@ -60,7 +64,18 @@ public class WebSocketSessionManagerImpl implements WebSocketSessionManager {
|
|||||||
sessions = userSessionsMap.get(user.getId());
|
sessions = userSessionsMap.get(user.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
System.out.println("---------sessions---------: " + session);
|
||||||
sessions.add(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
|
@Override
|
||||||
|
@ -39,6 +39,9 @@ public interface WebSocketSenderApi {
|
|||||||
*/
|
*/
|
||||||
void send(String sessionId, String messageType, String messageContent);
|
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) {
|
default void sendObject(Integer userType, Long userId, String messageType, Object messageContent) {
|
||||||
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
send(userType, userId, messageType, JsonUtils.toJsonString(messageContent));
|
||||||
}
|
}
|
||||||
@ -51,4 +54,8 @@ public interface WebSocketSenderApi {
|
|||||||
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
send(sessionId, messageType, JsonUtils.toJsonString(messageContent));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default void sendObject(String sessionId, Long userId, Integer userType,String messageType, Object messageContent) {
|
||||||
|
send(sessionId,userId,userType, messageType, JsonUtils.toJsonString(messageContent));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,9 @@ public class WebSocketSenderApiImpl implements WebSocketSenderApi {
|
|||||||
webSocketMessageSender.send(sessionId, messageType, messageContent);
|
webSocketMessageSender.send(sessionId, messageType, messageContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(String sessionId, Long userId, Integer userType, String messageType, String messageContent) {
|
||||||
|
webSocketMessageSender.send(sessionId, userId,userType,messageType, messageContent);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ public interface ErrorCodeConstants {
|
|||||||
// ========== 兑换记录 TODO 补充编号 ==========
|
// ========== 兑换记录 TODO 补充编号 ==========
|
||||||
ErrorCode POINT_ORDER_NOT_EXISTS = new ErrorCode(11111, "兑换记录不存在");
|
ErrorCode POINT_ORDER_NOT_EXISTS = new ErrorCode(11111, "兑换记录不存在");
|
||||||
|
|
||||||
|
|
||||||
|
ErrorCode KE_FU_CONFIGURATION_NOT_EXISTS = new ErrorCode(22222222, "客服配置不存在");
|
||||||
// ========== Banner 相关 1-013-002-000 ============
|
// ========== Banner 相关 1-013-002-000 ============
|
||||||
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1_013_002_000, "Banner 不存在");
|
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)
|
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private LocalDateTime createTime;
|
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.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;
|
||||||
|
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.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 cn.iocoder.yudao.module.promotion.service.kefu.KeFuMessageService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
@ -33,9 +37,15 @@ public class AppKeFuMessageController {
|
|||||||
@Resource
|
@Resource
|
||||||
private KeFuMessageService kefuMessageService;
|
private KeFuMessageService kefuMessageService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
KeFuConversationMapper keFuConversationMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MemberUserApi memberUserApi;
|
private MemberUserApi memberUserApi;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SupportStaffMapper supportStaffMapper;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/send")
|
@PostMapping("/send")
|
||||||
@Operation(summary = "发送客服消息")
|
@Operation(summary = "发送客服消息")
|
||||||
@ -70,11 +80,16 @@ public class AppKeFuMessageController {
|
|||||||
String systemUserAvatar = kefuMessageService.findSystemUserAvatar(keFuMessageDO.getSenderId());
|
String systemUserAvatar = kefuMessageService.findSystemUserAvatar(keFuMessageDO.getSenderId());
|
||||||
keFuMessageDO.setSenderAvatar(systemUserAvatar);
|
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));
|
return success(BeanUtils.toBean(pageResult, KeFuMessageRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/test")
|
@PostMapping("/test")
|
||||||
@Operation(summary = "获得客服消息分页")
|
@Operation(summary = "获得客服消息分页")
|
||||||
@PreAuthenticated
|
@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)
|
@TableField(exist = false)
|
||||||
private String senderAvatar;
|
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.enums.UserTypeEnum;
|
||||||
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.module.infra.api.websocket.WebSocketSenderApi;
|
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.MemberUserApi;
|
||||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
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.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
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.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
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);
|
getSelf().sendAsyncMessageToMembers(conversation.getKefuId(), KEFU_MESSAGE_TYPE, kefuMessage);
|
||||||
|
|
||||||
|
|
||||||
// 3. 通知所有管理员更新对话
|
// 3. 通知所有管理员更新对话
|
||||||
getSelf().sendAsyncMessageToAdmins(KEFU_MESSAGE_TYPE, kefuMessage);
|
getSelf().sendAsyncMessageToAdmins(KEFU_MESSAGE_TYPE, kefuMessage);
|
||||||
return kefuMessage.getId();
|
return kefuMessage.getId();
|
||||||
@ -165,7 +169,7 @@ public class KeFuMessageServiceImpl implements KeFuMessageService {
|
|||||||
|
|
||||||
@Async
|
@Async
|
||||||
public void sendAsyncMessageToMembers(Long userId, String messageType, Object content) {
|
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
|
@Async
|
||||||
|
@ -225,9 +225,12 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
|||||||
//获取用户头像和昵称
|
//获取用户头像和昵称
|
||||||
PayWalletDO payWalletDO = payWalletMapper.selectById(payWalletRechargeDO.getWalletId());
|
PayWalletDO payWalletDO = payWalletMapper.selectById(payWalletRechargeDO.getWalletId());
|
||||||
MemberUserRespDTO user = memberUserApi.getUser(payWalletDO.getUserId());
|
MemberUserRespDTO user = memberUserApi.getUser(payWalletDO.getUserId());
|
||||||
|
if(user.getLevelId() != null){
|
||||||
payWalletRechargeDO.setName(user.getNickname());
|
payWalletRechargeDO.setName(user.getNickname());
|
||||||
payWalletRechargeDO.setAvatar(user.getAvatar());
|
}
|
||||||
|
if (user.getAvatar() != null) {
|
||||||
|
payWalletRechargeDO.setAvatar(user.getAvatar());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return payWalletRechargeDOPageResult;
|
return payWalletRechargeDOPageResult;
|
||||||
|
Loading…
Reference in New Issue
Block a user