|
|
@@ -0,0 +1,337 @@
|
|
|
+package com.cyksj.web.controller.manage.corp.wxkf;
|
|
|
+
|
|
|
+import cn.dev33.satoken.stp.StpUtil;
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.cyksj.common.annotation.Log;
|
|
|
+import com.cyksj.dto.Result;
|
|
|
+import com.cyksj.enums.BusinessType;
|
|
|
+import com.cyksj.enums.GatewayResponse;
|
|
|
+import com.cyksj.mapper.UserMapper;
|
|
|
+import com.cyksj.mapper.corp.CorpFollowMapper;
|
|
|
+import com.cyksj.mapper.corp.kf.CorpKfAccountUserChangeRecordMapper;
|
|
|
+import com.cyksj.model.entity.*;
|
|
|
+import com.cyksj.model.request.CorpKfDutySetReq;
|
|
|
+import com.cyksj.model.request.corp.kf.CorpKfDutyReq;
|
|
|
+import com.cyksj.model.views.CorpKfDutyServicersStatusView;
|
|
|
+import com.cyksj.model.views.CorpKfServicerStatisticView;
|
|
|
+import com.cyksj.model.views.CorpKfUserChatRecordView;
|
|
|
+import com.cyksj.model.views.SysCorpFollowView;
|
|
|
+import com.cyksj.service.corp.kf.CorpKfService;
|
|
|
+import com.cyksj.service.mange.cms.service.CmsUserService;
|
|
|
+import com.cyksj.service.user.UserBindRelationService;
|
|
|
+import com.ejlchina.searcher.BeanSearcher;
|
|
|
+import com.ejlchina.searcher.SearchResult;
|
|
|
+import com.ejlchina.searcher.param.Operator;
|
|
|
+import com.ejlchina.searcher.util.MapBuilder;
|
|
|
+import com.ejlchina.searcher.util.MapUtils;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.dao.DuplicateKeyException;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Optional;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * admin/微信客服
|
|
|
+ * 项目名: yhlxj2
|
|
|
+ * 文件名: CorpWxKfController
|
|
|
+ * 创建者: JavaZou
|
|
|
+ * 创建时间:2024/12/30 18:02
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@RequestMapping("/manage/corp/kf")
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class CorpKfController {
|
|
|
+ private final CorpKfService corpKfService;
|
|
|
+
|
|
|
+ private final BeanSearcher beanSearcher;
|
|
|
+
|
|
|
+ private final HttpServletRequest request;
|
|
|
+
|
|
|
+ private final CmsUserService cmsUserService;
|
|
|
+
|
|
|
+ private final CorpFollowMapper corpFollowMapper;
|
|
|
+
|
|
|
+ private final CorpKfAccountUserChangeRecordMapper corpKfAccountUserChangeRecordMapper;
|
|
|
+
|
|
|
+ private final UserBindRelationService userBindRelationService;
|
|
|
+
|
|
|
+ private final UserMapper userMapper;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加客服账号
|
|
|
+ */
|
|
|
+ @PostMapping("/account/add")
|
|
|
+ public Result<String> addKfAccount(@RequestBody CorpKfAccount corpKfAccount) throws Exception {
|
|
|
+ corpKfService.addKfAccount(corpKfAccount);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除客服账号
|
|
|
+ */
|
|
|
+ @DeleteMapping("/account/del/{id}")
|
|
|
+ public Result<String> delKfAccount(@PathVariable Long id) throws Exception {
|
|
|
+ corpKfService.delKfAccount(id);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改客服账号
|
|
|
+ */
|
|
|
+ @PutMapping("/account/update")
|
|
|
+ public Result<String> updateKfAccount(@RequestBody CorpKfAccount corpKfAccount) throws Exception {
|
|
|
+ corpKfService.updateKfAccount(corpKfAccount);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 客服账号列表
|
|
|
+ */
|
|
|
+ @GetMapping("/account/get")
|
|
|
+ public Result<SearchResult<CorpKfAccount>> getKfAccount() {
|
|
|
+ SearchResult<CorpKfAccount> search = beanSearcher.search(CorpKfAccount.class, MapUtils.flatBuilder(request.getParameterMap()).build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(search);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取客服账号链接
|
|
|
+ */
|
|
|
+ @GetMapping("/get/url")
|
|
|
+ public Result<String> getUrl(String openKfId, String scene) throws Exception {
|
|
|
+ String url = corpKfService.getUrl(openKfId, scene);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(url);
|
|
|
+ }
|
|
|
+
|
|
|
+ //===============================================账号会话设置========================================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置规则
|
|
|
+ */
|
|
|
+ @PostMapping("/set/rule")
|
|
|
+ public Result<String> setKfAccountRule(@RequestBody CorpKfAccountSessionConfig CorpKfAccountSessionConfig) {
|
|
|
+ corpKfService.setKfAccountRuleOrAutoReply(CorpKfAccountSessionConfig);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取规则设置
|
|
|
+ */
|
|
|
+ @GetMapping("/get/rule")
|
|
|
+ public Result<CorpKfAccountSessionConfig> getRule(String openKfId) {
|
|
|
+ CorpKfAccountSessionConfig corpKfAccountSessionConfig = beanSearcher.searchFirst(CorpKfAccountSessionConfig.class, MapUtils.flatBuilder(request.getParameterMap()).field(CorpKfAccountSessionConfig::getOpenKfId, openKfId).build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccountSessionConfig);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置自动回复
|
|
|
+ */
|
|
|
+ @PostMapping("/set/auto/reply")
|
|
|
+ public Result<String> setKfAccountAutoReply(@RequestBody CorpKfAccountSessionConfig CorpKfAccountSessionConfig) {
|
|
|
+ corpKfService.setKfAccountRuleOrAutoReply(CorpKfAccountSessionConfig);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取自动回复设置
|
|
|
+ */
|
|
|
+ @GetMapping("/get/auto/reply")
|
|
|
+ public Result<CorpKfAccountSessionConfig> getAutoReply(String openKfId) {
|
|
|
+ CorpKfAccountSessionConfig corpKfAccountSessionConfig = beanSearcher.searchFirst(CorpKfAccountSessionConfig.class, MapUtils.flatBuilder(request.getParameterMap()).field(CorpKfAccountSessionConfig::getOpenKfId, openKfId).build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccountSessionConfig);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //===============================================账号值班设置========================================================================
|
|
|
+ /**
|
|
|
+ * 设置值班时间
|
|
|
+ */
|
|
|
+ @PostMapping("/set/duty")
|
|
|
+ public Result<String> setKfDuty(@RequestBody CorpKfDutyReq dutyReq) throws Exception {
|
|
|
+ long adminId = StpUtil.getLoginIdAsLong();
|
|
|
+ dutyReq.setAdminId(adminId);
|
|
|
+ corpKfService.setKfDuty(dutyReq);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 客服变更记录
|
|
|
+ */
|
|
|
+ @GetMapping("/get/follow/change/logs")
|
|
|
+ public Result<SearchResult<CorpKfFollowChangeRecord>> getChangeLogs() {
|
|
|
+ SearchResult<CorpKfFollowChangeRecord> search = beanSearcher.search(CorpKfFollowChangeRecord.class, MapUtils.flatBuilder(request.getParameterMap()).orderBy(CorpKfFollowChangeRecord::getId).desc().build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(search);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取账号值班设置
|
|
|
+ */
|
|
|
+ @GetMapping("/get/duty")
|
|
|
+ public Result<List<CorpKfAccountFollow>> getKfDuty(String openKfId) {
|
|
|
+ List<CorpKfAccountFollow> corpKfAccountFollows = beanSearcher.searchAll(CorpKfAccountFollow.class, MapUtils.flatBuilder(request.getParameterMap()).field(CorpKfAccountFollow::getOpenKfId, openKfId).build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccountFollows);
|
|
|
+ }
|
|
|
+
|
|
|
+ //===============================================数据统计========================================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 数据统计
|
|
|
+ */
|
|
|
+ @GetMapping("/get/statistics")
|
|
|
+ public Result<SearchResult<CorpKfServicerStatisticView>> getStatisticsData(String startTime, String endTime) {
|
|
|
+ long adminId = StpUtil.getLoginIdAsLong();
|
|
|
+ Boolean rootRole = cmsUserService.isRootRole(adminId);
|
|
|
+ MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
|
|
|
+ if (!rootRole) {
|
|
|
+ List<String> userids = corpFollowMapper.selectList(Wrappers.lambdaQuery(CorpFollow.class)
|
|
|
+ .eq(CorpFollow::getCmsUserId, adminId)).stream().map(CorpFollow::getUserid).collect(Collectors.toList());
|
|
|
+ builder.field(CorpKfServicerStatistic::getServicerUserid, userids).op(Operator.InList);
|
|
|
+ }
|
|
|
+ String timeSql = StrUtil.EMPTY;
|
|
|
+ if (startTime != null) {
|
|
|
+ timeSql += String.format(" statistics_date>= '%s'", startTime);
|
|
|
+ }
|
|
|
+ if (endTime != null) {
|
|
|
+ timeSql += String.format(" and statistics_date <= '%s'", endTime);
|
|
|
+ }
|
|
|
+ if (StrUtil.isNotEmpty(timeSql)) {
|
|
|
+ builder.put("time", timeSql);
|
|
|
+ }
|
|
|
+ SearchResult<CorpKfServicerStatisticView> search = beanSearcher.search(CorpKfServicerStatisticView.class, builder.build());
|
|
|
+ search.getDataList().forEach(data -> {
|
|
|
+ SysCorpFollowView sysCorpFollowView = beanSearcher.searchFirst(SysCorpFollowView.class, MapUtils.builder().field(SysCorpFollowView::getFollowId, data.getServicerUserid()).build());
|
|
|
+ if (sysCorpFollowView != null) {
|
|
|
+ data.setName(sysCorpFollowView.getName());
|
|
|
+ data.setFollowName(sysCorpFollowView.getFollowName());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(search);
|
|
|
+ }
|
|
|
+
|
|
|
+ //===============================================聊天记录========================================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 会话记录
|
|
|
+ */
|
|
|
+ @GetMapping("/get/session")
|
|
|
+ public Result<SearchResult<CorpKfUserChatRecordView>> getSession(Long userId, String keyword) {
|
|
|
+ String unionId = getUnionid(userId);
|
|
|
+ MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
|
|
|
+ if (unionId != null) {
|
|
|
+ builder.field(CorpKfUserChatRecordView::getUnionid, unionId);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(keyword)) {
|
|
|
+ builder.put("keyword", String.format(" and exist (select 1 from corp_kf_account_session_chat ct where ct.session_id = cr.id and ct.msg_content like '%s%%')", keyword));
|
|
|
+ }
|
|
|
+ SearchResult<CorpKfUserChatRecordView> search = beanSearcher.search(CorpKfUserChatRecordView.class, builder.build());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(search);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取聊天记录
|
|
|
+ */
|
|
|
+ @GetMapping("/get/session/chat")
|
|
|
+ public Result<SearchResult<CorpKfAccountSessionChat>> getSessionChat(){
|
|
|
+ Map<String, Object> build = MapUtils.flatBuilder(request.getParameterMap()).build();
|
|
|
+ SearchResult<CorpKfAccountSessionChat> search = beanSearcher.search(CorpKfAccountSessionChat.class, build);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(search);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 客服上下班
|
|
|
+ */
|
|
|
+ @PutMapping("/servicer/commute")
|
|
|
+ @Log(module = "微信客服/客服上下班", businessType = BusinessType.PUT, isSaveRequestData = true)
|
|
|
+ public Result<String> servicerCommute(@RequestBody CorpKfDutySetReq corpKfDutySetReq) throws Exception {
|
|
|
+ long cmsUserId = StpUtil.getLoginIdAsLong();
|
|
|
+ corpKfService.servicerCommute(cmsUserId, corpKfDutySetReq.getOpenKfId(), corpKfDutySetReq.getStatus());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 目前值班人员变化
|
|
|
+ */
|
|
|
+ @GetMapping("/get/duty/{openKfId}")
|
|
|
+ public Result<List<CorpKfDutyServicersStatusView>> getDutyFollowByOpenKfId(@PathVariable String openKfId) throws Exception {
|
|
|
+ long cmsUserId = StpUtil.getLoginIdAsLong();
|
|
|
+ List<CorpKfDutyServicersStatusView> dutyStatuses = corpKfService.getDutyFollowByOpenKfId(cmsUserId, openKfId);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(dutyStatuses);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 目前用户值班微信客服
|
|
|
+ */
|
|
|
+ @GetMapping("/get/duty/accounts")
|
|
|
+ public Result<List<CorpKfAccount>> getCorpKfAccountByUId() {
|
|
|
+ long cmsUserId = StpUtil.getLoginIdAsLong();
|
|
|
+ List<CorpKfAccount> corpKfAccounts = corpKfService.getCorpKfAccountByUId(cmsUserId);
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccounts);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录用户切换客服记录
|
|
|
+ */
|
|
|
+ @PostMapping("/change/account/record/{openKfId}")
|
|
|
+ public Result<String> recordUserAccountRecord(@PathVariable String openKfId) {
|
|
|
+ long cmsUserId = StpUtil.getLoginIdAsLong();
|
|
|
+ CorpKfAccountUserChangeRecord corpKfAccountUserChangeRecord = Optional.ofNullable(corpKfAccountUserChangeRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountUserChangeRecord.class)
|
|
|
+ .eq(CorpKfAccountUserChangeRecord::getCmsUserId, cmsUserId)
|
|
|
+ .last("limit 1"))).orElse(new CorpKfAccountUserChangeRecord());
|
|
|
+ corpKfAccountUserChangeRecord.setCmsUserId(cmsUserId);
|
|
|
+ corpKfAccountUserChangeRecord.setOpenKfId(openKfId);
|
|
|
+ if (corpKfAccountUserChangeRecord.getId() == null) {
|
|
|
+ try {
|
|
|
+ corpKfAccountUserChangeRecordMapper.insert(corpKfAccountUserChangeRecord);
|
|
|
+ } catch (DuplicateKeyException e) {
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ corpKfAccountUserChangeRecordMapper.updateById(corpKfAccountUserChangeRecord);
|
|
|
+ }
|
|
|
+
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用户切换德微信账号
|
|
|
+ */
|
|
|
+ @GetMapping("/get/change/account")
|
|
|
+ public Result<CorpKfAccountUserChangeRecord> getChangeAccount() {
|
|
|
+ long cmsUserId = StpUtil.getLoginIdAsLong();
|
|
|
+ CorpKfAccountUserChangeRecord corpKfAccountUserChangeRecord = Optional.ofNullable(corpKfAccountUserChangeRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountUserChangeRecord.class)
|
|
|
+ .eq(CorpKfAccountUserChangeRecord::getCmsUserId, cmsUserId)
|
|
|
+ .last("limit 1"))).orElse(new CorpKfAccountUserChangeRecord());
|
|
|
+ return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccountUserChangeRecord);
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getUnionid(Long userId) {
|
|
|
+ String unionId = null;
|
|
|
+ if (userId != null) {
|
|
|
+ try {
|
|
|
+ unionId = StrUtil.COLON;
|
|
|
+ List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
|
|
|
+ if (CollUtil.isNotEmpty(userIdList)) {
|
|
|
+ User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
|
|
|
+ .in(User::getId, userIdList)
|
|
|
+ .ne(User::getUnionid, StrUtil.EMPTY)
|
|
|
+ .last("limit 1"));
|
|
|
+ if (user != null) {
|
|
|
+ unionId = user.getUnionid();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return unionId;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|