diff --git a/.gitignore b/.gitignore index 0e4d448b..e0f95da3 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ nbdist/ !*/build/*.html !*/build/*.xml /get-pip.py +sql/database_update.sql diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/CustomerServiceReplyAppController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/CustomerServiceReplyAppController.java new file mode 100644 index 00000000..03557c21 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/CustomerServiceReplyAppController.java @@ -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 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 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 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 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()); + } + } +} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index b59f52de..1c435c2b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -304,6 +304,8 @@ public class ShiroConfig filterChainDefinitionMap.put("/system/video/app/**", "anon"); // 素材接口 filterChainDefinitionMap.put("/system/material/app/**", "anon"); + // 客服回复接口 + filterChainDefinitionMap.put("/system/customerServiceReply/app/**", "anon"); // 退出 logout地址,shiro去清除session filterChainDefinitionMap.put("/logout", "logout"); // 不需要拦截的访问 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerServiceReply.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerServiceReply.java new file mode 100644 index 00000000..d241e041 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CustomerServiceReply.java @@ -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(); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerServiceReplyMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerServiceReplyMapper.java new file mode 100644 index 00000000..7225a76b --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/CustomerServiceReplyMapper.java @@ -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 selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply); + + /** + * 根据关键字查询回复 + * + * @param keyword 关键字 + * @return 客服回复规则集合 + */ + public List 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); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerServiceReplyService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerServiceReplyService.java new file mode 100644 index 00000000..a7b9b61b --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICustomerServiceReplyService.java @@ -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 selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply); + + /** + * 根据关键字查询回复 + * + * @param keyword 关键字 + * @return 客服回复规则集合 + */ + public List 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); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerServiceReplyServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerServiceReplyServiceImpl.java new file mode 100644 index 00000000..c2d0d854 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CustomerServiceReplyServiceImpl.java @@ -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 selectCustomerServiceReplyList(CustomerServiceReply customerServiceReply) + { + return customerServiceReplyMapper.selectCustomerServiceReplyList(customerServiceReply); + } + + /** + * 根据关键字查询回复 + * + * @param keyword 关键字 + * @return 客服回复规则集合 + */ + @Override + public List 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 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); + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/CustomerServiceReplyMapper.xml b/ruoyi-system/src/main/resources/mapper/system/CustomerServiceReplyMapper.xml new file mode 100644 index 00000000..66b7c39a --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/CustomerServiceReplyMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + select id, keyword, reply_content, category, priority, is_active, match_type, created_time, updated_time, created_by, updated_by from customer_service_replies + + + + + + + + + + + + insert into customer_service_replies + + keyword, + reply_content, + category, + priority, + is_active, + match_type, + created_by, + updated_by, + + + #{keyword}, + #{replyContent}, + #{category}, + #{priority}, + #{isActive}, + #{matchType}, + #{createdBy}, + #{updatedBy}, + + + + + update customer_service_replies + + keyword = #{keyword}, + reply_content = #{replyContent}, + category = #{category}, + priority = #{priority}, + is_active = #{isActive}, + match_type = #{matchType}, + updated_by = #{updatedBy}, + + where id = #{id} + + + + delete from customer_service_replies where id = #{id} + + + + delete from customer_service_replies where id in + + #{id} + + + \ No newline at end of file