package com.ylx.web.controller.massage;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ylx.common.annotation.Log;
import com.ylx.common.config.RuoYiConfig;
import com.ylx.common.constant.Constants;
import com.ylx.common.core.controller.BaseController;
import com.ylx.common.core.domain.AjaxResult;
import com.ylx.common.core.domain.R;
import com.ylx.common.core.domain.model.BindPhoneBody;
import com.ylx.common.core.domain.model.PhoneLoginBody;
import com.ylx.common.core.domain.model.WxLoginUser;
import com.ylx.common.core.domain.model.aliyun.SMSVerificationCode;
import com.ylx.common.core.domain.model.aliyun.SendSmsComponents;
import com.ylx.common.core.domain.model.aliyun.SendSmsEnum;
import com.ylx.common.core.redis.RedisCache;
import com.ylx.common.enums.BusinessType;
import com.ylx.common.utils.MessageUtils;
import com.ylx.common.utils.StringUtils;
import com.ylx.common.utils.file.FileUploadUtils;
import com.ylx.framework.manager.AsyncManager;
import com.ylx.framework.manager.factory.AsyncFactory;
import com.ylx.framework.web.service.WxTokenService;
import com.ylx.massage.domain.TJs;
import com.ylx.massage.domain.TWxUser;
import com.ylx.coupon.service.CouponReceiveService;
import com.ylx.massage.service.TJsService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.massage.service.TbFileService;
import com.ylx.massage.utils.JsSignUtil;
import com.ylx.massage.utils.StringUtilsMassage;
import com.ylx.massage.utils.WeChatUtil;
import com.ylx.usercenter.domain.vo.OneAccountVO;
import com.ylx.usercenter.service.UnifiedUserCenterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.ylx.massage.utils.OtherUtil.verification;

/**
 * @author b16mt
 */
@Slf4j
@RestController
@Api(tags = {"微信服务号"})
@RequestMapping("/weChat")
public class WeChatController extends BaseController {

    private final static String TOKEN = "abcd1234";
    private final static String ENCODING = "UTF-8";
    private final static String ACCESS_TOKEN = "access_token";
    private final static String REFRESH_TOKEN = "refresh_token";
    private final static String OPEN_ID = "openid";

    public static final String PHONE_VERIFICATION_CODE_KEY = "sys:clientLogin:phone:";

    public static final Integer PHONE_VERIFICATION_CODE_KEY_TIME = 5;

    /**
     * 二维码保存路径
     */
    private String IMG_PATH = "D:\\Users\\";


    @Resource
    private WeChatUtil weChatUtil;

    @Resource
    private TWxUserService wxUserService;

    @Resource(name = "commonAsyncExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private CouponReceiveService couponReceiveService;

    @Resource
    private WxTokenService wxTokenService;

    @Resource
    private JsSignUtil jsSignUtil;

    @Autowired
    private TbFileService tbFileService;

    @Resource
    private TJsService jsService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SendSmsComponents sendSms;

    /**
     * 发送验证码开关（true:调用真实发送接口，false:验证码写死123456）
     */
    @Value("${ylx.sendSmsEnabled:false}")
    private boolean sendSmsEnabled;

    /**
     * 写死的验证码（sendSmsEnabled为false时使用）
     */
    @Value("${ylx.fixedVerifyCode:123456}")
    private String fixedVerifyCode;
    @Resource
    private UnifiedUserCenterService unifiedUserCenterService;

    /**
     * 微信Token验证
     *
     * @param signature 微信加密签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param echostr   随机字符串
     * @param response  HTTP响应对象
     * @throws Exception 如果处理过程中出现错误
     */
    @GetMapping("/verifyToken")
    @Log(title = "公众号pverifyToken", businessType = BusinessType.OTHER)
    public void verifyToken(@RequestParam(value = "signature") String signature,
                            @RequestParam(value = "timestamp") String timestamp,
                            @RequestParam(value = "nonce") String nonce,
                            @RequestParam(value = "echostr") String echostr, HttpServletResponse response) throws Exception {

        log.info("微信Token验证 入参: signature:{},timestamp:{},nonce:{},echostr:{},", signature, timestamp, nonce, echostr);
        // 参数排序
        String[] params = new String[]{timestamp, nonce, TOKEN};
        Arrays.sort(params);

        // 校验成功则响应 echostr，失败则不响应
        if (verification(params, signature) && echostr != null) {
            response.setCharacterEncoding(ENCODING);
            response.getWriter().write(echostr);
            response.getWriter().flush();
            response.getWriter().close();
        }
    }

    /**
     * 设置服务号的菜单
     *
     * @return Map<?, ?>
     */
    @GetMapping("/setMenu")
    @ApiOperation("设置菜单")
    @Log(title = "设置菜单", businessType = BusinessType.OTHER)
    public Map<?, ?> setMenu() {
        //获取access_token
        String token = weChatUtil.getToken();
        //获取的二维码ticket
        return weChatUtil.menuUtil(token);
    }

    /**
     * 前端获取jssdk签名
     *
     * @param url 页面url
     * @return Map<?, ?>
     */
    @GetMapping("/getSignature")
    @ApiOperation("前端获取jssdk签名")
    @Log(title = "前端获取jssdk签名", businessType = BusinessType.OTHER)
    public Map<?, ?> getSignature(String url) {
        //获取access_token
        String token = weChatUtil.getToken();
        //获取jsapi_ticket
        String jsapiTicket = weChatUtil.getJsapiTicket(token);
        //生成签名
        return jsSignUtil.sign(url, jsapiTicket);
    }


    /**
     * 处理微信公众号请求信息
     *
     * @param request
     * @return
     */
    @RequestMapping("/verifyToken")
    @ResponseBody
    @Log(title = "处理微信公众号请求信息", businessType = BusinessType.OTHER)
    public String handlePublicMsg(HttpServletRequest request) throws Exception {
        log.info("处理微信公众号请求信息:{}", request.toString());
        // 获得微信端返回的xml数据
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try {
            is = request.getInputStream();
            isr = new InputStreamReader(is, "utf-8");
            br = new BufferedReader(isr);
            String str = null;
            StringBuffer returnXml = new StringBuffer();
            while ((str = br.readLine()) != null) {
                //返回的是xml数据
                returnXml.append(str);
            }
            log.info("微信端返回的xml数据:{}", returnXml);
            Map<String, String> encryptMap = WeChatUtil.xmlToMap(returnXml.toString());
            // 得到公众号传来的加密信息并解密,得到的是明文xml数据
//            String decryptXml = WXPublicUtils.decrypt(encryptMap.get("Encrypt"));
            // 将xml数据转换为map
//            Map<String, String> decryptMap = WeChatUtil.xmlToMap(decryptXml);

            // 区分消息类型
            String msgType = encryptMap.get("MsgType");
            // 普通消息
            if ("text".equals(msgType)) { // 文本消息
                // todo 处理文本消息
            } else if ("image".equals(msgType)) { // 图片消息
                // todo 处理图片消息
            } else if ("voice".equals(msgType)) { //语音消息
                // todo 处理语音消息
            } else if ("video".equals(msgType)) { // 视频消息
                // todo 处理视频消息
            } else if ("shortvideo".equals(msgType)) { // 小视频消息
                // todo 处理小视频消息
            } else if ("location".equals(msgType)) { // 地理位置消息
                // todo 处理地理位置消息
            } else if ("link".equals(msgType)) { // 链接消息
                // todo 处理链接消息
            }
            // 事件推送
            else if ("event".equals(msgType)) { // 事件消息
                // 区分事件推送
                String event = encryptMap.get("Event");
                if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
                    return getString(encryptMap);
                } else if ("unsubscribe".equals(event)) { // 取消订阅事件
                    // todo 处理取消订阅事件
                } else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
                    return getString(encryptMap);
                } else if ("LOCATION".equals(event)) { // 上报地理位置事件
                    // todo 处理上报地理位置事件
                } else if ("CLICK".equals(event)) { // 点击菜单拉取消息时的事件推送事件
                    // todo 处理点击菜单拉取消息时的事件推送事件
                } else if ("VIEW".equals(event)) { // 点击菜单跳转链接时的事件推送
                    // todo 处理点击菜单跳转链接时的事件推送
                }
            }
        } catch (Exception e) {
            logger.error("处理微信公众号请求信息，失败", e);
        } finally {
            if (null != is) {
                is.close();
            }
            if (null != isr) {
                isr.close();
            }
            if (null != br) {
                br.close();
            }
        }
        return null;
    }

    private String getString(Map<String, String> encryptMap) throws Exception {
        // 返回消息时ToUserName的值与FromUserName的互换
        Map<String, String> returnMap = new HashMap<>();
        String content = "欢迎来到广誉源" + "\n" +
                "\n" +
                "广誉源是一家快速上门服务预约平台，提供正规 绿色 快捷上门服务，提供按摩、推拿、养生、SPA等服务，专业针对居家、差旅、酒店等顾客提供便捷健康养生服务";
        //添加新用户
        TWxUser fromUserName = wxUserService.getByOpenId(encryptMap.get("FromUserName"));
        if (fromUserName == null) {
            fromUserName = new TWxUser();
        }
        fromUserName.setcOpenid(encryptMap.get("FromUserName"));
        //fromUserName.setcUpUser(StringUtilsMassage.afterString(encryptMap.get("EventKey"), "qrscene_"));
        fromUserName.setRole(1);
        wxUserService.saveOrUpdate(fromUserName);
        //绑定技师
        TJs byId = jsService.getById(StringUtilsMassage.afterString(encryptMap.get("EventKey"), "qrscene_"));
        List<TJs> byOpenid = jsService.list(new LambdaQueryWrapper<TJs>().eq(TJs::getcOpenId, encryptMap.get("FromUserName")));
        if (CollectionUtil.isNotEmpty(byOpenid)) {
            content = "你已有绑定的账号如需换绑请先解绑";
        }
        if (StringUtils.isNotEmpty(byId.getcOpenId())) {
            content = "该账号已被绑定,请选择其他账号";
        } else if (CollectionUtil.isEmpty(byOpenid)) {
            TJs tJs = new TJs();
            tJs.setId(StringUtilsMassage.afterString(encryptMap.get("EventKey"), "qrscene_"));
            tJs.setcOpenId(encryptMap.get("FromUserName"));
            jsService.updateById(tJs);
        }
        returnMap.put("ToUserName", encryptMap.get("FromUserName"));
        returnMap.put("FromUserName", encryptMap.get("ToUserName"));
        returnMap.put("CreateTime", new Date().getTime() + "");
        returnMap.put("MsgType", "text");
        returnMap.put("Content", content);
        String encryptMsg = weChatUtil.mapToXml(returnMap).toString();
        return encryptMsg;
    }


    /**
     * 获取微信code
     *
     * @param state 状态参数
     * @return String
     */
    @ApiOperation("获取微信code")
    @Log(title = "获取微信code", businessType = BusinessType.OTHER)
    @GetMapping("/getCode")
    public String weiXinLogin(String state) {
        String code = weChatUtil.getCode(state);
        log.info("code的值:{}", code);
        redisCache.setCacheObject("code", state, 10, TimeUnit.MINUTES);
        return code;
    }

    /**
     * 获取token和userInfo
     *
     * @param code 微信授权码
     * @return R<WxLoginUser> 访问令牌
     */
    @GetMapping("/getAccessToken")
    @ApiOperation("公众号网页登录")
    public R<WxLoginUser> getAccessToken(@RequestParam String code) {
        // 发送get请求获取 AccessToken
        Map<?, ?> result = weChatUtil.getAccessToken(code);
        String accessToken = result.get(ACCESS_TOKEN).toString();
        String refreshToken = result.get(REFRESH_TOKEN).toString();
        String openid = result.get(OPEN_ID).toString();

        // 如果用户是第一次进行微信公众号授权
        // 进行这一步时用户应点击了同意授权按钮
        String userInfoJsom = weChatUtil.getUserInfo(accessToken, openid);
        // 解析JSON数据
        JSONObject jsonObject = new JSONObject(userInfoJsom);
        log.info("公众号网页登录：{}", jsonObject);
        // 将用户信息保存到数据库中
        LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        objectLambdaQueryWrapper.eq(TWxUser::getcOpenid, openid);
        TWxUser user = wxUserService.getOne(objectLambdaQueryWrapper);
        if (user == null || StringUtils.isEmpty(user.getcNickName())) {
            user = new TWxUser();
            user.setcOpenid(openid);
            user.setcNickName(jsonObject.get("nickname").toString());
            user.setSex((Integer) jsonObject.get("sex"));
            user.setcIcon(jsonObject.get("headimgurl").toString());
            user.setcSessionKey(refreshToken);
            wxUserService.saveOrUpdate(user);
            user.setId(user.getId());
        }

        WxLoginUser wxUser = new WxLoginUser();
        BeanUtils.copyProperties(user, wxUser);
        // 生成并返回令牌
        String token = wxTokenService.createToken(wxUser);
        log.info("生成的token值：{}", token);
        if (token == null || token.isEmpty()) {
            return R.fail("生成令牌失败");
        }
        wxUser.setToken(token);
        // 返回用户信息
        // 记录登录信息
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        return R.ok(wxUser);
    }

    /**
     * 刷新token，微信提供的token是有限时间的，但是对于财务报销系统仅需授权一次的情况下一般不需要进行更新
     *
     * @return accessToken
     */
    @GetMapping("/refreshToken")
    public String refreshToken() {

        WxLoginUser wxLoginUser = this.getWxLoginUser();
        TWxUser user = wxUserService.getByOpenId(wxLoginUser.getCOpenid());
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 发送get请求获取 RefreshToken
        Map<?, ?> result = weChatUtil.refreshToken(user.getcSessionKey());
        String accessToken = result.get(ACCESS_TOKEN).toString();
        String refreshToken = result.get(REFRESH_TOKEN).toString();
        // 更新用户信息
        user.setcSessionKey(refreshToken);
        // 存储数据库
        wxUserService.updateById(user);
        return accessToken;
    }

    /**
     * 获取服务号二维码
     *
     * @param openId
     * @return Map<?, ?> 包含二维码ticket的Map
     */
    @ApiOperation("获取服务号二维码")
    @RequestMapping(value = "getwxQrCode", method = RequestMethod.GET)
    public Map<?, ?> getWxQrCodeUtil(@RequestParam String openId) {
        try {
            //获取access_token
            String token = weChatUtil.getToken();
            //获取的二维码ticket
            return weChatUtil.getTicket(token, openId);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * @param jsId
     */
    @ApiOperation("获取JS公众号二维码ticket")
    @RequestMapping(value = "getJSwxQrCode", method = RequestMethod.GET)
    public void getJSwxQrCode(@RequestParam String jsId) {
        //获取access_token
        String token = weChatUtil.getToken();
        //获取的二维码ticket
        Map<?, ?> jsTicket = weChatUtil.getJsTicket(token, jsId);
        //获取的二维码ticket
        //获取二维码图片
        //String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
        //获取二维码图片
        //File file = QrCodeUtil.generate(qrCodeUrl, config, FileUtil.file(RuoYiConfig.getUploadPath() + "/code.png"));
        TJs tjs = new TJs();
        tjs.setId(jsId);
        tjs.setTicket(jsTicket.get("ticket").toString());
        jsService.updateById(tjs);
    }


    /**
     * 兑换技师公众号二维码
     *
     * @param ticket
     * @param id
     * @return String
     * @throws UnsupportedEncodingException
     */
    @ApiOperation("兑换技师公众号二维码")
    @RequestMapping(value = "getJSwxQrCodeDh", method = RequestMethod.GET)
    public String getJSwxQrCode1(@RequestParam String ticket, @RequestParam String id) throws UnsupportedEncodingException {

        String qrCodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + URLEncoder.encode(ticket, "UTF-8");
        String filePath = RuoYiConfig.getUploadEwmPath() + id + ".png";
        log.info("二维码地址：{}", filePath);

        try (InputStream in = new URL(qrCodeUrl).openStream();
             OutputStream out = Files.newOutputStream(Paths.get(filePath))) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        int lastSlashIndex = filePath.lastIndexOf("/");
        String fileName = filePath.substring(lastSlashIndex + 1);
        return Constants.RESOURCE_PREFIX + "/ewm/" + fileName;
    }


    @ApiOperation("获取公众号网页二维码")
    @GetMapping("/getweQrCode")
    public AjaxResult weiXinLogin1(String openId) {
        QrConfig config = new QrConfig(300, 300);
        // 设置边距，即二维码和背景之间的边距
        config.setMargin(1);
        // 生成二维码到文件，也可以到流
        String code = "https://www.baidu.com?openId=" + openId;
        log.info("code:{}", code);
        String str = IMG_PATH;
        File generate = QrCodeUtil.generate(code, config, FileUtil.file(RuoYiConfig.getUploadPath() + "/code.png"));

        MultipartFile multipartFile = FileUploadUtils.getMultipartFile(generate);
        return tbFileService.uploadFile(multipartFile);
    }

    /**
     * 发送验证码
     *
     * @param phone 手机号
     * @return R<?> 发送结果
     */
    @ApiOperation("发送绑定手机号验证码")
    @PostMapping("/sendBindPhoneCode")
    public R<?> sendBindPhoneCode(@RequestParam String phone) {
        if (StringUtils.isEmpty(phone)) {
            return R.fail("手机号不能为空");
        }
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            return R.fail("手机号格式不正确");
        }
        // 根据开关判断是否调用真实发送接口
        if (sendSmsEnabled) {
            // TODO: 调用真实发送验证码接口
            log.info("发送验证码到手机号: {}", phone);
        } else {
            // 使用写死的验证码
            log.info("发送验证码开关关闭，使用写死验证码: {}, 手机号: {}", fixedVerifyCode, phone);
        }
        return R.ok("验证码发送成功");
    }

    /**
     * 绑定手机号
     *
     * @param bindPhoneBody 绑定手机号请求参数
     * @return R<?> 绑定结果
     */
    @ApiOperation("绑定手机号")
    @PostMapping("/bindPhone")
    public R<?> bindPhone(@RequestBody BindPhoneBody bindPhoneBody) {
        String openId = bindPhoneBody.getOpenId();
        String phone = bindPhoneBody.getPhone();
        String code = bindPhoneBody.getCode();

        if (StringUtils.isEmpty(openId)) {
            return R.fail("openId不能为空");
        }
        if (StringUtils.isEmpty(phone)) {
            return R.fail("手机号不能为空");
        }
        if (StringUtils.isEmpty(code)) {
            return R.fail("验证码不能为空");
        }
        if (!phone.matches("^1[3-9]\\d{9}$")) {
            return R.fail("手机号格式不正确");
        }

        // 校验验证码
        if (!validateVerifyCode(phone, code)) {
            return R.fail("验证码错误");
        }

        // 查询当前用户
        TWxUser currentUser = wxUserService.getByOpenId(openId);
        if (currentUser == null) {
            return R.fail("用户不存在");
        }

        // 检查手机号是否已被其他用户绑定
        TWxUser existUser = wxUserService.getByPhone(phone);
        if (existUser != null && !existUser.getId().equals(currentUser.getId())) {
            return R.fail("手机号已被其他用户绑定");
        }

        // 如果该用户已经绑定过此手机号，直接返回成功（无变化）
        if (StringUtils.isNotEmpty(currentUser.getcPhone()) && currentUser.getcPhone().equals(phone)) {
            return R.ok("手机号已绑定，无需重复绑定");
        }

        // 绑定手机号
        boolean success = wxUserService.bindPhone(openId, phone);
        if (!success) {
            return R.fail("绑定失败");
        }
        log.info("用户openId: {} 绑定手机号: {} 成功", openId, phone);
        return R.ok("绑定成功");
    }

    /**
     * 校验验证码
     *
     * @param phone 手机号
     * @param code  用户输入的验证码
     * @return boolean 校验是否通过
     */
    private boolean validateVerifyCode(String phone, String code) {
        if (sendSmsEnabled) {
            // TODO: 从Redis或其他存储中获取真实发送的验证码进行校验
            // String realCode = redisCache.getCacheObject("sms:bindPhone:" + phone);
            // return code.equals(realCode);
            return true;
        } else {
            // 使用写死的验证码进行校验
            return fixedVerifyCode.equals(code);
        }
    }

    /**
     * 手机号登录
     *
     * @param phoneLoginBody 手机号登录请求参数
     * @return R<WxLoginUser> 登录结果
     */
    @ApiOperation("手机号登录")
    @PostMapping("/phoneLogin")
    //@Log(title = "手机号登录", businessType = BusinessType.OTHER)
    public R<WxLoginUser> phoneLogin(@RequestBody PhoneLoginBody phoneLoginBody) {
        String phone = phoneLoginBody.getPhone();
        String code = phoneLoginBody.getCode();

        // 校验验证码（验证码不为空且为6位数字在@Valid注解中已校验）
        if (StringUtils.isEmpty(code)) {
            return R.fail("验证码不能为空");
        }

        // 手机号登录获取用户
        TWxUser user = wxUserService.phoneLogin(phone);
        if (user == null) {
            return R.fail("登录失败");
        }

        // 构建WxLoginUser
        WxLoginUser wxUser = new WxLoginUser();
        BeanUtils.copyProperties(user, wxUser);

        // 生成并返回令牌
        String token = wxTokenService.createToken(wxUser);
        log.info("手机号登录生成的token值：{}", token);
        if (StringUtils.isEmpty(token)) {
            return R.fail("生成令牌失败");
        }
        wxUser.setToken(token);
        // 记录登录信息
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(phone, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        log.info("手机号: {} 登录成功", phone);
        return R.ok(wxUser);
    }

    /**
     * 发送短信验证码
     *
     * @param phone 手机号
     * @return R<String> 发送结果
     */
    @GetMapping("/sendMsg")
    @ApiOperation(value = "发送短信验证码", notes = "发送短信验证码")
    public R<String> sendMsg(@RequestParam String phone, HttpServletRequest request) {
        if (org.apache.commons.lang3.StringUtils.isEmpty(phone)) {
            return R.fail("手机号不能为空");
        }
        Random rand = new Random();
        // randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
        int randNumber = rand.nextInt(9999 - 1000 + 1) + 1000;
        // 保存验证码到redis
        redisCache.setCacheObject(PHONE_VERIFICATION_CODE_KEY + phone, String.valueOf(randNumber), PHONE_VERIFICATION_CODE_KEY_TIME, TimeUnit.MINUTES);
        try {
            SMSVerificationCode smsVerificationCode = new SMSVerificationCode(String.valueOf(randNumber));
            String jsonString = JSON.toJSONString(smsVerificationCode);
            sendSms.sendSms(phone, SendSmsEnum.SMS_220650024, jsonString);
            return R.ok("发送成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.fail("发送失败");
    }

    @ApiOperation("uuid登录")
    @PostMapping("/uuidLogin")
    @Log(title = "uuid登录", businessType = BusinessType.OTHER)
    public R<WxLoginUser> uuidLogin(@RequestBody PhoneLoginBody phoneLoginBody) {
        String uuid = phoneLoginBody.getUuid();

        if (StringUtils.isEmpty(uuid)) {
            return R.fail("uuid不能为空");
        }
        OneAccountVO oneAccountVO = this.unifiedUserCenterService.queryClients(phoneLoginBody.getUuid());
        if (ObjUtil.isNull(oneAccountVO)) {
            return R.fail("未查询到用户信息");
        }
        TWxUser user = wxUserService.getById(oneAccountVO.getUserId());
        if (ObjUtil.isNull(user)) {
            return R.fail("登录失败");
        }
        // 构建WxLoginUser
        WxLoginUser wxUser = new WxLoginUser();
        BeanUtils.copyProperties(user, wxUser);
        // 生成并返回令牌
        String token = wxTokenService.createToken(wxUser);
        log.info("uuid登录生成的token值：{}", token);
        if (StringUtils.isEmpty(token)) {
            return R.fail("生成令牌失败");
        }
        wxUser.setToken(token);
        // 记录登录信息
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(uuid, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        log.info("uuid: {} 登录成功", uuid);
        return R.ok(wxUser);
    }

}
