Compare commits

..

No commits in common. "6d8c8b4b83cbb5e114bc5d494aaf1621acc2160b" and "eb477862fcee04560e962222472f443abac83bd7" have entirely different histories.

55 changed files with 625 additions and 3845 deletions

View File

@ -1,43 +0,0 @@
import request from '@/config/axios'
// 自动回复 VO
export interface AutoResponseVO {
id: number // id
keyword: string // 关键字
type: number // 回复类型,文字消息/0图片消息/1
content: string // 回复内容
status: number // 是否开启,开启/1关闭/0
}
// 自动回复 API
export const AutoResponseApi = {
// 查询自动回复分页
getAutoResponsePage: async (params: any) => {
return await request.get({ url: `/promotion/auto-response/page`, params })
},
// 查询自动回复详情
getAutoResponse: async (id: number) => {
return await request.get({ url: `/promotion/auto-response/get?id=` + id })
},
// 新增自动回复
createAutoResponse: async (data: AutoResponseVO) => {
return await request.post({ url: `/promotion/auto-response/create`, data })
},
// 修改自动回复
updateAutoResponse: async (data: AutoResponseVO) => {
return await request.put({ url: `/promotion/auto-response/update`, data })
},
// 删除自动回复
deleteAutoResponse: async (id: number) => {
return await request.delete({ url: `/promotion/auto-response/delete?id=` + id })
},
// 导出自动回复 Excel
exportAutoResponse: async (params) => {
return await request.download({ url: `/promotion/auto-response/export-excel`, params })
}
}

View File

@ -1,51 +0,0 @@
import request from '@/config/axios'
// 用户留言 VO
export interface LeaveWordVO {
id: number // id
name: string // 昵称
phone: string // 电话
content: string // 内容
response: string //回复内容
status: number // 状态
}
// 用户留言 API
export const LeaveWordApi = {
// 查询用户留言分页
getLeaveWordPage: async (params: any) => {
return await request.get({ url: `/promotion/leave-word/page`, params })
},
// 查询用户留言详情
getLeaveWord: async (id: number) => {
return await request.get({ url: `/promotion/leave-word/get?id=` + id })
},
// 新增用户留言
createLeaveWord: async (data: LeaveWordVO) => {
return await request.post({ url: `/promotion/leave-word/create`, data })
},
// 修改用户留言
updateLeaveWord: async (data: LeaveWordVO) => {
return await request.put({ url: `/promotion/leave-word/update`, data })
},
// 删除用户留言
deleteLeaveWord: async (id: number) => {
return await request.delete({ url: `/promotion/leave-word/delete?id=` + id })
},
// 导出用户留言 Excel
exportLeaveWord: async (params) => {
return await request.download({ url: `/promotion/leave-word/export-excel`, params })
},
// 添加回复内容
addResponse: async (id: number, content: string) => {
return await request.get({ url: `/promotion/leave-word/addResponse?id=` + id +`&&response=` + content })
},
}

View File

@ -1,47 +0,0 @@
import request from '@/config/axios'
// 客服人员 VO
export interface SupportStaffVO {
id: number // ID
name: string // 客服名称
pic: string //头像
phone: string // 手机号码
account: string // 登录账号
password: string // 登录密码
status: number // 客服状态
orderManage: number // 手机订单管理
orderInform: number // 订单通知
}
// 客服人员 API
export const SupportStaffApi = {
// 查询客服人员分页
getSupportStaffPage: async (params: any) => {
return await request.get({ url: `/promotion/support-staff/page`, params })
},
// 查询客服人员详情
getSupportStaff: async (id: number) => {
return await request.get({ url: `/promotion/support-staff/get?id=` + id })
},
// 新增客服人员
createSupportStaff: async (data: SupportStaffVO) => {
return await request.post({ url: `/promotion/support-staff/create`, data })
},
// 修改客服人员
updateSupportStaff: async (data: SupportStaffVO) => {
return await request.put({ url: `/promotion/support-staff/update`, data })
},
// 删除客服人员
deleteSupportStaff: async (id: number) => {
return await request.delete({ url: `/promotion/support-staff/delete?id=` + id })
},
// 导出客服人员 Excel
exportSupportStaff: async (params) => {
return await request.download({ url: `/promotion/support-staff/export-excel`, params })
}
}

View File

@ -1,47 +0,0 @@
import request from '@/config/axios'
// 客服话术 VO
export interface VerbalTrickVO {
id: number // id
type: number // 分类
title: string // 标题
details: string // 详情
}
// 客服话术 API
export const VerbalTrickApi = {
// 查询客服话术分页
getVerbalTrickPage: async (params: any) => {
return await request.get({ url: `/promotion/verbal-trick/page`, params })
},
// 查询客服话术详情
getVerbalTrick: async (id: number) => {
return await request.get({ url: `/promotion/verbal-trick/get?id=` + id })
},
// 新增客服话术
createVerbalTrick: async (data: VerbalTrickVO) => {
return await request.post({ url: `/promotion/verbal-trick/create`, data })
},
// 修改客服话术
updateVerbalTrick: async (data: VerbalTrickVO) => {
return await request.put({ url: `/promotion/verbal-trick/update`, data })
},
// 删除客服话术
deleteVerbalTrick: async (id: number) => {
return await request.delete({ url: `/promotion/verbal-trick/delete?id=` + id })
},
// 导出客服话术 Excel
exportVerbalTrick: async (params) => {
return await request.download({ url: `/promotion/verbal-trick/export-excel`, params })
},
// 查询客服话术
getVerbalTrickList: async () => {
return await request.get({ url: `/promotion/verbal-trick/getVerbalTrickList` })
}
}

View File

@ -138,21 +138,6 @@ export enum DICT_TYPE {
//预约:机构管理
ORGANIZATION_STATUS = 'organization_status',
//客服:自动回复
KEFU_AUTO_RESPONSE_TYPE = 'kefu_auto_response_type',
KEFU_AUTO_RESPONSE_STATUS = 'kefu_auto_response_status',
//客服:留言
KEFU_LEAVE_WORD_STATUS = 'kefu_leave_word_status',
//客服:话术
KEFU_VERBAL_TRICK_TYPE = 'kefu_verbal_trick_type',
//客服人员管理
KEFU_SUPPORT_STAFF_STATUS = 'kefu_support_staff_status',
KEFU_SUPPORT_STAFF_ORDER_MANAGE = 'kefu_support_staff_order_manage',
KEFU_SUPPORT_STAFF_ORDER_INFORM = 'kefu_support_staff_order_inform',
// ========== SYSTEM 模块 ==========
SYSTEM_USER_SEX = 'system_user_sex',

View File

@ -1,125 +0,0 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="关键字" prop="keyword">
<el-input v-model="formData.keyword" placeholder="请输入关键字" />
</el-form-item>
<el-form-item label="回复类型" prop="type">
<el-select v-model="formData.type" placeholder="请选择回复类型">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_AUTO_RESPONSE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="回复内容" prop="content">
<el-input v-model="formData.content" type="textarea" placeholder="请输入回复内容" />
</el-form-item>
<el-form-item label="是否开启" prop="status">
<el-select v-model="formData.status" placeholder="请选择是否开启">
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_AUTO_RESPONSE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { AutoResponseApi, AutoResponseVO } from '@/api/mall/promotion/autoresponse'
/** 自动回复 表单 */
defineOptions({ name: 'AutoResponseForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
keyword: undefined,
type: undefined,
content: undefined,
status: undefined
})
const formRules = reactive({
keyword: [{ required: true, message: '关键字不能为空', trigger: 'blur' }],
type: [{ required: true, message: '回复类型不能为空', trigger: 'change' }],
content: [{ required: true, message: '回复内容不能为空', trigger: 'blur' }],
status: [{ required: true, message: '是否开启不能为空', trigger: 'change' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await AutoResponseApi.getAutoResponse(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as AutoResponseVO
if (formType.value === 'create') {
await AutoResponseApi.createAutoResponse(data)
message.success(t('common.createSuccess'))
} else {
await AutoResponseApi.updateAutoResponse(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
keyword: undefined,
type: undefined,
content: undefined,
status: undefined
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,232 +0,0 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="关键字" prop="keyword">
<el-input
v-model="queryParams.keyword"
placeholder="请输入关键字"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="回复类型" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择回复类型"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_AUTO_RESPONSE_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="是否开启" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择是否开启"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_AUTO_RESPONSE_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['promotion:auto-response:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['promotion:auto-response:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<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="keyword" />
<el-table-column label="回复类型" align="center" prop="type">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_AUTO_RESPONSE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="回复内容" align="center" prop="content" />
<el-table-column label="是否开启" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_AUTO_RESPONSE_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['promotion:auto-response:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['promotion:auto-response:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<AutoResponseForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { AutoResponseApi, AutoResponseVO } from '@/api/mall/promotion/autoresponse'
import AutoResponseForm from './AutoResponseForm.vue'
/** 自动回复 列表 */
defineOptions({ name: 'AutoResponse' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<AutoResponseVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
keyword: undefined,
type: undefined,
content: undefined,
status: undefined,
createTime: []
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await AutoResponseApi.getAutoResponsePage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await AutoResponseApi.deleteAutoResponse(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await AutoResponseApi.exportAutoResponse(queryParams)
download.excel(data, '自动回复.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,488 +1,467 @@
<template>
<el-container v-if="showKeFuMessageList" class="kefu">
<el-header>
<div class="kefu-title">{{ conversation.userNickname }}</div>
</el-header>
<el-main class="kefu-content overflow-visible">
<el-scrollbar ref="scrollbarRef" always height="calc(100vh - 495px)" @scroll="handleScroll">
<div v-if="refreshContent" ref="innerRef" class="w-[100%] pb-3px">
<!-- 消息列表 -->
<div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]">
<div class="flex justify-center items-center mb-20px">
<!-- 日期 -->
<div v-if="
<el-container v-if="showKeFuMessageList" class="kefu">
<el-header>
<div class="kefu-title">{{ conversation.userNickname }}</div>
</el-header>
<el-main class="kefu-content overflow-visible">
<el-scrollbar ref="scrollbarRef" always height="calc(100vh - 495px)" @scroll="handleScroll">
<div v-if="refreshContent" ref="innerRef" class="w-[100%] pb-3px">
<!-- 消息列表 -->
<div v-for="(item, index) in getMessageList0" :key="item.id" class="w-[100%]">
<div class="flex justify-center items-center mb-20px">
<!-- 日期 -->
<div
v-if="
item.contentType !== KeFuMessageContentTypeEnum.SYSTEM && showTime(item, index)
" class="date-message">
{{ formatDate(item.createTime) }}
</div>
<!-- 系统消息 -->
<div v-if="item.contentType === KeFuMessageContentTypeEnum.SYSTEM" class="system-message">
{{ item.content }}
</div>
</div>
<div :class="[
"
class="date-message"
>
{{ formatDate(item.createTime) }}
</div>
<!-- 系统消息 -->
<div
v-if="item.contentType === KeFuMessageContentTypeEnum.SYSTEM"
class="system-message"
>
{{ item.content }}
</div>
</div>
<div
:class="[
item.senderType === UserTypeEnum.MEMBER
? `ss-row-left`
: item.senderType === UserTypeEnum.ADMIN
? `ss-row-right`
: ''
]" class="flex mb-20px w-[100%]">
<el-avatar v-if="item.senderType === UserTypeEnum.MEMBER" :src="conversation.userAvatar"
alt="avatar" class="w-60px h-60px" />
<div :class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
class="p-10px">
<!-- 文本消息 -->
<MessageItem :message="item">
<template v-if="KeFuMessageContentTypeEnum.TEXT === item.contentType">
<div v-dompurify-html="replaceEmoji(item.content)" class="flex items-center">
</div>
</template>
</MessageItem>
<!-- 图片消息 -->
<MessageItem :message="item">
<el-image v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
:initial-index="0" :preview-src-list="[item.content]" :src="item.content"
class="w-200px" fit="contain" preview-teleported />
</MessageItem>
<!-- 商品消息 -->
<MessageItem :message="item">
<ProductItem v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
:spuId="getMessageContent(item).spuId" :picUrl="getMessageContent(item).picUrl"
:price="getMessageContent(item).price"
:skuText="getMessageContent(item).introduction"
:title="getMessageContent(item).spuName" :titleWidth="400" class="max-w-70%"
priceColor="#FF3000" />
</MessageItem>
<!-- 订单消息 -->
<MessageItem :message="item">
<OrderItem v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
:message="item" class="max-w-100%" />
</MessageItem>
</div>
<el-avatar v-if="item.senderType === UserTypeEnum.ADMIN" :src="item.senderAvatar"
alt="avatar" />
</div>
</div>
</div>
</el-scrollbar>
<div v-show="showNewMessageTip" class="newMessageTip flex items-center cursor-pointer"
@click="handleToNewMessage">
<span>有新消息</span>
<Icon class="ml-5px" icon="ep:bottom" />
</div>
</el-main>
<el-footer height="230px">
<div class="h-[100%]">
<div class="chat-tools flex items-center">
<EmojiSelectPopover @select-emoji="handleEmojiSelect" />
<PictureSelectUpload class="ml-15px mt-3px cursor-pointer" @send-picture="handleSendPicture" />
<!-- <VerbalTrick class="ml-11px mt-5px cursor-pointer" /> -->
<!-- 话术库 -->
<div style="margin-left: 9px; margin-top:5px;cursor: pointer;">
<img :src="Picture" class="w-32px h-32px" @click="huashu" />
</div>
</div>
<el-input v-model="message" :rows="6" style="border-style: none" type="textarea" />
<div class="h-45px flex justify-end">
<el-button class="mt-10px" type="primary" @click="handleSendMessage">发送</el-button>
</div>
</div>
</el-footer>
</el-container>
<el-empty v-else description="请选择左侧的一个会话后开始" />
<Dialog :title="dialogTitle" v-model="dialogVisible" :modal="false" width="700px">
<div style="display: flex; width: 100%; height: 400px;">
<!-- 左边占 30% -->
<div style="flex: 0 0 20%; background-color: #f0f0f0; padding: 10px;">
左边的内容
</div>
<!-- 右边占 70% -->
<div style="flex: 1; padding: 5px; overflow-y: auto; max-height: 400px;">
<p v-for="item in verbalTrickList" :key="item.id" style="font-size: 12px;cursor: pointer;transition: background-color 0.3s;" class="hover-shadow" @click="huashuClick(item.details)">
{{item.details}}
</p>
</div>
</div>
</Dialog>
]"
class="flex mb-20px w-[100%]"
>
<el-avatar
v-if="item.senderType === UserTypeEnum.MEMBER"
:src="conversation.userAvatar"
alt="avatar"
class="w-60px h-60px"
/>
<div
:class="{ 'kefu-message': KeFuMessageContentTypeEnum.TEXT === item.contentType }"
class="p-10px"
>
<!-- 文本消息 -->
<MessageItem :message="item">
<template v-if="KeFuMessageContentTypeEnum.TEXT === item.contentType">
<div
v-dompurify-html="replaceEmoji(item.content)"
class="flex items-center"
></div>
</template>
</MessageItem>
<!-- 图片消息 -->
<MessageItem :message="item">
<el-image
v-if="KeFuMessageContentTypeEnum.IMAGE === item.contentType"
:initial-index="0"
:preview-src-list="[item.content]"
:src="item.content"
class="w-200px"
fit="contain"
preview-teleported
/>
</MessageItem>
<!-- 商品消息 -->
<MessageItem :message="item">
<ProductItem
v-if="KeFuMessageContentTypeEnum.PRODUCT === item.contentType"
:spuId="getMessageContent(item).spuId"
:picUrl="getMessageContent(item).picUrl"
:price="getMessageContent(item).price"
:skuText="getMessageContent(item).introduction"
:title="getMessageContent(item).spuName"
:titleWidth="400"
class="max-w-70%"
priceColor="#FF3000"
/>
</MessageItem>
<!-- 订单消息 -->
<MessageItem :message="item">
<OrderItem
v-if="KeFuMessageContentTypeEnum.ORDER === item.contentType"
:message="item"
class="max-w-100%"
/>
</MessageItem>
</div>
<el-avatar
v-if="item.senderType === UserTypeEnum.ADMIN"
:src="item.senderAvatar"
alt="avatar"
/>
</div>
</div>
</div>
</el-scrollbar>
<div
v-show="showNewMessageTip"
class="newMessageTip flex items-center cursor-pointer"
@click="handleToNewMessage"
>
<span>有新消息</span>
<Icon class="ml-5px" icon="ep:bottom" />
</div>
</el-main>
<el-footer height="230px">
<div class="h-[100%]">
<div class="chat-tools flex items-center">
<EmojiSelectPopover @select-emoji="handleEmojiSelect" />
<PictureSelectUpload
class="ml-15px mt-3px cursor-pointer"
@send-picture="handleSendPicture"
/>
</div>
<el-input v-model="message" :rows="6" style="border-style: none" type="textarea" />
<div class="h-45px flex justify-end">
<el-button class="mt-10px" type="primary" @click="handleSendMessage">发送</el-button>
</div>
</div>
</el-footer>
</el-container>
<el-empty v-else description="请选择左侧的一个会话后开始" />
</template>
<script lang="ts" setup>
import { ElScrollbar as ElScrollbarType } from 'element-plus'
import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message'
import { VerbalTrickApi, VerbalTrickVO } from '@/api/mall/promotion/verbaltrick'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
import EmojiSelectPopover from './tools/EmojiSelectPopover.vue'
import PictureSelectUpload from './tools/PictureSelectUpload.vue'
// import VerbalTrick from './tools/VerbalTrick.vue'
import Picture from '@/views/mall/promotion/kefu/components/asserts/huashu.png'
import ProductItem from './message/ProductItem.vue'
import OrderItem from './message/OrderItem.vue'
import { Emoji, useEmoji } from './tools/emoji'
import { KeFuMessageContentTypeEnum } from './tools/constants'
import { isEmpty } from '@/utils/is'
import { UserTypeEnum } from '@/utils/constants'
import { formatDate } from '@/utils/formatTime'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { debounce } from 'lodash-es'
import { jsonParse } from '@/utils'
import { ElScrollbar as ElScrollbarType } from 'element-plus'
import { KeFuMessageApi, KeFuMessageRespVO } from '@/api/mall/promotion/kefu/message'
import { KeFuConversationRespVO } from '@/api/mall/promotion/kefu/conversation'
import EmojiSelectPopover from './tools/EmojiSelectPopover.vue'
import PictureSelectUpload from './tools/PictureSelectUpload.vue'
import ProductItem from './message/ProductItem.vue'
import OrderItem from './message/OrderItem.vue'
import { Emoji, useEmoji } from './tools/emoji'
import { KeFuMessageContentTypeEnum } from './tools/constants'
import { isEmpty } from '@/utils/is'
import { UserTypeEnum } from '@/utils/constants'
import { formatDate } from '@/utils/formatTime'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { debounce } from 'lodash-es'
import { jsonParse } from '@/utils'
dayjs.extend(relativeTime)
dayjs.extend(relativeTime)
defineOptions({ name: 'KeFuMessageList' })
defineOptions({ name: 'KeFuMessageList' })
let dialogVisible = ref(false) //
const dialogTitle = ref('客服话术') //
//
const verbalTrickList = ref<VerbalTrickVO[]>([])
const message = ref('') //
const { replaceEmoji } = useEmoji()
const messageTool = useMessage()
const messageList = ref<KeFuMessageRespVO[]>([]) //
const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) //
const showNewMessageTip = ref(false) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
conversationId: 0
})
const total = ref(0) //
const refreshContent = ref(false) // ,
const message = ref('') //
const { replaceEmoji } = useEmoji()
const messageTool = useMessage()
const messageList = ref<KeFuMessageRespVO[]>([]) //
const conversation = ref<KeFuConversationRespVO>({} as KeFuConversationRespVO) //
const showNewMessageTip = ref(false) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
conversationId: 0
})
const total = ref(0) //
const refreshContent = ref(false) // ,
/** 获悉消息内容 */
const getMessageContent = computed(() => (item : any) => jsonParse(item.content))
/** 获得消息列表 */
const getMessageList = async () => {
const res = await KeFuMessageApi.getKeFuMessagePage(queryParams)
total.value = res.total
//
if (queryParams.pageNo === 1) {
messageList.value = res.list
} else {
//
for (const item of res.list) {
pushMessage(item)
}
}
refreshContent.value = true
}
/** 获悉消息内容 */
const getMessageContent = computed(() => (item: any) => jsonParse(item.content))
/** 获得消息列表 */
const getMessageList = async () => {
const res = await KeFuMessageApi.getKeFuMessagePage(queryParams)
total.value = res.total
//
if (queryParams.pageNo === 1) {
messageList.value = res.list
} else {
//
for (const item of res.list) {
pushMessage(item)
}
}
refreshContent.value = true
}
/** 添加消息 */
const pushMessage = (message : any) => {
if (messageList.value.some((val) => val.id === message.id)) {
return
}
messageList.value.push(message)
}
/** 添加消息 */
const pushMessage = (message: any) => {
if (messageList.value.some((val) => val.id === message.id)) {
return
}
messageList.value.push(message)
}
/** 按照时间倒序,获取消息列表 */
const getMessageList0 = computed(() => {
messageList.value.sort((a : any, b : any) => a.createTime - b.createTime)
return messageList.value
})
/** 按照时间倒序,获取消息列表 */
const getMessageList0 = computed(() => {
messageList.value.sort((a: any, b: any) => a.createTime - b.createTime)
return messageList.value
})
/** 刷新消息列表 */
const refreshMessageList = async (message ?: any) => {
if (!conversation.value) {
return
}
/** 刷新消息列表 */
const refreshMessageList = async (message?: any) => {
if (!conversation.value) {
return
}
if (typeof message !== 'undefined') {
//
if (message.conversationId !== conversation.value.id) {
return
}
pushMessage(message)
} else {
// TODO @puhui999 page createTime
queryParams.pageNo = 1
await getMessageList()
}
if (typeof message !== 'undefined') {
//
if (message.conversationId !== conversation.value.id) {
return
}
pushMessage(message)
} else {
// TODO @puhui999 page createTime
queryParams.pageNo = 1
await getMessageList()
}
if (loadHistory.value) {
//
showNewMessageTip.value = true
} else {
//
await handleToNewMessage()
}
}
if (loadHistory.value) {
//
showNewMessageTip.value = true
} else {
//
await handleToNewMessage()
}
}
/** 获得新会话的消息列表 */
// TODO @puhui999 list merge
const getNewMessageList = async (val : KeFuConversationRespVO) => {
// ,
queryParams.pageNo = 1
messageList.value = []
total.value = 0
loadHistory.value = false
refreshContent.value = false
//
conversation.value = val
queryParams.conversationId = val.id
//
await refreshMessageList()
}
defineExpose({ getNewMessageList, refreshMessageList })
/** 获得新会话的消息列表 */
// TODO @puhui999 list merge
const getNewMessageList = async (val: KeFuConversationRespVO) => {
// ,
queryParams.pageNo = 1
messageList.value = []
total.value = 0
loadHistory.value = false
refreshContent.value = false
//
conversation.value = val
queryParams.conversationId = val.id
//
await refreshMessageList()
}
defineExpose({ getNewMessageList, refreshMessageList })
const showKeFuMessageList = computed(() => !isEmpty(conversation.value)) //
const skipGetMessageList = computed(() => {
//
return total.value > 0 && Math.ceil(total.value / queryParams.pageSize) === queryParams.pageNo
}) //
const showKeFuMessageList = computed(() => !isEmpty(conversation.value)) //
const skipGetMessageList = computed(() => {
//
return total.value > 0 && Math.ceil(total.value / queryParams.pageSize) === queryParams.pageNo
}) //
/** 处理表情选择 */
const handleEmojiSelect = (item : Emoji) => {
message.value += item.name
}
/** 处理表情选择 */
const handleEmojiSelect = (item: Emoji) => {
message.value += item.name
}
/** 处理图片发送 */
const handleSendPicture = async (picUrl : string) => {
//
const msg = {
conversationId: conversation.value.id,
contentType: KeFuMessageContentTypeEnum.IMAGE,
content: picUrl
}
await sendMessage(msg)
}
/** 处理图片发送 */
const handleSendPicture = async (picUrl: string) => {
//
const msg = {
conversationId: conversation.value.id,
contentType: KeFuMessageContentTypeEnum.IMAGE,
content: picUrl
}
await sendMessage(msg)
}
/*点击话术库*/
const huashu = async () => {
dialogVisible.value = true;
}
const getVerbalTrickList = async () => {
const response = await VerbalTrickApi.getVerbalTrickList();
verbalTrickList.value = response; // verbalTrickList
}
/*选择话术库内容*/
const huashuClick = (content: string) => {
message.value = content;
dialogVisible.value = false;
}
/** 发送文本消息 */
const handleSendMessage = async () => {
// 1.
if (isEmpty(unref(message.value))) {
messageTool.notifyWarning('请输入消息后再发送哦!')
return
}
// 2.
const msg = {
conversationId: conversation.value.id,
contentType: KeFuMessageContentTypeEnum.TEXT,
content: message.value
}
await sendMessage(msg)
}
/** 发送文本消息 */
const handleSendMessage = async () => {
// 1.
if (isEmpty(unref(message.value))) {
messageTool.notifyWarning('请输入消息后再发送哦!')
return
}
// 2.
const msg = {
conversationId: conversation.value.id,
contentType: KeFuMessageContentTypeEnum.TEXT,
content: message.value
}
await sendMessage(msg)
}
/** 真正发送消息 【共用】*/
const sendMessage = async (msg: any) => {
//
await KeFuMessageApi.sendKeFuMessage(msg)
message.value = ''
//
await refreshMessageList()
}
/** 真正发送消息 【共用】*/
const sendMessage = async (msg : any) => {
//
await KeFuMessageApi.sendKeFuMessage(msg)
message.value = ''
//
await refreshMessageList()
}
/** 滚动到底部 */
const innerRef = ref<HTMLDivElement>()
const scrollbarRef = ref<InstanceType<typeof ElScrollbarType>>()
const scrollToBottom = async () => {
// 1.
if (loadHistory.value) {
return
}
// 2.1
await nextTick()
scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight)
showNewMessageTip.value = false
// 2.2
await KeFuMessageApi.updateKeFuMessageReadStatus(conversation.value.id)
}
/** 滚动到底部 */
const innerRef = ref<HTMLDivElement>()
const scrollbarRef = ref<InstanceType<typeof ElScrollbarType>>()
const scrollToBottom = async () => {
// 1.
if (loadHistory.value) {
return
}
// 2.1
await nextTick()
scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight)
showNewMessageTip.value = false
// 2.2
await KeFuMessageApi.updateKeFuMessageReadStatus(conversation.value.id)
}
/** 查看新消息 */
const handleToNewMessage = async () => {
loadHistory.value = false
await scrollToBottom()
}
/** 查看新消息 */
const handleToNewMessage = async () => {
loadHistory.value = false
await scrollToBottom()
}
const loadHistory = ref(false) //
/** 处理消息列表滚动事件(debounce 限流) */
const handleScroll = debounce(({ scrollTop }) => {
if (skipGetMessageList.value) {
return
}
//
if (Math.floor(scrollTop) === 0) {
handleOldMessage()
}
const wrap = scrollbarRef.value?.wrapRef
//
if (Math.abs(wrap!.scrollHeight - wrap!.clientHeight - wrap!.scrollTop) < 1) {
loadHistory.value = false
refreshMessageList()
}
}, 200)
/** 加载历史消息 */
const handleOldMessage = async () => {
//
const oldPageHeight = innerRef.value?.clientHeight
if (!oldPageHeight) {
return
}
loadHistory.value = true
//
queryParams.pageNo += 1
await getMessageList()
//
scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight - oldPageHeight)
}
const loadHistory = ref(false) //
/** 处理消息列表滚动事件(debounce 限流) */
const handleScroll = debounce(({ scrollTop }) => {
if (skipGetMessageList.value) {
return
}
//
if (Math.floor(scrollTop) === 0) {
handleOldMessage()
}
const wrap = scrollbarRef.value?.wrapRef
//
if (Math.abs(wrap!.scrollHeight - wrap!.clientHeight - wrap!.scrollTop) < 1) {
loadHistory.value = false
refreshMessageList()
}
}, 200)
/** 加载历史消息 */
const handleOldMessage = async () => {
//
const oldPageHeight = innerRef.value?.clientHeight
if (!oldPageHeight) {
return
}
loadHistory.value = true
//
queryParams.pageNo += 1
await getMessageList()
//
scrollbarRef.value!.setScrollTop(innerRef.value!.clientHeight - oldPageHeight)
}
/**
* 是否显示时间
*
* @param {*} item - 数据
* @param {*} index - 索引
*/
const showTime = computed(() => (item : KeFuMessageRespVO, index : number) => {
if (unref(messageList.value)[index + 1]) {
let dateString = dayjs(unref(messageList.value)[index + 1].createTime).fromNow()
return dateString !== dayjs(unref(item).createTime).fromNow()
}
return false
})
/** 初始化 **/
onMounted(() => {
getVerbalTrickList()
})
/**
* 是否显示时间
*
* @param {*} item - 数据
* @param {*} index - 索引
*/
const showTime = computed(() => (item: KeFuMessageRespVO, index: number) => {
if (unref(messageList.value)[index + 1]) {
let dateString = dayjs(unref(messageList.value)[index + 1].createTime).fromNow()
return dateString !== dayjs(unref(item).createTime).fromNow()
}
return false
})
</script>
<style lang="scss" scoped>
.hover-shadow:hover {
background-color: lightgray; /* 可根据需要调整颜色 */
}
.kefu {
&-title {
border-bottom: #e4e0e0 solid 1px;
height: 60px;
line-height: 60px;
}
.kefu {
&-title {
border-bottom: #e4e0e0 solid 1px;
height: 60px;
line-height: 60px;
}
&-content {
position: relative;
&-content {
position: relative;
.newMessageTip {
position: absolute;
bottom: 35px;
right: 35px;
background-color: var(--app-content-bg-color);
padding: 10px;
border-radius: 30px;
font-size: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 阴影效果 */
}
.newMessageTip {
position: absolute;
bottom: 35px;
right: 35px;
background-color: var(--app-content-bg-color);
padding: 10px;
border-radius: 30px;
font-size: 12px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 阴影效果 */
}
.ss-row-left {
justify-content: flex-start;
.ss-row-left {
justify-content: flex-start;
.kefu-message {
margin-left: 20px;
position: relative;
.kefu-message {
margin-left: 20px;
position: relative;
&::before {
content: '';
width: 10px;
height: 10px;
left: -19px;
top: calc(50% - 10px);
position: absolute;
border-left: 5px solid transparent;
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid var(--app-content-bg-color);
}
}
}
&::before {
content: '';
width: 10px;
height: 10px;
left: -19px;
top: calc(50% - 10px);
position: absolute;
border-left: 5px solid transparent;
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid var(--app-content-bg-color);
}
}
}
.ss-row-right {
justify-content: flex-end;
.ss-row-right {
justify-content: flex-end;
.kefu-message {
margin-right: 20px;
position: relative;
.kefu-message {
margin-right: 20px;
position: relative;
&::after {
content: '';
width: 10px;
height: 10px;
right: -19px;
top: calc(50% - 10px);
position: absolute;
border-left: 5px solid var(--app-content-bg-color);
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid transparent;
}
}
}
&::after {
content: '';
width: 10px;
height: 10px;
right: -19px;
top: calc(50% - 10px);
position: absolute;
border-left: 5px solid var(--app-content-bg-color);
border-bottom: 5px solid transparent;
border-top: 5px solid transparent;
border-right: 5px solid transparent;
}
}
}
//
.kefu-message {
color: #a9a9a9;
border-radius: 5px;
box-shadow: 3px 3px 5px rgba(220, 220, 220, 0.1);
padding: 5px 10px;
width: auto;
max-width: 50%;
text-align: left;
display: inline-block !important;
position: relative;
word-break: break-all;
background-color: var(--app-content-bg-color);
transition: all 0.2s;
//
.kefu-message {
color: #a9a9a9;
border-radius: 5px;
box-shadow: 3px 3px 5px rgba(220, 220, 220, 0.1);
padding: 5px 10px;
width: auto;
max-width: 50%;
text-align: left;
display: inline-block !important;
position: relative;
word-break: break-all;
background-color: var(--app-content-bg-color);
transition: all 0.2s;
&:hover {
transform: scale(1.03);
}
}
&:hover {
transform: scale(1.03);
}
}
.date-message,
.system-message {
width: fit-content;
border-radius: 12rpx;
padding: 8rpx 16rpx;
margin-bottom: 16rpx;
//background-color: #e8e8e8;
color: #999;
font-size: 24rpx;
}
}
.date-message,
.system-message {
width: fit-content;
border-radius: 12rpx;
padding: 8rpx 16rpx;
margin-bottom: 16rpx;
//background-color: #e8e8e8;
color: #999;
font-size: 24rpx;
}
}
.chat-tools {
width: 100%;
border: var(--el-border-color) solid 1px;
border-radius: 10px;
height: 44px;
}
.chat-tools {
width: 100%;
border: var(--el-border-color) solid 1px;
border-radius: 10px;
height: 44px;
}
::v-deep(textarea) {
resize: none;
}
}
</style>
::v-deep(textarea) {
resize: none;
}
}
</style>

View File

@ -8,7 +8,7 @@
</el-col>
<!-- 会话详情选中会话的消息列表 -->
<el-col :span="12">
<ContentWrap>
<ContentWrap>
<KeFuMessageList ref="keFuChatBoxRef" @change="getConversationList" />
</ContentWrap>
</el-col>
@ -21,7 +21,6 @@
</el-row>
</template>
<script lang="ts" setup>
import { KeFuConversationList, KeFuMessageList, MemberBrowsingHistory } from './components'
import { WebSocketMessageTypeConstants } from './components/tools/constants'

View File

@ -1,73 +0,0 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:rules="formRules"
:model="formData"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="回复内容" >
<el-input v-model="formData.response" placeholder="请输入回复内容" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { LeaveWordApi, LeaveWordVO } from '@/api/mall/promotion/leaveword'
/** 用户留言 表单 */
defineOptions({ name: 'LeaveWordForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
// const formType = ref('') // create - update -
const formData = ref({
id: 0,
response: '',
})
const formRules = reactive({
response: [{ required: true, message: '回复内容', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (id: number) => {
dialogVisible.value = true
dialogTitle.value = t('回复')
// formType.value = ''
formData.value.id = id
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
console.log('1111111111111',formData.value.id +' , '+ formData.value.response )
await LeaveWordApi.addResponse(formData.value.id,formData.value.response)
message.notifySuccess('处理成功')
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
</script>

View File

@ -1,223 +0,0 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="昵称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入昵称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入电话"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_LEAVE_WORD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['promotion:leave-word:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<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="name" />
<el-table-column label="电话" align="center" prop="phone" />
<el-table-column label="内容" align="center" prop="content" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_LEAVE_WORD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button v-if="scope.row.status == 0"
link
type="primary"
@click="openForm( scope.row.id)"
v-hasPermi="['promotion:leave-word:update']"
>
待处理
</el-button>
<el-button v-if="scope.row.status == 1"
disabled
link
type="primary"
@click="openForm( scope.row.id)"
v-hasPermi="['promotion:leave-word:update']"
>
已处理
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['promotion:leave-word:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<LeaveWordForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { LeaveWordApi, LeaveWordVO } from '@/api/mall/promotion/leaveword'
import LeaveWordForm from './LeaveWordForm.vue'
/** 用户留言 列表 */
defineOptions({ name: 'LeaveWord' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<LeaveWordVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
phone: undefined,
content: undefined,
status: undefined,
createTime: []
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await LeaveWordApi.getLeaveWordPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (id?: number) => {
formRef.value.open(id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await LeaveWordApi.deleteLeaveWord(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await LeaveWordApi.exportLeaveWord(queryParams)
download.excel(data, '用户留言.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -1,5 +1,5 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="90%">
<Dialog v-model="dialogVisible" :title="dialogTitle" width="95%">
<Form
ref="formRef"
v-loading="formLoading"
@ -36,7 +36,7 @@
<el-input-number v-model="sku.productConfig.point" :min="0" class="w-100%" />
</template>
</el-table-column>
<!-- <el-table-column align="center" label="所需金额(元)" min-width="168">
<el-table-column align="center" label="所需金额(元)" min-width="168">
<template #default="{ row: sku }">
<el-input-number
v-model="sku.productConfig.price"
@ -46,7 +46,7 @@
class="w-100%"
/>
</template>
</el-table-column> -->
</el-table-column>
</SpuAndSkuList>
</template>
</Form>

View File

@ -1,159 +0,0 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="客服名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入客服名称" />
</el-form-item>
<el-form-item label="客服头像" prop="pic">
<UploadImg v-model="formData.pic" />
</el-form-item>
<el-form-item label="手机号码" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机号码" />
</el-form-item>
<el-form-item label="登录账号" prop="account">
<el-input v-model="formData.account" placeholder="请输入登录账号" />
</el-form-item>
<el-form-item label="登录密码" prop="password">
<el-input v-model="formData.password" placeholder="请输入登录密码" />
</el-form-item>
<el-form-item label="客服状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_STATUS)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="手机订单管理" prop="orderManage">
<el-radio-group v-model="formData.orderManage">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_MANAGE)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="订单通知" prop="orderInform">
<el-radio-group v-model="formData.orderInform">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_INFORM)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff'
/** 客服人员 表单 */
defineOptions({ name: 'SupportStaffForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
name: undefined,
pic: undefined,
phone: undefined,
account: undefined,
password: undefined,
status: undefined,
orderManage: undefined,
orderInform: undefined
})
const formRules = reactive({
name: [{ required: true, message: '客服名称不能为空', trigger: 'blur' }],
phone: [{ required: true, message: '手机号码不能为空', trigger: 'blur' }],
account: [{ required: true, message: '登录账号不能为空', trigger: 'blur' }],
password: [{ required: true, message: '登录密码不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await SupportStaffApi.getSupportStaff(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as SupportStaffVO
if (formType.value === 'create') {
await SupportStaffApi.createSupportStaff(data)
message.success(t('common.createSuccess'))
} else {
await SupportStaffApi.updateSupportStaff(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
name: undefined,
pic: undefined,
phone: undefined,
account: undefined,
password: undefined,
status: undefined,
orderManage: undefined,
orderInform: undefined
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,301 +0,0 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="客服名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入客服名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="手机号码" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入手机号码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="登录账号" prop="account">
<el-input
v-model="queryParams.account"
placeholder="请输入登录账号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<!-- <el-form-item label="登录密码" prop="password">
<el-input
v-model="queryParams.password"
placeholder="请输入登录密码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item> -->
<el-form-item label="客服状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择客服状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<!-- <el-form-item label="手机订单管理" prop="orderManage">
<el-select
v-model="queryParams.orderManage"
placeholder="请选择手机订单管理"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_MANAGE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item> -->
<!-- <el-form-item label="订单通知" prop="orderInform">
<el-select
v-model="queryParams.orderInform"
placeholder="请选择订单通知"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_INFORM)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</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')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['promotion:support-staff:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['promotion:support-staff:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<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="name" />
<el-table-column label="客服头像" align="center" prop="pic" >
<template #default="{ row }">
<div class="flex justify-center items-center">
<el-image
fit="cover"
:src="row.pic"
class="flex-none w-50px h-50px"
@click="imagePreview(row.pic)"
/>
</div>
</template>
</el-table-column>
<el-table-column label="手机号码" align="center" prop="phone" />
<el-table-column label="登录账号" align="center" prop="account" />
<!-- <el-table-column label="登录密码" align="center" prop="password" /> -->
<el-table-column label="客服状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_SUPPORT_STAFF_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<!-- <el-table-column label="手机订单管理" align="center" prop="orderManage">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_MANAGE" :value="scope.row.orderManage" />
</template>
</el-table-column>
<el-table-column label="订单通知" align="center" prop="orderInform">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_SUPPORT_STAFF_ORDER_INFORM" :value="scope.row.orderInform" />
</template>
</el-table-column> -->
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['promotion:support-staff:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['promotion:support-staff:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<SupportStaffForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { SupportStaffApi, SupportStaffVO } from '@/api/mall/promotion/supportstaff'
import SupportStaffForm from './SupportStaffForm.vue'
/** 客服人员 列表 */
defineOptions({ name: 'SupportStaff' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<SupportStaffVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
phone: undefined,
account: undefined,
password: undefined,
status: undefined,
orderManage: undefined,
orderInform: undefined,
createTime: []
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await SupportStaffApi.getSupportStaffPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await SupportStaffApi.deleteSupportStaff(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await SupportStaffApi.exportSupportStaff(queryParams)
download.excel(data, '客服人员.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>
<style>
</style>

View File

@ -1,111 +0,0 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<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)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题" />
</el-form-item>
<el-form-item label="详情" prop="details">
<el-input v-model="formData.details" type="textarea" placeholder="请输入详情" :rows="6" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { VerbalTrickApi, VerbalTrickVO } from '@/api/mall/promotion/verbaltrick'
/** 客服话术 表单 */
defineOptions({ name: 'VerbalTrickForm' })
const { t } = useI18n() //
const message = useMessage() //
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
type: undefined,
title: undefined,
details: undefined
})
const formRules = reactive({
title: [{ required: true, message: '标题不能为空', trigger: 'blur' }],
details: [{ required: true, message: '详情不能为空', trigger: 'blur' }]
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
if (id) {
formLoading.value = true
try {
formData.value = await VerbalTrickApi.getVerbalTrick(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = formData.value as unknown as VerbalTrickVO
if (formType.value === 'create') {
await VerbalTrickApi.createVerbalTrick(data)
message.success(t('common.createSuccess'))
} else {
await VerbalTrickApi.updateVerbalTrick(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
type: undefined,
title: undefined,
details: undefined
}
formRef.value?.resetFields()
}
</script>

View File

@ -1,211 +0,0 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="分类" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择分类"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.KEFU_VERBAL_TRICK_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input
v-model="queryParams.title"
placeholder="请输入标题"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</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')]"
class="!w-240px"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['promotion:verbal-trick:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['promotion:verbal-trick:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<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">
<template #default="scope">
<dict-tag :type="DICT_TYPE.KEFU_VERBAL_TRICK_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="标题" align="center" prop="title" />
<el-table-column label="详情" align="center" prop="details" />
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['promotion:verbal-trick:update']"
>
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['promotion:verbal-trick:delete']"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<VerbalTrickForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { VerbalTrickApi, VerbalTrickVO } from '@/api/mall/promotion/verbaltrick'
import VerbalTrickForm from './VerbalTrickForm.vue'
/** 客服话术 列表 */
defineOptions({ name: 'VerbalTrick' })
const message = useMessage() //
const { t } = useI18n() //
const loading = ref(true) //
const list = ref<VerbalTrickVO[]>([]) //
const total = ref(0) //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
type: undefined,
title: undefined,
details: undefined,
createTime: []
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await VerbalTrickApi.getVerbalTrickPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value.resetFields()
handleQuery()
}
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
try {
//
await message.delConfirm()
//
await VerbalTrickApi.deleteVerbalTrick(id)
message.success(t('common.delSuccess'))
//
await getList()
} catch {}
}
/** 导出按钮操作 */
const handleExport = async () => {
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await VerbalTrickApi.exportVerbalTrick(queryParams)
download.excel(data, '客服话术.xls')
} catch {
} finally {
exportLoading.value = false
}
}
/** 初始化 **/
onMounted(() => {
getList()
})
</script>

View File

@ -154,16 +154,4 @@ public interface ErrorCodeConstants {
ErrorCode TIME_FORMAT_ERROR = new ErrorCode(1_019_007_008, "秒杀时间段格式化错误");
// ========== 客服话术 TODO 补充编号 ==========
ErrorCode VERBAL_TRICK_NOT_EXISTS = new ErrorCode(1_020_00_001, "客服话术不存在");
// ========== 用户留言 TODO 补充编号 ==========
ErrorCode LEAVE_WORD_NOT_EXISTS = new ErrorCode(1_021_001_001, "用户留言不存在");
// ========== 自动回复 TODO 补充编号 ==========
ErrorCode AUTO_RESPONSE_NOT_EXISTS = new ErrorCode(1_022_000_000, "自动回复不存在");
// ========== 客服人员 TODO 补充编号 ==========
ErrorCode SUPPORT_STAFF_NOT_EXISTS = new ErrorCode(1_023_000_000, "客服人员不存在");
}

View File

@ -1,95 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.autoresponse;
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.autoresponse.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.autoresponse.AutoResponseDO;
import cn.iocoder.yudao.module.promotion.service.autoresponse.AutoResponseService;
@Tag(name = "管理后台 - 自动回复")
@RestController
@RequestMapping("/promotion/auto-response")
@Validated
public class AutoResponseController {
@Resource
private AutoResponseService autoResponseService;
@PostMapping("/create")
@Operation(summary = "创建自动回复")
@PreAuthorize("@ss.hasPermission('promotion:auto-response:create')")
public CommonResult<Long> createAutoResponse(@Valid @RequestBody AutoResponseSaveReqVO createReqVO) {
return success(autoResponseService.createAutoResponse(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新自动回复")
@PreAuthorize("@ss.hasPermission('promotion:auto-response:update')")
public CommonResult<Boolean> updateAutoResponse(@Valid @RequestBody AutoResponseSaveReqVO updateReqVO) {
autoResponseService.updateAutoResponse(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除自动回复")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:auto-response:delete')")
public CommonResult<Boolean> deleteAutoResponse(@RequestParam("id") Long id) {
autoResponseService.deleteAutoResponse(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得自动回复")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:auto-response:query')")
public CommonResult<AutoResponseRespVO> getAutoResponse(@RequestParam("id") Long id) {
AutoResponseDO autoResponse = autoResponseService.getAutoResponse(id);
return success(BeanUtils.toBean(autoResponse, AutoResponseRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得自动回复分页")
@PreAuthorize("@ss.hasPermission('promotion:auto-response:query')")
public CommonResult<PageResult<AutoResponseRespVO>> getAutoResponsePage(@Valid AutoResponsePageReqVO pageReqVO) {
PageResult<AutoResponseDO> pageResult = autoResponseService.getAutoResponsePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, AutoResponseRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出自动回复 Excel")
@PreAuthorize("@ss.hasPermission('promotion:auto-response:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportAutoResponseExcel(@Valid AutoResponsePageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AutoResponseDO> list = autoResponseService.getAutoResponsePage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "自动回复.xls", "数据", AutoResponseRespVO.class,
BeanUtils.toBean(list, AutoResponseRespVO.class));
}
}

View File

@ -1,34 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.autoresponse.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 AutoResponsePageReqVO extends PageParam {
@Schema(description = "关键字")
private String keyword;
@Schema(description = "回复类型,文字消息/0图片消息/1", example = "2")
private Integer type;
@Schema(description = "回复内容")
private String content;
@Schema(description = "是否开启,开启/1关闭/0", example = "2")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,43 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.autoresponse.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.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 自动回复 Response VO")
@Data
@ExcelIgnoreUnannotated
public class AutoResponseRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13888")
@ExcelProperty("id")
private Long id;
@Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("关键字")
private String keyword;
@Schema(description = "回复类型,文字消息/0图片消息/1", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "回复类型,文字消息/0图片消息/1", converter = DictConvert.class)
@DictFormat("kefu_auto_response_type") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer type;
@Schema(description = "回复内容", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("回复内容")
private String content;
@Schema(description = "是否开启,开启/1关闭/0", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "是否开启,开启/1关闭/0", converter = DictConvert.class)
@DictFormat("kefu_auto_response_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,31 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.autoresponse.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 AutoResponseSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "13888")
private Long id;
@Schema(description = "关键字", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "关键字不能为空")
private String keyword;
@Schema(description = "回复类型,文字消息/0图片消息/1", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "回复类型,文字消息/0图片消息/1不能为空")
private Integer type;
@Schema(description = "回复内容", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "回复内容不能为空")
private String content;
@Schema(description = "是否开启,开启/1关闭/0", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "是否开启,开启/1关闭/0不能为空")
private Integer status;
}

View File

@ -1,101 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.leaveword;
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.*;
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.leaveword.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.leaveword.LeaveWordDO;
import cn.iocoder.yudao.module.promotion.service.leaveword.LeaveWordService;
@Tag(name = "管理后台 - 用户留言")
@RestController
@RequestMapping("/promotion/leave-word")
@Validated
public class LeaveWordController {
@Resource
private LeaveWordService leaveWordService;
@PostMapping("/create")
@Operation(summary = "创建用户留言")
@PreAuthorize("@ss.hasPermission('promotion:leave-word:create')")
public CommonResult<Long> createLeaveWord(@Valid @RequestBody LeaveWordSaveReqVO createReqVO) {
return success(leaveWordService.createLeaveWord(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新用户留言")
@PreAuthorize("@ss.hasPermission('promotion:leave-word:update')")
public CommonResult<Boolean> updateLeaveWord(@Valid @RequestBody LeaveWordSaveReqVO updateReqVO) {
leaveWordService.updateLeaveWord(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除用户留言")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:leave-word:delete')")
public CommonResult<Boolean> deleteLeaveWord(@RequestParam("id") Long id) {
leaveWordService.deleteLeaveWord(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得用户留言")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:leave-word:query')")
public CommonResult<LeaveWordRespVO> getLeaveWord(@RequestParam("id") Long id) {
LeaveWordDO leaveWord = leaveWordService.getLeaveWord(id);
return success(BeanUtils.toBean(leaveWord, LeaveWordRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得用户留言分页")
@PreAuthorize("@ss.hasPermission('promotion:leave-word:query')")
public CommonResult<PageResult<LeaveWordRespVO>> getLeaveWordPage(@Valid LeaveWordPageReqVO pageReqVO) {
PageResult<LeaveWordDO> pageResult = leaveWordService.getLeaveWordPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, LeaveWordRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出用户留言 Excel")
@PreAuthorize("@ss.hasPermission('promotion:leave-word:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportLeaveWordExcel(@Valid LeaveWordPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<LeaveWordDO> list = leaveWordService.getLeaveWordPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "用户留言.xls", "数据", LeaveWordRespVO.class,
BeanUtils.toBean(list, LeaveWordRespVO.class));
}
//回复留言信息
@GetMapping("/addResponse")
public boolean addResponse(String id,String response){
return leaveWordService.addResponse(id,response);
}
}

View File

@ -1,36 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.leaveword.vo;
import lombok.*;
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 LeaveWordPageReqVO extends PageParam {
@Schema(description = "昵称", example = "芋艿")
private String name;
@Schema(description = "电话")
private String phone;
@Schema(description = "回复内容")
private String response;
@Schema(description = "内容")
private String content;
@Schema(description = "状态", example = "2")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,44 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.leaveword.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 用户留言 Response VO")
@Data
@ExcelIgnoreUnannotated
public class LeaveWordRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "25658")
@ExcelProperty("id")
private Long id;
@Schema(description = "昵称", example = "芋艿")
@ExcelProperty("昵称")
private String name;
@Schema(description = "电话", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("电话")
private String phone;
@Schema(description = "回复内容", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("回复内容")
private String response;
@Schema(description = "留言内容", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("留言内容")
private String content;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "状态", converter = DictConvert.class)
@DictFormat("kefu_leave_word_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,33 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.leaveword.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 用户留言新增/修改 Request VO")
@Data
public class LeaveWordSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "25658")
private Long id;
@Schema(description = "昵称", example = "芋艿")
private String name;
@Schema(description = "电话", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "电话不能为空")
private String phone;
@Schema(description = "回复内容", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "回复内容不能为空")
private String response;
@Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "内容不能为空")
private String content;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "状态不能为空")
private Integer status;
}

View File

@ -1,94 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.supportstaff;
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.*;
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.supportstaff.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.supportstaff.SupportStaffDO;
import cn.iocoder.yudao.module.promotion.service.supportstaff.SupportStaffService;
@Tag(name = "管理后台 - 客服人员")
@RestController
@RequestMapping("/promotion/support-staff")
@Validated
public class SupportStaffController {
@Resource
private SupportStaffService supportStaffService;
@PostMapping("/create")
@Operation(summary = "创建客服人员")
@PreAuthorize("@ss.hasPermission('promotion:support-staff:create')")
public CommonResult<Integer> createSupportStaff(@Valid @RequestBody SupportStaffSaveReqVO createReqVO) {
return success(supportStaffService.createSupportStaff(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新客服人员")
@PreAuthorize("@ss.hasPermission('promotion:support-staff:update')")
public CommonResult<Boolean> updateSupportStaff(@Valid @RequestBody SupportStaffSaveReqVO updateReqVO) {
supportStaffService.updateSupportStaff(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除客服人员")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:support-staff:delete')")
public CommonResult<Boolean> deleteSupportStaff(@RequestParam("id") Integer id) {
supportStaffService.deleteSupportStaff(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得客服人员")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:support-staff:query')")
public CommonResult<SupportStaffRespVO> getSupportStaff(@RequestParam("id") Integer id) {
SupportStaffDO supportStaff = supportStaffService.getSupportStaff(id);
return success(BeanUtils.toBean(supportStaff, SupportStaffRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得客服人员分页")
@PreAuthorize("@ss.hasPermission('promotion:support-staff:query')")
public CommonResult<PageResult<SupportStaffRespVO>> getSupportStaffPage(@Valid SupportStaffPageReqVO pageReqVO) {
PageResult<SupportStaffDO> pageResult = supportStaffService.getSupportStaffPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SupportStaffRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出客服人员 Excel")
@PreAuthorize("@ss.hasPermission('promotion:support-staff:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportSupportStaffExcel(@Valid SupportStaffPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<SupportStaffDO> list = supportStaffService.getSupportStaffPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "客服人员.xls", "数据", SupportStaffRespVO.class,
BeanUtils.toBean(list, SupportStaffRespVO.class));
}
}

View File

@ -1,45 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo;
import lombok.*;
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 SupportStaffPageReqVO extends PageParam {
@Schema(description = "客服名称", example = "张三")
private String name;
@Schema(description = "头像",example = "https://www.iocoder.cn")
private String pic;
@Schema(description = "手机号码")
private String phone;
@Schema(description = "登录账号", example = "31355")
private String account;
@Schema(description = "登录密码")
private String password;
@Schema(description = "客服状态", example = "2")
private Integer status;
@Schema(description = "手机订单管理")
private Integer orderManage;
@Schema(description = "订单通知")
private Integer orderInform;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,58 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 客服人员 Response VO")
@Data
@ExcelIgnoreUnannotated
public class SupportStaffRespVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "432")
@ExcelProperty("ID")
private Integer id;
@Schema(description = "客服名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
@ExcelProperty("客服名称")
private String name;
@Schema(description = "头像", example = "https://www.iocoder.cn")
@ExcelProperty("头像")
private String pic;
@Schema(description = "手机号码", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("手机号码")
private String phone;
@Schema(description = "登录账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31355")
@ExcelProperty("登录账号")
private String account;
@Schema(description = "登录密码", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("登录密码")
private String password;
@Schema(description = "客服状态", example = "2")
@ExcelProperty(value = "客服状态", converter = DictConvert.class)
@DictFormat("kefu_support_staff_status") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
@Schema(description = "手机订单管理")
@ExcelProperty(value = "手机订单管理", converter = DictConvert.class)
@DictFormat("kefu_support_staff_order_manage") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer orderManage;
@Schema(description = "订单通知")
@ExcelProperty(value = "订单通知", converter = DictConvert.class)
@DictFormat("kefu_support_staff_order_inform") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer orderInform;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,42 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 客服人员新增/修改 Request VO")
@Data
public class SupportStaffSaveReqVO {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "432")
private Integer id;
@Schema(description = "客服名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
@NotEmpty(message = "客服名称不能为空")
private String name;
@Schema(description = "头像", example = "https://www.iocoder.cn")
private String pic;
@Schema(description = "手机号码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "手机号码不能为空")
private String phone;
@Schema(description = "登录账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31355")
@NotEmpty(message = "登录账号不能为空")
private String account;
@Schema(description = "登录密码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "登录密码不能为空")
private String password;
@Schema(description = "客服状态", example = "2")
private Integer status;
@Schema(description = "手机订单管理")
private Integer orderManage;
@Schema(description = "订单通知")
private Integer orderInform;
}

View File

@ -1,123 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import org.springframework.util.StringUtils;
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.verbaltrick.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.verbaltrick.VerbalTrickDO;
import cn.iocoder.yudao.module.promotion.service.verbaltrick.VerbalTrickService;
@Tag(name = "管理后台 - 客服话术")
@RestController
@RequestMapping("/promotion/verbal-trick")
@Validated
public class VerbalTrickController {
@Resource
private VerbalTrickService verbalTrickService;
@Resource
public DictDataApi dictDataApi;
@PostMapping("/create")
@Operation(summary = "创建客服话术")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:create')")
public CommonResult<Long> createVerbalTrick(@Valid @RequestBody VerbalTrickSaveReqVO createReqVO) {
return success(verbalTrickService.createVerbalTrick(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新客服话术")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:update')")
public CommonResult<Boolean> updateVerbalTrick(@Valid @RequestBody VerbalTrickSaveReqVO updateReqVO) {
verbalTrickService.updateVerbalTrick(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除客服话术")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:delete')")
public CommonResult<Boolean> deleteVerbalTrick(@RequestParam("id") Long id) {
verbalTrickService.deleteVerbalTrick(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得客服话术")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:query')")
public CommonResult<VerbalTrickRespVO> getVerbalTrick(@RequestParam("id") Long id) {
VerbalTrickDO verbalTrick = verbalTrickService.getVerbalTrick(id);
return success(BeanUtils.toBean(verbalTrick, VerbalTrickRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得客服话术分页")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:query')")
public CommonResult<PageResult<VerbalTrickRespVO>> getVerbalTrickPage(@Valid VerbalTrickPageReqVO pageReqVO) {
PageResult<VerbalTrickDO> pageResult = verbalTrickService.getVerbalTrickPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, VerbalTrickRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出客服话术 Excel")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportVerbalTrickExcel(@Valid VerbalTrickPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<VerbalTrickDO> list = verbalTrickService.getVerbalTrickPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "客服话术.xls", "数据", VerbalTrickRespVO.class,
BeanUtils.toBean(list, VerbalTrickRespVO.class));
}
@GetMapping("/getVerbalTrickList")
@Operation(summary = "获得客服话术数据")
@PreAuthorize("@ss.hasPermission('promotion:verbal-trick:query')")
public CommonResult<List<VerbalTrickDO>> getVerbalTrickList() {
List<VerbalTrickDO> result = verbalTrickService.getVerbalTrickList();
return success(result);
}
/**
* 根据字典类型查询字典数据信息,分类
*/
// @GetMapping(value = "/type")
// public CommonResult dictType() {
// List<DictDataRespDTO> dictDataList = dictDataApi.getDictDataList("types");
// if (!dictDataList.isEmpty()) {
// dictDataList = new ArrayList<DictDataRespDTO>();
// }
// return CommonResult.success(dictDataList);
// }
}

View File

@ -1,31 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick.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 VerbalTrickPageReqVO extends PageParam {
@Schema(description = "分类", example = "1")
private Integer type;
@Schema(description = "标题")
private String title;
@Schema(description = "详情")
private String details;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,38 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick.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.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 客服话术 Response VO")
@Data
@ExcelIgnoreUnannotated
public class VerbalTrickRespVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19467")
@ExcelProperty("id")
private Long id;
@Schema(description = "分类", example = "1")
@ExcelProperty(value = "分类", converter = DictConvert.class)
@DictFormat("kefu_verbal_trick_type") // TODO 代码优化建议设置到对应的 DictTypeConstants 枚举类中
private Integer type;
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("标题")
private String title;
@Schema(description = "详情", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("详情")
private String details;
@Schema(description = "创建时间")
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick.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 VerbalTrickSaveReqVO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "19467")
private Long id;
@Schema(description = "分类", example = "1")
private Integer type;
@Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "标题不能为空")
private String title;
@Schema(description = "详情", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "详情不能为空")
private String details;
}

View File

@ -1,51 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.autoresponse;
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_auto_response")
@KeySequence("promotion_kefu_auto_response_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AutoResponseDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 关键字
*/
private String keyword;
/**
* 回复类型文字消息/0图片消息/1
*
* 枚举 {@link TODO kefu_auto_response_type 对应的类}
*/
private Integer type;
/**
* 回复内容
*/
private String content;
/**
* 是否开启开启/1关闭/0
*
* 枚举 {@link TODO kefu_auto_response_status 对应的类}
*/
private Integer status;
}

View File

@ -1,50 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.leaveword;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 用户留言 DO
*
* @author 管理员
*/
@TableName("promotion_kefu_leave_word")
@KeySequence("promotion_kefu_leave_word_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class LeaveWordDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 昵称
*/
private String name;
/**
* 电话
*/
private String phone;
/**
* 留言内容
*/
private String content;
/**
* 回复内容
*/
private String response;
/**
* 状态
*
* 枚举 {@link TODO kefu_leave_word_status 对应的类}
*/
private Integer status;
}

View File

@ -1,66 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.supportstaff;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 客服人员 DO
*
* @author 管理员
*/
@TableName("promotion_kefu_support_staff")
@KeySequence("promotion_kefu_support_staff_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SupportStaffDO extends BaseDO {
/**
* ID
*/
@TableId
private Integer id;
/**
* 客服名称
*/
private String name;
/**
* 客服头像
*/
private String pic;
/**
* 手机号码
*/
private String phone;
/**
* 登录账号
*/
private String account;
/**
* 登录密码
*/
private String password;
/**
* 客服状态
*
* 枚举 {@link TODO kefu_support_staff_status 对应的类}
*/
private Integer status;
/**
* 手机订单管理
*
* 枚举 {@link TODO kefu_support_staff_order_manage 对应的类}
*/
private Integer orderManage;
/**
* 订单通知
*
* 枚举 {@link TODO kefu_support_staff_order_inform 对应的类}
*/
private Integer orderInform;
}

View File

@ -1,42 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.verbaltrick;
import lombok.*;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 客服话术 DO
*
* @author 管理员
*/
@TableName("promotion_kefu_verbal_trick")
@KeySequence("promotion_kefu_verbal_trick_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VerbalTrickDO extends BaseDO {
/**
* id
*/
@TableId
private Long id;
/**
* 分类
*
* 枚举 {@link TODO kefu_verbal_trick_type 对应的类}
*/
private Integer type;
/**
* 标题
*/
private String title;
/**
* 详情
*/
private String details;
}

View File

@ -1,30 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.autoresponse;
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.autoresponse.AutoResponseDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.autoresponse.vo.*;
/**
* 自动回复 Mapper
*
* @author 管理员
*/
@Mapper
public interface AutoResponseMapper extends BaseMapperX<AutoResponseDO> {
default PageResult<AutoResponseDO> selectPage(AutoResponsePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<AutoResponseDO>()
.eqIfPresent(AutoResponseDO::getKeyword, reqVO.getKeyword())
.eqIfPresent(AutoResponseDO::getType, reqVO.getType())
.eqIfPresent(AutoResponseDO::getContent, reqVO.getContent())
.eqIfPresent(AutoResponseDO::getStatus, reqVO.getStatus())
.betweenIfPresent(AutoResponseDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(AutoResponseDO::getId));
}
}

View File

@ -1,29 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.leaveword;
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.leaveword.LeaveWordDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.leaveword.vo.*;
/**
* 用户留言 Mapper
*
* @author 管理员
*/
@Mapper
public interface LeaveWordMapper extends BaseMapperX<LeaveWordDO> {
default PageResult<LeaveWordDO> selectPage(LeaveWordPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<LeaveWordDO>()
.likeIfPresent(LeaveWordDO::getName, reqVO.getName())
.eqIfPresent(LeaveWordDO::getPhone, reqVO.getPhone())
.eqIfPresent(LeaveWordDO::getContent, reqVO.getContent())
.eqIfPresent(LeaveWordDO::getStatus, reqVO.getStatus())
.betweenIfPresent(LeaveWordDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(LeaveWordDO::getId));
}
}

View File

@ -1,32 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.supportstaff;
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.supportstaff.SupportStaffDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo.*;
/**
* 客服人员 Mapper
*
* @author 管理员
*/
@Mapper
public interface SupportStaffMapper extends BaseMapperX<SupportStaffDO> {
default PageResult<SupportStaffDO> selectPage(SupportStaffPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<SupportStaffDO>()
.likeIfPresent(SupportStaffDO::getName, reqVO.getName())
.eqIfPresent(SupportStaffDO::getPhone, reqVO.getPhone())
.eqIfPresent(SupportStaffDO::getAccount, reqVO.getAccount())
.eqIfPresent(SupportStaffDO::getPassword, reqVO.getPassword())
.eqIfPresent(SupportStaffDO::getStatus, reqVO.getStatus())
.eqIfPresent(SupportStaffDO::getOrderManage, reqVO.getOrderManage())
.eqIfPresent(SupportStaffDO::getOrderInform, reqVO.getOrderInform())
.betweenIfPresent(SupportStaffDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(SupportStaffDO::getId));
}
}

View File

@ -1,29 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.verbaltrick;
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.verbaltrick.VerbalTrickDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick.vo.*;
/**
* 客服话术 Mapper
*
* @author 管理员
*/
@Mapper
public interface VerbalTrickMapper extends BaseMapperX<VerbalTrickDO> {
default PageResult<VerbalTrickDO> selectPage(VerbalTrickPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<VerbalTrickDO>()
.eqIfPresent(VerbalTrickDO::getType, reqVO.getType())
.eqIfPresent(VerbalTrickDO::getTitle, reqVO.getTitle())
.eqIfPresent(VerbalTrickDO::getDetails, reqVO.getDetails())
.betweenIfPresent(VerbalTrickDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(VerbalTrickDO::getId));
}
}

View File

@ -1,55 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.autoresponse;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.autoresponse.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.autoresponse.AutoResponseDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 自动回复 Service 接口
*
* @author 管理员
*/
public interface AutoResponseService {
/**
* 创建自动回复
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createAutoResponse(@Valid AutoResponseSaveReqVO createReqVO);
/**
* 更新自动回复
*
* @param updateReqVO 更新信息
*/
void updateAutoResponse(@Valid AutoResponseSaveReqVO updateReqVO);
/**
* 删除自动回复
*
* @param id 编号
*/
void deleteAutoResponse(Long id);
/**
* 获得自动回复
*
* @param id 编号
* @return 自动回复
*/
AutoResponseDO getAutoResponse(Long id);
/**
* 获得自动回复分页
*
* @param pageReqVO 分页查询
* @return 自动回复分页
*/
PageResult<AutoResponseDO> getAutoResponsePage(AutoResponsePageReqVO pageReqVO);
}

View File

@ -1,74 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.autoresponse;
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.autoresponse.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.autoresponse.AutoResponseDO;
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.autoresponse.AutoResponseMapper;
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 AutoResponseServiceImpl implements AutoResponseService {
@Resource
private AutoResponseMapper autoResponseMapper;
@Override
public Long createAutoResponse(AutoResponseSaveReqVO createReqVO) {
// 插入
AutoResponseDO autoResponse = BeanUtils.toBean(createReqVO, AutoResponseDO.class);
autoResponseMapper.insert(autoResponse);
// 返回
return autoResponse.getId();
}
@Override
public void updateAutoResponse(AutoResponseSaveReqVO updateReqVO) {
// 校验存在
validateAutoResponseExists(updateReqVO.getId());
// 更新
AutoResponseDO updateObj = BeanUtils.toBean(updateReqVO, AutoResponseDO.class);
autoResponseMapper.updateById(updateObj);
}
@Override
public void deleteAutoResponse(Long id) {
// 校验存在
validateAutoResponseExists(id);
// 删除
autoResponseMapper.deleteById(id);
}
private void validateAutoResponseExists(Long id) {
if (autoResponseMapper.selectById(id) == null) {
throw exception(AUTO_RESPONSE_NOT_EXISTS);
}
}
@Override
public AutoResponseDO getAutoResponse(Long id) {
return autoResponseMapper.selectById(id);
}
@Override
public PageResult<AutoResponseDO> getAutoResponsePage(AutoResponsePageReqVO pageReqVO) {
return autoResponseMapper.selectPage(pageReqVO);
}
}

View File

@ -1,67 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.leaveword;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.leaveword.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.leaveword.LeaveWordDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 用户留言 Service 接口
*
* @author 管理员
*/
public interface LeaveWordService {
/**
* 创建用户留言
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createLeaveWord(@Valid LeaveWordSaveReqVO createReqVO);
/**
* 更新用户留言
*
* @param updateReqVO 更新信息
*/
void updateLeaveWord(@Valid LeaveWordSaveReqVO updateReqVO);
/**
* 删除用户留言
*
* @param id 编号
*/
void deleteLeaveWord(Long id);
/**
* 获得用户留言
*
* @param id 编号
* @return 用户留言
*/
LeaveWordDO getLeaveWord(Long id);
/**
* 获得用户留言分页
*
* @param pageReqVO 分页查询
* @return 用户留言分页
*/
PageResult<LeaveWordDO> getLeaveWordPage(LeaveWordPageReqVO pageReqVO);
/**
* 回复用户留言
* @param id
* @param response
* @return
*/
boolean addResponse(String id,String response);
}

View File

@ -1,86 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.leaveword;
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.leaveword.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.leaveword.LeaveWordDO;
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.leaveword.LeaveWordMapper;
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 LeaveWordServiceImpl implements LeaveWordService {
@Resource
private LeaveWordMapper leaveWordMapper;
@Override
public Long createLeaveWord(LeaveWordSaveReqVO createReqVO) {
// 插入
LeaveWordDO leaveWord = BeanUtils.toBean(createReqVO, LeaveWordDO.class);
leaveWordMapper.insert(leaveWord);
// 返回
return leaveWord.getId();
}
@Override
public void updateLeaveWord(LeaveWordSaveReqVO updateReqVO) {
// 校验存在
validateLeaveWordExists(updateReqVO.getId());
// 更新
LeaveWordDO updateObj = BeanUtils.toBean(updateReqVO, LeaveWordDO.class);
leaveWordMapper.updateById(updateObj);
}
@Override
public void deleteLeaveWord(Long id) {
// 校验存在
validateLeaveWordExists(id);
// 删除
leaveWordMapper.deleteById(id);
}
private void validateLeaveWordExists(Long id) {
if (leaveWordMapper.selectById(id) == null) {
throw exception(LEAVE_WORD_NOT_EXISTS);
}
}
@Override
public LeaveWordDO getLeaveWord(Long id) {
return leaveWordMapper.selectById(id);
}
@Override
public PageResult<LeaveWordDO> getLeaveWordPage(LeaveWordPageReqVO pageReqVO) {
return leaveWordMapper.selectPage(pageReqVO);
}
@Override
public boolean addResponse(String id, String response) {
LeaveWordDO leaveWordDO = leaveWordMapper.selectOne("id", id);
leaveWordDO.setResponse(leaveWordDO.getResponse());
leaveWordDO.setStatus(1);
int i = leaveWordMapper.updateById(leaveWordDO);
if (i >= 1){
return true;
}
return false;
}
}

View File

@ -1,53 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.supportstaff;
import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.supportstaff.SupportStaffDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
/**
* 客服人员 Service 接口
*
* @author 管理员
*/
public interface SupportStaffService {
/**
* 创建客服人员
*
* @param createReqVO 创建信息
* @return 编号
*/
Integer createSupportStaff(@Valid SupportStaffSaveReqVO createReqVO);
/**
* 更新客服人员
*
* @param updateReqVO 更新信息
*/
void updateSupportStaff(@Valid SupportStaffSaveReqVO updateReqVO);
/**
* 删除客服人员
*
* @param id 编号
*/
void deleteSupportStaff(Integer id);
/**
* 获得客服人员
*
* @param id 编号
* @return 客服人员
*/
SupportStaffDO getSupportStaff(Integer id);
/**
* 获得客服人员分页
*
* @param pageReqVO 分页查询
* @return 客服人员分页
*/
PageResult<SupportStaffDO> getSupportStaffPage(SupportStaffPageReqVO pageReqVO);
}

View File

@ -1,68 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.supportstaff;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.module.promotion.controller.admin.supportstaff.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.supportstaff.SupportStaffDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.promotion.dal.mysql.supportstaff.SupportStaffMapper;
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 SupportStaffServiceImpl implements SupportStaffService {
@Resource
private SupportStaffMapper supportStaffMapper;
@Override
public Integer createSupportStaff(SupportStaffSaveReqVO createReqVO) {
// 插入
SupportStaffDO supportStaff = BeanUtils.toBean(createReqVO, SupportStaffDO.class);
supportStaffMapper.insert(supportStaff);
// 返回
return supportStaff.getId();
}
@Override
public void updateSupportStaff(SupportStaffSaveReqVO updateReqVO) {
// 校验存在
validateSupportStaffExists(updateReqVO.getId());
// 更新
SupportStaffDO updateObj = BeanUtils.toBean(updateReqVO, SupportStaffDO.class);
supportStaffMapper.updateById(updateObj);
}
@Override
public void deleteSupportStaff(Integer id) {
// 校验存在
validateSupportStaffExists(id);
// 删除
supportStaffMapper.deleteById(id);
}
private void validateSupportStaffExists(Integer id) {
if (supportStaffMapper.selectById(id) == null) {
throw exception(SUPPORT_STAFF_NOT_EXISTS);
}
}
@Override
public SupportStaffDO getSupportStaff(Integer id) {
return supportStaffMapper.selectById(id);
}
@Override
public PageResult<SupportStaffDO> getSupportStaffPage(SupportStaffPageReqVO pageReqVO) {
return supportStaffMapper.selectPage(pageReqVO);
}
}

View File

@ -1,61 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.verbaltrick;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.promotion.controller.admin.verbaltrick.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.verbaltrick.VerbalTrickDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
/**
* 客服话术 Service 接口
*
* @author 管理员
*/
public interface VerbalTrickService {
/**
* 创建客服话术
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createVerbalTrick(@Valid VerbalTrickSaveReqVO createReqVO);
/**
* 更新客服话术
*
* @param updateReqVO 更新信息
*/
void updateVerbalTrick(@Valid VerbalTrickSaveReqVO updateReqVO);
/**
* 删除客服话术
*
* @param id 编号
*/
void deleteVerbalTrick(Long id);
/**
* 获得客服话术
*
* @param id 编号
* @return 客服话术
*/
VerbalTrickDO getVerbalTrick(Long id);
/**
* 获得客服话术分页
*
* @param pageReqVO 分页查询
* @return 客服话术分页
*/
PageResult<VerbalTrickDO> getVerbalTrickPage(VerbalTrickPageReqVO pageReqVO);
/**
* 获取话术数据
* @return
*/
List<VerbalTrickDO> getVerbalTrickList();
}

View File

@ -1,79 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.verbaltrick;
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.verbaltrick.vo.*;
import cn.iocoder.yudao.module.promotion.dal.dataobject.verbaltrick.VerbalTrickDO;
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.verbaltrick.VerbalTrickMapper;
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 VerbalTrickServiceImpl implements VerbalTrickService {
@Resource
private VerbalTrickMapper verbalTrickMapper;
@Override
public Long createVerbalTrick(VerbalTrickSaveReqVO createReqVO) {
// 插入
VerbalTrickDO verbalTrick = BeanUtils.toBean(createReqVO, VerbalTrickDO.class);
verbalTrickMapper.insert(verbalTrick);
// 返回
return verbalTrick.getId();
}
@Override
public void updateVerbalTrick(VerbalTrickSaveReqVO updateReqVO) {
// 校验存在
validateVerbalTrickExists(updateReqVO.getId());
// 更新
VerbalTrickDO updateObj = BeanUtils.toBean(updateReqVO, VerbalTrickDO.class);
verbalTrickMapper.updateById(updateObj);
}
@Override
public void deleteVerbalTrick(Long id) {
// 校验存在
validateVerbalTrickExists(id);
// 删除
verbalTrickMapper.deleteById(id);
}
private void validateVerbalTrickExists(Long id) {
if (verbalTrickMapper.selectById(id) == null) {
throw exception(VERBAL_TRICK_NOT_EXISTS);
}
}
@Override
public VerbalTrickDO getVerbalTrick(Long id) {
return verbalTrickMapper.selectById(id);
}
@Override
public PageResult<VerbalTrickDO> getVerbalTrickPage(VerbalTrickPageReqVO pageReqVO) {
return verbalTrickMapper.selectPage(pageReqVO);
}
@Override
public List<VerbalTrickDO> getVerbalTrickList() {
return verbalTrickMapper.selectList();
}
}

View File

@ -42,7 +42,6 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
@Validated
public class PayChannelServiceImpl implements PayChannelService {
/**
* {@link PayClient} 缓存通过它异步清空 smsClientFactory
*/

View File

@ -2,10 +2,13 @@ package cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.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.*;
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
@Schema(description = "管理后台 - 预约订单 Response VO")
@Data
@ExcelIgnoreUnannotated

View File

@ -38,4 +38,50 @@ public class AppBrandController {
return success(BeanUtils.toBean(pageResult, LitemallBrandRespVO.class));
}
/**
* 导出医馆管理列表
*/
// @PostMapping("/export")
// public void export(HttpServletResponse response, LitemallBrand litemallBrand) throws IOException {
// List<LitemallBrand> list = litemallBrandService.selectLitemallBrandList(litemallBrand);
// ExcelUtil<LitemallBrand> util = new ExcelUtil<LitemallBrand>(LitemallBrand.class);
// util.exportExcel(response, list, "医馆管理数据");
// }
/**
* 获取医馆管理详细信息
*/
// @GetMapping(value = "/{id}")
// public AjaxResult getInfo(@PathVariable("id") Integer id) {
// OrganizationDO organization = organizationService.getOrganization(id);
// return AjaxResult.success(organization);
// }
/**
* 新增医馆管理
*/
// @PostMapping
// public CommonResult<Integer> add(@RequestBody OrganizationSaveReqVO createReqVO) {
// return success(organizationService.createOrganization(createReqVO));
// }
/**
* 修改医馆管理
*/
// @PutMapping
// public AjaxResult edit(@RequestBody LitemallBrand litemallBrand)
// {
// return toAjax(litemallBrandService.updateLitemallBrand(litemallBrand));
// }
/**
* 删除医馆管理
*/
// @DeleteMapping("/{ids}")
// public AjaxResult remove(@PathVariable Long[] ids)
// {
// return toAjax(litemallBrandService.deleteLitemallBrandByIds(ids));
// }
}

View File

@ -7,15 +7,18 @@ import cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.vo.Litemal
import cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.vo.LitemallReservationRespVO;
import cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.vo.LitemallReservationSaveReqVO;
import cn.iocoder.yudao.module.srbscribe.dal.dataobject.reservation.LitemallReservationDO;
import cn.iocoder.yudao.module.srbscribe.dal.dataobject.technician.LitemallTechnicianDO;
import cn.iocoder.yudao.module.srbscribe.service.reservation.LitemallReservationService;
import cn.iocoder.yudao.module.srbscribe.util.AjaxResult;
import cn.iocoder.yudao.module.srbscribe.util.StringUtils;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -46,6 +49,7 @@ public class AppReservationController {
*/
@GetMapping(value = "/type")
public AjaxResult dictType() {
// List<SysDictData> data = dictTypeService.selectDictDataByType("tech_type");
List<DictDataRespDTO> dictDataList = dictDataApi.getDictDataList("types");
if (StringUtils.isNull(dictDataList)) {
dictDataList = new ArrayList<DictDataRespDTO>();
@ -54,6 +58,43 @@ public class AppReservationController {
}
/**
* 导出预约管理列表
*/
// @PostMapping("/export")
// public void export(HttpServletResponse response, LitemallReservation litemallReservation) throws IOException
// {
// List<LitemallReservation> list = litemallReservationService.selectLitemallReservationList(litemallReservation);
// ExcelUtil<LitemallReservation> util = new ExcelUtil<LitemallReservation>(LitemallReservation.class);
// util.exportExcel(response, list, "预约管理数据");
// }
// /**
// * 获取预约管理详细信息
// */
// @GetMapping(value = "/{id}")
// public CommonResult<SubscribeManageRespVO> getManage(@PathVariable("id") Long id) {
// SubscribeManageDO manage = subscribeManageService.getManage(id);
// return success(BeanUtils.toBean(manage, SubscribeManageRespVO.class));
// }
//
// /**
// * 新增预约管理
// */
// @PostMapping
// public CommonResult<Long> createLitemallReservation(@RequestBody LitemallReservationSaveReqVO createReqVO) {
// return success(litemallReservationService.createLitemallReservation(createReqVO));
// }
// /**
// * 新增预约管理
// */
// @PostMapping("/add")
// public CommonResult<Long> createLitemallReservation(@RequestBody LitemallReservationSaveReqVO litemallReservationDO) {
// return success(litemallReservationService.createReservation(litemallReservationDO));
// }
/**
* 新增预约管理
*/
@ -72,6 +113,24 @@ public class AppReservationController {
}
// /**
// * 修改预约管理
// */
// @PutMapping
// public CommonResult<Boolean> updateManage( @RequestBody SubscribeManageSaveReqVO updateReqVO) {
// subscribeManageService.updateManage(updateReqVO);
// return success(true);
// }
//
// /**
// * 删除预约管理
// */
// @DeleteMapping("/{ids}")
// public CommonResult<Boolean> deleteManage(@PathVariable("ids") Long[] ids) {
// subscribeManageService.deleteList(ids);
// return success(true);
// }
}

View File

@ -4,8 +4,11 @@ package cn.iocoder.yudao.module.srbscribe.controller.app.technician;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.vo.LitemallReservationPageReqVO;
import cn.iocoder.yudao.module.srbscribe.controller.admin.reservation.vo.LitemallReservationRespVO;
import cn.iocoder.yudao.module.srbscribe.controller.admin.technician.vo.LitemallTechnicianPageReqVO;
import cn.iocoder.yudao.module.srbscribe.controller.admin.technician.vo.LitemallTechnicianRespVO;
import cn.iocoder.yudao.module.srbscribe.controller.admin.technician.vo.LitemallTechnicianSaveReqVO;
import cn.iocoder.yudao.module.srbscribe.dal.dataobject.reservation.LitemallReservationDO;
import cn.iocoder.yudao.module.srbscribe.dal.dataobject.technician.LitemallTechnicianDO;
import cn.iocoder.yudao.module.srbscribe.service.reservation.LitemallReservationService;
@ -13,8 +16,12 @@ import cn.iocoder.yudao.module.srbscribe.service.technician.LitemallTechnicianSe
import org.json.JSONException;
import org.springframework.web.bind.annotation.*;
import org.json.JSONArray;
import javax.annotation.Resource;
import javax.validation.Valid;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -46,6 +53,39 @@ public class AppTechnicianController {
return success(BeanUtils.toBean(pageResult, LitemallTechnicianRespVO.class));
}
// /**
// * 首页查询技师管理列表名称去重
// */
// @GetMapping("/listmain")
// public CommonResult<PageResult<LitemallTechnicianRespVO>> listmain(LitemallTechnicianPageReqVO pageReqVO) {
// PageResult<LitemallTechnicianDO> pageResult = litemallTechnicianService.getLitemallTechnicianPage(pageReqVO);
// return success(BeanUtils.toBean(pageResult, LitemallTechnicianRespVO.class));
// }
// /**
// * 查询技师管理列表
// */
// @GetMapping("/list")
// public TableDataInfo list(LitemallTechnician litemallTechnician)
// {
// startPage();
// List<LitemallTechnician> list = litemallTechnicianService.selectLitemallTechnicianList(litemallTechnician);
// return getDataTable(list);
// }
// /**
// * 首页查询技师管理列表名称去重
// */
// @GetMapping("/listmain")
// public TableDataInfo listmain(LitemallTechnician litemallTechnician)
// {
// startPage();
// List<LitemallTechnician> list = litemallTechnicianService.selectLitemallTechnicianListmian(litemallTechnician);
// return getDataTable(list);
// }
/**
* 查询技师管理详情
*/
@ -79,6 +119,52 @@ public class AppTechnicianController {
}
/**
* 导出技师管理列表
*/
// @PostMapping("/export")
// public void export(HttpServletResponse response, LitemallTechnician litemallTechnician) throws IOException
// {
// List<LitemallTechnician> list = litemallTechnicianService.selectLitemallTechnicianList(litemallTechnician);
// ExcelUtil<LitemallTechnician> util = new ExcelUtil<LitemallTechnician>(LitemallTechnician.class);
// util.exportExcel(response, list, "技师管理数据");
// }
// /**
// * 获取技师管理详细信息
// */
// @GetMapping(value = "/{id}")
// public CommonResult<StaffRespVO> getInfo(@PathVariable("id") Long id) {
// StaffDO staff = staffService.getStaff(id);
// return success(BeanUtils.toBean(staff, StaffRespVO.class));
// }
//
// /**
// * 新增技师管理
// */
// @PostMapping
// public CommonResult<Long> add(@Valid @RequestBody StaffSaveReqVO createReqVO) {
// return success(staffService.createStaff(createReqVO));
// }
//
// /**
// * 修改技师管理
// */
// @PutMapping
// public CommonResult<Boolean> updateStaff( @RequestBody StaffSaveReqVO updateReqVO) {
// staffService.updateStaff(updateReqVO);
// return success(true);
// }
//
// /**
// * 删除技师管理
// */
// @DeleteMapping("/{ids}")
// public CommonResult<Boolean> deleteStaff(@PathVariable("ids") Long id) {
// staffService.deleteStaff(id);
// return success(true);
// }
}

View File

@ -1,6 +1,11 @@
package cn.iocoder.yudao.module.srbscribe.dal.dataobject.reservation;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;