stgl2.0
This commit is contained in:
1 parent
93711d76a3
commit
73ffd576bc
63 files changed
+5064
-647
No files matched your search
+15
-2
@@ -20,6 +20,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.dromara.stgl.domain.bo.StglActivityBo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityVo;
|
||||
import org.dromara.stgl.domain.vo.ActivityRatingVo;
|
||||
import org.dromara.stgl.service.IStglActivityService;
|
||||
|
||||
import java.util.List;
|
||||
@@ -106,8 +107,11 @@ public class StglActivityController extends BaseController {
|
||||
@Log(title = "复制活动信息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/copy")
|
||||
public R<Void> copy(@RequestParam("sourceId") Long sourceId, @RequestParam("newActivityName") String newActivityName) {
|
||||
return toAjax(stglActivityService.copyActivity(sourceId, newActivityName));
|
||||
public R<Void> copy(@RequestParam("sourceId") Long sourceId,
|
||||
@RequestParam("newActivityName") String newActivityName,
|
||||
@RequestParam(value = "activityStatus", defaultValue = "0") String activityStatus,
|
||||
@RequestParam(value = "registrationStatus", defaultValue = "0") Integer registrationStatus) {
|
||||
return toAjax(stglActivityService.copyActivity(sourceId, newActivityName, activityStatus, registrationStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,4 +147,13 @@ public class StglActivityController extends BaseController {
|
||||
return R.ok(stglActivityService.queryVolunteerTeamOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询活动评分列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:activity:query")
|
||||
@GetMapping("/{id}/ratings")
|
||||
public R<List<ActivityRatingVo>> getActivityRatings(@NotNull(message = "活动ID不能为空") @PathVariable Long id) {
|
||||
return R.ok(stglActivityService.getActivityRatings(id));
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.stgl.domain.vo.StglClassVo;
|
||||
import org.dromara.stgl.domain.bo.StglClassBo;
|
||||
import org.dromara.stgl.service.IStglClassService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/stclass")
|
||||
public class StglClassController extends BaseController {
|
||||
|
||||
private final IStglClassService stglClassService;
|
||||
|
||||
/**
|
||||
* 查询班主任的班级列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:list")
|
||||
@GetMapping("/teacher/classes")
|
||||
public R<List<Map<String, Object>>> getTeacherClasses() {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
List<Map<String, Object>> list = stglClassService.getTeacherClasses(userId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班级学生社团、志愿者队伍、活动参加情况列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglClassVo> list(StglClassBo bo, PageQuery pageQuery) {
|
||||
return stglClassService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生社团详情
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:query")
|
||||
@GetMapping("/student/clubs/{studentId}")
|
||||
public R<List<Map<String, Object>>> getStudentClubs(@NotNull(message = "学生ID不能为空") @PathVariable Long studentId) {
|
||||
List<Map<String, Object>> list = stglClassService.getStudentClubs(studentId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生志愿者队伍详情
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:query")
|
||||
@GetMapping("/student/volunteer-teams/{studentId}")
|
||||
public R<List<Map<String, Object>>> getStudentVolunteerTeams(@NotNull(message = "学生ID不能为空") @PathVariable Long studentId) {
|
||||
List<Map<String, Object>> list = stglClassService.getStudentVolunteerTeams(studentId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生活动详情
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:query")
|
||||
@GetMapping("/student/activities/{studentId}")
|
||||
public R<List<Map<String, Object>>> getStudentActivities(@NotNull(message = "学生ID不能为空") @PathVariable Long studentId) {
|
||||
List<Map<String, Object>> list = stglClassService.getStudentActivities(studentId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出班级学生社团、志愿者队伍、活动参加情况列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:stclass:export")
|
||||
@Log(title = "班级学生社团、志愿者队伍、活动参加情况", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglClassBo bo, HttpServletResponse response) {
|
||||
List<StglClassVo> list = stglClassService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "班级学生参与情况", StglClassVo.class, response);
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -64,8 +64,11 @@ public class StglMyController extends BaseController {
|
||||
@Operation(summary = "查询我报名的活动列表")
|
||||
@SaCheckPermission("stgl:my:list")
|
||||
@GetMapping("/activities")
|
||||
public R<List<MyActivityVo>> getMyActivities() {
|
||||
List<MyActivityVo> list = stglMyService.queryMyActivities();
|
||||
public R<List<MyActivityVo>> getMyActivities(
|
||||
@Parameter(description = "活动名称") @RequestParam(required = false) String activityName,
|
||||
@Parameter(description = "活动类型") @RequestParam(required = false) String activityType,
|
||||
@Parameter(description = "是否评分") @RequestParam(required = false) String isRated) {
|
||||
List<MyActivityVo> list = stglMyService.queryMyActivities(activityName, activityType, isRated);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -52,7 +52,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 查询志愿者成员列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:list")
|
||||
@SaCheckPermission("stgl:volunteermember:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglMemberVo> list(StglMemberBo bo, PageQuery pageQuery) {
|
||||
bo.setMemberType(2); // 志愿者成员
|
||||
@@ -62,7 +62,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 导出志愿者成员列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:export")
|
||||
@SaCheckPermission("stgl:volunteermember:export")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglMemberBo bo, HttpServletResponse response) {
|
||||
@@ -74,7 +74,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 获取志愿者成员详细信息
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:query")
|
||||
@SaCheckPermission("stgl:volunteermember:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglMemberVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
@@ -84,15 +84,15 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 新增志愿者成员
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:add")
|
||||
@SaCheckPermission("stgl:volunteermember:add")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMemberBo bo) {
|
||||
bo.setMemberType(2); // 志愿者成员
|
||||
// 如果前端没有传递roleType,设置默认值为1(队员)
|
||||
// 如果前端没有传递roleType,设置默认值为队员
|
||||
if (bo.getRoleType() == null) {
|
||||
bo.setRoleType("1");
|
||||
bo.setRoleType("队员");
|
||||
}
|
||||
return toAjax(stglMemberService.insertByBo(bo));
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 修改志愿者成员
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:edit")
|
||||
@SaCheckPermission("stgl:volunteermember:edit")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping
|
||||
@@ -112,7 +112,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 删除志愿者成员
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:remove")
|
||||
@SaCheckPermission("stgl:volunteermember:remove")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@@ -150,7 +150,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 根据队伍ID查询成员
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:list")
|
||||
@SaCheckPermission("stgl:volunteermember:list")
|
||||
@GetMapping("/team/{teamId}")
|
||||
public R<List<StglMemberVo>> getTeamMembers(@NotNull(message = "队伍ID不能为空")
|
||||
@PathVariable Long teamId) {
|
||||
@@ -164,7 +164,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 批量分配队伍
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:edit")
|
||||
@SaCheckPermission("stgl:volunteermember:edit")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/assignTeam")
|
||||
@@ -175,7 +175,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 获取志愿者成员统计信息
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:query")
|
||||
@SaCheckPermission("stgl:volunteermember:query")
|
||||
@GetMapping("/stats")
|
||||
public R<Object> getStats() {
|
||||
return R.ok(stglMemberService.getVolunteerMemberStats());
|
||||
@@ -185,7 +185,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
* 下载志愿者成员导入模板
|
||||
*/
|
||||
@PostMapping("/importTemplate")
|
||||
@SaCheckPermission("stgl:volunteerMember:import")
|
||||
@SaCheckPermission("stgl:volunteermember:import")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
// 创建示例数据
|
||||
List<StglVolunteerImportVo> templateData = new ArrayList<>();
|
||||
@@ -211,7 +211,7 @@ public class StglVolunteerMemberController extends BaseController {
|
||||
/**
|
||||
* 导入志愿者成员数据
|
||||
*/
|
||||
@SaCheckPermission("stgl:volunteerMember:import")
|
||||
@SaCheckPermission("stgl:volunteermember:import")
|
||||
@Log(title = "志愿者成员", businessType = BusinessType.IMPORT)
|
||||
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public R<Void> importData(@RequestPart("file") MultipartFile file,
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
@@ -48,9 +49,9 @@ public class StglActivityRating extends TenantEntity {
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 综合评分(1-5分)
|
||||
* 综合评分(1-5分,保留1位小数)
|
||||
*/
|
||||
private Integer ratingScore;
|
||||
private BigDecimal ratingScore;
|
||||
|
||||
/**
|
||||
* 评价意见
|
||||
|
||||
+38
@@ -2,6 +2,7 @@ package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
@@ -68,9 +69,46 @@ public class StglActivityTeamInfo extends TenantEntity {
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Integer deleted;
|
||||
|
||||
// 扩展字段(不存储到数据库,用于显示)
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
// 队长详细信息字段(通过关联查询获取)
|
||||
/**
|
||||
* 队长性别
|
||||
*/
|
||||
private String leaderGender;
|
||||
|
||||
/**
|
||||
* 队长联系电话
|
||||
*/
|
||||
private String leaderPhone;
|
||||
|
||||
/**
|
||||
* 队长邮箱
|
||||
*/
|
||||
private String leaderEmail;
|
||||
|
||||
/**
|
||||
* 队长院系
|
||||
*/
|
||||
private String leaderDepartment;
|
||||
|
||||
/**
|
||||
* 队长专业
|
||||
*/
|
||||
private String leaderMajor;
|
||||
|
||||
/**
|
||||
* 队长班级
|
||||
*/
|
||||
private String leaderClassName;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况对象 stgl_class
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xg_student_msg")
|
||||
public class StglClass extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private String classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 年级
|
||||
*/
|
||||
private String grade;
|
||||
|
||||
/**
|
||||
* 学籍状态
|
||||
*/
|
||||
private String studentStatus;
|
||||
}
|
||||
+5
@@ -117,6 +117,11 @@ public class StglVolunteerTeam extends TenantEntity {
|
||||
*/
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师JSON数据,支持多个指导老师
|
||||
*/
|
||||
private String advisorsJson;
|
||||
|
||||
/**
|
||||
* 人员上限
|
||||
*/
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.stgl.domain.StglClass;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况业务对象 stgl_class
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglClass.class, reverseConvertGenerate = false)
|
||||
public class StglClassBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private String classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 年级
|
||||
*/
|
||||
private String grade;
|
||||
|
||||
/**
|
||||
* 学籍状态
|
||||
*/
|
||||
private String studentStatus;
|
||||
}
|
||||
+5
@@ -138,6 +138,11 @@ public class StglVolunteerTeamBo extends BaseEntity {
|
||||
@Size(max = 100, message = "指导老师邮箱长度不能超过100个字符")
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师JSON数据,支持多个指导老师
|
||||
*/
|
||||
private String advisorsJson;
|
||||
|
||||
/**
|
||||
* 人员上限
|
||||
*/
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.stgl.domain.StglActivityRating;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 活动评分详细信息视图对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-07
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = StglActivityRating.class)
|
||||
public class ActivityRatingVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 评分ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 活动ID
|
||||
*/
|
||||
private Long activityId;
|
||||
|
||||
/**
|
||||
* 评分人ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 评分人姓名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 联系方式
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 院系名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 总评分(1-5分)
|
||||
*/
|
||||
private BigDecimal ratingScore;
|
||||
|
||||
/**
|
||||
* 内容评分(1-5分)
|
||||
*/
|
||||
private Integer contentScore;
|
||||
|
||||
/**
|
||||
* 组织评分(1-5分)
|
||||
*/
|
||||
private Integer organizationScore;
|
||||
|
||||
/**
|
||||
* 体验评分(1-5分)
|
||||
*/
|
||||
private Integer experienceScore;
|
||||
|
||||
/**
|
||||
* 评分备注
|
||||
*/
|
||||
private String ratingComment;
|
||||
|
||||
/**
|
||||
* 评分时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime ratingTime;
|
||||
}
|
||||
+8
-2
@@ -7,6 +7,7 @@ import org.dromara.stgl.domain.StglActivity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
@@ -110,15 +111,20 @@ public class MyActivityVo implements Serializable {
|
||||
*/
|
||||
private String myRegistrationStatus;
|
||||
|
||||
/**
|
||||
* 报名类型(1-个人 2-团队)
|
||||
*/
|
||||
private String registrationType;
|
||||
|
||||
/**
|
||||
* 我的评分状态(0-未评分 1-已评分)
|
||||
*/
|
||||
private Integer myRatingStatus;
|
||||
|
||||
/**
|
||||
* 我的综合评分
|
||||
* 我的综合评分(保留1位小数)
|
||||
*/
|
||||
private Integer myRatingScore;
|
||||
private BigDecimal myRatingScore;
|
||||
|
||||
/**
|
||||
* 我的评分时间
|
||||
|
||||
+5
@@ -52,6 +52,11 @@ public class MyVolunteerTeamVo implements Serializable {
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 指导老师JSON数据,支持多个指导老师
|
||||
*/
|
||||
private String advisorsJson;
|
||||
|
||||
/**
|
||||
* 当前成员数量
|
||||
*/
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.stgl.domain.StglClass;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况视图对象 stgl_class
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = StglClass.class)
|
||||
public class StglClassVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 加入社团数量
|
||||
*/
|
||||
private Integer clubCount;
|
||||
|
||||
/**
|
||||
* 加入志愿者队伍数量
|
||||
*/
|
||||
private Integer volunteerTeamCount;
|
||||
|
||||
/**
|
||||
* 参与活动数量
|
||||
*/
|
||||
private Integer activityCount;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 版本号
|
||||
*/
|
||||
private Long version;
|
||||
|
||||
/**
|
||||
* 逻辑删除
|
||||
*/
|
||||
private Long deleted;
|
||||
}
|
||||
+5
@@ -137,6 +137,11 @@ public class StglVolunteerTeamVo implements Serializable {
|
||||
@ExcelProperty(value = "指导老师邮箱")
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师JSON数据,支持多个指导老师
|
||||
*/
|
||||
private String advisorsJson;
|
||||
|
||||
/**
|
||||
* 人员上限
|
||||
*/
|
||||
|
||||
+1
-1
@@ -238,7 +238,7 @@ public class StglVolunteerImportListener extends AnalysisEventListener<StglVolun
|
||||
newMember.setStudentName(volunteerVo.getStudentName());
|
||||
// 🔑 关键修复:设置用户ID(学生ID就是用户ID)
|
||||
newMember.setUserId(student.getId());
|
||||
newMember.setRoleType("1"); // 志愿者角色 stgl_volunteer_role=1 队员
|
||||
newMember.setRoleType("队员"); // 队员角色 - 直接写入字符"队员"
|
||||
newMember.setStatus("2"); // 成员状态 stgl_member_status=2 已加入
|
||||
newMember.setJoinTime(volunteerVo.getJoinTime() != null ? volunteerVo.getJoinTime() : new Date());
|
||||
|
||||
|
||||
+11
@@ -3,6 +3,9 @@ package org.dromara.stgl.mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.stgl.domain.StglActivityRating;
|
||||
import org.dromara.stgl.domain.vo.ActivityRatingVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 活动评分数据访问层
|
||||
@@ -40,4 +43,12 @@ public interface StglActivityRatingMapper extends BaseMapperPlus<StglActivityRat
|
||||
*/
|
||||
Double selectAverageRatingByActivityId(@Param("activityId") Long activityId);
|
||||
|
||||
/**
|
||||
* 查询活动评分详情(关联用户表获取详细信息)
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @return 评分详细信息列表
|
||||
*/
|
||||
List<ActivityRatingVo> selectActivityRatingsWithUserInfo(@Param("activityId") Long activityId);
|
||||
|
||||
}
|
||||
+20
-1
@@ -1,9 +1,13 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.dromara.stgl.domain.StglActivityTeamInfo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityTeamInfoVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 活动团队信息Mapper接口
|
||||
@@ -13,4 +17,19 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
*/
|
||||
public interface StglActivityTeamInfoMapper extends BaseMapperPlus<StglActivityTeamInfo, StglActivityTeamInfoVo> {
|
||||
|
||||
/**
|
||||
* 根据条件查询团队信息列表(VO对象)
|
||||
*
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 团队信息列表
|
||||
*/
|
||||
List<StglActivityTeamInfoVo> selectVoList(@Param(Constants.WRAPPER) Wrapper<StglActivityTeamInfo> queryWrapper);
|
||||
|
||||
/**
|
||||
* 根据活动ID查询团队列表
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @return 团队列表
|
||||
*/
|
||||
List<StglActivityTeamInfoVo> selectVoListByActivityId(@Param("activityId") Long activityId);
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClass;
|
||||
import org.dromara.stgl.domain.vo.StglClassVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况Mapper接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface StglClassMapper extends BaseMapperPlus<StglClass, StglClassVo> {
|
||||
|
||||
/**
|
||||
* 查询班主任的班级列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 班级列表
|
||||
*/
|
||||
List<Map<String, Object>> selectTeacherClasses(Long userId);
|
||||
|
||||
/**
|
||||
* 查询班级学生列表(包含社团、志愿者队伍、活动统计)
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @return 学生列表
|
||||
*/
|
||||
List<StglClassVo> selectClassStudents(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 查询班级学生总数
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @return 学生总数
|
||||
*/
|
||||
Integer selectClassStudentsCount(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 查询学生社团详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 社团详情列表
|
||||
*/
|
||||
List<Map<String, Object>> selectStudentClubs(Long studentId);
|
||||
|
||||
/**
|
||||
* 查询学生志愿者队伍详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 志愿者队伍详情列表
|
||||
*/
|
||||
List<Map<String, Object>> selectStudentVolunteerTeams(Long studentId);
|
||||
|
||||
/**
|
||||
* 查询学生活动详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 活动详情列表
|
||||
*/
|
||||
List<Map<String, Object>> selectStudentActivities(Long studentId);
|
||||
}
|
||||
+6
-1
@@ -40,9 +40,14 @@ public interface StglMyMapper {
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param tenantId 租户ID
|
||||
* @param activityName 活动名称
|
||||
* @param activityType 活动类型
|
||||
* @param isRated 是否评分
|
||||
* @return 活动列表
|
||||
*/
|
||||
List<MyActivityVo> selectMyActivities(@Param("userId") Long userId, @Param("tenantId") String tenantId);
|
||||
List<MyActivityVo> selectMyActivities(@Param("userId") Long userId, @Param("tenantId") String tenantId,
|
||||
@Param("activityName") String activityName, @Param("activityType") String activityType,
|
||||
@Param("isRated") String isRated);
|
||||
|
||||
/**
|
||||
* 分页查询我的报名记录(社团+志愿团队+活动)
|
||||
|
||||
+12
-1
@@ -6,6 +6,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.stgl.domain.StglActivity;
|
||||
import org.dromara.stgl.domain.bo.StglActivityBo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityVo;
|
||||
import org.dromara.stgl.domain.vo.ActivityRatingVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -82,9 +83,11 @@ public interface IStglActivityService extends IService<StglActivity> {
|
||||
*
|
||||
* @param sourceId 源活动ID
|
||||
* @param newActivityName 新活动名称
|
||||
* @param activityStatus 新活动状态
|
||||
* @param registrationStatus 新活动报名状态
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean copyActivity(Long sourceId, String newActivityName);
|
||||
Boolean copyActivity(Long sourceId, String newActivityName, String activityStatus, Integer registrationStatus);
|
||||
|
||||
/**
|
||||
* 查询社团选择器选项
|
||||
@@ -112,4 +115,12 @@ public interface IStglActivityService extends IService<StglActivity> {
|
||||
*/
|
||||
Boolean summarizeActivity(Long id, String summary, String achievements, String summaryAttachments, String achievementsAttachments);
|
||||
|
||||
/**
|
||||
* 查询活动评分列表(包含评分人详细信息)
|
||||
*
|
||||
* @param activityId 活动ID
|
||||
* @return 活动评分详细信息列表
|
||||
*/
|
||||
List<ActivityRatingVo> getActivityRatings(Long activityId);
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglClassVo;
|
||||
import org.dromara.stgl.domain.bo.StglClassBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglClassService {
|
||||
|
||||
/**
|
||||
* 查询班主任的班级列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 班级列表
|
||||
*/
|
||||
List<Map<String, Object>> getTeacherClasses(Long userId);
|
||||
|
||||
/**
|
||||
* 查询班级学生社团、志愿者队伍、活动参加情况分页列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
TableDataInfo<StglClassVo> queryPageList(StglClassBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询班级学生社团、志愿者队伍、活动参加情况列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 列表结果
|
||||
*/
|
||||
List<StglClassVo> queryList(StglClassBo bo);
|
||||
|
||||
/**
|
||||
* 查询学生社团详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 社团详情列表
|
||||
*/
|
||||
List<Map<String, Object>> getStudentClubs(Long studentId);
|
||||
|
||||
/**
|
||||
* 查询学生志愿者队伍详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 志愿者队伍详情列表
|
||||
*/
|
||||
List<Map<String, Object>> getStudentVolunteerTeams(Long studentId);
|
||||
|
||||
/**
|
||||
* 查询学生活动详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 活动详情列表
|
||||
*/
|
||||
List<Map<String, Object>> getStudentActivities(Long studentId);
|
||||
}
|
||||
+4
-1
@@ -35,9 +35,12 @@ public interface IStglMyService {
|
||||
/**
|
||||
* 查询我报名的活动列表(带评分状态)
|
||||
*
|
||||
* @param activityName 活动名称
|
||||
* @param activityType 活动类型
|
||||
* @param isRated 是否评分
|
||||
* @return 活动列表
|
||||
*/
|
||||
List<MyActivityVo> queryMyActivities();
|
||||
List<MyActivityVo> queryMyActivities(String activityName, String activityType, String isRated);
|
||||
|
||||
/**
|
||||
* 分页查询我的报名记录
|
||||
|
||||
+15
-2
@@ -16,8 +16,10 @@ import org.dromara.stgl.domain.StglActivityTeamInfo;
|
||||
import org.dromara.stgl.domain.bo.StglActivityRegistrationBo;
|
||||
import org.dromara.stgl.domain.bo.StglActivityTeamInfoBo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityRegistrationVo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityVo;
|
||||
import org.dromara.stgl.mapper.StglActivityRegistrationMapper;
|
||||
import org.dromara.stgl.service.IStglActivityRegistrationService;
|
||||
import org.dromara.stgl.service.IStglActivityService;
|
||||
import org.dromara.stgl.service.IStglActivityTeamInfoService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -38,6 +40,7 @@ import java.util.List;
|
||||
public class StglActivityRegistrationServiceImpl extends ServiceImpl<StglActivityRegistrationMapper, StglActivityRegistration> implements IStglActivityRegistrationService {
|
||||
|
||||
private final StglActivityRegistrationMapper baseMapper;
|
||||
private final IStglActivityService stglActivityService;
|
||||
private final IStglActivityTeamInfoService teamInfoService;
|
||||
|
||||
/**
|
||||
@@ -192,9 +195,19 @@ public class StglActivityRegistrationServiceImpl extends ServiceImpl<StglActivit
|
||||
throw new RuntimeException("您已报名该活动,请勿重复报名");
|
||||
}
|
||||
|
||||
// 设置报名时间和状态
|
||||
// 设置报名时间
|
||||
bo.setRegistrationTime(new Date());
|
||||
bo.setApprovalStatus("0"); // 待审核
|
||||
|
||||
// 如果没有设置审核状态,则根据活动的审核设置来决定
|
||||
if (bo.getApprovalStatus() == null) {
|
||||
// 获取活动信息,检查是否需要审核
|
||||
StglActivityVo activity = stglActivityService.queryById(bo.getActivityId());
|
||||
if (activity != null && activity.getNeedApproval() != null && activity.getNeedApproval() == 0) {
|
||||
bo.setApprovalStatus("1"); // 无需审核,自动通过
|
||||
} else {
|
||||
bo.setApprovalStatus("0"); // 需要审核,待审核
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是团队报名,需要先创建团队信息
|
||||
if ("2".equals(bo.getRegistrationType()) && bo.getTeamId() == null) {
|
||||
|
||||
+215
-21
@@ -19,7 +19,9 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.stgl.domain.StglActivity;
|
||||
import org.dromara.stgl.domain.bo.StglActivityBo;
|
||||
import org.dromara.stgl.domain.vo.StglActivityVo;
|
||||
import org.dromara.stgl.domain.vo.ActivityRatingVo;
|
||||
import org.dromara.stgl.mapper.StglActivityMapper;
|
||||
import org.dromara.stgl.mapper.StglActivityRatingMapper;
|
||||
import org.dromara.stgl.service.IStglActivityService;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -42,6 +44,9 @@ import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.StglVolunteerTeam;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglVolunteerTeamMapper;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 活动信息Service业务层处理
|
||||
@@ -58,6 +63,8 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
private final StglClubMapper stglClubMapper;
|
||||
private final StglVolunteerTeamMapper stglVolunteerTeamMapper;
|
||||
private final StglActivityRatingMapper stglActivityRatingMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询活动信息
|
||||
@@ -336,7 +343,7 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean copyActivity(Long sourceId, String newActivityName) {
|
||||
public Boolean copyActivity(Long sourceId, String newActivityName, String activityStatus, Integer registrationStatus) {
|
||||
StglActivityVo sourceActivity = queryById(sourceId);
|
||||
if (sourceActivity == null) {
|
||||
throw new RuntimeException("源活动不存在");
|
||||
@@ -367,8 +374,8 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
|
||||
// 设置业务字段
|
||||
newActivityEntity.setActivityName(newActivityName);
|
||||
newActivityEntity.setActivityStatus("1"); // 默认筹备中
|
||||
newActivityEntity.setRegistrationStatus(0); // 默认未开始
|
||||
newActivityEntity.setActivityStatus(activityStatus); // 使用传递的活动状态参数
|
||||
newActivityEntity.setRegistrationStatus(registrationStatus); // 使用传递的报名状态参数
|
||||
newActivityEntity.setIsFinished(0); // 设置为未完成
|
||||
newActivityEntity.setSummary(null); // 清空总结
|
||||
newActivityEntity.setAchievements(null); // 清空成果
|
||||
@@ -552,7 +559,7 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
log.info("应用数据权限:用户 {} 为社长角色,只能查看自己创建的活动", currentUserId);
|
||||
}
|
||||
|
||||
// 🔥 新增:如果是stgl_instructor角色且不是管理员,只能查看自己作为指导老师的社团的活动
|
||||
// 🔥 修正:如果是stgl_instructor角色且不是管理员,只能查看自己作为指导老师的活动
|
||||
if (roleKeys.contains("stgl_instructor") &&
|
||||
!roleKeys.contains("admin") &&
|
||||
!roleKeys.contains("common")) {
|
||||
@@ -560,24 +567,20 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
// 获取用户作为指导老师的社团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);
|
||||
// 获取用户作为指导老师的志愿者队伍ID列表
|
||||
List<Long> userAdvisorTeamIds = getUserAdvisorTeamIds(currentUserId);
|
||||
|
||||
// 获取用户作为指导老师的活动ID列表
|
||||
List<Long> userAdvisorActivityIds = getUserAdvisorActivityIds(currentUserId);
|
||||
|
||||
// 构建数据权限过滤条件
|
||||
String dataScope = buildInstructorDataScope(userAdvisorClubIds, userAdvisorTeamIds, userAdvisorActivityIds);
|
||||
|
||||
if (bo.getParams() == null) {
|
||||
bo.setParams(new HashMap<>());
|
||||
}
|
||||
bo.getParams().put("dataScope", dataScope);
|
||||
log.info("应用数据权限:用户 {} 为指导老师角色,数据权限条件: {}", currentUserId, dataScope);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -634,4 +637,195 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
|
||||
return clubIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户作为指导老师的志愿者队伍ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 志愿者队伍ID列表
|
||||
*/
|
||||
private List<Long> getUserAdvisorTeamIds(Long userId) {
|
||||
List<Long> teamIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 从stgl_volunteer_team表的advisor_name字段查询
|
||||
List<Long> nameTeamIds = getNameAdvisorTeamIds(userId);
|
||||
teamIds.addAll(nameTeamIds);
|
||||
|
||||
// 从stgl_volunteer_team表的advisors_json字段查询
|
||||
List<Long> jsonTeamIds = getJsonAdvisorTeamIds(userId);
|
||||
teamIds.addAll(jsonTeamIds);
|
||||
|
||||
log.debug("用户 {} 作为指导老师的志愿者队伍ID列表: {}", userId, teamIds);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户 {} 作为指导老师的志愿者队伍ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return teamIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从志愿者队伍表的advisor_name字段获取用户作为指导老师的志愿者队伍ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 志愿者队伍ID列表
|
||||
*/
|
||||
private List<Long> getNameAdvisorTeamIds(Long userId) {
|
||||
List<Long> teamIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 先通过用户ID查询用户信息,获取用户姓名
|
||||
SysUserVo user = sysUserService.selectUserById(userId);
|
||||
if (user != null && StringUtils.isNotBlank(user.getNickName())) {
|
||||
// 查询志愿者队伍表中advisor_name字段匹配该用户姓名的记录
|
||||
LambdaQueryWrapper<StglVolunteerTeam> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.select(StglVolunteerTeam::getId);
|
||||
lqw.eq(StglVolunteerTeam::getAdvisorName, user.getNickName());
|
||||
|
||||
List<StglVolunteerTeam> teams = stglVolunteerTeamMapper.selectList(lqw);
|
||||
teamIds = teams.stream()
|
||||
.map(StglVolunteerTeam::getId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("从志愿者队伍表获取用户 {} 作为指导老师的志愿者队伍ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return teamIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从志愿者队伍表的advisors_json字段获取用户作为指导老师的志愿者队伍ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 志愿者队伍ID列表
|
||||
*/
|
||||
private List<Long> getJsonAdvisorTeamIds(Long userId) {
|
||||
List<Long> teamIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 查询志愿者队伍表中advisors_json字段包含该用户的记录
|
||||
LambdaQueryWrapper<StglVolunteerTeam> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.select(StglVolunteerTeam::getId);
|
||||
lqw.isNotNull(StglVolunteerTeam::getAdvisorsJson);
|
||||
lqw.ne(StglVolunteerTeam::getAdvisorsJson, "");
|
||||
lqw.like(StglVolunteerTeam::getAdvisorsJson, userId.toString());
|
||||
|
||||
List<StglVolunteerTeam> teams = stglVolunteerTeamMapper.selectList(lqw);
|
||||
teamIds = teams.stream()
|
||||
.map(StglVolunteerTeam::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("从志愿者队伍表获取用户 {} 作为指导老师的志愿者队伍ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return teamIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户作为指导老师的活动ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 活动ID列表
|
||||
*/
|
||||
private List<Long> getUserAdvisorActivityIds(Long userId) {
|
||||
List<Long> activityIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 从stgl_activity表的instructors字段查询
|
||||
List<Long> jsonActivityIds = getJsonAdvisorActivityIds(userId);
|
||||
activityIds.addAll(jsonActivityIds);
|
||||
|
||||
log.debug("用户 {} 作为指导老师的活动ID列表: {}", userId, activityIds);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户 {} 作为指导老师的活动ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return activityIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从活动表的instructors字段获取用户作为指导老师的活动ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 活动ID列表
|
||||
*/
|
||||
private List<Long> getJsonAdvisorActivityIds(Long userId) {
|
||||
List<Long> activityIds = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 查询活动表中instructors字段包含该用户的记录
|
||||
LambdaQueryWrapper<StglActivity> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.select(StglActivity::getId);
|
||||
lqw.like(StglActivity::getInstructors, userId.toString());
|
||||
|
||||
List<StglActivity> activities = baseMapper.selectList(lqw);
|
||||
activityIds = activities.stream()
|
||||
.map(StglActivity::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("从活动表获取用户 {} 作为指导老师的活动ID列表时发生异常: {}", userId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return activityIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建指导老师数据权限过滤条件
|
||||
*
|
||||
* @param userAdvisorClubIds 用户作为指导老师的社团ID列表
|
||||
* @param userAdvisorTeamIds 用户作为指导老师的志愿者队伍ID列表
|
||||
* @param userAdvisorActivityIds 用户作为指导老师的活动ID列表
|
||||
* @return 数据权限过滤条件
|
||||
*/
|
||||
private String buildInstructorDataScope(List<Long> userAdvisorClubIds, List<Long> userAdvisorTeamIds, List<Long> userAdvisorActivityIds) {
|
||||
List<String> conditions = new ArrayList<>();
|
||||
|
||||
// 1. 是活动关联社团的指导老师
|
||||
if (!userAdvisorClubIds.isEmpty()) {
|
||||
String clubIdsStr = userAdvisorClubIds.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(","));
|
||||
conditions.add("(sa.related_type = 1 AND sa.related_club_id IN (" + clubIdsStr + "))");
|
||||
}
|
||||
|
||||
// 2. 是活动关联志愿者队伍的指导老师
|
||||
if (!userAdvisorTeamIds.isEmpty()) {
|
||||
String teamIdsStr = userAdvisorTeamIds.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(","));
|
||||
conditions.add("(sa.related_type = 2 AND sa.related_club_id IN (" + teamIdsStr + "))");
|
||||
}
|
||||
|
||||
// 3. 是活动本身的指导老师
|
||||
if (!userAdvisorActivityIds.isEmpty()) {
|
||||
String activityIdsStr = userAdvisorActivityIds.stream()
|
||||
.map(String::valueOf)
|
||||
.collect(Collectors.joining(","));
|
||||
conditions.add("sa.id IN (" + activityIdsStr + ")");
|
||||
}
|
||||
|
||||
// 如果没有任何权限,返回一个永远为false的条件
|
||||
if (conditions.isEmpty()) {
|
||||
return "AND 1 = 0";
|
||||
}
|
||||
|
||||
// 组合所有条件,使用OR连接
|
||||
return "AND (" + String.join(" OR ", conditions) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ActivityRatingVo> getActivityRatings(Long activityId) {
|
||||
if (activityId == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 使用自定义SQL查询评分详情,关联用户表获取完整信息
|
||||
return stglActivityRatingMapper.selectActivityRatingsWithUserInfo(activityId);
|
||||
}
|
||||
}
|
||||
-1
@@ -118,7 +118,6 @@ public class StglActivityTeamInfoServiceImpl extends ServiceImpl<StglActivityTea
|
||||
public List<StglActivityTeamInfoVo> queryByActivityId(Long activityId) {
|
||||
LambdaQueryWrapper<StglActivityTeamInfo> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglActivityTeamInfo::getActivityId, activityId);
|
||||
lqw.orderByDesc(StglActivityTeamInfo::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import org.dromara.stgl.domain.StglClass;
|
||||
import org.dromara.stgl.domain.vo.StglClassVo;
|
||||
import org.dromara.stgl.domain.bo.StglClassBo;
|
||||
import org.dromara.stgl.mapper.StglClassMapper;
|
||||
import org.dromara.stgl.service.IStglClassService;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClassServiceImpl implements IStglClassService {
|
||||
|
||||
private final StglClassMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询班主任的班级列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 班级列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getTeacherClasses(Long userId) {
|
||||
return baseMapper.selectTeacherClasses(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班级学生社团、志愿者队伍、活动参加情况分页列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClassVo> queryPageList(StglClassBo bo, PageQuery pageQuery) {
|
||||
// 构建查询参数
|
||||
Map<String, Object> params = buildQueryParams(bo);
|
||||
params.put("offset", (pageQuery.getPageNum() - 1) * pageQuery.getPageSize());
|
||||
params.put("pageSize", pageQuery.getPageSize());
|
||||
|
||||
// 使用自定义SQL查询
|
||||
List<StglClassVo> list = baseMapper.selectClassStudents(params);
|
||||
|
||||
// 获取总数
|
||||
Map<String, Object> countParams = buildQueryParams(bo);
|
||||
Integer total = baseMapper.selectClassStudentsCount(countParams);
|
||||
|
||||
TableDataInfo<StglClassVo> result = new TableDataInfo<>();
|
||||
result.setRows(list);
|
||||
result.setTotal(total != null ? total : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班级学生社团、志愿者队伍、活动参加情况列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 列表结果
|
||||
*/
|
||||
@Override
|
||||
public List<StglClassVo> queryList(StglClassBo bo) {
|
||||
LambdaQueryWrapper<StglClass> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生社团详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 社团详情列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getStudentClubs(Long studentId) {
|
||||
return baseMapper.selectStudentClubs(studentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生志愿者队伍详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 志愿者队伍详情列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getStudentVolunteerTeams(Long studentId) {
|
||||
return baseMapper.selectStudentVolunteerTeams(studentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生活动详情
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 活动详情列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getStudentActivities(Long studentId) {
|
||||
return baseMapper.selectStudentActivities(studentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询参数
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 查询参数
|
||||
*/
|
||||
private Map<String, Object> buildQueryParams(StglClassBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
if (StringUtils.isNotBlank(bo.getClassId())) {
|
||||
params.put("classId", bo.getClassId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getName())) {
|
||||
params.put("studentName", bo.getName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(bo.getStudentNo())) {
|
||||
params.put("studentNo", bo.getStudentNo());
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 查询条件
|
||||
*/
|
||||
private LambdaQueryWrapper<StglClass> buildQueryWrapper(StglClassBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglClass> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getClassId()), StglClass::getClassId, bo.getClassId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), StglClass::getName, bo.getName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), StglClass::getStudentNo, bo.getStudentNo());
|
||||
return lqw;
|
||||
}
|
||||
}
|
||||
+126
@@ -25,6 +25,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
// 添加学生信息服务依赖
|
||||
import org.dromara.xg.domain.XgStudentMsg;
|
||||
import org.dromara.xg.mapper.XgStudentMsgMapper;
|
||||
// 添加社长角色分配相关依赖
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
import org.dromara.system.mapper.SysUserRoleMapper;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Collections;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
@@ -56,6 +59,9 @@ import java.util.Set;
|
||||
public class StglClubServiceImpl implements IStglClubService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(StglClubServiceImpl.class);
|
||||
|
||||
// 社长角色ID常量
|
||||
private static final Long CLUB_PRESIDENT_ROLE_ID = 1957336212742184962L;
|
||||
|
||||
private final StglClubMapper baseMapper;
|
||||
private final StglMemberMapper memberMapper;
|
||||
@@ -63,6 +69,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
private final XgStudentMsgMapper studentMsgMapper;
|
||||
// 添加指导老师角色分配工具
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
// 添加用户角色Mapper
|
||||
private final SysUserRoleMapper sysUserRoleMapper;
|
||||
|
||||
/**
|
||||
* 查询社团信息
|
||||
@@ -332,6 +340,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
createLeaderMemberRecords(add);
|
||||
// 为指导老师分配角色
|
||||
assignAdvisorRoles(add);
|
||||
// 为社长分配角色
|
||||
assignPresidentRole(add);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@@ -1095,6 +1105,23 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
memberMapper.insert(newMember);
|
||||
}
|
||||
|
||||
// 8. 处理社长角色分配:移除原社长角色,为新社长分配角色
|
||||
try {
|
||||
// 8.1 移除原社长的角色(根据社团信息获取原社长的用户ID)
|
||||
Long oldPresidentUserId = findUserIdByStudentNo(club.getPresidentStudentNo());
|
||||
if (oldPresidentUserId != null) {
|
||||
removePresidentRole(oldPresidentUserId);
|
||||
log.info("社团转让:成功移除原社长角色,用户ID: {}, 社团: {}", oldPresidentUserId, club.getClubName());
|
||||
}
|
||||
|
||||
// 8.2 为新社长分配角色
|
||||
assignPresidentRoleByUserId(newPresidentUserId, club.getClubName());
|
||||
log.info("社团转让:成功为新社长分配角色,用户ID: {}, 社团: {}", newPresidentUserId, club.getClubName());
|
||||
} catch (Exception e) {
|
||||
log.error("社团转让时角色分配出现异常,社团: {}", club.getClubName(), e);
|
||||
// 注意:这里不抛出异常,避免影响转让主流程
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1207,5 +1234,104 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
|
||||
return advisorUserIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为社长分配角色
|
||||
*
|
||||
* @param club 社团信息
|
||||
*/
|
||||
private void assignPresidentRole(StglClub club) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(club.getPresidentStudentNo())) {
|
||||
// 根据学号查找用户ID
|
||||
Long presidentUserId = findUserIdByStudentNo(club.getPresidentStudentNo());
|
||||
if (presidentUserId != null) {
|
||||
assignPresidentRoleByUserId(presidentUserId, club.getClubName());
|
||||
} else {
|
||||
log.warn("社团 {} 的社长学号 {} 对应的用户不存在,跳过角色分配",
|
||||
club.getClubName(), club.getPresidentStudentNo());
|
||||
}
|
||||
} else {
|
||||
log.warn("社团 {} 的社长学号为空,跳过角色分配", club.getClubName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为社团 {} 的社长分配角色时发生异常", club.getClubName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID为社长分配角色
|
||||
*
|
||||
* @param presidentUserId 社长用户ID
|
||||
* @param clubName 社团名称
|
||||
*/
|
||||
private void assignPresidentRoleByUserId(Long presidentUserId, String clubName) {
|
||||
try {
|
||||
// 检查用户是否已有该角色
|
||||
if (!hasUserRole(presidentUserId, CLUB_PRESIDENT_ROLE_ID)) {
|
||||
SysUserRole userRole = new SysUserRole();
|
||||
userRole.setUserId(presidentUserId);
|
||||
userRole.setRoleId(CLUB_PRESIDENT_ROLE_ID);
|
||||
|
||||
int result = sysUserRoleMapper.insert(userRole);
|
||||
if (result > 0) {
|
||||
log.info("成功为社团 {} 的社长分配角色,社长用户ID: {}, 角色ID: {}",
|
||||
clubName, presidentUserId, CLUB_PRESIDENT_ROLE_ID);
|
||||
} else {
|
||||
log.error("为社团 {} 的社长分配角色失败,社长用户ID: {}", clubName, presidentUserId);
|
||||
}
|
||||
} else {
|
||||
log.debug("社团 {} 的社长已有该角色,跳过分配", clubName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为社团 {} 的社长分配角色时发生异常,社长用户ID: {}", clubName, presidentUserId, e);
|
||||
throw new RuntimeException("分配社长角色失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除社长角色
|
||||
*
|
||||
* @param presidentUserId 社长用户ID
|
||||
*/
|
||||
private void removePresidentRole(Long presidentUserId) {
|
||||
try {
|
||||
int result = sysUserRoleMapper.delete(
|
||||
Wrappers.<SysUserRole>lambdaQuery()
|
||||
.eq(SysUserRole::getUserId, presidentUserId)
|
||||
.eq(SysUserRole::getRoleId, CLUB_PRESIDENT_ROLE_ID)
|
||||
);
|
||||
|
||||
if (result > 0) {
|
||||
log.info("成功移除用户 {} 的社长角色", presidentUserId);
|
||||
} else {
|
||||
log.debug("用户 {} 没有社长角色需要移除", presidentUserId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("移除用户 {} 的社长角色时发生异常", presidentUserId, e);
|
||||
throw new RuntimeException("移除社长角色失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已有指定角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 是否已有该角色
|
||||
*/
|
||||
private boolean hasUserRole(Long userId, Long roleId) {
|
||||
try {
|
||||
LambdaQueryWrapper<SysUserRole> query = Wrappers.lambdaQuery();
|
||||
query.eq(SysUserRole::getUserId, userId)
|
||||
.eq(SysUserRole::getRoleId, roleId);
|
||||
return sysUserRoleMapper.selectCount(query) > 0;
|
||||
} catch (Exception e) {
|
||||
log.error("检查用户角色关系时发生异常,用户ID: {}, 角色ID: {}", userId, roleId, e);
|
||||
// 如果查询失败,假设用户没有该角色,继续分配
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+85
-10
@@ -28,6 +28,7 @@ import java.util.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -150,13 +151,16 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
// 处理状态查询:优先使用statusList多状态查询,如果没有则使用单个status
|
||||
if (params != null && params.get("statusList") != null) {
|
||||
Object statusList = params.get("statusList");
|
||||
log.info("StglMemberServiceImpl - statusList参数: {}, 类型: {}", statusList, statusList.getClass());
|
||||
if (statusList instanceof List) {
|
||||
List<?> statuses = (List<?>) statusList;
|
||||
if (!statuses.isEmpty()) {
|
||||
log.info("StglMemberServiceImpl - 使用List类型statusList: {}", statuses);
|
||||
lqw.in(StglMember::getStatus, statuses);
|
||||
}
|
||||
} else if (statusList instanceof String) {
|
||||
String statusStr = (String) statusList;
|
||||
log.info("StglMemberServiceImpl - 使用String类型statusList: {}", statusStr);
|
||||
if (statusStr.contains(",")) {
|
||||
// 处理 "0,3" 格式的字符串
|
||||
String[] statuses = statusStr.split(",");
|
||||
@@ -164,15 +168,20 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
for (String status : statuses) {
|
||||
statusList2.add(status.trim());
|
||||
}
|
||||
log.info("StglMemberServiceImpl - 解析后的statusList: {}", statusList2);
|
||||
lqw.in(StglMember::getStatus, statusList2);
|
||||
} else {
|
||||
// 单个状态值
|
||||
log.info("StglMemberServiceImpl - 单个状态值: {}", statusStr);
|
||||
lqw.eq(StglMember::getStatus, statusStr);
|
||||
}
|
||||
}
|
||||
} else if (bo.getStatus() != null) {
|
||||
// 如果没有statusList,则使用单个status字段
|
||||
log.info("StglMemberServiceImpl - 使用单个status: {}", bo.getStatus());
|
||||
lqw.eq(StglMember::getStatus, bo.getStatus());
|
||||
} else {
|
||||
log.info("StglMemberServiceImpl - 无状态过滤条件");
|
||||
}
|
||||
|
||||
lqw.between(params.get("beginJoinTime") != null && params.get("endJoinTime") != null,
|
||||
@@ -238,7 +247,14 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
entity.setStatus(2); // 默认为已加入状态(stgl_member_status字典)
|
||||
}
|
||||
if (entity.getRoleType() == null) {
|
||||
entity.setRoleType("3"); // 默认为普通成员
|
||||
// 根据成员类型设置不同的默认角色
|
||||
if (entity.getMemberType() != null && entity.getMemberType() == 2) {
|
||||
// 志愿者成员默认角色为"队员"
|
||||
entity.setRoleType("队员");
|
||||
} else {
|
||||
// 社团成员默认角色为"3"(普通成员)
|
||||
entity.setRoleType("3");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +335,16 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
member.setMemberType(memberType);
|
||||
member.setRelationId(relationId);
|
||||
member.setUserId(userId);
|
||||
member.setRoleType(roleType != null ? roleType.toString() : "3");
|
||||
// 根据成员类型设置不同的默认角色
|
||||
if (roleType != null) {
|
||||
member.setRoleType(roleType.toString());
|
||||
} else if (memberType == 2) {
|
||||
// 志愿者成员默认角色为"队员"
|
||||
member.setRoleType("队员");
|
||||
} else {
|
||||
// 社团成员默认角色为"3"
|
||||
member.setRoleType("3");
|
||||
}
|
||||
member.setJoinTime(now);
|
||||
member.setStatus(2); // 已加入状态(stgl_member_status字典)
|
||||
return member;
|
||||
@@ -425,7 +450,16 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
memberBo.setStudentNo(memberVo.getStudentNo());
|
||||
memberBo.setStudentName(memberVo.getStudentName());
|
||||
memberBo.setRelationId(memberVo.getRelationId());
|
||||
memberBo.setRoleType(memberVo.getRoleType() != null ? memberVo.getRoleType() : "1"); // 默认普通成员
|
||||
// 根据成员类型设置不同的默认角色
|
||||
if (memberVo.getRoleType() != null) {
|
||||
memberBo.setRoleType(memberVo.getRoleType());
|
||||
} else if (memberType == 2) {
|
||||
// 志愿者成员默认角色为"队员"
|
||||
memberBo.setRoleType("队员");
|
||||
} else {
|
||||
// 社团成员默认角色为"1"
|
||||
memberBo.setRoleType("1");
|
||||
}
|
||||
memberBo.setStatus(memberVo.getStatus() != null ? memberVo.getStatus() : "1"); // 默认正常状态
|
||||
memberBo.setJoinTime(memberVo.getJoinTime() != null ? memberVo.getJoinTime() : new Date());
|
||||
|
||||
@@ -584,22 +618,30 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
return bo; // 不做任何过滤
|
||||
}
|
||||
|
||||
// 如果是志愿者队长,只能查看自己担任队长的队伍成员
|
||||
// 如果是志愿者队长,可以查看自己担任队长的队伍成员,或者自己所在的队伍成员
|
||||
if (roles.contains("stgl_volunteer_captain")) {
|
||||
// 查询用户担任队长的队伍ID列表
|
||||
List<Long> captainTeamIds = getCaptainTeamIds(currentUserId);
|
||||
|
||||
if (captainTeamIds.isEmpty()) {
|
||||
// 如果用户不是任何队伍的队长,返回空结果
|
||||
// 查询用户作为成员所在的志愿者队伍ID列表
|
||||
List<Long> memberTeamIds = getMemberTeamIds(currentUserId);
|
||||
|
||||
// 合并队长和成员的队伍ID列表
|
||||
Set<Long> accessibleTeamIds = new HashSet<>();
|
||||
accessibleTeamIds.addAll(captainTeamIds);
|
||||
accessibleTeamIds.addAll(memberTeamIds);
|
||||
|
||||
if (accessibleTeamIds.isEmpty()) {
|
||||
// 如果用户不在任何志愿者队伍中,返回空结果
|
||||
bo.setRelationId(-1L); // 设置一个不存在的关联ID
|
||||
} else if (bo.getRelationId() == null) {
|
||||
// 如果没有指定特定队伍,限制查询范围为该用户担任队长的队伍
|
||||
// 如果没有指定特定队伍,限制查询范围为该用户有权限访问的队伍
|
||||
// 由于查询接口限制,我们只能返回第一个队伍的数据
|
||||
// 在实际应用中,前端应该明确指定要查询的队伍ID
|
||||
bo.setRelationId(captainTeamIds.get(0));
|
||||
bo.setRelationId(accessibleTeamIds.iterator().next());
|
||||
} else {
|
||||
// 如果指定了队伍ID,验证用户是否有权限访问该队伍
|
||||
if (!captainTeamIds.contains(bo.getRelationId())) {
|
||||
if (!accessibleTeamIds.contains(bo.getRelationId())) {
|
||||
bo.setRelationId(-1L); // 设置一个不存在的关联ID
|
||||
}
|
||||
}
|
||||
@@ -628,7 +670,7 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
// 查询用户作为队长的志愿者队伍
|
||||
StglMemberBo captainBo = new StglMemberBo();
|
||||
captainBo.setMemberType(2); // 志愿者成员
|
||||
captainBo.setRoleType("0"); // 队长角色
|
||||
captainBo.setRoleType("队长"); // 队长角色
|
||||
|
||||
List<StglMemberVo> captainRecords = baseMapper.selectMemberWithUserInfo(
|
||||
captainBo.getMemberType(),
|
||||
@@ -654,4 +696,37 @@ public class StglMemberServiceImpl implements IStglMemberService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户作为成员所在的队伍ID列表
|
||||
*/
|
||||
private List<Long> getMemberTeamIds(Long userId) {
|
||||
try {
|
||||
// 查询用户作为成员的志愿者队伍
|
||||
StglMemberBo memberBo = new StglMemberBo();
|
||||
memberBo.setMemberType(2); // 志愿者成员
|
||||
|
||||
List<StglMemberVo> memberRecords = baseMapper.selectMemberWithUserInfo(
|
||||
memberBo.getMemberType(),
|
||||
null, // relationId 不限制
|
||||
null, // studentNo
|
||||
null, // studentName
|
||||
null, // roleType 不限制角色
|
||||
null, // status
|
||||
null, // clubName
|
||||
null, // teamName
|
||||
userId, // userId 权限过滤
|
||||
null // params
|
||||
);
|
||||
|
||||
return memberRecords.stream()
|
||||
.map(StglMemberVo::getRelationId)
|
||||
.filter(relationId -> relationId != null)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
} catch (Exception e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+9
-6
@@ -20,6 +20,8 @@ import org.dromara.system.service.ISysUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@@ -60,10 +62,10 @@ public class StglMyServiceImpl implements IStglMyService {
|
||||
* 查询我报名的活动列表(带评分状态)
|
||||
*/
|
||||
@Override
|
||||
public List<MyActivityVo> queryMyActivities() {
|
||||
public List<MyActivityVo> queryMyActivities(String activityName, String activityType, String isRated) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
return stglMyMapper.selectMyActivities(userId, tenantId);
|
||||
return stglMyMapper.selectMyActivities(userId, tenantId, activityName, activityType, isRated);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,9 +108,10 @@ public class StglMyServiceImpl implements IStglMyService {
|
||||
rating.setStudentNo(userInfo.getUserName()); // 使用用户名作为学号
|
||||
rating.setStudentName(userInfo.getNickName());
|
||||
|
||||
// 计算综合评分(三项评分平均值)
|
||||
double avgScore = (ratingBo.getContentScore() + ratingBo.getOrganizationScore() + ratingBo.getExperienceScore()) / 3.0;
|
||||
rating.setRatingScore((int) Math.round(avgScore));
|
||||
// 计算综合评分(三项评分平均值,保留1位小数)
|
||||
BigDecimal avgScore = BigDecimal.valueOf(ratingBo.getContentScore() + ratingBo.getOrganizationScore() + ratingBo.getExperienceScore())
|
||||
.divide(BigDecimal.valueOf(3), 1, RoundingMode.HALF_UP);
|
||||
rating.setRatingScore(avgScore);
|
||||
rating.setRatingTime(LocalDateTime.now());
|
||||
|
||||
return stglActivityRatingMapper.insert(rating) > 0;
|
||||
@@ -123,7 +126,7 @@ public class StglMyServiceImpl implements IStglMyService {
|
||||
String tenantId = LoginHelper.getTenantId();
|
||||
|
||||
// 查询用户的活动信息
|
||||
List<MyActivityVo> activities = stglMyMapper.selectMyActivities(userId, tenantId);
|
||||
List<MyActivityVo> activities = stglMyMapper.selectMyActivities(userId, tenantId, null, null, null);
|
||||
|
||||
// 查找指定的活动
|
||||
return activities.stream()
|
||||
|
||||
+247
-44
@@ -22,8 +22,10 @@ import org.dromara.xg.mapper.XgStudentMsgMapper;
|
||||
import org.dromara.xg.domain.vo.XgStudentMsgVo;
|
||||
import org.dromara.xg.domain.XgStudentMsg;
|
||||
import org.dromara.system.mapper.SysUserMapper;
|
||||
import org.dromara.system.mapper.SysUserRoleMapper;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
@@ -35,6 +37,11 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
* 志愿者队伍Service业务层处理
|
||||
@@ -51,8 +58,19 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
private final StglMemberMapper memberMapper;
|
||||
private final XgStudentMsgMapper studentMsgMapper;
|
||||
private final SysUserMapper userMapper;
|
||||
private final SysUserRoleMapper sysUserRoleMapper;
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
|
||||
/**
|
||||
* 志愿者队长角色ID
|
||||
*/
|
||||
private static final Long VOLUNTEER_CAPTAIN_ROLE_ID = 1957353206166118402L;
|
||||
|
||||
/**
|
||||
* 指导老师角色ID
|
||||
*/
|
||||
private static final Long ADVISOR_ROLE_ID = 1959880215953952769L;
|
||||
|
||||
/**
|
||||
* 查询志愿者队伍
|
||||
*/
|
||||
@@ -153,6 +171,8 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
bo.setId(add.getId());
|
||||
// 自动创建队长的成员记录
|
||||
createLeaderMemberRecord(add);
|
||||
// 为队长分配角色
|
||||
assignLeaderRole(add);
|
||||
// 为指导老师分配角色
|
||||
assignAdvisorRole(add);
|
||||
}
|
||||
@@ -168,7 +188,7 @@ 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());
|
||||
@@ -180,6 +200,8 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
if (updateResult) {
|
||||
// 同步更新队长的成员记录
|
||||
syncLeaderInMembers(update);
|
||||
// 处理队长角色分配
|
||||
handleLeaderRoleAssignment(oldTeam, update);
|
||||
// 处理指导老师角色分配
|
||||
handleAdvisorRoleAssignment(oldTeam, update);
|
||||
}
|
||||
@@ -318,7 +340,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
query.eq(StglMember::getMemberType, 2); // 志愿者成员
|
||||
query.eq(StglMember::getRelationId, teamId); // 指定队伍
|
||||
query.eq(StglMember::getStudentNo, studentNo); // 指定学号
|
||||
query.eq(StglMember::getRoleType, "0"); // 队长角色
|
||||
query.eq(StglMember::getRoleType, "队长"); // 队长角色
|
||||
query.eq(StglMember::getStatus, 2); // 已加入状态
|
||||
|
||||
return memberMapper.selectCount(query) > 0;
|
||||
@@ -448,7 +470,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
member.setUserId(LoginHelper.getUserId()); // 设置当前登录用户ID
|
||||
member.setStudentName(applicationBo.getStudentName());
|
||||
member.setStudentNo(applicationBo.getStudentNo());
|
||||
member.setRoleType("1"); // 1-队员(志愿者角色)
|
||||
member.setRoleType("队员"); // 队员角色 - 直接写入字符"队员"
|
||||
member.setStatus(0); // 0-待审核
|
||||
member.setJoinTime(new Date());
|
||||
|
||||
@@ -555,7 +577,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
leader.setUserId(team.getLeaderUserId());
|
||||
leader.setStudentNo(team.getLeaderStudentNo());
|
||||
leader.setStudentName(team.getLeaderName());
|
||||
leader.setRoleType("0"); // 队长 (stgl_volunteer_role=0)
|
||||
leader.setRoleType("队长"); // 队长角色 - 直接写入字符"队长"
|
||||
leader.setJoinTime(team.getCreateTime() != null ? team.getCreateTime() : new Date());
|
||||
leader.setStatus(2); // 已加入状态
|
||||
leader.setRemark("补充缺失的队长成员记录");
|
||||
@@ -599,6 +621,9 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
throw new RuntimeException("志愿者队伍不存在");
|
||||
}
|
||||
|
||||
// 保存原队长用户ID,用于角色分配处理
|
||||
Long oldLeaderUserId = team.getLeaderUserId();
|
||||
|
||||
// 2. 获取新队长的学生信息
|
||||
XgStudentMsg newLeaderStudent = studentMsgMapper.selectOne(
|
||||
Wrappers.<XgStudentMsg>lambdaQuery()
|
||||
@@ -633,23 +658,43 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
throw new RuntimeException("更新队伍信息失败");
|
||||
}
|
||||
|
||||
// 5. 更新成员表
|
||||
// 5. 处理角色分配:移除原队长角色,为新队长分配角色
|
||||
try {
|
||||
// 5.1 移除原队长的角色
|
||||
if (oldLeaderUserId != null) {
|
||||
removeLeaderRole(oldLeaderUserId);
|
||||
log.info("志愿者队伍转让:成功移除原队长角色,用户ID: {}, 队伍: {}", oldLeaderUserId, team.getTeamName());
|
||||
}
|
||||
|
||||
// 5.2 为新队长分配角色
|
||||
StglVolunteerTeam updatedTeam = new StglVolunteerTeam();
|
||||
updatedTeam.setId(teamId);
|
||||
updatedTeam.setTeamName(team.getTeamName());
|
||||
updatedTeam.setLeaderUserId(newLeaderUserId);
|
||||
assignLeaderRole(updatedTeam);
|
||||
log.info("志愿者队伍转让:成功为新队长分配角色,用户ID: {}, 队伍: {}", newLeaderUserId, team.getTeamName());
|
||||
} catch (Exception e) {
|
||||
log.error("志愿者队伍转让时角色分配出现异常,队伍: {}", team.getTeamName(), e);
|
||||
// 注意:这里不抛出异常,避免影响转让主流程
|
||||
}
|
||||
|
||||
// 6. 更新成员表
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 5.1 查询原队长在成员表中的记录
|
||||
// 6.1 查询原队长在成员表中的记录
|
||||
StglMember oldLeaderMember = null;
|
||||
if (currentUserId != null) {
|
||||
oldLeaderMember = memberMapper.selectOne(
|
||||
Wrappers.<StglMember>lambdaQuery()
|
||||
.eq(StglMember::getMemberType, 2) // 志愿者队伍成员
|
||||
.eq(StglMember::getRelationId, teamId)
|
||||
.eq(StglMember::getRoleType, 0) // 队长角色
|
||||
.eq(StglMember::getRoleType, "队长") // 队长角色 - 直接使用字符"队长"
|
||||
.eq(StglMember::getUserId, currentUserId) // 添加当前用户ID条件
|
||||
.eq(StglMember::getStatus, 2) // 已加入状态
|
||||
);
|
||||
}
|
||||
|
||||
// 5.2 查询新队长在成员表中的记录
|
||||
// 6.2 查询新队长在成员表中的记录
|
||||
StglMember newLeaderMember = memberMapper.selectOne(
|
||||
Wrappers.<StglMember>lambdaQuery()
|
||||
.eq(StglMember::getMemberType, 2) // 志愿者队伍成员
|
||||
@@ -657,7 +702,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
.eq(StglMember::getUserId, newLeaderUserId)
|
||||
);
|
||||
|
||||
// 5.3 更新原队长的成员状态为已退出
|
||||
// 6.3 更新原队长的成员状态为已退出
|
||||
if (oldLeaderMember != null) {
|
||||
StglMember updateOldLeader = new StglMember();
|
||||
updateOldLeader.setId(oldLeaderMember.getId());
|
||||
@@ -667,12 +712,12 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
memberMapper.updateById(updateOldLeader);
|
||||
}
|
||||
|
||||
// 5.4 添加或更新新队长的成员记录
|
||||
// 6.4 添加或更新新队长的成员记录
|
||||
if (newLeaderMember != null) {
|
||||
// 如果新队长已经是成员,更新角色和状态
|
||||
StglMember updateNewLeader = new StglMember();
|
||||
updateNewLeader.setId(newLeaderMember.getId());
|
||||
updateNewLeader.setRoleType("0"); // 队长角色
|
||||
updateNewLeader.setRoleType("队长"); // 队长角色 - 直接写入字符"队长"
|
||||
updateNewLeader.setStatus(2); // 已加入状态
|
||||
updateNewLeader.setJoinTime(new Date());
|
||||
updateNewLeader.setUpdateBy(LoginHelper.getUserId());
|
||||
@@ -690,7 +735,7 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
newMember.setUserId(newLeaderUserId);
|
||||
newMember.setStudentNo(newLeaderStudent.getStudentNo());
|
||||
newMember.setStudentName(newLeaderStudent.getName());
|
||||
newMember.setRoleType("0"); // 队长角色
|
||||
newMember.setRoleType("队长"); // 队长角色 - 直接写入字符"队长"
|
||||
newMember.setJoinTime(new Date());
|
||||
newMember.setStatus(2); // 已加入状态
|
||||
newMember.setCreateBy(LoginHelper.getUserId());
|
||||
@@ -854,10 +899,12 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
*/
|
||||
private void assignAdvisorRole(StglVolunteerTeam team) {
|
||||
try {
|
||||
Long advisorUserId = extractAdvisorUserId(team);
|
||||
if (advisorUserId != null) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserId);
|
||||
log.info("成功为志愿者队伍 {} 的指导老师分配角色,指导老师用户ID: {}", team.getTeamName(), advisorUserId);
|
||||
List<Long> advisorUserIds = extractAdvisorUserIds(team);
|
||||
for (Long advisorUserId : advisorUserIds) {
|
||||
if (advisorUserId != null) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserId);
|
||||
log.info("成功为志愿者队伍 {} 的指导老师分配角色,指导老师用户ID: {}", team.getTeamName(), advisorUserId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为志愿者队伍 {} 的指导老师分配角色时发生异常", team.getTeamName(), e);
|
||||
@@ -873,23 +920,30 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
*/
|
||||
private void handleAdvisorRoleAssignment(StglVolunteerTeam oldTeam, StglVolunteerTeam newTeam) {
|
||||
try {
|
||||
// 获取更新前后的指导老师用户ID
|
||||
Long oldAdvisorUserId = oldTeam != null ? extractAdvisorUserId(oldTeam) : null;
|
||||
Long newAdvisorUserId = extractAdvisorUserId(newTeam);
|
||||
// 获取更新前后的指导老师用户ID列表
|
||||
List<Long> oldAdvisorUserIds = oldTeam != null ? extractAdvisorUserIds(oldTeam) : new ArrayList<>();
|
||||
List<Long> newAdvisorUserIds = extractAdvisorUserIds(newTeam);
|
||||
|
||||
// 如果指导老师发生变化
|
||||
if (!Objects.equals(oldAdvisorUserId, newAdvisorUserId)) {
|
||||
// 移除旧指导老师的角色
|
||||
if (oldAdvisorUserId != null) {
|
||||
advisorRoleAssigner.removeAdvisorRole(oldAdvisorUserId);
|
||||
log.info("志愿者队伍 {} 移除指导老师,成功移除角色,用户ID: {}", newTeam.getTeamName(), oldAdvisorUserId);
|
||||
}
|
||||
// 找出需要移除角色的指导老师
|
||||
List<Long> removedAdvisorUserIds = oldAdvisorUserIds.stream()
|
||||
.filter(oldId -> !newAdvisorUserIds.contains(oldId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 为新指导老师分配角色
|
||||
if (newAdvisorUserId != null) {
|
||||
advisorRoleAssigner.assignAdvisorRole(newAdvisorUserId);
|
||||
log.info("志愿者队伍 {} 新增指导老师,成功分配角色,用户ID: {}", newTeam.getTeamName(), newAdvisorUserId);
|
||||
}
|
||||
// 找出需要分配角色的指导老师
|
||||
List<Long> addedAdvisorUserIds = newAdvisorUserIds.stream()
|
||||
.filter(newId -> !oldAdvisorUserIds.contains(newId))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 移除旧指导老师的角色
|
||||
for (Long advisorUserId : removedAdvisorUserIds) {
|
||||
advisorRoleAssigner.removeAdvisorRole(advisorUserId);
|
||||
log.info("志愿者队伍 {} 移除指导老师,成功移除角色,用户ID: {}", newTeam.getTeamName(), advisorUserId);
|
||||
}
|
||||
|
||||
// 为新指导老师分配角色
|
||||
for (Long advisorUserId : addedAdvisorUserIds) {
|
||||
advisorRoleAssigner.assignAdvisorRole(advisorUserId);
|
||||
log.info("志愿者队伍 {} 新增指导老师,成功分配角色,用户ID: {}", newTeam.getTeamName(), advisorUserId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理志愿者队伍 {} 的指导老师角色分配时发生异常", newTeam.getTeamName(), e);
|
||||
@@ -897,26 +951,175 @@ public class StglVolunteerTeamServiceImpl implements IStglVolunteerTeamService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 为队长分配角色
|
||||
*
|
||||
* @param team 志愿者队伍信息
|
||||
*/
|
||||
private void assignLeaderRole(StglVolunteerTeam team) {
|
||||
try {
|
||||
if (team.getLeaderUserId() != null) {
|
||||
// 检查用户是否已有该角色
|
||||
if (!hasUserRole(team.getLeaderUserId(), VOLUNTEER_CAPTAIN_ROLE_ID)) {
|
||||
SysUserRole userRole = new SysUserRole();
|
||||
userRole.setUserId(team.getLeaderUserId());
|
||||
userRole.setRoleId(VOLUNTEER_CAPTAIN_ROLE_ID);
|
||||
|
||||
int result = sysUserRoleMapper.insert(userRole);
|
||||
if (result > 0) {
|
||||
log.info("成功为志愿者队伍 {} 的队长分配角色,队长用户ID: {}, 角色ID: {}",
|
||||
team.getTeamName(), team.getLeaderUserId(), VOLUNTEER_CAPTAIN_ROLE_ID);
|
||||
} else {
|
||||
log.error("为志愿者队伍 {} 的队长分配角色失败,队长用户ID: {}", team.getTeamName(), team.getLeaderUserId());
|
||||
}
|
||||
} else {
|
||||
log.debug("志愿者队伍 {} 的队长已有该角色,跳过分配", team.getTeamName());
|
||||
}
|
||||
} else {
|
||||
log.warn("志愿者队伍 {} 的队长用户ID为空,跳过角色分配", team.getTeamName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为志愿者队伍 {} 的队长分配角色时发生异常", team.getTeamName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理队长角色分配(更新时使用)
|
||||
*
|
||||
* @param oldTeam 更新前的队伍信息
|
||||
* @param newTeam 更新后的队伍信息
|
||||
*/
|
||||
private void handleLeaderRoleAssignment(StglVolunteerTeam oldTeam, StglVolunteerTeam newTeam) {
|
||||
try {
|
||||
// 获取更新前后的队长用户ID
|
||||
Long oldLeaderUserId = oldTeam != null ? oldTeam.getLeaderUserId() : null;
|
||||
Long newLeaderUserId = newTeam.getLeaderUserId();
|
||||
|
||||
// 如果队长发生变化
|
||||
if (!Objects.equals(oldLeaderUserId, newLeaderUserId)) {
|
||||
// 移除旧队长的角色
|
||||
if (oldLeaderUserId != null) {
|
||||
removeLeaderRole(oldLeaderUserId);
|
||||
log.info("志愿者队伍 {} 更换队长,成功移除原队长角色,用户ID: {}", newTeam.getTeamName(), oldLeaderUserId);
|
||||
}
|
||||
|
||||
// 为新队长分配角色
|
||||
if (newLeaderUserId != null) {
|
||||
assignLeaderRole(newTeam);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理志愿者队伍 {} 的队长角色分配时发生异常", newTeam.getTeamName(), e);
|
||||
// 不抛出异常,避免影响主业务流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除队长角色
|
||||
*
|
||||
* @param leaderUserId 队长用户ID
|
||||
*/
|
||||
private void removeLeaderRole(Long leaderUserId) {
|
||||
try {
|
||||
int result = sysUserRoleMapper.delete(
|
||||
Wrappers.<SysUserRole>lambdaQuery()
|
||||
.eq(SysUserRole::getUserId, leaderUserId)
|
||||
.eq(SysUserRole::getRoleId, VOLUNTEER_CAPTAIN_ROLE_ID)
|
||||
);
|
||||
|
||||
if (result > 0) {
|
||||
log.info("成功移除用户 {} 的志愿者队长角色", leaderUserId);
|
||||
} else {
|
||||
log.debug("用户 {} 没有志愿者队长角色需要移除", leaderUserId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("移除用户 {} 的志愿者队长角色时发生异常", leaderUserId, e);
|
||||
throw new RuntimeException("移除志愿者队长角色失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已有指定角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param roleId 角色ID
|
||||
* @return 是否已有该角色
|
||||
*/
|
||||
private boolean hasUserRole(Long userId, Long roleId) {
|
||||
try {
|
||||
LambdaQueryWrapper<SysUserRole> query = Wrappers.lambdaQuery();
|
||||
query.eq(SysUserRole::getUserId, userId)
|
||||
.eq(SysUserRole::getRoleId, roleId);
|
||||
return sysUserRoleMapper.selectCount(query) > 0;
|
||||
} catch (Exception e) {
|
||||
log.error("检查用户角色关系时发生异常,用户ID: {}, 角色ID: {}", userId, roleId, e);
|
||||
// 如果查询失败,假设用户没有该角色,继续分配
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从志愿者队伍信息中提取指导老师用户ID
|
||||
*
|
||||
* @param team 志愿者队伍信息
|
||||
* @return 指导老师用户ID列表
|
||||
*/
|
||||
private List<Long> extractAdvisorUserIds(StglVolunteerTeam team) {
|
||||
List<Long> advisorUserIds = new ArrayList<>();
|
||||
|
||||
// 1. 从advisorsJson字段提取指导老师用户ID
|
||||
if (StringUtils.isNotBlank(team.getAdvisorsJson())) {
|
||||
try {
|
||||
List<Map<String, Object>> advisors = JsonUtils.parseObject(team.getAdvisorsJson(), new TypeReference<List<Map<String, Object>>>() {});
|
||||
if (advisors != null) {
|
||||
for (Map<String, Object> advisor : advisors) {
|
||||
Object userIdObj = advisor.get("userId");
|
||||
if (userIdObj != null) {
|
||||
Long userId = Long.valueOf(userIdObj.toString());
|
||||
advisorUserIds.add(userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析志愿者队伍 {} 的指导老师JSON数据时发生异常", team.getTeamName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 从advisorName字段提取指导老师用户ID(兼容旧数据)
|
||||
if (advisorUserIds.isEmpty() && StringUtils.isNotBlank(team.getAdvisorName())) {
|
||||
try {
|
||||
// 根据指导老师姓名查找用户ID
|
||||
LambdaQueryWrapper<SysUser> query = Wrappers.lambdaQuery();
|
||||
query.eq(SysUser::getNickName, team.getAdvisorName())
|
||||
.eq(SysUser::getDelFlag, "0")
|
||||
.eq(SysUser::getStatus, "0")
|
||||
.last("LIMIT 1");
|
||||
|
||||
SysUser advisor = userMapper.selectOne(query);
|
||||
if (advisor != null) {
|
||||
log.debug("找到志愿者队伍 {} 的指导老师用户ID: {} ({})", team.getTeamName(), advisor.getUserId(), team.getAdvisorName());
|
||||
advisorUserIds.add(advisor.getUserId());
|
||||
} else {
|
||||
log.debug("未找到志愿者队伍 {} 指导老师的用户信息: {}", team.getTeamName(), team.getAdvisorName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("查找志愿者队伍 {} 指导老师用户ID时发生异常", team.getTeamName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return advisorUserIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从志愿者队伍信息中提取指导老师用户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;
|
||||
List<Long> advisorUserIds = extractAdvisorUserIds(team);
|
||||
return advisorUserIds.isEmpty() ? null : advisorUserIds.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -64,4 +64,32 @@
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<!-- 查询活动评分详情(关联用户表获取详细信息) -->
|
||||
<select id="selectActivityRatingsWithUserInfo" resultType="org.dromara.stgl.domain.vo.ActivityRatingVo">
|
||||
SELECT
|
||||
sar.id,
|
||||
sar.activity_id as activityId,
|
||||
sar.user_id as userId,
|
||||
COALESCE(sar.student_name, su.nick_name, su.user_name) as userName,
|
||||
sar.student_no as studentNo,
|
||||
su.phonenumber as phoneNumber,
|
||||
sd.dept_name as deptName,
|
||||
su.remark as majorName,
|
||||
'' as className,
|
||||
sar.rating_score as ratingScore,
|
||||
sar.content_score as contentScore,
|
||||
sar.organization_score as organizationScore,
|
||||
sar.experience_score as experienceScore,
|
||||
sar.rating_comment as ratingComment,
|
||||
sar.rating_time as ratingTime
|
||||
FROM stgl_activity_rating sar
|
||||
LEFT JOIN sys_user su ON sar.user_id = su.user_id AND su.del_flag = '0'
|
||||
LEFT JOIN sys_dept sd ON su.dept_id = sd.dept_id AND sd.del_flag = '0'
|
||||
<where>
|
||||
sar.activity_id = #{activityId}
|
||||
AND sar.deleted = 0
|
||||
</where>
|
||||
ORDER BY sar.rating_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -200,6 +200,10 @@
|
||||
<if test="userId != null">
|
||||
AND m.user_id = #{userId}
|
||||
</if>
|
||||
<!-- 联系方式过滤:通过用户表的phonenumber字段 -->
|
||||
<if test="params != null and params.phone != null and params.phone != ''">
|
||||
AND u.phonenumber LIKE CONCAT('%', #{params.phone}, '%')
|
||||
</if>
|
||||
ORDER BY m.role_type ASC, m.join_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
a.update_time,
|
||||
ar.registration_time as my_registration_time,
|
||||
CAST(ar.approval_status AS CHAR) as my_registration_status,
|
||||
CAST(ar.registration_type AS CHAR) as registration_type,
|
||||
CASE WHEN rat.id IS NOT NULL THEN 1 ELSE 0 END as my_rating_status,
|
||||
rat.rating_score as my_rating_score,
|
||||
rat.rating_time as my_rating_time,
|
||||
@@ -149,15 +150,107 @@
|
||||
</sql>
|
||||
|
||||
<select id="selectMyActivities" resultType="org.dromara.stgl.domain.vo.MyActivityVo">
|
||||
<include refid="selectMyActivitiesVo"/>
|
||||
SELECT DISTINCT
|
||||
a.id,
|
||||
a.activity_name,
|
||||
CAST(a.activity_type AS CHAR) as activity_type,
|
||||
a.activity_theme,
|
||||
a.start_time,
|
||||
a.end_time,
|
||||
a.location,
|
||||
a.organizer_name,
|
||||
CAST(a.related_type AS CHAR) as related_type,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.club_name
|
||||
WHEN a.related_type = 2 THEN vt.team_name
|
||||
ELSE NULL
|
||||
END as organization_name,
|
||||
a.instructors,
|
||||
CAST(a.activity_status AS CHAR) as activity_status,
|
||||
-- 动态计算报名状态:优先根据活动状态,再根据报名时间范围
|
||||
CAST(
|
||||
CASE
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
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,
|
||||
a.poster_url,
|
||||
a.description,
|
||||
a.create_by,
|
||||
a.create_time,
|
||||
a.update_by,
|
||||
a.update_time,
|
||||
COALESCE(direct_ar.registration_time, team_ar.registration_time) as my_registration_time,
|
||||
CAST(COALESCE(direct_ar.approval_status, team_ar.approval_status) AS CHAR) as my_registration_status,
|
||||
CAST(COALESCE(direct_ar.registration_type, team_ar.registration_type) AS CHAR) as registration_type,
|
||||
CASE WHEN rat.id IS NOT NULL THEN 1 ELSE 0 END as my_rating_status,
|
||||
rat.rating_score as my_rating_score,
|
||||
rat.rating_time as my_rating_time,
|
||||
(SELECT AVG(rating_score) FROM stgl_activity_rating WHERE activity_id = a.id AND deleted = 0) as average_rating,
|
||||
CASE
|
||||
WHEN rat.id IS NOT NULL THEN 0
|
||||
WHEN a.activity_status IN ('4', '5') AND COALESCE(direct_ar.approval_status, team_ar.approval_status) = '1' THEN 1
|
||||
ELSE 0
|
||||
END as can_rate
|
||||
FROM stgl_activity a
|
||||
LEFT JOIN (
|
||||
-- 直接报名的活动(个人报名或作为队长的团队报名)
|
||||
SELECT ar.* FROM stgl_activity_registration ar
|
||||
WHERE ar.user_id = #{userId} AND ar.deleted = 0 AND ar.tenant_id = #{tenantId}
|
||||
) direct_ar ON a.id = direct_ar.activity_id
|
||||
LEFT JOIN (
|
||||
-- 作为团队成员参与的活动
|
||||
SELECT ar.activity_id, ar.registration_time, ar.approval_status, ar.registration_type
|
||||
FROM stgl_activity_registration ar
|
||||
INNER JOIN stgl_activity_team_info ati ON ar.team_id = ati.id
|
||||
WHERE JSON_SEARCH(ati.team_members, 'one', #{userId}, NULL, '$[*].userId') IS NOT NULL
|
||||
AND ar.deleted = 0
|
||||
AND ati.deleted = 0
|
||||
AND ar.tenant_id = #{tenantId}
|
||||
AND ati.tenant_id = #{tenantId}
|
||||
AND ar.approval_status = '1' -- 只显示已通过的团队报名
|
||||
) team_ar ON a.id = team_ar.activity_id
|
||||
LEFT JOIN stgl_club c ON a.related_type = 1 AND a.related_club_id = c.id AND c.deleted = 0 AND c.tenant_id = #{tenantId}
|
||||
LEFT JOIN stgl_volunteer_team vt ON a.related_type = 2 AND a.related_club_id = vt.id AND vt.deleted = 0 AND vt.tenant_id = #{tenantId}
|
||||
LEFT JOIN stgl_activity_rating rat ON a.id = rat.activity_id AND rat.user_id = #{userId} AND rat.deleted = 0
|
||||
<where>
|
||||
ar.user_id = #{userId}
|
||||
AND ar.deleted = 0
|
||||
(direct_ar.activity_id IS NOT NULL OR team_ar.activity_id IS NOT NULL)
|
||||
AND a.deleted = 0
|
||||
AND a.tenant_id = #{tenantId}
|
||||
AND ar.tenant_id = #{tenantId}
|
||||
<if test="activityName != null and activityName != ''">
|
||||
AND a.activity_name LIKE CONCAT('%', #{activityName}, '%')
|
||||
</if>
|
||||
<if test="activityType != null and activityType != ''">
|
||||
AND a.activity_type = #{activityType}
|
||||
</if>
|
||||
<if test="isRated != null and isRated != ''">
|
||||
<if test="isRated == '1'">
|
||||
AND rat.id IS NOT NULL
|
||||
</if>
|
||||
<if test="isRated == '0'">
|
||||
AND rat.id IS NULL
|
||||
</if>
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY ar.registration_time DESC
|
||||
ORDER BY COALESCE(direct_ar.registration_time, team_ar.registration_time) DESC
|
||||
</select>
|
||||
|
||||
<!-- 我的报名记录查询(统一查询社团+志愿团队+活动) -->
|
||||
|
||||
+39
-9
@@ -14,12 +14,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="teamMembers" column="team_members" />
|
||||
<result property="teamSize" column="team_size" />
|
||||
<result property="description" column="description" />
|
||||
<result property="leaderGender" column="leader_gender" />
|
||||
<result property="leaderPhone" column="leader_phone" />
|
||||
<result property="leaderEmail" column="leader_email" />
|
||||
<result property="leaderDepartment" column="leader_department" />
|
||||
<result property="leaderMajor" column="leader_major" />
|
||||
<result property="leaderClassName" column="leader_class_name" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="createDept" column="create_dept" />
|
||||
<result property="createBy" column="create_by" />
|
||||
@@ -28,16 +22,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateTime" column="update_time" />
|
||||
<result property="deleted" column="deleted" />
|
||||
<result property="activityName" column="activity_name" />
|
||||
<!-- 队长详细信息字段 -->
|
||||
<result property="leaderGender" column="leader_gender" />
|
||||
<result property="leaderPhone" column="leader_phone" />
|
||||
<result property="leaderEmail" column="leader_email" />
|
||||
<result property="leaderDepartment" column="leader_department" />
|
||||
<result property="leaderMajor" column="leader_major" />
|
||||
<result property="leaderClassName" column="leader_class_name" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglActivityTeamInfoVo">
|
||||
select t.id, t.team_name, t.activity_id, t.leader_user_id, t.leader_name, t.leader_student_no,
|
||||
t.team_members, t.team_size, t.description, t.leader_gender, t.leader_phone, t.leader_email,
|
||||
t.leader_department, t.leader_major, t.leader_class_name,
|
||||
t.team_members, t.team_size, t.description,
|
||||
t.tenant_id, t.create_dept, t.create_by, t.create_time, t.update_by, t.update_time, t.deleted,
|
||||
a.activity_name
|
||||
a.activity_name,
|
||||
<!-- 队长详细信息 -->
|
||||
s.gender as leader_gender,
|
||||
s.phone as leader_phone,
|
||||
s.email as leader_email,
|
||||
s.college_name as leader_department,
|
||||
s.major_name as leader_major,
|
||||
s.class_name as leader_class_name
|
||||
from stgl_activity_team_info t
|
||||
left join stgl_activity a on t.activity_id = a.id
|
||||
left join xg_student_msg s on t.leader_student_no = s.student_no and s.deleted = 0
|
||||
</sql>
|
||||
|
||||
<select id="selectList" parameterType="org.dromara.stgl.domain.StglActivityTeamInfo" resultMap="StglActivityTeamInfoResult">
|
||||
@@ -66,4 +74,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
order by t.create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据条件查询团队信息列表(VO对象) -->
|
||||
<select id="selectVoList" resultMap="StglActivityTeamInfoResult">
|
||||
<include refid="selectStglActivityTeamInfoVo"/>
|
||||
<where>
|
||||
t.deleted = 0
|
||||
<if test="ew != null and ew.sqlSegment != null and ew.sqlSegment != ''">
|
||||
and (${ew.sqlSegment})
|
||||
</if>
|
||||
</where>
|
||||
order by t.create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 根据活动ID查询团队列表 -->
|
||||
<select id="selectVoListByActivityId" parameterType="Long" resultMap="StglActivityTeamInfoResult">
|
||||
<include refid="selectStglActivityTeamInfoVo"/>
|
||||
<where>
|
||||
t.deleted = 0
|
||||
and t.activity_id = #{activityId}
|
||||
</where>
|
||||
order by t.create_time desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,242 @@
|
||||
<?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="org.dromara.stgl.mapper.StglClassMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.vo.StglClassVo" id="StglClassResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="studentNo" column="student_no"/>
|
||||
<result property="studentName" column="name"/>
|
||||
<result property="gender" column="gender"/>
|
||||
<result property="phone" column="phone"/>
|
||||
<result property="className" column="class_name"/>
|
||||
<result property="clubCount" column="club_count"/>
|
||||
<result property="volunteerTeamCount" column="volunteer_team_count"/>
|
||||
<result property="activityCount" column="activity_count"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="version" column="version"/>
|
||||
<result property="deleted" column="deleted"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 查询班主任的班级列表 -->
|
||||
<select id="selectTeacherClasses" parameterType="Long" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
c.id,
|
||||
c.class_name as className,
|
||||
c.college_name as collegeName,
|
||||
c.major_name as majorName,
|
||||
c.grade
|
||||
FROM xg_class_msg c
|
||||
INNER JOIN xg_class_teacher_counselor_rel tcr ON c.id = tcr.class_id
|
||||
WHERE tcr.teacher_id = #{userId}
|
||||
AND c.deleted = 0
|
||||
AND tcr.deleted = 0
|
||||
AND tcr.teacher_type = 'class_teacher'
|
||||
AND (tcr.end_date IS NULL OR tcr.end_date > NOW())
|
||||
ORDER BY c.grade DESC, c.class_name ASC
|
||||
</select>
|
||||
|
||||
<!-- 查询班级学生列表(包含社团、志愿者队伍、活动统计) -->
|
||||
<select id="selectClassStudents" parameterType="java.util.Map" resultMap="StglClassResult">
|
||||
SELECT
|
||||
s.id,
|
||||
s.student_no,
|
||||
s.name,
|
||||
s.gender,
|
||||
s.phone,
|
||||
c.class_name,
|
||||
COALESCE(club_stats.club_count, 0) as club_count,
|
||||
COALESCE(volunteer_stats.volunteer_team_count, 0) as volunteer_team_count,
|
||||
COALESCE(activity_stats.activity_count, 0) as activity_count,
|
||||
s.create_by,
|
||||
s.create_time,
|
||||
s.update_by,
|
||||
s.update_time,
|
||||
s.tenant_id,
|
||||
s.version,
|
||||
s.deleted
|
||||
FROM xg_student_msg s
|
||||
LEFT JOIN xg_class_msg c ON s.class_id = c.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
m.user_id,
|
||||
COUNT(DISTINCT m.relation_id) as club_count
|
||||
FROM stgl_member m
|
||||
WHERE m.member_type = 1
|
||||
AND m.deleted = 0
|
||||
AND m.status = 1
|
||||
GROUP BY m.user_id
|
||||
) club_stats ON s.id = club_stats.user_id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
m.user_id,
|
||||
COUNT(DISTINCT m.relation_id) as volunteer_team_count
|
||||
FROM stgl_member m
|
||||
WHERE m.member_type = 2
|
||||
AND m.deleted = 0
|
||||
AND m.status = 1
|
||||
GROUP BY m.user_id
|
||||
) volunteer_stats ON s.id = volunteer_stats.user_id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
ar.user_id,
|
||||
COUNT(DISTINCT ar.activity_id) as activity_count
|
||||
FROM stgl_activity_registration ar
|
||||
WHERE ar.deleted = 0
|
||||
AND ar.approval_status = 1
|
||||
GROUP BY ar.user_id
|
||||
) activity_stats ON s.id = activity_stats.user_id
|
||||
<where>
|
||||
s.deleted = 0
|
||||
AND s.student_status = '1'
|
||||
<if test="classId != null and classId != ''">
|
||||
AND s.class_id = #{classId}
|
||||
</if>
|
||||
<if test="studentName != null and studentName != ''">
|
||||
AND s.name LIKE CONCAT('%', #{studentName}, '%')
|
||||
</if>
|
||||
<if test="studentNo != null and studentNo != ''">
|
||||
AND s.student_no LIKE CONCAT('%', #{studentNo}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY s.student_no ASC
|
||||
<if test="offset != null and pageSize != null">
|
||||
LIMIT #{pageSize} OFFSET #{offset}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 查询班级学生总数 -->
|
||||
<select id="selectClassStudentsCount" parameterType="java.util.Map" resultType="java.lang.Integer">
|
||||
SELECT COUNT(*)
|
||||
FROM xg_student_msg s
|
||||
<where>
|
||||
s.deleted = 0
|
||||
AND s.student_status = '1'
|
||||
<if test="classId != null and classId != ''">
|
||||
AND s.class_id = #{classId}
|
||||
</if>
|
||||
<if test="studentName != null and studentName != ''">
|
||||
AND s.name LIKE CONCAT('%', #{studentName}, '%')
|
||||
</if>
|
||||
<if test="studentNo != null and studentNo != ''">
|
||||
AND s.student_no LIKE CONCAT('%', #{studentNo}, '%')
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<!-- 查询学生社团详情 -->
|
||||
<select id="selectStudentClubs" parameterType="Long" resultType="java.util.Map">
|
||||
SELECT
|
||||
c.id,
|
||||
c.club_name as clubName,
|
||||
c.club_type as clubType,
|
||||
DATE_FORMAT(c.establish_date, '%Y-%m-%d') as establishDate,
|
||||
c.member_limit as memberLimit,
|
||||
c.president_name as presidentName,
|
||||
c.president_phone as presidentPhone,
|
||||
c.president_dept as presidentDept,
|
||||
c.president_major as presidentMajor,
|
||||
c.president_class as presidentClass,
|
||||
c.advisor_name as advisorName,
|
||||
c.advisor_dept as advisorDept,
|
||||
c.advisor_phone as advisorPhone
|
||||
FROM stgl_club c
|
||||
INNER JOIN stgl_member m ON c.id = m.relation_id
|
||||
WHERE m.user_id = #{studentId}
|
||||
AND m.member_type = 1
|
||||
AND m.deleted = 0
|
||||
AND m.status = 1
|
||||
AND c.deleted = 0
|
||||
AND c.status = 1
|
||||
ORDER BY c.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询学生志愿者队伍详情 -->
|
||||
<select id="selectStudentVolunteerTeams" parameterType="Long" resultType="java.util.Map">
|
||||
SELECT
|
||||
vt.id,
|
||||
vt.team_name as teamName,
|
||||
DATE_FORMAT(vt.establish_date, '%Y-%m-%d') as establishDate,
|
||||
vt.leader_name as leaderName,
|
||||
vt.leader_phone as leaderPhone,
|
||||
vt.leader_dept as leaderDept,
|
||||
vt.leader_major as leaderMajor,
|
||||
vt.leader_class as leaderClass,
|
||||
vt.advisor_name as advisorName,
|
||||
vt.advisor_dept as advisorDept,
|
||||
vt.advisor_phone as advisorPhone
|
||||
FROM stgl_volunteer_team vt
|
||||
INNER JOIN stgl_member m ON vt.id = m.relation_id
|
||||
WHERE m.user_id = #{studentId}
|
||||
AND m.member_type = 2
|
||||
AND m.deleted = 0
|
||||
AND m.status = 1
|
||||
AND vt.deleted = 0
|
||||
AND vt.status = 1
|
||||
ORDER BY vt.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询学生活动详情 -->
|
||||
<select id="selectStudentActivities" parameterType="Long" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
a.id,
|
||||
a.activity_name as activityName,
|
||||
a.activity_type as activityType,
|
||||
a.activity_theme as activityTheme,
|
||||
a.location,
|
||||
CONCAT(
|
||||
DATE_FORMAT(a.start_time, '%Y-%m-%d %H:%i'),
|
||||
' 至 ',
|
||||
DATE_FORMAT(a.end_time, '%Y-%m-%d %H:%i')
|
||||
) as activityTime,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.club_name
|
||||
WHEN a.related_type = 2 THEN vt.team_name
|
||||
ELSE '无'
|
||||
END as relatedOrganization,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.advisor_name
|
||||
WHEN a.related_type = 2 THEN vt.advisor_name
|
||||
ELSE '无'
|
||||
END as advisorName,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.advisor_dept
|
||||
WHEN a.related_type = 2 THEN vt.advisor_dept
|
||||
ELSE '无'
|
||||
END as advisorDept,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.advisor_phone
|
||||
WHEN a.related_type = 2 THEN vt.advisor_phone
|
||||
ELSE '无'
|
||||
END as advisorPhone
|
||||
FROM stgl_activity a
|
||||
LEFT JOIN stgl_club c ON a.related_club_id = c.id AND a.related_type = 1
|
||||
LEFT JOIN stgl_volunteer_team vt ON a.related_club_id = vt.id AND a.related_type = 2
|
||||
WHERE a.deleted = 0
|
||||
AND (
|
||||
-- 个人报名
|
||||
EXISTS (
|
||||
SELECT 1 FROM stgl_activity_registration ar
|
||||
WHERE ar.activity_id = a.id
|
||||
AND ar.user_id = #{studentId}
|
||||
AND ar.deleted = 0
|
||||
AND ar.approval_status = 1
|
||||
)
|
||||
OR
|
||||
-- 团队报名(通过团队信息中的成员)
|
||||
EXISTS (
|
||||
SELECT 1 FROM stgl_activity_team_info ati
|
||||
WHERE ati.activity_id = a.id
|
||||
AND ati.deleted = 0
|
||||
AND JSON_CONTAINS(ati.team_members, JSON_OBJECT('userId', CAST(#{studentId} AS CHAR)), '$[*]')
|
||||
)
|
||||
)
|
||||
ORDER BY a.start_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,33 @@
|
||||
-- 班主任查看本班学生社团、志愿者队伍、活动参加情况权限配置
|
||||
-- 执行时间:2025-01-15
|
||||
|
||||
-- 1. 添加菜单权限
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (2000001, '班级学生参与情况', 2000, 1, 'stclass', 'stgl/stclass/index', NULL, 1, 0, 'C', '0', '0', 'stgl:stclass:list', 'education', 103, 1, NOW(), 1, NOW(), '班主任查看本班学生社团、志愿者队伍、活动参加情况');
|
||||
|
||||
-- 2. 添加按钮权限
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (2000002, '班级学生参与情况查询', 2000001, 1, '', '', NULL, 1, 0, 'F', '0', '0', 'stgl:stclass:query', '#', 103, 1, NOW(), 1, NOW(), '班级学生参与情况查询');
|
||||
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query_param, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES (2000003, '班级学生参与情况导出', 2000001, 2, '', '', NULL, 1, 0, 'F', '0', '0', 'stgl:stclass:export', '#', 103, 1, NOW(), 1, NOW(), '班级学生参与情况导出');
|
||||
|
||||
-- 3. 为班主任角色(head_teacher)分配权限
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1947639680473493505, 2000001);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1947639680473493505, 2000002);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1947639680473493505, 2000003);
|
||||
|
||||
-- 4. 为管理员角色分配权限
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 2000001);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 2000002);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (1, 2000003);
|
||||
|
||||
-- 5. 为超级管理员角色分配权限
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 2000001);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 2000002);
|
||||
INSERT INTO sys_role_menu (role_id, menu_id) VALUES (2, 2000003);
|
||||
|
||||
-- 权限字符说明:
|
||||
-- stgl:stclass:list - 班级学生参与情况列表查询权限
|
||||
-- stgl:stclass:query - 班级学生参与情况详情查询权限
|
||||
-- stgl:stclass:export - 班级学生参与情况导出权限
|
||||
@@ -545,7 +545,7 @@ CREATE TABLE `stgl_activity_rating` (
|
||||
`user_id` bigint(20) NOT NULL COMMENT '评分人ID',
|
||||
`student_no` varchar(20) COMMENT '学号',
|
||||
`student_name` varchar(50) COMMENT '学生姓名',
|
||||
`rating_score` tinyint NOT NULL COMMENT '评分(1-5分)',
|
||||
`rating_score` decimal(3,1) NOT NULL COMMENT '综合评分(1-5分,保留1位小数)',
|
||||
`rating_comment` varchar(500) COMMENT '评分备注',
|
||||
`rating_time` datetime COMMENT '评分时间',
|
||||
|
||||
@@ -566,8 +566,9 @@ CREATE TABLE `stgl_activity_rating` (
|
||||
```
|
||||
|
||||
#### 字段说明
|
||||
- `rating_score`: 总评分,1-5分,不支持0.5分
|
||||
- 扩展评分维度为预留字段,后续可扩展使用
|
||||
- `rating_score`: 综合评分,1-5分,保留1位小数,由三项分评分平均值计算得出
|
||||
- `content_score`、`organization_score`、`experience_score`: 三项分评分维度(内容、组织、体验),1-5分整数
|
||||
- 综合评分计算公式:`rating_score = ROUND((content_score + organization_score + experience_score) / 3, 1)`
|
||||
|
||||
## 3. 码表数据设计
|
||||
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
|
||||
- `activity_id` bigint(20) COMMENT '活动ID'
|
||||
- `user_id` bigint(20) COMMENT '评分人ID'
|
||||
- `rating_score` tinyint COMMENT '评分(1-5分)'
|
||||
- `rating_score` decimal(3,1) COMMENT '综合评分(1-5分,保留1位小数)'
|
||||
- `rating_comment` varchar(500) COMMENT '评分备注'
|
||||
- `rating_time` datetime COMMENT '评分时间'
|
||||
|
||||
|
||||
@@ -582,6 +582,16 @@ export interface ActivityCopyParams {
|
||||
* 新活动名称
|
||||
*/
|
||||
newActivityName: string;
|
||||
|
||||
/**
|
||||
* 新活动状态(复制后默认为草稿状态)
|
||||
*/
|
||||
activityStatus?: string;
|
||||
|
||||
/**
|
||||
* 新活动报名状态(复制后默认为未开始状态)
|
||||
*/
|
||||
registrationStatus?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,10 +649,50 @@ export interface ActivityRatingVO {
|
||||
userName?: string;
|
||||
|
||||
/**
|
||||
* 评分(1-5分)
|
||||
* 评分人学号
|
||||
*/
|
||||
studentNo?: string;
|
||||
|
||||
/**
|
||||
* 评分人联系方式
|
||||
*/
|
||||
phoneNumber?: string;
|
||||
|
||||
/**
|
||||
* 评分人院系
|
||||
*/
|
||||
deptName?: string;
|
||||
|
||||
/**
|
||||
* 评分人专业
|
||||
*/
|
||||
majorName?: string;
|
||||
|
||||
/**
|
||||
* 评分人班级
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 总评分(1-5分)
|
||||
*/
|
||||
ratingScore: number;
|
||||
|
||||
/**
|
||||
* 内容评分(1-5分)
|
||||
*/
|
||||
contentScore?: number;
|
||||
|
||||
/**
|
||||
* 组织评分(1-5分)
|
||||
*/
|
||||
organizationScore?: number;
|
||||
|
||||
/**
|
||||
* 体验评分(1-5分)
|
||||
*/
|
||||
experienceScore?: number;
|
||||
|
||||
/**
|
||||
* 评分备注
|
||||
*/
|
||||
|
||||
@@ -369,6 +369,11 @@ export interface StglActivityRegistrationForm {
|
||||
* 班级
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 审核状态(0-待审核 1-通过 2-驳回)
|
||||
*/
|
||||
approvalStatus?: number;
|
||||
}
|
||||
|
||||
// 团队成员信息
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import request from '@/utils/request';
|
||||
import { StglActivityTeamInfoVo } from './types';
|
||||
|
||||
// 查询活动团队信息列表
|
||||
export function listActivityTeamInfo(query?: any) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 查询活动团队信息详细
|
||||
export function getActivityTeamInfo(id: string | number) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增活动团队信息
|
||||
export function addActivityTeamInfo(data: any) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改活动团队信息
|
||||
export function updateActivityTeamInfo(data: any) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除活动团队信息
|
||||
export function delActivityTeamInfo(ids: string | number | Array<string | number>) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo/' + ids,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 导出活动团队信息
|
||||
export function exportActivityTeamInfo(query?: any) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo/export',
|
||||
method: 'post',
|
||||
data: query
|
||||
});
|
||||
}
|
||||
|
||||
// 根据活动ID查询团队列表
|
||||
export function getTeamsByActivityId(activityId: string | number) {
|
||||
return request({
|
||||
url: '/stgl/activityteaminfo/activity/' + activityId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
// 团队成员信息
|
||||
export interface TeamMemberInfo {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
userId: string | number;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
studentNo: string;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
studentName: string;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
gender?: string;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
phone?: string;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email?: string;
|
||||
|
||||
/**
|
||||
* 院系
|
||||
*/
|
||||
department?: string;
|
||||
|
||||
/**
|
||||
* 专业
|
||||
*/
|
||||
major?: string;
|
||||
|
||||
/**
|
||||
* 班级
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 是否为队长(0-否 1-是)
|
||||
*/
|
||||
isLeader?: number;
|
||||
}
|
||||
|
||||
// 活动团队信息表单对象
|
||||
export interface StglActivityTeamInfoForm {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 团队名称
|
||||
*/
|
||||
teamName: string;
|
||||
|
||||
/**
|
||||
* 关联活动ID
|
||||
*/
|
||||
activityId: string | number;
|
||||
|
||||
/**
|
||||
* 队长用户ID
|
||||
*/
|
||||
leaderUserId: string | number;
|
||||
|
||||
/**
|
||||
* 队长姓名
|
||||
*/
|
||||
leaderName: string;
|
||||
|
||||
/**
|
||||
* 队长学号
|
||||
*/
|
||||
leaderStudentNo: string;
|
||||
|
||||
/**
|
||||
* 团队成员信息(JSON格式)
|
||||
*/
|
||||
teamMembers?: string;
|
||||
|
||||
/**
|
||||
* 团队人数
|
||||
*/
|
||||
teamSize?: number;
|
||||
|
||||
/**
|
||||
* 团队简介
|
||||
*/
|
||||
description?: string;
|
||||
}
|
||||
|
||||
// 活动团队信息查询对象
|
||||
export interface StglActivityTeamInfoQuery {
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
pageNum?: number;
|
||||
|
||||
/**
|
||||
* 每页数量
|
||||
*/
|
||||
pageSize?: number;
|
||||
|
||||
/**
|
||||
* 团队名称
|
||||
*/
|
||||
teamName?: string;
|
||||
|
||||
/**
|
||||
* 关联活动ID
|
||||
*/
|
||||
activityId?: string | number;
|
||||
|
||||
/**
|
||||
* 队长用户ID
|
||||
*/
|
||||
leaderUserId?: string | number;
|
||||
|
||||
/**
|
||||
* 队长姓名
|
||||
*/
|
||||
leaderName?: string;
|
||||
|
||||
/**
|
||||
* 队长学号
|
||||
*/
|
||||
leaderStudentNo?: string;
|
||||
}
|
||||
|
||||
// 活动团队信息视图对象
|
||||
export interface StglActivityTeamInfoVo {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 团队名称
|
||||
*/
|
||||
teamName: string;
|
||||
|
||||
/**
|
||||
* 关联活动ID
|
||||
*/
|
||||
activityId: string | number;
|
||||
|
||||
/**
|
||||
* 队长用户ID
|
||||
*/
|
||||
leaderUserId: string | number;
|
||||
|
||||
/**
|
||||
* 队长姓名
|
||||
*/
|
||||
leaderName: string;
|
||||
|
||||
/**
|
||||
* 队长学号
|
||||
*/
|
||||
leaderStudentNo: string;
|
||||
|
||||
/**
|
||||
* 团队成员信息(JSON格式)
|
||||
*/
|
||||
teamMembers?: string;
|
||||
|
||||
/**
|
||||
* 团队人数
|
||||
*/
|
||||
teamSize?: number;
|
||||
|
||||
/**
|
||||
* 团队简介
|
||||
*/
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* 队长性别
|
||||
*/
|
||||
leaderGender?: string;
|
||||
|
||||
/**
|
||||
* 队长联系电话
|
||||
*/
|
||||
leaderPhone?: string;
|
||||
|
||||
/**
|
||||
* 队长邮箱
|
||||
*/
|
||||
leaderEmail?: string;
|
||||
|
||||
/**
|
||||
* 队长院系
|
||||
*/
|
||||
leaderDepartment?: string;
|
||||
|
||||
/**
|
||||
* 队长专业
|
||||
*/
|
||||
leaderMajor?: string;
|
||||
|
||||
/**
|
||||
* 队长班级
|
||||
*/
|
||||
leaderClassName?: string;
|
||||
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
activityName?: string;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
createBy?: string | number;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
updateBy?: string | number;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
}
|
||||
@@ -93,12 +93,14 @@ export interface MyActivityVO {
|
||||
location?: string;
|
||||
/** 主办方名称 */
|
||||
organizerName?: string;
|
||||
/** 承办方名称 */
|
||||
undertakerName?: string;
|
||||
/** 关联类型(1-社团 2-志愿者队伍) */
|
||||
relatedType?: number;
|
||||
/** 关联组织名称(社团名称或志愿者团队名称) */
|
||||
organizationName?: string;
|
||||
/** 指导老师 */
|
||||
instructors?: string;
|
||||
instructors?: string | any[];
|
||||
/** 活动状态 */
|
||||
activityStatus: string;
|
||||
/** 报名状态 */
|
||||
@@ -111,6 +113,8 @@ export interface MyActivityVO {
|
||||
myRegistrationTime: string;
|
||||
/** 我的报名状态 */
|
||||
myRegistrationStatus: string;
|
||||
/** 报名类型(1-个人 2-团队) */
|
||||
registrationType: string;
|
||||
/** 我的评分状态(0-未评分 1-已评分) */
|
||||
myRatingStatus: number;
|
||||
/** 我的综合评分 */
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import request from '@/utils/request';
|
||||
import { StglClassQuery, StglClassVO, StglClassDetailVO } from './types';
|
||||
|
||||
/**
|
||||
* 查询班主任的班级列表
|
||||
*/
|
||||
export function getTeacherClasses() {
|
||||
return request({
|
||||
url: '/stgl/stclass/teacher/classes',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询本班学生社团、志愿者队伍、活动参加情况列表
|
||||
*/
|
||||
export function listStglClass(query: StglClassQuery) {
|
||||
return request({
|
||||
url: '/stgl/stclass/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生社团详情
|
||||
*/
|
||||
export function getStudentClubs(studentId: string | number) {
|
||||
return request({
|
||||
url: `/stgl/stclass/student/clubs/${studentId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生志愿者队伍详情
|
||||
*/
|
||||
export function getStudentVolunteerTeams(studentId: string | number) {
|
||||
return request({
|
||||
url: `/stgl/stclass/student/volunteer-teams/${studentId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生活动参加详情
|
||||
*/
|
||||
export function getStudentActivities(studentId: string | number) {
|
||||
return request({
|
||||
url: `/stgl/stclass/student/activities/${studentId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出本班学生社团、志愿者队伍、活动参加情况
|
||||
*/
|
||||
export function exportStglClass(query: StglClassQuery) {
|
||||
return request({
|
||||
url: '/stgl/stclass/export',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
* 分页查询基础接口
|
||||
*/
|
||||
export interface PageQuery {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况查询对象
|
||||
*/
|
||||
export interface StglClassQuery extends PageQuery {
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
classId?: string | number;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
studentName?: string;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
studentNo?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 班级学生社团、志愿者队伍、活动参加情况视图对象
|
||||
*/
|
||||
export interface StglClassVO {
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
studentNo: string;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
studentName: string;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
gender: string;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
phone: string;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
className: string;
|
||||
|
||||
/**
|
||||
* 加入社团数量
|
||||
*/
|
||||
clubCount: number;
|
||||
|
||||
/**
|
||||
* 加入志愿者队伍数量
|
||||
*/
|
||||
volunteerTeamCount: number;
|
||||
|
||||
/**
|
||||
* 参与活动数量
|
||||
*/
|
||||
activityCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 社团详情对象
|
||||
*/
|
||||
export interface ClubDetailVO {
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
clubName: string;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
clubType: string;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
establishDate: string;
|
||||
|
||||
/**
|
||||
* 成员规模
|
||||
*/
|
||||
memberLimit: number;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
presidentName: string;
|
||||
|
||||
/**
|
||||
* 社长联系方式
|
||||
*/
|
||||
presidentPhone: string;
|
||||
|
||||
/**
|
||||
* 社长院系
|
||||
*/
|
||||
presidentDept: string;
|
||||
|
||||
/**
|
||||
* 社长专业
|
||||
*/
|
||||
presidentMajor: string;
|
||||
|
||||
/**
|
||||
* 社长班级
|
||||
*/
|
||||
presidentClass: string;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
advisorName: string;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
advisorDept: string;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
advisorPhone: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 志愿者队伍详情对象
|
||||
*/
|
||||
export interface VolunteerTeamDetailVO {
|
||||
/**
|
||||
* 队伍ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 队伍名称
|
||||
*/
|
||||
teamName: string;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
establishDate: string;
|
||||
|
||||
/**
|
||||
* 队长姓名
|
||||
*/
|
||||
leaderName: string;
|
||||
|
||||
/**
|
||||
* 队长联系方式
|
||||
*/
|
||||
leaderPhone: string;
|
||||
|
||||
/**
|
||||
* 队长院系
|
||||
*/
|
||||
leaderDept: string;
|
||||
|
||||
/**
|
||||
* 队长专业
|
||||
*/
|
||||
leaderMajor: string;
|
||||
|
||||
/**
|
||||
* 队长班级
|
||||
*/
|
||||
leaderClass: string;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
advisorName: string;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
advisorDept: string;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
advisorPhone: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动详情对象
|
||||
*/
|
||||
export interface ActivityDetailVO {
|
||||
/**
|
||||
* 活动ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
activityName: string;
|
||||
|
||||
/**
|
||||
* 活动类型
|
||||
*/
|
||||
activityType: string;
|
||||
|
||||
/**
|
||||
* 活动主题
|
||||
*/
|
||||
activityTheme: string;
|
||||
|
||||
/**
|
||||
* 活动地点
|
||||
*/
|
||||
location: string;
|
||||
|
||||
/**
|
||||
* 活动时间
|
||||
*/
|
||||
activityTime: string;
|
||||
|
||||
/**
|
||||
* 关联社团/队伍
|
||||
*/
|
||||
relatedOrganization: string;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
advisorName: string;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
advisorDept: string;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
advisorPhone: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 班级详情对象
|
||||
*/
|
||||
export interface StglClassDetailVO {
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
className: string;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
collegeName: string;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
majorName: string;
|
||||
|
||||
/**
|
||||
* 年级
|
||||
*/
|
||||
grade: string;
|
||||
}
|
||||
@@ -15,7 +15,11 @@
|
||||
<el-row :gutter="2" align="middle">
|
||||
<el-col :span="5">
|
||||
<el-form-item label="姓名" :prop="`advisors.${index}.name`">
|
||||
<TeacherSelector v-model="advisor.teacher" placeholder="选择指导老师" />
|
||||
<TeacherSelector
|
||||
:model-value="advisor.teacher"
|
||||
placeholder="选择指导老师"
|
||||
@update:model-value="(teacher) => handleTeacherChange(advisor, teacher)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
@@ -48,7 +52,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, nextTick, computed } from 'vue';
|
||||
import { ref, watch, computed } from 'vue';
|
||||
import { Plus, Delete } from '@element-plus/icons-vue';
|
||||
import TeacherSelector from '@/components/TeacherSelector/index.vue';
|
||||
import { TeacherVO } from '@/api/system/teacher/types';
|
||||
@@ -59,6 +63,7 @@ export interface AdvisorVO {
|
||||
phone: string;
|
||||
dept: string;
|
||||
email: string;
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
@@ -73,131 +78,74 @@ interface Emits {
|
||||
const props = defineProps<Props>();
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const advisors = ref<AdvisorVO[]>([]);
|
||||
const updateLock = ref(false);
|
||||
const advisors = ref<AdvisorVO[]>([...props.modelValue]);
|
||||
|
||||
// 计算属性:生成当前数据的hash值,用于检测变化
|
||||
const currentHash = computed(() => {
|
||||
return JSON.stringify(
|
||||
advisors.value.map((advisor) => ({
|
||||
userId: advisor.teacher?.userId,
|
||||
name: advisor.name,
|
||||
phone: advisor.phone,
|
||||
dept: advisor.dept,
|
||||
email: advisor.email
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
// 监听外部值变化
|
||||
// 监听props变化
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
console.log('AdvisorManager - 外部值变化:', newValue);
|
||||
if (!updateLock.value) {
|
||||
updateLock.value = true;
|
||||
nextTick(() => {
|
||||
// 确保深拷贝,避免引用问题
|
||||
advisors.value = newValue ? newValue.map((item) => ({ ...item })) : [];
|
||||
console.log('AdvisorManager - 更新内部值:', advisors.value);
|
||||
updateLock.value = false;
|
||||
});
|
||||
}
|
||||
advisors.value = newValue ? newValue.map((item) => ({ ...item })) : [];
|
||||
},
|
||||
{ immediate: true, deep: false }
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 监听内部值变化 - 使用hash比较避免深度比较
|
||||
watch(currentHash, (newHash, oldHash) => {
|
||||
// 避免初始化时的重复触发
|
||||
if (oldHash === undefined) return;
|
||||
|
||||
console.log('AdvisorManager - 内部值变化检测到:', newHash);
|
||||
if (!updateLock.value) {
|
||||
updateLock.value = true;
|
||||
// 延迟emit,避免在TabPane环境下的立即更新冲突
|
||||
nextTick(() => {
|
||||
const newValue = advisors.value.map((advisor) => ({ ...advisor }));
|
||||
console.log('AdvisorManager - 发送更新事件:', newValue);
|
||||
emit('update:modelValue', newValue);
|
||||
// 重新添加change事件,但添加防护机制
|
||||
emit('change', newValue);
|
||||
updateLock.value = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
// 监听内部数据变化,同步到父组件
|
||||
watch(
|
||||
advisors,
|
||||
(newValue) => {
|
||||
emit('update:modelValue', newValue);
|
||||
emit('change', newValue);
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
// 添加指导老师
|
||||
const addAdvisor = () => {
|
||||
// 使用函数式更新,确保响应性
|
||||
advisors.value = [
|
||||
...advisors.value,
|
||||
{
|
||||
teacher: null,
|
||||
name: '',
|
||||
phone: '',
|
||||
dept: '',
|
||||
email: ''
|
||||
}
|
||||
];
|
||||
advisors.value.push({
|
||||
teacher: null,
|
||||
name: '',
|
||||
phone: '',
|
||||
dept: '',
|
||||
email: '',
|
||||
userId: ''
|
||||
});
|
||||
};
|
||||
|
||||
// 删除指导老师
|
||||
const removeAdvisor = (index: number) => {
|
||||
// 使用函数式更新,确保响应性
|
||||
advisors.value = advisors.value.filter((_, i) => i !== index);
|
||||
advisors.value.splice(index, 1);
|
||||
};
|
||||
|
||||
// 监听teacher选择变化,自动填充相关信息
|
||||
watch(
|
||||
() => advisors.value.map((advisor) => advisor.teacher),
|
||||
(newTeachers, oldTeachers) => {
|
||||
console.log('AdvisorManager - teacher选择变化监听器触发');
|
||||
console.log('newTeachers:', newTeachers);
|
||||
console.log('oldTeachers:', oldTeachers);
|
||||
|
||||
newTeachers.forEach((teacher, index) => {
|
||||
const oldTeacher = oldTeachers?.[index];
|
||||
|
||||
console.log(`检查第${index}个指导老师:`, {
|
||||
newTeacher: teacher,
|
||||
oldTeacher: oldTeacher,
|
||||
hasChanged: teacher && (!oldTeacher || teacher.userId !== oldTeacher?.userId)
|
||||
});
|
||||
|
||||
// 检查是否是新选择的老师或者老师发生了变化
|
||||
if (teacher && (!oldTeacher || teacher.userId !== oldTeacher.userId)) {
|
||||
console.log('选择了新的指导老师:', teacher);
|
||||
const advisor = advisors.value[index];
|
||||
if (advisor) {
|
||||
// 自动填充老师信息
|
||||
advisor.name = teacher.nickName || '';
|
||||
advisor.phone = teacher.phonenumber || '';
|
||||
advisor.dept = teacher.deptName || '';
|
||||
advisor.email = teacher.email || '';
|
||||
|
||||
console.log('自动填充的信息:', {
|
||||
name: advisor.name,
|
||||
phone: advisor.phone,
|
||||
dept: advisor.dept,
|
||||
email: advisor.email
|
||||
});
|
||||
}
|
||||
} else if (!teacher && oldTeacher) {
|
||||
// 清空选择时重置所有信息
|
||||
console.log('清空指导老师选择');
|
||||
const advisor = advisors.value[index];
|
||||
if (advisor) {
|
||||
advisor.name = '';
|
||||
advisor.phone = '';
|
||||
advisor.dept = '';
|
||||
advisor.email = '';
|
||||
}
|
||||
}
|
||||
const handleTeacherChange = (advisor: AdvisorVO, teacher: TeacherVO | null) => {
|
||||
console.log('handleTeacherChange called with teacher:', teacher);
|
||||
|
||||
if (teacher) {
|
||||
// 自动填充老师信息
|
||||
advisor.name = teacher.nickName || '';
|
||||
advisor.phone = teacher.phonenumber || '暂无电话';
|
||||
advisor.dept = teacher.deptName || '';
|
||||
advisor.email = teacher.email || '暂无邮箱';
|
||||
advisor.userId = teacher.userId?.toString() || '';
|
||||
|
||||
console.log('Updated advisor:', {
|
||||
name: advisor.name,
|
||||
phone: advisor.phone,
|
||||
dept: advisor.dept,
|
||||
email: advisor.email,
|
||||
userId: advisor.userId
|
||||
});
|
||||
},
|
||||
{ deep: true, immediate: false }
|
||||
);
|
||||
} else {
|
||||
// 清空选择时重置所有信息
|
||||
advisor.name = '';
|
||||
advisor.phone = '';
|
||||
advisor.dept = '';
|
||||
advisor.email = '';
|
||||
advisor.userId = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 移除有问题的深度监听,改为在TeacherSelector的change事件中处理
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="detail-item">
|
||||
<label class="detail-label">关联社团</label>
|
||||
<label class="detail-label">关联社团/队伍</label>
|
||||
<div class="detail-value">{{ activity.relatedClubName || '暂无' }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -203,7 +203,10 @@
|
||||
<div class="detail-item">
|
||||
<label class="detail-label">是否需要审核</label>
|
||||
<div class="detail-value">
|
||||
<dict-tag :options="sys_yes_no" :value="activity.needApproval" />
|
||||
<!-- 临时解决方案:直接显示中文文本 -->
|
||||
<el-tag v-if="activity.needApproval === 1" type="warning" size="small">需要审核</el-tag>
|
||||
<el-tag v-else-if="activity.needApproval === 0" type="success" size="small">无需审核</el-tag>
|
||||
<span v-else class="text-gray-400">{{ activity.needApproval }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@@ -339,25 +342,6 @@
|
||||
<!-- 活动评分标签页 -->
|
||||
<el-tab-pane label="活动评分" name="rating" v-if="activity.id">
|
||||
<ActivityRatingView :activity-id="activity.id" />
|
||||
|
||||
<!-- 统计信息区域(只在活动评分标签页显示) -->
|
||||
<div class="statistics-section">
|
||||
<el-divider content-position="left">统计信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-statistic title="报名人数" :value="activity.registrationCount || 0" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-statistic title="平均评分" :value="activity.averageRating || 0" :precision="1" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="statistic-item">
|
||||
<div class="statistic-title">创建时间</div>
|
||||
<div class="statistic-value">{{ activity.createTime || '暂无' }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@@ -366,12 +350,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, onMounted, watch } from 'vue';
|
||||
import { StglActivityVO, CoOrganizerInfo, InstructorInfo } from '@/api/stgl/activity/types';
|
||||
import { StglActivityVo } from '@/api/stgl/activityregisterhall/types';
|
||||
import ActivityRatingView from './ActivityRatingView.vue';
|
||||
import ActivityRegistrationView from './ActivityRegistrationView.vue';
|
||||
import { listByIds } from '@/api/system/oss';
|
||||
|
||||
interface Props {
|
||||
activity: StglActivityVO;
|
||||
activity: StglActivityVO | StglActivityVo;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
@@ -381,6 +366,8 @@ const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_r
|
||||
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'sys_yes_no')
|
||||
);
|
||||
|
||||
|
||||
|
||||
// 当前激活的Tab页签
|
||||
const activeTab = ref('basic');
|
||||
|
||||
@@ -414,8 +401,8 @@ const loadAttachments = async () => {
|
||||
summaryAttachmentList.value = [];
|
||||
achievementsAttachmentList.value = [];
|
||||
|
||||
// 加载总结报告附件
|
||||
if (props.activity.summaryAttachments) {
|
||||
// 加载活动总结附件
|
||||
if (props.activity && 'summaryAttachments' in props.activity && props.activity.summaryAttachments) {
|
||||
// 检查数据格式:如果以 [ 开头,说明是JSON格式;否则是ossId格式
|
||||
const attachmentStr = String(props.activity.summaryAttachments);
|
||||
if (attachmentStr.trim().startsWith('[')) {
|
||||
@@ -423,7 +410,7 @@ const loadAttachments = async () => {
|
||||
// JSON格式:直接解析
|
||||
summaryAttachmentList.value = JSON.parse(attachmentStr);
|
||||
} catch (error) {
|
||||
console.error('总结报告附件JSON解析失败:', error);
|
||||
console.error('活动总结附件JSON解析失败:', error);
|
||||
summaryAttachmentList.value = [];
|
||||
}
|
||||
} else {
|
||||
@@ -438,7 +425,7 @@ const loadAttachments = async () => {
|
||||
ossId: oss.ossId
|
||||
}));
|
||||
} catch (apiError) {
|
||||
console.error('获取总结报告附件信息失败:', apiError);
|
||||
console.error('获取活动总结附件信息失败:', apiError);
|
||||
summaryAttachmentList.value = [];
|
||||
}
|
||||
}
|
||||
@@ -446,7 +433,7 @@ const loadAttachments = async () => {
|
||||
}
|
||||
|
||||
// 加载活动成果附件
|
||||
if (props.activity.achievementsAttachments) {
|
||||
if (props.activity && 'achievementsAttachments' in props.activity && props.activity.achievementsAttachments) {
|
||||
// 检查数据格式:如果以 [ 开头,说明是JSON格式;否则是ossId格式
|
||||
const attachmentStr = String(props.activity.achievementsAttachments);
|
||||
if (attachmentStr.trim().startsWith('[')) {
|
||||
@@ -622,26 +609,7 @@ onMounted(() => {
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.statistics-section {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.statistic-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.statistic-title {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.statistic-value {
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* 附件显示区域样式 */
|
||||
.attachment-list {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-dialog :title="`${activityName}活动报名管理`" :model-value="visible" @update:model-value="handleVisibleChange" width="1400px" append-to-body>
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tabs v-model="activeTab" type="border-card" @tab-change="handleTabChange">
|
||||
<!-- 已报名标签页 -->
|
||||
<el-tab-pane label="已报名" name="registered">
|
||||
<RegisteredMembersTab
|
||||
@@ -16,6 +16,7 @@
|
||||
:activity-id="activityId"
|
||||
:activity-name="activityName"
|
||||
ref="pendingTabRef"
|
||||
@refresh-other-tabs="handleRefreshOtherTabs"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -80,6 +81,18 @@ const handleTabChange = (tabName: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 处理其他标签页刷新
|
||||
const handleRefreshOtherTabs = () => {
|
||||
// 如果当前在待审核标签页,刷新已报名标签页
|
||||
if (activeTab.value === 'pending' && registeredTabRef.value) {
|
||||
registeredTabRef.value.getList();
|
||||
}
|
||||
// 如果当前在已报名标签页,刷新待审核标签页
|
||||
else if (activeTab.value === 'registered' && pendingTabRef.value) {
|
||||
pendingTabRef.value.getList();
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const handleClose = () => {
|
||||
emit('update:visible', false);
|
||||
@@ -93,6 +106,15 @@ defineExpose({
|
||||
} else if (activeTab.value === 'pending' && pendingTabRef.value) {
|
||||
pendingTabRef.value.getList();
|
||||
}
|
||||
},
|
||||
refreshAllTabs: () => {
|
||||
// 刷新所有标签页
|
||||
if (registeredTabRef.value) {
|
||||
registeredTabRef.value.getList();
|
||||
}
|
||||
if (pendingTabRef.value) {
|
||||
pendingTabRef.value.getList();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -5,31 +5,85 @@
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="rating-summary">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-statistic title="总评分数" :value="ratings.length" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-statistic title="平均评分" :value="averageRating" :precision="1" />
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-statistic title="最高评分" :value="maxRating" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<el-table :data="ratings" height="400" border>
|
||||
<el-table-column label="评分人" prop="userName" width="120" />
|
||||
<el-table-column label="评分" prop="ratingScore" width="120" align="center">
|
||||
<!-- 移除统计信息部分 -->
|
||||
|
||||
<el-table :data="ratings" height="600" border stripe>
|
||||
<!-- 基本信息 - 减少宽度 -->
|
||||
<el-table-column label="评分人信息" width="160" fixed="left">
|
||||
<template #default="scope">
|
||||
<el-rate :model-value="scope.row.ratingScore" disabled size="small" />
|
||||
<div class="user-info-compact">
|
||||
<div class="user-name">{{ scope.row.userName || '未知用户' }}</div>
|
||||
<div class="user-detail" v-if="scope.row.studentNo">{{ scope.row.studentNo }}</div>
|
||||
<div class="user-detail" v-if="scope.row.phoneNumber">{{ scope.row.phoneNumber }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 所属信息 - 减少宽度 -->
|
||||
<el-table-column label="所属信息" width="140">
|
||||
<template #default="scope">
|
||||
<div class="dept-info-compact">
|
||||
<div class="dept-detail" v-if="scope.row.deptName">{{ scope.row.deptName }}</div>
|
||||
<div class="dept-detail" v-if="scope.row.majorName">{{ scope.row.majorName }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 总评分 - 减少宽度 -->
|
||||
<el-table-column label="总评分" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<div class="rating-display-compact">
|
||||
<el-rate :model-value="scope.row.ratingScore" disabled size="small" />
|
||||
<div class="rating-number">{{ scope.row.ratingScore }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 各项分数 - 减少宽度 -->
|
||||
<el-table-column label="内容" width="70" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.contentScore" class="score-badge-small">
|
||||
{{ scope.row.contentScore }}
|
||||
</div>
|
||||
<span v-else class="no-score">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="组织" width="70" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.organizationScore" class="score-badge-small">
|
||||
{{ scope.row.organizationScore }}
|
||||
</div>
|
||||
<span v-else class="no-score">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="体验" width="70" align="center">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.experienceScore" class="score-badge-small">
|
||||
{{ scope.row.experienceScore }}
|
||||
</div>
|
||||
<span v-else class="no-score">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 评分备注 - 扩大宽度,取消tooltip,直接显示完整内容 -->
|
||||
<el-table-column label="评分备注" min-width="300">
|
||||
<template #default="scope">
|
||||
<div class="rating-comment-full">
|
||||
{{ scope.row.ratingComment || '无备注' }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 评分时间 - 简化显示格式,减少宽度 -->
|
||||
<el-table-column label="评分时间" width="120" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<div class="rating-time-compact">
|
||||
{{ formatDateTimeCompact(scope.row.ratingTime) }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="评分备注" prop="ratingComment" show-overflow-tooltip />
|
||||
<el-table-column label="评分时间" prop="ratingTime" width="160" align="center" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,19 +103,47 @@ const props = defineProps<Props>();
|
||||
const ratings = ref<ActivityRatingVO[]>([]);
|
||||
const loading = ref(false);
|
||||
|
||||
// 计算平均评分
|
||||
// 修复平均评分计算 - 确保数值类型正确转换
|
||||
const averageRating = computed(() => {
|
||||
if (ratings.value.length === 0) return 0;
|
||||
const sum = ratings.value.reduce((total, rating) => total + rating.ratingScore, 0);
|
||||
return sum / ratings.value.length;
|
||||
const sum = ratings.value.reduce((total, rating) => {
|
||||
// 确保评分是数字类型
|
||||
const score = typeof rating.ratingScore === 'string' ? parseFloat(rating.ratingScore) : rating.ratingScore;
|
||||
return total + (isNaN(score) ? 0 : score);
|
||||
}, 0);
|
||||
return Math.round((sum / ratings.value.length) * 10) / 10; // 保留一位小数
|
||||
});
|
||||
|
||||
// 计算最高评分
|
||||
const maxRating = computed(() => {
|
||||
if (ratings.value.length === 0) return 0;
|
||||
return Math.max(...ratings.value.map((rating) => rating.ratingScore));
|
||||
return Math.max(...ratings.value.map((rating) => {
|
||||
const score = typeof rating.ratingScore === 'string' ? parseFloat(rating.ratingScore) : rating.ratingScore;
|
||||
return isNaN(score) ? 0 : score;
|
||||
}));
|
||||
});
|
||||
|
||||
// 计算最低评分
|
||||
const minRating = computed(() => {
|
||||
if (ratings.value.length === 0) return 0;
|
||||
return Math.min(...ratings.value.map((rating) => {
|
||||
const score = typeof rating.ratingScore === 'string' ? parseFloat(rating.ratingScore) : rating.ratingScore;
|
||||
return isNaN(score) ? 0 : score;
|
||||
}));
|
||||
});
|
||||
|
||||
// 简化的日期时间格式化
|
||||
const formatDateTimeCompact = (dateStr?: string): string => {
|
||||
if (!dateStr) return '';
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleString('zh-CN', {
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
// 加载评分数据
|
||||
const loadRatings = async () => {
|
||||
if (!props.activityId) return;
|
||||
@@ -70,6 +152,7 @@ const loadRatings = async () => {
|
||||
try {
|
||||
const res = await getActivityRatings(props.activityId);
|
||||
ratings.value = res.data || [];
|
||||
console.log('加载的评分数据:', ratings.value);
|
||||
} catch (error: any) {
|
||||
// 如果是404错误,说明后端暂未实现该功能,静默处理
|
||||
if (error.response?.status === 404) {
|
||||
@@ -93,12 +176,100 @@ onMounted(() => {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.rating-summary {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
/* 紧凑的评分人信息样式 */
|
||||
.user-info-compact {
|
||||
padding: 4px 2px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.user-detail {
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 紧凑的所属信息样式 */
|
||||
.dept-info-compact {
|
||||
padding: 4px 2px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.dept-detail {
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* 紧凑的评分显示样式 */
|
||||
.rating-display-compact {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.rating-number {
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 小号分数徽章样式 */
|
||||
.score-badge-small {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: linear-gradient(135deg, #409eff 0%, #67c23a 100%);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.no-score {
|
||||
color: #c0c4cc;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* 完整评分备注样式 */
|
||||
.rating-comment-full {
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #303133;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
white-space: pre-wrap;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
/* 紧凑的时间显示样式 */
|
||||
.rating-time-compact {
|
||||
font-size: 11px;
|
||||
color: #606266;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* 表格行高优化 */
|
||||
:deep(.el-table .el-table__row) {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
:deep(.el-table .el-table__cell) {
|
||||
padding: 8px 0 !important;
|
||||
}
|
||||
</style>
|
||||
@@ -6,21 +6,16 @@
|
||||
<el-card shadow="always" style="padding: 8px 16px;">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="80px" style="padding: 0;">
|
||||
<el-row :gutter="16" align="middle">
|
||||
<el-col :span="5">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名" prop="studentName" style="margin-bottom: 0;">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入姓名" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="学号" prop="studentNo" style="margin-bottom: 0;">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="联系方式" prop="phone" style="margin-bottom: 0;">
|
||||
<el-input v-model="queryParams.phone" placeholder="请输入联系方式" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item style="margin-bottom: 0;">
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
@@ -38,27 +33,12 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Check" :disabled="single" @click="handleApprove()" v-hasPermi="['stgl:activityRegister:edit']">批量通过</el-button>
|
||||
<el-button type="success" plain icon="Check" :disabled="single" @click="handleApprove()" v-hasPermi="['stgl:activityRegister:approve']">批量通过</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Close" :disabled="single" @click="handleReject()" v-hasPermi="['stgl:activityRegister:edit']">批量拒绝</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['stgl:activityRegister:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-dropdown class="mt-[1px]">
|
||||
<el-button>
|
||||
更多
|
||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Download" @click="handleExport" v-hasPermi="['stgl:activityRegister:export']">导出数据</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-button type="danger" plain icon="Close" :disabled="single" @click="handleReject()" v-hasPermi="['stgl:activityRegister:approve']">批量拒绝</el-button>
|
||||
</el-col>
|
||||
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
@@ -100,19 +80,16 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请理由" align="center" prop="remark" width="200" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width" fixed="right">
|
||||
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['stgl:activityRegister:query']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="通过" placement="top">
|
||||
<el-button link type="success" icon="Check" @click="handleApprove(scope.row)" v-hasPermi="['stgl:activityRegister:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="拒绝" placement="top">
|
||||
<el-button link type="danger" icon="Close" @click="handleReject(scope.row)" v-hasPermi="['stgl:activityRegister:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['stgl:activityRegister:remove']"></el-button>
|
||||
<el-button link type="success" icon="Check" @click="handleApprove(scope.row)" v-hasPermi="['stgl:activityRegister:approve']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="拒绝" placement="top">
|
||||
<el-button link type="danger" icon="Close" @click="handleReject(scope.row)" v-hasPermi="['stgl:activityRegister:approve']"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -122,8 +99,9 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 查看成员详情对话框 -->
|
||||
<el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="800px" append-to-body>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="900px" append-to-body>
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="2" border class="mb-4">
|
||||
<el-descriptions-item label="学号">{{ viewForm.studentNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名">{{ viewForm.studentName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">
|
||||
@@ -136,11 +114,53 @@
|
||||
<el-descriptions-item label="报名类型">
|
||||
<dict-tag :options="stgl_registration_type" :value="viewForm.registrationType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="团队名称">{{ viewForm.teamName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请理由" :span="2">{{ viewForm.remark || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名时间">{{ parseTime(viewForm.registrationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 团队信息(仅团队报名时显示) -->
|
||||
<div v-if="Number(viewForm.registrationType) === 2 && teamInfo" class="team-info-section">
|
||||
<el-divider content-position="left">
|
||||
<span class="text-lg font-medium">团队信息</span>
|
||||
</el-divider>
|
||||
|
||||
<el-descriptions :column="2" border class="mb-4">
|
||||
<el-descriptions-item label="团队名称">{{ teamInfo.teamName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="团队人数">{{ teamInfo.teamSize || 0 }}人</el-descriptions-item>
|
||||
<el-descriptions-item label="队长姓名">{{ teamInfo.leaderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长学号">{{ teamInfo.leaderStudentNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长联系方式">{{ teamInfo.leaderPhone || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长院系">{{ teamInfo.leaderDepartment || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="团队简介" :span="2">{{ teamInfo.description || '暂无描述' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 队员列表 -->
|
||||
<div v-if="teamMembers.length > 0" class="team-members-section">
|
||||
<h4 class="text-base font-medium mb-3">队员列表</h4>
|
||||
<el-table :data="teamMembers" border stripe size="small">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="姓名" prop="studentName" width="100" align="center" />
|
||||
<el-table-column label="学号" prop="studentNo" width="120" align="center" />
|
||||
<el-table-column label="性别" prop="gender" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_user_sex" :value="scope.row.gender" v-if="scope.row.gender" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系方式" prop="phone" width="120" align="center" />
|
||||
<el-table-column label="院系" prop="department" width="120" align="center" />
|
||||
<el-table-column label="专业" prop="major" width="150" align="center" />
|
||||
<el-table-column label="班级" prop="className" width="100" align="center" />
|
||||
<el-table-column label="角色" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.isLeader === 1" type="success" size="small">队长</el-tag>
|
||||
<el-tag v-else type="info" size="small">队员</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelView">关 闭</el-button>
|
||||
@@ -182,12 +202,25 @@ import {
|
||||
listActivityRegister,
|
||||
getActivityRegister,
|
||||
delActivityRegister,
|
||||
updateActivityRegister,
|
||||
exportActivityRegister
|
||||
approveActivityRegister,
|
||||
batchApproveActivityRegister
|
||||
} from '@/api/stgl/activityregister';
|
||||
import { StglActivityRegistrationVo, StglActivityRegistrationForm, StglActivityRegistrationQuery } from '@/api/stgl/activityregister/types';
|
||||
import { getTeamsByActivityId } from '@/api/stgl/activityteaminfo';
|
||||
import { StglActivityTeamInfoVo, TeamMemberInfo } from '@/api/stgl/activityteaminfo/types';
|
||||
import { getStudent } from '@/api/xg/student';
|
||||
import { StudentVO } from '@/api/xg/student/types';
|
||||
import { parseTime } from '@/utils/ruoyi';
|
||||
import { ArrowDown } from '@element-plus/icons-vue';
|
||||
|
||||
// 扩展的类型定义,包含后端返回的所有字段
|
||||
interface ExtendedStglActivityRegistrationVo extends StglActivityRegistrationVo {
|
||||
gender?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
department?: string;
|
||||
major?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
activityId: string | number;
|
||||
@@ -201,7 +234,7 @@ const { sys_user_sex, stgl_registration_type, stgl_approval_status } = toRefs<an
|
||||
proxy?.useDict('sys_user_sex', 'stgl_registration_type', 'stgl_approval_status')
|
||||
);
|
||||
|
||||
const memberList = ref<StglActivityRegistrationVo[]>([]);
|
||||
const memberList = ref<ExtendedStglActivityRegistrationVo[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
@@ -223,10 +256,11 @@ const approvalDialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const viewForm = reactive<StglActivityRegistrationVo>({
|
||||
const viewForm = reactive<ExtendedStglActivityRegistrationVo>({
|
||||
id: undefined,
|
||||
activityId: undefined,
|
||||
studentId: undefined,
|
||||
activityName: '',
|
||||
userId: undefined,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
gender: '',
|
||||
@@ -234,16 +268,28 @@ const viewForm = reactive<StglActivityRegistrationVo>({
|
||||
major: '',
|
||||
className: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
registrationType: undefined,
|
||||
teamId: undefined,
|
||||
teamName: '',
|
||||
approvalStatus: undefined,
|
||||
registrationTime: '',
|
||||
approvalTime: '',
|
||||
remark: '',
|
||||
score: '',
|
||||
scoreTime: ''
|
||||
scoreTime: '',
|
||||
approvalBy: undefined,
|
||||
approvalRemark: '',
|
||||
scoreBy: undefined,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
});
|
||||
|
||||
// 团队信息相关数据
|
||||
const teamInfo = ref<StglActivityTeamInfoVo | null>(null);
|
||||
const teamMembers = ref<TeamMemberInfo[]>([]);
|
||||
const loadingTeamInfo = ref(false);
|
||||
|
||||
const approvalForm = reactive({
|
||||
ids: [] as Array<string | number>,
|
||||
approvalStatus: 1,
|
||||
@@ -269,15 +315,16 @@ const approvalRules = reactive({
|
||||
});
|
||||
|
||||
const data = reactive<PageData<StglActivityRegistrationForm, StglActivityRegistrationQuery>>({
|
||||
form: {} as StglActivityRegistrationForm,
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
activityId: props.activityId,
|
||||
approvalStatus: 0, // 待审核状态
|
||||
approvalStatus: '0', // 待审核状态,使用字符串类型
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
phone: undefined
|
||||
}
|
||||
studentNo: undefined
|
||||
},
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const { queryParams } = toRefs(data);
|
||||
@@ -285,17 +332,14 @@ const { queryParams } = toRefs(data);
|
||||
/** 查询成员列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 构建查询参数,查询待审核的报名记录
|
||||
const queryData = { ...queryParams.value };
|
||||
|
||||
// 确保查询待审核状态(approvalStatus=0)
|
||||
queryData.approvalStatus = 0;
|
||||
|
||||
console.log('PendingMembersTab: getList 开始查询,参数:', queryData);
|
||||
// 确保查询待审核状态(approvalStatus='0')
|
||||
queryData.approvalStatus = '0';
|
||||
|
||||
const res = await listActivityRegister(queryData);
|
||||
console.log('PendingMembersTab: 查询结果:', res);
|
||||
|
||||
memberList.value = res.rows;
|
||||
total.value = res.total;
|
||||
@@ -320,23 +364,22 @@ const resetQuery = () => {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
activityId: props.activityId,
|
||||
approvalStatus: 0,
|
||||
approvalStatus: '0',
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
phone: undefined
|
||||
studentNo: undefined
|
||||
};
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ActivityRegisterVO[]) => {
|
||||
const handleSelectionChange = (selection: ExtendedStglActivityRegistrationVo[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 批量通过操作 */
|
||||
const handleApprove = (row?: StglActivityRegistrationVo) => {
|
||||
const handleApprove = (row?: ExtendedStglActivityRegistrationVo) => {
|
||||
const _ids = row?.id ? [row.id] : ids.value;
|
||||
if (_ids.length === 0) {
|
||||
proxy?.$modal.msgError('请选择要审核的记录');
|
||||
@@ -351,7 +394,7 @@ const handleApprove = (row?: StglActivityRegistrationVo) => {
|
||||
};
|
||||
|
||||
/** 批量拒绝操作 */
|
||||
const handleReject = (row?: StglActivityRegistrationVo) => {
|
||||
const handleReject = (row?: ExtendedStglActivityRegistrationVo) => {
|
||||
const _ids = row?.id ? [row.id] : ids.value;
|
||||
if (_ids.length === 0) {
|
||||
proxy?.$modal.msgError('请选择要审核的记录');
|
||||
@@ -372,20 +415,29 @@ const submitApproval = () => {
|
||||
buttonLoading.value = true;
|
||||
|
||||
try {
|
||||
// 批量更新审核状态
|
||||
for (const id of approvalForm.ids) {
|
||||
await updateActivityRegister({
|
||||
id,
|
||||
approvalStatus: approvalForm.approvalStatus,
|
||||
approvalRemark: approvalForm.approvalRemark,
|
||||
approvalTime: new Date()
|
||||
} as StglActivityRegistrationForm);
|
||||
if (approvalForm.ids.length === 1) {
|
||||
// 单个审核
|
||||
await approveActivityRegister(
|
||||
approvalForm.ids[0],
|
||||
approvalForm.approvalStatus,
|
||||
approvalForm.approvalRemark
|
||||
);
|
||||
} else {
|
||||
// 批量审核
|
||||
await batchApproveActivityRegister(
|
||||
approvalForm.ids,
|
||||
approvalForm.approvalStatus,
|
||||
approvalForm.approvalRemark
|
||||
);
|
||||
}
|
||||
|
||||
const actionText = approvalForm.approvalStatus === 1 ? '通过' : '拒绝';
|
||||
proxy?.$modal.msgSuccess(`批量${actionText}成功`);
|
||||
approvalDialog.visible = false;
|
||||
await getList();
|
||||
|
||||
// 通知父组件刷新其他标签页
|
||||
notifyRefreshOtherTabs();
|
||||
} catch (error) {
|
||||
console.error('审核操作失败:', error);
|
||||
proxy?.$modal.msgError('审核操作失败');
|
||||
@@ -402,7 +454,7 @@ const cancelApproval = () => {
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: StglActivityRegistrationVo) => {
|
||||
const handleDelete = async (row?: ExtendedStglActivityRegistrationVo) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除选中的活动报名记录?');
|
||||
|
||||
@@ -421,34 +473,294 @@ const handleDelete = async (row?: StglActivityRegistrationVo) => {
|
||||
};
|
||||
|
||||
/** 查看按钮操作 */
|
||||
const handleView = async (row: StglActivityRegistrationVo) => {
|
||||
const handleView = async (row: ExtendedStglActivityRegistrationVo) => {
|
||||
const res = await getActivityRegister(row.id);
|
||||
Object.assign(viewForm, res.data);
|
||||
viewDialog.visible = true;
|
||||
viewDialog.title = '查看活动报名详情';
|
||||
|
||||
// 如果是团队报名,获取团队信息
|
||||
if (Number(viewForm.registrationType) === 2 && viewForm.teamId) {
|
||||
await loadTeamInfo(viewForm.teamId);
|
||||
} else {
|
||||
// 清空团队信息
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取团队信息 */
|
||||
const loadTeamInfo = async (teamId: string | number) => {
|
||||
if (!teamId) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingTeamInfo.value = true;
|
||||
|
||||
try {
|
||||
// 尝试调用团队信息API获取完整信息
|
||||
try {
|
||||
const response = await getTeamsByActivityId(viewForm.activityId);
|
||||
console.log('PendingMembersTab: 团队信息API响应:', response);
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
// 从团队列表中查找当前团队
|
||||
const teamData = response.data.find((team: any) => {
|
||||
return team.id == teamId || team.id.toString() === teamId || team.id === parseInt(teamId as string);
|
||||
});
|
||||
|
||||
console.log('PendingMembersTab: 找到的团队数据:', teamData);
|
||||
|
||||
if (teamData) {
|
||||
// 优先从teamMembers中查找队长信息
|
||||
let leaderPhone = '暂无联系方式';
|
||||
let leaderDepartment = '暂无院系信息';
|
||||
let leaderMajor = '';
|
||||
let leaderClassName = '';
|
||||
|
||||
try {
|
||||
if (teamData.teamMembers) {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
// 查找队长信息(isLeader: 1 或者 userId 匹配 leaderUserId)
|
||||
const leaderMember = membersData.find((member: any) =>
|
||||
member.isLeader === 1 || member.userId === teamData.leaderUserId
|
||||
);
|
||||
|
||||
if (leaderMember) {
|
||||
leaderPhone = leaderMember.phone || '暂无联系方式';
|
||||
leaderDepartment = leaderMember.department || '暂无院系信息';
|
||||
leaderMajor = leaderMember.major || '';
|
||||
leaderClassName = leaderMember.className || '';
|
||||
console.log('PendingMembersTab: 从teamMembers中找到队长信息:', leaderMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('PendingMembersTab: 解析团队成员JSON失败:', parseError);
|
||||
}
|
||||
|
||||
// 如果从teamMembers中没有找到队长信息,尝试通过leaderUserId获取
|
||||
if (leaderPhone === '暂无联系方式' || leaderDepartment === '暂无院系信息') {
|
||||
try {
|
||||
if (teamData.leaderUserId) {
|
||||
console.log('PendingMembersTab: 通过leaderUserId获取队长详细信息:', teamData.leaderUserId);
|
||||
const studentResponse = await getStudent(teamData.leaderUserId);
|
||||
console.log('PendingMembersTab: getStudent API响应:', studentResponse);
|
||||
|
||||
if (studentResponse.data) {
|
||||
const studentData = studentResponse.data;
|
||||
console.log('PendingMembersTab: 学生数据详情:', studentData);
|
||||
console.log('PendingMembersTab: 学生数据字段:', {
|
||||
phone: studentData.phone,
|
||||
collegeName: studentData.collegeName,
|
||||
majorName: studentData.majorName,
|
||||
className: studentData.className
|
||||
});
|
||||
|
||||
// 只有在teamMembers中没有找到时才使用API获取的信息
|
||||
if (leaderPhone === '暂无联系方式') {
|
||||
leaderPhone = studentData.phone || '暂无联系方式';
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息') {
|
||||
leaderDepartment = studentData.collegeName || '暂无院系信息';
|
||||
}
|
||||
if (!leaderMajor) {
|
||||
leaderMajor = studentData.majorName || '';
|
||||
}
|
||||
if (!leaderClassName) {
|
||||
leaderClassName = studentData.className || '';
|
||||
}
|
||||
console.log('PendingMembersTab: 获取到队长详细信息:', { leaderPhone, leaderDepartment, studentData });
|
||||
} else {
|
||||
console.log('PendingMembersTab: getStudent API返回数据为空');
|
||||
}
|
||||
}
|
||||
} catch (studentError) {
|
||||
console.log('PendingMembersTab: 获取队长详细信息失败:', studentError);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果仍然没有获取到队长信息,尝试从报名详情中获取
|
||||
if (leaderPhone === '暂无联系方式' && viewForm.phone) {
|
||||
leaderPhone = viewForm.phone;
|
||||
console.log('PendingMembersTab: 使用报名详情中的联系方式:', leaderPhone);
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息' && viewForm.department) {
|
||||
leaderDepartment = viewForm.department;
|
||||
console.log('PendingMembersTab: 使用报名详情中的院系信息:', leaderDepartment);
|
||||
}
|
||||
|
||||
// 最后的备用方案:如果还是没有获取到,尝试从teamMembers中查找匹配leaderUserId的成员
|
||||
if ((leaderPhone === '暂无联系方式' || leaderDepartment === '暂无院系信息') && teamData.teamMembers) {
|
||||
try {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
// 查找与leaderUserId匹配的成员
|
||||
const leaderMember = membersData.find((member: any) =>
|
||||
member.userId === teamData.leaderUserId
|
||||
);
|
||||
|
||||
if (leaderMember) {
|
||||
if (leaderPhone === '暂无联系方式') {
|
||||
leaderPhone = leaderMember.phone || '暂无联系方式';
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息') {
|
||||
leaderDepartment = leaderMember.department || '暂无院系信息';
|
||||
}
|
||||
if (!leaderMajor) {
|
||||
leaderMajor = leaderMember.major || '';
|
||||
}
|
||||
if (!leaderClassName) {
|
||||
leaderClassName = leaderMember.className || '';
|
||||
}
|
||||
console.log('PendingMembersTab: 从teamMembers中找到匹配leaderUserId的成员信息:', leaderMember);
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('PendingMembersTab: 备用方案解析团队成员JSON失败:', parseError);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新团队信息
|
||||
teamInfo.value = {
|
||||
id: teamData.id,
|
||||
teamName: teamData.teamName,
|
||||
activityId: teamData.activityId,
|
||||
leaderUserId: teamData.leaderUserId,
|
||||
teamSize: teamData.teamSize || 1,
|
||||
leaderName: teamData.leaderName,
|
||||
leaderStudentNo: teamData.leaderStudentNo,
|
||||
leaderPhone: leaderPhone,
|
||||
leaderDepartment: leaderDepartment,
|
||||
description: teamData.description || '',
|
||||
teamMembers: teamData.teamMembers || '[]'
|
||||
};
|
||||
|
||||
console.log('PendingMembersTab: 最终设置的团队信息:', teamInfo.value);
|
||||
|
||||
// 解析团队成员信息
|
||||
if (teamData.teamMembers) {
|
||||
try {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
teamMembers.value = membersData.map((member: any) => ({
|
||||
userId: member.userId,
|
||||
studentNo: member.studentNo,
|
||||
studentName: member.studentName,
|
||||
gender: member.gender,
|
||||
phone: member.phone,
|
||||
email: member.email,
|
||||
department: member.department,
|
||||
major: member.major,
|
||||
className: member.className,
|
||||
isLeader: member.isLeader
|
||||
}));
|
||||
} else {
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('解析团队成员JSON失败:', parseError);
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} else {
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} else {
|
||||
throw new Error('未找到对应的团队信息');
|
||||
}
|
||||
} else {
|
||||
throw new Error('API返回数据为空或格式错误');
|
||||
}
|
||||
} catch (apiError) {
|
||||
console.log('PendingMembersTab: 团队信息API调用失败,使用报名详情中的信息:', apiError);
|
||||
|
||||
// 如果API调用失败,使用报名详情中的信息
|
||||
if (viewForm.teamName) {
|
||||
// 尝试获取队长的详细信息
|
||||
let leaderPhone = '暂无联系方式';
|
||||
let leaderDepartment = '暂无院系信息';
|
||||
|
||||
try {
|
||||
if (viewForm.userId) {
|
||||
const studentResponse = await getStudent(viewForm.userId);
|
||||
if (studentResponse.data) {
|
||||
const studentData = studentResponse.data;
|
||||
leaderPhone = studentData.phone || '暂无联系方式';
|
||||
leaderDepartment = studentData.collegeName || '暂无院系信息';
|
||||
console.log('PendingMembersTab: 获取到队长详细信息:', studentData);
|
||||
}
|
||||
}
|
||||
} catch (studentError) {
|
||||
console.log('PendingMembersTab: 获取队长详细信息失败,使用报名详情中的信息:', studentError);
|
||||
// 如果获取学生信息失败,尝试使用报名详情中的字段
|
||||
if (viewForm.phone) {
|
||||
leaderPhone = viewForm.phone;
|
||||
}
|
||||
if (viewForm.department) {
|
||||
leaderDepartment = viewForm.department;
|
||||
}
|
||||
}
|
||||
|
||||
// 构造团队信息对象,优先使用获取到的详细信息
|
||||
teamInfo.value = {
|
||||
id: viewForm.teamId,
|
||||
teamName: viewForm.teamName,
|
||||
activityId: viewForm.activityId,
|
||||
leaderUserId: viewForm.userId,
|
||||
teamSize: 1, // 默认值,实际应该从后端获取
|
||||
leaderName: viewForm.studentName,
|
||||
leaderStudentNo: viewForm.studentNo,
|
||||
leaderPhone: leaderPhone,
|
||||
leaderDepartment: leaderDepartment,
|
||||
description: viewForm.remark || '暂无团队简介',
|
||||
teamMembers: '[]' // JSON格式的字符串
|
||||
};
|
||||
|
||||
// 团队成员信息暂时为空,因为报名详情中没有这个字段
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
|
||||
console.log('PendingMembersTab: 使用报名详情构造的团队信息:', teamInfo.value);
|
||||
} else {
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('PendingMembersTab: 处理团队信息失败:', error);
|
||||
proxy?.$modal.msgError('处理团队信息失败');
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
} finally {
|
||||
loadingTeamInfo.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消查看对话框 */
|
||||
const cancelView = () => {
|
||||
viewDialog.visible = false;
|
||||
// 清空团队信息
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'stgl/activity/register/export',
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`pending_activity_register_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// 暴露给父组件的方法
|
||||
defineExpose({
|
||||
getList
|
||||
});
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits<{
|
||||
refreshOtherTabs: []
|
||||
}>();
|
||||
|
||||
// 通知父组件刷新其他标签页
|
||||
const notifyRefreshOtherTabs = () => {
|
||||
emit('refreshOtherTabs');
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
@@ -466,4 +778,29 @@ onMounted(() => {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 团队信息区域样式 */
|
||||
.team-info-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.team-members-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mb-3 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -17,11 +17,6 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="联系方式" prop="phone" style="margin-bottom: 0;">
|
||||
<el-input v-model="queryParams.phone" placeholder="请输入联系方式" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item style="margin-bottom: 0;">
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
@@ -46,6 +41,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['stgl:activityRegister:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="Download" @click="handleExport" v-hasPermi="['stgl:activityRegister:export']">导出数据</el-button>
|
||||
</el-col>
|
||||
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
@@ -159,7 +157,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="团队名称" prop="teamName" v-if="form.registrationType === '2' || form.registrationType === '3'">
|
||||
<el-form-item label="团队名称" prop="teamName" v-if="form.registrationType === 2 || form.registrationType === 3">
|
||||
<el-input v-model="form.teamName" placeholder="请输入团队名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -179,8 +177,9 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看成员详情对话框 -->
|
||||
<el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="800px" append-to-body>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="900px" append-to-body>
|
||||
<!-- 基本信息 -->
|
||||
<el-descriptions :column="2" border class="mb-4">
|
||||
<el-descriptions-item label="学号">{{ viewForm.studentNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="姓名">{{ viewForm.studentName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">
|
||||
@@ -193,12 +192,54 @@
|
||||
<el-descriptions-item label="报名类型">
|
||||
<dict-tag :options="stgl_registration_type" :value="viewForm.registrationType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="团队名称">{{ viewForm.teamName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请理由">{{ viewForm.remark || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请理由" :span="2">{{ viewForm.remark || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名时间">{{ parseTime(viewForm.registrationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成绩">{{ viewForm.score || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 团队信息(仅团队报名时显示) -->
|
||||
<div v-if="Number(viewForm.registrationType) === 2 && teamInfo" class="team-info-section">
|
||||
<el-divider content-position="left">
|
||||
<span class="text-lg font-medium">团队信息</span>
|
||||
</el-divider>
|
||||
|
||||
<el-descriptions :column="2" border class="mb-4">
|
||||
<el-descriptions-item label="团队名称">{{ teamInfo.teamName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="团队人数">{{ teamInfo.teamSize || 0 }}人</el-descriptions-item>
|
||||
<el-descriptions-item label="队长姓名">{{ teamInfo.leaderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长学号">{{ teamInfo.leaderStudentNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长联系方式">{{ teamInfo.leaderPhone || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长院系">{{ teamInfo.leaderDepartment || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="团队简介" :span="2">{{ teamInfo.description || '暂无描述' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 队员列表 -->
|
||||
<div v-if="teamMembers.length > 0" class="team-members-section">
|
||||
<h4 class="text-base font-medium mb-3">队员列表</h4>
|
||||
<el-table :data="teamMembers" border stripe size="small">
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="姓名" prop="studentName" width="100" align="center" />
|
||||
<el-table-column label="学号" prop="studentNo" width="120" align="center" />
|
||||
<el-table-column label="性别" prop="gender" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_user_sex" :value="scope.row.gender" v-if="scope.row.gender" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系方式" prop="phone" width="120" align="center" />
|
||||
<el-table-column label="院系" prop="department" width="120" align="center" />
|
||||
<el-table-column label="专业" prop="major" width="150" align="center" />
|
||||
<el-table-column label="班级" prop="className" width="100" align="center" />
|
||||
<el-table-column label="角色" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.isLeader === 1" type="success" size="small">队长</el-tag>
|
||||
<el-tag v-else type="info" size="small">队员</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancelView">关 闭</el-button>
|
||||
@@ -253,24 +294,51 @@ import {
|
||||
updateActivityRegister,
|
||||
exportActivityRegister
|
||||
} from '@/api/stgl/activityregister';
|
||||
import { ActivityRegisterVO, ActivityRegisterForm, ActivityRegisterQuery } from '@/api/stgl/activityregister/types';
|
||||
import { StglActivityRegistrationVo, StglActivityRegistrationForm, StglActivityRegistrationQuery } from '@/api/stgl/activityregister/types';
|
||||
import { getTeamsByActivityId } from '@/api/stgl/activityteaminfo';
|
||||
import { StglActivityTeamInfoVo, TeamMemberInfo } from '@/api/stgl/activityteaminfo/types';
|
||||
import { getStudent } from '@/api/xg/student';
|
||||
import { StudentVO } from '@/api/xg/student/types';
|
||||
import StudentSelector from '@/components/StudentSelector/index.vue';
|
||||
import { parseTime } from '@/utils/ruoyi';
|
||||
import { globalHeaders } from '@/utils/request';
|
||||
import { ArrowDown, UploadFilled } from '@element-plus/icons-vue';
|
||||
import { UploadFilled } from '@element-plus/icons-vue';
|
||||
import type { UploadInstance } from 'element-plus';
|
||||
|
||||
// 扩展的类型定义,包含后端返回的所有字段
|
||||
interface ExtendedStglActivityRegistrationVo extends StglActivityRegistrationVo {
|
||||
gender?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
department?: string;
|
||||
major?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// 扩展ActivityRegisterForm以包含选择的学生对象和额外字段
|
||||
interface ExtendedActivityRegisterForm extends StglActivityRegistrationForm {
|
||||
selectedStudent?: StudentVO | null;
|
||||
gender?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
department?: string;
|
||||
major?: string;
|
||||
className?: string;
|
||||
registrationTime?: string;
|
||||
approvalTime?: string;
|
||||
scoreTime?: string;
|
||||
approvalBy?: string | number;
|
||||
approvalRemark?: string;
|
||||
scoreBy?: string | number;
|
||||
createTime?: string;
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
activityId: string | number;
|
||||
activityName: string;
|
||||
}
|
||||
|
||||
// 扩展ActivityRegisterForm以包含选择的学生对象
|
||||
interface ExtendedActivityRegisterForm extends ActivityRegisterForm {
|
||||
selectedStudent?: StudentVO | null;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@@ -278,7 +346,7 @@ const { sys_user_sex, stgl_registration_type, stgl_approval_status } = toRefs<an
|
||||
proxy?.useDict('sys_user_sex', 'stgl_registration_type', 'stgl_approval_status')
|
||||
);
|
||||
|
||||
const memberList = ref<ActivityRegisterVO[]>([]);
|
||||
const memberList = ref<ExtendedStglActivityRegistrationVo[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
@@ -300,10 +368,11 @@ const viewDialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const viewForm = reactive<ActivityRegisterVO>({
|
||||
const viewForm = reactive<ExtendedStglActivityRegistrationVo>({
|
||||
id: undefined,
|
||||
activityId: undefined,
|
||||
studentId: undefined,
|
||||
activityName: '',
|
||||
userId: undefined,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
gender: '',
|
||||
@@ -311,20 +380,32 @@ const viewForm = reactive<ActivityRegisterVO>({
|
||||
major: '',
|
||||
className: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
registrationType: undefined,
|
||||
teamId: undefined,
|
||||
teamName: '',
|
||||
approvalStatus: undefined,
|
||||
registrationTime: '',
|
||||
approvalTime: '',
|
||||
remark: '',
|
||||
score: '',
|
||||
scoreTime: ''
|
||||
scoreTime: '',
|
||||
approvalBy: undefined,
|
||||
approvalRemark: '',
|
||||
scoreBy: undefined,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
});
|
||||
|
||||
// 团队信息相关数据
|
||||
const teamInfo = ref<StglActivityTeamInfoVo | null>(null);
|
||||
const teamMembers = ref<TeamMemberInfo[]>([]);
|
||||
const loadingTeamInfo = ref(false);
|
||||
|
||||
const initFormData: ExtendedActivityRegisterForm = {
|
||||
id: undefined,
|
||||
activityId: props.activityId,
|
||||
studentId: undefined,
|
||||
userId: undefined,
|
||||
selectedStudent: null,
|
||||
studentName: '',
|
||||
studentNo: '',
|
||||
@@ -333,26 +414,31 @@ const initFormData: ExtendedActivityRegisterForm = {
|
||||
major: '',
|
||||
className: '',
|
||||
phone: '',
|
||||
registrationType: '1',
|
||||
registrationType: 1,
|
||||
teamId: undefined,
|
||||
teamName: '',
|
||||
approvalStatus: 1,
|
||||
registrationTime: undefined,
|
||||
approvalTime: undefined,
|
||||
remark: '',
|
||||
score: '',
|
||||
scoreTime: undefined
|
||||
scoreTime: undefined,
|
||||
approvalBy: undefined,
|
||||
approvalRemark: '',
|
||||
scoreBy: undefined,
|
||||
createTime: '',
|
||||
updateTime: ''
|
||||
};
|
||||
|
||||
const data = reactive<PageData<ExtendedActivityRegisterForm, ActivityRegisterQuery>>({
|
||||
const data = reactive<PageData<ExtendedActivityRegisterForm, StglActivityRegistrationQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
activityId: props.activityId,
|
||||
approvalStatus: undefined,
|
||||
approvalStatus: '1', // 使用字符串类型,符合查询接口定义
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
phone: undefined
|
||||
studentNo: undefined
|
||||
},
|
||||
rules: {
|
||||
selectedStudent: [{ required: true, message: '请选择学生', trigger: 'change' }],
|
||||
@@ -390,7 +476,7 @@ const getList = async () => {
|
||||
|
||||
// 如果状态字段为空或未选择,则查询已通过(approvalStatus=1)的报名记录
|
||||
if (!queryData.approvalStatus) {
|
||||
queryData.approvalStatus = 1;
|
||||
queryData.approvalStatus = '1';
|
||||
}
|
||||
|
||||
console.log('RegisteredMembersTab: getList 开始查询,参数:', queryData);
|
||||
@@ -433,16 +519,15 @@ const resetQuery = () => {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
activityId: props.activityId,
|
||||
approvalStatus: 1,
|
||||
approvalStatus: '1',
|
||||
studentName: undefined,
|
||||
studentNo: undefined,
|
||||
phone: undefined
|
||||
studentNo: undefined
|
||||
};
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ActivityRegisterVO[]) => {
|
||||
const handleSelectionChange = (selection: ExtendedStglActivityRegistrationVo[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
@@ -456,7 +541,7 @@ const handleAdd = () => {
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: ActivityRegisterVO) => {
|
||||
const handleUpdate = async (row?: ExtendedStglActivityRegistrationVo) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getActivityRegister(_id);
|
||||
@@ -464,15 +549,17 @@ const handleUpdate = async (row?: ActivityRegisterVO) => {
|
||||
|
||||
// 设置学生选择器数据
|
||||
if (res.data.studentName) {
|
||||
// 使用扩展类型来访问额外字段
|
||||
const extendedData = res.data as ExtendedStglActivityRegistrationVo;
|
||||
form.value.selectedStudent = {
|
||||
id: res.data.studentId || 0,
|
||||
id: res.data.userId || 0,
|
||||
studentNo: res.data.studentNo || '',
|
||||
name: res.data.studentName,
|
||||
gender: res.data.gender || '0',
|
||||
phone: res.data.phone || '',
|
||||
collegeName: res.data.department || '',
|
||||
majorName: res.data.major || '',
|
||||
className: res.data.className || ''
|
||||
gender: extendedData.gender || '0',
|
||||
phone: extendedData.phone || '',
|
||||
collegeName: extendedData.department || '',
|
||||
majorName: extendedData.major || '',
|
||||
className: extendedData.className || ''
|
||||
} as StudentVO;
|
||||
}
|
||||
|
||||
@@ -495,9 +582,9 @@ const submitForm = () => {
|
||||
|
||||
try {
|
||||
if (form.value.id) {
|
||||
await updateActivityRegister(submitData as ActivityRegisterForm);
|
||||
await updateActivityRegister(submitData as StglActivityRegistrationForm);
|
||||
} else {
|
||||
await addActivityRegister(submitData as ActivityRegisterForm);
|
||||
await addActivityRegister(submitData as StglActivityRegistrationForm);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
@@ -512,7 +599,7 @@ const submitForm = () => {
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: ActivityRegisterVO) => {
|
||||
const handleDelete = async (row?: ExtendedStglActivityRegistrationVo) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除选中的活动报名记录?');
|
||||
|
||||
@@ -531,22 +618,281 @@ const handleDelete = async (row?: ActivityRegisterVO) => {
|
||||
};
|
||||
|
||||
/** 查看按钮操作 */
|
||||
const handleView = async (row: ActivityRegisterVO) => {
|
||||
const handleView = async (row: ExtendedStglActivityRegistrationVo) => {
|
||||
const res = await getActivityRegister(row.id);
|
||||
Object.assign(viewForm, res.data);
|
||||
viewDialog.visible = true;
|
||||
viewDialog.title = '查看活动报名详情';
|
||||
|
||||
// 如果是团队报名,获取团队信息
|
||||
if (Number(viewForm.registrationType) === 2 && viewForm.teamId) {
|
||||
await loadTeamInfo(viewForm.teamId);
|
||||
} else {
|
||||
// 清空团队信息
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取团队信息 */
|
||||
const loadTeamInfo = async (teamId: string | number) => {
|
||||
if (!teamId) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadingTeamInfo.value = true;
|
||||
|
||||
try {
|
||||
// 尝试调用团队信息API获取完整信息
|
||||
try {
|
||||
const response = await getTeamsByActivityId(viewForm.activityId);
|
||||
console.log('RegisteredMembersTab: 团队信息API响应:', response);
|
||||
|
||||
if (response.data && Array.isArray(response.data)) {
|
||||
// 从团队列表中查找当前团队
|
||||
const teamData = response.data.find((team: any) => {
|
||||
return team.id == teamId || team.id.toString() === teamId || team.id === parseInt(teamId as string);
|
||||
});
|
||||
|
||||
console.log('RegisteredMembersTab: 找到的团队数据:', teamData);
|
||||
|
||||
if (teamData) {
|
||||
// 优先从teamMembers中查找队长信息
|
||||
let leaderPhone = '暂无联系方式';
|
||||
let leaderDepartment = '暂无院系信息';
|
||||
let leaderMajor = '';
|
||||
let leaderClassName = '';
|
||||
|
||||
try {
|
||||
if (teamData.teamMembers) {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
// 查找队长信息(isLeader: 1 或者 userId 匹配 leaderUserId)
|
||||
const leaderMember = membersData.find((member: any) =>
|
||||
member.isLeader === 1 || member.userId === teamData.leaderUserId
|
||||
);
|
||||
|
||||
if (leaderMember) {
|
||||
leaderPhone = leaderMember.phone || '暂无联系方式';
|
||||
leaderDepartment = leaderMember.department || '暂无院系信息';
|
||||
leaderMajor = leaderMember.major || '';
|
||||
leaderClassName = leaderMember.className || '';
|
||||
console.log('RegisteredMembersTab: 从teamMembers中找到队长信息:', leaderMember);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('RegisteredMembersTab: 解析团队成员JSON失败:', parseError);
|
||||
}
|
||||
|
||||
// 如果从teamMembers中没有找到队长信息,尝试通过leaderUserId获取
|
||||
if (leaderPhone === '暂无联系方式' || leaderDepartment === '暂无院系信息') {
|
||||
try {
|
||||
if (teamData.leaderUserId) {
|
||||
console.log('RegisteredMembersTab: 通过leaderUserId获取队长详细信息:', teamData.leaderUserId);
|
||||
const studentResponse = await getStudent(teamData.leaderUserId);
|
||||
console.log('RegisteredMembersTab: getStudent API响应:', studentResponse);
|
||||
|
||||
if (studentResponse.data) {
|
||||
const studentData = studentResponse.data;
|
||||
console.log('RegisteredMembersTab: 学生数据详情:', studentData);
|
||||
console.log('RegisteredMembersTab: 学生数据字段:', {
|
||||
phone: studentData.phone,
|
||||
collegeName: studentData.collegeName,
|
||||
majorName: studentData.majorName,
|
||||
className: studentData.className
|
||||
});
|
||||
|
||||
// 只有在teamMembers中没有找到时才使用API获取的信息
|
||||
if (leaderPhone === '暂无联系方式') {
|
||||
leaderPhone = studentData.phone || '暂无联系方式';
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息') {
|
||||
leaderDepartment = studentData.collegeName || '暂无院系信息';
|
||||
}
|
||||
if (!leaderMajor) {
|
||||
leaderMajor = studentData.majorName || '';
|
||||
}
|
||||
if (!leaderClassName) {
|
||||
leaderClassName = studentData.className || '';
|
||||
}
|
||||
console.log('RegisteredMembersTab: 获取到队长详细信息:', { leaderPhone, leaderDepartment, studentData });
|
||||
} else {
|
||||
console.log('RegisteredMembersTab: getStudent API返回数据为空');
|
||||
}
|
||||
}
|
||||
} catch (studentError) {
|
||||
console.log('RegisteredMembersTab: 获取队长详细信息失败:', studentError);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果仍然没有获取到队长信息,尝试从报名详情中获取
|
||||
if (leaderPhone === '暂无联系方式' && viewForm.phone) {
|
||||
leaderPhone = viewForm.phone;
|
||||
console.log('RegisteredMembersTab: 使用报名详情中的联系方式:', leaderPhone);
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息' && viewForm.department) {
|
||||
leaderDepartment = viewForm.department;
|
||||
console.log('RegisteredMembersTab: 使用报名详情中的院系信息:', leaderDepartment);
|
||||
}
|
||||
|
||||
// 最后的备用方案:如果还是没有获取到,尝试从teamMembers中查找匹配leaderUserId的成员
|
||||
if ((leaderPhone === '暂无联系方式' || leaderDepartment === '暂无院系信息') && teamData.teamMembers) {
|
||||
try {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
// 查找与leaderUserId匹配的成员
|
||||
const leaderMember = membersData.find((member: any) =>
|
||||
member.userId === teamData.leaderUserId
|
||||
);
|
||||
|
||||
if (leaderMember) {
|
||||
if (leaderPhone === '暂无联系方式') {
|
||||
leaderPhone = leaderMember.phone || '暂无联系方式';
|
||||
}
|
||||
if (leaderDepartment === '暂无院系信息') {
|
||||
leaderDepartment = leaderMember.department || '暂无院系信息';
|
||||
}
|
||||
if (!leaderMajor) {
|
||||
leaderMajor = leaderMember.major || '';
|
||||
}
|
||||
if (!leaderClassName) {
|
||||
leaderClassName = leaderMember.className || '';
|
||||
}
|
||||
console.log('RegisteredMembersTab: 从teamMembers中找到匹配leaderUserId的成员信息:', leaderMember);
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('RegisteredMembersTab: 备用方案解析团队成员JSON失败:', parseError);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新团队信息
|
||||
teamInfo.value = {
|
||||
id: teamData.id,
|
||||
teamName: teamData.teamName,
|
||||
activityId: teamData.activityId,
|
||||
leaderUserId: teamData.leaderUserId,
|
||||
teamSize: teamData.teamSize || 1,
|
||||
leaderName: teamData.leaderName,
|
||||
leaderStudentNo: teamData.leaderStudentNo,
|
||||
leaderPhone: leaderPhone,
|
||||
leaderDepartment: leaderDepartment,
|
||||
description: teamData.description || '',
|
||||
teamMembers: teamData.teamMembers || '[]'
|
||||
};
|
||||
|
||||
console.log('RegisteredMembersTab: 最终设置的团队信息:', teamInfo.value);
|
||||
|
||||
// 解析团队成员信息
|
||||
if (teamData.teamMembers) {
|
||||
try {
|
||||
const membersData = JSON.parse(teamData.teamMembers);
|
||||
if (Array.isArray(membersData)) {
|
||||
teamMembers.value = membersData.map((member: any) => ({
|
||||
userId: member.userId,
|
||||
studentNo: member.studentNo,
|
||||
studentName: member.studentName,
|
||||
gender: member.gender,
|
||||
phone: member.phone,
|
||||
email: member.email,
|
||||
department: member.department,
|
||||
major: member.major,
|
||||
className: member.className,
|
||||
isLeader: member.isLeader
|
||||
}));
|
||||
} else {
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error('解析团队成员JSON失败:', parseError);
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} else {
|
||||
teamMembers.value = [];
|
||||
}
|
||||
} else {
|
||||
throw new Error('未找到对应的团队信息');
|
||||
}
|
||||
} else {
|
||||
throw new Error('API返回数据为空或格式错误');
|
||||
}
|
||||
} catch (apiError) {
|
||||
console.log('RegisteredMembersTab: 团队信息API调用失败,使用报名详情中的信息:', apiError);
|
||||
|
||||
// 如果API调用失败,使用报名详情中的信息
|
||||
if (viewForm.teamName) {
|
||||
// 尝试获取队长的详细信息
|
||||
let leaderPhone = '暂无联系方式';
|
||||
let leaderDepartment = '暂无院系信息';
|
||||
|
||||
try {
|
||||
if (viewForm.userId) {
|
||||
const studentResponse = await getStudent(viewForm.userId);
|
||||
if (studentResponse.data) {
|
||||
const studentData = studentResponse.data;
|
||||
leaderPhone = studentData.phone || '暂无联系方式';
|
||||
leaderDepartment = studentData.collegeName || '暂无院系信息';
|
||||
console.log('RegisteredMembersTab: 获取到队长详细信息:', studentData);
|
||||
}
|
||||
}
|
||||
} catch (studentError) {
|
||||
console.log('RegisteredMembersTab: 获取队长详细信息失败,使用报名详情中的信息:', studentError);
|
||||
// 如果获取学生信息失败,尝试使用报名详情中的字段
|
||||
if (viewForm.phone) {
|
||||
leaderPhone = viewForm.phone;
|
||||
}
|
||||
if (viewForm.department) {
|
||||
leaderDepartment = viewForm.department;
|
||||
}
|
||||
}
|
||||
|
||||
// 构造团队信息对象,优先使用获取到的详细信息
|
||||
teamInfo.value = {
|
||||
id: viewForm.teamId,
|
||||
teamName: viewForm.teamName,
|
||||
activityId: viewForm.activityId,
|
||||
leaderUserId: viewForm.userId,
|
||||
teamSize: 1, // 默认值,实际应该从后端获取
|
||||
leaderName: viewForm.studentName,
|
||||
leaderStudentNo: viewForm.studentNo,
|
||||
leaderPhone: leaderPhone,
|
||||
leaderDepartment: leaderDepartment,
|
||||
description: viewForm.remark || '暂无团队简介',
|
||||
teamMembers: '[]' // JSON格式的字符串
|
||||
};
|
||||
|
||||
// 团队成员信息暂时为空,因为报名详情中没有这个字段
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
|
||||
console.log('RegisteredMembersTab: 使用报名详情构造的团队信息:', teamInfo.value);
|
||||
} else {
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('RegisteredMembersTab: 处理团队信息失败:', error);
|
||||
proxy?.$modal.msgError('处理团队信息失败');
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
} finally {
|
||||
loadingTeamInfo.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消查看对话框 */
|
||||
const cancelView = () => {
|
||||
viewDialog.visible = false;
|
||||
// 清空团队信息
|
||||
teamInfo.value = null;
|
||||
teamMembers.value = [] as TeamMemberInfo[];
|
||||
};
|
||||
|
||||
/** 学生选择变化处理 */
|
||||
const handleStudentChange = (student: StudentVO | null) => {
|
||||
if (student) {
|
||||
form.value.studentId = student.id;
|
||||
form.value.userId = student.id;
|
||||
form.value.studentNo = student.studentNo;
|
||||
form.value.studentName = student.name;
|
||||
form.value.gender = student.gender;
|
||||
@@ -555,7 +901,7 @@ const handleStudentChange = (student: StudentVO | null) => {
|
||||
form.value.className = student.className;
|
||||
form.value.phone = student.phone;
|
||||
} else {
|
||||
form.value.studentId = undefined;
|
||||
form.value.userId = undefined;
|
||||
form.value.studentNo = '';
|
||||
form.value.studentName = '';
|
||||
form.value.gender = '';
|
||||
@@ -573,7 +919,7 @@ const handleExport = () => {
|
||||
{
|
||||
...queryParams.value
|
||||
},
|
||||
`activity_register_${new Date().getTime()}.xlsx`
|
||||
`registered_activity_register_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
@@ -631,4 +977,29 @@ onMounted(() => {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 团队信息区域样式 */
|
||||
.team-info-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.team-members-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.text-lg {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.font-medium {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mb-3 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.mb-4 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -62,7 +62,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主办方" align="center" prop="organizerName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="关联社团" align="center" width="120" show-overflow-tooltip>
|
||||
<el-table-column label="关联社团/队伍" align="center" width="120" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.relatedClubName">{{ scope.row.relatedClubName }}</span>
|
||||
<span v-else class="text-gray-400">未关联</span>
|
||||
@@ -101,6 +101,12 @@
|
||||
<el-tag type="info" size="small">{{ scope.row.registrationCount || 0 }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="审核设置" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.needApproval === 0" type="success" size="small">无需审核</el-tag>
|
||||
<el-tag v-else type="warning" size="small">需要审核</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看详情" placement="top">
|
||||
@@ -141,6 +147,7 @@
|
||||
<!-- 查看活动详细信息对话框 -->
|
||||
<el-dialog :title="viewDialog.title" v-model="viewDialog.visible" width="1200px" append-to-body>
|
||||
<ActivityDetailView :activity="viewForm" />
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleRegister(viewForm)" v-if="canRegister(viewForm)">立即报名</el-button>
|
||||
@@ -156,6 +163,26 @@
|
||||
<el-input v-model="selectedActivity.activityName" disabled />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 审核设置提示 -->
|
||||
<el-form-item label="审核设置">
|
||||
<el-alert
|
||||
v-if="selectedActivity.needApproval === 0"
|
||||
title="无需审核"
|
||||
type="success"
|
||||
description="该活动设置为无需审核,报名后将自动通过"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<el-alert
|
||||
v-else
|
||||
title="需要审核"
|
||||
type="info"
|
||||
description="该活动设置为需要审核,报名后需要等待管理员审核通过"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="报名类型" prop="registrationType">
|
||||
<el-radio-group v-model="registerForm.registrationType" @change="handleRegistrationTypeChange">
|
||||
<el-radio v-if="isRegistrationTypeAllowed(1)" :value="1">个人报名</el-radio>
|
||||
@@ -228,16 +255,11 @@
|
||||
</el-form-item>
|
||||
|
||||
<!-- 团队负责人信息 -->
|
||||
<el-divider content-position="left">团队负责人</el-divider>
|
||||
<el-divider content-position="left">团队负责人(当前用户)</el-divider>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="负责人姓名" prop="presidentStudent">
|
||||
<StudentSelector
|
||||
v-model="registerForm.presidentStudent"
|
||||
placeholder="请选择团队负责人"
|
||||
:showStudentNo="false"
|
||||
@change="handlePresidentChange"
|
||||
/>
|
||||
<el-form-item label="负责人姓名" prop="studentName">
|
||||
<el-input v-model="registerForm.studentName" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -314,6 +336,7 @@
|
||||
|
||||
<script setup name="StglActivityRegisterHall" lang="ts">
|
||||
import { nextTick } from 'vue';
|
||||
import { CircleCheck, Clock } from '@element-plus/icons-vue';
|
||||
import {
|
||||
listRegistrableActivities,
|
||||
getActivityDetail,
|
||||
@@ -322,7 +345,7 @@ import {
|
||||
getMyRegistrations
|
||||
} from '@/api/stgl/activityregisterhall';
|
||||
import { StglActivityVO, StglActivityQuery } from '@/api/stgl/activity/types';
|
||||
import { StglActivityRegistrationForm, TeamMemberInfo } from '@/api/stgl/activityregisterhall/types';
|
||||
import { StglActivityRegistrationForm, TeamMemberInfo, StglActivityVo } from '@/api/stgl/activityregisterhall/types';
|
||||
import ActivityDetailView from '@/views/stgl/activity/components/ActivityDetailView.vue';
|
||||
import TeamMemberManager from '@/components/TeamMemberManager/index.vue';
|
||||
import VicePresidentManager from '@/components/VicePresidentManager/index.vue';
|
||||
@@ -331,13 +354,15 @@ import { getPersonalInfo } from '@/api/xg/xsjcxx/studentMsg/studentMsg/index';
|
||||
import type { StudentMsgForm } from '@/api/xg/xsjcxx/studentMsg/studentMsg/types';
|
||||
import { StudentVO } from '@/api/xg/student/types';
|
||||
import { VicePresidentVO } from '@/components/VicePresidentManager/index.vue';
|
||||
import { getUser } from '@/api/system/user';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { stgl_activity_type, stgl_registration_type, stgl_registration_status } = toRefs<any>(
|
||||
proxy?.useDict('stgl_activity_type', 'stgl_registration_type', 'stgl_registration_status')
|
||||
);
|
||||
|
||||
const activityList = ref<StglActivityVO[]>([]);
|
||||
// 修改类型定义,使用后端返回的StglActivityVo类型
|
||||
const activityList = ref<StglActivityVo[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
@@ -356,8 +381,8 @@ const registerDialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const selectedActivity = ref<StglActivityVO>({} as StglActivityVO);
|
||||
const viewForm = ref<StglActivityVO>({} as StglActivityVO);
|
||||
const selectedActivity = ref<StglActivityVo>({} as StglActivityVo);
|
||||
const viewForm = ref<StglActivityVo>({} as StglActivityVo);
|
||||
|
||||
// 用户报名状态缓存
|
||||
const userRegistrationStatus = ref<Record<number, boolean>>({});
|
||||
@@ -469,7 +494,7 @@ const resetQuery = () => {
|
||||
};
|
||||
|
||||
/** 查看按钮操作 */
|
||||
const handleView = async (row: StglActivityVO) => {
|
||||
const handleView = async (row: StglActivityVo) => {
|
||||
const res = await getActivityDetail(row.id);
|
||||
viewForm.value = res.data;
|
||||
viewDialog.visible = true;
|
||||
@@ -477,7 +502,7 @@ const handleView = async (row: StglActivityVO) => {
|
||||
};
|
||||
|
||||
/** 报名按钮操作 */
|
||||
const handleRegister = async (row: StglActivityVO) => {
|
||||
const handleRegister = async (row: StglActivityVo) => {
|
||||
selectedActivity.value = row;
|
||||
resetRegisterForm();
|
||||
|
||||
@@ -547,16 +572,28 @@ const handleRegistrationTypeChange = async (value: number) => {
|
||||
// 自动填充当前用户信息
|
||||
await loadUserInfoToForm();
|
||||
} else if (value === 2) {
|
||||
// 团队报名,清空个人信息,让用户选择团队负责人
|
||||
registerForm.studentName = undefined;
|
||||
registerForm.studentNo = undefined;
|
||||
registerForm.gender = undefined;
|
||||
registerForm.phone = undefined;
|
||||
registerForm.email = undefined;
|
||||
registerForm.department = undefined;
|
||||
registerForm.major = undefined;
|
||||
registerForm.className = undefined;
|
||||
registerForm.presidentStudent = null;
|
||||
// 团队报名,自动填充当前用户信息作为团队负责人
|
||||
await loadUserInfoToForm();
|
||||
|
||||
// 设置团队负责人为学生对象(用于StudentSelector组件)
|
||||
// 使用类型断言避免类型错误,因为我们只需要这些字段用于显示
|
||||
registerForm.presidentStudent = {
|
||||
id: 0, // 临时ID,实际提交时不需要
|
||||
name: registerForm.studentName || '',
|
||||
studentNo: registerForm.studentNo || '',
|
||||
gender: registerForm.gender || '',
|
||||
phone: registerForm.phone || '',
|
||||
email: registerForm.email || '',
|
||||
collegeId: '', // 必需的字段
|
||||
collegeName: registerForm.department || '',
|
||||
majorId: '', // 必需的字段
|
||||
majorName: registerForm.major || '',
|
||||
classId: '', // 必需的字段
|
||||
className: registerForm.className || '',
|
||||
grade: '', // 必需的字段
|
||||
studentStatus: '', // 必需的字段
|
||||
enrollmentYear: 0 // 必需的字段
|
||||
} as StudentVO;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -572,8 +609,14 @@ const handlePresidentChange = async (student: StudentVO | null) => {
|
||||
registerForm.major = student.majorName || '';
|
||||
registerForm.className = student.className || '';
|
||||
|
||||
// 清空email,让用户手动填写或通过其他方式获取
|
||||
registerForm.email = undefined;
|
||||
// 获取用户邮箱
|
||||
try {
|
||||
const userRes = await getUser(student.id);
|
||||
registerForm.email = userRes.data?.user?.email || '';
|
||||
} catch (error) {
|
||||
console.error('获取用户邮箱失败:', error);
|
||||
registerForm.email = ''; // 设置为空,让用户手动填写或通过其他方式获取
|
||||
}
|
||||
} else {
|
||||
// 清空负责人信息
|
||||
registerForm.studentName = undefined;
|
||||
@@ -598,7 +641,7 @@ const handleTeamMembersNewChange = (members: VicePresidentVO[]) => {
|
||||
studentName: member.name || member.student?.name || '',
|
||||
gender: member.student?.gender || '',
|
||||
phone: member.phone || member.student?.phone || '',
|
||||
email: '', // VicePresidentVO可能没有email字段
|
||||
email: '', // VicePresidentVO没有email字段,设置为空
|
||||
department: member.dept || member.student?.collegeName || '',
|
||||
major: member.major || member.student?.majorName || '',
|
||||
className: member.class || member.student?.className || '',
|
||||
@@ -663,6 +706,15 @@ const submitRegister = () => {
|
||||
remark: registerForm.remark
|
||||
};
|
||||
|
||||
// 根据活动的审核设置自动设置报名状态
|
||||
// 如果活动设置为不需要审核(needApproval = 0),则自动设置为通过状态(approvalStatus = 1)
|
||||
// 如果活动设置为需要审核(needApproval = 1),则保持默认的待审核状态(approvalStatus = 0)
|
||||
if (selectedActivity.value.needApproval === 0) {
|
||||
submitData.approvalStatus = 1; // 自动通过
|
||||
} else {
|
||||
submitData.approvalStatus = 0; // 待审核
|
||||
}
|
||||
|
||||
// 只有团队报名时才发送团队相关字段
|
||||
if (registerForm.registrationType === 2) {
|
||||
submitData.teamName = registerForm.teamName;
|
||||
@@ -678,7 +730,14 @@ const submitRegister = () => {
|
||||
// 个人报名时不发送任何团队相关字段
|
||||
|
||||
await registerActivity(submitData);
|
||||
proxy?.$modal.msgSuccess('报名成功,请等待审核');
|
||||
|
||||
// 根据审核设置显示不同的成功消息
|
||||
if (selectedActivity.value.needApproval === 0) {
|
||||
proxy?.$modal.msgSuccess('报名成功!您的报名已自动通过审核');
|
||||
} else {
|
||||
proxy?.$modal.msgSuccess('报名成功,请等待审核');
|
||||
}
|
||||
|
||||
registerDialog.visible = false;
|
||||
|
||||
// 更新报名状态
|
||||
@@ -695,13 +754,13 @@ const submitRegister = () => {
|
||||
};
|
||||
|
||||
/** 判断是否可以报名 */
|
||||
const canRegister = (activity: StglActivityVO): boolean => {
|
||||
const canRegister = (activity: StglActivityVo): boolean => {
|
||||
// 报名状态为0(未开始)或1(报名中),且用户未报名
|
||||
return [0, 1].includes(activity.registrationStatus || 0) && !isRegistered(activity);
|
||||
};
|
||||
|
||||
/** 判断用户是否已报名 */
|
||||
const isRegistered = (activity: StglActivityVO): boolean => {
|
||||
const isRegistered = (activity: StglActivityVo): boolean => {
|
||||
return userRegistrationStatus.value[activity.id as number] || false;
|
||||
};
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="关联社团" prop="relatedClubId">
|
||||
<el-form-item label="关联社团/队伍" prop="relatedClubId">
|
||||
<ClubSelector v-model="queryParams.relatedClub" @change="handleQueryRelatedClubChange" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -125,7 +125,7 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="主办方" align="center" prop="organizerName" width="120" show-overflow-tooltip />
|
||||
<el-table-column label="关联社团" align="center" width="120" show-overflow-tooltip>
|
||||
<el-table-column label="关联社团/队伍" align="center" width="120" show-overflow-tooltip>
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.relatedClubName">{{ scope.row.relatedClubName }}</span>
|
||||
<span v-else class="text-gray-400">未关联</span>
|
||||
@@ -270,7 +270,7 @@
|
||||
v-hasPermi="['stgl:activity:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="成员审核" placement="top">
|
||||
<el-tooltip content="报名管理" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="info"
|
||||
@@ -358,7 +358,7 @@
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="关联社团" prop="relatedClubId">
|
||||
<el-form-item label="关联社团/队伍" prop="relatedClubId">
|
||||
<ClubSelector v-model="form.relatedClub" @change="handleRelatedClubChange" :disabled="isRelatedClubDisabled" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -407,7 +407,8 @@
|
||||
<AdvisorManager
|
||||
:key="`advisor-manager-${form.id || 'new'}-${formKey}`"
|
||||
v-model="form.advisors"
|
||||
@change="handleAdvisorsChange"
|
||||
@change="handleAdvisorsChange"
|
||||
:initial-advisors="form.advisors"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
@@ -707,7 +708,7 @@ const initFormData: StglActivityForm = {
|
||||
coOrganizerList: [],
|
||||
coOrganizers: undefined,
|
||||
instructorList: [],
|
||||
instructors: undefined,
|
||||
instructors: '[]',
|
||||
advisors: [],
|
||||
registrationType: undefined,
|
||||
registrationStart: undefined,
|
||||
@@ -864,31 +865,37 @@ const cancel = () => {
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
// 使用nextTick来避免递归更新
|
||||
nextTick(() => {
|
||||
form.value = { ...initFormData };
|
||||
// 确保指导老师字段被正确初始化
|
||||
form.value.advisors = [];
|
||||
form.value.instructorList = [];
|
||||
form.value.instructors = undefined;
|
||||
|
||||
// 重置关联社团禁用状态
|
||||
isRelatedClubDisabled.value = false;
|
||||
|
||||
// 重置审批表单
|
||||
approveForm.id = undefined;
|
||||
approveForm.activityName = '';
|
||||
approveForm.approvalResult = 'approve';
|
||||
approveForm.rejectReason = '';
|
||||
|
||||
// 更新formKey以强制重新渲染组件
|
||||
formKey.value++;
|
||||
|
||||
activeTab.value = 'basic';
|
||||
nextTick(() => {
|
||||
activityFormRef.value?.resetFields();
|
||||
});
|
||||
// 直接重置,避免使用nextTick导致的递归更新
|
||||
form.value = { ...initFormData };
|
||||
// 确保指导老师字段被正确初始化
|
||||
form.value.advisors = [];
|
||||
form.value.instructorList = [];
|
||||
form.value.instructors = '[]';
|
||||
|
||||
// 重置关联社团禁用状态
|
||||
isRelatedClubDisabled.value = false;
|
||||
|
||||
// 重置审批表单
|
||||
approveForm.id = undefined;
|
||||
approveForm.activityName = '';
|
||||
approveForm.approvalResult = 'approve';
|
||||
approveForm.rejectReason = '';
|
||||
|
||||
// 更新formKey以强制重新渲染组件
|
||||
formKey.value++;
|
||||
|
||||
activeTab.value = 'basic';
|
||||
|
||||
console.log('表单重置后的状态:', {
|
||||
advisors: form.value.advisors,
|
||||
instructorList: form.value.instructorList,
|
||||
instructors: form.value.instructors
|
||||
});
|
||||
|
||||
// 延迟重置表单字段,避免递归更新
|
||||
setTimeout(() => {
|
||||
activityFormRef.value?.resetFields();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@@ -921,7 +928,7 @@ const handleAdd = () => {
|
||||
// 确保指导老师字段被正确初始化
|
||||
form.value.advisors = [];
|
||||
form.value.instructorList = [];
|
||||
form.value.instructors = undefined;
|
||||
form.value.instructors = '[]';
|
||||
|
||||
// 更新formKey以强制重新渲染组件
|
||||
formKey.value++;
|
||||
@@ -1038,8 +1045,25 @@ const handleUpdate = async (row?: StglActivityVO) => {
|
||||
// 处理AdvisorManager组件的指导老师数据
|
||||
if (res.data.instructors) {
|
||||
try {
|
||||
(res.data as any).advisors = JSON.parse(res.data.instructors);
|
||||
const instructorsData = JSON.parse(res.data.instructors);
|
||||
console.log('解析的指导老师数据:', instructorsData);
|
||||
|
||||
// 确保数据格式正确
|
||||
if (Array.isArray(instructorsData)) {
|
||||
(res.data as any).advisors = instructorsData.map((advisor: any) => ({
|
||||
...advisor,
|
||||
// 确保必要字段存在
|
||||
name: advisor.name || advisor.teacher?.nickName || '',
|
||||
dept: advisor.dept || advisor.teacher?.deptName || '',
|
||||
phone: advisor.phone || advisor.teacher?.phonenumber || '',
|
||||
email: advisor.email || advisor.teacher?.email || '',
|
||||
userId: advisor.userId || advisor.teacher?.userId || ''
|
||||
}));
|
||||
} else {
|
||||
(res.data as any).advisors = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('解析指导老师JSON数据失败:', error);
|
||||
(res.data as any).advisors = [];
|
||||
}
|
||||
} else {
|
||||
@@ -1047,6 +1071,17 @@ const handleUpdate = async (row?: StglActivityVO) => {
|
||||
}
|
||||
|
||||
Object.assign(form.value, res.data);
|
||||
|
||||
// 确保指导老师数据正确设置
|
||||
console.log('修改活动 - 设置表单数据后的状态:', {
|
||||
advisors: form.value.advisors,
|
||||
instructorList: form.value.instructorList,
|
||||
instructors: form.value.instructors
|
||||
});
|
||||
|
||||
// 更新formKey以强制重新渲染组件
|
||||
formKey.value++;
|
||||
|
||||
dialog.visible = true;
|
||||
dialog.title = '修改活动信息';
|
||||
};
|
||||
@@ -1059,6 +1094,12 @@ const submitForm = () => {
|
||||
|
||||
// 准备提交的数据
|
||||
const submitData = { ...form.value } as any;
|
||||
|
||||
console.log('提交前 - 原始表单数据:', {
|
||||
advisors: submitData.advisors,
|
||||
instructorList: submitData.instructorList,
|
||||
instructors: submitData.instructors
|
||||
});
|
||||
|
||||
// 新增时自动设置活动状态为0(草稿)
|
||||
if (!submitData.id) {
|
||||
@@ -1085,64 +1126,36 @@ const submitForm = () => {
|
||||
// 处理承办方数据
|
||||
if (submitData.coOrganizerList && submitData.coOrganizerList.length > 0) {
|
||||
submitData.coOrganizers = JSON.stringify(submitData.coOrganizerList);
|
||||
} else {
|
||||
submitData.coOrganizers = '[]'; // 修复:使用空JSON数组而不是undefined
|
||||
}
|
||||
|
||||
// 处理指导老师数据
|
||||
if (submitData.instructorList && submitData.instructorList.length > 0) {
|
||||
submitData.instructors = JSON.stringify(submitData.instructorList);
|
||||
}
|
||||
|
||||
// 处理AdvisorManager组件的指导老师数据
|
||||
if (submitData.advisors && submitData.advisors.length > 0) {
|
||||
console.log('提交前 - 原始advisors数据:', submitData.advisors);
|
||||
|
||||
// 确保advisors数据完整
|
||||
submitData.advisors = submitData.advisors.map((advisor: any) => {
|
||||
const processedAdvisor = {
|
||||
...advisor,
|
||||
name: advisor.name || advisor.teacher?.nickName || '',
|
||||
dept: advisor.dept || advisor.teacher?.deptName || '',
|
||||
phone: advisor.phone || advisor.teacher?.phonenumber || '',
|
||||
email: advisor.email || advisor.teacher?.email || ''
|
||||
};
|
||||
console.log('处理后的指导老师数据:', processedAdvisor);
|
||||
return processedAdvisor;
|
||||
});
|
||||
|
||||
submitData.instructors = JSON.stringify(submitData.advisors);
|
||||
console.log('提交的指导老师JSON数据:', submitData.instructors);
|
||||
|
||||
// 同步第一个指导老师信息到instructorList(保持兼容性)
|
||||
if (submitData.advisors.length > 0) {
|
||||
submitData.instructorList = submitData.advisors.map((advisor: any) => ({
|
||||
name: advisor.name,
|
||||
dept: advisor.dept,
|
||||
phone: advisor.phone,
|
||||
email: advisor.email
|
||||
}));
|
||||
console.log('同步的instructorList数据:', submitData.instructorList);
|
||||
}
|
||||
} else {
|
||||
console.log('提交时 - 没有指导老师数据或数据为空');
|
||||
submitData.instructors = '[]';
|
||||
submitData.advisors = [];
|
||||
submitData.instructors = '';
|
||||
submitData.instructorList = [];
|
||||
}
|
||||
|
||||
try {
|
||||
if (form.value.id) {
|
||||
await updateStglActivity(submitData);
|
||||
} else {
|
||||
await addStglActivity(submitData);
|
||||
try {
|
||||
if (form.value.id) {
|
||||
await updateStglActivity(submitData);
|
||||
} else {
|
||||
await addStglActivity(submitData);
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
|
||||
// 提交成功后重置表单
|
||||
reset();
|
||||
|
||||
await getList();
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
proxy?.$modal.msgSuccess('操作成功');
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error);
|
||||
} finally {
|
||||
buttonLoading.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1220,7 +1233,9 @@ const confirmCopy = async () => {
|
||||
try {
|
||||
await copyStglActivity({
|
||||
sourceId: copyForm.sourceId!,
|
||||
newActivityName: copyForm.newActivityName
|
||||
newActivityName: copyForm.newActivityName,
|
||||
activityStatus: '0', // 复制后的活动状态设置为0(草稿)
|
||||
registrationStatus: '0' // 复制后的报名状态设置为0(未开始)
|
||||
});
|
||||
proxy?.$modal.msgSuccess('复制成功');
|
||||
copyDialog.visible = false;
|
||||
@@ -1361,9 +1376,7 @@ const handleInstructorsChange = (instructors: InstructorInfo[]) => {
|
||||
|
||||
/** 指导老师变化处理 */
|
||||
const handleAdvisorsChange = (advisors: AdvisorVO[]) => {
|
||||
console.log('handleAdvisorsChange - 指导老师数据变化:', advisors);
|
||||
form.value.advisors = advisors;
|
||||
console.log('handleAdvisorsChange - 更新后的form.advisors:', form.value.advisors);
|
||||
};
|
||||
|
||||
/** 报名方式变化处理 */
|
||||
@@ -1479,11 +1492,11 @@ const confirmApprove = async () => {
|
||||
const endTime = new Date(activity.endTime);
|
||||
|
||||
if (now < startTime) {
|
||||
newStatus = '1'; // 未开始
|
||||
newStatus = '3'; // 已通过(活动还未开始)
|
||||
} else if (now >= startTime && now <= endTime) {
|
||||
newStatus = '4'; // 进行中
|
||||
newStatus = '4'; // 进行中(活动正在进行)
|
||||
} else {
|
||||
newStatus = '5'; // 已结束
|
||||
newStatus = '5'; // 已结束(活动已结束)
|
||||
}
|
||||
successMessage = '审批通过';
|
||||
} else {
|
||||
@@ -1586,6 +1599,11 @@ const hasActivityOperationPermission = (activity: StglActivityVO): boolean => {
|
||||
return activity.createBy === userStore.userId;
|
||||
}
|
||||
|
||||
// 志愿者队长只能操作自己创建的活动
|
||||
if (proxy?.$auth.hasRole('stgl_volunteer_captain')) {
|
||||
return activity.createBy === userStore.userId;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -52,14 +52,6 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="我的社团" name="my">
|
||||
<template #label>
|
||||
<span class="tab-label">
|
||||
<i class="el-icon-user-solid"></i>
|
||||
我的社团
|
||||
</span>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
@@ -462,7 +454,7 @@
|
||||
|
||||
<script setup name="StglRegister" lang="ts">
|
||||
import { Document } from '@element-plus/icons-vue';
|
||||
import { listStglClubRegister, listMyClubs, applyJoinClub, quitClub } from '@/api/stgl/register';
|
||||
import { listStglClubRegister, applyJoinClub, quitClub } from '@/api/stgl/register';
|
||||
import { StglClubRegisterVO, StglClubRegisterQuery, StglRegisterForm } from '@/api/stgl/register/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@@ -473,7 +465,7 @@ const selectedClub = ref<StglClubRegisterVO | null>(null);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
const activeTab = ref('all');
|
||||
const activeTab = ref('all'); // 固定为社团大厅
|
||||
const viewMode = ref('card');
|
||||
const applyLoading = ref(false);
|
||||
const charterDownloading = ref(false); // 新增:章程下载加载状态
|
||||
@@ -530,15 +522,7 @@ const getRoleTagType = (roleType: number): 'success' | 'warning' | 'info' | 'pri
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
let res;
|
||||
switch (activeTab.value) {
|
||||
case 'my':
|
||||
res = await listMyClubs(queryParams);
|
||||
break;
|
||||
default:
|
||||
res = await listStglClubRegister(queryParams);
|
||||
break;
|
||||
}
|
||||
const res = await listStglClubRegister(queryParams);
|
||||
clubList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} catch (error) {
|
||||
@@ -564,9 +548,8 @@ const resetQuery = () => {
|
||||
|
||||
/** 标签页切换 */
|
||||
const handleTabChange = (tabName: string) => {
|
||||
// 由于只有一个标签页,此函数可以简化或移除
|
||||
activeTab.value = tabName;
|
||||
queryParams.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 查看详情 */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="联系方式" prop="phone" style="margin-bottom: 0">
|
||||
<el-form-item label="联系方式" prop="params.phone" style="margin-bottom: 0">
|
||||
<el-input v-model="queryParams.params.phone" placeholder="请输入联系方式" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -486,7 +486,14 @@ const getList = async () => {
|
||||
delete queryData.status; // 删除单个status字段
|
||||
}
|
||||
|
||||
// 确保phone参数正确传递到params中
|
||||
if (queryData.params.phone) {
|
||||
// 保持phone参数在params中,后端会从params中读取
|
||||
console.log('JoinedMembersTab: phone参数:', queryData.params.phone);
|
||||
}
|
||||
|
||||
console.log('JoinedMembersTab: 最终查询参数:', queryData);
|
||||
console.log('JoinedMembersTab: phone参数值:', queryData.params?.phone);
|
||||
|
||||
const res = await listStglMember(queryData);
|
||||
console.log('JoinedMembersTab: 查询结果:', res);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="联系方式" prop="phone" style="margin-bottom: 0;">
|
||||
<el-form-item label="联系方式" prop="params.phone" style="margin-bottom: 0;">
|
||||
<el-input v-model="queryParams.params.phone" placeholder="请输入联系方式" clearable size="small" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -290,7 +290,14 @@ const getList = async () => {
|
||||
delete queryData.status; // 删除单个status字段
|
||||
}
|
||||
|
||||
// 确保phone参数正确传递到params中
|
||||
if (queryData.params.phone) {
|
||||
// 保持phone参数在params中,后端会从params中读取
|
||||
console.log('PendingMembersTab: phone参数:', queryData.params.phone);
|
||||
}
|
||||
|
||||
console.log('PendingMembersTab: 最终查询参数:', queryData);
|
||||
console.log('PendingMembersTab: phone参数值:', queryData.params?.phone);
|
||||
|
||||
const res = await listStglMember(queryData);
|
||||
console.log('PendingMembersTab: 查询结果:', res);
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<!-- 隐藏是否评分过滤条件 -->
|
||||
<!-- <el-col :span="6">
|
||||
<el-form-item label="是否评分" prop="isRated">
|
||||
<el-select
|
||||
v-model="queryParams.isRated"
|
||||
@@ -41,7 +42,7 @@
|
||||
<el-option label="未评分" value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
@@ -103,6 +104,16 @@
|
||||
<span>{{ parseTime(scope.row.myRegistrationTime, '{y}-{m}-{d} {h}:{i}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="报名状态" align="center" prop="myRegistrationStatus" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="scope.row.myRegistrationStatus === '1' ? 'success' : scope.row.myRegistrationStatus === '2' ? 'danger' : 'warning'"
|
||||
size="small"
|
||||
>
|
||||
{{ scope.row.myRegistrationStatus === '1' ? '已通过' : scope.row.myRegistrationStatus === '2' ? '已拒绝' : '待审核' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="我的评分" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.myRatingStatus === 1" class="rating-cell">
|
||||
@@ -160,9 +171,10 @@
|
||||
</el-card>
|
||||
|
||||
<!-- 查看活动详情对话框 -->
|
||||
<el-dialog title="活动详情" v-model="detailOpen" width="1000px" append-to-body>
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="基本信息">
|
||||
<el-dialog title="活动详情" v-model="detailOpen" width="1000px" append-to-body @close="handleDetailClose">
|
||||
<div class="detail-content">
|
||||
<!-- 基本信息 -->
|
||||
<div class="detail-section">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="活动名称">{{ detailForm.activityName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="活动类型">
|
||||
@@ -170,6 +182,7 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="活动主题">{{ detailForm.activityTheme || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="主办方">{{ detailForm.organizerName || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="承办方">{{ detailForm.undertakerName || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联组织">
|
||||
<span v-if="detailForm.organizationName">
|
||||
{{ detailForm.organizationName }}
|
||||
@@ -179,6 +192,12 @@
|
||||
</span>
|
||||
<span v-else>未关联</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师">
|
||||
<span v-if="detailForm.instructors && detailForm.instructors.length > 0">
|
||||
{{ getInstructorNames(detailForm.instructors) }}
|
||||
</span>
|
||||
<span v-else>暂无</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="活动地点">{{ detailForm.location || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开始时间">{{ parseTime(detailForm.startTime, '{y}-{m}-{d} {h}:{i}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结束时间">{{ parseTime(detailForm.endTime, '{y}-{m}-{d} {h}:{i}') }}</el-descriptions-item>
|
||||
@@ -188,17 +207,9 @@
|
||||
<el-descriptions-item label="报名状态">
|
||||
<dict-tag :options="stgl_registration_status" :value="detailForm.registrationStatus" />
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="我的报名信息">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="报名时间">{{ parseTime(detailForm.myRegistrationTime, '{y}-{m}-{d} {h}:{i}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="报名状态">
|
||||
<dict-tag :options="stgl_my_registration_status" :value="detailForm.myRegistrationStatus" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="评分状态">
|
||||
<el-tag v-if="detailForm.myRatingStatus === 1" type="success">已评分</el-tag>
|
||||
<el-tag v-else type="info">未评分</el-tag>
|
||||
<el-descriptions-item label="报名类型">
|
||||
<dict-tag :options="stgl_registration_type" :value="detailForm.registrationType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="我的评分" v-if="detailForm.myRatingStatus === 1">
|
||||
<div class="rating-cell">
|
||||
@@ -213,19 +224,111 @@
|
||||
<span class="rating-text">{{ detailForm.averageRating?.toFixed(1) }}</span>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="活动简介" :span="2">
|
||||
<div class="view-description">
|
||||
{{ detailForm.description || '暂无简介' }}
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="活动海报" v-if="detailForm.posterUrl">
|
||||
</div>
|
||||
|
||||
<!-- 活动海报 -->
|
||||
<div v-if="detailForm.posterUrl" class="detail-section">
|
||||
<h3 class="section-title">活动海报</h3>
|
||||
<div class="view-poster">
|
||||
<image-preview :src="detailForm.posterUrl" :width="300" :height="400" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="活动简介">
|
||||
<div class="view-description">
|
||||
{{ detailForm.description || '暂无简介' }}
|
||||
</div>
|
||||
|
||||
<!-- 我的队伍信息 -->
|
||||
<div v-if="detailForm.registrationType === '2'" class="detail-section">
|
||||
<h3 class="section-title">我的队伍信息</h3>
|
||||
<div v-if="teamInfoLoading" class="loading-container">
|
||||
<el-skeleton :rows="3" animated />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div v-else-if="teamInfo" class="team-info-content">
|
||||
<!-- 队伍基本信息 -->
|
||||
<el-descriptions :column="2" border class="team-basic-info">
|
||||
<el-descriptions-item label="队伍名称" class="team-name-col">
|
||||
<template #label>
|
||||
<span class="team-name-label">队伍名称</span>
|
||||
</template>
|
||||
<span class="team-name-value">{{ teamInfo.teamName }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="团队人数" class="team-size-col">{{ teamInfo.teamSize }}人</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 队长详细信息 -->
|
||||
<div class="team-leader-section">
|
||||
<h4 class="subsection-title">队长信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="姓名">{{ teamInfo.leaderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="学号">{{ teamInfo.leaderStudentNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="院系">{{ teamInfo.leaderDepartment || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="专业">{{ teamInfo.leaderMajor || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="班级">{{ teamInfo.leaderClassName || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ teamInfo.leaderPhone || '暂无' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="邮箱" :span="2">{{ teamInfo.leaderEmail || '暂无' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 队员详细信息 -->
|
||||
<div v-if="parseTeamMembers(teamInfo.teamMembers).length > 0" class="team-members-section">
|
||||
<h4 class="subsection-title">队员信息</h4>
|
||||
<el-table :data="parseTeamMembers(teamInfo.teamMembers)" border stripe size="small" class="members-table">
|
||||
<el-table-column label="姓名" prop="studentName" align="center" width="100" />
|
||||
<el-table-column label="学号" prop="studentNo" align="center" width="120" />
|
||||
<el-table-column label="院系" prop="department" align="center" min-width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.department || '暂无' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="专业" prop="major" align="center" min-width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.major || '暂无' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="班级" prop="className" align="center" width="100" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.className || '暂无' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系电话" prop="phone" align="center" width="120" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.phone || '暂无' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="邮箱" prop="email" align="center" min-width="150" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.email || '暂无' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="身份" align="center" width="80">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="row.isLeader === 1 ? 'success' : 'info'"
|
||||
size="small"
|
||||
>
|
||||
{{ row.isLeader === 1 ? '队长' : '队员' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else class="no-members">
|
||||
<el-empty description="暂无队员信息" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-team-info">
|
||||
<el-empty description="未找到队伍信息" :image-size="60">
|
||||
<el-button type="primary" size="small" @click="getTeamInfo(detailForm.id)">
|
||||
重新获取
|
||||
</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="detailOpen = false">关 闭</el-button>
|
||||
@@ -279,7 +382,15 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 签到对话框 -->
|
||||
<el-dialog title="活动签到" v-model="attendanceOpen" width="560px" append-to-body>
|
||||
<el-dialog
|
||||
title="活动签到"
|
||||
v-model="attendanceOpen"
|
||||
width="560px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="true"
|
||||
class="attendance-dialog"
|
||||
>
|
||||
<div class="attendance-content">
|
||||
<div class="attendance-actions">
|
||||
<el-button
|
||||
@@ -306,7 +417,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 签到记录 -->
|
||||
<div class="attendance-records">
|
||||
<div class="attendance-records" v-if="attendanceRecords.length > 0">
|
||||
<div class="records-header">
|
||||
<span class="records-title">签到记录</span>
|
||||
<el-button
|
||||
@@ -325,6 +436,7 @@
|
||||
size="small"
|
||||
class="records-table"
|
||||
v-loading="recordsLoading"
|
||||
:max-height="getTableMaxHeight()"
|
||||
>
|
||||
<el-table-column prop="signInTime" label="签到时间" width="200">
|
||||
<template #default="{ row }">
|
||||
@@ -348,10 +460,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-if="attendanceRecords.length === 0" class="no-records">
|
||||
<el-empty description="暂无签到记录" :image-size="60" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
@@ -359,25 +467,29 @@
|
||||
</template>
|
||||
|
||||
<script setup name="MyActivity" lang="ts">
|
||||
import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, computed, nextTick } from 'vue';
|
||||
import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, computed, nextTick, onMounted } from 'vue';
|
||||
import { getMyActivities, rateActivity } from '@/api/stgl/my';
|
||||
import type { MyActivityVO, ActivityRatingForm, MyActivityQuery } from '@/api/stgl/my/types';
|
||||
import { Calendar, Location, Clock, Check, Close } from '@element-plus/icons-vue';
|
||||
import { getInfo } from '@/api/login'; // 添加获取用户详细信息的API
|
||||
import request from '@/utils/request';
|
||||
import type { FormInstance } from 'element-plus';
|
||||
import { getTeamsByActivityId } from '@/api/stgl/activityteaminfo';
|
||||
import type { StglActivityTeamInfoVo } from '@/api/stgl/activityteaminfo/types';
|
||||
import { listActivityRegister } from '@/api/stgl/activityregister'; // 添加获取报名记录的API
|
||||
import { listStglActivity } from '@/api/stgl/activity'; // 添加获取所有活动的API
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { stgl_activity_type, stgl_activity_status, stgl_registration_status, stgl_my_registration_status } = toRefs<any>(
|
||||
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_status', 'stgl_my_registration_status')
|
||||
const { stgl_activity_type, stgl_activity_status, stgl_registration_status, stgl_registration_type } = toRefs<any>(
|
||||
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_status', 'stgl_registration_type')
|
||||
);
|
||||
|
||||
const queryRef = ref();
|
||||
const showSearch = ref(true);
|
||||
const queryParams = ref<MyActivityQuery>({
|
||||
activityName: '',
|
||||
activityType: '',
|
||||
isRated: ''
|
||||
activityType: ''
|
||||
// isRated: '' // 已隐藏是否评分过滤条件
|
||||
});
|
||||
const activityList = ref<MyActivityVO[]>([]);
|
||||
const loading = ref(true);
|
||||
@@ -387,6 +499,10 @@ const ratingOpen = ref(false);
|
||||
const ratingLoading = ref(false);
|
||||
const ratingFormRef = ref<FormInstance>();
|
||||
|
||||
// 新增队伍信息相关变量
|
||||
const teamInfo = ref<StglActivityTeamInfoVo | null>(null);
|
||||
const teamInfoLoading = ref(false);
|
||||
|
||||
const ratingForm = ref<ActivityRatingForm & { activityName?: string; studentName?: string; studentNo?: string }>({
|
||||
activityId: '',
|
||||
contentScore: 0,
|
||||
@@ -433,8 +549,29 @@ const getList = async () => {
|
||||
const params = Object.fromEntries(
|
||||
Object.entries(queryParams.value).filter(([_, value]) => value !== '' && value !== undefined && value !== null)
|
||||
);
|
||||
|
||||
// 直接使用getMyActivities接口,后端已经处理了所有情况(包括用户作为队员参与的活动)
|
||||
const res = await getMyActivities(params);
|
||||
activityList.value = res.data;
|
||||
const activities = res.data || [];
|
||||
|
||||
// 按报名时间排序
|
||||
activities.sort((a, b) => {
|
||||
const timeA = a.myRegistrationTime ? new Date(a.myRegistrationTime).getTime() : 0;
|
||||
const timeB = b.myRegistrationTime ? new Date(b.myRegistrationTime).getTime() : 0;
|
||||
return timeB - timeA; // 降序排列
|
||||
});
|
||||
|
||||
activityList.value = activities;
|
||||
|
||||
console.log('我的活动列表数据:', {
|
||||
totalCount: activities.length,
|
||||
activities: activities.map(activity => ({
|
||||
id: activity.id,
|
||||
activityName: activity.activityName,
|
||||
registrationType: activity.registrationType,
|
||||
myRegistrationStatus: activity.myRegistrationStatus
|
||||
}))
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('查询我的活动列表失败:', error);
|
||||
proxy?.$modal.msgError('查询我的活动列表失败');
|
||||
@@ -443,6 +580,8 @@ const getList = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
getList();
|
||||
@@ -455,11 +594,95 @@ const resetQuery = () => {
|
||||
};
|
||||
|
||||
/** 查看详情按钮操作 */
|
||||
const handleView = (row: MyActivityVO) => {
|
||||
const handleView = async (row: MyActivityVO) => {
|
||||
detailForm.value = { ...row };
|
||||
detailOpen.value = true;
|
||||
|
||||
// 如果是团队报名,获取队伍信息
|
||||
if (row.registrationType === '2') {
|
||||
await getTeamInfo(row.id);
|
||||
} else {
|
||||
teamInfo.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
/** 获取队伍信息 */
|
||||
const getTeamInfo = async (activityId: string | number) => {
|
||||
if (!activityId) return;
|
||||
|
||||
teamInfoLoading.value = true;
|
||||
try {
|
||||
const res = await getTeamsByActivityId(activityId);
|
||||
if (res.data && res.data.length > 0) {
|
||||
// 找到当前用户所在的队伍
|
||||
const userInfo = await getCurrentUserDetailInfo();
|
||||
if (!userInfo) {
|
||||
console.warn('未获取到用户信息');
|
||||
teamInfo.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const currentUserTeam = res.data.find((team: StglActivityTeamInfoVo) => {
|
||||
// 检查是否为队长
|
||||
if (team.leaderStudentNo === userInfo.userName) {
|
||||
return true;
|
||||
}
|
||||
// 检查是否为队员
|
||||
if (team.teamMembers) {
|
||||
try {
|
||||
const members = JSON.parse(team.teamMembers);
|
||||
return members.some((member: any) => member.studentNo === userInfo.userName);
|
||||
} catch (error) {
|
||||
console.error('解析队员信息失败:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
teamInfo.value = currentUserTeam || null;
|
||||
|
||||
if (currentUserTeam) {
|
||||
console.log('获取到队伍信息:', {
|
||||
teamName: currentUserTeam.teamName,
|
||||
leaderName: currentUserTeam.leaderName,
|
||||
leaderStudentNo: currentUserTeam.leaderStudentNo,
|
||||
leaderPhone: currentUserTeam.leaderPhone,
|
||||
leaderEmail: currentUserTeam.leaderEmail,
|
||||
leaderDepartment: currentUserTeam.leaderDepartment,
|
||||
leaderMajor: currentUserTeam.leaderMajor,
|
||||
leaderClassName: currentUserTeam.leaderClassName,
|
||||
teamMembers: currentUserTeam.teamMembers
|
||||
});
|
||||
} else {
|
||||
console.warn('未找到当前用户所在的队伍');
|
||||
}
|
||||
} else {
|
||||
teamInfo.value = null;
|
||||
console.log('该活动暂无队伍信息');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取队伍信息失败:', error);
|
||||
teamInfo.value = null;
|
||||
proxy?.$modal.msgError('获取队伍信息失败,请稍后重试');
|
||||
} finally {
|
||||
teamInfoLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 解析队员信息 */
|
||||
const parseTeamMembers = (teamMembersStr: string): any[] => {
|
||||
if (!teamMembersStr) return [];
|
||||
try {
|
||||
return JSON.parse(teamMembersStr);
|
||||
} catch (error) {
|
||||
console.error('解析队员信息失败:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** 活动评分按钮操作 */
|
||||
const handleRate = async (row: MyActivityVO) => {
|
||||
try {
|
||||
@@ -854,6 +1077,18 @@ const formatDateTime = (dateStr: string): string => {
|
||||
});
|
||||
};
|
||||
|
||||
/** 计算表格最大高度 */
|
||||
const getTableMaxHeight = () => {
|
||||
const recordCount = attendanceRecords.value.length;
|
||||
if (recordCount <= 3) {
|
||||
return 200; // 1-3条记录
|
||||
} else if (recordCount <= 6) {
|
||||
return 300; // 4-6条记录
|
||||
} else {
|
||||
return 400; // 超过6条记录,设置最大高度
|
||||
}
|
||||
};
|
||||
|
||||
/** 计算参与时长 */
|
||||
const calculateDuration = (signInTime: string, signOutTime: string): string => {
|
||||
if (!signInTime) return '-';
|
||||
@@ -873,6 +1108,39 @@ const calculateDuration = (signInTime: string, signOutTime: string): string => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 提取指导老师姓名 */
|
||||
const getInstructorNames = (instructors: string | any[]): string => {
|
||||
if (!instructors) return '暂无';
|
||||
|
||||
let instructorArray: any[] = [];
|
||||
|
||||
// 如果是字符串,尝试解析JSON
|
||||
if (typeof instructors === 'string') {
|
||||
try {
|
||||
instructorArray = JSON.parse(instructors);
|
||||
} catch (error) {
|
||||
console.error('解析指导老师数据失败:', error);
|
||||
return instructors; // 如果解析失败,直接返回原字符串
|
||||
}
|
||||
} else if (Array.isArray(instructors)) {
|
||||
instructorArray = instructors;
|
||||
} else {
|
||||
return '暂无';
|
||||
}
|
||||
|
||||
if (!instructorArray || instructorArray.length === 0) return '暂无';
|
||||
|
||||
return instructorArray
|
||||
.map(instructor => instructor.name || instructor.nickName || '未知')
|
||||
.filter(name => name && name !== '未知')
|
||||
.join('、');
|
||||
};
|
||||
|
||||
/** 对话框关闭时重置队伍信息 */
|
||||
const handleDetailClose = () => {
|
||||
teamInfo.value = null;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
@@ -947,6 +1215,28 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
/* 查看对话框样式 */
|
||||
.detail-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.detail-section:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0 0 16px 0;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #409eff;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.view-poster {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -964,53 +1254,173 @@ onMounted(() => {
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 签到弹窗样式 */
|
||||
.attendance-dialog :deep(.el-dialog__body) {
|
||||
padding: 16px 20px;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.attendance-content {
|
||||
padding: 20px 0;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.attendance-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
min-width: 120px;
|
||||
height: 44px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 签到记录样式 */
|
||||
.attendance-records {
|
||||
margin-top: 24px;
|
||||
margin-top: 16px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
padding-top: 20px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.records-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.records-title {
|
||||
font-size: 16px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.records-table {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.records-table :deep(.el-table__body-wrapper) {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.no-records {
|
||||
text-align: center;
|
||||
padding: 40px 0;
|
||||
padding: 20px 0;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.no-records :deep(.el-empty__image) {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.no-records :deep(.el-empty__description) {
|
||||
font-size: 14px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* 队伍信息样式 */
|
||||
.team-info-content {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* 队伍基本信息 */
|
||||
.team-basic-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 队伍名称列宽度控制 */
|
||||
.team-basic-info :deep(.team-name-col) {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
/* 团队人数列宽度控制 */
|
||||
.team-basic-info :deep(.team-size-col) {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
/* 队伍名称标签单元格宽度控制 */
|
||||
.team-basic-info :deep(.team-name-label) {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
/* 队伍名称值单元格宽度控制 */
|
||||
.team-basic-info :deep(.team-name-value) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
/* 队长信息区域 */
|
||||
.team-leader-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.subsection-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
margin: 0 0 12px 0;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
/* 队员信息区域 */
|
||||
.team-members-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.members-table {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.members-table :deep(.el-table__header) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.members-table :deep(.el-table__row) {
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.members-table :deep(.el-table__row:hover) {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
/* 空状态样式 */
|
||||
.no-members {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.team-description {
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
min-height: 60px;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 加载状态样式 */
|
||||
.loading-container {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.no-team-info {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<div class="p-2 page-container">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6">
|
||||
<el-form-item label="班级" prop="classId">
|
||||
<el-select v-model="queryParams.classId" placeholder="请选择班级" clearable style="width: 100%" @change="handleClassChange">
|
||||
<el-option v-for="item in classList" :key="item.id" :label="item.className" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="24" class="search-btn-container">
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never" class="button-card table-card">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="View" @click="handleView" v-hasPermi="['stgl:stclass:query']">查看</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Download" @click="handleExport" v-hasPermi="['stgl:stclass:export']">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="studentList" @selection-change="handleSelectionChange" @row-dblclick="handleView">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" width="120" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" width="140" />
|
||||
<el-table-column label="性别" align="center" prop="gender" width="80">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_user_sex" :value="scope.row.gender" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="联系电话" align="center" prop="phone" width="120" />
|
||||
<el-table-column label="加入社团" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.clubCount > 0"
|
||||
type="primary"
|
||||
link
|
||||
@click="handleViewClubs(scope.row)"
|
||||
style="font-size: 14px; font-weight: bold; color: #409eff"
|
||||
>
|
||||
{{ scope.row.clubCount }}
|
||||
</el-button>
|
||||
<span v-else class="no-data">0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="加入志愿者队伍" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.volunteerTeamCount > 0"
|
||||
type="success"
|
||||
link
|
||||
@click="handleViewVolunteerTeams(scope.row)"
|
||||
style="font-size: 14px; font-weight: bold; color: #67c23a"
|
||||
>
|
||||
{{ scope.row.volunteerTeamCount }}
|
||||
</el-button>
|
||||
<span v-else class="no-data">0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="参与活动" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-if="scope.row.activityCount > 0"
|
||||
type="warning"
|
||||
link
|
||||
@click="handleViewActivities(scope.row)"
|
||||
style="font-size: 14px; font-weight: bold; color: #e6a23c"
|
||||
>
|
||||
{{ scope.row.activityCount }}
|
||||
</el-button>
|
||||
<span v-else class="no-data">0</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 社团详情弹窗 -->
|
||||
<el-dialog v-model="clubDialog.visible" :title="clubDialog.title" width="800px" append-to-body>
|
||||
<div v-if="clubDetails.length > 0">
|
||||
<div v-for="(club, index) in clubDetails" :key="club.id" class="club-item">
|
||||
<el-divider v-if="index > 0" />
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="社团名称">{{ club.clubName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社团类型">
|
||||
<dict-tag :options="stgl_club_type" :value="club.clubType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="成立日期">{{ club.establishDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成员规模">{{ club.memberLimit }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社长姓名">{{ club.presidentName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社长联系方式">{{ club.presidentPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社长院系">{{ club.presidentDept }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社长专业">{{ club.presidentMajor }}</el-descriptions-item>
|
||||
<el-descriptions-item label="社长班级">{{ club.presidentClass }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师姓名">{{ club.advisorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师部门">{{ club.advisorDept }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师电话">{{ club.advisorPhone }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data-container">
|
||||
<span class="no-data-text">暂无社团信息</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 志愿者队伍详情弹窗 -->
|
||||
<el-dialog v-model="volunteerTeamDialog.visible" :title="volunteerTeamDialog.title" width="800px" append-to-body>
|
||||
<div v-if="volunteerTeamDetails.length > 0">
|
||||
<div v-for="(team, index) in volunteerTeamDetails" :key="team.id" class="team-item">
|
||||
<el-divider v-if="index > 0" />
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="队伍名称">{{ team.teamName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="成立日期">{{ team.establishDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长姓名">{{ team.leaderName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长联系方式">{{ team.leaderPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长院系">{{ team.leaderDept }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长专业">{{ team.leaderMajor }}</el-descriptions-item>
|
||||
<el-descriptions-item label="队长班级">{{ team.leaderClass }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师姓名">{{ team.advisorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师部门">{{ team.advisorDept }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师电话">{{ team.advisorPhone }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data-container">
|
||||
<span class="no-data-text">暂无志愿者队伍信息</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 活动详情弹窗 -->
|
||||
<el-dialog v-model="activityDialog.visible" :title="activityDialog.title" width="800px" append-to-body>
|
||||
<div v-if="activityDetails.length > 0">
|
||||
<div v-for="(activity, index) in activityDetails" :key="activity.id" class="activity-item">
|
||||
<el-divider v-if="index > 0" />
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="活动名称">{{ activity.activityName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="活动类型">
|
||||
<dict-tag :options="stgl_activity_type" :value="activity.activityType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="活动主题">{{ activity.activityTheme }}</el-descriptions-item>
|
||||
<el-descriptions-item label="活动地点">{{ activity.location }}</el-descriptions-item>
|
||||
<el-descriptions-item label="活动时间">{{ activity.activityTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联社团/队伍">{{ activity.relatedOrganization }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师姓名">{{ activity.advisorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师部门">{{ activity.advisorDept }}</el-descriptions-item>
|
||||
<el-descriptions-item label="指导老师电话">{{ activity.advisorPhone }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-data-container">
|
||||
<span class="no-data-text">暂无活动信息</span>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="StglClass" lang="ts">
|
||||
import {
|
||||
getTeacherClasses,
|
||||
listStglClass,
|
||||
getStudentClubs,
|
||||
getStudentVolunteerTeams,
|
||||
getStudentActivities,
|
||||
exportStglClass
|
||||
} from '@/api/stgl/stclass';
|
||||
import { StglClassQuery, StglClassVO, StglClassDetailVO, ClubDetailVO, VolunteerTeamDetailVO, ActivityDetailVO } from '@/api/stgl/stclass/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_user_sex, stgl_club_type, stgl_activity_type } = toRefs<any>(
|
||||
proxy?.useDict('sys_user_sex', 'stgl_club_type', 'stgl_activity_type')
|
||||
);
|
||||
|
||||
const loading = ref(false);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const studentList = ref<StglClassVO[]>([]);
|
||||
const classList = ref<StglClassDetailVO[]>([]);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const queryParams = ref<StglClassQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
classId: undefined,
|
||||
studentName: undefined,
|
||||
studentNo: undefined
|
||||
});
|
||||
|
||||
// 社团详情弹窗
|
||||
const clubDialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
const clubDetails = ref<ClubDetailVO[]>([]);
|
||||
|
||||
// 志愿者队伍详情弹窗
|
||||
const volunteerTeamDialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
const volunteerTeamDetails = ref<VolunteerTeamDetailVO[]>([]);
|
||||
|
||||
// 活动详情弹窗
|
||||
const activityDialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
const activityDetails = ref<ActivityDetailVO[]>([]);
|
||||
|
||||
/** 查询班主任的班级列表 */
|
||||
const getTeacherClassList = async () => {
|
||||
try {
|
||||
const res = await getTeacherClasses();
|
||||
if (res.code === 200 && res.data) {
|
||||
classList.value = res.data;
|
||||
// 默认选择第一个班级
|
||||
if (classList.value.length > 0) {
|
||||
queryParams.value.classId = classList.value[0].id;
|
||||
await getList();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取班级列表失败:', error);
|
||||
proxy?.$modal.msgError('获取班级列表失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 查询学生列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listStglClass(queryParams.value);
|
||||
if (res.code === 200) {
|
||||
studentList.value = res.rows;
|
||||
total.value = res.total;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('查询学生列表失败:', error);
|
||||
proxy?.$modal.msgError('查询学生列表失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: StglClassVO[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 班级切换处理 */
|
||||
const handleClassChange = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 查看按钮操作 */
|
||||
const handleView = (row?: StglClassVO) => {
|
||||
const _row = row || studentList.value.find(item => item.id === ids.value[0]);
|
||||
if (!_row) {
|
||||
proxy?.$modal.msgError('请选择要查看的学生');
|
||||
return;
|
||||
}
|
||||
// 这里可以跳转到学生详情页面或显示学生详细信息
|
||||
proxy?.$modal.msgInfo(`查看学生:${_row.studentName}`);
|
||||
};
|
||||
|
||||
/** 查看社团详情 */
|
||||
const handleViewClubs = async (row: StglClassVO) => {
|
||||
try {
|
||||
const res = await getStudentClubs(row.id);
|
||||
if (res.code === 200) {
|
||||
clubDetails.value = res.data || [];
|
||||
clubDialog.title = `${row.studentName} - 社团信息`;
|
||||
clubDialog.visible = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取社团详情失败:', error);
|
||||
proxy?.$modal.msgError('获取社团详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 查看志愿者队伍详情 */
|
||||
const handleViewVolunteerTeams = async (row: StglClassVO) => {
|
||||
try {
|
||||
const res = await getStudentVolunteerTeams(row.id);
|
||||
if (res.code === 200) {
|
||||
volunteerTeamDetails.value = res.data || [];
|
||||
volunteerTeamDialog.title = `${row.studentName} - 志愿者队伍信息`;
|
||||
volunteerTeamDialog.visible = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取志愿者队伍详情失败:', error);
|
||||
proxy?.$modal.msgError('获取志愿者队伍详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 查看活动详情 */
|
||||
const handleViewActivities = async (row: StglClassVO) => {
|
||||
try {
|
||||
const res = await getStudentActivities(row.id);
|
||||
if (res.code === 200) {
|
||||
activityDetails.value = res.data || [];
|
||||
activityDialog.title = `${row.studentName} - 活动信息`;
|
||||
activityDialog.visible = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取活动详情失败:', error);
|
||||
proxy?.$modal.msgError('获取活动详情失败');
|
||||
}
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download(
|
||||
'stgl/stclass/export',
|
||||
queryParams.value,
|
||||
`班级学生参与情况_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getTeacherClassList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 8px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 表格卡片布局 */
|
||||
.table-card {
|
||||
margin-top: 0;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e4e7ed;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.table-card :deep(.el-card__body) {
|
||||
padding: 0px 20px 20px 20px !important;
|
||||
}
|
||||
|
||||
/* 移除按钮栏底部边框 */
|
||||
.button-card :deep(.el-card__header) {
|
||||
border-bottom: none !important;
|
||||
background: linear-gradient(135deg, #fafbff 0%, #f8fafc 100%);
|
||||
padding: 16px 20px;
|
||||
}
|
||||
|
||||
/* 搜索按钮容器样式 */
|
||||
.search-btn-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 10px;
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 分页容器样式 */
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 16px 20px 0 0 !important;
|
||||
background-color: #fff;
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
/* 无数据样式 */
|
||||
.no-data {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.no-data-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.no-data-text {
|
||||
color: #909399;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 详情弹窗样式 */
|
||||
.club-item,
|
||||
.team-item,
|
||||
.activity-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.club-item:last-child,
|
||||
.team-item:last-child,
|
||||
.activity-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -46,15 +46,15 @@
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['stgl:volunteerMember:add']">新增</el-button>
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['stgl:volunteermember:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['stgl:volunteerMember:edit']"
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['stgl:volunteermember:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['stgl:volunteerMember:remove']"
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['stgl:volunteermember:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
@@ -67,8 +67,8 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="Download" @click="importTemplate">下载模板</el-dropdown-item>
|
||||
<el-dropdown-item icon="Top" @click="handleImport" v-hasPermi="['stgl:volunteerMember:import']">导入数据</el-dropdown-item>
|
||||
<el-dropdown-item icon="Download" @click="handleExport" v-hasPermi="['stgl:volunteerMember:export']">导出数据</el-dropdown-item>
|
||||
<el-dropdown-item icon="Top" @click="handleImport" v-hasPermi="['stgl:volunteermember:import']">导入数据</el-dropdown-item>
|
||||
<el-dropdown-item icon="Download" @click="handleExport" v-hasPermi="['stgl:volunteermember:export']">导出数据</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
@@ -122,7 +122,7 @@
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px; color: blue"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['stgl:volunteerMember:query']"
|
||||
v-hasPermi="['stgl:volunteermember:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
size="default"
|
||||
style="font-size: 16px; margin-right: 8px"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['stgl:volunteerMember:edit']"
|
||||
v-hasPermi="['stgl:volunteermember:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
@@ -171,7 +171,7 @@
|
||||
size="default"
|
||||
style="font-size: 16px"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['stgl:volunteerMember:remove']"
|
||||
v-hasPermi="['stgl:volunteermember:remove']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
@@ -445,10 +445,19 @@ const getList = async () => {
|
||||
|
||||
console.log('JoinedMembersTab: getList 开始查询,参数:', queryData);
|
||||
|
||||
// 构建params对象,包含所有需要在params中的查询条件
|
||||
queryData.params = { ...queryData.params } as any;
|
||||
|
||||
// 将phone等查询条件放入params中(后端期望params.phone)
|
||||
if (queryData.phone) {
|
||||
(queryData.params as any).phone = queryData.phone;
|
||||
delete queryData.phone; // 删除顶级phone字段
|
||||
}
|
||||
|
||||
// 如果状态字段为空或未选择,则查询已加入(status=2)和已退出(status=4)的成员
|
||||
if (!queryData.status) {
|
||||
// 使用params传递多状态查询
|
||||
queryData.params = { statusList: ['2', '4'] } as any;
|
||||
// 使用params传递多状态查询,传递字符串格式
|
||||
(queryData.params as any).statusList = '2,4';
|
||||
delete queryData.status; // 删除单个status字段
|
||||
}
|
||||
|
||||
|
||||
@@ -228,10 +228,20 @@ const getList = async () => {
|
||||
|
||||
console.log('PendingMembersTab: getList 开始查询,参数:', queryData);
|
||||
|
||||
// 构建params对象,包含所有需要在params中的查询条件
|
||||
queryData.params = { ...queryData.params } as any;
|
||||
|
||||
// 将phone等查询条件放入params中(后端期望params.phone)
|
||||
if (queryData.phone) {
|
||||
(queryData.params as any).phone = queryData.phone;
|
||||
console.log('PendingMembersTab: phone参数放入params:', queryData.phone);
|
||||
delete queryData.phone; // 删除顶级phone字段
|
||||
}
|
||||
|
||||
// 如果状态字段为空或未选择,则查询待审核(status=0)和已驳回(status=3)的成员
|
||||
if (!queryData.status) {
|
||||
// 使用params传递多状态查询
|
||||
queryData.params = { statusList: ['0', '3'] } as any;
|
||||
// 使用params传递多状态查询,保留现有params内容,传递字符串格式
|
||||
(queryData.params as any).statusList = '0,3';
|
||||
delete queryData.status; // 删除单个status字段
|
||||
}
|
||||
|
||||
@@ -240,16 +250,25 @@ const getList = async () => {
|
||||
const res = await listVolunteerMember(queryData);
|
||||
console.log('PendingMembersTab: 查询结果:', res);
|
||||
|
||||
memberList.value = res.rows;
|
||||
total.value = res.total;
|
||||
|
||||
// 调试:检查数据完整性
|
||||
if (memberList.value.length > 0) {
|
||||
console.log('PendingMembersTab: 第一条成员数据:', memberList.value[0]);
|
||||
console.log('PendingMembersTab: props.teamId:', props.teamId);
|
||||
// 防御性编程:检查响应数据结构
|
||||
if (!res || !res.rows) {
|
||||
console.warn('PendingMembersTab: API返回数据格式异常:', res);
|
||||
memberList.value = [];
|
||||
total.value = 0;
|
||||
} else {
|
||||
memberList.value = res.rows;
|
||||
total.value = res.total;
|
||||
|
||||
// 调试:检查数据完整性
|
||||
if (memberList.value.length > 0) {
|
||||
console.log('PendingMembersTab: 第一条成员数据:', memberList.value[0]);
|
||||
console.log('PendingMembersTab: props.teamId:', props.teamId);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('PendingMembersTab: 查询成员列表失败:', error);
|
||||
memberList.value = [];
|
||||
total.value = 0;
|
||||
proxy?.$modal.msgError('查询成员列表失败');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
|
||||
@@ -770,7 +770,7 @@ const data = reactive({
|
||||
advisorEmail: null,
|
||||
advisorUserId: null,
|
||||
status: '0',
|
||||
sighOpen: 'Y',
|
||||
sighOpen: 'N',
|
||||
remark: null
|
||||
} as any,
|
||||
detailForm: {} as any,
|
||||
@@ -864,7 +864,7 @@ function reset() {
|
||||
advisorEmail: null,
|
||||
advisorUserId: null,
|
||||
status: '0',
|
||||
sighOpen: 'Y',
|
||||
sighOpen: 'N',
|
||||
remark: null
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user