goupan
2024-04-14 ca931b87c7d7de8d3c75d6a4a5f0693d77420c8c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
package cn.stylefeng.roses.kernel.customer.modular.service.impl;
 
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.customer.api.OldPasswordValidateApi;
import cn.stylefeng.roses.kernel.customer.api.constants.CustomerConstants;
import cn.stylefeng.roses.kernel.customer.api.exception.CustomerException;
import cn.stylefeng.roses.kernel.customer.api.exception.enums.CustomerExceptionEnum;
import cn.stylefeng.roses.kernel.customer.api.expander.CustomerConfigExpander;
import cn.stylefeng.roses.kernel.customer.api.pojo.CustomerInfo;
import cn.stylefeng.roses.kernel.customer.api.pojo.CustomerInfoChangeAvatarPasswordRequest;
import cn.stylefeng.roses.kernel.customer.api.pojo.UserManagePageResponseDTO;
import cn.stylefeng.roses.kernel.customer.modular.entity.Customer;
import cn.stylefeng.roses.kernel.customer.modular.factory.CustomerFactory;
import cn.stylefeng.roses.kernel.customer.modular.mapper.CustomerMapper;
import cn.stylefeng.roses.kernel.customer.modular.request.CustomerRequest;
import cn.stylefeng.roses.kernel.customer.modular.service.CustomerService;
import cn.stylefeng.roses.kernel.db.api.factory.PageFactory;
import cn.stylefeng.roses.kernel.db.api.factory.PageResultFactory;
import cn.stylefeng.roses.kernel.db.api.pojo.page.PageResult;
import cn.stylefeng.roses.kernel.email.api.MailSenderApi;
import cn.stylefeng.roses.kernel.email.api.pojo.SendMailParam;
import cn.stylefeng.roses.kernel.file.api.FileOperatorApi;
import cn.stylefeng.roses.kernel.jwt.api.context.JwtContext;
import cn.stylefeng.roses.kernel.jwt.api.pojo.payload.DefaultJwtPayload;
import cn.stylefeng.roses.kernel.log.api.LoginLogServiceApi;
import cn.stylefeng.roses.kernel.rule.enums.*;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.rule.exception.enums.defaults.DefaultBusinessExceptionEnum;
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;
import cn.stylefeng.roses.kernel.security.api.DragCaptchaApi;
import cn.stylefeng.roses.kernel.security.api.ImageCaptchaApi;
import cn.stylefeng.roses.kernel.security.api.expander.SecurityConfigExpander;
import cn.stylefeng.roses.kernel.validator.api.exception.enums.ValidatorExceptionEnum;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
 
/**
 * C端用户表业务实现层
 *
 * @author fengshuonan
 * @date 2021/06/07 11:40
 */
@Service
@Slf4j
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {
 
    /**
     * 用于操作缓存时候加锁
     */
    private static final Object SESSION_OPERATE_LOCK = new Object();
 
    /**
     * 用于注册用户时候的加锁
     */
    private static final Object REG_LOCK = new Object();
 
    @Resource
    private MailSenderApi mailSenderApi;
 
    @Resource
    private PasswordStoredEncryptApi passwordStoredEncryptApi;
 
    @Resource
    private SessionManagerApi sessionManagerApi;
 
    @Resource
    private LoginLogServiceApi loginLogServiceApi;
 
    @Resource
    private CacheOperatorApi<CustomerInfo> customerInfoCacheOperatorApi;
 
    @Resource
    private FileOperatorApi fileOperatorApi;
 
    @Resource
    private DragCaptchaApi dragCaptchaApi;
 
    @Resource
    private OldPasswordValidateApi oldPasswordValidateApi;
 
    @Resource
    private ImageCaptchaApi imageCaptchaApi;
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reg(CustomerRequest customerRequest) {
 
        // 验证验证码
        this.validateCaptcha(customerRequest.getVerKey(), customerRequest.getVerCode());
 
        synchronized (REG_LOCK) {
            // 校验邮箱和账号是否重复
            validateRepeat(customerRequest);
 
            // 创建C端用户
            Customer regCustomer = CustomerFactory.createRegCustomer(customerRequest);
 
            // 保存用户
            this.save(regCustomer);
 
            // 发送邮箱验证码
            if (CustomerConfigExpander.getSendEmailFlag()) {
                try {
                    SendMailParam regEmailParam = CustomerFactory.createRegEmailParam(regCustomer.getEmail(), regCustomer.getVerifyCode());
                    mailSenderApi.sendMailHtml(regEmailParam);
                } catch (Exception exception) {
                    log.error("注册时,发送邮件失败!", exception);
                    throw new CustomerException(CustomerExceptionEnum.EMAIL_SEND_ERROR);
                }
            }
        }
    }
 
    @Override
    public void active(CustomerRequest customerRequest) {
        // 更新验证码的账号为激活状态
        LambdaUpdateWrapper<Customer> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Customer::getVerifiedFlag, YesOrNotEnum.Y.getCode());
        wrapper.eq(Customer::getVerifyCode, customerRequest.getVerifyCode());
        boolean result = this.update(wrapper);
        if (!result) {
            throw new CustomerException(CustomerExceptionEnum.ACTIVE_ERROR);
        }
    }
 
    @Override
    public LoginResponse login(LoginRequest loginRequest) {
 
        // 验证拖拽验证码
        this.validateCaptcha(loginRequest.getVerKey(), loginRequest.getVerCode());
 
        // 查询用户信息
        Wrapper<Customer> wrapper = Wrappers.<Customer>lambdaQuery()
                .eq(Customer::getUserType, CustomerUserTypeEnum.USER.getCode())
                .and(w -> w
                        .eq(Customer::getAccount, loginRequest.getAccount())
                        .or().eq(Customer::getEmail, loginRequest.getAccount())
                        .or().eq(Customer::getTelephone, loginRequest.getAccount())
                );
        Customer customer = this.getOne(wrapper, false);
        if (customer == null) {
            throw new CustomerException(CustomerExceptionEnum.CANT_FIND_CUSTOMER, loginRequest.getAccount());
        }
 
        // 如果开启了旧版密码,并且bcrypt密码是空
        if (CustomerConfigExpander.getOldPasswordValidate()
                && customer.getPassword().equals(CustomerConstants.DEFAULT_EMPTY_PASSWORD)) {
            if (!oldPasswordValidateApi.validatePassword(loginRequest.getPassword(), customer.getOldPassword(), customer.getOldPasswordSalt())) {
                throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
            }
        } else {
            // 校验用户密码
            Boolean passwordFlag = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), customer.getPassword());
            if (!passwordFlag) {
                throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
            }
        }
 
        // 组装返回结果
        return wrapperLoginResponse(customer, loginRequest);
    }
    @Override
    public LoginResponse wrapperLoginResponse(Customer customer, LoginRequest loginRequest) {
        // 不创建cookie,默认开启记住我(7天会话)
        loginRequest.setCreateCookie(loginRequest.getCreateCookie() != null ? loginRequest.getCreateCookie() : false);
        loginRequest.setRememberMe(loginRequest.getRememberMe() != null ? loginRequest.getRememberMe() :true);
 
        // 校验用户状态
        if (!StatusEnum.ENABLE.getCode().equals(customer.getStatusFlag())) {
            //throw new CustomerException(CustomerExceptionEnum.CUSTOMER_STATUS_ERROR, customer.getStatusFlag());
            throw new CustomerException(CustomerExceptionEnum.CUSTOMER_STATUS_ERROR, "");
        }
 
        // 校验用户是否激活
        if (!YesOrNotEnum.Y.getCode().equals(customer.getVerifiedFlag())) {
            throw new CustomerException(CustomerExceptionEnum.CUSTOMER_NOT_VERIFIED);
        }
 
        // 获取LoginUser,用于用户的缓存
        LoginUser loginUser = CustomerFactory.createLoginUser(customer, fileOperatorApi);
 
        // 生成用户的token
        DefaultJwtPayload defaultJwtPayload = new DefaultJwtPayload(loginUser.getUserId(), loginUser.getAccount(), loginRequest.getRememberMe(), null, null);
        String jwtToken = JwtContext.me().generateTokenDefaultPayload(defaultJwtPayload);
        loginUser.setToken(jwtToken);
 
        synchronized (SESSION_OPERATE_LOCK) {
            // 缓存用户信息,创建会话
            sessionManagerApi.createSession(jwtToken, loginUser, loginRequest.getCreateCookie());
 
            // 如果开启了单账号单端在线,则踢掉已经上线的该用户
            if (AuthConfigExpander.getSingleAccountLoginFlag()) {
                sessionManagerApi.removeSessionExcludeToken(jwtToken);
            }
        }
 
        // 更新用户ip和登录时间
        String ip = HttpServletUtil.getRequestClientIp(HttpServletUtil.getRequest());
        LambdaUpdateWrapper<Customer> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Customer::getCustomerId, loginUser.getUserId());
        updateWrapper.set(Customer::getLastLoginIp, ip);
        updateWrapper.set(Customer::getLastLoginTime, new Date());
        this.update(updateWrapper);
 
        // 登录成功日志
        loginLogServiceApi.loginSuccess(loginUser.getUserId());
 
        // 组装返回结果
        return new LoginResponse(loginUser, jwtToken, defaultJwtPayload.getExpirationDate());
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendResetPwdEmail(CustomerRequest customerRequest) {
 
        // 验证拖拽验证码
        this.validateCaptcha(customerRequest.getVerKey(), customerRequest.getVerCode());
 
        // 验证邮箱是否存在
        LambdaQueryWrapper<Customer> customerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        customerLambdaQueryWrapper.eq(Customer::getEmail, customerRequest.getEmail());
        Customer customer = this.getOne(customerLambdaQueryWrapper, false);
        if (customer == null) {
            throw new CustomerException(CustomerExceptionEnum.CANT_FIND_CUSTOMER, customerRequest.getEmail());
        }
 
        // 邮箱验证码
        String randomCode = RandomUtil.randomNumbers(6);
 
        // 存储到数据库验证码
        customer.setVerifyCode(randomCode);
        this.updateById(customer);
 
        // 发送邮箱验证码
        if (CustomerConfigExpander.getSendEmailFlag()) {
            SendMailParam resetPwdEmail = CustomerFactory.createResetPwdEmail(customerRequest.getEmail(), randomCode);
            mailSenderApi.sendMailHtml(resetPwdEmail);
        }
    }
 
    @Override
    public void resetPassword(CustomerRequest customerRequest) {
 
        // 检查校验码是否正确
        LambdaQueryWrapper<Customer> customerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        customerLambdaQueryWrapper.eq(Customer::getEmail, customerRequest.getEmail())
                .and(i -> i.eq(Customer::getVerifyCode, customerRequest.getVerifyCode()));
        Customer customer = this.getOne(customerLambdaQueryWrapper, false);
 
        // 如果不存在则为验证码错误
        if (customer == null) {
            throw new CustomerException(CustomerExceptionEnum.EMAIL_VERIFY_COD_ERROR);
        }
 
        // 根据请求密码,重置账号的密码
        String password = customerRequest.getPassword();
        String encrypt = passwordStoredEncryptApi.encrypt(password);
        customer.setPassword(encrypt);
        this.updateById(customer);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
    }
 
    @Override
    public void add(CustomerRequest customerRequest) {
        Customer customer = new Customer();
        BeanUtil.copyProperties(customerRequest, customer);
        this.save(customer);
    }
 
    @Override
    public void del(CustomerRequest customerRequest) {
        Customer customer = this.queryCustomer(customerRequest);
        this.removeById(customer.getCustomerId());
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
    }
 
    @Override
    public void edit(CustomerRequest customerRequest) {
        Customer customer = this.queryCustomer(customerRequest);
        BeanUtil.copyProperties(customerRequest, customer);
        this.updateById(customer);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
    }
 
    @Override
    public Customer detail(CustomerRequest customerRequest) {
        return this.queryCustomer(customerRequest);
    }
 
    @Override
    public PageResult<Customer> findPage(CustomerRequest customerRequest) {
        LambdaQueryWrapper<Customer> wrapper = createWrapper(customerRequest);
        Page<Customer> sysRolePage = this.page(PageFactory.defaultPage(), wrapper);
        return PageResultFactory.createPageResult(sysRolePage);
    }
 
    @Override
    public List<Customer> findList(CustomerRequest customerRequest) {
        LambdaQueryWrapper<Customer> wrapper = this.createWrapper(customerRequest);
        return this.list(wrapper);
    }
 
    @Override
    public void updatePassword(CustomerInfoChangeAvatarPasswordRequest customerInfoRequest) {
 
        CustomerRequest customerRequest = new CustomerRequest();
        customerRequest.setCustomerId(customerInfoRequest.getCustomerId());
        Customer customer = this.detail(customerRequest);
 
        // 校验旧密码是否正确
        Boolean passwordRightFlag = passwordStoredEncryptApi.checkPassword(customerInfoRequest.getOldPassword(), customer.getPassword());
 
        // 上一代密码校验md5
        boolean lastPasswordRightFlag = oldPasswordValidateApi.validatePassword(customerInfoRequest.getOldPassword(), customer.getOldPassword(), customer.getOldPasswordSalt());
 
        if (!passwordRightFlag && !lastPasswordRightFlag) {
            throw new CustomerException(CustomerExceptionEnum.PWD_ERROR);
        }
 
        // 更新密码
        String encryptPwd = passwordStoredEncryptApi.encrypt(customerInfoRequest.getNewPassword());
        customer.setPassword(encryptPwd);
 
        // 如果有上一代密码,则清空掉
        customer.setOldPassword(CustomerConstants.DEFAULT_EMPTY_PASSWORD);
        customer.setOldPasswordSalt(CustomerConstants.DEFAULT_EMPTY_PASSWORD);
 
        this.updateById(customer);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
    }
 
    @Override
    public void updateAvatar(CustomerInfoChangeAvatarPasswordRequest customerInfoRequest) {
 
        CustomerRequest customerRequest = new CustomerRequest();
        customerRequest.setCustomerId(customerInfoRequest.getCustomerId());
        Customer customer = this.detail(customerRequest);
 
//        // 根据id查询文件obj名称
//        SysFileInfoResponse fileInfo = fileInfoApi.getFileInfoWithoutContent(customerInfoRequest.getAvatar());
 
        // 更新头像
        customer.setAvatar(customerInfoRequest.getAvatar());
        customer.setAvatarObjectName(customerInfoRequest.getAvatar());
        this.updateById(customer);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
    }
 
    @Override
    public String updateSecret() {
        // 获取当前登录用户
        Long userId = LoginContext.me().getLoginUser().getUserId();
        return this.createOrUpdateCustomerSecret(userId);
    }
 
    @Override
    public String createOrUpdateCustomerSecret(Long customerId) {
        if (customerId == null) {
            return null;
        }
 
        // 重新生成秘钥
        String randomString = RandomUtil.randomString(32);
 
        // 秘钥过期时间24个月
        Date memberExpireTime = DateUtil.offset(new Date(), DateField.MONTH, 24);
 
        // 更新用户秘钥
        LambdaUpdateWrapper<Customer> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Customer::getSecretKey, randomString);
        wrapper.set(Customer::getMemberExpireTime, memberExpireTime);
        wrapper.eq(Customer::getCustomerId, customerId);
        this.update(wrapper);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customerId));
 
        return randomString;
    }
 
    @Override
    public CustomerInfo getCustomerInfoByKeyWords(String keyWords) {
        LambdaQueryWrapper<Customer> customerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        customerLambdaQueryWrapper.eq(Customer::getAccount, keyWords)
                .or().eq(Customer::getEmail, keyWords)
                .or().eq(Customer::getCustomerId, keyWords)
                .select(Customer::getCustomerId);
        Customer one = this.getOne(customerLambdaQueryWrapper, false);
        if (one == null) {
            return null;
        } else {
            return this.getCustomerInfoById(one.getCustomerId());
        }
    }
 
    @Override
    public CustomerInfo getCustomerInfoById(Long customerId) {
 
        // 查询缓存中有没有用户信息
        String customerIdKey = String.valueOf(customerId);
        CustomerInfo customerInfo = customerInfoCacheOperatorApi.get(customerIdKey);
        if (customerInfo != null) {
            return customerInfo;
        }
 
        // 获取C端用户详情
        Customer customer = this.getById(customerId);
        if (customer == null) {
            return null;
        }
 
        CustomerInfo result = new CustomerInfo();
        BeanUtil.copyProperties(customer, result);
 
//        // 获取头像的url
//        String fileAuthUrl = fileOperatorApi.getFileUnAuthUrl(
//                CustomerConfigExpander.getCustomerBucket(),
//                customer.getAvatarObjectName());
        result.setAvatarObjectUrl(customer.getAvatarObjectName());
 
        // 更新用户会员信息
        if (result.getMemberExpireTime() == null) {
            result.setMemberFlag(false);
        } else {
            if (DateUtil.compare(result.getMemberExpireTime(), new Date()) < 0) {
                result.setMemberFlag(false);
            } else {
                result.setMemberFlag(true);
            }
        }
 
        // 放入缓存用户信息
        customerInfoCacheOperatorApi.put(customerIdKey, result, CustomerConfigExpander.getCustomerCacheExpiredSeconds());
 
        return result;
    }
 
    @Override
    public CustomerInfo getCustomerInfoBySecretKey(String secretKey) {
 
        if (StrUtil.isEmpty(secretKey)) {
            return null;
        }
 
        // 先通过secretKey获取用户id
        LambdaQueryWrapper<Customer> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Customer::getSecretKey, secretKey);
        wrapper.select(Customer::getCustomerId);
        Customer customer = this.getOne(wrapper, false);
        if (customer == null) {
            return null;
        }
 
        // 再通过用户id,获取用户的信息
        return this.getCustomerInfoById(customer.getCustomerId());
    }
 
    @Override
    public void updateMemberExpiryDate(Long customerId, Date expiryDate) {
        LambdaUpdateWrapper<Customer> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Customer::getMemberExpireTime, expiryDate);
        wrapper.eq(Customer::getCustomerId, customerId);
        this.update(wrapper);
 
        // 清除缓存中的用户信息
        customerInfoCacheOperatorApi.remove(String.valueOf(customerId));
    }
 
    /**
     * 获取信息
     *
     * @author fengshuonan
     * @date 2021/06/07 11:40
     */
    private Customer queryCustomer(CustomerRequest customerRequest) {
        Customer customer = this.getById(customerRequest.getCustomerId());
        if (ObjectUtil.isEmpty(customer)) {
            throw new ServiceException(DefaultBusinessExceptionEnum.SYSTEM_RUNTIME_ERROR);
        }
        return customer;
    }
 
    /**
     * 创建查询wrapper
     *
     * @author fengshuonan
     * @date 2021/06/07 11:40
     */
    private LambdaQueryWrapper<Customer> createWrapper(CustomerRequest customerRequest) {
        LambdaQueryWrapper<Customer> queryWrapper = new LambdaQueryWrapper<>();
 
        Long customerId = customerRequest.getCustomerId();
        String account = customerRequest.getAccount();
        String password = customerRequest.getPassword();
        String nickName = customerRequest.getNickName();
        String email = customerRequest.getEmail();
        String telephone = customerRequest.getTelephone();
        String avatar = customerRequest.getAvatar();
        String avatarObjectName = customerRequest.getAvatarObjectName();
        Integer score = customerRequest.getScore();
 
        queryWrapper.eq(ObjectUtil.isNotNull(customerId), Customer::getCustomerId, customerId);
        queryWrapper.like(ObjectUtil.isNotEmpty(account), Customer::getAccount, account);
        queryWrapper.like(ObjectUtil.isNotEmpty(password), Customer::getPassword, password);
        queryWrapper.like(ObjectUtil.isNotEmpty(nickName), Customer::getNickName, nickName);
        queryWrapper.like(ObjectUtil.isNotEmpty(email), Customer::getEmail, email);
        queryWrapper.like(ObjectUtil.isNotEmpty(telephone), Customer::getTelephone, telephone);
        queryWrapper.eq(ObjectUtil.isNotNull(avatar), Customer::getAvatar, avatar);
        queryWrapper.like(ObjectUtil.isNotEmpty(avatarObjectName), Customer::getAvatarObjectName, avatarObjectName);
        queryWrapper.eq(ObjectUtil.isNotNull(score), Customer::getScore, score);
 
        return queryWrapper;
    }
 
    /**
     * 校验是否存在重复的账号和邮箱
     *
     * @author fengshuonan
     * @date 2021/6/7 21:43
     */
    private void validateRepeat(CustomerRequest customerRequest) {
        LambdaQueryWrapper<Customer> accountWrapper = new LambdaQueryWrapper<>();
        accountWrapper.eq(customerRequest.getUserType() != null, Customer::getUserType, customerRequest.getUserType());
        accountWrapper.eq(Customer::getAccount, customerRequest.getAccount());
        long count = this.count(accountWrapper);
        if (count > 0) {
            throw new CustomerException(CustomerExceptionEnum.ACCOUNT_REPEAT);
        }
 
        if (StrUtil.isNotEmpty(customerRequest.getTelephone())) {
            // 验证手机号是否重复
            LambdaQueryWrapper<Customer> phoneWrapper = new LambdaQueryWrapper<>();
            phoneWrapper.eq(customerRequest.getUserType() != null, Customer::getUserType, customerRequest.getUserType());
            phoneWrapper.eq(Customer::getTelephone, customerRequest.getTelephone());
            long phoneCount = this.count(phoneWrapper);
            if (phoneCount > 0) {
                throw new CustomerException(CustomerExceptionEnum.ACCOUNT_REPEAT);
            }
        }
 
        LambdaQueryWrapper<Customer> emailWrapper = new LambdaQueryWrapper<>();
        emailWrapper.eq(customerRequest.getUserType() != null, Customer::getUserType, customerRequest.getUserType());
        emailWrapper.eq(Customer::getEmail, customerRequest.getEmail());
        long emailCount = this.count(emailWrapper);
        if (emailCount > 0) {
            //throw new CustomerException(CustomerExceptionEnum.EMAIL_REPEAT);
        }
    }
 
    /**
     * 验证码是否正确
     *
     * @author fengshuonan
     * @date 2021/7/6 15:07
     */
    private void validateCaptcha(String verKey, String verCode) {
 
        // 如果开启了验证码校验,则验证当前请求的验证码是否正确
        if (SecurityConfigExpander.getCaptchaOpen()) {
            if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verCode)) {
                throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY);
            }
            if (!imageCaptchaApi.validateCaptcha(verKey, verCode)) {
                throw new AuthException(ValidatorExceptionEnum.CAPTCHA_ERROR);
            }
            return;
        }
 
        // 如果开启了拖拽验证码
        if (SecurityConfigExpander.getDragCaptchaOpen()) {
            if (StrUtil.isEmpty(verKey) || StrUtil.isEmpty(verCode)) {
                throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY);
            }
            if (!dragCaptchaApi.validateCaptcha(verKey, Convert.toInt(verCode))) {
                throw new AuthException(ValidatorExceptionEnum.DRAG_CAPTCHA_ERROR);
            }
        }
    }
 
    @Override
    public List<Customer> getWorkerListByLineStatusAndPost(String lineStatus, Integer postType, Integer postId, Integer workStatus) {
        return this.baseMapper.getWorkerListByLineStatusAndPostType(lineStatus, postType, postId, workStatus);
    }
 
    @Override
    public Customer randomWorkerByLineStatusAndPost(String lineStatus, Integer postType, Integer postId, Integer workStatus) {
        List<Customer> list = this.baseMapper.getWorkerListByLineStatusAndPostType(lineStatus, postType, postId, workStatus);
        if (CollUtil.isNotEmpty(list)) {
            return list.get(RandomUtil.randomInt(list.size()));
        }
        return null;
    }
 
    @Override
    public Long randomWorkerIdByLineStatusAndPost(String lineStatus, Integer postType, Integer postId, Integer workStatus) {
        // 获取指定在线状态,指定岗位的工作人员ID
        List<Long> list = this.baseMapper.getWorkerIdByLineStatusAndPostType(lineStatus, postType, postId, workStatus);
        if (CollUtil.isNotEmpty(list)) {
            // 随机一个工作人员ID
            return list.get(RandomUtil.randomInt(list.size()));
        }
        return null;
    }
 
    @Override
    public Long randomWorkerIdByLineStatusAndPostNeWorkerId(String lineStatus, Integer postType, Integer postId, Integer workStatus, Integer mentalAnalysisStatus, List<Long> eqWorkerIdList, List<Long> neWorkerIdList) {
        // 获取指定在线状态,指定岗位的工作人员ID
        List<Long> list = this.baseMapper.randomWorkerByLineStatusAndPostNeWorkerId(lineStatus, postType, postId, workStatus, mentalAnalysisStatus, eqWorkerIdList, neWorkerIdList);
        if (CollUtil.isNotEmpty(list)) {
            // 随机一个工作人员ID
            return list.get(RandomUtil.randomInt(list.size()));
        }
        return null;
    }
 
    @Override
    public boolean updateCustomerRemoveCache(Customer customer) {
        boolean update = this.updateById(customer);
        if (update) {
            // 清除缓存中的用户信息
            customerInfoCacheOperatorApi.remove(String.valueOf(customer.getCustomerId()));
        }
        return update;
    }
 
    @Override
    public boolean changeCustomerPhone(Long userId, String phone) {
        // 更新用户手机号
        Customer customerInfo = this.getById(userId);
        Assert.notNull(customerInfo, "用户信息错误");
        long count = this.count(
                Wrappers.<Customer>lambdaQuery()
                        .ne(Customer::getCustomerId, userId)
                        .eq(Customer::getAccount, phone)
                        .eq(Customer::getUserType, customerInfo.getUserType())
        );
        Assert.isTrue(count <= 0, "用户手机号已存在");
 
        Customer customer = new Customer();
        customer.setCustomerId(userId);
        customer.setAccount(phone);
        customer.setTelephone(phone);
 
        // 修改用户信息
        Boolean update = this.updateCustomerRemoveCache(customer);
        return update;
    }
 
    @Override
    public Page<UserManagePageResponseDTO> getCustomerPage(Page<Object> page, Integer userType, Long id, String name, String telephone, Integer statusFlag) {
        return this.baseMapper.getCustomerPage(page, userType, id, name, telephone, statusFlag);
    }
 
    @Override
    public Integer getCustomerMentalAnalysisStatus(Long customerId, String oldPostIds, String newPostIds) {
        if (StrUtil.isEmpty(oldPostIds) && customerId != null) {
            // 获取用户岗位
            CustomerInfo customerInfo = this.getCustomerInfoById(customerId);
            oldPostIds = customerInfo.getPostIds();
        }
 
        // 岗位不设置、无变动直接返回null
        if (StrUtil.isEmpty(newPostIds) || newPostIds.equals(oldPostIds)) {
            return null;
        }
 
        // 是否有岗位配置
        boolean noPost = true;
        String[] postIds = newPostIds.split(",");
        for (String pid : postIds) {
            if (pid.equals(PostIdEnum.PO_31.getCode() + "")) {
                noPost = false;
            }
        }
 
        return noPost ? CustomerMentalAnalysisStatusEnum.NO_POST.getCode() : CustomerMentalAnalysisStatusEnum.OFF_WORK.getCode();
    }
 
    @Override
    public String[] getBindWorkerPostIds(String workerNo, PostIdEnum post11Enum, PostIdEnum post21Enum) {
        // 获取顾问信息
        Customer worker = this.getOne(Wrappers.<Customer>lambdaQuery().eq(Customer::getWorkerNo, workerNo), false);
        Assert.notNull(worker, "没有找到对应的顾问工号:" + workerNo);
 
        // 工作人员岗位ID串
        String[] postIds = worker.getPostIds().split(",");
 
        // 幸福顾问
        String post11 = post11Enum.getCode().toString();
        // 咨询顾问
        String post21 = post21Enum.getCode().toString();
 
        // 判断岗位ID是否包含 幸福顾问 或 咨询顾问
        boolean containsPostId = Arrays.stream(postIds).anyMatch(postId -> post11.equals(postId) || post21.equals(postId));
        Assert.isTrue(containsPostId, "请绑定" + post11Enum.getName() + "或" + post21Enum.getName() + "工号!");
 
        return postIds;
    }
}