Browse Source

Merge branch 'feature/1204-tenant' into online

yuanliang 11 months ago
parent
commit
bafbd044ae
31 changed files with 1240 additions and 40 deletions
  1. 26 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java
  2. 1 1
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java
  3. 61 13
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantActivationCodeController.java
  4. 40 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumPurchaseController.java
  5. 84 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java
  6. 101 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/UserTenantBindRecordController.java
  7. 123 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenStudentController.java
  8. 91 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/UserTenantBindRecordVo.java
  9. 23 0
      cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/TenantActivationCodeVo.java
  10. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantActivationCode.java
  11. 4 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumPurchase.java
  12. 46 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserTenantBindRecord.java
  13. 2 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java
  14. 29 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantBindRecordMapper.java
  15. 43 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserTenantBindRecordService.java
  16. 24 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java
  17. 38 6
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java
  18. 24 5
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantActivationCodeServiceImpl.java
  19. 42 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantGroupServiceImpl.java
  20. 12 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantUnbindRecordServiceImpl.java
  21. 116 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantBindRecordServiceImpl.java
  22. 6 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantActivationCodeWrapper.java
  23. 12 3
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantAlbumPurchaseWrapper.java
  24. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantGroupWrapper.java
  25. 3 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantInfoWrapper.java
  26. 151 0
      cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserTenantBindRecordWrapper.java
  27. 4 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantActivationCodeMapper.xml
  28. 16 8
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantAlbumPurchaseMapper.xml
  29. 1 1
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantGroupMapper.xml
  30. 3 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantInfoMapper.xml
  31. 107 0
      cooleshow-user/user-biz/src/main/resources/config/mybatis/UserTenantBindRecordMapper.xml

+ 26 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/StudentController.java

@@ -7,10 +7,12 @@ import com.yonge.cooleshow.biz.dal.dto.VipSubmitReq;
 import com.yonge.cooleshow.biz.dal.dto.search.StudentSearch;
 import com.yonge.cooleshow.biz.dal.dto.search.VipRecordSearch;
 import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.TenantActivationCode;
 import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
 import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
 import com.yonge.cooleshow.biz.dal.service.MemberPriceSettingsService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
 import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.service.VipCardRecordService;
 import com.yonge.cooleshow.biz.dal.vo.StudentVo;
@@ -48,6 +50,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -73,6 +76,9 @@ public class StudentController extends BaseController {
     @Autowired
     private TenantGroupService tenantGroupService;
 
+    @Autowired
+    private TenantActivationCodeService tenantActivationCodeService;
+
     @GetMapping("/detail/{id}")
     @ApiOperation(value = "详情", notes = "传入id")
     @ApiImplicitParams({
@@ -113,6 +119,25 @@ public class StudentController extends BaseController {
         IPage<StudentVo> pages = studentService.selectPage(PageUtil.getPage(query), query);
         List<StudentVo> rows = pages.getRecords();
 
+        //如果真实姓名字段为空 把真实姓名赋值给昵称
+        rows.forEach(r -> {
+            if (StringUtils.isEmpty(r.getRealName())) {
+                if (StringUtils.isNotEmpty(r.getUsername())) {
+                    r.setRealName(r.getUsername());
+                }
+            }
+        });
+
+        Map<String, List<TenantActivationCode>> groupByPhone = new HashMap<>();
+        if (!rows.isEmpty() && query.getTenantAlbumPurchaseId() != null) {
+            List<String> studentPhones =
+                    rows.stream().map(StudentVo::getPhone).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+            groupByPhone = tenantActivationCodeService.lambdaQuery()
+                    .eq(TenantActivationCode::getTenantAlbumPurchaseId, query.getTenantAlbumPurchaseId())
+                    .in(TenantActivationCode::getActivationPhone, studentPhones)
+                    .list().stream().collect(Collectors.groupingBy(TenantActivationCode::getActivationPhone));
+        }
+
         List<Long> tenantGroupIds = rows.stream().map(Student::getTenantGroupId)
                 .filter(next -> next != null && next != -1L).distinct().collect(Collectors.toList());
         Map<Long, String> tenantGroupIdNameMap = new HashMap<>();
@@ -125,6 +150,7 @@ public class StudentController extends BaseController {
 
 
         for (StudentVo vo : rows) {
+            vo.setSendActiveCodeNum(groupByPhone.getOrDefault(vo.getPhone(), new ArrayList<>()).size());
             if (vo.getDelFlag() == YesOrNoEnum.YES) {
                 vo.setUserStatus(UserStatusEnum.CLOSED);
             } else {

+ 1 - 1
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TeacherController.java

@@ -163,7 +163,7 @@ public class TeacherController extends BaseController {
     }
 
     @PostMapping("/updateTenant")
-    @ApiOperation(value = "新增或修改", notes = "传入teacher")
+    @ApiOperation(value = "新增或修改机构", notes = "传入teacher")
     @PreAuthorize("@pcs.hasPermissions('teacher/updateTenant')")
     public HttpResponseResult<Boolean> updateTenant(@Valid @RequestBody TeacherWrapper.UpdateTenant updateTenant) {
         SysUser sysUser = sysUserFeignService.queryUserInfo();

+ 61 - 13
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantActivationCodeController.java

@@ -1,27 +1,38 @@
 package com.yonge.cooleshow.admin.controller;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
 import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.entity.TenantActivationCode;
 import com.yonge.cooleshow.biz.dal.entity.TenantAlbumPurchase;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
 import com.yonge.cooleshow.biz.dal.service.TenantActivationCodeService;
 import com.yonge.cooleshow.biz.dal.service.TenantAlbumPurchaseService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantActivationCodeWrapper;
 import com.yonge.cooleshow.common.controller.BaseController;
 import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.tenant.vo.TenantActivationCodeVo;
 import com.yonge.toolset.base.exception.BizException;
-import com.yonge.toolset.base.page.PageInfo;
 import com.yonge.toolset.mybatis.support.PageUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
 
 @Slf4j
 @Validated
@@ -36,32 +47,69 @@ public class TenantActivationCodeController extends BaseController {
     @Autowired
     private TenantAlbumPurchaseService tenantAlbumPurchaseService;
 
+    @Autowired
+    private TenantInfoService tenantInfoService;
 
     @ApiOperation(value = "查询分页", notes = "机构激活码- 传入 TenantActivationCodeVo.TenantActivationCodeQuery")
     @PostMapping("/page")
+    @PreAuthorize("@pcs.hasPermissions('tenantActivationCode/page')")
     public HttpResponseResult<PageInfo<TenantActivationCodeWrapper.TenantActivationCode>> page(
             @RequestBody TenantActivationCodeWrapper.TenantActivationCodeQuery query) {
 
-        if (StringUtils.isBlank(query.getOrderNo())) {
-            throw new BizException("订单号不能为空");
+        String activationTime = query.getActivationTime();
+        if (StringUtils.isNotEmpty(activationTime)) {
+            Date parse = new SimpleDateFormat("yyyy-MM").parse(activationTime, new ParsePosition(0));
+            query.setActivationStartTime(parse);
+            Calendar instance = Calendar.getInstance();
+            instance.setTime(parse);
+            instance.add(Calendar.MONTH, 1);
+            instance.add(Calendar.DATE, -1);
+            instance.set(Calendar.HOUR_OF_DAY, 23);
+            instance.set(Calendar.MINUTE, 59);
+            instance.set(Calendar.MILLISECOND, 59);
+            query.setActivationEndTime(instance.getTime());
         }
-        // 查询订单购买的专辑
-        TenantAlbumPurchase albumPurchase = tenantAlbumPurchaseService.getByOrderNo(query.getOrderNo());
-        if (albumPurchase == null) {
-            return succeed(new PageInfo<>());
-        }
-        query.setActivationStatus(true);
-        query.setTenantAlbumPurchaseId(albumPurchase.getId());
-        // 查询数据
         IPage<TenantActivationCodeWrapper.TenantActivationCode> pages =
                 tenantActivationCodeService.selectPage(QueryInfo.getPage(query), query);
-        PageInfo<TenantActivationCodeWrapper.TenantActivationCode> pageInfo = PageUtil.pageInfo(pages);
+        com.microsvc.toolkit.common.response.paging.PageInfo<TenantActivationCodeWrapper.TenantActivationCode> pageInfo = QueryInfo.pageInfo(pages,
+                pages.getRecords());
 
         if (query.getTenantAlbumPurchaseId() != null) {
-            pageInfo.setStatInfo(albumPurchase);
+            TenantActivationCodeWrapper.TenantActivationCode extra =
+                    new TenantActivationCodeWrapper.TenantActivationCode();
+            TenantAlbumPurchase purchase = tenantAlbumPurchaseService.getById(query.getTenantAlbumPurchaseId());
+            extra.setActiveQuantity(purchase.getActiveQuantity());
+            pageInfo.setExtra(extra);
         }
 
         return succeed(pageInfo);
     }
 
+    @ApiOperation(value = "激活码发放", notes = "机构激活码- 传入 TenantActivationCodeVo.TenantActivationCodeSend")
+    @PostMapping("/send")
+    @PreAuthorize("@pcs.hasPermissions('tenantActivationCode/send')")
+    public HttpResponseResult<Boolean> send(@Validated @RequestBody TenantActivationCodeVo.TenantActivationCodeSend send) {
+        tenantActivationCodeService.sendActivationCode(send.getTenantId(), send.getTenantAlbumPurchaseId(),
+                send.getActivationCodeList(),
+                send.getStudentIdList());
+        return succeed();
+    }
+
+    @ApiOperation(value = "激活码重发", notes = "机构激活码- 传入 TenantActivationCodeVo.TenantActivationCodeSend")
+    @PostMapping("/resend")
+    @PreAuthorize("@pcs.hasPermissions('tenantActivationCode/resend')")
+    public HttpResponseResult<Boolean> resend(@Validated @RequestBody TenantActivationCodeVo.TenantActivationCodeResend send) {
+        tenantActivationCodeService.resend(send.getCode(), send.getUserId(), send.getTenantId(), send.getTenantAlbumPurchaseId());
+        return succeed();
+    }
+
+    @ApiOperation(value = "激活码发放取消", notes = "传入 激活码的ID")
+    @PostMapping("/sendCancel")
+    @PreAuthorize("@pcs.hasPermissions('tenantActivationCode/sendCancel')")
+    public HttpResponseResult<Boolean> sendCancel(@Validated @RequestBody TenantActivationCodeVo.CodeSend codeSend) {
+        TenantActivationCode activationCode = tenantActivationCodeService.getById(codeSend.getId());
+        TenantInfo tenantInfo = tenantInfoService.getById(codeSend.getTenantId());
+        tenantActivationCodeService.sendCancel(tenantInfo, activationCode);
+        return succeed();
+    }
 }

+ 40 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantAlbumPurchaseController.java

@@ -0,0 +1,40 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.biz.dal.service.TenantAlbumPurchaseService;
+import com.yonge.cooleshow.biz.dal.wrapper.TenantAlbumPurchaseWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.admin:}/tenantAlbumPurchase")
+@Api(tags = "机构专辑采购")
+public class TenantAlbumPurchaseController extends BaseController {
+
+    @Autowired
+    private TenantAlbumPurchaseService tenantAlbumPurchaseService;
+
+    @ApiOperation(value = "查询分页", notes = "机构专辑采购- 传入 TenantAlbumPurchaseVo.TenantAlbumPurchaseQuery")
+    @PostMapping("/page")
+    public HttpResponseResult<PageInfo<TenantAlbumPurchaseWrapper.TenantAlbumPurchase>> page(
+            @RequestBody TenantAlbumPurchaseWrapper.TenantAlbumPurchaseQuery query) {
+        // 查询数据
+        IPage<TenantAlbumPurchaseWrapper.TenantAlbumPurchase> pages =
+                tenantAlbumPurchaseService.selectPage(QueryInfo.getPage(query), query);
+        return succeed(QueryInfo.pageInfo(pages, pages.getRecords()));
+    }
+}

+ 84 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/TenantGroupController.java

@@ -1,21 +1,39 @@
 package com.yonge.cooleshow.admin.controller;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.microsvc.toolkit.common.response.paging.PageInfo;
 import com.microsvc.toolkit.common.response.paging.QueryInfo;
 import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.ImGroup;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.TenantGroupService;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantGroupWrapper;
+import com.yonge.cooleshow.tenant.vo.TenantGroupVo;
+import com.yonge.toolset.base.exception.BizException;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Slf4j
 @Validated
 @RestController
@@ -26,6 +44,12 @@ public class TenantGroupController {
     @Autowired
     private TenantGroupService tenantGroupService;
 
+    @Resource
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private ImGroupService imGroupService;
+
     @ApiOperation(value = "查询分页", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroupQuery")
     @PreAuthorize("@pcs.hasPermissions('tenantGroup/page', {'BACKEND'})")
     @PostMapping("/page")
@@ -40,4 +64,64 @@ public class TenantGroupController {
         return R.from(tenantGroupService.adjustTenantGroup(adjustTenantGroup));
     }
 
+    @ApiOperation(value = "详情", notes = "机构小组表-根据详情ID查询单条, 传入id")
+    @GetMapping("/detail/{id}")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/detail')")
+    public R<TenantGroupWrapper.TenantGroup> detail(@PathVariable("id") Long id) {
+        TenantGroup wrapper = tenantGroupService.detail(id);
+        if (wrapper == null) {
+            return R.from(new TenantGroupWrapper.TenantGroup());
+        }
+        TenantGroupWrapper.TenantGroup group = TenantGroupWrapper.TenantGroup.from(JSON.toJSONString(wrapper));
+        group.setImGroupExist(false);
+        if (StringUtils.isNotEmpty(wrapper.getImGroupId())) {
+            ImGroup imGroup = imGroupService.getById(wrapper.getImGroupId());
+            if (imGroup != null) {
+                group.setImGroupExist(true);
+            }
+        }
+        List<TenantGroupWrapper.TenantGroupMember> members =
+                tenantGroupService.queryGroupMember(wrapper.getTenantId(), id);
+        List<Long> userIds = members.stream().map(TenantGroupWrapper.TenantGroupMember::getUserId)
+                .collect(Collectors.toList());
+        group.setUserIds(userIds);
+        group.setGroupUserCount(members.size());
+        group.setUserList(members);
+        return R.from(group);
+    }
+
+    @ApiOperation(value = "新增", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroup")
+    @PostMapping("/save")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/save')")
+    public R<JSONObject> add(@Validated @RequestBody TenantGroupVo.TenantGroup tenantGroup) {
+        Long tenantId = tenantGroup.getTenantId();
+        if (tenantId == null) {
+            throw new BizException("机构ID不能为空");
+        }
+        SysUser sysUser = sysUserFeignService.queryUserInfo();
+        TenantGroupWrapper.TenantGroup group = TenantGroupWrapper.TenantGroup.from(tenantGroup.jsonString());
+        group.setCreateBy(sysUser.getId());
+        // 新增数据
+        tenantGroupService.add(group, tenantGroup.getImGroupCreate());
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "修改", notes = "机构小组表- 传入 TenantGroupWrapper.TenantGroup")
+    @PostMapping("/update")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/update')")
+    public R<JSONObject> update(@Validated @RequestBody TenantGroupVo.TenantGroup tenantGroup) {
+        // 更新数据
+        tenantGroupService.update(TenantGroupWrapper.TenantGroup.from(tenantGroup.jsonString()), tenantGroup.getImGroupCreate());
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "删除", notes = "机构小组表- 传入id")
+    @PostMapping("/remove")
+    @PreAuthorize("@pcs.hasPermissions('tenantGroup/remove')")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(tenantGroupService.delete(id));
+    }
 }

+ 101 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/UserTenantBindRecordController.java

@@ -0,0 +1,101 @@
+package com.yonge.cooleshow.admin.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.microsvc.toolkit.common.response.paging.PageInfo;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.microsvc.toolkit.common.response.template.R;
+import com.yonge.cooleshow.admin.io.request.UserTenantBindRecordVo;
+import com.yonge.cooleshow.biz.dal.entity.UserTenantBindRecord;
+import com.yonge.cooleshow.biz.dal.service.UserTenantBindRecordService;
+import com.yonge.cooleshow.biz.dal.wrapper.UserTenantBindRecordWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+
+
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("${app-config.url.admin:}/userTenantBindRecord")
+@Api(tags = "用户机构绑定解绑记录")
+public class UserTenantBindRecordController extends BaseController {
+
+    @Autowired
+    private UserTenantBindRecordService userTenantBindRecordService;
+
+    @ApiOperation(value = "详情", notes = "用户机构绑定解绑记录-根据详情ID查询单条, 传入id")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
+    })
+    @PreAuthorize("@pcs.hasPermissions('userTenantBindRecord/detail', {'BACKEND'})")
+//    @GetMapping("/detail/{id}")
+    public R<UserTenantBindRecordVo.UserTenantBindRecord> detail(@PathVariable("id") Long id) {
+
+        UserTenantBindRecord wrapper = userTenantBindRecordService.detail(id);
+
+        return R.from(UserTenantBindRecordVo.UserTenantBindRecord.from(JSON.toJSONString(wrapper)));
+    }
+
+    @ApiOperation(value = "查询分页", notes = "用户机构绑定解绑记录- 传入 UserTenantBindRecordVo.UserTenantBindRecordQuery")
+    @PreAuthorize("@pcs.hasPermissions('userTenantBindRecord/page', {'BACKEND'})")
+    @PostMapping("/page")
+    public R<PageInfo<UserTenantBindRecordWrapper.UserTenantBindRecord>> page(@RequestBody UserTenantBindRecordWrapper.UserTenantBindRecordQuery query) {
+
+        if (query.getTenantId() == null || StringUtils.isEmpty(query.getUserType())) {
+            throw new BizException("参数错误");
+        }
+        // 查询数据
+        IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> pages = userTenantBindRecordService.selectPage(QueryInfo.getPage(query), query);
+        return R.from(QueryInfo.pageInfo(pages, pages.getRecords()));
+    }
+
+    @ApiOperation(value = "新增", notes = "用户机构绑定解绑记录- 传入 UserTenantBindRecordVo.UserTenantBindRecord")
+    @PreAuthorize("@pcs.hasPermissions('userTenantBindRecord/save', {'BACKEND'})")
+//    @PostMapping("/save")
+    public R<JSONObject> add(@Validated @RequestBody UserTenantBindRecordVo.UserTenantBindRecord userTenantBindRecordVo) {
+
+        // 新增数据
+        userTenantBindRecordService.save(JSON.parseObject(userTenantBindRecordVo.jsonString(), UserTenantBindRecord.class));
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "修改", notes = "用户机构绑定解绑记录- 传入 UserTenantBindRecordVo.UserTenantBindRecord")
+    @PreAuthorize("@pcs.hasPermissions('userTenantBindRecord/update', {'BACKEND'})")
+//    @PostMapping("/update")
+    public R<JSONObject> update(@Validated @RequestBody UserTenantBindRecordVo.UserTenantBindRecord userTenantBindRecordVo) {
+
+        // 更新数据
+        userTenantBindRecordService.updateById(JSON.parseObject(userTenantBindRecordVo.jsonString(), UserTenantBindRecord.class));
+
+        return R.defaultR();
+    }
+
+    @ApiOperation(value = "删除", notes = "用户机构绑定解绑记录- 传入id")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "id", dataType = "long")
+    })
+    @PreAuthorize("@pcs.hasPermissions('userTenantBindRecord/remove', {'BACKEND'})")
+//    @PostMapping("/remove")
+    public R<Boolean> remove(@RequestParam Long id) {
+
+        return R.from(userTenantBindRecordService.removeById(id));
+    }
+}

+ 123 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/controller/open/OpenStudentController.java

@@ -0,0 +1,123 @@
+package com.yonge.cooleshow.admin.controller.open;
+
+import com.alibaba.fastjson.JSON;
+import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
+import com.yonge.cooleshow.auth.api.entity.SysUser;
+import com.yonge.cooleshow.biz.dal.entity.Student;
+import com.yonge.cooleshow.biz.dal.entity.TenantGroup;
+import com.yonge.cooleshow.biz.dal.entity.TenantInfo;
+import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
+import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
+import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
+import com.yonge.cooleshow.biz.dal.service.ImGroupService;
+import com.yonge.cooleshow.biz.dal.service.ImUserFriendService;
+import com.yonge.cooleshow.biz.dal.service.SmsCodeService;
+import com.yonge.cooleshow.biz.dal.service.StudentService;
+import com.yonge.cooleshow.biz.dal.service.TeacherService;
+import com.yonge.cooleshow.biz.dal.service.TenantInfoService;
+import com.yonge.cooleshow.biz.dal.wrapper.StudentWrapper;
+import com.yonge.cooleshow.common.controller.BaseController;
+import com.yonge.cooleshow.common.entity.HttpResponseResult;
+import com.yonge.cooleshow.tenant.vo.StudentVo;
+import com.yonge.toolset.base.exception.BizException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Objects;
+
+@Slf4j
+@RestController
+@RequestMapping("${app-config.url.admin:}/open/student")
+@Api(value = "学生表", tags = "学生表")
+public class OpenStudentController extends BaseController {
+    @Autowired
+    private StudentService studentService;
+
+    @Autowired
+    private TenantInfoService tenantInfoService;
+
+    @Autowired
+    private SysUserFeignService sysUserFeignService;
+
+    @Autowired
+    private SmsCodeService smsCodeService;
+
+
+    @Autowired
+    private TenantGroupMapper tenantGroupMapper;
+
+    @PostMapping("/save")
+    @ApiOperation(value = "新增/修改", notes = "传入Student,换绑时按照返回错误码5004判断,是否需要换绑,updateTenant=true表示换绑")
+    public HttpResponseResult<Boolean> save(@Validated @RequestBody StudentVo.Student student) {
+        String code = student.getCode();
+        if (StringUtils.isEmpty(code)) {
+            throw new BizException("验证码不能为空");
+        }
+        if (!smsCodeService.verifyValidCode(student.getPhone(), code, "REGISTER")) {
+            throw new BizException("验证码错误");
+        }
+        Long tenantId = student.getTenantId();
+        if (tenantId == null) {
+            throw new BizException("未指定机构");
+        }
+        TenantInfo tenantInfo = tenantInfoService.getById(tenantId);
+        if (tenantInfo == null) {
+            throw new BizException("机构不存在");
+        }
+        Long tenantGroupId = student.getTenantGroupId();
+        TenantGroup tenantGroup = tenantGroupMapper.selectById(tenantGroupId);
+        if (tenantGroup == null) {
+            throw new BizException("该链接已失效");
+        }
+        Long studentId = student.getId();
+
+        if (studentId == null) {
+            SysUser sysUser = sysUserFeignService.queryUserByMobile(student.getPhone());
+            if (sysUser != null && sysUser.getUserType().contains(ClientEnum.STUDENT.getCode())) {
+                studentId = sysUser.getId();
+            }
+        }
+
+        if (studentId != null) {
+            Student one = studentService.lambdaQuery()
+                    .eq(Student::getUserId, studentId)
+                    .last("limit 1").one();
+            if (one != null) {
+                if (one.getTenantId().equals(-1L)) {
+                    throw new BizException("该手机号已经注册为平台学生");
+                }
+                if (one.getTenantId().equals(tenantId)) {
+                    //已经注册当前机构,请勿重复注册
+                    throw new BizException("已经注册当前机构,请勿重复注册");
+                }
+                // 转到其他机构
+                if ((!Objects.equals(student.getTenantId(), one.getTenantId()))) {
+                    if (student.getUpdateTenant() == null || Boolean.FALSE.equals(student.getUpdateTenant())) {
+                        TenantInfo oldTenant = tenantInfoService.getById(one.getTenantId());
+                        throw new BizException(5004, oldTenant.getName());
+                    }
+                }
+
+                // 更新头像
+                if (StringUtils.isEmpty(student.getAvatar())) {
+                    student.setAvatar(one.getAvatar());
+                }
+            }
+            student.setId(studentId);
+        }
+
+        StudentWrapper.Student studentInfo = JSON.parseObject(JSON.toJSONString(student), StudentWrapper.Student.class);
+        studentInfo.setTenantId(tenantInfo.getId());
+
+        studentService.save(studentInfo);
+        return succeed();
+    }
+}

+ 91 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/admin/io/request/UserTenantBindRecordVo.java

@@ -0,0 +1,91 @@
+package com.yonge.cooleshow.admin.io.request;
+
+import com.alibaba.fastjson.JSON;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.common.enums.ESettlementFrom;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+
+import lombok.Data;
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+@ApiModel(value = "UserTenantBindRecordVo对象", description = "用户机构绑定解绑记录查询视图对象")
+public class UserTenantBindRecordVo {
+
+    @Data
+    @ApiModel(" UserTenantBindRecordQuery-用户机构绑定解绑记录")
+    public static class UserTenantBindRecordQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static UserTenantBindRecordQuery from(String json) {
+            return JSON.parseObject(json, UserTenantBindRecordQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" UserTenantBindRecord-用户机构绑定解绑记录")
+    public static class UserTenantBindRecord {
+
+
+        @ApiModelProperty("")
+        private Long id;
+
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+
+        @ApiModelProperty("TEACHER:老师,STUDENT:学生")
+        private String userType;
+
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+
+        @ApiModelProperty("绑定状态:1:已绑定,0:未绑定")
+        private Boolean bindStatus;
+
+
+        @ApiModelProperty("绑定/解绑最新时间")
+        private Date bindTime;
+
+        @ApiModelProperty("姓名")
+        private String userName;
+
+        @ApiModelProperty("手机号")
+        private String phone;
+
+        @ApiModelProperty("小组名称")
+        private String tenantGroupName;
+
+        @ApiModelProperty("结算方式")
+        private ESettlementFrom settlementFrom;
+
+        @ApiModelProperty("锁定状态")
+        private Boolean lockFlag;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static UserTenantBindRecord from(String json) {
+            return JSON.parseObject(json, UserTenantBindRecord.class);
+        }
+    }
+
+}

+ 23 - 0
cooleshow-app/src/main/java/com/yonge/cooleshow/tenant/vo/TenantActivationCodeVo.java

@@ -27,6 +27,9 @@ public class TenantActivationCodeVo {
         @NotNull(message = "专辑购买记录的ID不能为空")
         private Long tenantAlbumPurchaseId;
 
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
         @ApiModelProperty("激活码列表,批量发送时为空")
         private List<String> activationCodeList = new ArrayList<>();
 
@@ -45,6 +48,9 @@ public class TenantActivationCodeVo {
         @NotNull(message = "专辑购买记录的ID不能为空")
         private Long tenantAlbumPurchaseId;
 
+        @ApiModelProperty("结构ID")
+        private Long tenantId;
+
         @ApiModelProperty("激活码")
         @NotBlank(message = "激活码不能为空")
         private String code;
@@ -107,6 +113,9 @@ public class TenantActivationCodeVo {
         @ApiModelProperty("创建时间")
         private Date createTime;
 
+        @ApiModelProperty("发放时间")
+        private Date sendTime;
+
 
         public String jsonString() {
             return JSON.toJSONString(this);
@@ -117,4 +126,18 @@ public class TenantActivationCodeVo {
         }
     }
 
+    @Data
+    @ApiModel("激活码发放")
+    public static class CodeSend {
+
+        @ApiModelProperty("机构ID")
+        @NotNull
+        private Long tenantId;
+
+        @ApiModelProperty("激活码ID")
+        @NotNull
+        private Long id;
+
+    }
+
 }

+ 4 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantActivationCode.java

@@ -72,4 +72,8 @@ public class TenantActivationCode implements Serializable {
 	@TableField(value = "create_time_")
     private Date createTime;
 
+    @ApiModelProperty("发放时间")
+	@TableField(value = "send_time_")
+    private Date sendTime;
+
 }

+ 4 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/TenantAlbumPurchase.java

@@ -65,6 +65,10 @@ public class TenantAlbumPurchase implements Serializable {
 	@TableField(value = "purchase_status_")
     private String purchaseStatus;
 
+    @ApiModelProperty("激活状态:NONE:未激活,PART:部分,ALL:全部")
+	@TableField(value = "active_status_")
+    private String activeStatus;
+
     @ApiModelProperty("更新时间") 
 	@TableField(value = "update_time_")
     private Date updateTime;

+ 46 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/entity/UserTenantBindRecord.java

@@ -0,0 +1,46 @@
+package com.yonge.cooleshow.biz.dal.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+@Data
+@ApiModel(" UserTenantBindRecord-用户机构绑定解绑记录")
+@TableName("user_tenant_bind_record")
+public class UserTenantBindRecord implements Serializable {
+
+    @TableId(value = "id_")
+    private Long id;
+
+    @ApiModelProperty("用户ID")
+    @TableField(value = "user_id_")
+    private Long userId;
+
+    @ApiModelProperty("TEACHER:老师,STUDENT:学生")
+    @TableField(value = "user_type_")
+    private String userType;
+
+    @ApiModelProperty("机构ID")
+    @TableField(value = "tenant_id_")
+    private Long tenantId;
+
+    @ApiModelProperty("绑定状态:1:已绑定,0:未绑定")
+    @TableField(value = "bind_status_")
+    private Boolean bindStatus;
+
+    @ApiModelProperty("绑定/解绑最新时间")
+    @TableField(value = "bind_time_")
+    private Date bindTime;
+
+}

+ 2 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/enums/MessageTypeEnum.java

@@ -131,6 +131,8 @@ public enum MessageTypeEnum implements BaseEnum<String, MessageTypeEnum> {
     TENANT_MUSIC_BUY("购买曲目"),
     TENANT_STUDENT_CHANGE("机构变更"),
     ADD_COOPERATE_TENANT("添加合作机构"),
+    TEACHER_BIND_TENANT("老师绑定机构"),
+    TEACHER_UNBIND_TENANT("老师解绑机构"),
     ;
 
     MessageTypeEnum(String msg) {

+ 29 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/mapper/UserTenantBindRecordMapper.java

@@ -0,0 +1,29 @@
+package com.yonge.cooleshow.biz.dal.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.yonge.cooleshow.biz.dal.entity.UserTenantBindRecord;
+import com.yonge.cooleshow.biz.dal.wrapper.UserTenantBindRecordWrapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+@Repository
+public interface UserTenantBindRecordMapper extends BaseMapper<UserTenantBindRecord> {
+
+    /**
+     * 分页查询
+     * @param page IPage<UserTenantBindRecordWrapper.UserTenantBindRecord>
+     * @param param UserTenantBindRecordWrapper.UserTenantBindRecordQuery
+     * @return List<UserTenantBindRecordWrapper.UserTenantBindRecord>
+     */
+    List<UserTenantBindRecordWrapper.UserTenantBindRecord> selectPage(@Param("page") IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> page,
+                                                                      @Param("param") UserTenantBindRecordWrapper.UserTenantBindRecordQuery param);
+
+    void add(@Param("record") UserTenantBindRecord record);
+}

+ 43 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/UserTenantBindRecordService.java

@@ -0,0 +1,43 @@
+package com.yonge.cooleshow.biz.dal.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.yonge.cooleshow.biz.dal.wrapper.UserTenantBindRecordWrapper;
+import com.yonge.cooleshow.biz.dal.entity.UserTenantBindRecord;
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+public interface UserTenantBindRecordService extends IService<UserTenantBindRecord>  {
+
+    /**
+     * 查询详情
+     * @param id 详情ID
+     * @return UserTenantBindRecord
+     */
+    UserTenantBindRecord detail(Long id);
+
+    /**
+     * 分页查询
+     * @param page IPage<UserTenantBindRecord>
+     * @param query UserTenantBindRecordWrapper.UserTenantBindRecordQuery
+     * @return IPage<UserTenantBindRecord>
+     */
+    IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> selectPage(IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> page, UserTenantBindRecordWrapper.UserTenantBindRecordQuery query);
+
+    /**
+     * 添加
+     * @param userTenantBindRecord UserTenantBindRecordWrapper.UserTenantBindRecord
+     * @return Boolean
+     */
+    Boolean add(UserTenantBindRecordWrapper.UserTenantBindRecord userTenantBindRecord);
+
+    /**
+     * 更新
+     * @param userTenantBindRecord UserTenantBindRecordWrapper.UserTenantBindRecord
+     * @return Boolean
+     */
+    Boolean update(UserTenantBindRecordWrapper.UserTenantBindRecord userTenantBindRecord);
+
+}

+ 24 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/StudentServiceImpl.java

@@ -25,6 +25,7 @@ import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantAlbumRefMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
+import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
 import com.yonge.cooleshow.biz.dal.vo.MyFollow;
@@ -125,6 +126,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
     @Autowired
     private TenantGroupMapper tenantGroupMapper;
 
+    @Autowired
+    private UserTenantBindRecordMapper userTenantBindRecordMapper;
     @Override
     public StudentVo detail(Long userId) {
         return baseMapper.detail(userId);
@@ -582,6 +585,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
 //             删除好友
             imUserFriendService.delTeacherFriendByTenantId(student.getTenantId(), student.getUserId(),
                     ClientEnum.STUDENT.getCode());
+            addBindUnBindRecord(student.getUserId(),student.getTenantId(),false);
         }
         if (toTenantId != null && toTenantId != -1L) {
             // 加好友
@@ -593,6 +597,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                 studentIds.add(student.getUserId());
                 imUserFriendService.saveUserFriend(teacher.getUserId(), studentIds);
             }
+            addBindUnBindRecord(student.getUserId(),student.getTenantId(),true);
         }
         this.lambdaUpdate().set(Student::getTenantId, toTenantId)
                 .set(Student::getTenantGroupId, -1L)
@@ -672,6 +677,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             imUserFriendService.delTeacherFriendByTenantId(student.getTenantId(), student.getUserId(),
                     ClientEnum.STUDENT.getCode());
 
+            addBindUnBindRecord(student.getUserId(),student.getTenantId(),false);
+
             // 加好友
             QueryWrapper<Teacher> query = new QueryWrapper<>();
             query.lambda().eq(Teacher::getTenantId, newTenantId);
@@ -682,6 +689,7 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                 imUserFriendService.saveUserFriend(teacher.getUserId(), studentIds);
             }
 
+            addBindUnBindRecord(student.getUserId(),studentInfo.getTenantId(),true);
             sendStudentTenantChange(student,newTenantId);
         }
 
@@ -700,6 +708,11 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
                     .set(StringUtils.isNotEmpty(studentInfo.getAvatar()), Student::getAvatar, studentInfo.getAvatar())
                     .eq(Student::getUserId, studentInfo.getId())
                     .update();
+
+            userTenantBindRecordMapper.update(null, Wrappers.<UserTenantBindRecord>lambdaUpdate()
+                    .eq(UserTenantBindRecord::getUserId, studentInfo.getId())
+                    .eq(UserTenantBindRecord::getUserType, "STUDENT")
+                    .set(UserTenantBindRecord::getUserId, sysUser.getId()));
         } else {
             Student newStudent = new Student();
             newStudent.setUserId(studentInfo.getId());
@@ -837,6 +850,8 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
             List<Teacher> teacherList = teacherDao.selectList(queryWrapper);
             teacherList.forEach(next -> imUserFriendService.saveUserFriend(next.getUserId(),
                     new HashSet<>(ImmutableList.of(sysUser.getId()))));
+
+            addBindUnBindRecord(student.getUserId(), student.getTenantId(), true);
         }
 
         //  与随机一个客服建立好友
@@ -938,4 +953,13 @@ public class StudentServiceImpl extends ServiceImpl<StudentDao, Student> impleme
         }
     }
 
+    private void addBindUnBindRecord(Long studentId, Long tenantId, Boolean bind) {
+        UserTenantBindRecord bindRecord = new UserTenantBindRecord();
+        bindRecord.setUserId(studentId);
+        bindRecord.setUserType("STUDENT");
+        bindRecord.setTenantId(tenantId);
+        bindRecord.setBindStatus(bind);
+        bindRecord.setBindTime(new Date());
+        userTenantBindRecordMapper.add(bindRecord);
+    }
 }

+ 38 - 6
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TeacherServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.google.common.collect.Lists;
+import com.microsvc.toolkit.middleware.rtc.enums.EDeviceMessageType;
 import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
 import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
 import com.yonge.cooleshow.auth.api.entity.SysUser;
@@ -26,6 +27,7 @@ import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 import com.yonge.cooleshow.biz.dal.enums.TeacherTagEnum;
 import com.yonge.cooleshow.biz.dal.enums.TeacherTypeEnum;
 import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
+import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
 import com.yonge.cooleshow.biz.dal.queryInfo.TeacherQueryInfo;
 import com.yonge.cooleshow.biz.dal.service.ImGroupService;
 import com.yonge.cooleshow.biz.dal.service.StudentService;
@@ -203,6 +205,9 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
     @Autowired
     private TenantGroupMapper tenantGroupMapper;
 
+    @Autowired
+    private UserTenantBindRecordMapper userTenantBindRecordMapper;
+
 
     @Override
     public TeacherDao getDao() {
@@ -500,6 +505,10 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                     .map(Student::getUserId).collect(Collectors.toSet());
 
             imUserFriendService.saveUserFriend(teacher.getUserId(), collect);
+
+            // 机构老师添加机构绑定记录
+            addBindUnBindRecord(teacher.getUserId(),teacher.getTenantId(),true);
+            sendBindUnBindSMS(teacher.getUserId(), teacherSubmitReq.getPhone(), MessageTypeEnum.TEACHER_BIND_TENANT, teacher.getTenantId());
         }
         //  与客服建立好友
         String customerService = customerServiceConfig.getCustomerService();
@@ -1095,21 +1104,23 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
                 });
             }
             // 删除好友关系
-            imUserFriendService.delStudentFriendByTenantId(teacher.getTenantId(), teacher.getUserId(),ClientEnum.TEACHER.getCode());
+            imUserFriendService.delStudentFriendByTenantId(teacher.getTenantId(), teacher.getUserId(), ClientEnum.TEACHER.getCode());
+            addBindUnBindRecord(teacher.getUserId(), teacher.getTenantId(), false);
+            SysUser sysUser = sysUserMapper.getByUserId(teacher.getUserId());
+            sendBindUnBindSMS(teacher.getUserId(), sysUser.getPhone(), MessageTypeEnum.TEACHER_UNBIND_TENANT, teacher.getTenantId());
 
         }
 
-        if (updateTenant.getTenantId().equals(-1L)) {
+        long tenantId = Optional.ofNullable(updateTenant.getTenantId()).orElse(-1L);
+        if (tenantId == -1L) {
             // 平台老师处理流程
             if (ESettlementFrom.TENANT.equals(teacher.getSettlementFrom())) {
                 // 解绑后,结算方式如果是机构,默认调整为老师
                 teacher.setSettlementFrom(ESettlementFrom.TEACHER);
                 teacher.setIsSettlement(true);
             }
-        }
-
-        // 机构老师与学生互加好友关系
-        if (Optional.ofNullable(updateTenant.getTenantId()).orElse(-1L) > 0) {
+        }else {
+            // 机构老师与学生互加好友关系
             // 自动与机构学生成为好友
             Set<Long> collect = studentService.lambdaQuery()
                     .eq(Student::getTenantId, updateTenant.getTenantId()).list().stream()
@@ -1119,6 +1130,9 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
             if (!collect.isEmpty()) {
                 imUserFriendService.saveUserFriend(teacher.getUserId(), collect);
             }
+            addBindUnBindRecord(teacher.getUserId(),updateTenant.getTenantId(),true);
+            SysUser sysUser = sysUserMapper.getByUserId(teacher.getUserId());
+            sendBindUnBindSMS(teacher.getUserId(), sysUser.getPhone(), MessageTypeEnum.TEACHER_BIND_TENANT, updateTenant.getTenantId());
         }
 
         teacher.setTenantId(updateTenant.getTenantId());
@@ -1199,4 +1213,22 @@ public class TeacherServiceImpl extends ServiceImpl<TeacherDao, Teacher> impleme
 
         return teachers.stream().collect(Collectors.toMap(Teacher::getUserId, o -> o, (o, n) -> n));
     }
+
+    private void addBindUnBindRecord(Long teacherId, Long tenantId, Boolean bind) {
+        UserTenantBindRecord bindRecord = new UserTenantBindRecord();
+        bindRecord.setUserId(teacherId);
+        bindRecord.setUserType("TEACHER");
+        bindRecord.setTenantId(tenantId);
+        bindRecord.setBindStatus(bind);
+        bindRecord.setBindTime(new Date());
+        userTenantBindRecordMapper.add(bindRecord);
+    }
+
+    private void sendBindUnBindSMS(Long userId, String phone, MessageTypeEnum messageType, Long tenantId) {
+        TenantInfo tenantInfo = tenantInfoService.getById(tenantId);
+        Map<Long, String> receivers = new HashMap<>();
+        receivers.put(userId, phone);
+        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, messageType,
+                receivers, null, 0, null, ClientEnum.SYSTEM.getCode(), tenantInfo.getName());
+    }
 }

+ 24 - 5
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantActivationCodeServiceImpl.java

@@ -158,6 +158,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
             boolean update = this.lambdaUpdate()
                     .set(TenantActivationCode::getSendStatus, EActivationCode.SEND.getCode())
                     .set(TenantActivationCode::getActivationPhone, idPhoneMap.get(studentId))
+                    .set(TenantActivationCode::getSendTime, new Date())
                     .eq(TenantActivationCode::getActivationStatus, false)
                     .eq(TenantActivationCode::getId, tenantActivationCodes.get(i).getId())
                     .update();
@@ -240,10 +241,14 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
                 .eq(TenantActivationCode::getTenantAlbumPurchaseId, code.getTenantAlbumPurchaseId())
                 .eq(TenantActivationCode::getActivationStatus, true).count();
 
-        TenantAlbumPurchase tenantAlbumPurchase = new TenantAlbumPurchase();
-        tenantAlbumPurchase.setId(code.getTenantAlbumPurchaseId());
-        tenantAlbumPurchase.setActiveQuantity(activeCodeNumber);
-        tenantAlbumPurchaseMapper.updateById(tenantAlbumPurchase);
+        TenantAlbumPurchase albumPurchase = tenantAlbumPurchaseMapper.selectById(code.getTenantAlbumPurchaseId());
+        albumPurchase.setActiveQuantity(activeCodeNumber);
+        if (activeCodeNumber.equals(albumPurchase.getPurchaseQuantity())) {
+            albumPurchase.setActiveStatus("ALL");
+        } else {
+            albumPurchase.setActiveStatus("PART");
+        }
+        tenantAlbumPurchaseMapper.updateById(albumPurchase);
     }
 
 
@@ -297,6 +302,12 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         TenantAlbumPurchase tenantAlbumPurchase = new TenantAlbumPurchase();
         tenantAlbumPurchase.setId(code.getTenantAlbumPurchaseId());
         tenantAlbumPurchase.setActiveQuantity(activeCodeNumber);
+
+        if (activeCodeNumber.equals(tenantAlbumPurchase.getPurchaseQuantity())) {
+            tenantAlbumPurchase.setActiveStatus("ALL");
+        } else {
+            tenantAlbumPurchase.setActiveStatus("PART");
+        }
         tenantAlbumPurchaseMapper.updateById(tenantAlbumPurchase);
 
     }
@@ -337,12 +348,19 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         boolean update = this.lambdaUpdate()
                 .set(TenantActivationCode::getSendStatus, EActivationCode.WAIT)
                 .set(TenantActivationCode::getActivationPhone, "")
+                .set(TenantActivationCode::getSendTime, null)
                 .eq(TenantActivationCode::getId, activationCode.getId())
                 .eq(TenantActivationCode::getActivationStatus, false)
                 .eq(TenantActivationCode::getSendStatus, EActivationCode.SEND)
                 .update();
         if (!update) {
-            throw new BizException("激活码已经激活");
+            TenantActivationCode code = this.getById(activationCode.getId());
+            if (EActivationCode.WAIT.equals(code.getSendStatus())) {
+                throw new BizException("激活码已撤回");
+            }
+            if (Boolean.TRUE.equals(code.getActivationStatus())) {
+                throw new BizException("激活码已经激活");
+            }
         }
         com.yonge.cooleshow.auth.api.entity.SysUser sysUser = sysUserService.findUserByPhone(activationCode.getActivationPhone());
         if (sysUser != null) {
@@ -402,6 +420,7 @@ public class TenantActivationCodeServiceImpl extends ServiceImpl<TenantActivatio
         for (int i = 0; i < studentIdList.size(); i++) {
             TenantActivationCode tenantActivationCode = activationCodes.get(i);
             tenantActivationCode.setSendStatus(EActivationCode.SEND);
+            tenantActivationCode.setSendTime(new Date());
             tenantActivationCode.setActivationPhone(mapPhoneById.getOrDefault(studentIdList.get(i), ""));
             updates.add(tenantActivationCode);
         }

+ 42 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantGroupServiceImpl.java

@@ -109,10 +109,15 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
                         .list().stream().map(ImGroup::getId).collect(Collectors.toList());
                 existImgGroupIds.addAll(imgGroupIds);
             }
+            List<Long> adminIdList = records.stream().map(TenantGroupWrapper.TenantGroup::getAdminId).distinct().collect(Collectors.toList());
+            Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> mapByIds = sysUserService.getMapByIds(adminIdList);
 
             for (TenantGroupWrapper.TenantGroup record : records) {
                 record.setGroupUserCount(groupBy.getOrDefault(record.getId(), 0));
                 record.setImGroupExist(existImgGroupIds.contains(record.getImGroupId()));
+                if (mapByIds.containsKey(record.getAdminId())) {
+                    record.setAdminName(mapByIds.get(record.getAdminId()).getUsername());
+                }
             }
         }
         return iPage;
@@ -135,8 +140,15 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
         if (count > 0) {
             throw new BizException("小组名称已存在");
         }
-        this.save(entity);
         Long adminId = tenantGroup.getAdminId();
+        Teacher teacher = teacherDao.selectById(adminId);
+        if (!tenantGroup.getTenantId().equals(teacher.getTenantId())) {
+            throw new BizException("负责人机构已经变更,请重新选择");
+        }
+        List<Long> userIds = tenantGroup.getUserIds();
+        checkStudent(tenantGroup.getTenantId(), userIds,null);
+
+        this.save(entity);
         if (adminId != null && Boolean.TRUE.equals(imGroupCreate)) {
             // 建群
             try {
@@ -153,7 +165,6 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
                 throw new BizException("创建机构小组群失败");
             }
             // 加群成员
-            List<Long> userIds = tenantGroup.getUserIds();
             if (CollectionUtils.isNotEmpty(userIds)) {
                 try {
                     imGroupService.addGroupMember(entity.getImGroupId(), new HashSet<>(userIds));
@@ -164,7 +175,6 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
             }
         }
         // 加群成员
-        List<Long> userIds = tenantGroup.getUserIds();
         if (CollectionUtils.isNotEmpty(userIds)) {
             studentDao.update(null, Wrappers.<Student>lambdaUpdate()
                     .in(Student::getUserId, userIds)
@@ -194,6 +204,13 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
             throw new BizException("小组名称已经存在");
         }
 
+        Long adminId = tenantGroup.getAdminId();
+        Teacher teacher = teacherDao.selectById(adminId);
+        if (!tenantGroup.getTenantId().equals(teacher.getTenantId())) {
+            throw new BizException("负责人机构已经变更,请重新选择");
+        }
+        checkStudent(tenantGroup.getTenantId(), tenantGroup.getUserIds(),tenantGroup.getId());
+
         TenantGroup entity = JSON.parseObject(tenantGroup.jsonString(), TenantGroup.class);
         entity.setImGroupId(oldGroup.getImGroupId());
         // 是否建群
@@ -523,4 +540,26 @@ public class TenantGroupServiceImpl extends ServiceImpl<TenantGroupMapper, Tenan
                 .eq(Student::getTenantGroupId, tenantGroupId);
         return studentDao.selectList(queryWrapper);
     }
+
+    private void checkStudent(Long tenantId, List<Long> userIds,Long tenantGroupId) {
+        if (CollectionUtils.isEmpty(userIds)) {
+            return;
+        }
+        QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda()
+                .in(Student::getUserId, userIds);
+        List<Student> students = studentDao.selectList(queryWrapper);
+        if (userIds.size() != students.size()) {
+            throw new BizException("参数错误");
+        }
+        for (Student student : students) {
+            if (!tenantId.equals(student.getTenantId())) {
+                throw new BizException("学生已经在其他机构");
+            }
+            Long groupId = student.getTenantGroupId();
+            if (groupId != -1L && !groupId.equals(tenantGroupId)) {
+                throw new BizException("学生已经在其他小组");
+            }
+        }
+    }
 }

+ 12 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/TenantUnbindRecordServiceImpl.java

@@ -19,6 +19,7 @@ import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
 import com.yonge.cooleshow.biz.dal.mapper.SysAreaMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
 import com.yonge.cooleshow.biz.dal.mapper.TenantUnbindRecordMapper;
+import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
 import com.yonge.cooleshow.biz.dal.service.*;
 import com.yonge.cooleshow.biz.dal.wrapper.TenantUnbindRecordWrapper;
 import com.yonge.cooleshow.common.constant.SysConfigConstant;
@@ -93,6 +94,9 @@ public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecor
     @Autowired
     private ImGroupMemberService imGroupMemberService;
 
+    @Autowired
+    private UserTenantBindRecordMapper userTenantBindRecordMapper;
+
     /**
      * @param id 详情ID
      * @return TenantUnbindRecord
@@ -270,6 +274,14 @@ public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecor
                     .set(ESettlementFrom.TENANT.equals(teacher.getSettlementFrom()), Teacher::getSettlementFrom,
                             ESettlementFrom.TEACHER)
                     .set(Teacher::getTenantId, -1L));
+
+            UserTenantBindRecord bindRecord = new UserTenantBindRecord();
+            bindRecord.setUserId(unbindRecord.getUserId());
+            bindRecord.setUserType("TEACHER");
+            bindRecord.setTenantId(tenantId);
+            bindRecord.setBindStatus(false);
+            bindRecord.setBindTime(new Date());
+            userTenantBindRecordMapper.add(bindRecord);
         }
 
         // 添加历史记录

+ 116 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/service/impl/UserTenantBindRecordServiceImpl.java

@@ -0,0 +1,116 @@
+package com.yonge.cooleshow.biz.dal.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.yonge.cooleshow.biz.dal.entity.Subject;
+import com.yonge.cooleshow.biz.dal.entity.UserTenantAlbumRecord;
+import com.yonge.cooleshow.biz.dal.entity.UserTenantBindRecord;
+import com.yonge.cooleshow.biz.dal.mapper.UserTenantAlbumRecordMapper;
+import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
+import com.yonge.cooleshow.biz.dal.service.SubjectService;
+import com.yonge.cooleshow.biz.dal.service.UserTenantBindRecordService;
+import com.yonge.cooleshow.biz.dal.wrapper.UserTenantBindRecordWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+@Slf4j
+@Service
+public class UserTenantBindRecordServiceImpl extends ServiceImpl<UserTenantBindRecordMapper, UserTenantBindRecord> implements UserTenantBindRecordService {
+
+    @Autowired
+    private UserTenantAlbumRecordMapper userTenantAlbumRecordMapper;
+
+    @Autowired
+    private SubjectService subjectService;
+
+    /**
+     * 查询详情
+     *
+     * @param id 详情ID
+     * @return UserTenantBindRecord
+     */
+    @Override
+    public UserTenantBindRecord detail(Long id) {
+
+        return baseMapper.selectById(id);
+    }
+
+    /**
+     * 分页查询
+     *
+     * @param page  IPage<UserTenantBindRecord>
+     * @param query UserTenantBindRecordWrapper.UserTenantBindRecordQuery
+     * @return IPage<UserTenantBindRecord>
+     */
+    @Override
+    public IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> selectPage(IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> page,
+                                                                              UserTenantBindRecordWrapper.UserTenantBindRecordQuery query) {
+
+        IPage<UserTenantBindRecordWrapper.UserTenantBindRecord> pageRecord = page.setRecords(baseMapper.selectPage(page, query));
+        List<UserTenantBindRecordWrapper.UserTenantBindRecord> records = pageRecord.getRecords();
+        if (!records.isEmpty() && "STUDENT".equals(query.getUserType())) {
+            List<Long> userIds = records.stream().map(UserTenantBindRecordWrapper.UserTenantBindRecord::getUserId).distinct().collect(Collectors.toList());
+
+            QueryWrapper<UserTenantAlbumRecord> queryWrapper = new QueryWrapper<>();
+            queryWrapper.lambda()
+                    .in(UserTenantAlbumRecord::getUserId, userIds)
+                    .ge(UserTenantAlbumRecord::getEndTime, new Date());
+            Map<String, List<UserTenantAlbumRecord>> groupByAlbum = userTenantAlbumRecordMapper.selectList(queryWrapper).stream()
+                    .collect(Collectors.groupingBy(next -> next.getUserId() + "_" + next.getTenantId()));
+
+            List<String> collect = records.stream().map(UserTenantBindRecordWrapper.UserTenantBindRecord::getSubjectId).distinct().collect(Collectors.toList());
+            Map<Integer, Subject> mapByIds = subjectService.getMapByIds(collect);
+            records.forEach(next -> {
+                String key = next.getUserId() + "_" + next.getTenantId();
+                if (groupByAlbum.containsKey(key)) {
+                    next.setTenantAlbumActiveStatus(true);
+                    List<UserTenantAlbumRecord> userTenantAlbumRecords = groupByAlbum.get(key);
+                    userTenantAlbumRecords.sort((o1, o2) -> o2.getEndTime().compareTo(o1.getEndTime()));
+                    next.setTenantAlbumExpireTime(userTenantAlbumRecords.get(0).getEndTime());
+                } else {
+                    next.setTenantAlbumActiveStatus(false);
+                }
+                next.setSubjectName(mapByIds.getOrDefault(Integer.valueOf(next.getSubjectId()), new Subject()).getName());
+            });
+        }
+
+        return pageRecord;
+
+    }
+
+    /**
+     * 添加
+     *
+     * @param userTenantBindRecord UserTenantBindRecordWrapper.UserTenantBindRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean add(UserTenantBindRecordWrapper.UserTenantBindRecord userTenantBindRecord) {
+
+        return this.save(JSON.parseObject(userTenantBindRecord.jsonString(), UserTenantBindRecord.class));
+    }
+
+    /**
+     * 更新
+     *
+     * @param userTenantBindRecord UserTenantBindRecordWrapper.UserTenantBindRecord
+     * @return Boolean
+     */
+    @Override
+    public Boolean update(UserTenantBindRecordWrapper.UserTenantBindRecord userTenantBindRecord) {
+
+        return this.updateById(JSON.parseObject(userTenantBindRecord.jsonString(), UserTenantBindRecord.class));
+    }
+}

+ 6 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantActivationCodeWrapper.java

@@ -76,6 +76,9 @@ public class TenantActivationCodeWrapper {
         @ApiModelProperty("订单号 订单详情专用")
         private String orderNo;
 
+        @ApiModelProperty("激活码")
+        private String activationCode;
+
         public String getKeyword() {
             return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
         }
@@ -148,6 +151,9 @@ public class TenantActivationCodeWrapper {
         @ApiModelProperty("购买数量")
         private Integer  purchaseQuantity;
 
+        @ApiModelProperty("发放时间")
+        private Date sendTime;
+
         public String jsonString() {
             return JSON.toJSONString(this);
         }

+ 12 - 3
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantAlbumPurchaseWrapper.java

@@ -41,12 +41,18 @@ public class TenantAlbumPurchaseWrapper {
         @ApiModelProperty("机构ID")
         private Long tenantId;
 
-        @ApiModelProperty(value = "排序规则", hidden = true)
-        private String orderBy;
-
 
         @ApiModelProperty("采购状态 WAIT_PAY 待支付   PAID 已付款 CLOSE 已关闭")
         private String purchaseStatus;
+
+        @ApiModelProperty("激活状态:NONE:未激活,PART:部分,ALL:全部")
+        private String activeStatus;
+
+        @ApiModelProperty("采购开始时间")
+        private Date purchaseStartTime;
+
+        @ApiModelProperty("采购结束时间")
+        private Date purchaseEndTime;
         public String getKeyword() {
             return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
         }
@@ -106,6 +112,9 @@ public class TenantAlbumPurchaseWrapper {
         @ApiModelProperty("创建时间")
         private Date createTime;
 
+        @ApiModelProperty("激活状态:NONE:未激活,PART:部分,ALL:全部")
+        private String activeStatus;
+
         public String jsonString() {
             return JSON.toJSONString(this);
         }

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantGroupWrapper.java

@@ -78,6 +78,9 @@ public class TenantGroupWrapper {
         @ApiModelProperty("管理员ID")
         private Long adminId;
 
+        @ApiModelProperty("管理员名称")
+        private String adminName;
+
         @ApiModelProperty("IM群聊ID")
         private String imGroupId;
 

+ 3 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/TenantInfoWrapper.java

@@ -49,6 +49,9 @@ public class TenantInfoWrapper {
         @ApiModelProperty("地区街道编码")
         private Integer regionCode;
 
+        @ApiModelProperty("启用/停用")
+        private Boolean enableFlag;
+
         public String getKeyword() {
             return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
         }

+ 151 - 0
cooleshow-user/user-biz/src/main/java/com/yonge/cooleshow/biz/dal/wrapper/UserTenantBindRecordWrapper.java

@@ -0,0 +1,151 @@
+package com.yonge.cooleshow.biz.dal.wrapper;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.microsvc.toolkit.common.response.paging.QueryInfo;
+import com.yonge.cooleshow.common.enums.ESettlementFrom;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+import java.util.Optional;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 用户机构绑定解绑记录
+ * 2023-12-04 15:30:02
+ */
+@ApiModel(value = "UserTenantBindRecordWrapper对象", description = "用户机构绑定解绑记录查询对象")
+public class UserTenantBindRecordWrapper {
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @ApiModel(" UserTenantBindRecordQuery-用户机构绑定解绑记录")
+    public static class UserTenantBindRecordQuery implements QueryInfo {
+
+        @ApiModelProperty("当前页")
+        private Integer page;
+
+        @ApiModelProperty("分页行数")
+        private Integer rows;
+
+        @ApiModelProperty("关键字匹配")
+        private String keyword;
+
+        @ApiModelProperty("TEACHER:老师,STUDENT:学生")
+        private String userType;
+
+        @ApiModelProperty("机构小组ID")
+        private Long tenantGroupId;
+
+        @ApiModelProperty("结算方式")
+        private ESettlementFrom settlementFrom;
+
+        @ApiModelProperty("绑定状态,1:绑定。2:未绑定")
+        private Boolean bindStatus;
+
+        @ApiModelProperty("账号锁定状态,1:锁定,0:未锁定")
+        private Boolean lockFlag;
+
+        @ApiModelProperty("绑定开始时间")
+        private Date bindStartTime;
+
+        @ApiModelProperty("绑定结束时间")
+        private Date bindEndTime;
+
+        @ApiModelProperty("声部")
+        private String subjectId;
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+        public String getKeyword() {
+            return Optional.ofNullable(keyword).filter(StringUtils::isNotBlank).orElse(null);
+        }
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static UserTenantBindRecordQuery from(String json) {
+            return JSON.parseObject(json, UserTenantBindRecordQuery.class);
+        }
+    }
+
+    @Data
+    @ApiModel(" UserTenantBindRecord-用户机构绑定解绑记录")
+    public static class UserTenantBindRecord {
+
+        @ApiModelProperty("")
+        private Long id;
+
+
+        @ApiModelProperty("用户ID")
+        private Long userId;
+
+
+        @ApiModelProperty("TEACHER:老师,STUDENT:学生")
+        private String userType;
+
+
+        @ApiModelProperty("机构ID")
+        private Long tenantId;
+
+
+        @ApiModelProperty("绑定状态:1:已绑定,0:未绑定")
+        private Boolean bindStatus;
+
+
+        @ApiModelProperty("绑定/解绑最新时间")
+        private Date bindTime;
+
+        @ApiModelProperty("姓名")
+        private String userName;
+
+        @ApiModelProperty("手机号")
+        private String phone;
+
+        @ApiModelProperty("性别")
+        private Integer gender;
+
+        @ApiModelProperty("小组名称")
+        private String tenantGroupName;
+
+        @ApiModelProperty("小组名称")
+        private String tenantGroupId;
+
+        @ApiModelProperty("结算方式")
+        private ESettlementFrom settlementFrom;
+
+        @ApiModelProperty("锁定状态")
+        private Boolean lockFlag;
+
+        @ApiModelProperty("声部")
+        private String subjectName;
+
+        @ApiModelProperty("声部")
+        private String subjectId;
+
+        @ApiModelProperty("专辑状态,1:激活,0:为激活")
+        private Boolean tenantAlbumActiveStatus;
+
+        @ApiModelProperty("失效时间")
+        private Date tenantAlbumExpireTime;
+
+        public String jsonString() {
+            return JSON.toJSONString(this);
+        }
+
+        public static UserTenantBindRecord from(String json) {
+            return JSON.parseObject(json, UserTenantBindRecord.class);
+        }
+    }
+
+}

+ 4 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantActivationCodeMapper.xml

@@ -15,6 +15,7 @@
         , t.activation_user_id_ AS activationUserId
         , t.update_time_ AS updateTime
         , t.create_time_ AS createTime
+        , t.send_time_ AS sendTime
     </sql>
 
     <select id="selectPage"
@@ -66,6 +67,9 @@
             <if test="param.tenantGroupId != null">
                 and st.tenant_group_id_ = #{param.tenantGroupId}
             </if>
+            <if test="param.activationCode != null and param.activationCode.trim() != ''">
+                AND t.activation_code_ like concat('%',#{param.activationCode},'%')
+            </if>
         </where>
         order by t.activation_status_ asc, t.id_ desc
     </select>

+ 16 - 8
cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantAlbumPurchaseMapper.xml

@@ -16,6 +16,7 @@
         , t.active_quantity_ AS activeQuantity
         , t.purchase_price_ AS purchasePrice
         , t.purchase_status_ AS purchaseStatus
+        , t.active_status_ AS activeStatus
         , t.update_time_ AS updateTime
         , t.create_time_ AS createTime
         </sql>
@@ -28,6 +29,11 @@
         LEFT JOIN tenant_album ta on t.tenant_album_id_ = ta.id_
         left join user_order t2 on t2.order_no_ = t.order_no_
         <where>
+            <if test="param.keyword != null and param.keyword.trim() != ''">
+                AND (ta.name_ like concat('%',#{param.keyword},'%')
+                or t.purchase_quantity_ like concat('%',#{param.keyword},'%')
+                )
+            </if>
             <if test="param.tenantId != null">
                 AND t.tenant_id_ = #{param.tenantId}
             </if>
@@ -42,15 +48,17 @@
                     AND t2.status_ in ( 'CLOSE','FAIL')
                 </if>
             </if>
+            <if test="param.activeStatus != null">
+                AND t.active_status_ = #{param.activeStatus}
+            </if>
+            <if test="param.purchaseStartTime != null">
+                AND t.create_time_ >= #{param.purchaseStartTime}
+            </if>
+            <if test="param.purchaseEndTime != null">
+                AND #{param.purchaseEndTime} >= t.create_time_
+            </if>
         </where>
-        <choose>
-            <when test="param.orderBy != null and param.orderBy.trim() != ''">
-                order by #{param.orderBy}
-            </when>
-            <otherwise>
-                order by t.id_ desc
-            </otherwise>
-        </choose>
+        order by t.create_time_ desc
     </select>
     
 </mapper>

+ 1 - 1
cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantGroupMapper.xml

@@ -30,7 +30,7 @@
                 AND t.admin_id_ = #{param.adminId}
             </if>
         </where>
-        ORDER BY t.id_ ASC
+        ORDER BY t.id_ DESC
     </select>
 
 </mapper>

+ 3 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/TenantInfoMapper.xml

@@ -105,6 +105,9 @@
             <if test="param.regionCode != null">
                 and t.region_code_ = #{param.regionCode}
             </if>
+            <if test="param.enableFlag != null">
+                and t.enable_flag_ = #{param.enableFlag}
+            </if>
         </where>
         order by t.create_time_ desc
 	</select>

+ 107 - 0
cooleshow-user/user-biz/src/main/resources/config/mybatis/UserTenantBindRecordMapper.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE  mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper">
+
+
+
+    <!-- 表字段 -->
+    <sql id="baseColumns">
+        t.id_ AS id
+        , t.user_id_ AS userId
+        , t.user_type_ AS userType
+        , t.tenant_id_ AS tenantId
+        , t.bind_status_ AS bindStatus
+        , t.bind_time_ AS bindTime
+    </sql>
+
+    <select id="selectPage" resultType="com.yonge.cooleshow.biz.dal.wrapper.UserTenantBindRecordWrapper$UserTenantBindRecord">
+        SELECT
+        <include refid="baseColumns"/>
+        ,su.username_ userName
+        ,su.phone_ phone
+        ,su.gender_ gender
+<!--        ,su.lock_flag_ lockFlag-->
+        <if test="param.userType == 'TEACHER'">
+            ,if(su.lock_flag_ = 0 and tc.lock_flag_= 0,0,1) as lockFlag
+            ,tc.settlement_from_ settlementFrom
+            ,group_concat(tg.name_) tenantGroupName
+            ,group_concat(tg.id_) tenantGroupId
+        </if>
+        <if test="param.userType == 'STUDENT'">
+            ,tg.name_ tenantGroupName
+            ,tg.id_ tenantGroupId
+            ,st.subject_id_ subjectId
+            ,if(su.lock_flag_ = 0 and st.lock_flag_= 0,0,1) as lockFlag
+        </if>
+        FROM user_tenant_bind_record t
+        LEFT JOIN sys_user su ON t.user_id_ = su.id_
+        <if test="param.userType == 'TEACHER'">
+            LEFT JOIN teacher tc on t.user_id_ = tc.user_id_
+            LEFT JOIN tenant_group tg on t.user_id_ = tg.admin_id_
+            <if test="param.tenantId != null">
+                and tg.tenant_id_ = #{param.tenantId}
+            </if>
+        </if>
+        <if test="param.userType == 'STUDENT'">
+            LEFT JOIN student st on t.user_id_ = st.user_id_
+            LEFT JOIN tenant_group tg on st.tenant_group_id_ = tg.id_
+            <if test="param.tenantId != null">
+                and tg.tenant_id_ = #{param.tenantId}
+            </if>
+        </if>
+        <where>
+            <if test="param.keyword != null and param.keyword.trim() != ''">
+                AND (t.user_id_ like concat('%',#{param.keyword},'%')
+                or su.username_ like concat('%',#{param.keyword},'%')
+                or su.phone_ like concat('%',#{param.keyword},'%')
+                )
+            </if>
+            <if test="param.tenantId != null">
+                AND t.tenant_id_ = #{param.tenantId}
+            </if>
+            <if test="param.userType != null and param.userType.trim() != ''">
+                AND t.user_type_ = #{param.userType}
+            </if>
+            <if test="param.tenantGroupId != null">
+<!--                <if test="param.userType == 'TEACHER'">-->
+<!--                    AND tg.id_ =#{param.tenantGroupId}-->
+<!--                </if>-->
+                <if test="param.userType == 'STUDENT'">
+                    AND st.tenant_group_id_ = #{param.tenantGroupId}
+                </if>
+            </if>
+            <if test="param.userType == 'TEACHER' and param.settlementFrom != null">
+                AND tc.settlement_from_ = #{param.settlementFrom}
+            </if>
+            <if test="param.bindStatus != null">
+                AND t.bind_status_ = #{param.bindStatus}
+            </if>
+            <if test="param.lockFlag != null">
+                AND su.lock_flag_ = #{param.lockFlag}
+            </if>
+            <if test="param.bindStartTime != null">
+                AND t.bind_time_ >= #{param.bindStartTime}
+            </if>
+            <if test="param.bindEndTime != null">
+                AND #{param.bindEndTime} >= t.bind_time_
+            </if>
+            <if test="param.userType == 'STUDENT' and param.subjectId != null">
+                AND st.subject_id_ = #{param.subjectId}
+            </if>
+        </where>
+        <if test="param.userType == 'TEACHER'">
+            group by t.user_id_
+        </if>
+        <if test="param.tenantGroupId != null and param.userType == 'TEACHER'">
+            HAVING find_in_set(#{param.tenantGroupId},tenantGroupId)
+        </if>
+        order by field(t.bind_status_,1,0) ,t.bind_time_ desc
+    </select>
+
+    <insert id="add">
+        INSERT INTO user_tenant_bind_record(user_id_, user_type_, tenant_id_, bind_status_, bind_time_)
+        VALUES (#{record.userId}, #{record.userType}, #{record.tenantId}, #{record.bindStatus}, #{record.bindTime})
+        ON DUPLICATE KEY UPDATE bind_status_ = VALUES(bind_status_),
+                                bind_time_   = VALUES(bind_time_)
+    </insert>
+</mapper>