|
|
@@ -0,0 +1,437 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.etotem.cfc.entity.Activity;
|
|
|
+import com.etotem.cfc.entity.ActivityTeam;
|
|
|
+import com.etotem.cfc.entity.ActivityTeamMember;
|
|
|
+import com.etotem.cfc.entity.ServiceAssignment;
|
|
|
+import com.etotem.cfc.entity.User;
|
|
|
+import com.etotem.cfc.mapper.ActivityMapper;
|
|
|
+import com.etotem.cfc.mapper.ActivityTeamMapper;
|
|
|
+import com.etotem.cfc.mapper.ActivityTeamMemberMapper;
|
|
|
+import com.etotem.cfc.mapper.ServiceAssignmentMapper;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动管理团队(T35 规格 §2.2/§5)。
|
|
|
+ *
|
|
|
+ * <p>职责:
|
|
|
+ * <ol>
|
|
|
+ * <li>活动团队创建与成员管理(activity_team / activity_team_member);</li>
|
|
|
+ * <li>服务指派(复用服务指派机制,service_type=ACTIVITY_SUPPORT,
|
|
|
+ * 见 {@link ServiceAssignment}),把团队成员指派为某活动(或团队整体)的运营协作者;</li>
|
|
|
+ * <li>团队成员协作判定:团队 active 成员或活动服务指派人可协作运营该活动。</li>
|
|
|
+ * </ol>
|
|
|
+ *
|
|
|
+ * <p>说明:团队数据独立于 supply_system(供应体系)——供应体系成员会被商品分销同体系判定
|
|
|
+ * 复用(见 ProductService 的同体系判定),活动运营人员若混入其中会误获分销价,故单列。</p>
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ActivityTeamService extends ServiceImpl<ActivityTeamMapper, ActivityTeam> {
|
|
|
+
|
|
|
+ /** 服务指派类型:活动运营服务(T34 服务指派机制的 ACTIVITY_SUPPORT) */
|
|
|
+ public static final String SERVICE_TYPE_ACTIVITY_SUPPORT = "ACTIVITY_SUPPORT";
|
|
|
+
|
|
|
+ /** 指派目标类型:具体活动 */
|
|
|
+ public static final String TARGET_TYPE_ACTIVITY = "ACTIVITY";
|
|
|
+
|
|
|
+ /** 指派目标类型:团队整体 */
|
|
|
+ public static final String TARGET_TYPE_ACTIVITY_TEAM = "ACTIVITY_TEAM";
|
|
|
+
|
|
|
+ /** 团队成员角色 */
|
|
|
+ public static final String MEMBER_ROLE_OWNER = "owner";
|
|
|
+ public static final String MEMBER_ROLE_MANAGER = "manager";
|
|
|
+ public static final String MEMBER_ROLE_OPERATOR = "operator";
|
|
|
+
|
|
|
+ /** 服务指派角色 */
|
|
|
+ public static final String ASSIGN_ROLE_LEAD = "lead";
|
|
|
+ public static final String ASSIGN_ROLE_SUPPORT = "support";
|
|
|
+ public static final String ASSIGN_ROLE_CHECKIN = "checkin";
|
|
|
+ public static final String ASSIGN_ROLE_CONTENT = "content";
|
|
|
+
|
|
|
+ private static final Set<String> MEMBER_ROLES = new HashSet<>(Arrays.asList(
|
|
|
+ MEMBER_ROLE_OWNER, MEMBER_ROLE_MANAGER, MEMBER_ROLE_OPERATOR));
|
|
|
+ private static final Set<String> ASSIGN_ROLES = new HashSet<>(Arrays.asList(
|
|
|
+ ASSIGN_ROLE_LEAD, ASSIGN_ROLE_SUPPORT, ASSIGN_ROLE_CHECKIN, ASSIGN_ROLE_CONTENT));
|
|
|
+ private static final Set<String> TARGET_TYPES = new HashSet<>(Arrays.asList(
|
|
|
+ TARGET_TYPE_ACTIVITY, TARGET_TYPE_ACTIVITY_TEAM));
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ActivityTeamMemberMapper activityTeamMemberMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ServiceAssignmentMapper serviceAssignmentMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ActivityMapper activityMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private UserMapper userMapper;
|
|
|
+
|
|
|
+ // ==================== 团队 ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建活动团队,创建人自动成为团长成员(owner)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ActivityTeam createTeam(String name, String description, Long ownerId) {
|
|
|
+ if (name == null || name.trim().isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("团队名称不能为空");
|
|
|
+ }
|
|
|
+ if (ownerId == null) {
|
|
|
+ throw new IllegalArgumentException("创建人不能为空");
|
|
|
+ }
|
|
|
+ ActivityTeam team = new ActivityTeam();
|
|
|
+ team.setName(name.trim());
|
|
|
+ team.setDescription(description);
|
|
|
+ team.setOwnerId(ownerId);
|
|
|
+ team.setStatus("active");
|
|
|
+ team.setCreatedAt(new Date());
|
|
|
+ team.setUpdatedAt(new Date());
|
|
|
+ this.save(team);
|
|
|
+
|
|
|
+ ActivityTeamMember member = new ActivityTeamMember();
|
|
|
+ member.setTeamId(team.getId());
|
|
|
+ member.setUserId(ownerId);
|
|
|
+ member.setRole(MEMBER_ROLE_OWNER);
|
|
|
+ member.setStatus("active");
|
|
|
+ member.setJoinedAt(new Date());
|
|
|
+ activityTeamMemberMapper.insert(member);
|
|
|
+ return team;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 我所在的团队(团长或 active 成员)。includeAll=true 时返回全部团队(管理端视角)。
|
|
|
+ */
|
|
|
+ public List<ActivityTeam> listTeams(Long userId, boolean includeAll) {
|
|
|
+ if (includeAll) {
|
|
|
+ return this.list(new LambdaQueryWrapper<ActivityTeam>()
|
|
|
+ .orderByDesc(ActivityTeam::getId));
|
|
|
+ }
|
|
|
+ if (userId == null) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ Set<Long> teamIds = new HashSet<>();
|
|
|
+ List<ActivityTeamMember> memberships = activityTeamMemberMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<ActivityTeamMember>()
|
|
|
+ .eq(ActivityTeamMember::getUserId, userId)
|
|
|
+ .eq(ActivityTeamMember::getStatus, "active"));
|
|
|
+ for (ActivityTeamMember m : memberships) {
|
|
|
+ if (m.getTeamId() != null) {
|
|
|
+ teamIds.add(m.getTeamId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 防御:团长可能有成员记录缺失
|
|
|
+ List<ActivityTeam> owned = this.list(new LambdaQueryWrapper<ActivityTeam>()
|
|
|
+ .eq(ActivityTeam::getOwnerId, userId));
|
|
|
+ for (ActivityTeam t : owned) {
|
|
|
+ teamIds.add(t.getId());
|
|
|
+ }
|
|
|
+ if (teamIds.isEmpty()) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ return this.list(new LambdaQueryWrapper<ActivityTeam>()
|
|
|
+ .in(ActivityTeam::getId, teamIds)
|
|
|
+ .orderByDesc(ActivityTeam::getId));
|
|
|
+ }
|
|
|
+
|
|
|
+ public ActivityTeam getTeam(Long teamId) {
|
|
|
+ return teamId == null ? null : this.getById(teamId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 成员 ====================
|
|
|
+
|
|
|
+ public List<ActivityTeamMember> listMembers(Long teamId) {
|
|
|
+ if (teamId == null) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ return activityTeamMemberMapper.selectList(new LambdaQueryWrapper<ActivityTeamMember>()
|
|
|
+ .eq(ActivityTeamMember::getTeamId, teamId)
|
|
|
+ .eq(ActivityTeamMember::getStatus, "active")
|
|
|
+ .orderByAsc(ActivityTeamMember::getId));
|
|
|
+ }
|
|
|
+
|
|
|
+ public ActivityTeamMember getMembership(Long teamId, Long userId) {
|
|
|
+ if (teamId == null || userId == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return activityTeamMemberMapper.selectOne(new LambdaQueryWrapper<ActivityTeamMember>()
|
|
|
+ .eq(ActivityTeamMember::getTeamId, teamId)
|
|
|
+ .eq(ActivityTeamMember::getUserId, userId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 是否为团队在团成员 */
|
|
|
+ public boolean isActiveMember(Long teamId, Long userId) {
|
|
|
+ ActivityTeamMember member = getMembership(teamId, userId);
|
|
|
+ return member != null && "active".equals(member.getStatus());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 是否可管理团队(团长或运营主管) */
|
|
|
+ public boolean isTeamManager(Long teamId, Long userId) {
|
|
|
+ ActivityTeamMember member = getMembership(teamId, userId);
|
|
|
+ if (member == null || !"active".equals(member.getStatus())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return MEMBER_ROLE_OWNER.equals(member.getRole()) || MEMBER_ROLE_MANAGER.equals(member.getRole());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加团队成员(幂等:已在团则更新角色;已移出则重新激活)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ActivityTeamMember addMember(Long teamId, Long userId, String role) {
|
|
|
+ if (teamId == null) {
|
|
|
+ throw new IllegalArgumentException("团队不能为空");
|
|
|
+ }
|
|
|
+ if (userId == null) {
|
|
|
+ throw new IllegalArgumentException("成员用户不能为空");
|
|
|
+ }
|
|
|
+ User user = userMapper.selectById(userId);
|
|
|
+ if (user == null) {
|
|
|
+ throw new IllegalArgumentException("用户不存在");
|
|
|
+ }
|
|
|
+ String memberRole = normalizeMemberRole(role);
|
|
|
+ ActivityTeamMember existing = getMembership(teamId, userId);
|
|
|
+ if (existing != null) {
|
|
|
+ existing.setRole(memberRole);
|
|
|
+ existing.setStatus("active");
|
|
|
+ existing.setJoinedAt(new Date());
|
|
|
+ activityTeamMemberMapper.updateById(existing);
|
|
|
+ return existing;
|
|
|
+ }
|
|
|
+ ActivityTeamMember member = new ActivityTeamMember();
|
|
|
+ member.setTeamId(teamId);
|
|
|
+ member.setUserId(userId);
|
|
|
+ member.setRole(memberRole);
|
|
|
+ member.setStatus("active");
|
|
|
+ member.setJoinedAt(new Date());
|
|
|
+ activityTeamMemberMapper.insert(member);
|
|
|
+ return member;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 移出团队成员(团长不可被移出)
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public boolean removeMember(Long teamId, Long userId) {
|
|
|
+ ActivityTeam team = getTeam(teamId);
|
|
|
+ if (team == null) {
|
|
|
+ throw new IllegalArgumentException("团队不存在");
|
|
|
+ }
|
|
|
+ if (team.getOwnerId() != null && team.getOwnerId().equals(userId)) {
|
|
|
+ throw new IllegalArgumentException("团长不能被移出团队");
|
|
|
+ }
|
|
|
+ ActivityTeamMember member = getMembership(teamId, userId);
|
|
|
+ if (member == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ member.setStatus("removed");
|
|
|
+ activityTeamMemberMapper.updateById(member);
|
|
|
+ // 同步撤销该成员在本团队下的活动服务指派
|
|
|
+ List<ServiceAssignment> assignments = serviceAssignmentMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<ServiceAssignment>()
|
|
|
+ .eq(ServiceAssignment::getTeamId, teamId)
|
|
|
+ .eq(ServiceAssignment::getAssigneeId, userId)
|
|
|
+ .eq(ServiceAssignment::getServiceType, SERVICE_TYPE_ACTIVITY_SUPPORT)
|
|
|
+ .eq(ServiceAssignment::getStatus, "active"));
|
|
|
+ for (ServiceAssignment assignment : assignments) {
|
|
|
+ assignment.setStatus("revoked");
|
|
|
+ assignment.setUpdatedAt(new Date());
|
|
|
+ serviceAssignmentMapper.updateById(assignment);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String normalizeMemberRole(String role) {
|
|
|
+ if (role == null || role.trim().isEmpty()) {
|
|
|
+ return MEMBER_ROLE_OPERATOR;
|
|
|
+ }
|
|
|
+ String normalized = role.trim().toLowerCase();
|
|
|
+ if (!MEMBER_ROLES.contains(normalized)) {
|
|
|
+ throw new IllegalArgumentException("成员角色不合法: " + role);
|
|
|
+ }
|
|
|
+ return normalized;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 服务指派(ACTIVITY_SUPPORT) ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 指派服务:把团队成员指派为某活动(或团队整体)的运营协作者。
|
|
|
+ *
|
|
|
+ * @param teamId 团队ID
|
|
|
+ * @param targetType ACTIVITY / ACTIVITY_TEAM
|
|
|
+ * @param targetId 目标ID
|
|
|
+ * @param assigneeId 被指派人 userId(须为团队在团成员)
|
|
|
+ * @param role 指派角色 lead/support/checkin/content
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public ServiceAssignment assignService(Long teamId, String targetType, Long targetId,
|
|
|
+ Long assigneeId, String role, String remark, Long operatorId) {
|
|
|
+ if (teamId == null) {
|
|
|
+ throw new IllegalArgumentException("团队不能为空");
|
|
|
+ }
|
|
|
+ if (targetType == null || !TARGET_TYPES.contains(targetType.trim().toUpperCase())) {
|
|
|
+ throw new IllegalArgumentException("指派目标类型不合法");
|
|
|
+ }
|
|
|
+ String normalizedTargetType = targetType.trim().toUpperCase();
|
|
|
+ if (targetId == null) {
|
|
|
+ throw new IllegalArgumentException("指派目标不能为空");
|
|
|
+ }
|
|
|
+ if (assigneeId == null) {
|
|
|
+ throw new IllegalArgumentException("被指派人不能为空");
|
|
|
+ }
|
|
|
+ String assignRole = normalizeAssignRole(role);
|
|
|
+ if (getTeam(teamId) == null) {
|
|
|
+ throw new IllegalArgumentException("团队不存在");
|
|
|
+ }
|
|
|
+ if (TARGET_TYPE_ACTIVITY.equals(normalizedTargetType)) {
|
|
|
+ if (activityMapper.selectById(targetId) == null) {
|
|
|
+ throw new IllegalArgumentException("活动不存在");
|
|
|
+ }
|
|
|
+ } else if (getTeam(targetId) == null) {
|
|
|
+ throw new IllegalArgumentException("目标团队不存在");
|
|
|
+ }
|
|
|
+ if (!isActiveMember(teamId, assigneeId)) {
|
|
|
+ throw new IllegalArgumentException("被指派人须为团队在团成员");
|
|
|
+ }
|
|
|
+
|
|
|
+ ServiceAssignment existing = serviceAssignmentMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<ServiceAssignment>()
|
|
|
+ .eq(ServiceAssignment::getServiceType, SERVICE_TYPE_ACTIVITY_SUPPORT)
|
|
|
+ .eq(ServiceAssignment::getTargetType, normalizedTargetType)
|
|
|
+ .eq(ServiceAssignment::getTargetId, targetId)
|
|
|
+ .eq(ServiceAssignment::getAssigneeId, assigneeId)
|
|
|
+ .eq(ServiceAssignment::getRole, assignRole)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ Date now = new Date();
|
|
|
+ if (existing != null) {
|
|
|
+ existing.setStatus("active");
|
|
|
+ existing.setTeamId(teamId);
|
|
|
+ existing.setRemark(remark);
|
|
|
+ existing.setAssignedBy(operatorId);
|
|
|
+ existing.setUpdatedAt(now);
|
|
|
+ serviceAssignmentMapper.updateById(existing);
|
|
|
+ return existing;
|
|
|
+ }
|
|
|
+ ServiceAssignment assignment = new ServiceAssignment();
|
|
|
+ assignment.setServiceType(SERVICE_TYPE_ACTIVITY_SUPPORT);
|
|
|
+ assignment.setTargetType(normalizedTargetType);
|
|
|
+ assignment.setTargetId(targetId);
|
|
|
+ assignment.setTeamId(teamId);
|
|
|
+ assignment.setAssigneeId(assigneeId);
|
|
|
+ assignment.setRole(assignRole);
|
|
|
+ assignment.setStatus("active");
|
|
|
+ assignment.setRemark(remark);
|
|
|
+ assignment.setAssignedBy(operatorId);
|
|
|
+ assignment.setCreatedAt(now);
|
|
|
+ assignment.setUpdatedAt(now);
|
|
|
+ serviceAssignmentMapper.insert(assignment);
|
|
|
+ return assignment;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询服务指派记录。targetId 为空时按 teamId 查全部。
|
|
|
+ */
|
|
|
+ public List<ServiceAssignment> listAssignments(Long teamId, String targetType, Long targetId) {
|
|
|
+ LambdaQueryWrapper<ServiceAssignment> wrapper = new LambdaQueryWrapper<ServiceAssignment>()
|
|
|
+ .eq(ServiceAssignment::getServiceType, SERVICE_TYPE_ACTIVITY_SUPPORT)
|
|
|
+ .eq(ServiceAssignment::getStatus, "active");
|
|
|
+ if (teamId != null) {
|
|
|
+ wrapper.eq(ServiceAssignment::getTeamId, teamId);
|
|
|
+ }
|
|
|
+ if (targetType != null && !targetType.trim().isEmpty()) {
|
|
|
+ wrapper.eq(ServiceAssignment::getTargetType, targetType.trim().toUpperCase());
|
|
|
+ }
|
|
|
+ if (targetId != null) {
|
|
|
+ wrapper.eq(ServiceAssignment::getTargetId, targetId);
|
|
|
+ }
|
|
|
+ wrapper.orderByDesc(ServiceAssignment::getId);
|
|
|
+ return serviceAssignmentMapper.selectList(wrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 撤销服务指派
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public boolean revokeAssignment(Long assignmentId) {
|
|
|
+ if (assignmentId == null) {
|
|
|
+ throw new IllegalArgumentException("指派记录不能为空");
|
|
|
+ }
|
|
|
+ ServiceAssignment assignment = serviceAssignmentMapper.selectById(assignmentId);
|
|
|
+ if (assignment == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ assignment.setStatus("revoked");
|
|
|
+ assignment.setUpdatedAt(new Date());
|
|
|
+ return serviceAssignmentMapper.updateById(assignment) > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String normalizeAssignRole(String role) {
|
|
|
+ if (role == null || role.trim().isEmpty()) {
|
|
|
+ return ASSIGN_ROLE_SUPPORT;
|
|
|
+ }
|
|
|
+ String normalized = role.trim().toLowerCase();
|
|
|
+ if (!ASSIGN_ROLES.contains(normalized)) {
|
|
|
+ throw new IllegalArgumentException("指派角色不合法: " + role);
|
|
|
+ }
|
|
|
+ return normalized;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 协作判定 ====================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否为该活动的运营协作者:团队在团成员,或该活动(或其团队)的服务指派人。
|
|
|
+ */
|
|
|
+ public boolean isActivityCollaborator(Activity activity, Long userId) {
|
|
|
+ if (activity == null || userId == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (activity.getTeamId() != null && isActiveMember(activity.getTeamId(), userId)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return isAssigneeOfActivity(activity, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否被指派参与该活动(服务指派 ACTIVITY_SUPPORT,status=active)
|
|
|
+ */
|
|
|
+ public boolean isAssigneeOfActivity(Activity activity, Long userId) {
|
|
|
+ if (activity == null || userId == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Long count = serviceAssignmentMapper.selectCount(new LambdaQueryWrapper<ServiceAssignment>()
|
|
|
+ .eq(ServiceAssignment::getServiceType, SERVICE_TYPE_ACTIVITY_SUPPORT)
|
|
|
+ .eq(ServiceAssignment::getStatus, "active")
|
|
|
+ .eq(ServiceAssignment::getAssigneeId, userId)
|
|
|
+ .and(w -> w
|
|
|
+ .and(x -> x.eq(ServiceAssignment::getTargetType, TARGET_TYPE_ACTIVITY)
|
|
|
+ .eq(ServiceAssignment::getTargetId, activity.getId()))
|
|
|
+ .or(x -> x.eq(ServiceAssignment::getTargetType, TARGET_TYPE_ACTIVITY_TEAM)
|
|
|
+ .eq(ServiceAssignment::getTargetId, activity.getTeamId() == null ? -1L : activity.getTeamId()))));
|
|
|
+ return count != null && count > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 团队名下活动列表
|
|
|
+ */
|
|
|
+ public List<Activity> listTeamActivities(Long teamId) {
|
|
|
+ if (teamId == null) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ return activityMapper.selectList(new LambdaQueryWrapper<Activity>()
|
|
|
+ .eq(Activity::getTeamId, teamId)
|
|
|
+ .orderByDesc(Activity::getId));
|
|
|
+ }
|
|
|
+}
|