| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- package com.kym.service.impl;
- import cn.dev33.satoken.stp.StpUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
- import com.github.pagehelper.PageHelper;
- import com.github.yulichang.base.MPJBaseServiceImpl;
- import com.kym.common.R;
- import com.kym.common.config.WxConfig;
- import com.kym.common.constant.ResponseEnum;
- import com.kym.common.enums.WxApi;
- import com.kym.common.exception.BusinessException;
- import com.kym.common.utils.CommUtil;
- import com.kym.common.utils.HttpUtil;
- import com.kym.entity.*;
- import com.kym.entity.common.PageBean;
- import com.kym.entity.queryParams.CommonQueryParam;
- import com.kym.entity.queryParams.WxLoginParams;
- import com.kym.entity.vo.CustomUserVo;
- import com.kym.entity.vo.UserVo;
- import com.kym.entity.wechat.WxPhoneNum;
- import com.kym.mapper.MpRelationMapper;
- import com.kym.mapper.UserMapper;
- import com.kym.service.AccountService;
- import com.kym.service.CarsService;
- import com.kym.service.RefundLogService;
- import com.kym.service.UserService;
- import com.kym.service.cache.KymCache;
- import jakarta.annotation.PostConstruct;
- import lombok.SneakyThrows;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeanUtils;
- import org.springframework.context.annotation.Lazy;
- import org.springframework.scheduling.annotation.Async;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.LocalTime;
- import java.time.temporal.TemporalAdjusters;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import java.util.stream.Collectors;
- import static java.util.Map.of;
- /**
- * <p>
- * 用户表 服务实现类
- * </p>
- *
- * @author skyline
- * @since 2023-06-27
- */
- @Service
- public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements UserService {
- private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
- private final WxConfig wxConfig;
- private final AccountService accountService;
- private final RefundLogService refundLogService;
- private final CarsService carsService;
- private final MpRelationMapper mpRelationMapper;
- public UserServiceImpl(WxConfig wxConfig, @Lazy AccountService accountService, RefundLogService refundLogService,
- CarsService carsService, MpRelationMapper mpRelationMapper) {
- this.wxConfig = wxConfig;
- this.accountService = accountService;
- this.refundLogService = refundLogService;
- this.carsService = carsService;
- this.mpRelationMapper = mpRelationMapper;
- }
- @PostConstruct
- private void init() {
- // 初始化缓存
- QueryWrapper<User> wrapper = new QueryWrapper<User>().select("id", "station_id");
- List<User> users = baseMapper.selectList(wrapper);
- var map = users.stream().collect(Collectors.toMap(User::getId, User::getStationId));
- KymCache.INSTANCE.putUserId2StationId(map);
- }
- @Transactional(rollbackFor = Exception.class)
- @SneakyThrows
- @Override
- public R<?> wxLogin(WxLoginParams params) {
- // 微信登录
- var json = HttpUtil.getJson(WxApi.WX_MP_LOGIN.getApi(), Map.of(
- "appid", wxConfig.getAppid(),
- "secret", wxConfig.getSecret(),
- "js_code", params.getCode()
- ));
- Integer errorCode = json.getInteger("errcode");
- if (errorCode == null) {
- // 业务逻辑处理
- var openid = json.getString("openid");
- var unionid = json.getString("unionid") == null ? "" : json.getString("unionid");
- // 判断有没有,没有就新增
- var user = baseMapper.selectOne(new QueryWrapper<User>().eq("openid", openid));
- if (user != null) {
- // 登录逻辑
- if (CommUtil.isNotEmptyAndNull(unionid) && CommUtil.isEmptyOrNull(user.getUnionid())) {
- user.setUnionid(unionid);
- }
- return handleLogin(user);
- } else {
- if (CommUtil.isEmptyOrNull(params.getPhoneCode())) {
- throw new BusinessException(ResponseEnum.WX_MP_LOGIN_ERROR);
- }
- // 注册逻辑
- // 新增用户
- var newUser = new User();
- newUser.setOpenid(openid);
- newUser.setUnionid(unionid);
- // 手机号解密:先获取access_token,再请求手机号信息
- // access_token获取
- var accessTokenJson = HttpUtil.getJson(WxApi.WX_GET_ACCESS_TOKEN.getApi(), Map.of("appid", wxConfig.getAppid(), "secret", wxConfig.getSecret()));
- var accessToken = accessTokenJson.getString("access_token");
- var wxPhoneNum = HttpUtil.post(WxApi.WX_MP_GET_PHONE.getApi().replace("ACCESS_TOKEN", accessToken), Map.of("code", params.getPhoneCode()), WxPhoneNum.class);
- var mobilePhone = wxPhoneNum.getPhone_info().getPurePhoneNumber();
- newUser.setMobilePhone(mobilePhone);
- newUser.setUsername(mobilePhone);
- newUser.setAvatar(params.getAvatar());
- newUser.setNickname(params.getNickname());
- // 用户归属站点
- if (CommUtil.isNotEmptyAndNull(params.getShortId())) {
- newUser.setStationId(KymCache.INSTANCE.gesStationIdByShortId(params.getShortId()));
- } else {
- // todo 用户归属 扫设备二维码以外注册的用户,统一归属平台自己的商户,初始化系统时创建对应的商户
- newUser.setStationId("000");
- }
- KymCache.INSTANCE.putUserId2StationId(Map.of(newUser.getId(), newUser.getStationId()));
- baseMapper.insert(newUser);
- // 创建用户账户
- var account = new Account();
- account.setUserId(newUser.getId());
- accountService.save(account);
- // 登录逻辑
- return handleLogin(newUser);
- }
- } else {
- // 抛出异常
- LOGGER.error("微信登录异常,错误码{},异常信息{}", errorCode, json.getString("errmsg"));
- throw new BusinessException(ResponseEnum.WX_MP_LOGIN_ERROR);
- }
- }
- /**
- * 获取当前登录用户信息
- *
- * @return
- */
- @Override
- public UserVo getMe() {
- var userId = StpUtil.getLoginIdAsLong();
- var userVo = baseMapper.getMe(userId);
- var car = carsService.lambdaQuery().eq(Cars::getUserId, userId).eq(Cars::getIsDefault, 1).one();
- if (car != null) {
- userVo.setDefaultPlateNo(car.getPlateNo());
- userVo.setVin(car.getVin());
- }
- return userVo;
- }
- /**
- * 登录逻辑处理
- *
- * @param user
- * @return
- */
- private R<?> handleLogin(User user) {
- StpUtil.login(user.getId());
- // 用户名存入session,统一日志读取使用
- StpUtil.getSession().set("openid", user.getOpenid());
- StpUtil.getSession().set("unionid", user.getUnionid());
- StpUtil.getSession().set("userId", user.getId());
- StpUtil.getSession().set("username", user.getUsername());
- StpUtil.getSession().set("mobilePhone", user.getMobilePhone());
- StpUtil.getSession().set("stationId", user.getStationId());
- user.setLastLoginTime(LocalDateTime.now());
- updateById(user);
- LOGGER.info("用户:{}/{}登录成功,tokenName:{},tokenValue:{}", user.getMobilePhone(), user.getId(), StpUtil.getTokenName(), StpUtil.getTokenValue());
- updateUnionid();
- return R.success(of("userId", user.getId(), "satoken", StpUtil.getTokenValue()));
- }
- @Async
- protected void updateUnionid() {
- var unionid = StpUtil.getSession().getString("unionid");
- if (CommUtil.isNotEmptyAndNull(unionid)) {
- // 匹配公众号用户
- var wrapper = new LambdaUpdateWrapper<MpRelation>().eq(MpRelation::getUnionid, unionid).set(MpRelation::getUserId, StpUtil.getLoginIdAsLong()).set(MpRelation::getOpenid, StpUtil.getSession().getString("openid"));
- mpRelationMapper.update(null, wrapper);
- }
- }
- @Transactional(rollbackFor = Exception.class)
- @Override
- public void updateUser(UserVo userVo) {
- userVo.setId(StpUtil.getSession().getLong("userId"));
- var user = new User();
- BeanUtils.copyProperties(userVo, user);
- if (!CommUtil.isEmptyOrNull(user.getAvatar()) || !CommUtil.isEmptyOrNull(user.getMobilePhone()) || !CommUtil.isEmptyOrNull(user.getNickname())) {
- baseMapper.updateById(user);
- }
- // 更新车牌信息
- if (userVo.getDefaultPlateNo() != null) {
- var car = new Cars();
- car.setUserId(userVo.getId());
- car.setPlateNo(userVo.defaultPlateNo);
- // 设置为默认
- car.setIsDefault(true);
- if (userVo.getVin() != null) {
- car.setVin(userVo.getVin());
- }
- // 将用户名下其他车辆设为非默认
- var cars = carsService.listByMap(Map.of("user_id", userVo.getId()));
- cars.stream().filter(c -> !userVo.getDefaultPlateNo().equals(c.getEngineNo())).peek(s -> s.setIsDefault(false)).collect(Collectors.toList());
- carsService.updateBatchById(cars);
- var wrapper = new QueryWrapper<Cars>();
- wrapper.eq("plate_no", userVo.getDefaultPlateNo());
- carsService.saveOrUpdate(car, wrapper);
- }
- }
- @Override
- public PageBean<UserVo> listUserVo(Integer pageNum, Integer pageSize) {
- PageHelper.startPage(pageNum, pageSize);
- var userVoList = list().stream().map(user -> {
- var userVo = new UserVo();
- BeanUtils.copyProperties(user, userVo);
- return userVo;
- }).collect(Collectors.toList());
- return new PageBean<>(userVoList);
- }
- /**
- * 分页查询用户列表
- *
- * @param params
- * @return
- */
- @Override
- public PageBean<CustomUserVo> listCustomUser(CommonQueryParam params) {
- // 站点数据权限
- var adminStationIds = KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong());
- if (CommUtil.isEmptyOrNull(params.getStationId()) &&
- CommUtil.isNotEmptyAndNull(KymCache.INSTANCE.getAdminUserStationIds(StpUtil.getLoginIdAsLong()))) {
- params.setStationId(adminStationIds.get(0));
- }
- List<Long> userIds = lambdaQuery()
- .eq(CommUtil.isNotEmptyAndNull(params.getMobilePhone()), User::getMobilePhone, params.getMobilePhone())
- .eq(CommUtil.isNotEmptyAndNull(params.getStationId()), User::getStationId, params.getStationId())
- .eq(CommUtil.isNotEmptyAndNull(params.getStatus()), User::getStatus, params.getStatus())
- .list().stream().map(User::getId)
- .toList();
- if (CommUtil.isEmptyOrNull(userIds)) {
- return new PageBean<>();
- }
- PageHelper.startPage(params.getPageNum(), params.getPageSize());
- var result = baseMapper.listUser(userIds);
- var page = new PageBean<>(result);
- // 用户余额,退款次数,退款金额
- var account = accountService.lambdaQuery().in(Account::getUserId, result.stream().map(CustomUserVo::getUserId).toList()).list();
- var user2Balance = account.stream().collect(Collectors.groupingBy(Account::getUserId, Collectors.summingInt(Account::getBalance)));
- var user2FrozenAmount = account.stream().collect(Collectors.groupingBy(Account::getUserId, Collectors.summingInt(Account::getFrozenAmount)));
- var refund = refundLogService.lambdaQuery().in(RefundLog::getUserId, result.stream().map(CustomUserVo::getUserId).toList()).list();
- // refund按照用户维度计算退款次数和退款总金额
- var user2RefundAmount = refund.stream().collect(Collectors.groupingBy(RefundLog::getUserId, Collectors.summingInt(RefundLog::getRefund)));
- var user2RefundDiscountAmount = refund.stream().collect(Collectors.groupingBy(RefundLog::getUserId, Collectors.summingInt(RefundLog::getDiscountAmount)));
- var user2RefundTimes = refund.stream().collect(Collectors.groupingBy(RefundLog::getUserId, Collectors.counting()));
- // 将用户余额,退款次数,退款金额放入result中
- var res = result.stream().peek(vo -> {
- vo.setBalance(user2Balance.getOrDefault(vo.getUserId(), 0));
- vo.setFrozenAmount(user2FrozenAmount.getOrDefault(vo.getUserId(), 0));
- vo.setRefundTimes(user2RefundTimes.getOrDefault(vo.getUserId(), 0L));
- vo.setRefundAmount(user2RefundAmount.getOrDefault(vo.getUserId(), 0));
- vo.setRefundDiscountAmount(user2RefundDiscountAmount.getOrDefault(vo.getUserId(), 0));
- vo.setStationName(KymCache.INSTANCE.getStationNameById(vo.getStationId()));
- }).toList();
- page.setList(res);
- return page;
- }
- /**
- * 统计指定日期注册用户数量
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> countDailyRegister(LocalDate statDay, String... stationId) {
- LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
- wrapper.ge(User::getCreateTime, LocalDateTime.of(statDay, LocalTime.MIN));
- wrapper.lt(User::getCreateTime, LocalDateTime.of(statDay, LocalTime.MAX));
- if (stationId.length > 0) {
- wrapper.in(User::getStationId, Arrays.asList(stationId));
- }
- // 按照站点分组统计订单数量
- return list(wrapper).stream().collect(Collectors.groupingBy(User::getStationId, Collectors.summingInt(o -> 1)));
- }
- /**
- * 统计指定日期当月注册用户数量
- *
- * @param statDay
- * @return
- */
- @Override
- public Map<String, Integer> countMonthRegister(LocalDate statDay) {
- var startTime = statDay.with(TemporalAdjusters.firstDayOfMonth()).atTime(LocalTime.MIN);
- var endTime = statDay.with(TemporalAdjusters.lastDayOfMonth()).atTime(LocalTime.MAX);
- LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
- wrapper.ge(User::getCreateTime, startTime);
- wrapper.lt(User::getCreateTime, endTime);
- return list(wrapper).stream().collect(Collectors.groupingBy(User::getStationId, Collectors.summingInt(o -> 1)));
- }
- }
|