소스 검색

企业微信端迁移车票查看功能;
微信客服动态排队提示、设置设备标记

zoujiajian 1 년 전
부모
커밋
8f1b652a7e

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpKfAccountSessionConfig.java

@@ -34,6 +34,11 @@ public class CorpKfAccountSessionConfig extends BaseEntity{
 	 */
 	private String welcomeContent;
 
+	/**
+	 * 动态排队提示
+	 */
+	private String dynamicQueueTips;
+
 	/**
 	 * 排队提示
 	 */

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpKfUser.java

@@ -1,5 +1,8 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbIgnore;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -21,4 +24,24 @@ public class CorpKfUser extends BaseEntity{
 	private Integer gender;
 
 	private String avatar;
+
+	/**
+	 * 微信客服备注
+	 */
+	private String remark;
+
+	/**
+	 * 是否是设备用户
+	 */
+	private Boolean isDevice;
+
+	/**
+	 * 标记用户设备客服
+	 */
+	@TableField(updateStrategy = FieldStrategy.IGNORED)
+	private String followId;
+
+	@DbIgnore
+	@TableField(exist = false)
+	private String followName;
 }

+ 22 - 0
netflix-dao/src/main/java/com/cyksj/model/request/CorpKfUserMarkReq.java

@@ -0,0 +1,22 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfUserMarkReq
+ * 创建者: JavaZou
+ * 创建时间:2025/1/17 11:08
+ */
+@Getter
+@Setter
+public class CorpKfUserMarkReq {
+
+	private String externalUserid;
+
+	/**
+	 * 客服id
+	 */
+	private String followId;
+}

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/model/views/TicketView.java

@@ -49,6 +49,9 @@ public class TicketView {
 	@DbField("a.password")
 	private String password;
 
+	@DbField("if(a.api_secret='',false,true)")
+	private Boolean isVerify;
+
 	/**
 	 * 国区id
 	 */

+ 7 - 0
netflix-dao/src/main/java/com/cyksj/model/views/YHLXUserDetailView.java

@@ -1,6 +1,7 @@
 package com.cyksj.model.views;
 
 import com.cyksj.model.entity.Address;
+import com.cyksj.model.entity.CorpKfUser;
 import com.cyksj.model.entity.User;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
@@ -67,4 +68,10 @@ public class YHLXUserDetailView {
 	 */
 	@DbIgnore
 	private Boolean isVip;
+
+	/**
+	 * 微信客服 用户信息
+	 */
+	@DbIgnore
+	private CorpKfUser corpKfUser;
 }

+ 37 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpUserServiceImpl.java

@@ -6,8 +6,11 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.config.corp.WeChatCorpFactory;
 import com.cyksj.mapper.*;
+import com.cyksj.mapper.corp.CorpFollowMapper;
 import com.cyksj.mapper.corp.CorpUserAuthMapper;
 import com.cyksj.mapper.corp.CorpUserMapper;
+import com.cyksj.mapper.corp.kf.CorpKfUserMapper;
+import com.cyksj.mapper.manage.cms.CmsUserMapper;
 import com.cyksj.mapper.market.task.UserBindDetailMapper;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.kf.CorpKfUserInfo;
@@ -65,6 +68,12 @@ public class CorpUserServiceImpl implements CorpUserService {
 
 	private final WxCorpOps wxCorpOps;
 
+	private final CorpKfUserMapper corpKfUserMapper;
+
+	private final CorpFollowMapper corpFollowMapper;
+
+	private final CmsUserMapper cmsUserMapper;
+
 	@Override
 	public YHLXUserDetailView getUserDetailView(String externalUserid, String corpId) throws Exception {
 		CorpUser corpUser = getExternalUserId(corpId, externalUserid);
@@ -123,6 +132,8 @@ public class CorpUserServiceImpl implements CorpUserService {
 				.in(UserIdentity::getUserId, userIdList)
 				.eq(UserIdentity::getTag, UserIdentity.Tag.VIP));
 		view.setIsVip(count2 > 0);
+		//微信客服 用户
+		view.setCorpKfUser(getCorpKfUser(externalUserid));
 		return view;
 	}
 
@@ -298,4 +309,30 @@ public class CorpUserServiceImpl implements CorpUserService {
 		}
 		return corpUser;
 	}
+
+	private CorpKfUser getCorpKfUser(String externalUserid) {
+		//微信客服用户信息
+		CorpKfUser corpKfUser = corpKfUserMapper.selectOne(Wrappers.lambdaQuery(CorpKfUser.class)
+				.eq(CorpKfUser::getExternalUserid, externalUserid)
+				.last("limit 1"));
+		if (corpKfUser != null) {
+			if (corpKfUser.getIsDevice()) {
+				CorpFollow corpFollow = corpFollowMapper.selectOne(Wrappers.lambdaQuery(CorpFollow.class)
+						.eq(CorpFollow::getUserid, corpKfUser.getFollowId())
+						.last("limit 1"));
+				String followName = null;
+				if (corpFollow != null) {
+					followName = corpFollow.getName();
+					if (corpFollow.getCmsUserId() != null) {
+						CmsUser cmsUser = cmsUserMapper.selectById(corpFollow.getCmsUserId());
+						if (cmsUser != null) {
+							followName = cmsUser.getNickname();
+						}
+					}
+				}
+				corpKfUser.setFollowName(followName);
+			}
+		}
+		return corpKfUser;
+	}
 }

+ 242 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/relation/CorpRelationController.java

@@ -0,0 +1,242 @@
+package com.cyksj.web.controller.manage.corp.relation;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.GoogleGenerator;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.DoubleVerifyClickRecordMapper;
+import com.cyksj.mapper.DoubleVerifyClickRefreshRecordMapper;
+import com.cyksj.model.dto.DoubleVerifyDto;
+import com.cyksj.model.entity.DoubleVerifyClickRecord;
+import com.cyksj.model.entity.DoubleVerifyClickRefreshRecord;
+import com.cyksj.model.manage.views.GroupsRelationView;
+import com.cyksj.model.request.NfDeviceReq;
+import com.cyksj.model.request.TicketLoginReq;
+import com.cyksj.model.views.DoubleVerifyCodeView;
+import com.cyksj.model.views.RenewalView;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.relation.GroupRelationFrontService;
+import com.cyksj.service.relation.GroupsRelationNetflixService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.util.MapUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * admin/企业微信/车票功能
+ * 项目名: yhlxj2
+ * 文件名: CorpRelationController
+ * 创建者: JavaZou
+ * 创建时间:2025/1/16 18:13
+ */
+@RestController
+@RequestMapping("/manage/corp/relation")
+@RequiredArgsConstructor
+public class CorpRelationController {
+	private final GroupRelationFrontService groupRelationFrontService;
+
+	private final GroupsRelationNetflixService groupsRelationNetflixService;
+
+	private final DoubleVerifyClickRecordMapper doubleVerifyRecordMapper;
+
+	private final DoubleVerifyClickRefreshRecordMapper refreshRecordMapper;
+
+	private final BeanSearcher beanSearcher;
+
+	private final RedisService redisService;
+
+
+	/**
+	 * 车票用户所有购买平台
+	 */
+	@GetMapping("/get/pay/goods")
+	public Result<List<RenewalView>> getHasPayGoods(Long userId) {
+		List<RenewalView> hasPayGoods = groupRelationFrontService.getHasPayGoods(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(hasPayGoods);
+	}
+
+	/**
+	 * 奈飞同户装置链接
+	 */
+	@GetMapping("/get/nf/household/device")
+	public Result<String> getNfHouseholdDevice(@NotNull Long relationId, Long userId) throws Exception {
+		String url = groupRelationFrontService.getNfHouseholdDevice(userId, relationId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(url);
+	}
+
+	/**
+	 * 读取车票账号登录验证码
+	 */
+	@PostMapping("/get/verifyCode")
+	public Result<String> getAiVerifyCode(@RequestBody TicketLoginReq loginReq) throws Exception {
+		return GatewayResponse.SUCCESS.newBuilder().toResult(groupRelationFrontService.getAiVerifyCode(loginReq));
+	}
+
+	/**
+	 * 设置pin码
+	 */
+	@PutMapping("/set/pin/{relationId}")
+	public Result<String> setPin(@PathVariable Long relationId, String code, Long userId) {
+		JSONObject data = groupsRelationNetflixService.setNetflixPin(relationId, userId, code);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(data.toString());
+	}
+
+	/**
+	 * 查询是否设置成功
+	 */
+	@GetMapping("/get/pin/status/{taskId}")
+	public Result<Integer> getPinStatus(@PathVariable String taskId) throws Exception {
+		return GatewayResponse.SUCCESS.newBuilder().toResult(groupsRelationNetflixService.getPinStatus(taskId));
+	}
+
+	/**
+	 * 踢出奈飞设备
+	 */
+	@PostMapping("/kickOut/nf/{relationId}")
+	public Result<String> nfKickOut(@PathVariable Long relationId, Long userId) {
+		JSONObject data = groupsRelationNetflixService.nfKickOut(userId, relationId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(data.toString());
+	}
+
+	/**
+	 * 代点奈飞同户装置
+	 */
+	@PostMapping("/click/nf/household/device")
+	public void clickNfHouseholdDevice(@RequestBody NfDeviceReq nfDeviceReq) {
+		groupsRelationNetflixService.clickNfHouseholdDevice(nfDeviceReq);
+	}
+
+	/**
+	 * 获取双重验证码记录
+	 */
+	@GetMapping("/get/doubleVerify/codeList")
+	public Result<List<DoubleVerifyCodeView>> getDoubleVerifyCodeList(Long relationId, Long userId) {
+		List<DoubleVerifyCodeView> views = doubleVerifyRecordMapper.getDoubleVerifyCodeList(userId, relationId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(views);
+	}
+
+	/**
+	 * 获取AI类 ChatGPT产品谷歌验证码
+	 */
+	@GetMapping("/get/authCode")
+	public Result<String> getAuthCode(Long relationId, Long userId) {
+		if (relationId == null) throw BusinessRuntimeException.getInstance("车票不存在");
+		GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder()
+				.field(GroupsRelationView::getId, relationId)
+				.field(GroupsRelationView::getUserId, userId).build());
+		if (groupsRelationView == null) throw BusinessRuntimeException.getInstance("车票不存在");
+		if (StrUtil.isEmpty(groupsRelationView.getApiSecret()))
+			throw BusinessRuntimeException.getInstance("未开启验证");
+		DateTime now = DateTime.now();
+		//获取双重验证码
+		Boolean isHasVerifyCode = StrUtil.isNotBlank(groupsRelationView.getVerifyCode()) ? true : false;
+		//一分钟内 只能一人获取
+		boolean b = redisService.setNx(RedisService.key.DOUBLE_VERIFY_CODE_VIEW_MINUTES_KEY.getName() + groupsRelationView.getTripsAccount(), relationId, RedisService.key.DOUBLE_VERIFY_CODE_VIEW_MINUTES_KEY.getTimeout());
+		if (!b) {
+			throw BusinessRuntimeException.getInstance("一分钟内已有人获取该账号验证码,请稍后获取..");
+		}
+		int second = now.second();
+		if (second < 30 && 30 - second < 3) {
+			ThreadUtil.sleep(30 - second + 1, TimeUnit.SECONDS);
+		} else if (second > 30 && 60 - second < 3) {
+			ThreadUtil.sleep(60 - second + 1, TimeUnit.SECONDS);
+		}
+		StringBuilder sb = new StringBuilder();
+		JSONObject re = new JSONObject();
+		try {
+			long code = GoogleGenerator.getCode(groupsRelationView.getApiSecret(), now.getTime());
+			sb.append(code);
+			while (sb.length() < 6) {
+				sb.insert(0, 0);
+			}
+			re.putOpt("code", sb.toString());
+			int nowSecond = DateTime.now().second();
+			int time = 0;
+			if (nowSecond < 30) {
+				time = 30 - nowSecond;
+			} else {
+				time = 60 - nowSecond;
+			}
+			re.putOpt("time", time);
+
+			DoubleVerifyClickRecord doubleVerifyClickRecord = new DoubleVerifyClickRecord();
+			doubleVerifyClickRecord.setRelationId(relationId);
+			//设置为0
+			doubleVerifyClickRecord.setUserId(0l);
+
+			doubleVerifyClickRecord.setAccountId(groupsRelationView.getAccountId());
+			doubleVerifyClickRecord.setAccount(groupsRelationView.getTripsAccount());
+			doubleVerifyClickRecord.setSkuId(groupsRelationView.getSkuId());
+			doubleVerifyClickRecord.setCode(sb.toString());
+			doubleVerifyClickRecord.setRemainTime(time);
+			doubleVerifyRecordMapper.insert(doubleVerifyClickRecord);
+
+			DoubleVerifyDto doubleVerifyDto = new DoubleVerifyDto();
+			doubleVerifyDto.setClickId(doubleVerifyClickRecord.getId());
+			doubleVerifyDto.setApiSecret(groupsRelationView.getApiSecret());
+			redisService.set(String.format("%s-%s", userId, sb.toString()), 0, 60 * 10l);
+			redisService.set(String.format("%s/%s", userId, sb.toString()), Jsons.toJson(doubleVerifyDto), 60 * 10l);
+		} catch (Exception e) {
+			throw BusinessRuntimeException.getInstance("获取双重验证码错误,请联系开发");
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(re.toString());
+	}
+
+	/**
+	 * 刷新验证码
+	 */
+	@GetMapping("/refresh/code")
+	public Result<String> refreshCode(String code, Long userId) {
+		String objKey = String.format("%s/%s", userId, code);
+		Object objValue =  redisService.get(objKey);
+		String apiSecret = null;
+		Long clickId = 0l;
+		try {
+			DoubleVerifyDto dto = Jsons.parseObject(objValue.toString(), DoubleVerifyDto.class);
+			apiSecret = dto.getApiSecret();
+			clickId = dto.getClickId();
+		} catch (Exception e) {
+			apiSecret = objValue.toString();
+		}
+		if (apiSecret == null) {
+			throw BusinessRuntimeException.getInstance("密钥不存在");
+		}
+		StringBuilder sb = new StringBuilder();
+		try {
+			long c = GoogleGenerator.getCode(apiSecret, DateTime.now().getTime());
+			sb.append(c);
+			while (sb.length() < 6) {
+				sb.insert(0, 0);
+			}
+
+		} catch (Exception e) {
+			throw BusinessRuntimeException.getInstance("刷新双重验证码错误,请联系开发");
+		}
+		if (clickId != 0) {
+			int nowSecond = DateTime.now().second();
+			int time = 0;
+			if (nowSecond < 30) {
+				time = 30 - nowSecond;
+			} else {
+				time = 60 - nowSecond;
+			}
+			//刷新双重验证码记录
+			DoubleVerifyClickRefreshRecord refreshRecord = new DoubleVerifyClickRefreshRecord();
+			refreshRecord.setClickId(clickId);
+			refreshRecord.setUserId(0l);
+			refreshRecord.setCode(sb.toString());
+			refreshRecord.setRemainTime(time);
+			refreshRecordMapper.insert(refreshRecord);
+		}
+		return GatewayResponse.SUCCESS.newBuilder().toResult(sb.toString());
+	}
+}

+ 84 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/wxkf/CorpKfUserController.java

@@ -0,0 +1,84 @@
+package com.cyksj.web.controller.manage.corp.wxkf;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.corp.kf.CorpKfUserMapper;
+import com.cyksj.model.entity.CorpKfUser;
+import com.cyksj.model.kf.CorpKfUserInfo;
+import com.cyksj.model.request.CorpKfUserMarkReq;
+import com.cyksj.service.corp.WxCorpOps;
+import lombok.RequiredArgsConstructor;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * admin/企业微信/微信客服
+ * 项目名: yhlxj2
+ * 文件名: CorpKfUserController
+ * 创建者: JavaZou
+ * 创建时间:2025/1/15 18:27
+ */
+@RestController
+@RequestMapping("/manage/corp/kf/user")
+@RequiredArgsConstructor
+public class CorpKfUserController {
+	private final CorpKfUserMapper corpKfUserMapper;
+
+	private final WxCorpOps wxCorpOps;
+
+	/**
+	 * 微信客户详情
+	 */
+	@GetMapping("/get/detail")
+	public Result<CorpKfUser> getCorpKfUserInfo(String externalUserid) throws Exception {
+		CorpKfUser user = getCorpUser(externalUserid);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(user);
+	}
+
+	/**
+	 * 设置备注
+	 */
+	@PostMapping("/set/remark")
+	public Result<String> setUserRemark(@RequestBody CorpKfUser corpKfUser) throws Exception {
+		CorpKfUser user = getCorpUser(corpKfUser.getExternalUserid());
+		user.setRemark(corpKfUser.getRemark());
+		corpKfUserMapper.updateById(user);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	/**
+	 * 标记为设备用户
+	 */
+	@PostMapping("/mark/device")
+	public Result<String> markUserDevice(@RequestBody CorpKfUserMarkReq corpKfUserMarkReq) throws Exception {
+		String externalUserid = corpKfUserMarkReq.getExternalUserid();
+		String followId = corpKfUserMarkReq.getFollowId();
+		CorpKfUser user = getCorpUser(externalUserid);
+		if (user.getIsDevice()) {
+			user.setFollowId(null);
+		} else {
+			user.setFollowId(followId);
+		}
+		user.setIsDevice(!user.getIsDevice());
+		corpKfUserMapper.updateById(user);
+		return GatewayResponse.SUCCESS.newBuilder().toResult();
+	}
+
+	public CorpKfUser getCorpUser(String externalUserid) throws Exception {
+		CorpKfUser corpKfUser = corpKfUserMapper.selectOne(Wrappers.lambdaQuery(CorpKfUser.class)
+				.eq(CorpKfUser::getExternalUserid, externalUserid)
+				.last("limit 1"));
+		if (corpKfUser == null) {
+			CorpKfUserInfo corpKfUserInfo = wxCorpOps.getCorpKfUserInfo(externalUserid);
+			try {
+				corpKfUser = new CorpKfUser();
+				BeanUtil.copyProperties(corpKfUserInfo, corpKfUser);
+				corpKfUserMapper.insert(corpKfUser);
+			} catch (DuplicateKeyException e) {
+			}
+		}
+		return corpKfUser;
+	}
+}