no message

This commit is contained in:
cb 2025-07-23 17:21:46 +08:00
parent 9b611ab46f
commit a25e34794f
8 changed files with 756 additions and 0 deletions

1
.gitignore vendored
View File

@ -45,3 +45,4 @@ nbdist/
!*/build/*.html !*/build/*.html
!*/build/*.xml !*/build/*.xml
/get-pip.py /get-pip.py
sql/database_update.sql

View File

@ -0,0 +1,163 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.system.domain.CustomerServiceReply;
import com.ruoyi.system.service.ICustomerServiceReplyService;
/**
* 客服回复规则App接口Controller
*
* @author ruoyi
* @date 2024-01-01
*/
@RestController
@RequestMapping("/system/customerServiceReply/app")
public class CustomerServiceReplyAppController extends BaseController
{
@Autowired
private ICustomerServiceReplyService customerServiceReplyService;
/**
* 根据用户输入获取最佳回复
*/
@PostMapping("/getReply")
public AjaxResult getReply(@RequestBody CustomerServiceReply customerServiceReply)
{
try {
String userInput = customerServiceReply.getKeyword();
if (userInput == null || userInput.trim().isEmpty()) {
return AjaxResult.error("用户输入不能为空");
}
CustomerServiceReply reply = customerServiceReplyService.getBestReply(userInput.trim());
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取回复失败", e);
return AjaxResult.error("获取回复失败:" + e.getMessage());
}
}
/**
* 根据用户输入获取最佳回复GET方式
*/
@GetMapping("/getReply")
public AjaxResult getReplyGet(@RequestParam("keyword") String keyword)
{
try {
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("用户输入不能为空");
}
CustomerServiceReply reply = customerServiceReplyService.getBestReply(keyword.trim());
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取回复失败", e);
return AjaxResult.error("获取回复失败:" + e.getMessage());
}
}
/**
* 根据关键字查询回复列表
*/
@PostMapping("/getReplyList")
public AjaxResult getReplyList(@RequestBody CustomerServiceReply customerServiceReply)
{
try {
String keyword = customerServiceReply.getKeyword();
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("关键字不能为空");
}
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyByKeyword(keyword.trim());
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询回复列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 根据关键字查询回复列表GET方式
*/
@GetMapping("/getReplyList")
public AjaxResult getReplyListGet(@RequestParam("keyword") String keyword,
@RequestParam(value = "limit", defaultValue = "10") Integer limit)
{
try {
if (keyword == null || keyword.trim().isEmpty()) {
return AjaxResult.error("关键字不能为空");
}
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyByKeyword(keyword.trim());
// 限制返回数量
if (limit != null && limit > 0 && list.size() > limit) {
list = list.subList(0, limit);
}
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询回复列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 获取所有客服回复规则列表
*/
@GetMapping("/list")
public AjaxResult list()
{
try {
CustomerServiceReply query = new CustomerServiceReply();
query.setIsActive(1); // 只查询启用状态的数据
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyList(query);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("查询客服回复规则列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 根据分类获取客服回复规则列表
*/
@GetMapping("/listByCategory")
public AjaxResult listByCategory(@RequestParam("category") String category)
{
try {
CustomerServiceReply query = new CustomerServiceReply();
query.setIsActive(1); // 只查询启用状态的数据
query.setCategory(category);
List<CustomerServiceReply> list = customerServiceReplyService.selectCustomerServiceReplyList(query);
return AjaxResult.success(list);
} catch (Exception e) {
logger.error("根据分类查询客服回复规则列表失败", e);
return AjaxResult.error("查询失败:" + e.getMessage());
}
}
/**
* 获取默认回复
*/
@GetMapping("/getDefaultReply")
public AjaxResult getDefaultReply()
{
try {
CustomerServiceReply reply = customerServiceReplyService.selectDefaultReply();
return AjaxResult.success(reply);
} catch (Exception e) {
logger.error("获取默认回复失败", e);
return AjaxResult.error("获取默认回复失败:" + e.getMessage());
}
}
}

View File

@ -304,6 +304,8 @@ public class ShiroConfig
filterChainDefinitionMap.put("/system/video/app/**", "anon"); filterChainDefinitionMap.put("/system/video/app/**", "anon");
// 素材接口 // 素材接口
filterChainDefinitionMap.put("/system/material/app/**", "anon"); filterChainDefinitionMap.put("/system/material/app/**", "anon");
// 客服回复接口
filterChainDefinitionMap.put("/system/customerServiceReply/app/**", "anon");
// 退出 logout地址shiro去清除session // 退出 logout地址shiro去清除session
filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/logout", "logout");
// 不需要拦截的访问 // 不需要拦截的访问

View File

@ -0,0 +1,181 @@
package com.ruoyi.system.domain;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
/**
* 客服回复规则对象 customer_service_replies
*
* @author ruoyi
* @date 2024-01-01
*/
public class CustomerServiceReply extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 关键字 */
@Excel(name = "关键字")
private String keyword;
/** 回复内容 */
@Excel(name = "回复内容")
private String replyContent;
/** 分类 */
@Excel(name = "分类")
private String category;
/** 优先级(数字越大优先级越高) */
@Excel(name = "优先级")
private Integer priority;
/** 是否启用1启用 0禁用 */
@Excel(name = "是否启用", readConverterExp = "1=启用,0=禁用")
private Integer isActive;
/** 匹配类型 */
@Excel(name = "匹配类型", readConverterExp = "contains=包含,exact=精确,regex=正则")
private String matchType;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date updatedTime;
/** 创建人 */
@Excel(name = "创建人")
private String createdBy;
/** 更新人 */
@Excel(name = "更新人")
private String updatedBy;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setKeyword(String keyword)
{
this.keyword = keyword;
}
public String getKeyword()
{
return keyword;
}
public void setReplyContent(String replyContent)
{
this.replyContent = replyContent;
}
public String getReplyContent()
{
return replyContent;
}
public void setCategory(String category)
{
this.category = category;
}
public String getCategory()
{
return category;
}
public void setPriority(Integer priority)
{
this.priority = priority;
}
public Integer getPriority()
{
return priority;
}
public void setIsActive(Integer isActive)
{
this.isActive = isActive;
}
public Integer getIsActive()
{
return isActive;
}
public void setMatchType(String matchType)
{
this.matchType = matchType;
}
public String getMatchType()
{
return matchType;
}
public void setCreatedTime(Date createdTime)
{
this.createdTime = createdTime;
}
public Date getCreatedTime()
{
return createdTime;
}
public void setUpdatedTime(Date updatedTime)
{
this.updatedTime = updatedTime;
}
public Date getUpdatedTime()
{
return updatedTime;
}
public void setCreatedBy(String createdBy)
{
this.createdBy = createdBy;
}
public String getCreatedBy()
{
return createdBy;
}
public void setUpdatedBy(String updatedBy)
{
this.updatedBy = updatedBy;
}
public String getUpdatedBy()
{
return updatedBy;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("keyword", getKeyword())
.append("replyContent", getReplyContent())
.append("category", getCategory())
.append("priority", getPriority())
.append("isActive", getIsActive())
.append("matchType", getMatchType())
.append("createdTime", getCreatedTime())
.append("updatedTime", getUpdatedTime())
.append("createdBy", getCreatedBy())
.append("updatedBy", getUpdatedBy())
.toString();
}
}

View File

@ -0,0 +1,76 @@
package com.ruoyi.system.mapper;
import java.util.List;
import com.ruoyi.system.domain.CustomerServiceReply;
/**
* 客服回复规则Mapper接口
*
* @author ruoyi
* @date 2024-01-01
*/
public interface CustomerServiceReplyMapper
{
/**
* 查询客服回复规则
*
* @param id 客服回复规则主键
* @return 客服回复规则
*/
public CustomerServiceReply selectCustomerServiceReplyById(Long id);
/**
* 查询客服回复规则列表
*
* @param customerServiceReply 客服回复规则
* @return 客服回复规则集合
*/
public List<CustomerServiceReply> selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply);
/**
* 根据关键字查询回复
*
* @param keyword 关键字
* @return 客服回复规则集合
*/
public List<CustomerServiceReply> selectCustomerServiceReplyByKeyword(String keyword);
/**
* 获取默认回复
*
* @return 默认回复
*/
public CustomerServiceReply selectDefaultReply();
/**
* 新增客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
public int insertCustomerServiceReply(CustomerServiceReply customerServiceReply);
/**
* 修改客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
public int updateCustomerServiceReply(CustomerServiceReply customerServiceReply);
/**
* 删除客服回复规则
*
* @param id 客服回复规则主键
* @return 结果
*/
public int deleteCustomerServiceReplyById(Long id);
/**
* 批量删除客服回复规则
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteCustomerServiceReplyByIds(Long[] ids);
}

View File

@ -0,0 +1,84 @@
package com.ruoyi.system.service;
import java.util.List;
import com.ruoyi.system.domain.CustomerServiceReply;
/**
* 客服回复规则Service接口
*
* @author ruoyi
* @date 2024-01-01
*/
public interface ICustomerServiceReplyService
{
/**
* 查询客服回复规则
*
* @param id 客服回复规则主键
* @return 客服回复规则
*/
public CustomerServiceReply selectCustomerServiceReplyById(Long id);
/**
* 查询客服回复规则列表
*
* @param customerServiceReply 客服回复规则
* @return 客服回复规则集合
*/
public List<CustomerServiceReply> selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply);
/**
* 根据关键字查询回复
*
* @param keyword 关键字
* @return 客服回复规则集合
*/
public List<CustomerServiceReply> selectCustomerServiceReplyByKeyword(String keyword);
/**
* 获取默认回复
*
* @return 默认回复
*/
public CustomerServiceReply selectDefaultReply();
/**
* 根据用户输入获取最佳回复
*
* @param userInput 用户输入
* @return 最佳回复
*/
public CustomerServiceReply getBestReply(String userInput);
/**
* 新增客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
public int insertCustomerServiceReply(CustomerServiceReply customerServiceReply);
/**
* 修改客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
public int updateCustomerServiceReply(CustomerServiceReply customerServiceReply);
/**
* 批量删除客服回复规则
*
* @param ids 需要删除的客服回复规则主键集合
* @return 结果
*/
public int deleteCustomerServiceReplyByIds(Long[] ids);
/**
* 删除客服回复规则信息
*
* @param id 客服回复规则主键
* @return 结果
*/
public int deleteCustomerServiceReplyById(Long id);
}

View File

@ -0,0 +1,141 @@
package com.ruoyi.system.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.CustomerServiceReplyMapper;
import com.ruoyi.system.domain.CustomerServiceReply;
import com.ruoyi.system.service.ICustomerServiceReplyService;
/**
* 客服回复规则Service业务层处理
*
* @author ruoyi
* @date 2024-01-01
*/
@Service
public class CustomerServiceReplyServiceImpl implements ICustomerServiceReplyService
{
@Autowired
private CustomerServiceReplyMapper customerServiceReplyMapper;
/**
* 查询客服回复规则
*
* @param id 客服回复规则主键
* @return 客服回复规则
*/
@Override
public CustomerServiceReply selectCustomerServiceReplyById(Long id)
{
return customerServiceReplyMapper.selectCustomerServiceReplyById(id);
}
/**
* 查询客服回复规则列表
*
* @param customerServiceReply 客服回复规则
* @return 客服回复规则
*/
@Override
public List<CustomerServiceReply> selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply)
{
return customerServiceReplyMapper.selectCustomerServiceReplyList(customerServiceReply);
}
/**
* 根据关键字查询回复
*
* @param keyword 关键字
* @return 客服回复规则集合
*/
@Override
public List<CustomerServiceReply> selectCustomerServiceReplyByKeyword(String keyword)
{
return customerServiceReplyMapper.selectCustomerServiceReplyByKeyword(keyword);
}
/**
* 获取默认回复
*
* @return 默认回复
*/
@Override
public CustomerServiceReply selectDefaultReply()
{
return customerServiceReplyMapper.selectDefaultReply();
}
/**
* 根据用户输入获取最佳回复
*
* @param userInput 用户输入
* @return 最佳回复
*/
@Override
public CustomerServiceReply getBestReply(String userInput)
{
if (userInput == null || userInput.trim().isEmpty()) {
return selectDefaultReply();
}
// 根据关键字查询匹配的回复
List<CustomerServiceReply> replies = selectCustomerServiceReplyByKeyword(userInput.trim());
// 如果找到匹配的回复返回优先级最高的
if (replies != null && !replies.isEmpty()) {
return replies.get(0); // 已经按优先级排序取第一个
}
// 如果没有找到匹配的回复返回默认回复
return selectDefaultReply();
}
/**
* 新增客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
@Override
public int insertCustomerServiceReply(CustomerServiceReply customerServiceReply)
{
return customerServiceReplyMapper.insertCustomerServiceReply(customerServiceReply);
}
/**
* 修改客服回复规则
*
* @param customerServiceReply 客服回复规则
* @return 结果
*/
@Override
public int updateCustomerServiceReply(CustomerServiceReply customerServiceReply)
{
return customerServiceReplyMapper.updateCustomerServiceReply(customerServiceReply);
}
/**
* 批量删除客服回复规则
*
* @param ids 需要删除的客服回复规则主键
* @return 结果
*/
@Override
public int deleteCustomerServiceReplyByIds(Long[] ids)
{
return customerServiceReplyMapper.deleteCustomerServiceReplyByIds(ids);
}
/**
* 删除客服回复规则信息
*
* @param id 客服回复规则主键
* @return 结果
*/
@Override
public int deleteCustomerServiceReplyById(Long id)
{
return customerServiceReplyMapper.deleteCustomerServiceReplyById(id);
}
}

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.CustomerServiceReplyMapper">
<resultMap type="CustomerServiceReply" id="CustomerServiceReplyResult">
<result property="id" column="id" />
<result property="keyword" column="keyword" />
<result property="replyContent" column="reply_content"/>
<result property="category" column="category" />
<result property="priority" column="priority" />
<result property="isActive" column="is_active" />
<result property="matchType" column="match_type" />
<result property="createdTime" column="created_time" />
<result property="updatedTime" column="updated_time" />
<result property="createdBy" column="created_by" />
<result property="updatedBy" column="updated_by" />
</resultMap>
<sql id="selectCustomerServiceReplyVo">
select id, keyword, reply_content, category, priority, is_active, match_type, created_time, updated_time, created_by, updated_by from customer_service_replies
</sql>
<select id="selectCustomerServiceReplyList" parameterType="CustomerServiceReply" resultMap="CustomerServiceReplyResult">
<include refid="selectCustomerServiceReplyVo"/>
<where>
<if test="keyword != null and keyword != ''"> and keyword like concat('%', #{keyword}, '%')</if>
<if test="category != null and category != ''"> and category = #{category}</if>
<if test="isActive != null"> and is_active = #{isActive}</if>
<if test="matchType != null and matchType != ''"> and match_type = #{matchType}</if>
</where>
order by priority desc, created_time desc
</select>
<select id="selectCustomerServiceReplyById" parameterType="Long" resultMap="CustomerServiceReplyResult">
<include refid="selectCustomerServiceReplyVo"/>
where id = #{id}
</select>
<select id="selectCustomerServiceReplyByKeyword" parameterType="String" resultMap="CustomerServiceReplyResult">
<include refid="selectCustomerServiceReplyVo"/>
where is_active = 1
and (
<if test="keyword != null and keyword != ''">
(match_type = 'exact' and keyword = #{keyword})
or (match_type = 'contains' and #{keyword} like concat('%', keyword, '%'))
or (match_type = 'regex' and #{keyword} regexp keyword)
</if>
)
order by priority desc, created_time desc
</select>
<select id="selectDefaultReply" resultMap="CustomerServiceReplyResult">
<include refid="selectCustomerServiceReplyVo"/>
where is_active = 1 and keyword = 'default'
limit 1
</select>
<insert id="insertCustomerServiceReply" parameterType="CustomerServiceReply" useGeneratedKeys="true" keyProperty="id">
insert into customer_service_replies
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="keyword != null and keyword != ''">keyword,</if>
<if test="replyContent != null and replyContent != ''">reply_content,</if>
<if test="category != null">category,</if>
<if test="priority != null">priority,</if>
<if test="isActive != null">is_active,</if>
<if test="matchType != null">match_type,</if>
<if test="createdBy != null">created_by,</if>
<if test="updatedBy != null">updated_by,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="keyword != null and keyword != ''">#{keyword},</if>
<if test="replyContent != null and replyContent != ''">#{replyContent},</if>
<if test="category != null">#{category},</if>
<if test="priority != null">#{priority},</if>
<if test="isActive != null">#{isActive},</if>
<if test="matchType != null">#{matchType},</if>
<if test="createdBy != null">#{createdBy},</if>
<if test="updatedBy != null">#{updatedBy},</if>
</trim>
</insert>
<update id="updateCustomerServiceReply" parameterType="CustomerServiceReply">
update customer_service_replies
<trim prefix="SET" suffixOverrides=",">
<if test="keyword != null and keyword != ''">keyword = #{keyword},</if>
<if test="replyContent != null and replyContent != ''">reply_content = #{replyContent},</if>
<if test="category != null">category = #{category},</if>
<if test="priority != null">priority = #{priority},</if>
<if test="isActive != null">is_active = #{isActive},</if>
<if test="matchType != null">match_type = #{matchType},</if>
<if test="updatedBy != null">updated_by = #{updatedBy},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteCustomerServiceReplyById" parameterType="Long">
delete from customer_service_replies where id = #{id}
</delete>
<delete id="deleteCustomerServiceReplyByIds" parameterType="String">
delete from customer_service_replies where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>