|
|
@@ -14,7 +14,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Random;
|
|
|
import com.etotem.cfc.util.SortUtil;
|
|
|
|
|
|
@Service
|
|
|
@@ -26,6 +29,9 @@ public class SupplySystemService extends ServiceImpl<SupplySystemMapper, SupplyS
|
|
|
@Resource
|
|
|
private UserMapper userMapper;
|
|
|
|
|
|
+ @Resource
|
|
|
+ private SupplyHierarchyService supplyHierarchyService;
|
|
|
+
|
|
|
public Page<SupplySystem> list(String keyword, String status, int page, int size) {
|
|
|
Page<SupplySystem> pageParam = new Page<>(page, size);
|
|
|
LambdaQueryWrapper<SupplySystem> wrapper = new LambdaQueryWrapper<>();
|
|
|
@@ -202,4 +208,155 @@ public class SupplySystemService extends ServiceImpl<SupplySystemMapper, SupplyS
|
|
|
member.setRole(role);
|
|
|
return supplySystemMemberMapper.updateById(member) > 0;
|
|
|
}
|
|
|
+
|
|
|
+ // ========== 邀请功能(T38:在我的团队邀请其他用户加入)==========
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成/获取当前成员的个人专属邀请码(T38)。
|
|
|
+ * refresh=false 且已有码 → 幂等复用;refresh=true(或空码)→ 重新生成并使旧码失效。
|
|
|
+ *
|
|
|
+ * @throws IllegalArgumentException 团队不存在/已停用/当前用户不是该团队成员
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public String generateInviteCode(Long systemId, Long userId, boolean refresh) {
|
|
|
+ if (systemId == null || userId == null) {
|
|
|
+ throw new IllegalArgumentException("参数不完整");
|
|
|
+ }
|
|
|
+ SupplySystem system = this.getById(systemId);
|
|
|
+ if (system == null) {
|
|
|
+ throw new IllegalArgumentException("团队不存在");
|
|
|
+ }
|
|
|
+ if (!"active".equals(system.getStatus())) {
|
|
|
+ throw new IllegalArgumentException("团队已停用,无法生成邀请码");
|
|
|
+ }
|
|
|
+ SupplySystemMember member = getMemberBySystemAndUser(systemId, userId);
|
|
|
+ if (member == null) {
|
|
|
+ throw new IllegalArgumentException("您不是该团队成员,无法生成邀请码");
|
|
|
+ }
|
|
|
+ if (!refresh && member.getInviteCode() != null && !member.getInviteCode().isEmpty()) {
|
|
|
+ return member.getInviteCode();
|
|
|
+ }
|
|
|
+ String code = generateUniqueInviteCode();
|
|
|
+ member.setInviteCode(code);
|
|
|
+ supplySystemMemberMapper.updateById(member);
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 邀请码信息(确认页展示:团队名/邀请人昵称头像/成员数,不泄露其他隐私)(T38)。
|
|
|
+ * 不校验当前用户身份——凭码即可查看(确认页在加入前使用)。
|
|
|
+ */
|
|
|
+ public Map<String, Object> getInviteInfo(String inviteCode) {
|
|
|
+ SupplySystemMember inviter = getMemberByInviteCode(inviteCode);
|
|
|
+ if (inviter == null || inviter.getSystemId() == null) {
|
|
|
+ throw new IllegalArgumentException("邀请码不存在或已失效");
|
|
|
+ }
|
|
|
+ Long systemId = inviter.getSystemId();
|
|
|
+ SupplySystem system = this.getById(systemId);
|
|
|
+ if (system == null) {
|
|
|
+ throw new IllegalArgumentException("邀请码不存在或已失效");
|
|
|
+ }
|
|
|
+ Map<String, Object> info = new HashMap<>();
|
|
|
+ info.put("systemId", systemId);
|
|
|
+ info.put("teamName", system.getName());
|
|
|
+ info.put("inviterId", inviter.getUserId());
|
|
|
+ User inviterUser = userMapper.selectById(inviter.getUserId());
|
|
|
+ info.put("inviterNickname", inviterUser != null ? inviterUser.getNickname() : "微信用户");
|
|
|
+ info.put("inviterAvatar", inviterUser != null ? inviterUser.getAvatar() : null);
|
|
|
+ Long memberCount = supplySystemMemberMapper.selectCount(new LambdaQueryWrapper<SupplySystemMember>()
|
|
|
+ .eq(SupplySystemMember::getSystemId, systemId)
|
|
|
+ .eq(SupplySystemMember::getStatus, "active"));
|
|
|
+ info.put("memberCount", memberCount != null ? memberCount : 0L);
|
|
|
+ info.put("active", "active".equals(system.getStatus()));
|
|
|
+ return info;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 凭邀请码加入团队(T38):
|
|
|
+ * 校验码有效 + 用户未 active 加入过该体系 → 成为 role=member/status=active 成员
|
|
|
+ * → supply_hierarchy 挂 parentId=邀请人 / level=父级level+1(邀请人=其上级,
|
|
|
+ * 成员子树整体结算给该成员,与 §0.5 负责人结算口径一致)。
|
|
|
+ * 边界:同一 (systemId,userId) 仅 active 一次(active 拒绝重复加入,inactive 可重新加入)。
|
|
|
+ *
|
|
|
+ * @return 加入后的团队/邀请人信息(同 getInviteInfo)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public Map<String, Object> joinByInviteCode(String inviteCode, Long userId) {
|
|
|
+ if (userId == null) {
|
|
|
+ throw new IllegalArgumentException("未登录");
|
|
|
+ }
|
|
|
+ SupplySystemMember inviter = getMemberByInviteCode(inviteCode);
|
|
|
+ if (inviter == null || inviter.getSystemId() == null) {
|
|
|
+ throw new IllegalArgumentException("邀请码不存在或已失效");
|
|
|
+ }
|
|
|
+ Long systemId = inviter.getSystemId();
|
|
|
+ SupplySystem system = this.getById(systemId);
|
|
|
+ if (system == null) {
|
|
|
+ throw new IllegalArgumentException("邀请码不存在或已失效");
|
|
|
+ }
|
|
|
+ if (!"active".equals(system.getStatus())) {
|
|
|
+ throw new IllegalArgumentException("团队已停用,暂无法加入");
|
|
|
+ }
|
|
|
+ // 同一 (systemId,userId) 仅加入一次;active → 拒绝,inactive(被移除)→ 重新激活
|
|
|
+ SupplySystemMember existing = getMemberBySystemAndUser(systemId, userId);
|
|
|
+ if (existing != null && "active".equals(existing.getStatus())) {
|
|
|
+ throw new IllegalArgumentException("您已在该团队中,无需重复加入");
|
|
|
+ }
|
|
|
+ SupplySystemMember member;
|
|
|
+ if (existing != null) {
|
|
|
+ existing.setRole("member");
|
|
|
+ existing.setStatus("active");
|
|
|
+ existing.setJoinedAt(new Date());
|
|
|
+ supplySystemMemberMapper.updateById(existing);
|
|
|
+ member = existing;
|
|
|
+ } else {
|
|
|
+ member = new SupplySystemMember();
|
|
|
+ member.setSystemId(systemId);
|
|
|
+ member.setUserId(userId);
|
|
|
+ member.setRole("member");
|
|
|
+ member.setStatus("active");
|
|
|
+ member.setJoinedAt(new Date());
|
|
|
+ supplySystemMemberMapper.insert(member);
|
|
|
+ }
|
|
|
+ // 挂上级:parentId=邀请人,level=父level+1(已存在 inactive 关系则恢复 active 并更新,避免重复行)
|
|
|
+ supplyHierarchyService.ensureRelation(systemId, inviter.getUserId(), userId);
|
|
|
+ return getInviteInfo(inviteCode);
|
|
|
+ }
|
|
|
+
|
|
|
+ private SupplySystemMember getMemberBySystemAndUser(Long systemId, Long userId) {
|
|
|
+ return supplySystemMemberMapper.selectOne(new LambdaQueryWrapper<SupplySystemMember>()
|
|
|
+ .eq(SupplySystemMember::getSystemId, systemId)
|
|
|
+ .eq(SupplySystemMember::getUserId, userId));
|
|
|
+ }
|
|
|
+
|
|
|
+ private SupplySystemMember getMemberByInviteCode(String inviteCode) {
|
|
|
+ if (inviteCode == null || inviteCode.trim().isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return supplySystemMemberMapper.selectOne(new LambdaQueryWrapper<SupplySystemMember>()
|
|
|
+ .eq(SupplySystemMember::getInviteCode, inviteCode.trim()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成全体系唯一邀请码:字符集去除易混淆字符(I/O/0/1),
|
|
|
+ * 幂等/重生成均校验唯一性(配合迁移444的 uk_supply_member_invite_code 唯一索引兜底)。
|
|
|
+ */
|
|
|
+ private String generateUniqueInviteCode() {
|
|
|
+ String chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
|
+ Random random = new Random();
|
|
|
+ for (int attempt = 0; attempt < 50; attempt++) {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (int i = 0; i < 8; i++) {
|
|
|
+ sb.append(chars.charAt(random.nextInt(chars.length())));
|
|
|
+ }
|
|
|
+ String code = sb.toString();
|
|
|
+ Long count = supplySystemMemberMapper.selectCount(new LambdaQueryWrapper<SupplySystemMember>()
|
|
|
+ .eq(SupplySystemMember::getInviteCode, code));
|
|
|
+ if (count == null || count == 0) {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 极端碰撞兜底(唯一索引重试仍失败时),避免死循环
|
|
|
+ return "T" + System.currentTimeMillis();
|
|
|
+ }
|
|
|
}
|