stgl1.1
This commit is contained in:
1 parent
d5316b3d37
commit
4c2154bfde
8 files changed
+1019
-59
No files matched your search
+253
-1
@@ -21,16 +21,27 @@ import org.dromara.stgl.domain.bo.StglActivityBo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityVo;
|
||||
import org.dromara.stgl.mapper.StglActivityMapper;
|
||||
import org.dromara.stgl.service.IStglActivityService;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.StglVolunteerTeam;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglVolunteerTeamMapper;
|
||||
|
||||
/**
|
||||
* 活动信息Service业务层处理
|
||||
@@ -38,11 +49,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @author ruoyi
|
||||
* @date 2025-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, StglActivity> implements IStglActivityService {
|
||||
|
||||
private final StglActivityMapper baseMapper;
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
private final StglClubMapper stglClubMapper;
|
||||
private final StglVolunteerTeamMapper stglVolunteerTeamMapper;
|
||||
|
||||
/**
|
||||
* 查询活动信息
|
||||
@@ -57,6 +72,9 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglActivityVo> queryPageList(StglActivityBo bo, PageQuery pageQuery) {
|
||||
// 应用数据权限控制
|
||||
applyDataScope(bo);
|
||||
|
||||
// 转换为实体对象,使用自定义SQL查询(包含关联信息)
|
||||
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
|
||||
Page<StglActivityVo> result = baseMapper.selectVoPage(pageQuery.build(), activity);
|
||||
@@ -68,6 +86,9 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
*/
|
||||
@Override
|
||||
public List<StglActivityVo> queryList(StglActivityBo bo) {
|
||||
// 应用数据权限控制
|
||||
applyDataScope(bo);
|
||||
|
||||
// 转换为实体对象,使用自定义SQL查询(包含关联信息)
|
||||
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
|
||||
List<StglActivityVo> list = baseMapper.selectVoList(activity);
|
||||
@@ -215,6 +236,8 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
// 为指导老师分配角色
|
||||
assignAdvisorRoles(add);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@@ -227,7 +250,21 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
public Boolean updateByBo(StglActivityBo bo) {
|
||||
StglActivity update = MapstructUtils.convert(bo, StglActivity.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
|
||||
// 获取更新前的活动信息,用于比较指导老师变化
|
||||
StglActivity oldActivity = null;
|
||||
if (update.getId() != null) {
|
||||
oldActivity = baseMapper.selectById(update.getId());
|
||||
}
|
||||
|
||||
boolean updateResult = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (updateResult) {
|
||||
// 处理指导老师角色分配
|
||||
handleAdvisorRoleAssignment(oldActivity, update);
|
||||
}
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,4 +419,219 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
return baseMapper.update(null, wrapper) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指导老师分配角色
|
||||
*
|
||||
* @param activity 活动信息
|
||||
*/
|
||||
private void assignAdvisorRoles(StglActivity activity) {
|
||||
try {
|
||||
List<Long> advisorUserIds = extractAdvisorUserIds(activity);
|
||||
if (!advisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserIds);
|
||||
log.info("成功为活动 {} 的指导老师分配角色,指导老师数量: {}", activity.getActivityName(), advisorUserIds.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为活动 {} 的指导老师分配角色时发生异常: {}", activity.getActivityName(), e.getMessage());
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指导老师角色分配(更新时使用)
|
||||
*
|
||||
* @param oldActivity 更新前的活动信息
|
||||
* @param newActivity 更新后的活动信息
|
||||
*/
|
||||
private void handleAdvisorRoleAssignment(StglActivity oldActivity, StglActivity newActivity) {
|
||||
try {
|
||||
// 获取更新前后的指导老师用户ID列表
|
||||
List<Long> oldAdvisorUserIds = oldActivity != null ? extractAdvisorUserIds(oldActivity) : new ArrayList<>();
|
||||
List<Long> newAdvisorUserIds = extractAdvisorUserIds(newActivity);
|
||||
|
||||
// 找出新增的指导老师
|
||||
List<Long> addedAdvisorUserIds = newAdvisorUserIds.stream()
|
||||
.filter(id -> !oldAdvisorUserIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 找出移除的指导老师
|
||||
List<Long> removedAdvisorUserIds = oldAdvisorUserIds.stream()
|
||||
.filter(id -> !newAdvisorUserIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 为新指导老师分配角色
|
||||
if (!addedAdvisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.assignAdvisorRole(addedAdvisorUserIds);
|
||||
log.info("活动 {} 新增指导老师,成功分配角色,数量: {}", newActivity.getActivityName(), addedAdvisorUserIds.size());
|
||||
}
|
||||
|
||||
// 移除旧指导老师的角色
|
||||
if (!removedAdvisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.removeAdvisorRoles(removedAdvisorUserIds);
|
||||
log.info("活动 {} 移除指导老师,成功移除角色,数量: {}", newActivity.getActivityName(), removedAdvisorUserIds.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理活动 {} 的指导老师角色分配时发生异常: {}", newActivity.getActivityName(), e.getMessage());
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从活动信息中提取指导老师用户ID列表
|
||||
*
|
||||
* @param activity 活动信息
|
||||
* @return 指导老师用户ID列表
|
||||
*/
|
||||
private List<Long> extractAdvisorUserIds(StglActivity activity) {
|
||||
List<Long> advisorUserIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 从JSON字段读取指导老师数据
|
||||
if (StringUtils.isNotBlank(activity.getInstructors())) {
|
||||
List<Map<String, Object>> instructors = JsonUtils.parseObject(activity.getInstructors(), new TypeReference<List<Map<String, Object>>>() {});
|
||||
for (Map<String, Object> instructor : instructors) {
|
||||
// 修复:支持嵌套的JSON结构,从teacher子对象中提取userId
|
||||
Object userIdObj = null;
|
||||
|
||||
// 尝试直接从instructor对象获取userId(兼容旧格式)
|
||||
if (instructor.containsKey("userId")) {
|
||||
userIdObj = instructor.get("userId");
|
||||
}
|
||||
// 尝试从teacher子对象获取userId(新格式)
|
||||
else if (instructor.containsKey("teacher")) {
|
||||
Object teacherObj = instructor.get("teacher");
|
||||
if (teacherObj instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> teacher = (Map<String, Object>) teacherObj;
|
||||
userIdObj = teacher.get("userId");
|
||||
}
|
||||
}
|
||||
|
||||
if (userIdObj != null) {
|
||||
Long userId = Long.valueOf(userIdObj.toString());
|
||||
if (userId != null) {
|
||||
advisorUserIds.add(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析活动 {} 的指导老师数据时发生异常: {}", activity.getActivityName(), e.getMessage());
|
||||
}
|
||||
|
||||
return advisorUserIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用数据权限控制
|
||||
* 如果是stgl_president角色,只能查看自己创建的活动
|
||||
* 如果是stgl_instructor角色,只能查看自己作为指导老师的社团的活动
|
||||
*
|
||||
* @param bo 查询条件
|
||||
*/
|
||||
private void applyDataScope(StglActivityBo bo) {
|
||||
try {
|
||||
// 获取当前登录用户信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
if (currentUserId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> roleKeys = LoginHelper.getLoginUser().getRolePermission();
|
||||
|
||||
// 如果是stgl_president角色且不是管理员,只能查看自己创建的活动
|
||||
if (roleKeys.contains("stgl_president") &&
|
||||
!roleKeys.contains("admin") &&
|
||||
!roleKeys.contains("common")) {
|
||||
|
||||
// 设置数据权限过滤条件 - 使用params.dataScope方式,与XML中的${activity.params.dataScope}对应
|
||||
if (bo.getParams() == null) {
|
||||
bo.setParams(new HashMap<>());
|
||||
}
|
||||
bo.getParams().put("dataScope", "AND sa.create_by = " + currentUserId);
|
||||
log.info("应用数据权限:用户 {} 为社长角色,只能查看自己创建的活动", currentUserId);
|
||||
}
|
||||
|
||||
// 🔥 新增:如果是stgl_instructor角色且不是管理员,只能查看自己作为指导老师的社团的活动
|
||||
if (roleKeys.contains("stgl_instructor") &&
|
||||
!roleKeys.contains("admin") &&
|
||||
!roleKeys.contains("common")) {
|
||||
|
||||
// 获取用户作为指导老师的社团ID列表
|
||||
List<Long> userAdvisorClubIds = getUserAdvisorClubIds(currentUserId);
|
||||
|
||||
if (userAdvisorClubIds.isEmpty()) {
|
||||
// 如果不是任何社团的指导老师,设置一个不存在的ID,返回空结果
|
||||
if (bo.getParams() == null) {
|
||||
bo.setParams(new HashMap<>());
|
||||
}
|
||||
bo.getParams().put("dataScope", "AND sa.related_club_id = -1");
|
||||
log.info("应用数据权限:用户 {} 为指导老师角色,但不是任何社团的指导老师,返回空结果", currentUserId);
|
||||
} else {
|
||||
// 设置数据权限过滤条件 - 只能查看自己作为指导老师的社团的活动
|
||||
if (bo.getParams() == null) {
|
||||
bo.setParams(new HashMap<>());
|
||||
}
|
||||
String clubIdsStr = userAdvisorClubIds.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(","));
|
||||
bo.getParams().put("dataScope", "AND sa.related_club_id IN (" + clubIdsStr + ")");
|
||||
log.info("应用数据权限:用户 {} 为指导老师角色,只能查看社团ID为 {} 的活动", currentUserId, clubIdsStr);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("应用数据权限控制失败:{}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户作为指导老师的社团ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团ID列表
|
||||
*/
|
||||
private List<Long> getUserAdvisorClubIds(Long userId) {
|
||||
List<Long> clubIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 从stgl_club表的advisors_json字段查询
|
||||
List<Long> jsonClubIds = getJsonAdvisorClubIds(userId);
|
||||
clubIds.addAll(jsonClubIds);
|
||||
|
||||
log.debug("用户 {} 作为指导老师的社团ID列表: {}", userId, clubIds);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户 {} 作为指导老师的社团ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return clubIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从社团表的advisors_json字段获取用户作为指导老师的社团ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团ID列表
|
||||
*/
|
||||
private List<Long> getJsonAdvisorClubIds(Long userId) {
|
||||
List<Long> clubIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 查询社团表中advisors_json字段包含该用户的记录
|
||||
LambdaQueryWrapper<StglClub> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.select(StglClub::getId);
|
||||
lqw.like(StglClub::getAdvisorsJson, userId.toString());
|
||||
|
||||
List<StglClub> clubs = stglClubMapper.selectList(lqw);
|
||||
clubIds = clubs.stream()
|
||||
.map(StglClub::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("从社团表获取用户 {} 作为指导老师的社团ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return clubIds;
|
||||
}
|
||||
}
|
||||
+237
-2
@@ -17,6 +17,7 @@ import org.dromara.stgl.domain.StglMember;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglMemberMapper;
|
||||
import org.dromara.stgl.service.IStglClubService;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
@@ -35,10 +36,12 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -58,6 +61,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
private final StglMemberMapper memberMapper;
|
||||
// 添加学生信息Mapper
|
||||
private final XgStudentMsgMapper studentMsgMapper;
|
||||
// 添加指导老师角色分配工具
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
|
||||
/**
|
||||
* 查询社团信息
|
||||
@@ -143,6 +148,31 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
bo.setClubIds(userClubIds);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 新增:如果是stgl_instructor角色且不是管理员,只能查看自己作为指导老师的社团
|
||||
if (roleKeys.contains("stgl_instructor") &&
|
||||
!roleKeys.contains("admin") &&
|
||||
!roleKeys.contains("common")) {
|
||||
|
||||
// 获取用户作为指导老师的社团ID列表
|
||||
List<Long> userAdvisorClubIds = getUserAdvisorClubIds(currentUserId);
|
||||
|
||||
if (userAdvisorClubIds.isEmpty()) {
|
||||
// 如果不是任何社团的指导老师,设置一个不存在的ID,返回空结果
|
||||
bo.setClubIds(Collections.singletonList(-1L));
|
||||
} else {
|
||||
// 如果之前已经设置了clubIds(比如stgl_president角色),则取交集
|
||||
if (CollectionUtils.isNotEmpty(bo.getClubIds())) {
|
||||
List<Long> intersection = bo.getClubIds().stream()
|
||||
.filter(userAdvisorClubIds::contains)
|
||||
.collect(Collectors.toList());
|
||||
bo.setClubIds(intersection.isEmpty() ? Collections.singletonList(-1L) : intersection);
|
||||
} else {
|
||||
// 设置数据权限过滤条件
|
||||
bo.setClubIds(userAdvisorClubIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果获取权限信息失败,不影响正常查询
|
||||
log.warn("获取用户权限信息失败: {}", e.getMessage());
|
||||
@@ -164,7 +194,7 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, 1) // 社团成员
|
||||
.eq(StglMember::getUserId, userId) // 当前用户
|
||||
.eq(StglMember::getRoleType, 1) // 社长角色
|
||||
.eq(StglMember::getRoleType, "社长") // 社长角色 - 修复:使用字符串而不是数值
|
||||
.eq(StglMember::getStatus, 2); // 已加入状态
|
||||
|
||||
List<StglMember> members = memberMapper.selectList(lqw);
|
||||
@@ -178,6 +208,91 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户作为指导老师的社团ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团ID列表
|
||||
*/
|
||||
private List<Long> getUserAdvisorClubIds(Long userId) {
|
||||
if (userId == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
// 方法1:从stgl_member表查询(如果指导老师作为成员记录)
|
||||
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
|
||||
memberLqw.eq(StglMember::getMemberType, 1) // 社团成员
|
||||
.eq(StglMember::getUserId, userId) // 当前用户
|
||||
.eq(StglMember::getRoleType, "指导老师") // 指导老师角色
|
||||
.eq(StglMember::getStatus, 2); // 已加入状态
|
||||
|
||||
List<StglMember> memberAdvisors = memberMapper.selectList(memberLqw);
|
||||
List<Long> memberClubIds = memberAdvisors.stream()
|
||||
.map(StglMember::getRelationId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 方法2:从社团表的advisors_json字段查询(主要方法)
|
||||
LambdaQueryWrapper<StglClub> clubLqw = Wrappers.lambdaQuery();
|
||||
clubLqw.select(StglClub::getId, StglClub::getAdvisorsJson);
|
||||
clubLqw.isNotNull(StglClub::getAdvisorsJson);
|
||||
clubLqw.ne(StglClub::getAdvisorsJson, "");
|
||||
|
||||
List<StglClub> clubs = baseMapper.selectList(clubLqw);
|
||||
List<Long> jsonClubIds = new ArrayList<>();
|
||||
|
||||
for (StglClub club : clubs) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(club.getAdvisorsJson())) {
|
||||
List<Map<String, Object>> advisors = JsonUtils.parseObject(
|
||||
club.getAdvisorsJson(),
|
||||
new TypeReference<List<Map<String, Object>>>() {}
|
||||
);
|
||||
|
||||
for (Map<String, Object> advisor : advisors) {
|
||||
Object userIdObj = null;
|
||||
|
||||
// 尝试直接从advisor对象获取userId
|
||||
if (advisor.containsKey("userId")) {
|
||||
userIdObj = advisor.get("userId");
|
||||
}
|
||||
// 尝试从teacher子对象获取userId
|
||||
else if (advisor.containsKey("teacher")) {
|
||||
Object teacherObj = advisor.get("teacher");
|
||||
if (teacherObj instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> teacher = (Map<String, Object>) teacherObj;
|
||||
userIdObj = teacher.get("userId");
|
||||
}
|
||||
}
|
||||
|
||||
if (userIdObj != null && userId.toString().equals(userIdObj.toString())) {
|
||||
jsonClubIds.add(club.getId());
|
||||
break; // 找到该用户,继续下一个社团
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析社团 {} 的指导老师JSON数据失败: {}", club.getId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 合并两种方法的结果
|
||||
Set<Long> allClubIds = new HashSet<>();
|
||||
allClubIds.addAll(memberClubIds);
|
||||
allClubIds.addAll(jsonClubIds);
|
||||
|
||||
log.info("用户 {} 作为指导老师的社团ID列表: memberClubIds={}, jsonClubIds={}, 最终结果={}",
|
||||
userId, memberClubIds, jsonClubIds, allClubIds);
|
||||
|
||||
return new ArrayList<>(allClubIds);
|
||||
} catch (Exception e) {
|
||||
log.error("查询用户作为指导老师的社团失败: {}", e.getMessage(), e);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglClub> buildQueryWrapper(StglClubBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
@@ -215,6 +330,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
bo.setId(add.getId());
|
||||
// 自动创建社长和副社长的成员记录
|
||||
createLeaderMemberRecords(add);
|
||||
// 为指导老师分配角色
|
||||
assignAdvisorRoles(add);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@@ -231,12 +348,20 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
StglClub update = MapstructUtils.convert(bo, StglClub.class);
|
||||
validEntityBeforeSave(update);
|
||||
|
||||
// 获取更新前的社团信息,用于比较指导老师变化
|
||||
StglClub oldClub = null;
|
||||
if (update.getId() != null) {
|
||||
oldClub = baseMapper.selectById(update.getId());
|
||||
}
|
||||
|
||||
// 更新社团基本信息
|
||||
boolean updateResult = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (updateResult) {
|
||||
// 同步更新副社长的成员记录
|
||||
syncVicePresidentsInMembers(update);
|
||||
// 处理指导老师角色分配
|
||||
handleAdvisorRoleAssignment(oldClub, update);
|
||||
}
|
||||
|
||||
return updateResult;
|
||||
@@ -867,7 +992,7 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
lqw.eq(StglMember::getMemberType, 1); // 社团成员
|
||||
lqw.eq(StglMember::getRelationId, clubId); // 该社团
|
||||
lqw.eq(StglMember::getUserId, userId); // 指定用户
|
||||
lqw.eq(StglMember::getRoleType, 1); // 社长角色 (1-社长)
|
||||
lqw.eq(StglMember::getRoleType, "社长"); // 社长角色 - 修复:使用字符串而不是数值
|
||||
lqw.eq(StglMember::getStatus, 2); // 已加入状态 (2-已加入)
|
||||
|
||||
StglMember member = memberMapper.selectOne(lqw);
|
||||
@@ -973,4 +1098,114 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指导老师分配角色
|
||||
*
|
||||
* @param club 社团信息
|
||||
*/
|
||||
private void assignAdvisorRoles(StglClub club) {
|
||||
try {
|
||||
List<Long> advisorUserIds = extractAdvisorUserIds(club);
|
||||
if (!advisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserIds);
|
||||
log.info("成功为社团 {} 的指导老师分配角色,指导老师数量: {}", club.getClubName(), advisorUserIds.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为社团 {} 的指导老师分配角色时发生异常", club.getClubName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指导老师角色分配(更新时使用)
|
||||
*
|
||||
* @param oldClub 更新前的社团信息
|
||||
* @param newClub 更新后的社团信息
|
||||
*/
|
||||
private void handleAdvisorRoleAssignment(StglClub oldClub, StglClub newClub) {
|
||||
try {
|
||||
// 获取更新前后的指导老师用户ID列表
|
||||
List<Long> oldAdvisorUserIds = oldClub != null ? extractAdvisorUserIds(oldClub) : new ArrayList<>();
|
||||
List<Long> newAdvisorUserIds = extractAdvisorUserIds(newClub);
|
||||
|
||||
// 找出新增的指导老师
|
||||
List<Long> addedAdvisorUserIds = newAdvisorUserIds.stream()
|
||||
.filter(id -> !oldAdvisorUserIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 找出移除的指导老师
|
||||
List<Long> removedAdvisorUserIds = oldAdvisorUserIds.stream()
|
||||
.filter(id -> !newAdvisorUserIds.contains(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 为新指导老师分配角色
|
||||
if (!addedAdvisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.assignAdvisorRole(addedAdvisorUserIds);
|
||||
log.info("社团 {} 新增指导老师,成功分配角色,数量: {}", newClub.getClubName(), addedAdvisorUserIds.size());
|
||||
}
|
||||
|
||||
// 移除旧指导老师的角色
|
||||
if (!removedAdvisorUserIds.isEmpty()) {
|
||||
advisorRoleAssigner.removeAdvisorRoles(removedAdvisorUserIds);
|
||||
log.info("社团 {} 移除指导老师,成功移除角色,数量: {}", newClub.getClubName(), removedAdvisorUserIds.size());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理社团 {} 的指导老师角色分配时发生异常", newClub.getClubName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从社团信息中提取指导老师用户ID列表
|
||||
*
|
||||
* @param club 社团信息
|
||||
* @return 指导老师用户ID列表
|
||||
*/
|
||||
private List<Long> extractAdvisorUserIds(StglClub club) {
|
||||
List<Long> advisorUserIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 优先从JSON字段读取指导老师数据
|
||||
if (StringUtils.isNotBlank(club.getAdvisorsJson())) {
|
||||
List<Map<String, Object>> advisors = JsonUtils.parseObject(club.getAdvisorsJson(), new TypeReference<List<Map<String, Object>>>() {});
|
||||
for (Map<String, Object> advisor : advisors) {
|
||||
// 修复:支持嵌套的JSON结构,从teacher子对象中提取userId
|
||||
Object userIdObj = null;
|
||||
|
||||
// 尝试直接从advisor对象获取userId(兼容旧格式)
|
||||
if (advisor.containsKey("userId")) {
|
||||
userIdObj = advisor.get("userId");
|
||||
}
|
||||
// 尝试从teacher子对象获取userId(新格式)
|
||||
else if (advisor.containsKey("teacher")) {
|
||||
Object teacherObj = advisor.get("teacher");
|
||||
if (teacherObj instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> teacher = (Map<String, Object>) teacherObj;
|
||||
userIdObj = teacher.get("userId");
|
||||
}
|
||||
}
|
||||
|
||||
if (userIdObj != null) {
|
||||
Long userId = Long.valueOf(userIdObj.toString());
|
||||
if (userId != null) {
|
||||
advisorUserIds.add(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有JSON数据,尝试从单一字段获取
|
||||
if (advisorUserIds.isEmpty() && StringUtils.isNotBlank(club.getAdvisorName())) {
|
||||
// 这里需要根据指导老师姓名查找用户ID,暂时跳过
|
||||
// 因为单一字段模式下没有用户ID信息
|
||||
log.debug("社团 {} 使用单一指导老师字段,无法获取用户ID", club.getClubName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析社团 {} 的指导老师数据时发生异常", club.getClubName(), e);
|
||||
}
|
||||
|
||||
return advisorUserIds;
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -25,13 +25,16 @@ import org.dromara.system.mapper.SysUserMapper;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 志愿者队伍Service业务层处理
|
||||
@@ -39,6 +42,7 @@ import java.util.List;
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
@@ -47,6 +51,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
private final StglMemberMapper memberMapper;
|
||||
private final XgStudentMsgMapper studentMsgMapper;
|
||||
private final SysUserMapper userMapper;
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
|
||||
/**
|
||||
* 查询志愿者队伍
|
||||
@@ -148,6 +153,8 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
bo.setId(add.getId());
|
||||
// 自动创建队长的成员记录
|
||||
createLeaderMemberRecord(add);
|
||||
// 为指导老师分配角色
|
||||
assignAdvisorRole(add);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@@ -161,12 +168,20 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
StglVolunteerTeam update = MapstructUtils.convert(bo, StglVolunteerTeam.class);
|
||||
validEntityBeforeSave(update);
|
||||
|
||||
// 获取更新前的队伍信息,用于比较指导老师变化
|
||||
StglVolunteerTeam oldTeam = null;
|
||||
if (update.getId() != null) {
|
||||
oldTeam = baseMapper.selectById(update.getId());
|
||||
}
|
||||
|
||||
// 更新队伍基本信息
|
||||
boolean updateResult = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (updateResult) {
|
||||
// 同步更新队长的成员记录
|
||||
syncLeaderInMembers(update);
|
||||
// 处理指导老师角色分配
|
||||
handleAdvisorRoleAssignment(oldTeam, update);
|
||||
}
|
||||
|
||||
return updateResult;
|
||||
@@ -831,4 +846,77 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
team.setSighOpen(sighOpen);
|
||||
return baseMapper.updateById(team) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为指导老师分配角色
|
||||
*
|
||||
* @param team 志愿者队伍信息
|
||||
*/
|
||||
private void assignAdvisorRole(StglVolunteerTeam team) {
|
||||
try {
|
||||
Long advisorUserId = extractAdvisorUserId(team);
|
||||
if (advisorUserId != null) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserId);
|
||||
log.info("成功为志愿者队伍 {} 的指导老师分配角色,指导老师用户ID: {}", team.getTeamName(), advisorUserId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为志愿者队伍 {} 的指导老师分配角色时发生异常", team.getTeamName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理指导老师角色分配(更新时使用)
|
||||
*
|
||||
* @param oldTeam 更新前的队伍信息
|
||||
* @param newTeam 更新后的队伍信息
|
||||
*/
|
||||
private void handleAdvisorRoleAssignment(StglVolunteerTeam oldTeam, StglVolunteerTeam newTeam) {
|
||||
try {
|
||||
// 获取更新前后的指导老师用户ID
|
||||
Long oldAdvisorUserId = oldTeam != null ? extractAdvisorUserId(oldTeam) : null;
|
||||
Long newAdvisorUserId = extractAdvisorUserId(newTeam);
|
||||
|
||||
// 如果指导老师发生变化
|
||||
if (!Objects.equals(oldAdvisorUserId, newAdvisorUserId)) {
|
||||
// 移除旧指导老师的角色
|
||||
if (oldAdvisorUserId != null) {
|
||||
advisorRoleAssigner.removeAdvisorRole(oldAdvisorUserId);
|
||||
log.info("志愿者队伍 {} 移除指导老师,成功移除角色,用户ID: {}", newTeam.getTeamName(), oldAdvisorUserId);
|
||||
}
|
||||
|
||||
// 为新指导老师分配角色
|
||||
if (newAdvisorUserId != null) {
|
||||
advisorRoleAssigner.assignAdvisorRole(newAdvisorUserId);
|
||||
log.info("志愿者队伍 {} 新增指导老师,成功分配角色,用户ID: {}", newTeam.getTeamName(), newAdvisorUserId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理志愿者队伍 {} 的指导老师角色分配时发生异常", newTeam.getTeamName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从志愿者队伍信息中提取指导老师用户ID
|
||||
*
|
||||
* @param team 志愿者队伍信息
|
||||
* @return 指导老师用户ID
|
||||
*/
|
||||
private Long extractAdvisorUserId(StglVolunteerTeam team) {
|
||||
// 志愿者队伍目前使用单一指导老师字段,需要根据指导老师姓名查找用户ID
|
||||
if (StringUtils.isNotBlank(team.getAdvisorName())) {
|
||||
try {
|
||||
// 这里需要根据指导老师姓名查找用户ID
|
||||
// 由于志愿者队伍表没有直接存储指导老师用户ID,需要额外的查询逻辑
|
||||
// 暂时返回null,后续可以根据需要实现
|
||||
log.debug("志愿者队伍 {} 的指导老师 {} 需要根据姓名查找用户ID", team.getTeamName(), team.getAdvisorName());
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("查找志愿者队伍 {} 指导老师用户ID时发生异常", team.getTeamName(), e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,13 +99,28 @@
|
||||
END as organization_name,
|
||||
a.instructors,
|
||||
CAST(a.activity_status AS CHAR) as activity_status,
|
||||
-- 动态计算报名状态:基于当前时间和报名时间范围
|
||||
-- 动态计算报名状态:优先根据活动状态,再根据报名时间范围
|
||||
CAST(
|
||||
CASE
|
||||
WHEN a.registration_start IS NULL OR a.registration_end IS NULL THEN a.registration_status
|
||||
WHEN NOW() < a.registration_start THEN '0'
|
||||
WHEN NOW() >= a.registration_start AND NOW() <= a.registration_end THEN '1'
|
||||
WHEN NOW() > a.registration_end THEN '2'
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN a.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN a.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN a.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN a.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN a.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN a.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN a.activity_status = '3' OR a.activity_status = '4' THEN
|
||||
CASE
|
||||
WHEN a.registration_start IS NULL OR a.registration_end IS NULL THEN a.registration_status
|
||||
<![CDATA[WHEN NOW() < a.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= a.registration_start AND NOW() <= a.registration_end THEN '1']]>
|
||||
<![CDATA[WHEN NOW() > a.registration_end THEN '2']]>
|
||||
ELSE a.registration_status
|
||||
END
|
||||
|
||||
-- 其他情况保持原状态
|
||||
ELSE a.registration_status
|
||||
END AS CHAR
|
||||
) as registration_status,
|
||||
|
||||
+77
-17
@@ -56,12 +56,27 @@
|
||||
sa.poster_url, sa.related_club_id, sa.related_type, sa.organizer_name, sa.organizer_type,
|
||||
sa.organizer_contact, sa.organizer_phone, sa.co_organizers, sa.instructors,
|
||||
sa.registration_type, sa.registration_start, sa.registration_end,
|
||||
-- 动态计算报名状态:基于当前时间和报名时间范围
|
||||
-- 动态计算报名状态:优先根据活动状态,再根据报名时间范围
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
WHEN NOW() < sa.registration_start THEN '0'
|
||||
WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1'
|
||||
WHEN NOW() > sa.registration_end THEN '2'
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
|
||||
-- 其他情况保持原状态
|
||||
ELSE sa.registration_status
|
||||
END AS registration_status,
|
||||
sa.max_participants, sa.max_teams, sa.team_size_min, sa.team_size_max, sa.need_approval,
|
||||
@@ -120,10 +135,25 @@
|
||||
<if test="registrationStatus != null">
|
||||
AND (
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
WHEN NOW() < sa.registration_start THEN '0'
|
||||
WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1'
|
||||
WHEN NOW() > sa.registration_end THEN '2'
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
|
||||
-- 其他情况保持原状态
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
) = #{registrationStatus}
|
||||
@@ -187,10 +217,25 @@
|
||||
<if test="activity.registrationStatus != null and activity.registrationStatus != ''">
|
||||
AND (
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
WHEN NOW() < sa.registration_start THEN '0'
|
||||
WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1'
|
||||
WHEN NOW() > sa.registration_end THEN '2'
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
|
||||
-- 其他情况保持原状态
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
) = #{activity.registrationStatus}
|
||||
@@ -199,10 +244,25 @@
|
||||
<if test="activity.params != null and activity.params.registrationStatusList != null and activity.params.registrationStatusList.size() > 0">
|
||||
AND (
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
WHEN NOW() < sa.registration_start THEN '0'
|
||||
WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1'
|
||||
WHEN NOW() > sa.registration_end THEN '2'
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
CASE
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
<![CDATA[WHEN NOW() > sa.registration_end THEN '2']]>
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
|
||||
-- 其他情况保持原状态
|
||||
ELSE sa.registration_status
|
||||
END
|
||||
) IN
|
||||
|
||||
@@ -478,6 +478,11 @@ export interface StglActivityQuery extends PageQuery {
|
||||
*/
|
||||
isFinished?: number;
|
||||
|
||||
/**
|
||||
* 创建者ID
|
||||
*/
|
||||
createBy?: string | number;
|
||||
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
|
||||
@@ -84,19 +84,28 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['stgl:activity:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="!single && selectedActivity && !['2', '3', '4', '5'].includes(selectedActivity.activityStatus)">
|
||||
<el-button icon="Edit" @click="handleUpdate()" v-hasPermi="['stgl:activity:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="!single && selectedActivity && ['0', '7', '6'].includes(selectedActivity.activityStatus) && hasActivityOperationPermission(selectedActivity)">
|
||||
<el-button icon="Edit" @click="handleUpdate()" v-hasPermi="['stgl:activity:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="!single && selectedActivity && selectedActivity.activityStatus === '0' && hasActivityOperationPermission(selectedActivity)">
|
||||
<el-button type="success" icon="Upload" @click="handleSubmit()" v-hasPermi="['stgl:activity:edit']">提交</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="!single && selectedActivity && selectedActivity.activityStatus === '2' && hasActivityOperationPermission(selectedActivity)">
|
||||
<el-button type="warning" icon="Check" @click="handleApprove()" v-hasPermi="['stgl:activity:approve']">审批</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="!single && selectedActivity && ['3', '4'].includes(selectedActivity.activityStatus) && hasActivityOperationPermission(selectedActivity)">
|
||||
<el-button type="danger" icon="Close" @click="handleCancel()" v-hasPermi="['stgl:activity:edit']">取消活动</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button icon="CopyDocument" :disabled="single" @click="handleCopy()" v-hasPermi="['stgl:activity:add']">复制</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
icon="Delete"
|
||||
:disabled="multiple || (selectedActivity && selectedActivity.activityStatus !== '1')"
|
||||
:disabled="multiple || !['0', '7'].includes(selectedActivity?.activityStatus || '')"
|
||||
@click="handleDelete()"
|
||||
v-hasPermi="['stgl:activity:remove']"
|
||||
:title="selectedActivity && selectedActivity.activityStatus !== '1' ? '只有筹备中的活动可以删除' : ''"
|
||||
:title="selectedActivity && !['0', '7'].includes(selectedActivity.activityStatus) ? '只有草稿和已驳回状态的活动可以删除' : ''"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
@@ -195,7 +204,7 @@
|
||||
v-hasPermi="['stgl:activity:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="修改" placement="top" v-if="!['2', '3', '4', '5'].includes(scope.row.activityStatus)">
|
||||
<el-tooltip content="修改" placement="top" v-if="['0', '7', '6'].includes(scope.row.activityStatus) && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@@ -206,6 +215,39 @@
|
||||
v-hasPermi="['stgl:activity:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="提交" placement="top" v-if="scope.row.activityStatus === '0' && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="success"
|
||||
icon="Upload"
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px"
|
||||
@click="handleSubmit(scope.row)"
|
||||
v-hasPermi="['stgl:activity:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="审批" placement="top" v-if="scope.row.activityStatus === '2' && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
icon="Check"
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px"
|
||||
@click="handleApprove(scope.row)"
|
||||
v-hasPermi="['stgl:activity:approve']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="取消活动" placement="top" v-if="['3', '4'].includes(scope.row.activityStatus) && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
icon="Close"
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px"
|
||||
@click="handleCancel(scope.row)"
|
||||
v-hasPermi="['stgl:activity:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="复制" placement="top">
|
||||
<el-button
|
||||
link
|
||||
@@ -217,7 +259,7 @@
|
||||
v-hasPermi="['stgl:activity:add']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="活动总结" placement="top" v-if="shouldShowSummaryButton(scope.row)">
|
||||
<el-tooltip content="活动总结" placement="top" v-if="shouldShowSummaryButton(scope.row) && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="success"
|
||||
@@ -239,7 +281,7 @@
|
||||
v-hasPermi="['stgl:activity:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top" v-if="scope.row.activityStatus === '1'">
|
||||
<el-tooltip content="删除" placement="top" v-if="['0', '7'].includes(scope.row.activityStatus) && hasActivityOperationPermission(scope.row)">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@@ -315,16 +357,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="活动状态" prop="activityStatus">
|
||||
<el-select v-model="form.activityStatus" placeholder="请选择活动状态" style="width: 100%">
|
||||
<el-option v-for="dict in stgl_activity_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="关联社团" prop="relatedClubId">
|
||||
<ClubSelector v-model="form.relatedClub" @change="handleRelatedClubChange" />
|
||||
<ClubSelector v-model="form.relatedClub" @change="handleRelatedClubChange" :disabled="isRelatedClubDisabled" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -519,6 +554,37 @@
|
||||
:activity-name="selectedActivity?.activityName"
|
||||
ref="membersDialogRef"
|
||||
/>
|
||||
|
||||
<!-- 审批对话框 -->
|
||||
<el-dialog v-model="approveDialog.visible" title="审批活动" width="500px" append-to-body>
|
||||
<el-form ref="approveFormRef" :model="approveForm" label-width="100px">
|
||||
<el-form-item label="活动名称">
|
||||
<el-input v-model="approveForm.activityName" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="审批结果" prop="approvalResult">
|
||||
<el-radio-group v-model="approveForm.approvalResult">
|
||||
<el-radio label="approve">通过</el-radio>
|
||||
<el-radio label="reject">驳回</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="驳回原因" prop="rejectReason" v-if="approveForm.approvalResult === 'reject'">
|
||||
<el-input
|
||||
v-model="approveForm.rejectReason"
|
||||
type="textarea"
|
||||
placeholder="请输入驳回原因"
|
||||
:rows="3"
|
||||
:maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="approveDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmApprove" :loading="approveLoading">确认审批</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -545,10 +611,12 @@ import ActivityDetailView from './components/ActivityDetailView.vue';
|
||||
import ActivityMembersDialog from './components/ActivityMembersDialog.vue';
|
||||
import ActivityRegistrationView from './components/ActivityRegistrationView.vue'; // Added import
|
||||
import { AdvisorVO } from '@/components/AdvisorManager/index.vue';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_registration_status, sys_yes_no } = toRefs<any>(
|
||||
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'sys_yes_no')
|
||||
);
|
||||
@@ -570,6 +638,7 @@ const queryFormRef = ref<ElFormInstance>();
|
||||
const activityFormRef = ref<ElFormInstance>();
|
||||
const copyFormRef = ref<ElFormInstance>();
|
||||
const summaryFormRef = ref<ElFormInstance>();
|
||||
const approveFormRef = ref<ElFormInstance>();
|
||||
const membersDialogRef = ref();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
@@ -597,8 +666,26 @@ const membersDialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
// 审批对话框
|
||||
const approveDialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
// 审批表单
|
||||
const approveForm = reactive({
|
||||
id: undefined as string | number | undefined,
|
||||
activityName: '',
|
||||
approvalResult: 'approve' as 'approve' | 'reject',
|
||||
rejectReason: ''
|
||||
});
|
||||
|
||||
const copyLoading = ref(false);
|
||||
const summaryLoading = ref(false);
|
||||
const approveLoading = ref(false);
|
||||
|
||||
// 关联社团禁用状态控制
|
||||
const isRelatedClubDisabled = ref(false);
|
||||
|
||||
const initFormData: StglActivityForm = {
|
||||
id: undefined,
|
||||
@@ -631,7 +718,7 @@ const initFormData: StglActivityForm = {
|
||||
teamSizeMin: undefined,
|
||||
teamSizeMax: undefined,
|
||||
needApproval: 1,
|
||||
activityStatus: '1',
|
||||
activityStatus: '0',
|
||||
isFinished: 0,
|
||||
summary: undefined,
|
||||
achievements: undefined,
|
||||
@@ -668,8 +755,7 @@ const data = reactive<PageData<StglActivityForm, StglActivityQuery & { relatedCl
|
||||
activityType: [{ required: true, message: '活动类型不能为空', trigger: 'change' }],
|
||||
startTime: [{ required: true, message: '开始时间不能为空', trigger: 'blur' }],
|
||||
endTime: [{ required: true, message: '结束时间不能为空', trigger: 'blur' }],
|
||||
organizerName: [{ required: true, message: '主办方名称不能为空', trigger: 'blur' }],
|
||||
activityStatus: [{ required: true, message: '活动状态不能为空', trigger: 'change' }]
|
||||
organizerName: [{ required: true, message: '主办方名称不能为空', trigger: 'blur' }]
|
||||
}
|
||||
});
|
||||
|
||||
@@ -753,6 +839,11 @@ const getList = async () => {
|
||||
queryParams.value.endTime = undefined;
|
||||
}
|
||||
|
||||
// 如果用户是社长角色,只能查看自己创建的活动
|
||||
if (proxy?.$auth.hasRole('stgl_president')) {
|
||||
queryParams.value.createBy = userStore.userId;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await listStglActivity(queryParams.value);
|
||||
activityList.value = res.rows;
|
||||
@@ -781,6 +872,15 @@ const reset = () => {
|
||||
form.value.instructorList = [];
|
||||
form.value.instructors = undefined;
|
||||
|
||||
// 重置关联社团禁用状态
|
||||
isRelatedClubDisabled.value = false;
|
||||
|
||||
// 重置审批表单
|
||||
approveForm.id = undefined;
|
||||
approveForm.activityName = '';
|
||||
approveForm.approvalResult = 'approve';
|
||||
approveForm.rejectReason = '';
|
||||
|
||||
// 更新formKey以强制重新渲染组件
|
||||
formKey.value++;
|
||||
|
||||
@@ -839,6 +939,9 @@ const handleAdd = () => {
|
||||
form.value.relatedClubId = queryParams.value.relatedClub.relatedClubId;
|
||||
form.value.relatedType = queryParams.value.relatedClub.relatedType;
|
||||
|
||||
// 设置关联社团字段为禁用状态(不允许修改)
|
||||
isRelatedClubDisabled.value = true;
|
||||
|
||||
console.log('新增活动 - 自动填充关联组织信息:', {
|
||||
relatedType: queryParams.value.relatedClub.relatedType,
|
||||
relatedClubId: queryParams.value.relatedClub.relatedClubId,
|
||||
@@ -851,6 +954,9 @@ const handleAdd = () => {
|
||||
formRelatedClubId: form.value.relatedClubId,
|
||||
formRelatedType: form.value.relatedType
|
||||
});
|
||||
} else {
|
||||
// 没有关联组织时,允许编辑关联社团字段
|
||||
isRelatedClubDisabled.value = false;
|
||||
}
|
||||
|
||||
dialog.visible = true;
|
||||
@@ -874,8 +980,8 @@ const handleUpdate = async (row?: StglActivityVO) => {
|
||||
// 先获取活动数据检查状态
|
||||
const res = await getStglActivity(_id);
|
||||
|
||||
// 检查活动状态是否允许修改(2:报名中、3:报名结束、4:进行中、5:已结束 不允许修改)
|
||||
if (['2', '3', '4', '5'].includes(res.data.activityStatus)) {
|
||||
// 检查活动状态是否允许修改(只有草稿0、已驳回7、已取消6状态允许修改)
|
||||
if (!['0', '7', '6'].includes(res.data.activityStatus)) {
|
||||
const statusDict = stgl_activity_status.value.find((dict: any) => dict.value === res.data.activityStatus);
|
||||
const statusName = statusDict ? statusDict.label : '当前状态';
|
||||
proxy?.$modal.msgWarning(`活动状态为"${statusName}",不允许修改`);
|
||||
@@ -896,6 +1002,15 @@ const handleUpdate = async (row?: StglActivityVO) => {
|
||||
relatedType: res.data.relatedType,
|
||||
uniqueKey: `${res.data.relatedType}-${res.data.relatedClubId}`
|
||||
};
|
||||
|
||||
// 修改时,如果是从URL参数进入的,则禁用关联社团字段
|
||||
if (queryParams.value.relatedClub && queryParams.value.relatedClub.relatedClubId === res.data.relatedClubId) {
|
||||
isRelatedClubDisabled.value = true;
|
||||
} else {
|
||||
isRelatedClubDisabled.value = false;
|
||||
}
|
||||
} else {
|
||||
isRelatedClubDisabled.value = false;
|
||||
}
|
||||
|
||||
// 处理承办方数据
|
||||
@@ -945,6 +1060,11 @@ const submitForm = () => {
|
||||
// 准备提交的数据
|
||||
const submitData = { ...form.value } as any;
|
||||
|
||||
// 新增时自动设置活动状态为0(草稿)
|
||||
if (!submitData.id) {
|
||||
submitData.activityStatus = '0';
|
||||
}
|
||||
|
||||
// 处理关联社团数据
|
||||
if (submitData.relatedClub) {
|
||||
submitData.relatedClubId = submitData.relatedClub.relatedClubId;
|
||||
@@ -1032,23 +1152,23 @@ const handleDelete = async (row?: StglActivityVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
let confirmMessage = '';
|
||||
|
||||
// 检查删除权限 - 只有筹备中(状态1)的活动可以删除
|
||||
// 检查删除权限 - 只有草稿(状态0)和已驳回(状态7)的活动可以删除
|
||||
if (row) {
|
||||
if (row.activityStatus !== '1') {
|
||||
if (!['0', '7'].includes(row.activityStatus)) {
|
||||
const statusDict = stgl_activity_status.value.find((dict: any) => dict.value === row.activityStatus);
|
||||
const statusName = statusDict ? statusDict.label : '当前状态';
|
||||
proxy?.$modal.msgWarning(`活动状态为"${statusName}",只有筹备中的活动可以删除`);
|
||||
proxy?.$modal.msgWarning(`活动状态为"${statusName}",只有草稿和已驳回状态的活动可以删除`);
|
||||
return;
|
||||
}
|
||||
confirmMessage = `是否确认删除活动"${row.activityName}"?`;
|
||||
} else {
|
||||
const selectedItems = activityList.value.filter((item) => ids.value.includes(item.id));
|
||||
|
||||
// 检查选中的活动是否都是筹备中状态
|
||||
const nonDeletableItems = selectedItems.filter((item) => item.activityStatus !== '1');
|
||||
// 检查选中的活动是否都是草稿或已驳回状态
|
||||
const nonDeletableItems = selectedItems.filter((item) => !['0', '7'].includes(item.activityStatus));
|
||||
if (nonDeletableItems.length > 0) {
|
||||
const names = nonDeletableItems.map((item) => item.activityName).join('、');
|
||||
proxy?.$modal.msgWarning(`活动"${names}"不是筹备中状态,只有筹备中的活动可以删除`);
|
||||
proxy?.$modal.msgWarning(`活动"${names}"不是草稿或已驳回状态,只有草稿和已驳回状态的活动可以删除`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1273,6 +1393,127 @@ const handleMembersReview = (row: StglActivityVO) => {
|
||||
membersDialog.title = `${row.activityName}活动报名管理`;
|
||||
};
|
||||
|
||||
/** 提交按钮操作 */
|
||||
const handleSubmit = async (row?: StglActivityVO) => {
|
||||
const activity = row || selectedActivity.value;
|
||||
if (!activity) return;
|
||||
|
||||
try {
|
||||
await proxy?.$modal.confirm(`是否确认提交活动"${activity.activityName}"?提交后将进入审批流程。`);
|
||||
|
||||
// 调用后端接口更新活动状态为2(待审批)
|
||||
// 传递完整的活动数据,避免后端验证失败
|
||||
await updateStglActivity({
|
||||
...activity,
|
||||
activityStatus: '2'
|
||||
});
|
||||
|
||||
proxy?.$modal.msgSuccess('提交成功');
|
||||
await getList();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('提交失败:', error);
|
||||
proxy?.$modal.msgError('提交失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** 审批按钮操作 */
|
||||
const handleApprove = async (row?: StglActivityVO) => {
|
||||
const activity = row || selectedActivity.value;
|
||||
if (!activity) return;
|
||||
|
||||
// 显示审批对话框
|
||||
approveDialog.visible = true;
|
||||
approveDialog.title = `审批活动 - ${activity.activityName}`;
|
||||
approveForm.id = activity.id;
|
||||
approveForm.activityName = activity.activityName || '';
|
||||
approveForm.approvalResult = 'approve';
|
||||
approveForm.rejectReason = '';
|
||||
};
|
||||
|
||||
/** 取消活动按钮操作 */
|
||||
const handleCancel = async (row?: StglActivityVO) => {
|
||||
const activity = row || selectedActivity.value;
|
||||
if (!activity) return;
|
||||
|
||||
try {
|
||||
await proxy?.$modal.confirm(`是否确认取消活动"${activity.activityName}"?取消后将无法恢复。`);
|
||||
|
||||
// 调用后端接口更新活动状态为6(已取消)
|
||||
// 传递完整的活动数据,避免后端验证失败
|
||||
await updateStglActivity({
|
||||
...activity,
|
||||
activityStatus: '6'
|
||||
});
|
||||
|
||||
proxy?.$modal.msgSuccess('取消活动成功');
|
||||
await getList();
|
||||
} catch (error) {
|
||||
if (error !== 'cancel') {
|
||||
console.error('取消活动失败:', error);
|
||||
proxy?.$modal.msgError('取消活动失败');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** 确认审批 */
|
||||
const confirmApprove = async () => {
|
||||
if (!approveFormRef.value) return;
|
||||
|
||||
approveLoading.value = true;
|
||||
try {
|
||||
const activity = activityList.value.find(item => item.id === approveForm.id);
|
||||
if (!activity) {
|
||||
proxy?.$modal.msgError('活动信息不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
let newStatus: string;
|
||||
let successMessage: string;
|
||||
|
||||
if (approveForm.approvalResult === 'approve') {
|
||||
// 审批通过,根据时间比较确定状态
|
||||
const now = new Date();
|
||||
const startTime = new Date(activity.startTime);
|
||||
const endTime = new Date(activity.endTime);
|
||||
|
||||
if (now < startTime) {
|
||||
newStatus = '1'; // 未开始
|
||||
} else if (now >= startTime && now <= endTime) {
|
||||
newStatus = '4'; // 进行中
|
||||
} else {
|
||||
newStatus = '5'; // 已结束
|
||||
}
|
||||
successMessage = '审批通过';
|
||||
} else {
|
||||
// 审批驳回
|
||||
if (!approveForm.rejectReason.trim()) {
|
||||
proxy?.$modal.msgWarning('请输入驳回原因');
|
||||
return;
|
||||
}
|
||||
newStatus = '7'; // 已驳回
|
||||
successMessage = '审批驳回';
|
||||
}
|
||||
|
||||
// 调用后端接口更新活动状态
|
||||
// 传递完整的活动数据,避免后端验证失败
|
||||
await updateStglActivity({
|
||||
...activity,
|
||||
activityStatus: newStatus
|
||||
});
|
||||
|
||||
proxy?.$modal.msgSuccess(successMessage);
|
||||
approveDialog.visible = false;
|
||||
await getList();
|
||||
} catch (error) {
|
||||
console.error('审批失败:', error);
|
||||
proxy?.$modal.msgError('审批失败');
|
||||
} finally {
|
||||
approveLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 格式化日期 */
|
||||
const formatDate = (dateStr: string): string => {
|
||||
if (!dateStr) return '';
|
||||
@@ -1303,6 +1544,51 @@ const getAdvisorNames = (activity: StglActivityVO): string[] => {
|
||||
return [];
|
||||
};
|
||||
|
||||
// 检查是否拥有指导老师或管理员权限
|
||||
const hasInstructorPermission = computed(() => {
|
||||
return proxy?.$auth.hasRoleOr(['stgl_instructor', 'stgl_stgl_admin', 'superadmin']);
|
||||
});
|
||||
|
||||
// 检查当前用户是否为指定活动的指导老师
|
||||
const isCurrentUserAdvisor = (activity: StglActivityVO): boolean => {
|
||||
if (!activity.instructors) return false;
|
||||
|
||||
try {
|
||||
const advisors = JSON.parse(activity.instructors);
|
||||
if (Array.isArray(advisors)) {
|
||||
return advisors.some((advisor: any) => {
|
||||
// 支持两种数据结构:直接包含userId或嵌套在teacher对象中
|
||||
const userId = advisor.userId || advisor.teacher?.userId;
|
||||
return userId && userId.toString() === userStore.userId?.toString();
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('解析活动指导老师数据失败:', error);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// 检查当前用户是否有活动操作权限(指导老师只能操作自己指导的活动)
|
||||
const hasActivityOperationPermission = (activity: StglActivityVO): boolean => {
|
||||
// 管理员有所有权限
|
||||
if (proxy?.$auth.hasRole('admin') || proxy?.$auth.hasRole('common')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 指导老师只能操作自己指导的活动
|
||||
if (proxy?.$auth.hasRole('stgl_instructor')) {
|
||||
return isCurrentUserAdvisor(activity);
|
||||
}
|
||||
|
||||
// 社长只能操作自己创建的活动
|
||||
if (proxy?.$auth.hasRole('stgl_president')) {
|
||||
return activity.createBy === userStore.userId;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initUrlParams();
|
||||
getList();
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
|
||||
|
||||
<el-row>
|
||||
<el-col :span="24" class="search-btn-container">
|
||||
<el-form-item>
|
||||
@@ -619,6 +621,18 @@
|
||||
</template>
|
||||
|
||||
<script setup name="StglClub" lang="ts">
|
||||
/**
|
||||
* 社团信息管理
|
||||
*
|
||||
* 权限控制说明:
|
||||
* - stgl_president角色:可以操作自己担任社长的社团(无论是否为创建者)
|
||||
* - stgl_instructor角色:指导老师,有部分字段的只读权限
|
||||
* - 管理员角色:可以操作所有社团
|
||||
*
|
||||
* 业务逻辑:
|
||||
* 管理员创建社团后选择社长,被选中的社长(stgl_president角色)
|
||||
* 需要能够看到和操作自己担任社长的社团,不再受限于创建者身份
|
||||
*/
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
listStglClub,
|
||||
@@ -646,9 +660,15 @@ const { stgl_club_type, sys_normal_disable, stgl_funding_source, sys_yes_no } =
|
||||
|
||||
// 检查是否拥有指导老师或管理员权限
|
||||
const hasInstructorPermission = computed(() => {
|
||||
return proxy?.$auth.hasRoleOr(['stgl_instructor', 'stgl_admin', 'superadmin']);
|
||||
return proxy?.$auth.hasRoleOr(['stgl_instructor', 'stgl_stgl_admin', 'superadmin']);
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 社长权限控制 - 检查用户是否为各社团的社长(无论是否为创建者)
|
||||
// 用于控制转让按钮显示和社长相关操作权限
|
||||
const presidentRoles = ref<Record<string | number, boolean>>({});
|
||||
|
||||
const clubList = ref<StglClubVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
@@ -660,9 +680,6 @@ const total = ref(0);
|
||||
const activeTab = ref('basic');
|
||||
const charterDownloading = ref(false);
|
||||
|
||||
// 社长权限控制
|
||||
const presidentRoles = ref<Record<string | number, boolean>>({});
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const clubFormRef = ref<ElFormInstance>();
|
||||
|
||||
@@ -1281,7 +1298,7 @@ const handleAdvisorsChange = (advisors: AdvisorVO[]) => {
|
||||
});
|
||||
};
|
||||
|
||||
/** 检查用户是否为指定社团的社长 */
|
||||
/** 检查用户是否为指定社团的社长(无论是否为创建者) */
|
||||
const checkIsPresident = async (clubId: string | number): Promise<boolean> => {
|
||||
try {
|
||||
console.log('🔍 checkIsPresident: 开始检查社长权限, clubId:', clubId);
|
||||
@@ -1296,7 +1313,7 @@ const checkIsPresident = async (clubId: string | number): Promise<boolean> => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 批量检查社长权限 */
|
||||
/** 批量检查社长权限(检查用户是否为各社团的社长,无论是否为创建者) */
|
||||
const checkBatchPresidentRoles = async (clubs: StglClubVO[]) => {
|
||||
console.log('🔍 checkBatchPresidentRoles: 开始批量检查权限, clubs数量:', clubs.length);
|
||||
const checks = clubs.map(async (club) => {
|
||||
@@ -1334,7 +1351,7 @@ const shouldShowTransferButton = (club: StglClubVO): boolean => {
|
||||
console.log('⏳ shouldShowTransferButton: 权限检查未完成,返回false避免闪现');
|
||||
return false;
|
||||
}
|
||||
// 只有社长才能看到转让按钮
|
||||
// 社长可以看到转让按钮(无论是否为创建者)
|
||||
const result = isPresident === true;
|
||||
console.log('🔍 shouldShowTransferButton: stgl_president角色最终结果:', result);
|
||||
return result;
|
||||
@@ -1689,6 +1706,8 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 人员信息部分样式 */
|
||||
.personnel-section {
|
||||
margin-bottom: 24px;
|
||||
|
||||
Reference in new issue
Block a user