Merge branch 'master' of http://47.99.164.66:3000/hzdyjs-xg/all-project
This commit is contained in:
commit
74ab953c17
164 files changed
+25187
-1775
No files matched your search
@@ -328,3 +328,6 @@ docs/部署文档/nginx配置/hzdyjsweb.camasort.com.conf
|
||||
首页完善的提示词.md
|
||||
scripts/
|
||||
学生宿舍卫生检查、学生违纪记录统计.md
|
||||
学生调宿、退宿功能.md
|
||||
学生动向信息界面(宿管员).md
|
||||
prompt/
|
||||
@@ -93,6 +93,12 @@
|
||||
<artifactId>ruoyi-xg</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统模块 - 用于访问用户信息 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.stgl.domain.StglAnnualReviewAudit;
|
||||
import org.dromara.stgl.domain.bo.StglAnnualReviewApprovalBo;
|
||||
import org.dromara.stgl.service.IStglAnnualReviewAuditService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审审批
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/annualReviewAudit")
|
||||
public class StglAnnualReviewAuditController extends BaseController {
|
||||
|
||||
private final IStglAnnualReviewAuditService stglAnnualReviewAuditService;
|
||||
|
||||
/**
|
||||
* 查询社团年审审批详细
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglAnnualReviewAudit> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(stglAnnualReviewAuditService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询审批记录
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:query")
|
||||
@GetMapping("/byAnnualReview/{annualReviewId}")
|
||||
public R<List<StglAnnualReviewAudit>> getByAnnualReviewId(@NotNull(message = "年审记录ID不能为空")
|
||||
@PathVariable Long annualReviewId) {
|
||||
return R.ok(stglAnnualReviewAuditService.queryByAnnualReviewId(annualReviewId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据审批人ID查询待审批记录
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:query")
|
||||
@GetMapping("/pending/{approverId}")
|
||||
public R<List<StglAnnualReviewAudit>> getPendingByApproverId(@NotNull(message = "审批人ID不能为空")
|
||||
@PathVariable Long approverId) {
|
||||
return R.ok(stglAnnualReviewAuditService.queryPendingByApproverId(approverId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团年审审批
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:add")
|
||||
@Log(title = "社团年审审批", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglAnnualReviewAudit stglAnnualReviewAudit) {
|
||||
return toAjax(stglAnnualReviewAuditService.insertByBo(stglAnnualReviewAudit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团年审审批
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:edit")
|
||||
@Log(title = "社团年审审批", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglAnnualReviewAudit stglAnnualReviewAudit) {
|
||||
return toAjax(stglAnnualReviewAuditService.updateByBo(stglAnnualReviewAudit));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团年审审批
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:remove")
|
||||
@Log(title = "社团年审审批", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(stglAnnualReviewAuditService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批年审记录
|
||||
*/
|
||||
@SaCheckPermission("stgl:annualReviewAudit:approve")
|
||||
@Log(title = "社团年审审批", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/approve")
|
||||
public R<Void> approve(@Validated @RequestBody StglAnnualReviewApprovalBo approvalBo) {
|
||||
return toAjax(stglAnnualReviewAuditService.approveAnnualReview(approvalBo));
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.stgl.domain.vo.StglAuditorVo;
|
||||
import org.dromara.stgl.domain.bo.StglAuditorBo;
|
||||
import org.dromara.stgl.service.IStglAuditorService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/auditor")
|
||||
public class StglAuditorController extends BaseController {
|
||||
|
||||
private final IStglAuditorService stglAuditorService;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglAuditorVo> list(StglAuditorBo bo, PageQuery pageQuery) {
|
||||
return stglAuditorService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出社团管理审核人配置列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:export")
|
||||
@Log(title = "社团管理审核人配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglAuditorBo bo, HttpServletResponse response) {
|
||||
List<StglAuditorVo> list = stglAuditorService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "社团管理审核人配置", StglAuditorVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团管理审核人配置详细信息
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglAuditorVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(stglAuditorService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团管理审核人配置
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:add")
|
||||
@Log(title = "社团管理审核人配置", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglAuditorBo bo) {
|
||||
return toAjax(stglAuditorService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团管理审核人配置
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:edit")
|
||||
@Log(title = "社团管理审核人配置", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglAuditorBo bo) {
|
||||
return toAjax(stglAuditorService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团管理审核人配置
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:remove")
|
||||
@Log(title = "社团管理审核人配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(stglAuditorService.deleteWithValidByIds(List.of(ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:add")
|
||||
@Log(title = "批量添加审核人", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/batchAdd")
|
||||
public R<Void> batchAdd(@RequestBody BatchAddRequest request) {
|
||||
return toAjax(stglAuditorService.batchAddAuditors(request.getUserIds(), request.getRemark()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我配置的审核人列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:list")
|
||||
@GetMapping("/myConfig")
|
||||
public TableDataInfo<StglAuditorVo> myConfigList(StglAuditorBo bo, PageQuery pageQuery) {
|
||||
return stglAuditorService.queryMyConfigList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量启用审核人
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:edit")
|
||||
@Log(title = "启用审核人", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/enable")
|
||||
public R<Void> enable(@RequestBody List<Long> ids) {
|
||||
return toAjax(stglAuditorService.enableAuditors(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量停用审核人
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:edit")
|
||||
@Log(title = "停用审核人", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/disable")
|
||||
public R<Void> disable(@RequestBody List<Long> ids) {
|
||||
return toAjax(stglAuditorService.disableAuditors(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
*/
|
||||
@SaCheckPermission("stgl:auditor:list")
|
||||
@GetMapping("/users/{deptId}")
|
||||
public R<List<SysUserVo>> listUserByDeptId(@PathVariable String deptId) {
|
||||
List<SysUserVo> users = sysUserService.selectUserListByDept(Long.valueOf(deptId));
|
||||
return R.ok(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加请求对象
|
||||
*/
|
||||
public static class BatchAddRequest {
|
||||
private List<Long> userIds;
|
||||
private String remark;
|
||||
|
||||
public List<Long> getUserIds() {
|
||||
return userIds;
|
||||
}
|
||||
|
||||
public void setUserIds(List<Long> userIds) {
|
||||
this.userIds = userIds;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.stgl.domain.vo.StglClubAdvisorHistoryVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubAdvisorHistoryBo;
|
||||
import org.dromara.stgl.service.IStglClubAdvisorHistoryService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史管理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/club/advisor/history")
|
||||
@Tag(name = "社团指导老师任职历史管理", description = "社团指导老师任职历史管理")
|
||||
public class StglClubAdvisorHistoryController extends BaseController {
|
||||
|
||||
private final IStglClubAdvisorHistoryService stglClubAdvisorHistoryService;
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史列表
|
||||
*/
|
||||
@Operation(summary = "查询社团指导老师任职历史列表")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglClubAdvisorHistoryVo> list(StglClubAdvisorHistoryBo bo, PageQuery pageQuery) {
|
||||
return stglClubAdvisorHistoryService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出社团指导老师任职历史列表
|
||||
*/
|
||||
@Operation(summary = "导出社团指导老师任职历史列表")
|
||||
@SaCheckPermission("stgl:club:export")
|
||||
@Log(title = "社团指导老师任职历史", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglClubAdvisorHistoryBo bo, HttpServletResponse response) {
|
||||
List<StglClubAdvisorHistoryVo> list = stglClubAdvisorHistoryService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "社团指导老师任职历史", StglClubAdvisorHistoryVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团指导老师任职历史详细信息
|
||||
*/
|
||||
@Operation(summary = "获取社团指导老师任职历史详细信息")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglClubAdvisorHistoryVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(stglClubAdvisorHistoryService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的当前在任指导老师
|
||||
*/
|
||||
@Operation(summary = "查询指定社团的当前在任指导老师")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/current/{clubId}")
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
public R<List<StglClubAdvisorHistoryVo>> getCurrentAdvisors(@PathVariable Long clubId) {
|
||||
List<StglClubAdvisorHistoryVo> list = stglClubAdvisorHistoryService.getCurrentAdvisorsByClubId(clubId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的历史指导老师(已离任)
|
||||
*/
|
||||
@Operation(summary = "查询指定社团的历史指导老师")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/history/{clubId}")
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
public R<List<StglClubAdvisorHistoryVo>> getHistoryAdvisors(@PathVariable Long clubId) {
|
||||
List<StglClubAdvisorHistoryVo> list = stglClubAdvisorHistoryService.getHistoryAdvisorsByClubId(clubId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的所有指导老师(包含当前和历史)
|
||||
*/
|
||||
@Operation(summary = "查询指定社团的所有指导老师")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/all/{clubId}")
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
public R<List<StglClubAdvisorHistoryVo>> getAllAdvisors(@PathVariable Long clubId) {
|
||||
List<StglClubAdvisorHistoryVo> list = stglClubAdvisorHistoryService.getAllAdvisorsByClubId(clubId);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团指导老师任职历史
|
||||
*/
|
||||
@Operation(summary = "新增社团指导老师任职历史")
|
||||
@SaCheckPermission("stgl:club:add")
|
||||
@Log(title = "社团指导老师任职历史", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglClubAdvisorHistoryBo bo) {
|
||||
return toAjax(stglClubAdvisorHistoryService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团指导老师任职历史
|
||||
*/
|
||||
@Operation(summary = "修改社团指导老师任职历史")
|
||||
@SaCheckPermission("stgl:club:edit")
|
||||
@Log(title = "社团指导老师任职历史", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglClubAdvisorHistoryBo bo) {
|
||||
return toAjax(stglClubAdvisorHistoryService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团指导老师任职历史
|
||||
*/
|
||||
@Operation(summary = "删除社团指导老师任职历史")
|
||||
@SaCheckPermission("stgl:club:remove")
|
||||
@Log(title = "社团指导老师任职历史", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(stglClubAdvisorHistoryService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.stgl.domain.vo.StglClubAnnualReviewVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubAnnualReviewBo;
|
||||
import org.dromara.stgl.service.IStglClubAnnualReviewService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* 社团年审记录管理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/club/annualReview")
|
||||
@Tag(name = "社团年审记录管理", description = "社团年审记录管理")
|
||||
public class StglClubAnnualReviewController extends BaseController {
|
||||
|
||||
private final IStglClubAnnualReviewService stglClubAnnualReviewService;
|
||||
|
||||
/**
|
||||
* 查询社团年审记录列表
|
||||
*/
|
||||
@Operation(summary = "查询社团年审记录列表")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglClubAnnualReviewVo> list(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
|
||||
return stglClubAnnualReviewService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的社团年审记录列表
|
||||
*/
|
||||
@Operation(summary = "查询我的社团年审记录列表")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:myList")
|
||||
@GetMapping("/myList")
|
||||
public TableDataInfo<StglClubAnnualReviewVo> myList(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
|
||||
return stglClubAnnualReviewService.queryMyPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出社团年审记录列表
|
||||
*/
|
||||
@Operation(summary = "导出社团年审记录列表")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:export")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglClubAnnualReviewBo bo, HttpServletResponse response) {
|
||||
List<StglClubAnnualReviewVo> list = stglClubAnnualReviewService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "社团年审记录", StglClubAnnualReviewVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团年审记录详细信息
|
||||
*/
|
||||
@Operation(summary = "获取社团年审记录详细信息")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglClubAnnualReviewVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(stglClubAnnualReviewService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团年审记录
|
||||
*/
|
||||
@Operation(summary = "新增社团年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:add")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglClubAnnualReviewBo bo) {
|
||||
return toAjax(stglClubAnnualReviewService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团年审记录
|
||||
*/
|
||||
@Operation(summary = "修改社团年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:edit")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglClubAnnualReviewBo bo) {
|
||||
return toAjax(stglClubAnnualReviewService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团年审记录
|
||||
*/
|
||||
@Operation(summary = "删除社团年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:remove")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(stglClubAnnualReviewService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交年审记录
|
||||
*/
|
||||
@Operation(summary = "提交年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:submit")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/submit/{id}")
|
||||
public R<Void> submit(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return toAjax(stglClubAnnualReviewService.submitReview(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回年审记录
|
||||
*/
|
||||
@Operation(summary = "撤回年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:withdraw")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/withdraw/{id}")
|
||||
public R<Void> withdraw(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return toAjax(stglClubAnnualReviewService.withdrawReview(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核年审记录
|
||||
*/
|
||||
@Operation(summary = "审核年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:audit")
|
||||
@Log(title = "社团年审记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/audit")
|
||||
public R<Void> audit(@RequestParam @NotNull(message = "年审记录ID不能为空") Long id,
|
||||
@RequestParam @NotBlank(message = "审核结果不能为空") String auditResult,
|
||||
@RequestParam String auditOpinion,
|
||||
@RequestParam @NotBlank(message = "审核类型不能为空") String auditType) {
|
||||
return toAjax(stglClubAnnualReviewService.auditReview(id, auditResult, auditOpinion, auditType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以创建年审记录
|
||||
*/
|
||||
@Operation(summary = "检查是否可以创建年审记录")
|
||||
@SaCheckPermission("stgl:clubAnnualReview:check")
|
||||
@GetMapping("/check")
|
||||
public R<Boolean> checkCanCreate(@RequestParam @NotNull(message = "社团ID不能为空") Long clubId,
|
||||
@RequestParam @NotNull(message = "年审年度不能为空") Integer reviewYear) {
|
||||
return R.ok(stglClubAnnualReviewService.checkCanCreateReview(clubId, reviewYear));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取年审状态选项
|
||||
*/
|
||||
@Operation(summary = "获取年审状态选项")
|
||||
@GetMapping("/statusOptions")
|
||||
public R<List<String>> getStatusOptions() {
|
||||
List<String> options = List.of("0", "1", "2", "3", "4");
|
||||
return R.ok(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团ID和年审年度获取该年度的活动数据
|
||||
*/
|
||||
@Operation(summary = "根据社团ID和年审年度获取该年度的活动数据")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true),
|
||||
@Parameter(name = "reviewYear", description = "年审年度", required = true)
|
||||
})
|
||||
@SaCheckPermission("stgl:clubAnnualReview:query")
|
||||
@GetMapping("/clubActivities")
|
||||
public R<List<org.dromara.stgl.domain.vo.StglActivityVo>> getClubActivities(
|
||||
@RequestParam @NotNull(message = "社团ID不能为空") Long clubId,
|
||||
@RequestParam @NotNull(message = "年审年度不能为空") Integer reviewYear) {
|
||||
return R.ok(stglClubAnnualReviewService.getClubActivitiesByReviewYear(clubId, reviewYear));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年审记录ID获取对应的活动数据
|
||||
*/
|
||||
@Operation(summary = "根据年审记录ID获取对应的活动数据")
|
||||
@Parameter(name = "id", description = "年审记录ID", required = true)
|
||||
@SaCheckPermission("stgl:clubAnnualReview:query")
|
||||
@GetMapping("/{id}/activities")
|
||||
public R<List<org.dromara.stgl.domain.vo.StglClubAnnualReviewActivityVo>> getAnnualReviewActivities(
|
||||
@NotNull(message = "年审记录ID不能为空") @PathVariable Long id) {
|
||||
return R.ok(stglClubAnnualReviewService.getAnnualReviewActivities(id));
|
||||
}
|
||||
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.stgl.domain.vo.ClubActivityPermissionResult;
|
||||
import org.dromara.stgl.service.IStglClubPermissionService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 社团权限管理Controller
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/club/permission")
|
||||
public class StglClubPermissionController extends BaseController {
|
||||
|
||||
private final IStglClubPermissionService clubPermissionService;
|
||||
|
||||
/**
|
||||
* 检查社团活动权限
|
||||
* 前端每次进入活动管理页面都会调用这个接口
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 权限检查结果
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/checkActivityPermission/{clubId}")
|
||||
@Log(title = "检查社团活动权限", businessType = BusinessType.OTHER)
|
||||
public R<ClubActivityPermissionResult> checkActivityPermission(@PathVariable Long clubId) {
|
||||
log.info("检查社团活动权限请求,clubId: {}", clubId);
|
||||
|
||||
if (clubId == null || clubId <= 0) {
|
||||
return R.fail("社团ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
ClubActivityPermissionResult result = clubPermissionService.checkClubActivityPermission(clubId);
|
||||
log.info("社团ID: {} 权限检查结果: {}", clubId, result.getStatus());
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
log.error("检查社团活动权限失败,clubId: {}", clubId, e);
|
||||
return R.fail("检查权限失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量检查多个社团的权限状态
|
||||
* 用于列表页面显示多个社团的权限状态
|
||||
*
|
||||
* @param clubIds 社团ID列表
|
||||
* @return 权限检查结果映射
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@PostMapping("/batchCheckPermission")
|
||||
@Log(title = "批量检查社团权限", businessType = BusinessType.OTHER)
|
||||
public R<Map<Long, ClubActivityPermissionResult>> batchCheckPermission(@RequestBody List<Long> clubIds) {
|
||||
log.info("批量检查社团权限请求,社团数量: {}", clubIds != null ? clubIds.size() : 0);
|
||||
|
||||
if (clubIds == null || clubIds.isEmpty()) {
|
||||
return R.fail("社团ID列表不能为空");
|
||||
}
|
||||
|
||||
if (clubIds.size() > 100) {
|
||||
return R.fail("批量检查数量不能超过100个");
|
||||
}
|
||||
|
||||
try {
|
||||
Map<Long, ClubActivityPermissionResult> results =
|
||||
clubPermissionService.batchCheckClubActivityPermission(clubIds);
|
||||
log.info("批量权限检查完成,处理社团数量: {}", results.size());
|
||||
return R.ok(results);
|
||||
} catch (Exception e) {
|
||||
log.error("批量检查社团权限失败,clubIds: {}", clubIds, e);
|
||||
return R.fail("批量检查权限失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团是否在年审窗口期内
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 是否在年审窗口期
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/isInAnnualReviewWindow/{clubId}")
|
||||
public R<Boolean> isInAnnualReviewWindow(@PathVariable Long clubId) {
|
||||
log.debug("检查社团是否在年审窗口期,clubId: {}", clubId);
|
||||
|
||||
if (clubId == null || clubId <= 0) {
|
||||
return R.fail("社团ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
boolean inWindow = clubPermissionService.isInAnnualReviewWindow(clubId);
|
||||
return R.ok(inWindow);
|
||||
} catch (Exception e) {
|
||||
log.error("检查年审窗口期失败,clubId: {}", clubId, e);
|
||||
return R.fail("检查失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团距离下次年审的天数
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 距离年审的天数
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/getDaysUntilNextAnnualReview/{clubId}")
|
||||
public R<Long> getDaysUntilNextAnnualReview(@PathVariable Long clubId) {
|
||||
log.debug("获取社团距离年审天数,clubId: {}", clubId);
|
||||
|
||||
if (clubId == null || clubId <= 0) {
|
||||
return R.fail("社团ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
long days = clubPermissionService.getDaysUntilNextAnnualReview(clubId);
|
||||
return R.ok(days);
|
||||
} catch (Exception e) {
|
||||
log.error("获取距离年审天数失败,clubId: {}", clubId, e);
|
||||
return R.fail("获取失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团是否已在当前年审期内提交年审
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 是否已提交年审
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/hasSubmittedCurrentYearAnnualReview/{clubId}")
|
||||
public R<Boolean> hasSubmittedCurrentYearAnnualReview(@PathVariable Long clubId) {
|
||||
log.debug("检查社团是否已提交年审,clubId: {}", clubId);
|
||||
|
||||
if (clubId == null || clubId <= 0) {
|
||||
return R.fail("社团ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
boolean hasSubmitted = clubPermissionService.hasSubmittedCurrentYearAnnualReview(clubId);
|
||||
return R.ok(hasSubmitted);
|
||||
} catch (Exception e) {
|
||||
log.error("检查年审提交状态失败,clubId: {}", clubId, e);
|
||||
return R.fail("检查失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团权限详细信息(包含所有相关信息的综合接口)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 权限详细信息
|
||||
*/
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/getPermissionDetails/{clubId}")
|
||||
@Log(title = "获取社团权限详情", businessType = BusinessType.OTHER)
|
||||
public R<Map<String, Object>> getPermissionDetails(@PathVariable Long clubId) {
|
||||
log.info("获取社团权限详情,clubId: {}", clubId);
|
||||
|
||||
if (clubId == null || clubId <= 0) {
|
||||
return R.fail("社团ID不能为空");
|
||||
}
|
||||
|
||||
try {
|
||||
ClubActivityPermissionResult permissionResult =
|
||||
clubPermissionService.checkClubActivityPermission(clubId);
|
||||
boolean inWindow = clubPermissionService.isInAnnualReviewWindow(clubId);
|
||||
long daysUntilNext = clubPermissionService.getDaysUntilNextAnnualReview(clubId);
|
||||
boolean hasSubmitted = clubPermissionService.hasSubmittedCurrentYearAnnualReview(clubId);
|
||||
|
||||
Map<String, Object> details = Map.of(
|
||||
"permissionResult", permissionResult,
|
||||
"isInAnnualReviewWindow", inWindow,
|
||||
"daysUntilNextAnnualReview", daysUntilNext,
|
||||
"hasSubmittedCurrentYearAnnualReview", hasSubmitted
|
||||
);
|
||||
|
||||
return R.ok(details);
|
||||
} catch (Exception e) {
|
||||
log.error("获取社团权限详情失败,clubId: {}", clubId, e);
|
||||
return R.fail("获取详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -82,6 +82,30 @@ public class StglActivity extends TenantEntity {
|
||||
@TableField("poster_url")
|
||||
private String posterUrl;
|
||||
|
||||
/**
|
||||
* 关联部门ID
|
||||
*/
|
||||
@TableField("related_dept_id")
|
||||
private Long relatedDeptId;
|
||||
|
||||
/**
|
||||
* 关联部门名称
|
||||
*/
|
||||
@TableField("related_dept_name")
|
||||
private String relatedDeptName;
|
||||
|
||||
/**
|
||||
* 关联部门ID列表(JSON格式)
|
||||
*/
|
||||
@TableField("related_dept_ids")
|
||||
private String relatedDeptIds;
|
||||
|
||||
/**
|
||||
* 关联部门名称列表(逗号分隔)
|
||||
*/
|
||||
@TableField("related_dept_names")
|
||||
private String relatedDeptNames;
|
||||
|
||||
/**
|
||||
* 关联社团ID
|
||||
*/
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审审批对象 stgl_annual_review_audit
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_annual_review_audit")
|
||||
public class StglAnnualReviewAudit extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
/**
|
||||
* 年审记录ID
|
||||
*/
|
||||
private Long annualReviewId;
|
||||
|
||||
/**
|
||||
* 节点代码(advisor_approve/college_approve/youth_league_approve)
|
||||
*/
|
||||
private String nodeCode;
|
||||
|
||||
/**
|
||||
* 节点名称(指导老师审批/学院审批/校团委审批)
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 节点顺序(1.1,1.2,2,3)
|
||||
*/
|
||||
private BigDecimal nodeOrder;
|
||||
|
||||
/**
|
||||
* 节点状态(pending/waiting/approved)
|
||||
*/
|
||||
@TableField("audit_status")
|
||||
private String nodeStatus;
|
||||
|
||||
/**
|
||||
* 审批人ID
|
||||
*/
|
||||
private Long approverId;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
private String approverName;
|
||||
|
||||
/**
|
||||
* 审批结果(通过/不通过)
|
||||
*/
|
||||
private String approveResult;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
@TableField("audit_opinion")
|
||||
private String approveOpinion;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
@TableField("audit_time")
|
||||
private Date approveTime;
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置对象 stgl_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_auditor")
|
||||
public class StglAuditor extends TenantEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
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;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史对象 stgl_club_advisor_history
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_club_advisor_history")
|
||||
public class StglClubAdvisorHistory extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
private String advisorPhone;
|
||||
|
||||
/**
|
||||
* 指导老师邮箱
|
||||
*/
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师用户ID
|
||||
*/
|
||||
private Long advisorUserId;
|
||||
|
||||
/**
|
||||
* 在任状态:1-当前在任,0-历史(已离任)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 上任时间
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 离任时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审记录对象 stgl_club_annual_review
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_club_annual_review")
|
||||
public class StglClubAnnualReview extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 年审年度
|
||||
*/
|
||||
private Integer reviewYear;
|
||||
|
||||
/**
|
||||
* 年审开始日期
|
||||
*/
|
||||
private Date reviewStartDate;
|
||||
|
||||
/**
|
||||
* 年审结束日期
|
||||
*/
|
||||
private Date reviewEndDate;
|
||||
|
||||
/**
|
||||
* 年审时间
|
||||
*/
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 是否有章程
|
||||
*/
|
||||
private String hasCharter;
|
||||
|
||||
/**
|
||||
* 章程文件URL
|
||||
*/
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 是否有资金
|
||||
*/
|
||||
private String hasFunds;
|
||||
|
||||
/**
|
||||
* 资金数额
|
||||
*/
|
||||
private BigDecimal fundAmount;
|
||||
|
||||
/**
|
||||
* 成员数量
|
||||
*/
|
||||
private Integer memberCount;
|
||||
|
||||
/**
|
||||
* 状态(0-草稿 1-已提交 2-审核中 3-审核通过 4-审核不通过)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 指导老师意见
|
||||
*/
|
||||
private String advisorOpinion;
|
||||
|
||||
/**
|
||||
* 学院意见
|
||||
*/
|
||||
private String collegeOpinion;
|
||||
|
||||
/**
|
||||
* 团委意见
|
||||
*/
|
||||
private String youthLeagueOpinion;
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审记录活动对象 stgl_club_annual_review_activity
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-12-31
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_club_annual_review_activity")
|
||||
@Schema(description = "社团年审记录活动")
|
||||
public class StglClubAnnualReviewActivity extends TenantEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 年审记录ID
|
||||
*/
|
||||
@Schema(description = "年审记录ID")
|
||||
private Long annualReviewId;
|
||||
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
@Schema(description = "活动名称")
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动时间
|
||||
*/
|
||||
@Schema(description = "活动时间")
|
||||
private Date activityTime;
|
||||
|
||||
/**
|
||||
* 活动开始时间
|
||||
*/
|
||||
@Schema(description = "活动开始时间")
|
||||
private Date activityStartTime;
|
||||
|
||||
/**
|
||||
* 活动结束时间
|
||||
*/
|
||||
@Schema(description = "活动结束时间")
|
||||
private Date activityEndTime;
|
||||
|
||||
/**
|
||||
* 活动地点
|
||||
*/
|
||||
@Schema(description = "活动地点")
|
||||
private String activityLocation;
|
||||
|
||||
/**
|
||||
* 活动类型
|
||||
*/
|
||||
@Schema(description = "活动类型")
|
||||
private String activityType;
|
||||
|
||||
/**
|
||||
* 参与人数
|
||||
*/
|
||||
@Schema(description = "参与人数")
|
||||
private Integer participantCount;
|
||||
|
||||
/**
|
||||
* 活动描述
|
||||
*/
|
||||
@Schema(description = "活动描述")
|
||||
private String activityDescription;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Integer deleted;
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 社团年审记录成员对象 stgl_club_annual_review_member
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-12-31
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_club_annual_review_member")
|
||||
@Schema(description = "社团年审记录成员")
|
||||
public class StglClubAnnualReviewMember extends TenantEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 年审记录ID
|
||||
*/
|
||||
@Schema(description = "年审记录ID")
|
||||
private Long annualReviewId;
|
||||
|
||||
/**
|
||||
* 成员姓名
|
||||
*/
|
||||
@Schema(description = "成员姓名")
|
||||
private String memberName;
|
||||
|
||||
/**
|
||||
* 班级
|
||||
*/
|
||||
@Schema(description = "班级")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 职务
|
||||
*/
|
||||
@Schema(description = "职务")
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* 联系方式
|
||||
*/
|
||||
@Schema(description = "联系方式")
|
||||
private String contactInfo;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Integer deleted;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 社团管理用户和部门完整信息
|
||||
* 用于批量添加审核人时获取完整的用户数据
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class StglUserWithDeptInfo {
|
||||
|
||||
/** 用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** 用户账号 */
|
||||
private String userName;
|
||||
|
||||
/** 用户昵称 */
|
||||
private String nickName;
|
||||
|
||||
/** 部门ID */
|
||||
private Long deptId;
|
||||
|
||||
/** 部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/** 手机号码 */
|
||||
private String phonenumber;
|
||||
|
||||
/** 用户邮箱 */
|
||||
private String email;
|
||||
|
||||
/** 帐号状态(1正常 0停用) */
|
||||
private String status;
|
||||
|
||||
}
|
||||
+20
-1
@@ -76,6 +76,26 @@ public class StglActivityBo extends BaseEntity {
|
||||
*/
|
||||
private String posterUrl;
|
||||
|
||||
/**
|
||||
* 关联部门ID
|
||||
*/
|
||||
private Long relatedDeptId;
|
||||
|
||||
/**
|
||||
* 关联部门名称
|
||||
*/
|
||||
private String relatedDeptName;
|
||||
|
||||
/**
|
||||
* 关联部门ID列表(JSON格式)
|
||||
*/
|
||||
private String relatedDeptIds;
|
||||
|
||||
/**
|
||||
* 关联部门名称列表(逗号分隔)
|
||||
*/
|
||||
private String relatedDeptNames;
|
||||
|
||||
/**
|
||||
* 关联社团ID
|
||||
*/
|
||||
@@ -89,7 +109,6 @@ public class StglActivityBo extends BaseEntity {
|
||||
/**
|
||||
* 主办方名称
|
||||
*/
|
||||
@NotBlank(message = "主办方名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String organizerName;
|
||||
|
||||
/**
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审审批请求业务对象
|
||||
*
|
||||
* @author system
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class StglAnnualReviewApprovalBo {
|
||||
|
||||
/**
|
||||
* 审批记录ID
|
||||
*/
|
||||
@NotNull(message = "审批记录ID不能为空")
|
||||
private Long auditId;
|
||||
|
||||
/**
|
||||
* 审批结果
|
||||
*/
|
||||
@NotBlank(message = "审批结果不能为空")
|
||||
private String approveResult;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String approveOpinion;
|
||||
|
||||
/**
|
||||
* 下一步审核人列表
|
||||
*/
|
||||
private List<NextAuditor> nextAuditors;
|
||||
|
||||
/**
|
||||
* 下一步审核人信息
|
||||
*/
|
||||
@Data
|
||||
public static class NextAuditor {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
private String nickName;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.stgl.domain.StglAuditor;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置业务对象 stgl_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglAuditor.class, reverseConvertGenerate = false)
|
||||
public class StglAuditorBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@NotBlank(message = "用户姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@NotBlank(message = "用户昵称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@NotBlank(message = "部门名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
private String searchValue;
|
||||
|
||||
/**
|
||||
* 创建时间范围
|
||||
*/
|
||||
private List<Date> createTimeRange;
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.dromara.stgl.domain.StglClubAdvisorHistory;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史业务对象 stgl_club_advisor_history
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglClubAdvisorHistory.class, reverseConvertGenerate = false)
|
||||
public class StglClubAdvisorHistoryBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
@NotNull(message = "社团ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
@NotBlank(message = "指导老师姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 100, message = "指导老师姓名长度不能超过100个字符")
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
@Size(max = 200, message = "指导老师部门长度不能超过200个字符")
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
@Size(max = 20, message = "指导老师电话长度不能超过20个字符")
|
||||
private String advisorPhone;
|
||||
|
||||
/**
|
||||
* 指导老师邮箱
|
||||
*/
|
||||
@Size(max = 100, message = "指导老师邮箱长度不能超过100个字符")
|
||||
@Email(message = "指导老师邮箱格式不正确")
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师用户ID
|
||||
*/
|
||||
private Long advisorUserId;
|
||||
|
||||
/**
|
||||
* 在任状态:1-当前在任,0-历史(已离任)
|
||||
*/
|
||||
@NotNull(message = "在任状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 上任时间
|
||||
*/
|
||||
@NotNull(message = "上任时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 离任时间
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审记录业务对象 StglClubAnnualReviewBo
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglClubAnnualReview.class, reverseConvertGenerate = false)
|
||||
public class StglClubAnnualReviewBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
@NotNull(message = "社团ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 年审年度
|
||||
*/
|
||||
@NotNull(message = "年审年度不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Min(value = 2000, message = "年审年度不能小于2000年")
|
||||
@Max(value = 9999, message = "年审年度不能大于9999年")
|
||||
private Integer reviewYear;
|
||||
|
||||
/**
|
||||
* 年审开始日期
|
||||
*/
|
||||
@NotNull(message = "年审开始日期不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date reviewStartDate;
|
||||
|
||||
/**
|
||||
* 年审结束日期
|
||||
*/
|
||||
@NotNull(message = "年审结束日期不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date reviewEndDate;
|
||||
|
||||
/**
|
||||
* 年审时间
|
||||
*/
|
||||
@NotNull(message = "年审时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
@NotBlank(message = "社团名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 100, message = "社团名称长度不能超过100个字符")
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
@Size(max = 50, message = "社长姓名长度不能超过50个字符")
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
@Size(max = 20, message = "社团类型长度不能超过20个字符")
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
@Size(max = 50, message = "指导老师姓名长度不能超过50个字符")
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
@Size(max = 100, message = "指导老师部门长度不能超过100个字符")
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 是否有章程
|
||||
*/
|
||||
@Pattern(regexp = "^[YN]$", message = "是否有章程必须是Y或N")
|
||||
private String hasCharter;
|
||||
|
||||
/**
|
||||
* 章程文件URL
|
||||
*/
|
||||
@Size(max = 500, message = "章程文件URL长度不能超过500个字符")
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 是否有资金
|
||||
*/
|
||||
@Pattern(regexp = "^[YN]$", message = "是否有资金必须是Y或N")
|
||||
private String hasFunds;
|
||||
|
||||
/**
|
||||
* 资金数额
|
||||
*/
|
||||
@DecimalMin(value = "0.00", message = "资金数额不能小于0")
|
||||
@DecimalMax(value = "99999999.99", message = "资金数额不能超过99999999.99")
|
||||
private BigDecimal fundAmount;
|
||||
|
||||
/**
|
||||
* 成员数量
|
||||
*/
|
||||
@Min(value = 0, message = "成员数量不能小于0")
|
||||
@Max(value = 9999, message = "成员数量不能超过9999")
|
||||
private Integer memberCount;
|
||||
|
||||
/**
|
||||
* 状态(0-草稿 1-已提交 2-审核中 3-审核通过 4-审核不通过)
|
||||
*/
|
||||
@Pattern(regexp = "^[0-4]$", message = "状态值必须是0-4之间的数字")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 指导老师意见
|
||||
*/
|
||||
private String advisorOpinion;
|
||||
|
||||
/**
|
||||
* 学院意见
|
||||
*/
|
||||
private String collegeOpinion;
|
||||
|
||||
/**
|
||||
* 团委意见
|
||||
*/
|
||||
private String youthLeagueOpinion;
|
||||
|
||||
/**
|
||||
* 成员信息JSON(前端传入)
|
||||
*/
|
||||
private String membersJson;
|
||||
|
||||
/**
|
||||
* 活动信息JSON(前端传入)
|
||||
*/
|
||||
private String activitiesJson;
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团活动权限检查结果
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
public class ClubActivityPermissionResult {
|
||||
|
||||
/**
|
||||
* 是否可以发起活动
|
||||
*/
|
||||
private Boolean canCreateActivity;
|
||||
|
||||
/**
|
||||
* 权限状态
|
||||
* NORMAL - 正常状态
|
||||
* TEMPORARILY_LIMITED - 临时限制(15天内可恢复)
|
||||
* PERMANENTLY_LIMITED - 永久限制(超过15天)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 状态描述信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 年审截止时间(仅临时限制时有值)
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date deadlineTime;
|
||||
|
||||
/**
|
||||
* 剩余小时数(仅临时限制时有值)
|
||||
*/
|
||||
private Long remainingHours;
|
||||
|
||||
/**
|
||||
* 剩余天数(仅临时限制时有值)
|
||||
*/
|
||||
private Long remainingDays;
|
||||
|
||||
/**
|
||||
* 年审开始时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date annualReviewStartTime;
|
||||
|
||||
/**
|
||||
* 创建正常状态结果
|
||||
*/
|
||||
public static ClubActivityPermissionResult allowed() {
|
||||
ClubActivityPermissionResult result = new ClubActivityPermissionResult();
|
||||
result.setCanCreateActivity(true);
|
||||
result.setStatus("NORMAL");
|
||||
result.setMessage("权限正常,可以发起活动");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建临时限制状态结果
|
||||
*/
|
||||
public static ClubActivityPermissionResult temporarilyDenied(String message, Date deadlineTime,
|
||||
Date annualReviewStartTime,
|
||||
Long remainingHours, Long remainingDays) {
|
||||
ClubActivityPermissionResult result = new ClubActivityPermissionResult();
|
||||
result.setCanCreateActivity(false);
|
||||
result.setStatus("TEMPORARILY_LIMITED");
|
||||
result.setMessage(message);
|
||||
result.setDeadlineTime(deadlineTime);
|
||||
result.setAnnualReviewStartTime(annualReviewStartTime);
|
||||
result.setRemainingHours(remainingHours);
|
||||
result.setRemainingDays(remainingDays);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建永久限制状态结果
|
||||
*/
|
||||
public static ClubActivityPermissionResult permanentlyDenied(String message) {
|
||||
ClubActivityPermissionResult result = new ClubActivityPermissionResult();
|
||||
result.setCanCreateActivity(false);
|
||||
result.setStatus("PERMANENTLY_LIMITED");
|
||||
result.setMessage(message);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+10
@@ -65,6 +65,16 @@ public class MyActivityVo implements Serializable {
|
||||
*/
|
||||
private String organizerName;
|
||||
|
||||
/**
|
||||
* 关联部门名称
|
||||
*/
|
||||
private String relatedDeptName;
|
||||
|
||||
/**
|
||||
* 关联部门名称列表
|
||||
*/
|
||||
private String relatedDeptNames;
|
||||
|
||||
/**
|
||||
* 关联类型(1-社团 2-志愿者队伍)
|
||||
*/
|
||||
|
||||
+21
@@ -88,6 +88,27 @@ public class StglActivityVo implements Serializable {
|
||||
*/
|
||||
private String posterUrl;
|
||||
|
||||
/**
|
||||
* 关联部门ID
|
||||
*/
|
||||
private Long relatedDeptId;
|
||||
|
||||
/**
|
||||
* 关联部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "关联部门")
|
||||
private String relatedDeptName;
|
||||
|
||||
/**
|
||||
* 关联部门ID列表(JSON格式)
|
||||
*/
|
||||
private String relatedDeptIds;
|
||||
|
||||
/**
|
||||
* 关联部门名称列表(逗号分隔)
|
||||
*/
|
||||
private String relatedDeptNames;
|
||||
|
||||
/**
|
||||
* 关联社团ID
|
||||
*/
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.stgl.domain.StglAuditor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置视图对象 stgl_auditor
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = StglAuditor.class)
|
||||
public class StglAuditorVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@ExcelProperty(value = "用户姓名")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@ExcelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@ExcelProperty(value = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
@ExcelProperty(value = "联系电话")
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
@ExcelProperty(value = "邮箱地址")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
@ExcelProperty(value = "备注说明")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "配置人")
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者ID
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者ID
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+15
@@ -65,6 +65,21 @@ public class StglClassVo implements Serializable {
|
||||
*/
|
||||
private Integer activityCount;
|
||||
|
||||
/**
|
||||
* 今日活动名称(审核通过且时间为今天的活动)
|
||||
*/
|
||||
private String todayActivityName;
|
||||
|
||||
/**
|
||||
* 今日活动开始时间
|
||||
*/
|
||||
private String todayActivityStartTime;
|
||||
|
||||
/**
|
||||
* 今日活动结束时间
|
||||
*/
|
||||
private String todayActivityEndTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAdvisorHistory;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史视图对象 stgl_club_advisor_history
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = StglClubAdvisorHistory.class)
|
||||
public class StglClubAdvisorHistoryVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
@ExcelProperty(value = "社团ID")
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
@ExcelProperty(value = "社团名称")
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师姓名")
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师部门")
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 指导老师电话
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师电话")
|
||||
private String advisorPhone;
|
||||
|
||||
/**
|
||||
* 指导老师邮箱
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师邮箱")
|
||||
private String advisorEmail;
|
||||
|
||||
/**
|
||||
* 指导老师用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师用户ID")
|
||||
private Long advisorUserId;
|
||||
|
||||
/**
|
||||
* 在任状态:1-当前在任,0-历史(已离任)
|
||||
*/
|
||||
@ExcelProperty(value = "在任状态", converter = org.dromara.common.excel.convert.ExcelDictConvert.class)
|
||||
@org.dromara.common.excel.annotation.ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 上任时间
|
||||
*/
|
||||
@ExcelProperty(value = "上任时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 离任时间
|
||||
*/
|
||||
@ExcelProperty(value = "离任时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReviewActivity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审记录活动视图对象 StglClubAnnualReviewActivityVo
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = StglClubAnnualReviewActivity.class)
|
||||
public class StglClubAnnualReviewActivityVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 年审记录ID
|
||||
*/
|
||||
private Long annualReviewId;
|
||||
|
||||
/**
|
||||
* 活动名称
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
/**
|
||||
* 活动时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date activityTime;
|
||||
|
||||
/**
|
||||
* 活动开始时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date activityStartTime;
|
||||
|
||||
/**
|
||||
* 活动结束时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date activityEndTime;
|
||||
|
||||
/**
|
||||
* 活动地点
|
||||
*/
|
||||
private String activityLocation;
|
||||
|
||||
/**
|
||||
* 活动类型
|
||||
*/
|
||||
private String activityType;
|
||||
|
||||
/**
|
||||
* 参与人数
|
||||
*/
|
||||
private Integer participantCount;
|
||||
|
||||
/**
|
||||
* 活动描述
|
||||
*/
|
||||
private String activityDescription;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
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;
|
||||
|
||||
// 为了兼容前端,添加一些别名字段
|
||||
/**
|
||||
* 地点(别名)
|
||||
*/
|
||||
public String getLocation() {
|
||||
return this.activityLocation;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.activityLocation = location;
|
||||
}
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团年审记录视图对象 StglClubAnnualReviewVo
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = StglClubAnnualReview.class)
|
||||
public class StglClubAnnualReviewVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团ID
|
||||
*/
|
||||
private Long clubId;
|
||||
|
||||
/**
|
||||
* 年审年度
|
||||
*/
|
||||
private Integer reviewYear;
|
||||
|
||||
/**
|
||||
* 年审开始日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date reviewStartDate;
|
||||
|
||||
/**
|
||||
* 年审结束日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date reviewEndDate;
|
||||
|
||||
/**
|
||||
* 年审时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师部门
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 是否有章程
|
||||
*/
|
||||
private String hasCharter;
|
||||
|
||||
/**
|
||||
* 章程文件URL
|
||||
*/
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 是否有资金
|
||||
*/
|
||||
private String hasFunds;
|
||||
|
||||
/**
|
||||
* 资金数额
|
||||
*/
|
||||
private BigDecimal fundAmount;
|
||||
|
||||
/**
|
||||
* 成员数量
|
||||
*/
|
||||
private Integer memberCount;
|
||||
|
||||
/**
|
||||
* 状态(0-草稿 1-已提交 2-审核中 3-审核通过 4-审核不通过)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 指导老师意见
|
||||
*/
|
||||
private String advisorOpinion;
|
||||
|
||||
/**
|
||||
* 学院意见
|
||||
*/
|
||||
private String collegeOpinion;
|
||||
|
||||
/**
|
||||
* 团委意见
|
||||
*/
|
||||
private String youthLeagueOpinion;
|
||||
|
||||
/**
|
||||
* 成员信息JSON(用于前端显示)
|
||||
*/
|
||||
private String membersJson;
|
||||
|
||||
/**
|
||||
* 活动信息JSON(用于前端显示)
|
||||
*/
|
||||
private String activitiesJson;
|
||||
|
||||
// 继承的基础字段
|
||||
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;
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglAnnualReviewAudit;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审审批Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface StglAnnualReviewAuditMapper extends BaseMapperPlus<StglAnnualReviewAudit, StglAnnualReviewAudit> {
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询审批记录
|
||||
*
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> selectByAnnualReviewId(Long annualReviewId);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID和节点代码查询审批记录
|
||||
*
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @param nodeCode 节点代码
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> selectByAnnualReviewIdAndNodeCode(Long annualReviewId, String nodeCode);
|
||||
|
||||
/**
|
||||
* 根据审批人ID查询待审批记录
|
||||
*
|
||||
* @param approverId 审批人ID
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> selectPendingByApproverId(Long approverId);
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglAuditor;
|
||||
import org.dromara.stgl.domain.vo.StglAuditorVo;
|
||||
import org.dromara.stgl.domain.StglUserWithDeptInfo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface StglAuditorMapper extends BaseMapperPlus<StglAuditor, StglAuditorVo> {
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置
|
||||
*
|
||||
* @param id 社团管理审核人配置主键
|
||||
* @return 社团管理审核人配置
|
||||
*/
|
||||
StglAuditorVo selectStglAuditorVoById(Long id);
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*
|
||||
* @param stglAuditor 社团管理审核人配置
|
||||
* @return 社团管理审核人配置集合
|
||||
*/
|
||||
List<StglAuditorVo> selectStglAuditorVoList(StglAuditor stglAuditor);
|
||||
|
||||
/**
|
||||
* 根据用户ID检查是否已存在审核人配置
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 记录数
|
||||
*/
|
||||
int checkUserExists(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 批量启用审核人
|
||||
*
|
||||
* @param ids 审核人ID列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
int enableAuditorsByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量停用审核人
|
||||
*
|
||||
* @param ids 审核人ID列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
int disableAuditorsByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询完整的用户信息(包含部门信息)用于批量添加
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @return 用户和部门完整信息列表
|
||||
*/
|
||||
List<StglUserWithDeptInfo> selectUsersWithDeptInfo(@Param("userIds") List<Long> userIds);
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAdvisorHistory;
|
||||
import org.dromara.stgl.domain.vo.StglClubAdvisorHistoryVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史Mapper接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface StglClubAdvisorHistoryMapper extends BaseMapperPlus<StglClubAdvisorHistory, StglClubAdvisorHistoryVo> {
|
||||
|
||||
/**
|
||||
* 查询指定社团的当前在任指导老师
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 当前在任指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> selectCurrentAdvisorsByClubId(@Param("clubId") Long clubId);
|
||||
|
||||
/**
|
||||
* 查询指定社团的历史指导老师(已离任)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 历史指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> selectHistoryAdvisorsByClubId(@Param("clubId") Long clubId);
|
||||
|
||||
/**
|
||||
* 查询指定社团的所有指导老师(包含当前和历史)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 所有指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> selectAllAdvisorsByClubId(@Param("clubId") Long clubId);
|
||||
|
||||
/**
|
||||
* 批量设置指导老师为历史状态(离任)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param advisorNames 指导老师姓名列表
|
||||
* @param endTime 离任时间
|
||||
* @return 更新记录数
|
||||
*/
|
||||
int batchSetHistoryStatus(@Param("clubId") Long clubId,
|
||||
@Param("advisorNames") List<String> advisorNames,
|
||||
@Param("endTime") java.util.Date endTime);
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReviewActivity;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审记录活动Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-12-31
|
||||
*/
|
||||
public interface StglClubAnnualReviewActivityMapper extends BaseMapperPlus<StglClubAnnualReviewActivity, StglClubAnnualReviewActivity> {
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询活动列表
|
||||
*/
|
||||
List<StglClubAnnualReviewActivity> selectActivitiesByAnnualReviewId(@Param("annualReviewId") Long annualReviewId);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID删除活动
|
||||
*/
|
||||
int deleteActivitiesByAnnualReviewId(@Param("annualReviewId") Long annualReviewId);
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import org.dromara.stgl.domain.vo.StglClubAnnualReviewVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 社团年审记录Mapper接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface StglClubAnnualReviewMapper extends BaseMapperPlus<StglClubAnnualReview, StglClubAnnualReviewVo> {
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClubAnnualReviewMember;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审记录成员Mapper接口
|
||||
*
|
||||
* @author Lion Li
|
||||
* @date 2024-12-31
|
||||
*/
|
||||
public interface StglClubAnnualReviewMemberMapper extends BaseMapperPlus<StglClubAnnualReviewMember, StglClubAnnualReviewMember> {
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询成员列表
|
||||
*/
|
||||
List<StglClubAnnualReviewMember> selectMembersByAnnualReviewId(@Param("annualReviewId") Long annualReviewId);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID删除成员
|
||||
*/
|
||||
int deleteMembersByAnnualReviewId(@Param("annualReviewId") Long annualReviewId);
|
||||
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.StglAnnualReviewAudit;
|
||||
import org.dromara.stgl.domain.bo.StglAnnualReviewApprovalBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审审批Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface IStglAnnualReviewAuditService {
|
||||
|
||||
/**
|
||||
* 查询社团年审审批
|
||||
*
|
||||
* @param id 社团年审审批主键
|
||||
* @return 社团年审审批
|
||||
*/
|
||||
StglAnnualReviewAudit queryById(Long id);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询审批记录
|
||||
*
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> queryByAnnualReviewId(Long annualReviewId);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID和节点代码查询审批记录
|
||||
*
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @param nodeCode 节点代码
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> queryByAnnualReviewIdAndNodeCode(Long annualReviewId, String nodeCode);
|
||||
|
||||
/**
|
||||
* 根据审批人ID查询待审批记录
|
||||
*
|
||||
* @param approverId 审批人ID
|
||||
* @return 审批记录列表
|
||||
*/
|
||||
List<StglAnnualReviewAudit> queryPendingByApproverId(Long approverId);
|
||||
|
||||
/**
|
||||
* 新增社团年审审批
|
||||
*
|
||||
* @param stglAnnualReviewAudit 社团年审审批
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(StglAnnualReviewAudit stglAnnualReviewAudit);
|
||||
|
||||
/**
|
||||
* 修改社团年审审批
|
||||
*
|
||||
* @param stglAnnualReviewAudit 社团年审审批
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(StglAnnualReviewAudit stglAnnualReviewAudit);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团年审审批信息
|
||||
*
|
||||
* @param ids 需要删除的社团年审审批主键集合
|
||||
* @param isValid 是否校验,true-删除前校验,false-不校验
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 创建指导老师审批记录
|
||||
*
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @param advisorIds 指导老师ID列表
|
||||
* @param advisorNames 指导老师姓名列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean createAdvisorApprovalRecords(Long annualReviewId, List<Long> advisorIds, List<String> advisorNames);
|
||||
|
||||
/**
|
||||
* 审批年审记录
|
||||
*
|
||||
* @param auditId 审批记录ID
|
||||
* @param approveResult 审批结果
|
||||
* @param approveOpinion 审批意见
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean approveAnnualReview(Long auditId, String approveResult, String approveOpinion);
|
||||
|
||||
/**
|
||||
* 审批年审记录(支持动态审核人选择)
|
||||
*
|
||||
* @param approvalBo 审批请求对象
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean approveAnnualReview(StglAnnualReviewApprovalBo approvalBo);
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglAuditorVo;
|
||||
import org.dromara.stgl.domain.bo.StglAuditorBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface IStglAuditorService {
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 社团管理审核人配置
|
||||
*/
|
||||
StglAuditorVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团管理审核人配置集合
|
||||
*/
|
||||
TableDataInfo<StglAuditorVo> queryPageList(StglAuditorBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 社团管理审核人配置集合
|
||||
*/
|
||||
List<StglAuditorVo> queryList(StglAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 新增社团管理审核人配置
|
||||
*
|
||||
* @param bo 社团管理审核人配置
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(StglAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 修改社团管理审核人配置
|
||||
*
|
||||
* @param bo 社团管理审核人配置
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(StglAuditorBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团管理审核人配置信息
|
||||
*
|
||||
* @param ids 需要删除的主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @param remark 备注
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean batchAddAuditors(List<Long> userIds, String remark);
|
||||
|
||||
/**
|
||||
* 查询我配置的审核人列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 审核人列表
|
||||
*/
|
||||
TableDataInfo<StglAuditorVo> queryMyConfigList(StglAuditorBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 批量启用审核人
|
||||
*
|
||||
* @param ids 审核人ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean enableAuditors(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量停用审核人
|
||||
*
|
||||
* @param ids 审核人ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean disableAuditors(List<Long> ids);
|
||||
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglClubAdvisorHistoryVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubAdvisorHistoryBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
public interface IStglClubAdvisorHistoryService {
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史
|
||||
*/
|
||||
StglClubAdvisorHistoryVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史列表
|
||||
*/
|
||||
TableDataInfo<StglClubAdvisorHistoryVo> queryPageList(StglClubAdvisorHistoryBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> queryList(StglClubAdvisorHistoryBo bo);
|
||||
|
||||
/**
|
||||
* 新增社团指导老师任职历史
|
||||
*/
|
||||
Boolean insertByBo(StglClubAdvisorHistoryBo bo);
|
||||
|
||||
/**
|
||||
* 修改社团指导老师任职历史
|
||||
*/
|
||||
Boolean updateByBo(StglClubAdvisorHistoryBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团指导老师任职历史信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 查询指定社团的当前在任指导老师
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 当前在任指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> getCurrentAdvisorsByClubId(Long clubId);
|
||||
|
||||
/**
|
||||
* 查询指定社团的历史指导老师(已离任)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 历史指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> getHistoryAdvisorsByClubId(Long clubId);
|
||||
|
||||
/**
|
||||
* 查询指定社团的所有指导老师(包含当前和历史)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 所有指导老师列表
|
||||
*/
|
||||
List<StglClubAdvisorHistoryVo> getAllAdvisorsByClubId(Long clubId);
|
||||
|
||||
/**
|
||||
* 更新社团指导老师历史记录
|
||||
* 对比新旧指导老师列表,处理新增和离任
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param newAdvisors 新的指导老师列表
|
||||
*/
|
||||
void updateClubAdvisors(Long clubId, List<AdvisorInfo> newAdvisors);
|
||||
|
||||
/**
|
||||
* 更新社团指导老师历史记录(指定开始时间)
|
||||
* 对比新旧指导老师列表,处理新增和离任
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param newAdvisors 新的指导老师列表
|
||||
* @param startTime 新指导老师的上任时间(如社团成立日期)
|
||||
*/
|
||||
void updateClubAdvisors(Long clubId, List<AdvisorInfo> newAdvisors, java.util.Date startTime);
|
||||
|
||||
/**
|
||||
* 指导老师信息
|
||||
*/
|
||||
class AdvisorInfo {
|
||||
private String name;
|
||||
private String dept;
|
||||
private String phone;
|
||||
private String email;
|
||||
private Long userId;
|
||||
|
||||
// 构造方法
|
||||
public AdvisorInfo() {}
|
||||
|
||||
public AdvisorInfo(String name, String dept, String phone, String email, Long userId) {
|
||||
this.name = name;
|
||||
this.dept = dept;
|
||||
this.phone = phone;
|
||||
this.email = email;
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
// getter和setter方法
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
|
||||
public String getDept() { return dept; }
|
||||
public void setDept(String dept) { this.dept = dept; }
|
||||
|
||||
public String getPhone() { return phone; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
|
||||
public Long getUserId() { return userId; }
|
||||
public void setUserId(Long userId) { this.userId = userId; }
|
||||
}
|
||||
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglClubAnnualReviewVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubAnnualReviewBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团年审记录Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglClubAnnualReviewService {
|
||||
|
||||
/**
|
||||
* 查询社团年审记录
|
||||
*/
|
||||
StglClubAnnualReviewVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询社团年审记录列表
|
||||
*/
|
||||
TableDataInfo<StglClubAnnualReviewVo> queryPageList(StglClubAnnualReviewBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询社团年审记录列表
|
||||
*/
|
||||
List<StglClubAnnualReviewVo> queryList(StglClubAnnualReviewBo bo);
|
||||
|
||||
/**
|
||||
* 新增社团年审记录
|
||||
*/
|
||||
Boolean insertByBo(StglClubAnnualReviewBo bo);
|
||||
|
||||
/**
|
||||
* 修改社团年审记录
|
||||
*/
|
||||
Boolean updateByBo(StglClubAnnualReviewBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团年审记录信息
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 提交年审记录
|
||||
*/
|
||||
Boolean submitReview(Long id);
|
||||
|
||||
/**
|
||||
* 撤回年审记录
|
||||
*/
|
||||
Boolean withdrawReview(Long id);
|
||||
|
||||
/**
|
||||
* 审核年审记录
|
||||
*/
|
||||
Boolean auditReview(Long id, String auditResult, String auditOpinion, String auditType);
|
||||
|
||||
/**
|
||||
* 获取当前用户的年审记录列表
|
||||
*/
|
||||
TableDataInfo<StglClubAnnualReviewVo> queryMyPageList(StglClubAnnualReviewBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 检查是否可以创建年审记录
|
||||
*/
|
||||
Boolean checkCanCreateReview(Long clubId, Integer reviewYear);
|
||||
|
||||
/**
|
||||
* 根据社团ID和成立日期获取一年内的活动数据
|
||||
* @param clubId 社团ID
|
||||
* @param establishDate 成立日期字符串 (yyyy-MM-dd格式)
|
||||
* @return 活动列表
|
||||
*/
|
||||
List<org.dromara.stgl.domain.vo.StglActivityVo> getClubActivitiesByReviewYear(Long clubId, Integer reviewYear);
|
||||
|
||||
/**
|
||||
* 根据年审记录ID获取对应的活动数据
|
||||
* @param annualReviewId 年审记录ID
|
||||
* @return 年审活动列表
|
||||
*/
|
||||
List<org.dromara.stgl.domain.vo.StglClubAnnualReviewActivityVo> getAnnualReviewActivities(Long annualReviewId);
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.ClubActivityPermissionResult;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 社团权限管理Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglClubPermissionService {
|
||||
|
||||
/**
|
||||
* 检查社团活动权限(实时计算)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 权限检查结果
|
||||
*/
|
||||
ClubActivityPermissionResult checkClubActivityPermission(Long clubId);
|
||||
|
||||
/**
|
||||
* 批量检查社团活动权限
|
||||
*
|
||||
* @param clubIds 社团ID列表
|
||||
* @return 权限检查结果映射(key: clubId, value: 权限结果)
|
||||
*/
|
||||
Map<Long, ClubActivityPermissionResult> batchCheckClubActivityPermission(List<Long> clubIds);
|
||||
|
||||
/**
|
||||
* 检查社团是否在年审窗口期内
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return true-在窗口期内,false-不在窗口期内
|
||||
*/
|
||||
boolean isInAnnualReviewWindow(Long clubId);
|
||||
|
||||
/**
|
||||
* 获取社团距离下次年审的天数
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 距离年审的天数,负数表示已过期
|
||||
*/
|
||||
long getDaysUntilNextAnnualReview(Long clubId);
|
||||
|
||||
/**
|
||||
* 检查社团是否已在当前年审期内提交年审
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return true-已提交,false-未提交
|
||||
*/
|
||||
boolean hasSubmittedCurrentYearAnnualReview(Long clubId);
|
||||
}
|
||||
+52
-1
@@ -129,7 +129,7 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
StglActivity activity = BeanUtil.toBean(bo, StglActivity.class);
|
||||
|
||||
// 设置查询条件:只查询报名状态为0(未开始)和1(报名中)的活动
|
||||
// 通过设置params参数来传递IN查询条件
|
||||
// 注意:现在草稿、待审批、已驳回状态的活动的registration_status为NULL,不会被包含在查询结果中
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("registrationStatusList", Arrays.asList("0", "1"));
|
||||
|
||||
@@ -258,6 +258,9 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
StglActivity add = MapstructUtils.convert(bo, StglActivity.class);
|
||||
validEntityBeforeSave(add);
|
||||
|
||||
// 处理多选部门数据
|
||||
handleMultiDeptData(bo, add);
|
||||
|
||||
// 设置默认值
|
||||
if (add.getIsFinished() == null) {
|
||||
add.setIsFinished(0);
|
||||
@@ -287,6 +290,9 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
StglActivity update = MapstructUtils.convert(bo, StglActivity.class);
|
||||
validEntityBeforeSave(update);
|
||||
|
||||
// 处理多选部门数据
|
||||
handleMultiDeptData(bo, update);
|
||||
|
||||
// 获取更新前的活动信息,用于比较指导老师变化
|
||||
StglActivity oldActivity = null;
|
||||
if (update.getId() != null) {
|
||||
@@ -857,4 +863,49 @@ public class StglActivityServiceImpl extends ServiceImpl<StglActivityMapper, Stg
|
||||
// 使用自定义SQL查询评分详情,关联用户表获取完整信息
|
||||
return stglActivityRatingMapper.selectActivityRatingsWithUserInfo(activityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理多选部门数据
|
||||
* 将前端传递的多选部门数据转换为后端存储格式
|
||||
*/
|
||||
private void handleMultiDeptData(StglActivityBo bo, StglActivity entity) {
|
||||
// 如果有多选部门ID数据(JSON格式字符串)
|
||||
if (StringUtils.isNotBlank(bo.getRelatedDeptIds())) {
|
||||
try {
|
||||
// 解析JSON格式的部门ID列表
|
||||
List<Long> deptIds = JsonUtils.parseArray(bo.getRelatedDeptIds(), Long.class);
|
||||
|
||||
if (deptIds != null && !deptIds.isEmpty()) {
|
||||
// 设置多选部门ID列表(JSON格式)
|
||||
entity.setRelatedDeptIds(JsonUtils.toJsonString(deptIds));
|
||||
|
||||
// 设置第一个部门作为主要关联部门(保持兼容性)
|
||||
entity.setRelatedDeptId(deptIds.get(0));
|
||||
|
||||
// 如果有多选部门名称,直接使用
|
||||
if (StringUtils.isNotBlank(bo.getRelatedDeptNames())) {
|
||||
entity.setRelatedDeptNames(bo.getRelatedDeptNames());
|
||||
|
||||
// 设置第一个部门名称作为主要关联部门名称
|
||||
String[] deptNames = bo.getRelatedDeptNames().split(",");
|
||||
if (deptNames.length > 0) {
|
||||
entity.setRelatedDeptName(deptNames[0].trim());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("处理多选部门数据 - 活动ID: {}, 部门ID列表: {}, 部门名称列表: {}",
|
||||
entity.getId(), entity.getRelatedDeptIds(), entity.getRelatedDeptNames());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析多选部门数据失败: {}", bo.getRelatedDeptIds(), e);
|
||||
// 解析失败时清空多选字段
|
||||
entity.setRelatedDeptIds(null);
|
||||
entity.setRelatedDeptNames(null);
|
||||
}
|
||||
} else {
|
||||
// 没有多选部门数据,清空相关字段
|
||||
entity.setRelatedDeptIds(null);
|
||||
entity.setRelatedDeptNames(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
+409
@@ -0,0 +1,409 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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 org.dromara.stgl.domain.StglAnnualReviewAudit;
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import org.dromara.stgl.domain.bo.StglAnnualReviewApprovalBo;
|
||||
import org.dromara.stgl.mapper.StglAnnualReviewAuditMapper;
|
||||
import org.dromara.stgl.mapper.StglClubAnnualReviewMapper;
|
||||
import org.dromara.stgl.service.IStglAnnualReviewAuditService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 社团年审审批Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglAnnualReviewAuditServiceImpl implements IStglAnnualReviewAuditService {
|
||||
|
||||
private final StglAnnualReviewAuditMapper baseMapper;
|
||||
private final StglClubAnnualReviewMapper annualReviewMapper;
|
||||
|
||||
/**
|
||||
* 查询社团年审审批
|
||||
*/
|
||||
@Override
|
||||
public StglAnnualReviewAudit queryById(Long id) {
|
||||
return baseMapper.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年审记录ID查询审批记录
|
||||
*/
|
||||
@Override
|
||||
public List<StglAnnualReviewAudit> queryByAnnualReviewId(Long annualReviewId) {
|
||||
return baseMapper.selectByAnnualReviewId(annualReviewId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年审记录ID和节点代码查询审批记录
|
||||
*/
|
||||
@Override
|
||||
public List<StglAnnualReviewAudit> queryByAnnualReviewIdAndNodeCode(Long annualReviewId, String nodeCode) {
|
||||
return baseMapper.selectByAnnualReviewIdAndNodeCode(annualReviewId, nodeCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据审批人ID查询待审批记录
|
||||
*/
|
||||
@Override
|
||||
public List<StglAnnualReviewAudit> queryPendingByApproverId(Long approverId) {
|
||||
return baseMapper.selectPendingByApproverId(approverId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团年审审批
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(StglAnnualReviewAudit bo) {
|
||||
StglAnnualReviewAudit add = BeanUtil.toBean(bo, StglAnnualReviewAudit.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团年审审批
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(StglAnnualReviewAudit bo) {
|
||||
StglAnnualReviewAudit update = BeanUtil.toBean(bo, StglAnnualReviewAudit.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglAnnualReviewAudit entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除社团年审审批
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指导老师审批记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean createAdvisorApprovalRecords(Long annualReviewId, List<Long> advisorIds, List<String> advisorNames) {
|
||||
if (ObjectUtil.isEmpty(advisorIds) || ObjectUtil.isEmpty(advisorNames) || advisorIds.size() != advisorNames.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除已存在的指导老师审批记录
|
||||
LambdaQueryWrapper<StglAnnualReviewAudit> wrapper = Wrappers.lambdaQuery();
|
||||
wrapper.eq(StglAnnualReviewAudit::getAnnualReviewId, annualReviewId)
|
||||
.eq(StglAnnualReviewAudit::getNodeCode, "advisor_approve");
|
||||
baseMapper.delete(wrapper);
|
||||
|
||||
// 创建新的指导老师审批记录
|
||||
for (int i = 0; i < advisorIds.size(); i++) {
|
||||
StglAnnualReviewAudit audit = new StglAnnualReviewAudit();
|
||||
audit.setAnnualReviewId(annualReviewId);
|
||||
audit.setNodeCode("advisor_approve");
|
||||
audit.setNodeName("指导老师审批");
|
||||
|
||||
// 设置节点顺序:单个指导老师为1.0,多个指导老师为1.1, 1.2, 1.3...
|
||||
if (advisorIds.size() == 1) {
|
||||
audit.setNodeOrder(new BigDecimal("1.0"));
|
||||
} else {
|
||||
audit.setNodeOrder(new BigDecimal("1." + (i + 1)));
|
||||
}
|
||||
|
||||
// 设置节点状态:第一个为pending,其他为waiting
|
||||
audit.setNodeStatus(i == 0 ? "pending" : "waiting");
|
||||
audit.setApproverId(advisorIds.get(i));
|
||||
audit.setApproverName(advisorNames.get(i));
|
||||
|
||||
baseMapper.insert(audit);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean approveAnnualReview(Long auditId, String approveResult, String approveOpinion) {
|
||||
// 1. 获取当前审批记录
|
||||
StglAnnualReviewAudit currentAudit = baseMapper.selectById(auditId);
|
||||
if (currentAudit == null || !"pending".equals(currentAudit.getNodeStatus())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 更新当前审批记录
|
||||
currentAudit.setNodeStatus("approved");
|
||||
currentAudit.setApproveResult(approveResult);
|
||||
currentAudit.setApproveOpinion(approveOpinion);
|
||||
currentAudit.setApproveTime(new Date());
|
||||
baseMapper.updateById(currentAudit);
|
||||
|
||||
// 3. 如果审批不通过,直接更新年审记录状态为4(审核不通过)
|
||||
if ("不通过".equals(approveResult)) {
|
||||
StglClubAnnualReview annualReview = annualReviewMapper.selectById(currentAudit.getAnnualReviewId());
|
||||
if (annualReview != null) {
|
||||
annualReview.setStatus("4");
|
||||
annualReviewMapper.updateById(annualReview);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 4. 如果审批通过,检查是否有下一个待审批的同环节审批人
|
||||
List<StglAnnualReviewAudit> samePhaseAudits = baseMapper.selectByAnnualReviewIdAndNodeCode(
|
||||
currentAudit.getAnnualReviewId(), currentAudit.getNodeCode());
|
||||
|
||||
// 查找下一个waiting状态的审批记录
|
||||
StglAnnualReviewAudit nextAudit = null;
|
||||
for (StglAnnualReviewAudit audit : samePhaseAudits) {
|
||||
if ("waiting".equals(audit.getNodeStatus()) &&
|
||||
audit.getNodeOrder().compareTo(currentAudit.getNodeOrder()) > 0) {
|
||||
if (nextAudit == null || audit.getNodeOrder().compareTo(nextAudit.getNodeOrder()) < 0) {
|
||||
nextAudit = audit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 如果有下一个审批人,将其状态改为pending
|
||||
if (nextAudit != null) {
|
||||
nextAudit.setNodeStatus("pending");
|
||||
baseMapper.updateById(nextAudit);
|
||||
} else {
|
||||
// 6. 如果同环节所有审批人都审批通过,检查是否是第一个审批节点,决定是否更新状态为2(审核中)
|
||||
boolean allApproved = samePhaseAudits.stream()
|
||||
.allMatch(audit -> "approved".equals(audit.getNodeStatus()) && "通过".equals(audit.getApproveResult()));
|
||||
|
||||
if (allApproved) {
|
||||
// 只有第一个审批节点(node_order=1.1)通过时才设置为2-审核中
|
||||
if (isFirstApprovalNode(currentAudit)) {
|
||||
StglClubAnnualReview annualReview = annualReviewMapper.selectById(currentAudit.getAnnualReviewId());
|
||||
if (annualReview != null) {
|
||||
annualReview.setStatus("2");
|
||||
annualReviewMapper.updateById(annualReview);
|
||||
log.info("第一个审批节点通过,年审记录状态更新为2-审核中,年审记录ID: {}", annualReview.getId());
|
||||
}
|
||||
} else {
|
||||
log.info("非第一个审批节点通过,保持当前状态,当前节点: {}, node_order: {}",
|
||||
currentAudit.getNodeName(), currentAudit.getNodeOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批年审记录(支持动态审核人选择)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean approveAnnualReview(StglAnnualReviewApprovalBo approvalBo) {
|
||||
// 调用原有方法进行基础审批
|
||||
Boolean result = approveAnnualReview(approvalBo.getAuditId(),
|
||||
approvalBo.getApproveResult(),
|
||||
approvalBo.getApproveOpinion());
|
||||
|
||||
// 如果审批通过且有指定下一步审核人,创建新的审批记录
|
||||
if (result && "通过".equals(approvalBo.getApproveResult()) &&
|
||||
approvalBo.getNextAuditors() != null && !approvalBo.getNextAuditors().isEmpty()) {
|
||||
|
||||
// 获取当前审批记录
|
||||
StglAnnualReviewAudit currentAudit = baseMapper.selectById(approvalBo.getAuditId());
|
||||
if (currentAudit != null) {
|
||||
// 创建下一步审核人的审批记录
|
||||
createNextStepAuditRecords(currentAudit.getAnnualReviewId(), approvalBo.getNextAuditors());
|
||||
}
|
||||
} else if (result && "通过".equals(approvalBo.getApproveResult()) &&
|
||||
(approvalBo.getNextAuditors() == null || approvalBo.getNextAuditors().isEmpty())) {
|
||||
|
||||
// 如果审批通过且没有下一步审核人,检查是否是校团委最后节点,决定是否结束流程
|
||||
StglAnnualReviewAudit currentAudit = baseMapper.selectById(approvalBo.getAuditId());
|
||||
if (currentAudit != null && isSchoolCommitteeLastNode(currentAudit)) {
|
||||
// 校团委最后节点审批通过,流程结束,将年审记录状态设置为3(审核通过)
|
||||
StglClubAnnualReview annualReview = annualReviewMapper.selectById(currentAudit.getAnnualReviewId());
|
||||
if (annualReview != null) {
|
||||
annualReview.setStatus("3");
|
||||
annualReviewMapper.updateById(annualReview);
|
||||
log.info("校团委最后节点审批通过,年审流程结束,年审记录ID: {}, 状态更新为: 3", annualReview.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建下一步审批记录
|
||||
*/
|
||||
private void createNextStepAuditRecords(Long annualReviewId, List<StglAnnualReviewApprovalBo.NextAuditor> nextAuditors) {
|
||||
// 查询已有的审批记录,确定下一个审批层级
|
||||
List<StglAnnualReviewAudit> existingAudits = baseMapper.selectByAnnualReviewId(annualReviewId);
|
||||
|
||||
// 确定下一个审批层级
|
||||
int nextLevel = determineNextApprovalLevel(existingAudits);
|
||||
|
||||
for (int i = 0; i < nextAuditors.size(); i++) {
|
||||
StglAnnualReviewApprovalBo.NextAuditor auditor = nextAuditors.get(i);
|
||||
|
||||
StglAnnualReviewAudit nextAudit = new StglAnnualReviewAudit();
|
||||
nextAudit.setAnnualReviewId(annualReviewId);
|
||||
nextAudit.setNodeCode(getNodeCodeByLevel(nextLevel));
|
||||
nextAudit.setNodeName(getNodeNameByLevel(nextLevel));
|
||||
|
||||
// 根据层级和顺序设置node_order
|
||||
if (nextAuditors.size() == 1 && nextLevel == 3) {
|
||||
// 校团委审批单个审核人为3.0
|
||||
nextAudit.setNodeOrder(new BigDecimal(nextLevel + ".0"));
|
||||
} else {
|
||||
// 其他情况按 层级.序号 格式设置
|
||||
nextAudit.setNodeOrder(new BigDecimal(nextLevel + "." + (i + 1)));
|
||||
}
|
||||
|
||||
nextAudit.setApproverId(auditor.getUserId());
|
||||
nextAudit.setApproverName(auditor.getNickName() != null ? auditor.getNickName() : auditor.getUserName());
|
||||
nextAudit.setNodeStatus(i == 0 ? "pending" : "waiting"); // 第一个为pending,其余为waiting
|
||||
nextAudit.setCreateTime(new Date());
|
||||
|
||||
baseMapper.insert(nextAudit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定下一个审批层级
|
||||
*/
|
||||
private int determineNextApprovalLevel(List<StglAnnualReviewAudit> existingAudits) {
|
||||
int maxLevel = 1; // 默认从指导老师审批层级开始
|
||||
|
||||
for (StglAnnualReviewAudit audit : existingAudits) {
|
||||
BigDecimal nodeOrder = audit.getNodeOrder();
|
||||
if (nodeOrder != null) {
|
||||
int level = nodeOrder.intValue(); // 获取整数部分作为层级
|
||||
if (level > maxLevel) {
|
||||
maxLevel = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxLevel + 1; // 下一个层级
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据层级获取节点代码
|
||||
*/
|
||||
private String getNodeCodeByLevel(int level) {
|
||||
switch (level) {
|
||||
case 1:
|
||||
return "advisor_approve";
|
||||
case 2:
|
||||
return "college_approve";
|
||||
case 3:
|
||||
return "youth_league_approve";
|
||||
default:
|
||||
return "college_approve"; // 默认为二级学院审批
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据层级获取节点名称
|
||||
*/
|
||||
private String getNodeNameByLevel(int level) {
|
||||
switch (level) {
|
||||
case 1:
|
||||
return "指导老师审批";
|
||||
case 2:
|
||||
return "二级学院审批";
|
||||
case 3:
|
||||
return "校团委审批";
|
||||
default:
|
||||
return "二级学院审批"; // 默认为二级学院审批
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为第一个审批节点(node_order=1.1)
|
||||
*/
|
||||
private boolean isFirstApprovalNode(StglAnnualReviewAudit currentAudit) {
|
||||
// 检查node_order是否为1.1
|
||||
return currentAudit != null &&
|
||||
currentAudit.getNodeOrder() != null &&
|
||||
currentAudit.getNodeOrder().compareTo(new BigDecimal("1.1")) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前是否是校团委审批的最后一个节点
|
||||
*/
|
||||
private boolean isSchoolCommitteeLastNode(StglAnnualReviewAudit currentAudit) {
|
||||
if (currentAudit == null || currentAudit.getNodeOrder() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentNodeName = currentAudit.getNodeName();
|
||||
BigDecimal currentNodeOrder = currentAudit.getNodeOrder();
|
||||
|
||||
// 检查是否是校团委审批节点且node_order是3.X格式
|
||||
boolean isSchoolCommitteeNode = "校团委审批".equals(currentNodeName);
|
||||
boolean isNodeOrder3X = currentNodeOrder.compareTo(new BigDecimal("3")) >= 0 &&
|
||||
currentNodeOrder.compareTo(new BigDecimal("4")) < 0;
|
||||
|
||||
if (!isSchoolCommitteeNode || !isNodeOrder3X) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取同一环节的所有节点
|
||||
List<StglAnnualReviewAudit> samePhaseNodes = baseMapper.selectByAnnualReviewIdAndNodeCode(
|
||||
currentAudit.getAnnualReviewId(), currentAudit.getNodeCode());
|
||||
|
||||
if (samePhaseNodes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 找出同一环节中最大的nodeOrder
|
||||
BigDecimal maxNodeOrder = samePhaseNodes.stream()
|
||||
.map(StglAnnualReviewAudit::getNodeOrder)
|
||||
.filter(order -> order != null)
|
||||
.max(BigDecimal::compareTo)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
|
||||
// 当前节点的nodeOrder等于同环节最大nodeOrder时,表示是最后一个节点
|
||||
boolean isLastNode = currentNodeOrder.compareTo(maxNodeOrder) == 0;
|
||||
|
||||
log.info("校团委最后节点判断: 节点名称={}, nodeOrder={}, 是否校团委={}, 是否3.X={}, 是否最后节点={}",
|
||||
currentNodeName, currentNodeOrder, isSchoolCommitteeNode, isNodeOrder3X, isLastNode);
|
||||
|
||||
return isLastNode;
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
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.dromara.stgl.domain.bo.StglAuditorBo;
|
||||
import org.dromara.stgl.domain.vo.StglAuditorVo;
|
||||
import org.dromara.stgl.domain.StglAuditor;
|
||||
import org.dromara.stgl.domain.StglUserWithDeptInfo;
|
||||
import org.dromara.stgl.mapper.StglAuditorMapper;
|
||||
import org.dromara.stgl.service.IStglAuditorService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 社团管理审核人配置Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglAuditorServiceImpl implements IStglAuditorService {
|
||||
|
||||
private final StglAuditorMapper baseMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置
|
||||
*/
|
||||
@Override
|
||||
public StglAuditorVo queryById(Long id) {
|
||||
StglAuditor entity = baseMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
return MapstructUtils.convert(entity, StglAuditorVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglAuditorVo> queryPageList(StglAuditorBo bo, PageQuery pageQuery) {
|
||||
// 直接使用查询条件构建器
|
||||
LambdaQueryWrapper<StglAuditor> lqw = buildQueryWrapper(bo);
|
||||
Page<StglAuditor> entityPage = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
|
||||
// 转换为 VO 对象
|
||||
List<StglAuditorVo> voList = new ArrayList<>();
|
||||
for (StglAuditor entity : entityPage.getRecords()) {
|
||||
StglAuditorVo vo = MapstructUtils.convert(entity, StglAuditorVo.class);
|
||||
voList.add(vo);
|
||||
}
|
||||
|
||||
// 构建分页结果
|
||||
Page<StglAuditorVo> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
|
||||
voPage.setRecords(voList);
|
||||
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团管理审核人配置列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglAuditorVo> queryList(StglAuditorBo bo) {
|
||||
LambdaQueryWrapper<StglAuditor> lqw = buildQueryWrapper(bo);
|
||||
List<StglAuditor> entityList = baseMapper.selectList(lqw);
|
||||
|
||||
// 转换为 VO 对象
|
||||
List<StglAuditorVo> voList = new ArrayList<>();
|
||||
for (StglAuditor entity : entityList) {
|
||||
StglAuditorVo vo = MapstructUtils.convert(entity, StglAuditorVo.class);
|
||||
voList.add(vo);
|
||||
}
|
||||
|
||||
return voList;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglAuditor> buildQueryWrapper(StglAuditorBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglAuditor> lqw = Wrappers.<StglAuditor>lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, StglAuditor::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getUserName()), StglAuditor::getUserName, bo.getUserName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getNickName()), StglAuditor::getNickName, bo.getNickName());
|
||||
lqw.eq(bo.getDeptId() != null, StglAuditor::getDeptId, bo.getDeptId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), StglAuditor::getStatus, bo.getStatus());
|
||||
lqw.eq(bo.getConfigBy() != null, StglAuditor::getConfigBy, bo.getConfigBy());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
StglAuditor::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
lqw.orderByDesc(StglAuditor::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团管理审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(StglAuditorBo bo) {
|
||||
StglAuditor add = MapstructUtils.convert(bo, StglAuditor.class);
|
||||
validEntityBeforeSave(add);
|
||||
|
||||
// 设置配置人信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
add.setConfigBy(currentUserId);
|
||||
|
||||
// 获取当前用户信息设置配置人姓名
|
||||
try {
|
||||
SysUserVo currentUser = sysUserService.selectUserById(currentUserId);
|
||||
if (currentUser != null) {
|
||||
add.setConfigByName(currentUser.getUserName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果获取失败,使用默认值
|
||||
add.setConfigByName("系统管理员");
|
||||
}
|
||||
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团管理审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(StglAuditorBo bo) {
|
||||
StglAuditor update = MapstructUtils.convert(bo, StglAuditor.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglAuditor entity) {
|
||||
if (entity.getUserId() != null) {
|
||||
// 检查用户是否已存在(新增时或修改用户ID时)
|
||||
if (entity.getId() == null) {
|
||||
// 新增时检查
|
||||
int count = baseMapper.checkUserExists(entity.getUserId());
|
||||
if (count > 0) {
|
||||
throw new ServiceException("该用户已配置为审核人,不能重复添加");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除社团管理审核人配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids) {
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加审核人
|
||||
*/
|
||||
@Override
|
||||
public Boolean batchAddAuditors(List<Long> userIds, String remark) {
|
||||
if (userIds == null || userIds.isEmpty()) {
|
||||
throw new ServiceException("用户ID列表不能为空");
|
||||
}
|
||||
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
String currentUserName = "系统管理员";
|
||||
|
||||
// 获取当前用户信息
|
||||
try {
|
||||
SysUserVo currentUser = sysUserService.selectUserById(currentUserId);
|
||||
if (currentUser != null) {
|
||||
currentUserName = currentUser.getUserName();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 使用默认值
|
||||
}
|
||||
|
||||
// 1. 获取完整的用户信息(包含部门信息)
|
||||
List<StglUserWithDeptInfo> users = baseMapper.selectUsersWithDeptInfo(userIds);
|
||||
if (users.isEmpty()) {
|
||||
throw new ServiceException("没有找到有效的用户信息");
|
||||
}
|
||||
|
||||
// 2. 过滤已存在的审核人
|
||||
List<Long> existingUserIds = baseMapper.selectList(Wrappers.<StglAuditor>lambdaQuery()
|
||||
.in(StglAuditor::getUserId, userIds))
|
||||
.stream().map(StglAuditor::getUserId).collect(Collectors.toList());
|
||||
|
||||
// 3. 构建新增审核人列表
|
||||
List<StglAuditor> auditorList = new ArrayList<>();
|
||||
for (StglUserWithDeptInfo user : users) {
|
||||
if (!existingUserIds.contains(user.getUserId())) {
|
||||
StglAuditor auditor = new StglAuditor();
|
||||
auditor.setUserId(user.getUserId());
|
||||
auditor.setUserName(user.getUserName());
|
||||
auditor.setNickName(user.getNickName());
|
||||
auditor.setDeptId(user.getDeptId());
|
||||
auditor.setDeptName(user.getDeptName() != null ? user.getDeptName() : "");
|
||||
auditor.setPhoneNumber(user.getPhonenumber());
|
||||
auditor.setEmail(user.getEmail());
|
||||
auditor.setStatus("1"); // 默认正常状态
|
||||
auditor.setRemark(remark);
|
||||
auditor.setConfigBy(currentUserId);
|
||||
auditor.setConfigByName(currentUserName);
|
||||
auditorList.add(auditor);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 批量保存
|
||||
if (auditorList.isEmpty()) {
|
||||
throw new ServiceException("所有用户都已存在,无需重复添加");
|
||||
}
|
||||
|
||||
return baseMapper.insertBatch(auditorList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我配置的审核人列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglAuditorVo> queryMyConfigList(StglAuditorBo bo, PageQuery pageQuery) {
|
||||
bo.setConfigBy(LoginHelper.getUserId());
|
||||
return queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量启用审核人
|
||||
*/
|
||||
@Override
|
||||
public Boolean enableAuditors(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.enableAuditorsByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量停用审核人
|
||||
*/
|
||||
@Override
|
||||
public Boolean disableAuditors(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.disableAuditorsByIds(ids) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
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 org.dromara.stgl.domain.bo.StglClubAdvisorHistoryBo;
|
||||
import org.dromara.stgl.domain.vo.StglClubAdvisorHistoryVo;
|
||||
import org.dromara.stgl.domain.StglClubAdvisorHistory;
|
||||
import org.dromara.stgl.mapper.StglClubAdvisorHistoryMapper;
|
||||
import org.dromara.stgl.service.IStglClubAdvisorHistoryService;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 社团指导老师任职历史Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClubAdvisorHistoryServiceImpl implements IStglClubAdvisorHistoryService {
|
||||
|
||||
private final StglClubAdvisorHistoryMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史
|
||||
*/
|
||||
@Override
|
||||
public StglClubAdvisorHistoryVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClubAdvisorHistoryVo> queryPageList(StglClubAdvisorHistoryBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<StglClubAdvisorHistory> lqw = buildQueryWrapper(bo);
|
||||
Page<StglClubAdvisorHistoryVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团指导老师任职历史列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubAdvisorHistoryVo> queryList(StglClubAdvisorHistoryBo bo) {
|
||||
LambdaQueryWrapper<StglClubAdvisorHistory> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglClubAdvisorHistory> buildQueryWrapper(StglClubAdvisorHistoryBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglClubAdvisorHistory> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getClubId() != null, StglClubAdvisorHistory::getClubId, bo.getClubId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAdvisorName()), StglClubAdvisorHistory::getAdvisorName, bo.getAdvisorName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAdvisorDept()), StglClubAdvisorHistory::getAdvisorDept, bo.getAdvisorDept());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAdvisorPhone()), StglClubAdvisorHistory::getAdvisorPhone, bo.getAdvisorPhone());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAdvisorEmail()), StglClubAdvisorHistory::getAdvisorEmail, bo.getAdvisorEmail());
|
||||
lqw.eq(bo.getAdvisorUserId() != null, StglClubAdvisorHistory::getAdvisorUserId, bo.getAdvisorUserId());
|
||||
lqw.eq(bo.getStatus() != null, StglClubAdvisorHistory::getStatus, bo.getStatus());
|
||||
lqw.eq(bo.getStartTime() != null, StglClubAdvisorHistory::getStartTime, bo.getStartTime());
|
||||
lqw.eq(bo.getEndTime() != null, StglClubAdvisorHistory::getEndTime, bo.getEndTime());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团指导老师任职历史
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(StglClubAdvisorHistoryBo bo) {
|
||||
StglClubAdvisorHistory add = MapstructUtils.convert(bo, StglClubAdvisorHistory.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团指导老师任职历史
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(StglClubAdvisorHistoryBo bo) {
|
||||
StglClubAdvisorHistory update = MapstructUtils.convert(bo, StglClubAdvisorHistory.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglClubAdvisorHistory entity){
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除社团指导老师任职历史
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的当前在任指导老师
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubAdvisorHistoryVo> getCurrentAdvisorsByClubId(Long clubId) {
|
||||
return baseMapper.selectCurrentAdvisorsByClubId(clubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的历史指导老师(已离任)
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubAdvisorHistoryVo> getHistoryAdvisorsByClubId(Long clubId) {
|
||||
return baseMapper.selectHistoryAdvisorsByClubId(clubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询指定社团的所有指导老师(包含当前和历史)
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubAdvisorHistoryVo> getAllAdvisorsByClubId(Long clubId) {
|
||||
return baseMapper.selectAllAdvisorsByClubId(clubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新社团指导老师历史记录
|
||||
* 对比新旧指导老师列表,处理新增和离任
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateClubAdvisors(Long clubId, List<AdvisorInfo> newAdvisors) {
|
||||
updateClubAdvisors(clubId, newAdvisors, new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新社团指导老师历史记录(指定开始时间)
|
||||
* 对比新旧指导老师列表,处理新增和离任
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateClubAdvisors(Long clubId, List<AdvisorInfo> newAdvisors, Date startTime) {
|
||||
Date currentDate = new Date();
|
||||
|
||||
// 1. 获取当前指导老师列表
|
||||
List<StglClubAdvisorHistoryVo> currentRecords = getCurrentAdvisorsByClubId(clubId);
|
||||
|
||||
// 2. 建立姓名映射
|
||||
Set<String> currentNames = currentRecords.stream()
|
||||
.map(StglClubAdvisorHistoryVo::getAdvisorName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> newNames = newAdvisors.stream()
|
||||
.map(AdvisorInfo::getName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 3. 处理被移除的指导老师
|
||||
List<String> removedNames = currentNames.stream()
|
||||
.filter(name -> !newNames.contains(name))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!removedNames.isEmpty()) {
|
||||
baseMapper.batchSetHistoryStatus(clubId, removedNames, currentDate);
|
||||
}
|
||||
|
||||
// 4. 处理新增的指导老师
|
||||
for (AdvisorInfo newAdvisor : newAdvisors) {
|
||||
if (StringUtils.isNotBlank(newAdvisor.getName()) &&
|
||||
!currentNames.contains(newAdvisor.getName())) {
|
||||
|
||||
StglClubAdvisorHistory newRecord = new StglClubAdvisorHistory();
|
||||
newRecord.setClubId(clubId);
|
||||
newRecord.setAdvisorName(newAdvisor.getName());
|
||||
newRecord.setAdvisorDept(newAdvisor.getDept());
|
||||
newRecord.setAdvisorPhone(newAdvisor.getPhone());
|
||||
newRecord.setAdvisorEmail(newAdvisor.getEmail());
|
||||
newRecord.setAdvisorUserId(newAdvisor.getUserId());
|
||||
newRecord.setStatus(1);
|
||||
// 使用传入的开始时间,而不是当前时间
|
||||
newRecord.setStartTime(startTime != null ? startTime : currentDate);
|
||||
newRecord.setEndTime(null);
|
||||
|
||||
baseMapper.insert(newRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+740
@@ -0,0 +1,740 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
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 org.dromara.common.satoken.utils.LoginHelper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.stgl.domain.bo.StglClubAnnualReviewBo;
|
||||
import org.dromara.stgl.domain.vo.StglClubAnnualReviewVo;
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import org.dromara.stgl.domain.StglClubAnnualReviewMember;
|
||||
import org.dromara.stgl.domain.StglClubAnnualReviewActivity;
|
||||
import org.dromara.stgl.mapper.StglClubAnnualReviewMapper;
|
||||
import org.dromara.stgl.mapper.StglClubAnnualReviewMemberMapper;
|
||||
import org.dromara.stgl.mapper.StglClubAnnualReviewActivityMapper;
|
||||
import org.dromara.stgl.service.IStglClubAnnualReviewService;
|
||||
import org.dromara.stgl.service.IStglActivityService;
|
||||
import org.dromara.stgl.service.IStglClubService;
|
||||
import org.dromara.stgl.service.IStglAnnualReviewAuditService;
|
||||
import org.dromara.stgl.domain.bo.StglActivityBo;
|
||||
import org.dromara.stgl.domain.vo.StglClubVo;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Date;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 社团年审记录Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClubAnnualReviewServiceImpl implements IStglClubAnnualReviewService {
|
||||
|
||||
private final StglClubAnnualReviewMapper baseMapper;
|
||||
private final StglClubAnnualReviewMemberMapper memberMapper;
|
||||
private final StglClubAnnualReviewActivityMapper activityMapper;
|
||||
private final IStglActivityService stglActivityService;
|
||||
private final IStglClubService stglClubService;
|
||||
private final IStglAnnualReviewAuditService auditService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 查询社团年审记录
|
||||
*/
|
||||
@Override
|
||||
public StglClubAnnualReviewVo queryById(Long id){
|
||||
StglClubAnnualReviewVo vo = baseMapper.selectVoById(id);
|
||||
if (vo == null) {
|
||||
log.warn("未找到年审记录,ID: {}", id);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 查询关联的成员数据
|
||||
List<StglClubAnnualReviewMember> members = memberMapper.selectMembersByAnnualReviewId(id);
|
||||
|
||||
// 查询关联的活动数据
|
||||
List<StglClubAnnualReviewActivity> activities = activityMapper.selectActivitiesByAnnualReviewId(id);
|
||||
|
||||
// 将成员和活动数据转为JSON格式返回给前端
|
||||
if (!members.isEmpty()) {
|
||||
// 转换成员数据格式,匹配前端期望的字段名
|
||||
List<Map<String, Object>> membersList = new ArrayList<>();
|
||||
for (StglClubAnnualReviewMember member : members) {
|
||||
Map<String, Object> memberMap = new HashMap<>();
|
||||
memberMap.put("name", member.getMemberName());
|
||||
memberMap.put("className", member.getClassName());
|
||||
memberMap.put("role", member.getRole());
|
||||
memberMap.put("phone", member.getContactInfo());
|
||||
membersList.add(memberMap);
|
||||
}
|
||||
vo.setMembersJson(objectMapper.writeValueAsString(membersList));
|
||||
} else {
|
||||
vo.setMembersJson("[]"); // 设置空数组而不是null
|
||||
}
|
||||
|
||||
if (!activities.isEmpty()) {
|
||||
// 转换活动数据格式,匹配前端期望的字段名
|
||||
List<Map<String, Object>> activitiesList = new ArrayList<>();
|
||||
for (StglClubAnnualReviewActivity activity : activities) {
|
||||
Map<String, Object> activityMap = new HashMap<>();
|
||||
activityMap.put("activityName", activity.getActivityName());
|
||||
activityMap.put("location", activity.getActivityLocation());
|
||||
activityMap.put("participantCount", activity.getParticipantCount());
|
||||
|
||||
// 格式化活动时间显示 - 优先使用新的开始/结束时间字段
|
||||
if (activity.getActivityStartTime() != null) {
|
||||
activityMap.put("activityStartTime", activity.getActivityStartTime().toString());
|
||||
}
|
||||
if (activity.getActivityEndTime() != null) {
|
||||
activityMap.put("activityEndTime", activity.getActivityEndTime().toString());
|
||||
}
|
||||
// 保持向后兼容
|
||||
if (activity.getActivityTime() != null) {
|
||||
activityMap.put("activityDate", activity.getActivityTime().toString());
|
||||
} else {
|
||||
activityMap.put("activityDate", "");
|
||||
}
|
||||
|
||||
activitiesList.add(activityMap);
|
||||
}
|
||||
vo.setActivitiesJson(objectMapper.writeValueAsString(activitiesList));
|
||||
} else {
|
||||
vo.setActivitiesJson("[]"); // 设置空数组而不是null
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("处理年审记录关联数据失败,ID: {}", id, e);
|
||||
// 确保JSON字段不为null
|
||||
if (vo.getMembersJson() == null) {
|
||||
vo.setMembersJson("[]");
|
||||
}
|
||||
if (vo.getActivitiesJson() == null) {
|
||||
vo.setActivitiesJson("[]");
|
||||
}
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团年审记录列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClubAnnualReviewVo> queryPageList(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<StglClubAnnualReview> lqw = buildQueryWrapper(bo);
|
||||
Page<StglClubAnnualReviewVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团年审记录列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubAnnualReviewVo> queryList(StglClubAnnualReviewBo bo) {
|
||||
LambdaQueryWrapper<StglClubAnnualReview> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglClubAnnualReview> buildQueryWrapper(StglClubAnnualReviewBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglClubAnnualReview> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getClubId() != null, StglClubAnnualReview::getClubId, bo.getClubId());
|
||||
lqw.eq(bo.getReviewYear() != null, StglClubAnnualReview::getReviewYear, bo.getReviewYear());
|
||||
lqw.between(params.get("beginReviewStartDate") != null && params.get("endReviewStartDate") != null,
|
||||
StglClubAnnualReview::getReviewStartDate, params.get("beginReviewStartDate"), params.get("endReviewStartDate"));
|
||||
lqw.between(params.get("beginReviewEndDate") != null && params.get("endReviewEndDate") != null,
|
||||
StglClubAnnualReview::getReviewEndDate, params.get("beginReviewEndDate"), params.get("endReviewEndDate"));
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClubName()), StglClubAnnualReview::getClubName, bo.getClubName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getClubType()), StglClubAnnualReview::getClubType, bo.getClubType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), StglClubAnnualReview::getStatus, bo.getStatus());
|
||||
lqw.orderByDesc(StglClubAnnualReview::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean insertByBo(StglClubAnnualReviewBo bo) {
|
||||
// 检查是否可以创建年审记录
|
||||
if (!checkCanCreateReview(bo.getClubId(), bo.getReviewYear())) {
|
||||
throw new RuntimeException("该社团在该年度已存在年审记录");
|
||||
}
|
||||
|
||||
StglClubAnnualReview add = MapstructUtils.convert(bo, StglClubAnnualReview.class);
|
||||
// 设置默认状态为草稿
|
||||
if (StringUtils.isBlank(add.getStatus())) {
|
||||
add.setStatus("0");
|
||||
}
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
|
||||
// 保存成员数据
|
||||
saveMembers(add.getId(), bo.getMembersJson());
|
||||
|
||||
// 保存活动数据
|
||||
saveActivities(add.getId(), bo.getActivitiesJson());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(StglClubAnnualReviewBo bo) {
|
||||
StglClubAnnualReview update = MapstructUtils.convert(bo, StglClubAnnualReview.class);
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
|
||||
if (flag) {
|
||||
// 保存成员数据
|
||||
saveMembers(bo.getId(), bo.getMembersJson());
|
||||
|
||||
// 保存活动数据
|
||||
saveActivities(bo.getId(), bo.getActivitiesJson());
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglClubAnnualReview entity){
|
||||
// 可以在此处进行额外的业务校验
|
||||
if (entity.getReviewStartDate() != null && entity.getReviewEndDate() != null) {
|
||||
if (entity.getReviewStartDate().after(entity.getReviewEndDate())) {
|
||||
throw new RuntimeException("年审开始日期不能晚于结束日期");
|
||||
}
|
||||
}
|
||||
|
||||
// 自动填充社长信息(如果社长姓名为空且有社团ID)
|
||||
if (entity.getClubId() != null && StringUtils.isBlank(entity.getPresidentName())) {
|
||||
StglClubVo clubVo = stglClubService.queryById(entity.getClubId());
|
||||
if (clubVo != null) {
|
||||
entity.setPresidentName(clubVo.getPresidentName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存成员数据 - 优化版本:精确删除而非全量重建
|
||||
*/
|
||||
private void saveMembers(Long annualReviewId, String membersJson) {
|
||||
if (StringUtils.isBlank(membersJson)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 1. 获取现有成员数据
|
||||
List<StglClubAnnualReviewMember> existingMembers =
|
||||
memberMapper.selectMembersByAnnualReviewId(annualReviewId);
|
||||
|
||||
// 2. 解析前端提交的数据
|
||||
List<Map<String, Object>> newMembersList = objectMapper.readValue(membersJson,
|
||||
new TypeReference<List<Map<String, Object>>>() {});
|
||||
|
||||
// 3. 构建要保留的成员标识集合
|
||||
Set<String> keepMemberKeys = newMembersList.stream()
|
||||
.map(this::generateMemberKey)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 4. 只逻辑删除不在保留列表中的成员
|
||||
for (StglClubAnnualReviewMember existingMember : existingMembers) {
|
||||
String existingKey = generateMemberKey(existingMember);
|
||||
if (!keepMemberKeys.contains(existingKey)) {
|
||||
// 逻辑删除该成员
|
||||
memberMapper.deleteById(existingMember.getId());
|
||||
log.info("删除年审成员记录: annualReviewId={}, memberName={}, className={}",
|
||||
annualReviewId, existingMember.getMemberName(), existingMember.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 新增不存在的成员(如果有的话 - 虽然当前页面只支持删除)
|
||||
Set<String> existingMemberKeys = existingMembers.stream()
|
||||
.map(this::generateMemberKey)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (Map<String, Object> memberData : newMembersList) {
|
||||
String memberKey = generateMemberKey(memberData);
|
||||
if (!existingMemberKeys.contains(memberKey)) {
|
||||
// 新增成员
|
||||
StglClubAnnualReviewMember member = new StglClubAnnualReviewMember();
|
||||
member.setAnnualReviewId(annualReviewId);
|
||||
member.setMemberName((String) memberData.get("name"));
|
||||
member.setClassName((String) memberData.get("className"));
|
||||
member.setRole((String) memberData.get("role"));
|
||||
member.setContactInfo((String) memberData.get("phone"));
|
||||
|
||||
// 注意:userId字段已从数据库表中删除,不再设置
|
||||
|
||||
memberMapper.insert(member);
|
||||
log.info("新增年审成员记录: annualReviewId={}, memberName={}, className={}",
|
||||
annualReviewId, member.getMemberName(), member.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("保存成员数据失败: annualReviewId={}", annualReviewId, e);
|
||||
throw new RuntimeException("保存成员数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成成员唯一标识 - 优先使用userId,其次使用姓名+班级组合
|
||||
*/
|
||||
private String generateMemberKey(Map<String, Object> memberData) {
|
||||
// 如果有user_id,优先使用
|
||||
Object userId = memberData.get("userId");
|
||||
if (userId != null && StringUtils.isNotBlank(userId.toString())) {
|
||||
return "user_" + userId.toString();
|
||||
}
|
||||
// 否则使用姓名+班级的组合
|
||||
String name = (String) memberData.get("name");
|
||||
String className = (String) memberData.get("className");
|
||||
return (name != null ? name : "") + "_" + (className != null ? className : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成成员唯一标识 - 实体对象版本
|
||||
*/
|
||||
private String generateMemberKey(StglClubAnnualReviewMember member) {
|
||||
// userId字段已删除,直接使用姓名+班级的组合
|
||||
String name = member.getMemberName();
|
||||
String className = member.getClassName();
|
||||
return (name != null ? name : "") + "_" + (className != null ? className : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存活动数据 - 基于ID的精确匹配版本
|
||||
*/
|
||||
private void saveActivities(Long annualReviewId, String activitiesJson) {
|
||||
if (StringUtils.isBlank(activitiesJson)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 1. 获取现有活动数据
|
||||
List<StglClubAnnualReviewActivity> existingActivities =
|
||||
activityMapper.selectActivitiesByAnnualReviewId(annualReviewId);
|
||||
|
||||
// 2. 解析前端提交的数据
|
||||
List<Map<String, Object>> newActivitiesList = objectMapper.readValue(activitiesJson,
|
||||
new TypeReference<List<Map<String, Object>>>() {});
|
||||
|
||||
// 3. 构建要保留的活动ID集合(只包含有ID的活动,即数据库中已存在的)
|
||||
Set<Long> keepActivityIds = new HashSet<>();
|
||||
List<Map<String, Object>> newActivities = new ArrayList<>();
|
||||
|
||||
for (Map<String, Object> activity : newActivitiesList) {
|
||||
Object idObj = activity.get("id");
|
||||
if (idObj != null) {
|
||||
// 现有活动,添加到保留ID集合
|
||||
Long activityId = Long.valueOf(idObj.toString());
|
||||
keepActivityIds.add(activityId);
|
||||
} else {
|
||||
// 新活动,添加到新增列表
|
||||
newActivities.add(activity);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 删除不在保留列表中的活动
|
||||
for (StglClubAnnualReviewActivity existingActivity : existingActivities) {
|
||||
if (!keepActivityIds.contains(existingActivity.getId())) {
|
||||
// 逻辑删除该活动
|
||||
activityMapper.deleteById(existingActivity.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 新增活动
|
||||
for (Map<String, Object> activityData : newActivities) {
|
||||
StglClubAnnualReviewActivity activity = new StglClubAnnualReviewActivity();
|
||||
activity.setAnnualReviewId(annualReviewId);
|
||||
activity.setActivityName((String) activityData.get("activityName"));
|
||||
activity.setActivityLocation((String) activityData.get("location"));
|
||||
activity.setParticipantCount(activityData.get("participantCount") != null ?
|
||||
Integer.parseInt(activityData.get("participantCount").toString()) : 0);
|
||||
|
||||
// 处理时间字段
|
||||
parseAndSetActivityTimes(activity, activityData);
|
||||
|
||||
activityMapper.insert(activity);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("保存活动数据失败: annualReviewId={}", annualReviewId, e);
|
||||
throw new RuntimeException("保存活动数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析并设置活动时间
|
||||
*/
|
||||
private void parseAndSetActivityTimes(StglClubAnnualReviewActivity activity, Map<String, Object> activityData) {
|
||||
// 处理活动日期 (保持兼容性)
|
||||
if (activityData.get("activityDate") != null) {
|
||||
String dateStr = activityData.get("activityDate").toString();
|
||||
if (StringUtils.isNotBlank(dateStr)) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date activityDate = sdf.parse(dateStr);
|
||||
activity.setActivityTime(activityDate);
|
||||
} catch (ParseException e) {
|
||||
log.warn("解析活动时间失败: {}", dateStr, e);
|
||||
activity.setActivityTime(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理活动开始时间
|
||||
if (activityData.get("activityStartTime") != null) {
|
||||
String startTimeStr = activityData.get("activityStartTime").toString();
|
||||
if (StringUtils.isNotBlank(startTimeStr)) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Date startTime = sdf.parse(startTimeStr);
|
||||
activity.setActivityStartTime(startTime);
|
||||
} catch (ParseException e) {
|
||||
try {
|
||||
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
Date startTime = sdf2.parse(startTimeStr);
|
||||
activity.setActivityStartTime(startTime);
|
||||
} catch (ParseException e2) {
|
||||
log.warn("解析活动开始时间失败: {}", startTimeStr, e2);
|
||||
activity.setActivityStartTime(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理活动结束时间
|
||||
if (activityData.get("activityEndTime") != null) {
|
||||
String endTimeStr = activityData.get("activityEndTime").toString();
|
||||
if (StringUtils.isNotBlank(endTimeStr)) {
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Date endTime = sdf.parse(endTimeStr);
|
||||
activity.setActivityEndTime(endTime);
|
||||
} catch (ParseException e) {
|
||||
try {
|
||||
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||
Date endTime = sdf2.parse(endTimeStr);
|
||||
activity.setActivityEndTime(endTime);
|
||||
} catch (ParseException e2) {
|
||||
log.warn("解析活动结束时间失败: {}", endTimeStr, e2);
|
||||
activity.setActivityEndTime(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成活动唯一标识 - 优先使用activityId,其次使用活动名称+时间+地点组合
|
||||
*/
|
||||
private String generateActivityKey(Map<String, Object> activityData) {
|
||||
// 如果有activity_id,优先使用
|
||||
Object activityId = activityData.get("activityId");
|
||||
if (activityId != null && StringUtils.isNotBlank(activityId.toString())) {
|
||||
return "activity_" + activityId.toString();
|
||||
}
|
||||
// 否则使用活动名称+时间+地点的组合
|
||||
String name = (String) activityData.get("activityName");
|
||||
String location = (String) activityData.get("location");
|
||||
String time = "";
|
||||
|
||||
// 优先使用开始时间,其次使用活动日期
|
||||
if (activityData.get("activityStartTime") != null) {
|
||||
time = activityData.get("activityStartTime").toString();
|
||||
} else if (activityData.get("activityDate") != null) {
|
||||
time = activityData.get("activityDate").toString();
|
||||
}
|
||||
|
||||
return (name != null ? name : "") + "_" + time + "_" + (location != null ? location : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成活动唯一标识 - 实体对象版本
|
||||
*/
|
||||
private String generateActivityKey(StglClubAnnualReviewActivity activity) {
|
||||
// activityId字段已删除,直接使用活动名称+时间+地点的组合
|
||||
String name = activity.getActivityName();
|
||||
String location = activity.getActivityLocation();
|
||||
String time = "";
|
||||
|
||||
// 优先使用开始时间,其次使用活动时间
|
||||
if (activity.getActivityStartTime() != null) {
|
||||
time = activity.getActivityStartTime().toString();
|
||||
} else if (activity.getActivityTime() != null) {
|
||||
time = activity.getActivityTime().toString();
|
||||
}
|
||||
|
||||
return (name != null ? name : "") + "_" + time + "_" + (location != null ? location : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除社团年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
// 做一些业务上的校验,判断是否需要校验
|
||||
for (Long id : ids) {
|
||||
StglClubAnnualReviewVo vo = queryById(id);
|
||||
if (vo != null && !"0".equals(vo.getStatus())) {
|
||||
throw new RuntimeException("只能删除草稿状态的年审记录");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除关联的成员和活动数据
|
||||
for (Long id : ids) {
|
||||
memberMapper.deleteMembersByAnnualReviewId(id);
|
||||
activityMapper.deleteActivitiesByAnnualReviewId(id);
|
||||
}
|
||||
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean submitReview(Long id) {
|
||||
StglClubAnnualReview entity = baseMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("年审记录不存在");
|
||||
}
|
||||
if (!"0".equals(entity.getStatus())) {
|
||||
throw new RuntimeException("只能提交草稿状态的年审记录");
|
||||
}
|
||||
|
||||
// 获取社团信息,提取指导老师信息
|
||||
StglClubVo club = stglClubService.queryById(entity.getClubId());
|
||||
if (club == null) {
|
||||
throw new RuntimeException("社团信息不存在");
|
||||
}
|
||||
|
||||
// 提取指导老师信息
|
||||
List<Long> advisorIds = new ArrayList<>();
|
||||
List<String> advisorNames = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 优先从JSON字段读取指导老师数据
|
||||
if (StringUtils.isNotBlank(club.getAdvisorsJson())) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
List<Map<String, Object>> advisors = mapper.readValue(club.getAdvisorsJson(),
|
||||
new com.fasterxml.jackson.core.type.TypeReference<List<Map<String, Object>>>() {});
|
||||
|
||||
for (Map<String, Object> advisor : advisors) {
|
||||
// 提取用户ID和姓名
|
||||
Object userIdObj = null;
|
||||
String advisorName = null;
|
||||
|
||||
// 尝试直接从advisor对象获取userId和name(兼容旧格式)
|
||||
if (advisor.containsKey("userId")) {
|
||||
userIdObj = advisor.get("userId");
|
||||
advisorName = (String) advisor.get("name");
|
||||
}
|
||||
// 尝试从teacher子对象获取userId和name(新格式)
|
||||
else if (advisor.containsKey("teacher")) {
|
||||
Object teacherObj = advisor.get("teacher");
|
||||
if (teacherObj instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> teacher = (Map<String, Object>) teacherObj;
|
||||
userIdObj = teacher.get("userId");
|
||||
advisorName = (String) teacher.get("nickName");
|
||||
if (StringUtils.isBlank(advisorName)) {
|
||||
advisorName = (String) teacher.get("userName");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (userIdObj != null && StringUtils.isNotBlank(advisorName)) {
|
||||
Long userId = Long.valueOf(userIdObj.toString());
|
||||
advisorIds.add(userId);
|
||||
advisorNames.add(advisorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有JSON数据,尝试从单一字段获取
|
||||
if (advisorIds.isEmpty() && StringUtils.isNotBlank(club.getAdvisorName())) {
|
||||
// 这种情况下无法获取用户ID,暂时跳过审批流程
|
||||
log.warn("社团 {} 的指导老师信息不完整,无法创建审批记录", club.getClubName());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析指导老师信息失败", e);
|
||||
throw new RuntimeException("解析指导老师信息失败");
|
||||
}
|
||||
|
||||
// 更新年审记录状态
|
||||
entity.setStatus("1");
|
||||
entity.setReviewTime(new Date());
|
||||
boolean updateResult = baseMapper.updateById(entity) > 0;
|
||||
|
||||
// 如果有指导老师信息,创建审批记录
|
||||
if (!advisorIds.isEmpty() && updateResult) {
|
||||
try {
|
||||
auditService.createAdvisorApprovalRecords(id, advisorIds, advisorNames);
|
||||
} catch (Exception e) {
|
||||
log.error("创建审批记录失败", e);
|
||||
throw new RuntimeException("创建审批记录失败");
|
||||
}
|
||||
}
|
||||
|
||||
return updateResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 撤回年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean withdrawReview(Long id) {
|
||||
StglClubAnnualReview entity = baseMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("年审记录不存在");
|
||||
}
|
||||
if (!"1".equals(entity.getStatus())) {
|
||||
throw new RuntimeException("只能撤回已提交状态的年审记录");
|
||||
}
|
||||
|
||||
entity.setStatus("0");
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核年审记录
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean auditReview(Long id, String auditResult, String auditOpinion, String auditType) {
|
||||
StglClubAnnualReview entity = baseMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("年审记录不存在");
|
||||
}
|
||||
|
||||
// 根据审核类型设置意见
|
||||
switch (auditType) {
|
||||
case "advisor":
|
||||
entity.setAdvisorOpinion(auditOpinion);
|
||||
break;
|
||||
case "college":
|
||||
entity.setCollegeOpinion(auditOpinion);
|
||||
break;
|
||||
case "youth_league":
|
||||
entity.setYouthLeagueOpinion(auditOpinion);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("无效的审核类型");
|
||||
}
|
||||
|
||||
// 设置审核结果状态
|
||||
entity.setStatus("3".equals(auditResult) ? "3" : "4");
|
||||
|
||||
return baseMapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的年审记录列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClubAnnualReviewVo> queryMyPageList(StglClubAnnualReviewBo bo, PageQuery pageQuery) {
|
||||
// 这里需要根据实际业务逻辑,通过用户ID查询其所属社团的年审记录
|
||||
// 暂时使用相同的查询逻辑,实际应该加上用户权限过滤
|
||||
return queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以创建年审记录
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkCanCreateReview(Long clubId, Integer reviewYear) {
|
||||
LambdaQueryWrapper<StglClubAnnualReview> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClubAnnualReview::getClubId, clubId);
|
||||
lqw.eq(StglClubAnnualReview::getReviewYear, reviewYear);
|
||||
return baseMapper.selectCount(lqw) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团ID和年审年度获取该年度的活动数据
|
||||
* @param clubId 社团ID
|
||||
* @param reviewYear 年审年度 (例如:2024)
|
||||
* @return 活动列表 - 只包含已通过、进行中、已结束的活动
|
||||
*/
|
||||
@Override
|
||||
public List<org.dromara.stgl.domain.vo.StglActivityVo> getClubActivitiesByReviewYear(Long clubId, Integer reviewYear) {
|
||||
// 计算年审年度的时间范围:年审年度的1月1日到12月31日
|
||||
LocalDate startDate = LocalDate.of(reviewYear, 1, 1);
|
||||
LocalDate endDate = LocalDate.of(reviewYear, 12, 31);
|
||||
|
||||
// 构建查询条件
|
||||
StglActivityBo bo = new StglActivityBo();
|
||||
bo.setRelatedClubId(clubId); // 设置社团ID
|
||||
bo.setRelatedType(1); // 关联类型为社团(1表示社团,2表示志愿团队)
|
||||
|
||||
// 设置时间范围查询条件(查询活动开始时间在该年度内的活动)
|
||||
bo.setStartTime(java.sql.Date.valueOf(startDate));
|
||||
bo.setEndTime(java.sql.Date.valueOf(endDate));
|
||||
|
||||
// 查询活动列表
|
||||
List<org.dromara.stgl.domain.vo.StglActivityVo> allActivities = stglActivityService.queryList(bo);
|
||||
|
||||
// 过滤活动状态:只保留已通过(3)、进行中(4)、已结束(5)的活动
|
||||
return allActivities.stream()
|
||||
.filter(activity -> {
|
||||
String status = activity.getActivityStatus();
|
||||
return "3".equals(status) || "4".equals(status) || "5".equals(status);
|
||||
})
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据年审记录ID获取对应的活动数据
|
||||
*/
|
||||
@Override
|
||||
public List<org.dromara.stgl.domain.vo.StglClubAnnualReviewActivityVo> getAnnualReviewActivities(Long annualReviewId) {
|
||||
LambdaQueryWrapper<StglClubAnnualReviewActivity> lqw = new LambdaQueryWrapper<>();
|
||||
lqw.eq(StglClubAnnualReviewActivity::getAnnualReviewId, annualReviewId);
|
||||
lqw.orderByAsc(StglClubAnnualReviewActivity::getActivityStartTime);
|
||||
|
||||
List<StglClubAnnualReviewActivity> activities = activityMapper.selectList(lqw);
|
||||
return BeanUtil.copyToList(activities, org.dromara.stgl.domain.vo.StglClubAnnualReviewActivityVo.class);
|
||||
}
|
||||
|
||||
}
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.vo.ClubActivityPermissionResult;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.service.IStglClubPermissionService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 社团通知定时任务
|
||||
* 仅用于发送年审提醒通知,不管理权限状态
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@ConditionalOnProperty(name = "stgl.club.notification.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class StglClubNotificationScheduler {
|
||||
|
||||
private final StglClubMapper clubMapper;
|
||||
private final IStglClubPermissionService clubPermissionService;
|
||||
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 每天早上8点发送年审相关通知
|
||||
* 通过实时权限检查确定通知类型,不存储状态
|
||||
*/
|
||||
@Scheduled(cron = "0 0 8 * * ?")
|
||||
public void sendDailyAnnualReviewReminders() {
|
||||
log.info("开始执行社团年审通知任务");
|
||||
|
||||
try {
|
||||
Date today = new Date();
|
||||
|
||||
// 获取所有正常状态的社团
|
||||
List<StglClub> allClubs = getAllActiveClubs();
|
||||
log.info("获取到活跃社团数量: {}", allClubs.size());
|
||||
|
||||
int todayLimitedCount = 0;
|
||||
int urgentReminderCount = 0;
|
||||
int permanentlyLimitedCount = 0;
|
||||
|
||||
for (StglClub club : allClubs) {
|
||||
try {
|
||||
// 实时检查权限状态
|
||||
ClubActivityPermissionResult permission =
|
||||
clubPermissionService.checkClubActivityPermission(club.getId());
|
||||
|
||||
switch (permission.getStatus()) {
|
||||
case "TEMPORARILY_LIMITED":
|
||||
handleTemporarilyLimitedClub(club, permission);
|
||||
if (isFirstDayOfRestriction(club, today)) {
|
||||
todayLimitedCount++;
|
||||
}
|
||||
if (isUrgentReminder(permission)) {
|
||||
urgentReminderCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
case "PERMANENTLY_LIMITED":
|
||||
if (isFirstDayOfPermanentRestriction(club, today)) {
|
||||
handlePermanentlyLimitedClub(club);
|
||||
permanentlyLimitedCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
case "NORMAL":
|
||||
// 正常状态无需通知
|
||||
break;
|
||||
|
||||
default:
|
||||
log.warn("未知的权限状态: {}, 社团ID: {}", permission.getStatus(), club.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理社团通知失败,社团ID: {}", club.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("社团年审通知任务完成 - 今日开始限制: {}, 紧急提醒: {}, 永久限制: {}",
|
||||
todayLimitedCount, urgentReminderCount, permanentlyLimitedCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("执行社团年审通知任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理临时限制状态的社团
|
||||
*/
|
||||
private void handleTemporarilyLimitedClub(StglClub club, ClubActivityPermissionResult permission) {
|
||||
if (permission.getRemainingDays() != null) {
|
||||
if (permission.getRemainingDays() <= 3) {
|
||||
// 剩余3天内,发送紧急提醒
|
||||
sendUrgentAnnualReviewReminder(club, permission);
|
||||
} else if (permission.getRemainingDays() >= 12) {
|
||||
// 刚开始限制(剩余12天以上),发送开始通知
|
||||
sendAnnualReviewStartNotification(club, permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理永久限制状态的社团
|
||||
*/
|
||||
private void handlePermanentlyLimitedClub(StglClub club) {
|
||||
sendPermanentRestrictionNotification(club);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送年审开始通知
|
||||
*/
|
||||
private void sendAnnualReviewStartNotification(StglClub club, ClubActivityPermissionResult permission) {
|
||||
String message = String.format(
|
||||
"【年审提醒】尊敬的%s社团,您的社团从今天开始进入年审期,活动发起功能已限制。" +
|
||||
"请在%d天内完成年审提交,截止时间:%s。" +
|
||||
"提醒:超过期限将永久限制活动发起功能。",
|
||||
club.getClubName(),
|
||||
permission.getRemainingDays(),
|
||||
dateFormat.format(permission.getDeadlineTime())
|
||||
);
|
||||
|
||||
log.info("发送年审开始通知 - 社团: {}, 剩余天数: {}", club.getClubName(), permission.getRemainingDays());
|
||||
sendNotificationToClub(club, "年审开始通知", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送紧急年审提醒
|
||||
*/
|
||||
private void sendUrgentAnnualReviewReminder(StglClub club, ClubActivityPermissionResult permission) {
|
||||
String message = String.format(
|
||||
"【紧急提醒】%s社团,您的年审即将到期!" +
|
||||
"仅剩%d天%d小时,截止时间:%s。" +
|
||||
"请立即提交年审,否则将永久限制活动发起功能!",
|
||||
club.getClubName(),
|
||||
permission.getRemainingDays(),
|
||||
permission.getRemainingHours() % 24,
|
||||
dateFormat.format(permission.getDeadlineTime())
|
||||
);
|
||||
|
||||
log.warn("发送紧急年审提醒 - 社团: {}, 剩余: {}天{}小时",
|
||||
club.getClubName(), permission.getRemainingDays(), permission.getRemainingHours() % 24);
|
||||
sendNotificationToClub(club, "紧急年审提醒", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送永久限制通知
|
||||
*/
|
||||
private void sendPermanentRestrictionNotification(StglClub club) {
|
||||
String message = String.format(
|
||||
"【权限限制】%s社团,很遗憾通知您,由于超过年审提交期限," +
|
||||
"您的社团活动发起功能已被永久限制。即使现在补交年审也无法恢复权限。" +
|
||||
"如有疑问,请联系管理员。",
|
||||
club.getClubName()
|
||||
);
|
||||
|
||||
log.warn("发送永久限制通知 - 社团: {}", club.getClubName());
|
||||
sendNotificationToClub(club, "活动权限永久限制", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送通知到社团(实际发送逻辑)
|
||||
*/
|
||||
private void sendNotificationToClub(StglClub club, String title, String message) {
|
||||
try {
|
||||
// TODO: 集成实际的通知系统
|
||||
// 可以是站内信、邮件、短信等
|
||||
log.info("通知发送 - 社团: {}, 标题: {}, 内容: {}", club.getClubName(), title, message);
|
||||
|
||||
// 示例:记录通知日志
|
||||
recordNotificationLog(club.getId(), title, message);
|
||||
} catch (Exception e) {
|
||||
log.error("发送通知失败 - 社团: {}, 标题: {}", club.getClubName(), title, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录通知日志
|
||||
*/
|
||||
private void recordNotificationLog(Long clubId, String title, String message) {
|
||||
// TODO: 将通知记录保存到数据库,用于审计和跟踪
|
||||
log.debug("记录通知日志 - 社团ID: {}, 标题: {}", clubId, title);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有活跃的社团
|
||||
*/
|
||||
private List<StglClub> getAllActiveClubs() {
|
||||
LambdaQueryWrapper<StglClub> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(StglClub::getStatus, 1) // 1-正常状态
|
||||
.isNotNull(StglClub::getEstablishDate); // 必须有成立日期
|
||||
return clubMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是限制的第一天
|
||||
*/
|
||||
private boolean isFirstDayOfRestriction(StglClub club, Date today) {
|
||||
try {
|
||||
ClubActivityPermissionResult permission =
|
||||
clubPermissionService.checkClubActivityPermission(club.getId());
|
||||
|
||||
if (!"TEMPORARILY_LIMITED".equals(permission.getStatus())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果剩余天数接近15天,说明是刚开始限制
|
||||
return permission.getRemainingDays() != null && permission.getRemainingDays() >= 14;
|
||||
} catch (Exception e) {
|
||||
log.error("判断限制第一天失败,社团ID: {}", club.getId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要紧急提醒
|
||||
*/
|
||||
private boolean isUrgentReminder(ClubActivityPermissionResult permission) {
|
||||
return permission.getRemainingDays() != null && permission.getRemainingDays() <= 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是永久限制的第一天
|
||||
*/
|
||||
private boolean isFirstDayOfPermanentRestriction(StglClub club, Date today) {
|
||||
try {
|
||||
// 检查昨天的状态是否还是临时限制
|
||||
Date yesterday = new Date(today.getTime() - TimeUnit.DAYS.toMillis(1));
|
||||
|
||||
// 通过计算年审截止时间来判断
|
||||
// 如果今天刚好是截止后的第一天,就发送通知
|
||||
Date establishDate = club.getEstablishDate();
|
||||
if (establishDate == null) return false;
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(establishDate);
|
||||
cal.set(Calendar.YEAR, Calendar.getInstance().get(Calendar.YEAR));
|
||||
cal.add(Calendar.DAY_OF_MONTH, 15);
|
||||
|
||||
Date deadlineDate = cal.getTime();
|
||||
|
||||
// 如果今天是截止日期后的1-2天内,认为是刚刚永久限制
|
||||
long daysSinceDeadline = TimeUnit.MILLISECONDS.toDays(
|
||||
today.getTime() - deadlineDate.getTime());
|
||||
|
||||
return daysSinceDeadline >= 0 && daysSinceDeadline <= 1;
|
||||
} catch (Exception e) {
|
||||
log.error("判断永久限制第一天失败,社团ID: {}", club.getId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.StglClubAnnualReview;
|
||||
import org.dromara.stgl.domain.vo.ClubActivityPermissionResult;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglClubAnnualReviewMapper;
|
||||
import org.dromara.stgl.service.IStglClubPermissionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 社团权限管理Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClubPermissionServiceImpl implements IStglClubPermissionService {
|
||||
|
||||
private final StglClubMapper clubMapper;
|
||||
private final StglClubAnnualReviewMapper annualReviewMapper;
|
||||
|
||||
/**
|
||||
* 年审窗口期天数(15天)
|
||||
*/
|
||||
private static final int ANNUAL_REVIEW_WINDOW_DAYS = 15;
|
||||
|
||||
/**
|
||||
* 检查社团活动权限(实时计算,精确到秒级)
|
||||
*/
|
||||
@Override
|
||||
public ClubActivityPermissionResult checkClubActivityPermission(Long clubId) {
|
||||
log.debug("开始检查社团权限,clubId: {}", clubId);
|
||||
|
||||
// 1. 获取社团基础信息
|
||||
StglClub clubInfo = clubMapper.selectById(clubId);
|
||||
if (clubInfo == null) {
|
||||
throw new ServiceException("社团不存在,ID: " + clubId);
|
||||
}
|
||||
|
||||
Date establishDate = clubInfo.getEstablishDate();
|
||||
if (establishDate == null) {
|
||||
throw new ServiceException("社团成立日期不能为空");
|
||||
}
|
||||
|
||||
Date currentTime = new Date(); // 当前精确时间(到毫秒)
|
||||
|
||||
// 2. 计算关键时间点(精确到秒)
|
||||
Date annualReviewStartTime = calculateAnnualReviewStartTime(establishDate, currentTime);
|
||||
Date annualReviewDeadlineTime = addDays(annualReviewStartTime, ANNUAL_REVIEW_WINDOW_DAYS);
|
||||
|
||||
log.debug("社团ID: {}, 成立时间: {}, 年审开始时间: {}, 年审截止时间: {}, 当前时间: {}",
|
||||
clubId, establishDate, annualReviewStartTime, annualReviewDeadlineTime, currentTime);
|
||||
|
||||
// 3. 时间段判断(精确比较)
|
||||
if (currentTime.before(annualReviewStartTime)) {
|
||||
// 未到年审时间,正常状态
|
||||
log.debug("社团ID: {} 未到年审时间,状态正常", clubId);
|
||||
return ClubActivityPermissionResult.allowed();
|
||||
}
|
||||
|
||||
if (currentTime.after(annualReviewDeadlineTime)) {
|
||||
// 超过15天期限,永久限制
|
||||
log.debug("社团ID: {} 已超过年审期限,永久限制", clubId);
|
||||
return ClubActivityPermissionResult.permanentlyDenied(
|
||||
"已超过年审提交期限(15天),无法发起活动");
|
||||
}
|
||||
|
||||
// 4. 在15天窗口期内,检查年审提交情况(精确查询)
|
||||
boolean hasValidSubmission = checkAnnualReviewSubmissionWithPrecision(
|
||||
clubId, annualReviewStartTime, currentTime);
|
||||
|
||||
if (hasValidSubmission) {
|
||||
log.debug("社团ID: {} 已在窗口期内提交年审,权限恢复", clubId);
|
||||
return ClubActivityPermissionResult.allowed();
|
||||
} else {
|
||||
// 计算剩余时间
|
||||
long remainingMillis = annualReviewDeadlineTime.getTime() - currentTime.getTime();
|
||||
long remainingHours = TimeUnit.MILLISECONDS.toHours(remainingMillis);
|
||||
long remainingDays = TimeUnit.MILLISECONDS.toDays(remainingMillis);
|
||||
|
||||
String message = String.format("需要先提交年审,剩余时间:%d天%d小时",
|
||||
remainingDays, remainingHours % 24);
|
||||
|
||||
log.debug("社团ID: {} 在年审窗口期内但未提交,剩余{}天{}小时",
|
||||
clubId, remainingDays, remainingHours % 24);
|
||||
|
||||
return ClubActivityPermissionResult.temporarilyDenied(
|
||||
message, annualReviewDeadlineTime, annualReviewStartTime,
|
||||
remainingHours, remainingDays);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量检查社团活动权限
|
||||
*/
|
||||
@Override
|
||||
public Map<Long, ClubActivityPermissionResult> batchCheckClubActivityPermission(List<Long> clubIds) {
|
||||
if (clubIds == null || clubIds.isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
return clubIds.stream()
|
||||
.collect(Collectors.toMap(
|
||||
clubId -> clubId,
|
||||
this::checkClubActivityPermission,
|
||||
(existing, replacement) -> existing
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团是否在年审窗口期内
|
||||
*/
|
||||
@Override
|
||||
public boolean isInAnnualReviewWindow(Long clubId) {
|
||||
ClubActivityPermissionResult result = checkClubActivityPermission(clubId);
|
||||
return "TEMPORARILY_LIMITED".equals(result.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团距离下次年审的天数
|
||||
*/
|
||||
@Override
|
||||
public long getDaysUntilNextAnnualReview(Long clubId) {
|
||||
StglClub clubInfo = clubMapper.selectById(clubId);
|
||||
if (clubInfo == null || clubInfo.getEstablishDate() == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Date currentTime = new Date();
|
||||
Date nextAnnualReviewTime = calculateAnnualReviewStartTime(clubInfo.getEstablishDate(), currentTime);
|
||||
|
||||
// 如果已经过了今年的年审时间,计算明年的
|
||||
if (currentTime.after(nextAnnualReviewTime)) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(nextAnnualReviewTime);
|
||||
cal.add(Calendar.YEAR, 1);
|
||||
nextAnnualReviewTime = cal.getTime();
|
||||
}
|
||||
|
||||
long diffMillis = nextAnnualReviewTime.getTime() - currentTime.getTime();
|
||||
return TimeUnit.MILLISECONDS.toDays(diffMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团是否已在当前年审期内提交年审
|
||||
*/
|
||||
@Override
|
||||
public boolean hasSubmittedCurrentYearAnnualReview(Long clubId) {
|
||||
StglClub clubInfo = clubMapper.selectById(clubId);
|
||||
if (clubInfo == null || clubInfo.getEstablishDate() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date currentTime = new Date();
|
||||
Date annualReviewStartTime = calculateAnnualReviewStartTime(clubInfo.getEstablishDate(), currentTime);
|
||||
Date annualReviewDeadlineTime = addDays(annualReviewStartTime, ANNUAL_REVIEW_WINDOW_DAYS);
|
||||
|
||||
// 如果当前不在年审窗口期,返回false
|
||||
if (currentTime.before(annualReviewStartTime) || currentTime.after(annualReviewDeadlineTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkAnnualReviewSubmissionWithPrecision(clubId, annualReviewStartTime, currentTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算年审开始时间(精确到具体时刻)
|
||||
*
|
||||
* @param establishDate 社团成立时间
|
||||
* @param currentDate 当前时间
|
||||
* @return 今年的年审开始时间
|
||||
*/
|
||||
private Date calculateAnnualReviewStartTime(Date establishDate, Date currentDate) {
|
||||
Calendar establishCal = Calendar.getInstance();
|
||||
establishCal.setTime(establishDate);
|
||||
|
||||
Calendar currentCal = Calendar.getInstance();
|
||||
currentCal.setTime(currentDate);
|
||||
|
||||
// 构造今年同月同日的时间,保持原有的时分秒毫秒
|
||||
Calendar annualReviewCal = Calendar.getInstance();
|
||||
annualReviewCal.set(Calendar.YEAR, currentCal.get(Calendar.YEAR));
|
||||
annualReviewCal.set(Calendar.MONTH, establishCal.get(Calendar.MONTH));
|
||||
annualReviewCal.set(Calendar.DAY_OF_MONTH, establishCal.get(Calendar.DAY_OF_MONTH));
|
||||
annualReviewCal.set(Calendar.HOUR_OF_DAY, establishCal.get(Calendar.HOUR_OF_DAY));
|
||||
annualReviewCal.set(Calendar.MINUTE, establishCal.get(Calendar.MINUTE));
|
||||
annualReviewCal.set(Calendar.SECOND, establishCal.get(Calendar.SECOND));
|
||||
annualReviewCal.set(Calendar.MILLISECOND, establishCal.get(Calendar.MILLISECOND));
|
||||
|
||||
return annualReviewCal.getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* 精确检查年审提交情况(关键改进 - 支持秒级精度)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param windowStartTime 窗口开始时间
|
||||
* @param queryTime 查询时间点
|
||||
* @return 是否已提交年审
|
||||
*/
|
||||
private boolean checkAnnualReviewSubmissionWithPrecision(Long clubId, Date windowStartTime, Date queryTime) {
|
||||
LambdaQueryWrapper<StglClubAnnualReview> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(StglClubAnnualReview::getClubId, clubId)
|
||||
.ge(StglClubAnnualReview::getCreateTime, windowStartTime) // 大于等于窗口开始时间
|
||||
.le(StglClubAnnualReview::getCreateTime, queryTime) // 小于等于当前查询时间
|
||||
.ne(StglClubAnnualReview::getStatus, "0"); // 非草稿状态
|
||||
|
||||
long count = annualReviewMapper.selectCount(wrapper);
|
||||
|
||||
log.debug("年审提交检查 - 社团ID: {}, 窗口开始: {}, 查询时间: {}, 提交记录数: {}",
|
||||
clubId, windowStartTime, queryTime, count);
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期加天数工具方法
|
||||
*
|
||||
* @param date 原始日期
|
||||
* @param days 要添加的天数
|
||||
* @return 新日期
|
||||
*/
|
||||
private Date addDays(Date date, int days) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
cal.add(Calendar.DAY_OF_MONTH, days);
|
||||
return cal.getTime();
|
||||
}
|
||||
}
|
||||
+107
@@ -17,6 +17,7 @@ import org.dromara.stgl.domain.StglMember;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglMemberMapper;
|
||||
import org.dromara.stgl.service.IStglClubService;
|
||||
import org.dromara.stgl.service.IStglClubAdvisorHistoryService;
|
||||
import org.dromara.stgl.utils.AdvisorRoleAssigner;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
@@ -71,6 +72,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
private final AdvisorRoleAssigner advisorRoleAssigner;
|
||||
// 添加用户角色Mapper
|
||||
private final SysUserRoleMapper sysUserRoleMapper;
|
||||
// 添加指导老师历史记录Service
|
||||
private final IStglClubAdvisorHistoryService advisorHistoryService;
|
||||
|
||||
/**
|
||||
* 查询社团信息
|
||||
@@ -342,6 +345,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
assignAdvisorRoles(add);
|
||||
// 为社长分配角色
|
||||
assignPresidentRole(add);
|
||||
// 创建指导老师历史记录
|
||||
createAdvisorHistoryRecords(add);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
@@ -372,6 +377,8 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
syncVicePresidentsInMembers(update);
|
||||
// 处理指导老师角色分配
|
||||
handleAdvisorRoleAssignment(oldClub, update);
|
||||
// 更新指导老师历史记录
|
||||
updateAdvisorHistoryRecords(oldClub, update);
|
||||
}
|
||||
|
||||
return updateResult;
|
||||
@@ -1347,4 +1354,104 @@ public class StglClubServiceImpl implements IStglClubService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建指导老师历史记录(新增社团时)
|
||||
*
|
||||
* @param club 社团信息
|
||||
*/
|
||||
private void createAdvisorHistoryRecords(StglClub club) {
|
||||
try {
|
||||
List<IStglClubAdvisorHistoryService.AdvisorInfo> advisors = parseAdvisorsFromClub(club);
|
||||
if (!advisors.isEmpty()) {
|
||||
// 新建社团时,指导老师的上任时间应该是社团成立日期,而不是当前时间
|
||||
Date startTime = club.getEstablishDate() != null ? club.getEstablishDate() : new Date();
|
||||
advisorHistoryService.updateClubAdvisors(club.getId(), advisors, startTime);
|
||||
log.info("为社团 {} 创建指导老师历史记录成功,指导老师数量: {},上任时间: {}",
|
||||
club.getClubName(), advisors.size(), startTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("为社团 {} 创建指导老师历史记录失败", club.getClubName(), e);
|
||||
// 不抛出异常,避免影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新指导老师历史记录(更新社团时)
|
||||
*
|
||||
* @param oldClub 旧的社团信息
|
||||
* @param newClub 新的社团信息
|
||||
*/
|
||||
private void updateAdvisorHistoryRecords(StglClub oldClub, StglClub newClub) {
|
||||
try {
|
||||
List<IStglClubAdvisorHistoryService.AdvisorInfo> advisors = parseAdvisorsFromClub(newClub);
|
||||
advisorHistoryService.updateClubAdvisors(newClub.getId(), advisors);
|
||||
log.info("为社团 {} 更新指导老师历史记录成功,指导老师数量: {}", newClub.getClubName(), advisors.size());
|
||||
} catch (Exception e) {
|
||||
log.error("为社团 {} 更新指导老师历史记录失败", newClub.getClubName(), e);
|
||||
// 不抛出异常,避免影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从社团信息中解析指导老师列表
|
||||
*
|
||||
* @param club 社团信息
|
||||
* @return 指导老师列表
|
||||
*/
|
||||
private List<IStglClubAdvisorHistoryService.AdvisorInfo> parseAdvisorsFromClub(StglClub club) {
|
||||
List<IStglClubAdvisorHistoryService.AdvisorInfo> advisors = new ArrayList<>();
|
||||
|
||||
// 优先从JSON字段解析
|
||||
if (StringUtils.isNotBlank(club.getAdvisorsJson())) {
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
List<Map<String, Object>> advisorMaps = mapper.readValue(
|
||||
club.getAdvisorsJson(),
|
||||
new TypeReference<List<Map<String, Object>>>() {}
|
||||
);
|
||||
|
||||
for (Map<String, Object> advisorMap : advisorMaps) {
|
||||
String name = (String) advisorMap.get("name");
|
||||
String dept = (String) advisorMap.get("dept");
|
||||
String phone = (String) advisorMap.get("phone");
|
||||
String email = (String) advisorMap.get("email");
|
||||
Long userId = null;
|
||||
|
||||
// 尝试获取用户ID
|
||||
Object userIdObj = advisorMap.get("userId");
|
||||
if (userIdObj != null) {
|
||||
if (userIdObj instanceof Number) {
|
||||
userId = ((Number) userIdObj).longValue();
|
||||
} else if (userIdObj instanceof String) {
|
||||
try {
|
||||
userId = Long.parseLong((String) userIdObj);
|
||||
} catch (NumberFormatException e) {
|
||||
// 忽略解析错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
advisors.add(new IStglClubAdvisorHistoryService.AdvisorInfo(name, dept, phone, email, userId));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析指导老师JSON数据失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果JSON解析失败或为空,回退到单一字段
|
||||
if (advisors.isEmpty() && StringUtils.isNotBlank(club.getAdvisorName())) {
|
||||
advisors.add(new IStglClubAdvisorHistoryService.AdvisorInfo(
|
||||
club.getAdvisorName(),
|
||||
club.getAdvisorDept(),
|
||||
club.getAdvisorPhone(),
|
||||
club.getAdvisorEmail(),
|
||||
null
|
||||
));
|
||||
}
|
||||
|
||||
return advisors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -159,6 +159,8 @@
|
||||
a.end_time,
|
||||
a.location,
|
||||
a.organizer_name,
|
||||
a.related_dept_name,
|
||||
a.related_dept_names,
|
||||
CAST(a.related_type AS CHAR) as related_type,
|
||||
CASE
|
||||
WHEN a.related_type = 1 THEN c.club_name
|
||||
|
||||
+66
-42
@@ -14,6 +14,10 @@
|
||||
<result property="location" column="location"/>
|
||||
<result property="description" column="description"/>
|
||||
<result property="posterUrl" column="poster_url"/>
|
||||
<result property="relatedDeptId" column="related_dept_id"/>
|
||||
<result property="relatedDeptName" column="related_dept_name"/>
|
||||
<result property="relatedDeptIds" column="related_dept_ids"/>
|
||||
<result property="relatedDeptNames" column="related_dept_names"/>
|
||||
<result property="relatedClubId" column="related_club_id"/>
|
||||
<result property="relatedClubName" column="related_club_name"/>
|
||||
<result property="relatedType" column="related_type"/>
|
||||
@@ -55,22 +59,25 @@
|
||||
SELECT
|
||||
sa.id, sa.activity_name, sa.activity_type, sa.activity_theme,
|
||||
sa.start_time, sa.end_time, sa.location, sa.description,
|
||||
sa.poster_url, sa.related_club_id, sa.related_type, sa.organizer_name, sa.organizer_type,
|
||||
sa.poster_url, sa.related_dept_id, sa.related_dept_name, sa.related_dept_ids, sa.related_dept_names,
|
||||
sa.related_club_id, sa.related_type, sa.organizer_name, sa.organizer_type,
|
||||
sa.organizer_contact, sa.organizer_phone, sa.co_organizers, sa.instructors,
|
||||
sa.registration_type, sa.registration_start, sa.registration_end,
|
||||
-- 动态计算报名状态:优先根据活动状态,再根据报名时间范围
|
||||
-- 动态计算报名状态:只有审批通过的活动才根据时间计算报名状态
|
||||
CASE
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
-- 草稿、待审批、已驳回状态不映射报名状态,保持为空
|
||||
WHEN sa.activity_status IN ('0', '2', '7') THEN NULL
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
-- 已取消的活动设置为已关闭
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
|
||||
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
|
||||
WHEN sa.activity_status IN ('3', '4', '5') THEN
|
||||
CASE
|
||||
-- 已结束的活动强制设置报名结束
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
|
||||
-- 已通过和进行中的活动根据报名时间判断
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
@@ -119,9 +126,9 @@
|
||||
END
|
||||
ELSE NULL
|
||||
END AS related_club_name,
|
||||
-- 统计报名人数(子查询)
|
||||
-- 统计报名人数(子查询)- 只统计审核通过的报名记录
|
||||
(SELECT COUNT(*) FROM stgl_activity_registration sar
|
||||
WHERE sar.activity_id = sa.id AND sar.deleted = 0) AS registration_count,
|
||||
WHERE sar.activity_id = sa.id AND sar.deleted = 0 AND sar.approval_status = 1) AS registration_count,
|
||||
-- 统计平均评分(子查询)
|
||||
(SELECT ROUND(AVG(rating_score), 1) FROM stgl_activity_rating sar2
|
||||
WHERE sar2.activity_id = sa.id AND sar2.deleted = 0) AS average_rating
|
||||
@@ -156,17 +163,19 @@
|
||||
<if test="registrationStatus != null">
|
||||
AND (
|
||||
CASE
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
-- 草稿、待审批、已驳回状态不映射报名状态,保持为空
|
||||
WHEN sa.activity_status IN ('0', '2', '7') THEN NULL
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
-- 已取消的活动设置为已关闭
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
|
||||
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
|
||||
WHEN sa.activity_status IN ('3', '4', '5') THEN
|
||||
CASE
|
||||
-- 已结束的活动强制设置报名结束
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
|
||||
-- 已通过和进行中的活动根据报名时间判断
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
@@ -191,6 +200,9 @@
|
||||
<if test="registrationEnd != null">
|
||||
AND sa.registration_end <= #{registrationEnd}
|
||||
</if>
|
||||
<if test="relatedDeptId != null">
|
||||
AND sa.related_dept_id = #{relatedDeptId}
|
||||
</if>
|
||||
<if test="relatedClubId != null">
|
||||
AND sa.related_club_id = #{relatedClubId}
|
||||
</if>
|
||||
@@ -258,17 +270,19 @@
|
||||
<if test="activity.registrationStatus != null and activity.registrationStatus != ''">
|
||||
AND (
|
||||
CASE
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
-- 草稿、待审批、已驳回状态不映射报名状态,保持为空
|
||||
WHEN sa.activity_status IN ('0', '2', '7') THEN NULL
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
-- 已取消的活动设置为已关闭
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
|
||||
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
|
||||
WHEN sa.activity_status IN ('3', '4', '5') THEN
|
||||
CASE
|
||||
-- 已结束的活动强制设置报名结束
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
|
||||
-- 已通过和进行中的活动根据报名时间判断
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
@@ -285,17 +299,19 @@
|
||||
<if test="activity.params != null and activity.params.registrationStatusList != null and activity.params.registrationStatusList.size() > 0">
|
||||
AND (
|
||||
CASE
|
||||
-- 首先根据活动状态强制设置(优先级最高)
|
||||
WHEN sa.activity_status = '0' THEN '0' -- 草稿 → 未开始(固定)
|
||||
WHEN sa.activity_status = '1' THEN '0' -- 未开始 → 未开始(固定)
|
||||
WHEN sa.activity_status = '2' THEN '0' -- 待审批 → 未开始(固定)
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
WHEN sa.activity_status = '7' THEN '0' -- 已驳回 → 未开始(固定)
|
||||
-- 草稿、待审批、已驳回状态不映射报名状态,保持为空
|
||||
WHEN sa.activity_status IN ('0', '2', '7') THEN NULL
|
||||
|
||||
-- 然后根据活动状态和报名时间判断
|
||||
WHEN sa.activity_status = '3' OR sa.activity_status = '4' THEN
|
||||
-- 已取消的活动设置为已关闭
|
||||
WHEN sa.activity_status = '6' THEN '3' -- 已取消 → 已关闭(固定)
|
||||
|
||||
-- 只有审批通过的活动(已通过、进行中、已结束)才根据时间计算报名状态
|
||||
WHEN sa.activity_status IN ('3', '4', '5') THEN
|
||||
CASE
|
||||
-- 已结束的活动强制设置报名结束
|
||||
WHEN sa.activity_status = '5' THEN '2' -- 已结束 → 报名结束(固定)
|
||||
|
||||
-- 已通过和进行中的活动根据报名时间判断
|
||||
WHEN sa.registration_start IS NULL OR sa.registration_end IS NULL THEN sa.registration_status
|
||||
<![CDATA[WHEN NOW() < sa.registration_start THEN '0']]>
|
||||
<![CDATA[WHEN NOW() >= sa.registration_start AND NOW() <= sa.registration_end THEN '1']]>
|
||||
@@ -323,6 +339,12 @@
|
||||
<if test="activity.tenantId != null and activity.tenantId != ''">
|
||||
AND sa.tenant_id = #{activity.tenantId}
|
||||
</if>
|
||||
<if test="activity.relatedDeptId != null">
|
||||
AND sa.related_dept_id = #{activity.relatedDeptId}
|
||||
</if>
|
||||
<if test="activity.relatedClubId != null">
|
||||
AND sa.related_club_id = #{activity.relatedClubId}
|
||||
</if>
|
||||
<!-- 活动面向群体过滤:当activity_range=1时,只有组织成员才能看到 -->
|
||||
<if test="activity.params != null and activity.params.userOrganizations != null">
|
||||
AND (
|
||||
@@ -383,7 +405,8 @@
|
||||
INSERT INTO stgl_activity (
|
||||
id, tenant_id, create_dept, create_by, create_time, update_by, update_time,
|
||||
activity_name, activity_type, activity_theme, start_time, end_time, location,
|
||||
description, poster_url, related_club_id, organizer_name, organizer_type,
|
||||
description, poster_url, related_dept_id, related_dept_name, related_dept_ids, related_dept_names,
|
||||
related_club_id, organizer_name, organizer_type,
|
||||
organizer_contact, organizer_phone, co_organizers, instructors,
|
||||
registration_type, registration_start, registration_end, registration_status,
|
||||
max_participants, max_teams, team_size_min, team_size_max, need_approval,
|
||||
@@ -394,7 +417,8 @@
|
||||
#{newActivity.createBy}, #{newActivity.createTime}, #{newActivity.updateBy}, #{newActivity.updateTime},
|
||||
#{newActivity.activityName}, activity_type, activity_theme,
|
||||
#{newActivity.startTime}, #{newActivity.endTime}, location,
|
||||
description, poster_url, related_club_id, organizer_name, organizer_type,
|
||||
description, poster_url, related_dept_id, related_dept_name, related_dept_ids, related_dept_names,
|
||||
related_club_id, organizer_name, organizer_type,
|
||||
organizer_contact, organizer_phone, co_organizers, instructors,
|
||||
registration_type, #{newActivity.registrationStart}, #{newActivity.registrationEnd},
|
||||
#{newActivity.registrationStatus}, max_participants, max_teams, team_size_min, team_size_max, need_approval,
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
<?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.StglAnnualReviewAuditMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.StglAnnualReviewAudit" id="StglAnnualReviewAuditResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="createDept" column="create_dept" />
|
||||
<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="deleted" column="deleted" />
|
||||
<result property="annualReviewId" column="annual_review_id" />
|
||||
<result property="nodeCode" column="node_code" />
|
||||
<result property="nodeName" column="node_name" />
|
||||
<result property="nodeOrder" column="node_order" />
|
||||
<result property="nodeStatus" column="audit_status" />
|
||||
<result property="approverId" column="approver_id" />
|
||||
<result property="approverName" column="approver_name" />
|
||||
<result property="approveResult" column="approve_result" />
|
||||
<result property="approveOpinion" column="audit_opinion" />
|
||||
<result property="approveTime" column="audit_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglAnnualReviewAuditVo">
|
||||
select id, tenant_id, create_dept, create_by, create_time, update_by, update_time, deleted,
|
||||
annual_review_id, node_code, node_name, node_order, audit_status,
|
||||
approver_id, approver_name, approve_result, audit_opinion, audit_time
|
||||
from stgl_annual_review_audit
|
||||
</sql>
|
||||
|
||||
<!-- 根据年审记录ID查询审批记录 -->
|
||||
<select id="selectByAnnualReviewId" parameterType="Long" resultMap="StglAnnualReviewAuditResult">
|
||||
<include refid="selectStglAnnualReviewAuditVo"/>
|
||||
where annual_review_id = #{annualReviewId} and deleted = 0
|
||||
order by node_order
|
||||
</select>
|
||||
|
||||
<!-- 根据年审记录ID和节点代码查询审批记录 -->
|
||||
<select id="selectByAnnualReviewIdAndNodeCode" resultMap="StglAnnualReviewAuditResult">
|
||||
<include refid="selectStglAnnualReviewAuditVo"/>
|
||||
where annual_review_id = #{annualReviewId} and node_code = #{nodeCode} and deleted = 0
|
||||
order by node_order
|
||||
</select>
|
||||
|
||||
<!-- 根据审批人ID查询待审批记录 -->
|
||||
<select id="selectPendingByApproverId" parameterType="Long" resultMap="StglAnnualReviewAuditResult">
|
||||
<include refid="selectStglAnnualReviewAuditVo"/>
|
||||
where approver_id = #{approverId} and audit_status = 'pending' and deleted = 0
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
<?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.StglAuditorMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.vo.StglAuditorVo" id="StglAuditorResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="userName" column="user_name" />
|
||||
<result property="nickName" column="nick_name" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="deptName" column="dept_name" />
|
||||
<result property="phoneNumber" column="phone_number" />
|
||||
<result property="email" column="email" />
|
||||
<result property="status" column="status" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="configBy" column="config_by" />
|
||||
<result property="configByName" column="config_by_name" />
|
||||
<result property="createBy" column="create_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
<result property="updateBy" column="update_by" />
|
||||
<result property="updateTime" column="update_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglAuditorVo">
|
||||
SELECT
|
||||
sa.id,
|
||||
sa.user_id,
|
||||
sa.user_name,
|
||||
sa.nick_name,
|
||||
sa.dept_id,
|
||||
sa.dept_name,
|
||||
sa.phone_number,
|
||||
sa.email,
|
||||
sa.status,
|
||||
sa.remark,
|
||||
sa.config_by,
|
||||
sa.config_by_name,
|
||||
sa.create_by,
|
||||
sa.create_time,
|
||||
sa.update_by,
|
||||
sa.update_time
|
||||
FROM stgl_auditor sa
|
||||
</sql>
|
||||
|
||||
<select id="selectStglAuditorVoList" parameterType="org.dromara.stgl.domain.StglAuditor" resultMap="StglAuditorResult">
|
||||
<include refid="selectStglAuditorVo"/>
|
||||
<where>
|
||||
sa.deleted = 0
|
||||
<if test="userId != null">
|
||||
AND sa.user_id = #{userId}
|
||||
</if>
|
||||
<if test="userName != null and userName != ''">
|
||||
AND sa.user_name LIKE CONCAT('%', #{userName}, '%')
|
||||
</if>
|
||||
<if test="nickName != null and nickName != ''">
|
||||
AND sa.nick_name LIKE CONCAT('%', #{nickName}, '%')
|
||||
</if>
|
||||
<if test="deptId != null">
|
||||
AND sa.dept_id = #{deptId}
|
||||
</if>
|
||||
<if test="status != null and status != ''">
|
||||
AND sa.status = #{status}
|
||||
</if>
|
||||
<if test="configBy != null">
|
||||
AND sa.config_by = #{configBy}
|
||||
</if>
|
||||
<if test="params.beginCreateTime != null and params.beginCreateTime != ''">
|
||||
AND sa.create_time >= #{params.beginCreateTime}
|
||||
</if>
|
||||
<if test="params.endCreateTime != null and params.endCreateTime != ''">
|
||||
AND sa.create_time <= #{params.endCreateTime}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY sa.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectStglAuditorVoById" parameterType="Long" resultMap="StglAuditorResult">
|
||||
<include refid="selectStglAuditorVo"/>
|
||||
<where>
|
||||
sa.id = #{id} AND sa.deleted = 0
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="checkUserExists" parameterType="Long" resultType="int">
|
||||
SELECT COUNT(1) FROM stgl_auditor
|
||||
WHERE user_id = #{userId} AND deleted = 0
|
||||
</select>
|
||||
|
||||
<update id="enableAuditorsByIds">
|
||||
UPDATE stgl_auditor
|
||||
SET status = '1', update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = 0
|
||||
</update>
|
||||
|
||||
<update id="disableAuditorsByIds">
|
||||
UPDATE stgl_auditor
|
||||
SET status = '0', update_time = NOW()
|
||||
WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 查询完整的用户信息(包含部门信息)用于批量添加 -->
|
||||
<select id="selectUsersWithDeptInfo" resultType="org.dromara.stgl.domain.StglUserWithDeptInfo">
|
||||
select
|
||||
u.user_id as userId,
|
||||
u.user_name as userName,
|
||||
u.nick_name as nickName,
|
||||
u.dept_id as deptId,
|
||||
d.dept_name as deptName,
|
||||
u.phonenumber as phonenumber,
|
||||
u.email as email,
|
||||
u.status as status
|
||||
from sys_user u
|
||||
left join sys_dept d on u.dept_id = d.dept_id
|
||||
where u.status = '0'
|
||||
and u.user_id in
|
||||
<foreach item="userId" collection="userIds" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
order by u.dept_id, u.user_name
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -14,6 +14,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="clubCount" column="club_count"/>
|
||||
<result property="volunteerTeamCount" column="volunteer_team_count"/>
|
||||
<result property="activityCount" column="activity_count"/>
|
||||
<result property="todayActivityName" column="today_activity_name"/>
|
||||
<result property="todayActivityStartTime" column="today_activity_start_time"/>
|
||||
<result property="todayActivityEndTime" column="today_activity_end_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
@@ -52,6 +55,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
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,
|
||||
today_activity_stats.activity_name as today_activity_name,
|
||||
today_activity_stats.start_time as today_activity_start_time,
|
||||
today_activity_stats.end_time as today_activity_end_time,
|
||||
s.create_by,
|
||||
s.create_time,
|
||||
s.update_by,
|
||||
@@ -60,6 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
s.deleted
|
||||
FROM xg_student_msg s
|
||||
LEFT JOIN xg_class_msg c ON s.class_id = c.id
|
||||
AND c.tenant_id = '000000'
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
m.user_id,
|
||||
@@ -68,6 +75,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
WHERE m.member_type = 1
|
||||
AND m.deleted = 0
|
||||
AND m.status = 2
|
||||
AND m.tenant_id = '000000'
|
||||
GROUP BY m.user_id
|
||||
) club_stats ON s.id = club_stats.user_id
|
||||
LEFT JOIN (
|
||||
@@ -78,6 +86,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
WHERE m.member_type = 2
|
||||
AND m.deleted = 0
|
||||
AND m.status = 2
|
||||
AND m.tenant_id = '000000'
|
||||
GROUP BY m.user_id
|
||||
) volunteer_stats ON s.id = volunteer_stats.user_id
|
||||
LEFT JOIN (
|
||||
@@ -125,9 +134,132 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND user_id != ''
|
||||
GROUP BY user_id
|
||||
) activity_stats ON s.id = activity_stats.user_id
|
||||
LEFT JOIN (
|
||||
-- 查询学生今日活动信息(审核通过且时间为今天的活动,只取最早的一个)
|
||||
-- 使用兼容MySQL 5.7的方式,通过MIN函数和相关子查询实现
|
||||
SELECT
|
||||
ta.user_id,
|
||||
ta.activity_name,
|
||||
DATE_FORMAT(ta.start_time, '%H:%i') as start_time,
|
||||
DATE_FORMAT(ta.end_time, '%H:%i') as end_time
|
||||
FROM (
|
||||
-- 个人报名的今日活动
|
||||
SELECT
|
||||
ar.user_id,
|
||||
a.activity_name,
|
||||
a.start_time,
|
||||
a.end_time
|
||||
FROM stgl_activity_registration ar
|
||||
INNER JOIN stgl_activity a ON ar.activity_id = a.id
|
||||
AND ar.tenant_id = '000000'
|
||||
AND a.tenant_id = '000000'
|
||||
WHERE ar.deleted = 0
|
||||
AND ar.approval_status = 1
|
||||
AND ar.tenant_id = '000000'
|
||||
AND a.deleted = 0
|
||||
AND DATE(a.start_time) = CURDATE() -- 今日活动
|
||||
AND a.tenant_id = '000000'
|
||||
|
||||
UNION
|
||||
|
||||
-- 团队报名的今日活动(通过团队成员信息)
|
||||
SELECT
|
||||
JSON_UNQUOTE(JSON_EXTRACT(ati.team_members, CONCAT('$[', numbers.n, '].userId'))) as user_id,
|
||||
a.activity_name,
|
||||
a.start_time,
|
||||
a.end_time
|
||||
FROM stgl_activity_team_info ati
|
||||
CROSS JOIN (
|
||||
SELECT 0 as n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
|
||||
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION
|
||||
SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION
|
||||
SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 19
|
||||
) numbers
|
||||
INNER JOIN stgl_activity a ON ati.activity_id = a.id
|
||||
AND ati.tenant_id = '000000'
|
||||
AND a.tenant_id = '000000'
|
||||
WHERE ati.deleted = 0
|
||||
AND ati.tenant_id = '000000'
|
||||
AND a.deleted = 0
|
||||
AND DATE(a.start_time) = CURDATE() -- 今日活动
|
||||
AND a.tenant_id = '000000'
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(ati.team_members, CONCAT('$[', numbers.n, '].userId'))) IS NOT NULL
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(ati.team_members, CONCAT('$[', numbers.n, '].userId'))) != ''
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM stgl_activity_registration team_ar
|
||||
WHERE team_ar.team_id = ati.id
|
||||
AND team_ar.deleted = 0
|
||||
AND team_ar.approval_status = 1
|
||||
AND team_ar.registration_type = 2
|
||||
AND team_ar.tenant_id = '000000'
|
||||
AND team_ar.tenant_id = '000000'
|
||||
)
|
||||
AND ati.tenant_id = '000000'
|
||||
) ta
|
||||
WHERE ta.user_id IS NOT NULL
|
||||
AND ta.user_id != ''
|
||||
-- 只取每个用户最早的活动(通过相关子查询实现,兼容MySQL 5.7)
|
||||
AND ta.start_time = (
|
||||
SELECT MIN(ta2.start_time)
|
||||
FROM (
|
||||
-- 个人报名的今日活动
|
||||
SELECT
|
||||
ar2.user_id,
|
||||
a2.start_time
|
||||
FROM stgl_activity_registration ar2
|
||||
INNER JOIN stgl_activity a2 ON ar2.activity_id = a2.id
|
||||
AND ar2.tenant_id = '000000'
|
||||
AND a2.tenant_id = '000000'
|
||||
WHERE ar2.deleted = 0
|
||||
AND ar2.approval_status = 1
|
||||
AND ar2.tenant_id = '000000'
|
||||
AND a2.deleted = 0
|
||||
AND DATE(a2.start_time) = CURDATE()
|
||||
AND a2.tenant_id = '000000'
|
||||
|
||||
UNION
|
||||
|
||||
-- 团队报名的今日活动
|
||||
SELECT
|
||||
JSON_UNQUOTE(JSON_EXTRACT(ati2.team_members, CONCAT('$[', numbers2.n, '].userId'))) as user_id,
|
||||
a2.start_time
|
||||
FROM stgl_activity_team_info ati2
|
||||
CROSS JOIN (
|
||||
SELECT 0 as n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
|
||||
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION
|
||||
SELECT 10 UNION SELECT 11 UNION SELECT 12 UNION SELECT 13 UNION SELECT 14 UNION
|
||||
SELECT 15 UNION SELECT 16 UNION SELECT 17 UNION SELECT 18 UNION SELECT 19
|
||||
) numbers2
|
||||
INNER JOIN stgl_activity a2 ON ati2.activity_id = a2.id
|
||||
AND ati2.tenant_id = '000000'
|
||||
AND a2.tenant_id = '000000'
|
||||
WHERE ati2.deleted = 0
|
||||
AND ati2.tenant_id = '000000'
|
||||
AND a2.deleted = 0
|
||||
AND DATE(a2.start_time) = CURDATE()
|
||||
AND a2.tenant_id = '000000'
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(ati2.team_members, CONCAT('$[', numbers2.n, '].userId'))) IS NOT NULL
|
||||
AND JSON_UNQUOTE(JSON_EXTRACT(ati2.team_members, CONCAT('$[', numbers2.n, '].userId'))) != ''
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM stgl_activity_registration team_ar2
|
||||
WHERE team_ar2.team_id = ati2.id
|
||||
AND team_ar2.deleted = 0
|
||||
AND team_ar2.approval_status = 1
|
||||
AND team_ar2.registration_type = 2
|
||||
AND team_ar2.tenant_id = '000000'
|
||||
AND team_ar2.tenant_id = '000000'
|
||||
)
|
||||
AND ati2.tenant_id = '000000'
|
||||
) ta2
|
||||
WHERE ta2.user_id = ta.user_id
|
||||
AND ta2.user_id IS NOT NULL
|
||||
AND ta2.user_id != ''
|
||||
)
|
||||
) today_activity_stats ON s.id = today_activity_stats.user_id
|
||||
<where>
|
||||
s.deleted = 0
|
||||
AND s.student_status = '1'
|
||||
AND s.tenant_id = '000000'
|
||||
<if test="classId != null and classId != ''">
|
||||
AND s.class_id = #{classId}
|
||||
</if>
|
||||
@@ -151,6 +283,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<where>
|
||||
s.deleted = 0
|
||||
AND s.student_status = '1'
|
||||
AND s.tenant_id = '000000'
|
||||
<if test="classId != null and classId != ''">
|
||||
AND s.class_id = #{classId}
|
||||
</if>
|
||||
@@ -185,7 +318,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND m.member_type = 1
|
||||
AND m.deleted = 0
|
||||
AND m.status = 2
|
||||
AND m.tenant_id = '000000'
|
||||
AND c.deleted = 0
|
||||
AND c.tenant_id = '000000'
|
||||
ORDER BY c.create_time DESC
|
||||
</select>
|
||||
|
||||
@@ -209,7 +344,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND m.member_type = 2
|
||||
AND m.deleted = 0
|
||||
AND m.status = 2
|
||||
AND m.tenant_id = '000000'
|
||||
AND vt.deleted = 0
|
||||
AND vt.tenant_id = '000000'
|
||||
ORDER BY vt.create_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?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.StglClubAdvisorHistoryMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.vo.StglClubAdvisorHistoryVo" id="StglClubAdvisorHistoryResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="clubId" column="club_id"/>
|
||||
<result property="clubName" column="club_name"/>
|
||||
<result property="advisorName" column="advisor_name"/>
|
||||
<result property="advisorDept" column="advisor_dept"/>
|
||||
<result property="advisorPhone" column="advisor_phone"/>
|
||||
<result property="advisorEmail" column="advisor_email"/>
|
||||
<result property="advisorUserId" column="advisor_user_id"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="startTime" column="start_time"/>
|
||||
<result property="endTime" column="end_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglClubAdvisorHistoryVo">
|
||||
select h.id, h.club_id, h.advisor_name, h.advisor_dept, h.advisor_phone, h.advisor_email,
|
||||
h.advisor_user_id, h.status, h.start_time, h.end_time,
|
||||
h.create_by, h.create_time, h.update_by, h.update_time,
|
||||
c.club_name
|
||||
from stgl_club_advisor_history h
|
||||
left join stgl_club c on h.club_id = c.id
|
||||
</sql>
|
||||
|
||||
<!-- 查询指定社团的当前在任指导老师 -->
|
||||
<select id="selectCurrentAdvisorsByClubId" parameterType="Long" resultMap="StglClubAdvisorHistoryResult">
|
||||
<include refid="selectStglClubAdvisorHistoryVo"/>
|
||||
where h.club_id = #{clubId} and h.status = 1 and h.deleted = 0
|
||||
order by h.start_time asc
|
||||
</select>
|
||||
|
||||
<!-- 查询指定社团的历史指导老师(已离任) -->
|
||||
<select id="selectHistoryAdvisorsByClubId" parameterType="Long" resultMap="StglClubAdvisorHistoryResult">
|
||||
<include refid="selectStglClubAdvisorHistoryVo"/>
|
||||
where h.club_id = #{clubId} and h.status = 0 and h.deleted = 0
|
||||
order by h.end_time desc
|
||||
</select>
|
||||
|
||||
<!-- 查询指定社团的所有指导老师(包含当前和历史) -->
|
||||
<select id="selectAllAdvisorsByClubId" parameterType="Long" resultMap="StglClubAdvisorHistoryResult">
|
||||
<include refid="selectStglClubAdvisorHistoryVo"/>
|
||||
where h.club_id = #{clubId} and h.deleted = 0
|
||||
order by h.status desc, h.start_time desc
|
||||
</select>
|
||||
|
||||
<!-- 批量设置指导老师为历史状态(离任) -->
|
||||
<update id="batchSetHistoryStatus">
|
||||
update stgl_club_advisor_history
|
||||
set status = 0, end_time = #{endTime}, update_time = now()
|
||||
where club_id = #{clubId} and status = 1 and deleted = 0
|
||||
<if test="advisorNames != null and advisorNames.size() > 0">
|
||||
and advisor_name in
|
||||
<foreach collection="advisorNames" item="name" open="(" close=")" separator=",">
|
||||
#{name}
|
||||
</foreach>
|
||||
</if>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?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.StglClubAnnualReviewActivityMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.StglClubAnnualReviewActivity" id="StglClubAnnualReviewActivityResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="createDept" column="create_dept" />
|
||||
<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="deleted" column="deleted" />
|
||||
<result property="annualReviewId" column="annual_review_id" />
|
||||
<result property="activityName" column="activity_name" />
|
||||
<result property="activityTime" column="activity_time" />
|
||||
<result property="activityLocation" column="activity_location" />
|
||||
<result property="activityType" column="activity_type" />
|
||||
<result property="participantCount" column="participant_count" />
|
||||
<result property="activityDescription" column="activity_description" />
|
||||
<result property="activityStartTime" column="activity_start_time" />
|
||||
<result property="activityEndTime" column="activity_end_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglClubAnnualReviewActivityVo">
|
||||
select id, tenant_id, create_dept, create_by, create_time, update_by, update_time, deleted, annual_review_id, activity_name, activity_time, activity_start_time, activity_end_time, activity_location, activity_type, participant_count, activity_description from stgl_club_annual_review_activity
|
||||
</sql>
|
||||
|
||||
<!-- 根据年审记录ID查询活动列表 -->
|
||||
<select id="selectActivitiesByAnnualReviewId" parameterType="Long" resultMap="StglClubAnnualReviewActivityResult">
|
||||
<include refid="selectStglClubAnnualReviewActivityVo"/>
|
||||
where annual_review_id = #{annualReviewId} and deleted = 0
|
||||
order by activity_time desc, create_time asc
|
||||
</select>
|
||||
|
||||
<!-- 根据年审记录ID删除活动 -->
|
||||
<update id="deleteActivitiesByAnnualReviewId" parameterType="Long">
|
||||
update stgl_club_annual_review_activity set deleted = 1
|
||||
where annual_review_id = #{annualReviewId} and deleted = 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
<?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.StglClubAnnualReviewMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.vo.StglClubAnnualReviewVo" id="StglClubAnnualReviewResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="clubId" column="club_id" />
|
||||
<result property="reviewYear" column="review_year" />
|
||||
<result property="reviewStartDate" column="review_start_date" />
|
||||
<result property="reviewEndDate" column="review_end_date" />
|
||||
<result property="reviewTime" column="review_time" />
|
||||
<result property="clubName" column="club_name" />
|
||||
<result property="establishDate" column="establish_date" />
|
||||
<result property="presidentName" column="president_name" />
|
||||
<result property="clubType" column="club_type" />
|
||||
<result property="advisorName" column="advisor_name" />
|
||||
<result property="advisorDept" column="advisor_dept" />
|
||||
<result property="hasCharter" column="has_charter" />
|
||||
<result property="charterUrl" column="charter_url" />
|
||||
<result property="hasFunds" column="has_funds" />
|
||||
<result property="fundAmount" column="fund_amount" />
|
||||
<result property="memberCount" column="member_count" />
|
||||
<result property="status" column="status" />
|
||||
<result property="advisorOpinion" column="advisor_opinion" />
|
||||
<result property="collegeOpinion" column="college_opinion" />
|
||||
<result property="youthLeagueOpinion" column="youth_league_opinion" />
|
||||
<result property="membersJson" column="members_json" />
|
||||
<result property="activitiesJson" column="activities_json" />
|
||||
<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" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglClubAnnualReviewVo">
|
||||
select
|
||||
ar.id, ar.club_id, ar.review_year, ar.review_start_date, ar.review_end_date, ar.review_time,
|
||||
ar.club_name, ar.establish_date, ar.club_type, ar.advisor_name, ar.advisor_dept,
|
||||
ar.has_charter, ar.charter_url, ar.has_funds, ar.fund_amount, ar.member_count,
|
||||
ar.status, ar.advisor_opinion, ar.college_opinion, ar.youth_league_opinion,
|
||||
ar.members_json, ar.activities_json,
|
||||
ar.create_by, ar.create_time, ar.update_by, ar.update_time, ar.tenant_id,
|
||||
c.president_name
|
||||
from stgl_club_annual_review ar
|
||||
left join stgl_club c on ar.club_id = c.id
|
||||
</sql>
|
||||
|
||||
<select id="selectVoList" parameterType="com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper" resultMap="StglClubAnnualReviewResult">
|
||||
<include refid="selectStglClubAnnualReviewVo"/>
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="selectVoPage" resultMap="StglClubAnnualReviewResult">
|
||||
<include refid="selectStglClubAnnualReviewVo"/>
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="selectVoById" parameterType="Long" resultMap="StglClubAnnualReviewResult">
|
||||
<include refid="selectStglClubAnnualReviewVo"/>
|
||||
where ar.id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?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.StglClubAnnualReviewMemberMapper">
|
||||
|
||||
<resultMap type="org.dromara.stgl.domain.StglClubAnnualReviewMember" id="StglClubAnnualReviewMemberResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="tenantId" column="tenant_id" />
|
||||
<result property="createDept" column="create_dept" />
|
||||
<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="deleted" column="deleted" />
|
||||
<result property="annualReviewId" column="annual_review_id" />
|
||||
<result property="memberName" column="member_name" />
|
||||
<result property="className" column="class_name" />
|
||||
<result property="role" column="role" />
|
||||
<result property="contactInfo" column="contact_info" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectStglClubAnnualReviewMemberVo">
|
||||
select id, tenant_id, create_dept, create_by, create_time, update_by, update_time, deleted, annual_review_id, member_name, class_name, role, contact_info from stgl_club_annual_review_member
|
||||
</sql>
|
||||
|
||||
<!-- 根据年审记录ID查询成员列表 -->
|
||||
<select id="selectMembersByAnnualReviewId" parameterType="Long" resultMap="StglClubAnnualReviewMemberResult">
|
||||
<include refid="selectStglClubAnnualReviewMemberVo"/>
|
||||
where annual_review_id = #{annualReviewId} and deleted = 0
|
||||
order by create_time asc
|
||||
</select>
|
||||
|
||||
<!-- 根据年审记录ID删除成员 -->
|
||||
<update id="deleteMembersByAnnualReviewId" parameterType="Long">
|
||||
update stgl_club_annual_review_member set deleted = 1
|
||||
where annual_review_id = #{annualReviewId} and deleted = 0
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.vo.StudentOptionVo;
|
||||
import org.dromara.xg.domain.bo.StudentOptionBo;
|
||||
import org.dromara.xg.service.IXgDormApplicationService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/dormApplication/dormApplication")
|
||||
public class XgDormApplicationController extends BaseController {
|
||||
|
||||
private final IXgDormApplicationService xgDormApplicationService;
|
||||
|
||||
/**
|
||||
* 查询学生宿舍申请单表(调宿+退宿)列表
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XgDormApplicationVo> list(XgDormApplicationBo bo, PageQuery pageQuery) {
|
||||
return xgDormApplicationService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生选择器选项列表(支持按学号、姓名检索)
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:list")
|
||||
@GetMapping("/studentOptions")
|
||||
public TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery) {
|
||||
return xgDormApplicationService.getStudentOptions(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出学生宿舍申请单表(调宿+退宿)列表
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:export")
|
||||
@Log(title = "学生宿舍申请单表(调宿+退宿)", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(XgDormApplicationBo bo, HttpServletResponse response) {
|
||||
List<XgDormApplicationVo> list = xgDormApplicationService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "学生宿舍申请单表(调宿+退宿)", XgDormApplicationVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生宿舍申请单表(调宿+退宿)详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XgDormApplicationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(xgDormApplicationService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:add")
|
||||
@Log(title = "学生宿舍申请单表(调宿+退宿)", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<XgDormApplicationVo> add(@Validated(AddGroup.class) @RequestBody XgDormApplicationBo bo) {
|
||||
XgDormApplicationVo result = xgDormApplicationService.insertByBo(bo);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:edit")
|
||||
@Log(title = "学生宿舍申请单表(调宿+退宿)", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XgDormApplicationBo bo) {
|
||||
return toAjax(xgDormApplicationService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:remove")
|
||||
@Log(title = "学生宿舍申请单表(调宿+退宿)", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(xgDormApplicationService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二级学院审批人列表
|
||||
*
|
||||
* @param collegeId 学院ID
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:list")
|
||||
@GetMapping("/getCollegeApprovers")
|
||||
public R<List<Map<String, Object>>> getCollegeApprovers(@RequestParam Long collegeId) {
|
||||
List<Map<String, Object>> approvers = xgDormApplicationService.getCollegeApprovers(collegeId);
|
||||
return R.ok(approvers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学工处审批人列表
|
||||
*/
|
||||
@SaCheckPermission("dormApplication:dormApplication:list")
|
||||
@GetMapping("/getStudentAffairsApprovers")
|
||||
public R<List<Map<String, Object>>> getStudentAffairsApprovers() {
|
||||
List<Map<String, Object>> approvers = xgDormApplicationService.getStudentAffairsApprovers();
|
||||
return R.ok(approvers);
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -332,4 +332,26 @@ public class XgDormBedStudentController extends BaseController {
|
||||
return R.ok(roomStudents);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据学生ID获取当前宿舍信息
|
||||
* 包含校区、宿舍楼、房间号、床位号等信息
|
||||
*/
|
||||
@SaCheckPermission("dormBedStudent:dormBedStudent:list")
|
||||
@GetMapping("/currentDormInfo/{studentId}")
|
||||
public R<Object> getCurrentDormInfo(@NotNull(message = "学生ID不能为空") @PathVariable Long studentId) {
|
||||
Object currentDormInfo = xgDormBedStudentService.getCurrentDormInfo(studentId);
|
||||
return R.ok(currentDormInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据床位ID获取该床位的学生信息
|
||||
* 包含学生基本信息、学院、专业、班级等信息
|
||||
*/
|
||||
@SaCheckPermission("dormBedStudent:dormBedStudent:list")
|
||||
@GetMapping("/bedStudentInfo/{bedId}")
|
||||
public R<Object> getBedStudentInfo(@NotNull(message = "床位ID不能为空") @PathVariable Long bedId) {
|
||||
Object bedStudentInfo = xgDormBedStudentService.getBedStudentInfo(bedId);
|
||||
return R.ok(bedStudentInfo);
|
||||
}
|
||||
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
package org.dromara.xg.domain;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)对象 xg_dorm_application
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xg_dorm_application")
|
||||
public class XgDormApplication extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申请名称
|
||||
*/
|
||||
private String applicationName;
|
||||
|
||||
/**
|
||||
* 申请类型(1:调宿申请 2:退宿申请)
|
||||
*/
|
||||
private String applicationType;
|
||||
|
||||
/**
|
||||
* 审批状态:cancel-已撤销 , draft-草稿, waiting-待审核, finish-已完成, invalid-已作废, back-已退回,
|
||||
* termination-已终止
|
||||
*/
|
||||
private String applicationStatus;
|
||||
|
||||
/**
|
||||
* 申请学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学生联系电话
|
||||
*/
|
||||
private String studentPhone;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 当前校区ID
|
||||
*/
|
||||
private Long currentCampusId;
|
||||
|
||||
/**
|
||||
* 当前校区名称
|
||||
*/
|
||||
private String currentCampusName;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼ID
|
||||
*/
|
||||
private Long currentBuildingId;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼名称
|
||||
*/
|
||||
private String currentBuildingName;
|
||||
|
||||
/**
|
||||
* 当前房间ID
|
||||
*/
|
||||
private Long currentRoomId;
|
||||
|
||||
/**
|
||||
* 当前房间号
|
||||
*/
|
||||
private String currentRoomNo;
|
||||
|
||||
/**
|
||||
* 当前床位ID
|
||||
*/
|
||||
private Long currentBedId;
|
||||
|
||||
/**
|
||||
* 当前床位号
|
||||
*/
|
||||
private String currentBedNo;
|
||||
|
||||
/**
|
||||
* 目标校区ID
|
||||
*/
|
||||
private Long targetCampusId;
|
||||
|
||||
/**
|
||||
* 目标校区名称
|
||||
*/
|
||||
private String targetCampusName;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼ID
|
||||
*/
|
||||
private Long targetBuildingId;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼名称
|
||||
*/
|
||||
private String targetBuildingName;
|
||||
|
||||
/**
|
||||
* 目标房间ID
|
||||
*/
|
||||
private Long targetRoomId;
|
||||
|
||||
/**
|
||||
* 目标房间号
|
||||
*/
|
||||
private String targetRoomNo;
|
||||
|
||||
/**
|
||||
* 目标床位ID
|
||||
*/
|
||||
private Long targetBedId;
|
||||
|
||||
/**
|
||||
* 目标床位号
|
||||
*/
|
||||
private String targetBedNo;
|
||||
|
||||
/**
|
||||
* 详细原因说明
|
||||
*/
|
||||
private String reasonDetail;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID,多个用逗号分隔
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 扩展字段1
|
||||
*/
|
||||
private String extField1;
|
||||
|
||||
/**
|
||||
* 扩展字段2
|
||||
*/
|
||||
private String extField2;
|
||||
|
||||
/**
|
||||
* 扩展字段3
|
||||
*/
|
||||
private String extField3;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private String deleted;
|
||||
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import org.dromara.xg.domain.XgDormApplication;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)业务对象 xg_dorm_application
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XgDormApplication.class, reverseConvertGenerate = false)
|
||||
public class XgDormApplicationBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申请名称
|
||||
*/
|
||||
@NotBlank(message = "申请名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String applicationName;
|
||||
|
||||
/**
|
||||
* 申请类型(1:调宿申请 2:退宿申请)
|
||||
*/
|
||||
@NotBlank(message = "申请类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String applicationType;
|
||||
|
||||
/**
|
||||
* 审批状态:cancel-已撤销 , draft-草稿, waiting-待审核, finish-已完成, invalid-已作废, back-已退回,
|
||||
* termination-已终止
|
||||
*/
|
||||
private String applicationStatus;
|
||||
|
||||
/**
|
||||
* 申请学生ID
|
||||
*/
|
||||
@NotNull(message = "申请学生ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学生联系电话
|
||||
*/
|
||||
private String studentPhone;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
@NotNull(message = "学院ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 当前校区ID
|
||||
*/
|
||||
private Long currentCampusId;
|
||||
|
||||
/**
|
||||
* 当前校区名称
|
||||
*/
|
||||
private String currentCampusName;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼ID
|
||||
*/
|
||||
private Long currentBuildingId;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼名称
|
||||
*/
|
||||
private String currentBuildingName;
|
||||
|
||||
/**
|
||||
* 当前房间ID
|
||||
*/
|
||||
private Long currentRoomId;
|
||||
|
||||
/**
|
||||
* 当前房间号
|
||||
*/
|
||||
private String currentRoomNo;
|
||||
|
||||
/**
|
||||
* 当前床位ID
|
||||
*/
|
||||
private Long currentBedId;
|
||||
|
||||
/**
|
||||
* 当前床位号
|
||||
*/
|
||||
private String currentBedNo;
|
||||
|
||||
/**
|
||||
* 目标校区ID
|
||||
*/
|
||||
private Long targetCampusId;
|
||||
|
||||
/**
|
||||
* 目标校区名称
|
||||
*/
|
||||
private String targetCampusName;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼ID
|
||||
*/
|
||||
private Long targetBuildingId;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼名称
|
||||
*/
|
||||
private String targetBuildingName;
|
||||
|
||||
/**
|
||||
* 目标房间ID
|
||||
*/
|
||||
private Long targetRoomId;
|
||||
|
||||
/**
|
||||
* 目标房间号
|
||||
*/
|
||||
private String targetRoomNo;
|
||||
|
||||
/**
|
||||
* 目标床位ID
|
||||
*/
|
||||
private Long targetBedId;
|
||||
|
||||
/**
|
||||
* 目标床位号
|
||||
*/
|
||||
private String targetBedNo;
|
||||
|
||||
/**
|
||||
* 详细原因说明
|
||||
*/
|
||||
@NotBlank(message = "详细原因说明不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String reasonDetail;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@NotNull(message = "申请时间不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID,多个用逗号分隔
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 扩展字段1
|
||||
*/
|
||||
private String extField1;
|
||||
|
||||
/**
|
||||
* 扩展字段2
|
||||
*/
|
||||
private String extField2;
|
||||
|
||||
/**
|
||||
* 扩展字段3
|
||||
*/
|
||||
private String extField3;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
private String deleted;
|
||||
|
||||
}
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import org.dromara.xg.domain.XgDormApplication;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)视图对象 xg_dorm_application
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@AutoMapper(target = XgDormApplication.class)
|
||||
public class XgDormApplicationVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 申请名称
|
||||
*/
|
||||
private String applicationName;
|
||||
|
||||
/**
|
||||
* 申请类型(1:调宿申请 2:退宿申请)
|
||||
*/
|
||||
private String applicationType;
|
||||
|
||||
/**
|
||||
* 审批状态:cancel-已撤销 , draft-草稿, waiting-待审核, finish-已完成, invalid-已作废, back-已退回,
|
||||
* termination-已终止
|
||||
*/
|
||||
private String applicationStatus;
|
||||
|
||||
/**
|
||||
* 申请学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学生联系电话
|
||||
*/
|
||||
private String studentPhone;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 当前校区ID
|
||||
*/
|
||||
private Long currentCampusId;
|
||||
|
||||
/**
|
||||
* 当前校区名称
|
||||
*/
|
||||
private String currentCampusName;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼ID
|
||||
*/
|
||||
private Long currentBuildingId;
|
||||
|
||||
/**
|
||||
* 当前宿舍楼名称
|
||||
*/
|
||||
private String currentBuildingName;
|
||||
|
||||
/**
|
||||
* 当前房间ID
|
||||
*/
|
||||
private Long currentRoomId;
|
||||
|
||||
/**
|
||||
* 当前房间号
|
||||
*/
|
||||
private String currentRoomNo;
|
||||
|
||||
/**
|
||||
* 当前床位ID
|
||||
*/
|
||||
private Long currentBedId;
|
||||
|
||||
/**
|
||||
* 当前床位号
|
||||
*/
|
||||
private String currentBedNo;
|
||||
|
||||
/**
|
||||
* 目标校区ID
|
||||
*/
|
||||
private Long targetCampusId;
|
||||
|
||||
/**
|
||||
* 目标校区名称
|
||||
*/
|
||||
private String targetCampusName;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼ID
|
||||
*/
|
||||
private Long targetBuildingId;
|
||||
|
||||
/**
|
||||
* 目标宿舍楼名称
|
||||
*/
|
||||
private String targetBuildingName;
|
||||
|
||||
/**
|
||||
* 目标房间ID
|
||||
*/
|
||||
private Long targetRoomId;
|
||||
|
||||
/**
|
||||
* 目标房间号
|
||||
*/
|
||||
private String targetRoomNo;
|
||||
|
||||
/**
|
||||
* 目标床位ID
|
||||
*/
|
||||
private Long targetBedId;
|
||||
|
||||
/**
|
||||
* 目标床位号
|
||||
*/
|
||||
private String targetBedNo;
|
||||
|
||||
/**
|
||||
* 详细原因说明
|
||||
*/
|
||||
private String reasonDetail;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date applyTime;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID,多个用逗号分隔
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 扩展字段1
|
||||
*/
|
||||
private String extField1;
|
||||
|
||||
/**
|
||||
* 扩展字段2
|
||||
*/
|
||||
private String extField2;
|
||||
|
||||
/**
|
||||
* 扩展字段3
|
||||
*/
|
||||
private String extField3;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
private String deleted;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.dromara.xg.domain.XgDormApplication;
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.vo.StudentOptionVo;
|
||||
import org.dromara.xg.domain.bo.StudentOptionBo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface XgDormApplicationMapper extends BaseMapperPlus<XgDormApplication, XgDormApplicationVo> {
|
||||
|
||||
/**
|
||||
* 查询学生选择器选项列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @return 学生选择器选项分页列表
|
||||
*/
|
||||
Page<StudentOptionVo> selectStudentOptions(IPage<?> page, @Param("bo") StudentOptionBo bo);
|
||||
|
||||
}
|
||||
+91
@@ -188,4 +188,95 @@ public interface XgDormBedStudentMapper extends BaseMapperPlus<XgDormBedStudent,
|
||||
""")
|
||||
List<Map<String, Object>> selectRoomStudents(@Param("roomId") Long roomId);
|
||||
|
||||
/**
|
||||
* 根据学生ID获取当前宿舍信息
|
||||
* 包含校区、宿舍楼、房间号、床位号等信息
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 当前宿舍信息
|
||||
*/
|
||||
@Select("""
|
||||
SELECT
|
||||
-- 校区信息
|
||||
campus.id as campus_id,
|
||||
campus.campus_name,
|
||||
|
||||
-- 宿舍区信息
|
||||
area.id as area_id,
|
||||
area.area_name,
|
||||
|
||||
-- 楼栋信息
|
||||
building.id as building_id,
|
||||
building.building_name,
|
||||
building.building_code,
|
||||
|
||||
-- 房间信息
|
||||
r.id as room_id,
|
||||
r.room_name,
|
||||
r.room_code as room_no,
|
||||
|
||||
-- 床位信息
|
||||
b.id as bed_id,
|
||||
b.bed_name,
|
||||
b.bed_code as bed_no
|
||||
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_dorm_bed b ON bs.bed_id = b.id AND b.deleted = '0'
|
||||
INNER JOIN xg_dorm_room r ON b.room_id = r.id AND r.deleted = '0'
|
||||
INNER JOIN xg_dorm_building building ON r.building_id = building.id AND building.deleted = '0'
|
||||
INNER JOIN xg_dorm_area area ON building.area_id = area.id AND area.deleted = '0'
|
||||
INNER JOIN xg_dorm_campus campus ON area.campus_id = campus.id AND campus.deleted = '0'
|
||||
|
||||
WHERE bs.student_id = #{studentId}
|
||||
AND bs.student_id IS NOT NULL
|
||||
AND bs.status = '0'
|
||||
AND bs.deleted = '0'
|
||||
|
||||
LIMIT 1
|
||||
""")
|
||||
Map<String, Object> selectCurrentDormInfo(@Param("studentId") Long studentId);
|
||||
|
||||
/**
|
||||
* 根据床位ID获取该床位的学生信息
|
||||
* 包含学生基本信息、学院、专业、班级等信息
|
||||
*
|
||||
* @param bedId 床位ID
|
||||
* @return 床位学生信息
|
||||
*/
|
||||
@Select("""
|
||||
SELECT
|
||||
bs.student_id,
|
||||
bs.bed_id,
|
||||
|
||||
-- 学生基本信息
|
||||
s.student_no,
|
||||
s.name as student_name,
|
||||
s.gender,
|
||||
s.phone,
|
||||
|
||||
-- 班级信息
|
||||
c.class_name,
|
||||
|
||||
-- 学院信息
|
||||
d.dept_name as college_name,
|
||||
|
||||
-- 专业信息
|
||||
major.dept_name as major_name
|
||||
|
||||
FROM xg_dorm_bed_student bs
|
||||
INNER JOIN xg_student_msg s ON bs.student_id = s.id AND s.deleted = 0
|
||||
LEFT JOIN xg_class_msg c ON s.class_id = c.id AND c.deleted = 0
|
||||
LEFT JOIN sys_dept d ON c.college_id = d.dept_id AND d.del_flag = '0'
|
||||
LEFT JOIN sys_dept major ON c.major_id = major.dept_id AND major.del_flag = '0'
|
||||
|
||||
WHERE bs.bed_id = #{bedId}
|
||||
AND bs.student_id IS NOT NULL
|
||||
AND bs.status = '0'
|
||||
AND bs.deleted = '0'
|
||||
AND s.student_status = '1'
|
||||
|
||||
LIMIT 1
|
||||
""")
|
||||
Map<String, Object> selectBedStudentInfo(@Param("bedId") Long bedId);
|
||||
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.vo.StudentOptionVo;
|
||||
import org.dromara.xg.domain.bo.StudentOptionBo;
|
||||
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 zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IXgDormApplicationService {
|
||||
|
||||
/**
|
||||
* 查询学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param id 学生宿舍申请单表(调宿+退宿)主键
|
||||
* @return 学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
XgDormApplicationVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询学生宿舍申请单表(调宿+退宿)列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生宿舍申请单表(调宿+退宿)分页列表
|
||||
*/
|
||||
TableDataInfo<XgDormApplicationVo> queryPageList(XgDormApplicationBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生宿舍申请单表(调宿+退宿)列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生宿舍申请单表(调宿+退宿)列表
|
||||
*/
|
||||
List<XgDormApplicationVo> queryList(XgDormApplicationBo bo);
|
||||
|
||||
/**
|
||||
* 新增学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param bo 学生宿舍申请单表(调宿+退宿)
|
||||
* @return 新增成功的学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
XgDormApplicationVo insertByBo(XgDormApplicationBo bo);
|
||||
|
||||
/**
|
||||
* 修改学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param bo 学生宿舍申请单表(调宿+退宿)
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(XgDormApplicationBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生宿舍申请单表(调宿+退宿)信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 获取学生选择器选项列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生选择器选项分页列表
|
||||
*/
|
||||
TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 获取二级学院审批人列表
|
||||
*
|
||||
* @param collegeId 学院ID
|
||||
* @return 审批人列表
|
||||
*/
|
||||
List<Map<String, Object>> getCollegeApprovers(Long collegeId);
|
||||
|
||||
/**
|
||||
* 获取学工处审批人列表
|
||||
*
|
||||
* @return 审批人列表
|
||||
*/
|
||||
List<Map<String, Object>> getStudentAffairsApprovers();
|
||||
|
||||
}
|
||||
+18
@@ -242,4 +242,22 @@ public interface IXgDormBedStudentService {
|
||||
* @return 房间学生信息列表
|
||||
*/
|
||||
List<Object> getRoomStudents(Long roomId);
|
||||
|
||||
/**
|
||||
* 根据学生ID获取当前宿舍信息
|
||||
* 包含校区、宿舍楼、房间号、床位号等信息
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 当前宿舍信息
|
||||
*/
|
||||
Object getCurrentDormInfo(Long studentId);
|
||||
|
||||
/**
|
||||
* 根据床位ID获取该床位的学生信息
|
||||
* 包含学生基本信息、学院、专业、班级等信息
|
||||
*
|
||||
* @param bedId 床位ID
|
||||
* @return 床位学生信息
|
||||
*/
|
||||
Object getBedStudentInfo(Long bedId);
|
||||
}
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.xg.domain.bo.XgDormApplicationBo;
|
||||
import org.dromara.xg.domain.vo.XgDormApplicationVo;
|
||||
import org.dromara.xg.domain.vo.StudentOptionVo;
|
||||
import org.dromara.xg.domain.bo.StudentOptionBo;
|
||||
import org.dromara.xg.domain.XgDormApplication;
|
||||
import org.dromara.xg.mapper.XgDormApplicationMapper;
|
||||
import org.dromara.xg.service.IXgDormApplicationService;
|
||||
import org.dromara.workflow.common.ConditionalOnEnable;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.common.core.domain.event.ProcessTaskEvent;
|
||||
import org.dromara.common.core.domain.event.ProcessDeleteEvent;
|
||||
import org.dromara.common.core.domain.event.ProcessEvent;
|
||||
import org.dromara.common.core.enums.BusinessStatusEnum;
|
||||
import org.dromara.common.core.service.WorkflowService;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.system.mapper.SysDeptMapper;
|
||||
import org.dromara.system.mapper.SysUserMapper;
|
||||
import org.dromara.system.mapper.SysUserRoleMapper;
|
||||
import org.dromara.system.mapper.SysRoleMapper;
|
||||
import org.dromara.system.domain.SysDept;
|
||||
import org.dromara.system.domain.SysUser;
|
||||
import org.dromara.system.domain.SysRole;
|
||||
import org.dromara.xg.mapper.XgStudentManagerMapper;
|
||||
import org.dromara.xg.mapper.XgStudentManagerSourceMapper;
|
||||
import org.dromara.xg.mapper.XgClassMsgMapper;
|
||||
import org.dromara.xg.mapper.XgDormBedStudentMapper;
|
||||
import org.dromara.xg.service.IXgDormBedStudentService;
|
||||
import org.dromara.xg.domain.XgStudentManager;
|
||||
import org.dromara.xg.domain.XgStudentManagerSource;
|
||||
import org.dromara.xg.domain.XgClassMsg;
|
||||
import org.dromara.xg.domain.XgDormBedStudent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 学生宿舍申请单表(调宿+退宿)Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@ConditionalOnEnable
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgDormApplicationServiceImpl implements IXgDormApplicationService {
|
||||
|
||||
private final XgDormApplicationMapper baseMapper;
|
||||
private final WorkflowService workflowService;
|
||||
private final XgDormBedStudentMapper xgDormBedStudentMapper;
|
||||
private final IXgDormBedStudentService xgDormBedStudentService;
|
||||
// 添加权限过滤需要的依赖
|
||||
private final SysDeptMapper sysDeptMapper;
|
||||
private final SysUserMapper sysUserMapper;
|
||||
private final SysUserRoleMapper sysUserRoleMapper;
|
||||
private final SysRoleMapper sysRoleMapper;
|
||||
private final XgStudentManagerMapper xgStudentManagerMapper;
|
||||
private final XgStudentManagerSourceMapper xgStudentManagerSourceMapper;
|
||||
private final XgClassMsgMapper xgClassMsgMapper;
|
||||
|
||||
/**
|
||||
* 查询学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
@Override
|
||||
public XgDormApplicationVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学生宿舍申请单表(调宿+退宿)列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生宿舍申请单表(调宿+退宿)分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgDormApplicationVo> queryPageList(XgDormApplicationBo bo, PageQuery pageQuery) {
|
||||
// 增加班级数据权限的过滤功能
|
||||
// 第一步:调用权限过滤方法,获取过滤后的班级IDs(传入101作为根组织ID)
|
||||
List<Long> filteredDeptIds = filterDeptIdsByPermission(101L);
|
||||
log.info("权限过滤后的班级ID列表: {}", filteredDeptIds);
|
||||
|
||||
// 第二步:使用带权限过滤的查询条件构建器
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = buildQueryWrapperWithPermission(bo, filteredDeptIds);
|
||||
Page<XgDormApplicationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生宿舍申请单表(调宿+退宿)列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生宿舍申请单表(调宿+退宿)列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgDormApplicationVo> queryList(XgDormApplicationBo bo) {
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限过滤方法
|
||||
* 根据当前用户的权限范围过滤部门ID列表
|
||||
*
|
||||
* @param deptId 入参的部门ID
|
||||
* @return 过滤后的部门ID列表
|
||||
*/
|
||||
private List<Long> filterDeptIdsByPermission(Long deptId) {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
log.info("当前登录用户ID: {}", currentUserId);
|
||||
|
||||
// 第一步:判断当前用户是否为全校管理员
|
||||
boolean isSchoolManager = checkIsSchoolManager(currentUserId);
|
||||
if (isSchoolManager) {
|
||||
log.info("用户 {} 是全校管理员,不进行权限过滤", currentUserId);
|
||||
// 全校管理员不进行过滤,返回包含入参deptId及其子组织的列表
|
||||
return getDeptIdsWithChildren(deptId);
|
||||
}
|
||||
|
||||
// 第二步:获取用户的总权限集合
|
||||
Set<Long> userAuthDeptIds = getUserAuthDeptIds(currentUserId);
|
||||
log.info("用户 {} 的权限范围: {}", currentUserId, userAuthDeptIds);
|
||||
|
||||
// 第三步:判断入参deptId是否在用户权限范围内
|
||||
if (deptId != null && userAuthDeptIds.contains(deptId)) {
|
||||
log.info("入参deptId {} 在用户权限范围内,不进行过滤", deptId);
|
||||
// 在权限范围内,返回包含入参deptId及其子组织的列表
|
||||
return getDeptIdsWithChildren(deptId);
|
||||
} else {
|
||||
log.info("入参deptId {} 不在用户权限范围内,进行权限过滤", deptId);
|
||||
// 不在权限范围内,过滤deptIds,只保留在权限范围内的
|
||||
List<Long> filteredDeptIds = new ArrayList<>();
|
||||
if (deptId != null) {
|
||||
// 如果入参deptId不为空,检查其子组织是否在权限范围内
|
||||
List<Long> deptIdsWithChildren = getDeptIdsWithChildren(deptId);
|
||||
for (Long deptIdWithChild : deptIdsWithChildren) {
|
||||
if (userAuthDeptIds.contains(deptIdWithChild)) {
|
||||
filteredDeptIds.add(deptIdWithChild);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 如果入参deptId为空,直接使用用户权限范围内的所有部门
|
||||
filteredDeptIds.addAll(userAuthDeptIds);
|
||||
}
|
||||
|
||||
// 对过滤后的deptIds,查找所有子组织包括他们自己
|
||||
Set<Long> finalDeptIds = new HashSet<>();
|
||||
for (Long filteredDeptId : filteredDeptIds) {
|
||||
List<Long> deptIdsWithChildren = getDeptIdsWithChildren(filteredDeptId);
|
||||
finalDeptIds.addAll(deptIdsWithChildren);
|
||||
}
|
||||
|
||||
return new ArrayList<>(finalDeptIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否为全校管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 是否为全校管理员
|
||||
*/
|
||||
private boolean checkIsSchoolManager(Long userId) {
|
||||
LambdaQueryWrapper<XgStudentManager> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(XgStudentManager::getUserId, userId)
|
||||
.eq(XgStudentManager::getDeleted, "0")
|
||||
.eq(XgStudentManager::getStatus, "0")
|
||||
.eq(XgStudentManager::getManagerType, "1");
|
||||
|
||||
return xgStudentManagerMapper.selectCount(lqw) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的总权限集合
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户权限范围内的部门ID集合
|
||||
*/
|
||||
private Set<Long> getUserAuthDeptIds(Long userId) {
|
||||
Set<Long> authDeptIds = new HashSet<>();
|
||||
|
||||
// 第三步:通过xg_student_manager和xg_student_manager_source关联,获取用户的权限范围
|
||||
LambdaQueryWrapper<XgStudentManager> managerWrapper = Wrappers.lambdaQuery();
|
||||
managerWrapper.eq(XgStudentManager::getUserId, userId)
|
||||
.eq(XgStudentManager::getDeleted, "0")
|
||||
.eq(XgStudentManager::getStatus, "0");
|
||||
|
||||
List<XgStudentManager> managers = xgStudentManagerMapper.selectList(managerWrapper);
|
||||
|
||||
for (XgStudentManager manager : managers) {
|
||||
LambdaQueryWrapper<XgStudentManagerSource> sourceWrapper = Wrappers.lambdaQuery();
|
||||
sourceWrapper.eq(XgStudentManagerSource::getManagerId, manager.getId())
|
||||
.eq(XgStudentManagerSource::getDeleted, "0")
|
||||
.eq(XgStudentManagerSource::getStatus, "0");
|
||||
|
||||
List<XgStudentManagerSource> sources = xgStudentManagerSourceMapper.selectList(sourceWrapper);
|
||||
for (XgStudentManagerSource source : sources) {
|
||||
if (source.getAuthSource() != null) {
|
||||
authDeptIds.add(source.getAuthSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 第四步:通过xg_class_msg表,class_teacher_id=当前登录人id,deleted='0',class_status='1',获取id
|
||||
LambdaQueryWrapper<XgClassMsg> classWrapper = Wrappers.lambdaQuery();
|
||||
classWrapper.eq(XgClassMsg::getClassTeacherId, userId)
|
||||
.eq(XgClassMsg::getDeleted, 0L)
|
||||
.eq(XgClassMsg::getClassStatus, "1");
|
||||
|
||||
List<XgClassMsg> classes = xgClassMsgMapper.selectList(classWrapper);
|
||||
for (XgClassMsg classMsg : classes) {
|
||||
if (classMsg.getId() != null) {
|
||||
authDeptIds.add(classMsg.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return authDeptIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门ID及其所有子组织的ID列表
|
||||
*
|
||||
* @param deptId 部门ID
|
||||
* @return 包含部门ID及其子组织的ID列表
|
||||
*/
|
||||
private List<Long> getDeptIdsWithChildren(Long deptId) {
|
||||
List<Long> deptIds = new ArrayList<>();
|
||||
if (deptId != null) {
|
||||
deptIds.add(deptId); // 包含自己
|
||||
|
||||
// 查找所有子组织
|
||||
List<SysDept> childDepts = sysDeptMapper.selectListByParentId(deptId);
|
||||
if (!childDepts.isEmpty()) {
|
||||
List<Long> childDeptIds = childDepts.stream()
|
||||
.map(SysDept::getDeptId)
|
||||
.collect(Collectors.toList());
|
||||
deptIds.addAll(childDeptIds);
|
||||
}
|
||||
}
|
||||
return deptIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建带权限过滤的查询条件包装器
|
||||
*/
|
||||
private LambdaQueryWrapper<XgDormApplication> buildQueryWrapperWithPermission(XgDormApplicationBo bo,
|
||||
List<Long> filteredDeptIds) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(XgDormApplication::getCreateTime);
|
||||
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 添加权限过滤条件:(班级ID必须在权限范围内) OR (是自己创建的申请单)
|
||||
lqw.and(wrapper -> {
|
||||
if (filteredDeptIds != null && !filteredDeptIds.isEmpty()) {
|
||||
wrapper.in(XgDormApplication::getClassId, filteredDeptIds);
|
||||
} else {
|
||||
// 如果用户没有任何权限,使用一个不存在的ID
|
||||
wrapper.eq(XgDormApplication::getClassId, -1L);
|
||||
}
|
||||
// OR 用户可以查看自己创建的申请单
|
||||
wrapper.or().eq(XgDormApplication::getStudentId, currentUserId);
|
||||
});
|
||||
|
||||
// 原有的查询条件
|
||||
lqw.like(StringUtils.isNotBlank(bo.getApplicationName()), XgDormApplication::getApplicationName,
|
||||
bo.getApplicationName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationType()), XgDormApplication::getApplicationType,
|
||||
bo.getApplicationType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationStatus()), XgDormApplication::getApplicationStatus,
|
||||
bo.getApplicationStatus());
|
||||
lqw.eq(bo.getStudentId() != null, XgDormApplication::getStudentId, bo.getStudentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XgDormApplication::getStudentName, bo.getStudentName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), XgDormApplication::getStudentNo, bo.getStudentNo());
|
||||
lqw.eq(bo.getClassId() != null, XgDormApplication::getClassId, bo.getClassId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgDormApplication::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getMajorId() != null, XgDormApplication::getMajorId, bo.getMajorId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgDormApplication::getMajorName, bo.getMajorName());
|
||||
lqw.eq(bo.getCollegeId() != null, XgDormApplication::getCollegeId, bo.getCollegeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgDormApplication::getCollegeName, bo.getCollegeName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeleted()), XgDormApplication::getDeleted, bo.getDeleted());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<XgDormApplication> buildQueryWrapper(XgDormApplicationBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XgDormApplication> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByDesc(XgDormApplication::getCreateTime);
|
||||
|
||||
lqw.like(StringUtils.isNotBlank(bo.getApplicationName()), XgDormApplication::getApplicationName,
|
||||
bo.getApplicationName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationType()), XgDormApplication::getApplicationType,
|
||||
bo.getApplicationType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApplicationStatus()), XgDormApplication::getApplicationStatus,
|
||||
bo.getApplicationStatus());
|
||||
lqw.eq(bo.getStudentId() != null, XgDormApplication::getStudentId, bo.getStudentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XgDormApplication::getStudentName, bo.getStudentName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), XgDormApplication::getStudentNo, bo.getStudentNo());
|
||||
lqw.eq(bo.getClassId() != null, XgDormApplication::getClassId, bo.getClassId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgDormApplication::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getMajorId() != null, XgDormApplication::getMajorId, bo.getMajorId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgDormApplication::getMajorName, bo.getMajorName());
|
||||
lqw.eq(bo.getCollegeId() != null, XgDormApplication::getCollegeId, bo.getCollegeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgDormApplication::getCollegeName, bo.getCollegeName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDeleted()), XgDormApplication::getDeleted, bo.getDeleted());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param bo 学生宿舍申请单表(调宿+退宿)
|
||||
* @return 新增成功的学生宿舍申请单表(调宿+退宿)
|
||||
*/
|
||||
@Override
|
||||
public XgDormApplicationVo insertByBo(XgDormApplicationBo bo) {
|
||||
XgDormApplication add = MapstructUtils.convert(bo, XgDormApplication.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
// 返回新增成功的记录信息
|
||||
return MapstructUtils.convert(add, XgDormApplicationVo.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生宿舍申请单表(调宿+退宿)
|
||||
*
|
||||
* @param bo 学生宿舍申请单表(调宿+退宿)
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(XgDormApplicationBo bo) {
|
||||
XgDormApplication update = MapstructUtils.convert(bo, XgDormApplication.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(XgDormApplication entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生宿舍申请单表(调宿+退宿)信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
|
||||
* 正常使用只需#processEvent.flowCode=='hzdyjs-tsts'
|
||||
*
|
||||
* @param processEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processEvent.flowCode=='hzdyjs-tsts'")
|
||||
public void processHandler(ProcessEvent processEvent) {
|
||||
log.info("当前任务执行了{}", processEvent.toString());
|
||||
XgDormApplication xgDormApplication = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
|
||||
xgDormApplication.setApplicationStatus(processEvent.getStatus());
|
||||
|
||||
// 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程
|
||||
Map<String, Object> params = processEvent.getParams();
|
||||
if (MapUtil.isNotEmpty(params)) {
|
||||
// 历史任务扩展(通常为附件)
|
||||
String hisTaskExt = Convert.toStr(params.get("hisTaskExt"));
|
||||
// 办理人
|
||||
String handler = Convert.toStr(params.get("handler"));
|
||||
// 办理意见
|
||||
String message = Convert.toStr(params.get("message"));
|
||||
}
|
||||
|
||||
if (processEvent.getSubmit()) {
|
||||
xgDormApplication.setApplicationStatus(BusinessStatusEnum.WAITING.getStatus());
|
||||
}
|
||||
|
||||
// 当审批完成时,执行调宿/退宿操作
|
||||
if ("finish".equals(processEvent.getStatus())) {
|
||||
executeApplicationOperation(xgDormApplication);
|
||||
}
|
||||
|
||||
baseMapper.updateById(xgDormApplication);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行调宿/退宿操作
|
||||
*
|
||||
* @param application 申请单
|
||||
*/
|
||||
private void executeApplicationOperation(XgDormApplication application) {
|
||||
try {
|
||||
if ("1".equals(application.getApplicationType())) {
|
||||
// 调宿申请 - 区分两种场景处理
|
||||
log.info("执行调宿操作: 学生ID={}, 目标床位ID={}", application.getStudentId(), application.getTargetBedId());
|
||||
|
||||
// 1. 根据目标床位ID查找当前占用该床位的学生ID
|
||||
Long targetStudentId = findStudentByBedId(application.getTargetBedId());
|
||||
|
||||
Boolean operationResult = false;
|
||||
|
||||
if (targetStudentId != null) {
|
||||
// 场景1:目标床位有学生 - 两个学生互换床位
|
||||
log.info("目标床位已有学生,执行床位互换: 申请学生ID={}, 目标学生ID={}",
|
||||
application.getStudentId(), targetStudentId);
|
||||
|
||||
operationResult = xgDormBedStudentService.classTeacherExchangeBeds(
|
||||
application.getStudentId(), // 源学生ID(申请人)
|
||||
targetStudentId, // 目标学生ID(目标床位当前占用者)
|
||||
application.getClassId() // 班级ID
|
||||
);
|
||||
|
||||
if (operationResult) {
|
||||
log.info("床位互换操作执行成功: 申请学生ID={}, 目标学生ID={}, 班级ID={}",
|
||||
application.getStudentId(), targetStudentId, application.getClassId());
|
||||
} else {
|
||||
log.error("床位互换操作执行失败: 申请学生ID={}, 目标学生ID={}, 班级ID={}",
|
||||
application.getStudentId(), targetStudentId, application.getClassId());
|
||||
throw new RuntimeException("床位互换操作执行失败");
|
||||
}
|
||||
|
||||
} else {
|
||||
// 场景2:目标床位为空 - 学生移动到新床位
|
||||
log.info("目标床位为空,执行床位移动: 申请学生ID={}, 目标床位ID={}",
|
||||
application.getStudentId(), application.getTargetBedId());
|
||||
|
||||
operationResult = xgDormBedStudentService.classTeacherMoveBed(
|
||||
application.getStudentId(), // 源学生ID(申请人)
|
||||
application.getTargetBedId(), // 目标床位ID
|
||||
application.getClassId() // 班级ID
|
||||
);
|
||||
|
||||
if (operationResult) {
|
||||
log.info("床位移动操作执行成功: 申请学生ID={}, 目标床位ID={}, 班级ID={}",
|
||||
application.getStudentId(), application.getTargetBedId(), application.getClassId());
|
||||
} else {
|
||||
log.error("床位移动操作执行失败: 申请学生ID={}, 目标床位ID={}, 班级ID={}",
|
||||
application.getStudentId(), application.getTargetBedId(), application.getClassId());
|
||||
throw new RuntimeException("床位移动操作执行失败");
|
||||
}
|
||||
}
|
||||
|
||||
} else if ("2".equals(application.getApplicationType())) {
|
||||
// 退宿申请 - 调用退宿接口
|
||||
log.info("执行退宿操作: 学生ID={}, 当前床位ID={}", application.getStudentId(), application.getCurrentBedId());
|
||||
|
||||
// 构建退宿参数并调用接口
|
||||
List<Long> bedIds = List.of(application.getCurrentBedId());
|
||||
Boolean stayawayResult = xgDormBedStudentService.classTeacherStayawaySelectedBeds(
|
||||
bedIds, // 床位ID列表
|
||||
application.getClassId() // 班级ID
|
||||
);
|
||||
|
||||
if (stayawayResult) {
|
||||
log.info("退宿操作执行成功: 学生ID={}, 床位ID={}, 班级ID={}",
|
||||
application.getStudentId(), application.getCurrentBedId(), application.getClassId());
|
||||
} else {
|
||||
log.error("退宿操作执行失败: 学生ID={}, 床位ID={}, 班级ID={}",
|
||||
application.getStudentId(), application.getCurrentBedId(), application.getClassId());
|
||||
throw new RuntimeException("退宿操作执行失败");
|
||||
}
|
||||
} else {
|
||||
log.error("未知的申请类型: {}", application.getApplicationType());
|
||||
throw new RuntimeException("未知的申请类型: " + application.getApplicationType());
|
||||
}
|
||||
|
||||
log.info("宿舍申请操作执行成功,申请ID: {}", application.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("宿舍申请操作执行失败,申请ID: {}, 错误信息: {}", application.getId(), e.getMessage(), e);
|
||||
// 抛出异常,让调用方处理
|
||||
throw new RuntimeException("宿舍申请操作执行失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据床位ID查找当前占用该床位的学生ID
|
||||
*
|
||||
* @param bedId 床位ID
|
||||
* @return 学生ID,如果没有找到则返回null
|
||||
*/
|
||||
private Long findStudentByBedId(Long bedId) {
|
||||
if (bedId == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
LambdaQueryWrapper<XgDormBedStudent> queryWrapper = Wrappers.lambdaQuery();
|
||||
queryWrapper.eq(XgDormBedStudent::getBedId, bedId)
|
||||
.eq(XgDormBedStudent::getStatus, "0") // 0-正常状态
|
||||
.eq(XgDormBedStudent::getDeleted, 0L); // 未删除
|
||||
|
||||
XgDormBedStudent bedStudent = xgDormBedStudentMapper.selectOne(queryWrapper);
|
||||
if (bedStudent != null) {
|
||||
log.info("根据床位ID: {} 找到学生ID: {}", bedId, bedStudent.getStudentId());
|
||||
return bedStudent.getStudentId();
|
||||
} else {
|
||||
log.warn("床位ID: {} 没有找到对应的学生", bedId);
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("根据床位ID: {} 查找学生失败: {}", bedId, e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行任务创建监听
|
||||
* 示例:也可通过 @EventListener(condition =
|
||||
* "#processTaskEvent.flowCode=='hzdyjs-tsts'")进行判断
|
||||
* 在方法中判断流程节点key
|
||||
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
|
||||
* //执行业务逻辑
|
||||
* }
|
||||
*
|
||||
* @param processTaskEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processTaskEvent.flowCode=='hzdyjs-tsts'")
|
||||
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
|
||||
log.info("当前任务创建了{}", processTaskEvent.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听删除流程事件
|
||||
* 正常使用只需#processDeleteEvent.flowCode=='hzdyjs-tsts'
|
||||
*
|
||||
* @param processDeleteEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processDeleteEvent.flowCode=='hzdyjs-tsts'")
|
||||
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
|
||||
log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString());
|
||||
XgDormApplication xgDormApplication = baseMapper.selectById(Long.valueOf(processDeleteEvent.getBusinessId()));
|
||||
if (ObjectUtil.isNull(xgDormApplication)) {
|
||||
return;
|
||||
}
|
||||
baseMapper.deleteById(xgDormApplication.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生选择器选项列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生选择器选项分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StudentOptionVo> getStudentOptions(StudentOptionBo bo, PageQuery pageQuery) {
|
||||
Page<StudentOptionVo> result = baseMapper.selectStudentOptions(pageQuery.build(), bo);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二级学院审批人列表
|
||||
*
|
||||
* @param collegeId 学院ID
|
||||
* @return 审批人列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getCollegeApprovers(Long collegeId) {
|
||||
try {
|
||||
// 查询角色key为'ejxyssgly'的角色ID
|
||||
LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
|
||||
roleWrapper.eq(SysRole::getRoleKey, "ejxyssgly");
|
||||
SysRole role = sysRoleMapper.selectOne(roleWrapper);
|
||||
|
||||
if (role == null) {
|
||||
log.warn("未找到角色key为'ejxyssgly'的角色");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 通过角色ID查询用户角色关系表
|
||||
LambdaQueryWrapper<org.dromara.system.domain.SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
|
||||
userRoleWrapper.eq(org.dromara.system.domain.SysUserRole::getRoleId, role.getRoleId());
|
||||
List<org.dromara.system.domain.SysUserRole> userRoles = sysUserRoleMapper.selectList(userRoleWrapper);
|
||||
|
||||
if (userRoles.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 获取用户ID列表
|
||||
List<Long> userIds = userRoles.stream()
|
||||
.map(org.dromara.system.domain.SysUserRole::getUserId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 查询用户信息,过滤指定学院的用户
|
||||
LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
|
||||
userWrapper.in(SysUser::getUserId, userIds)
|
||||
.eq(SysUser::getDeptId, collegeId)
|
||||
.eq(SysUser::getStatus, "0"); // 只查询启用状态的用户
|
||||
List<SysUser> users = sysUserMapper.selectList(userWrapper);
|
||||
|
||||
// 转换为Map格式返回
|
||||
return users.stream().map(user -> {
|
||||
Map<String, Object> approver = MapUtil.newHashMap();
|
||||
approver.put("userId", user.getUserId());
|
||||
approver.put("userName", user.getUserName());
|
||||
approver.put("nickName", user.getNickName());
|
||||
approver.put("deptId", user.getDeptId());
|
||||
return approver;
|
||||
}).collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
log.error("获取二级学院审批人列表失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学工处审批人列表
|
||||
*
|
||||
* @return 审批人列表
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> getStudentAffairsApprovers() {
|
||||
try {
|
||||
// 查询角色key为'xscxsxxgly'的角色ID
|
||||
LambdaQueryWrapper<SysRole> roleWrapper = new LambdaQueryWrapper<>();
|
||||
roleWrapper.eq(SysRole::getRoleKey, "xscxsxxgly");
|
||||
SysRole role = sysRoleMapper.selectOne(roleWrapper);
|
||||
|
||||
if (role == null) {
|
||||
log.warn("未找到角色key为'xscxsxxgly'的角色");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 通过角色ID查询用户角色关系表
|
||||
LambdaQueryWrapper<org.dromara.system.domain.SysUserRole> userRoleWrapper = new LambdaQueryWrapper<>();
|
||||
userRoleWrapper.eq(org.dromara.system.domain.SysUserRole::getRoleId, role.getRoleId());
|
||||
List<org.dromara.system.domain.SysUserRole> userRoles = sysUserRoleMapper.selectList(userRoleWrapper);
|
||||
|
||||
if (userRoles.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 获取用户ID列表
|
||||
List<Long> userIds = userRoles.stream()
|
||||
.map(org.dromara.system.domain.SysUserRole::getUserId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 查询用户信息
|
||||
LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
|
||||
userWrapper.in(SysUser::getUserId, userIds)
|
||||
.eq(SysUser::getStatus, "0"); // 只查询启用状态的用户
|
||||
List<SysUser> users = sysUserMapper.selectList(userWrapper);
|
||||
|
||||
// 转换为Map格式返回
|
||||
return users.stream().map(user -> {
|
||||
Map<String, Object> approver = MapUtil.newHashMap();
|
||||
approver.put("userId", user.getUserId());
|
||||
approver.put("userName", user.getUserName());
|
||||
approver.put("nickName", user.getNickName());
|
||||
approver.put("deptId", user.getDeptId());
|
||||
return approver;
|
||||
}).collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
log.error("获取学工处审批人列表失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+127
@@ -2500,4 +2500,131 @@ public class XgDormBedStudentServiceImpl implements IXgDormBedStudentService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据学生ID获取当前宿舍信息
|
||||
* 包含校区、宿舍楼、房间号、床位号等信息
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 当前宿舍信息
|
||||
*/
|
||||
@Override
|
||||
public Object getCurrentDormInfo(Long studentId) {
|
||||
try {
|
||||
log.info("开始获取学生当前宿舍信息,学生ID: {}", studentId);
|
||||
|
||||
if (studentId == null) {
|
||||
log.warn("学生ID为空,无法获取宿舍信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用SQL关联查询,获取学生当前宿舍信息
|
||||
Map<String, Object> dormInfo = baseMapper.selectCurrentDormInfo(studentId);
|
||||
|
||||
if (dormInfo == null || dormInfo.isEmpty()) {
|
||||
log.warn("学生ID: {} 未找到宿舍分配信息", studentId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 组装返回结果
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
|
||||
// 校区信息
|
||||
result.put("campusId", dormInfo.get("campus_id"));
|
||||
result.put("campusName", dormInfo.get("campus_name"));
|
||||
|
||||
// 宿舍区信息
|
||||
result.put("areaId", dormInfo.get("area_id"));
|
||||
result.put("areaName", dormInfo.get("area_name"));
|
||||
|
||||
// 楼栋信息
|
||||
result.put("buildingId", dormInfo.get("building_id"));
|
||||
result.put("buildingName", dormInfo.get("building_name"));
|
||||
result.put("buildingCode", dormInfo.get("building_code"));
|
||||
|
||||
// 房间信息
|
||||
result.put("roomId", dormInfo.get("room_id"));
|
||||
result.put("roomName", dormInfo.get("room_name"));
|
||||
result.put("roomNo", dormInfo.get("room_no"));
|
||||
result.put("roomNumber", dormInfo.get("room_no")); // 兼容字段
|
||||
|
||||
// 床位信息
|
||||
result.put("bedId", dormInfo.get("bed_id"));
|
||||
result.put("bedName", dormInfo.get("bed_name"));
|
||||
result.put("bedNo", dormInfo.get("bed_no"));
|
||||
result.put("bedNumber", dormInfo.get("bed_no")); // 兼容字段
|
||||
|
||||
log.info("获取学生当前宿舍信息成功,学生ID: {}, 宿舍信息: {}校区-{}楼-{}房间-{}床位",
|
||||
studentId,
|
||||
result.get("campusName"),
|
||||
result.get("buildingName"),
|
||||
result.get("roomNo"),
|
||||
result.get("bedNo"));
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取学生当前宿舍信息失败,学生ID: {}", studentId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据床位ID获取该床位的学生信息
|
||||
* 包含学生基本信息、学院、专业、班级等信息
|
||||
*
|
||||
* @param bedId 床位ID
|
||||
* @return 床位学生信息
|
||||
*/
|
||||
@Override
|
||||
public Object getBedStudentInfo(Long bedId) {
|
||||
try {
|
||||
log.info("开始获取床位学生信息,床位ID: {}", bedId);
|
||||
|
||||
if (bedId == null) {
|
||||
log.warn("床位ID为空,无法获取学生信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用SQL关联查询,获取床位学生信息
|
||||
Map<String, Object> studentInfo = baseMapper.selectBedStudentInfo(bedId);
|
||||
|
||||
if (studentInfo == null || studentInfo.isEmpty()) {
|
||||
log.warn("床位ID: {} 未找到学生信息", bedId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 组装返回结果
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
|
||||
// 学生基本信息
|
||||
result.put("studentId", studentInfo.get("student_id"));
|
||||
result.put("studentNo", studentInfo.get("student_no"));
|
||||
result.put("studentName", studentInfo.get("student_name"));
|
||||
result.put("gender", studentInfo.get("gender"));
|
||||
result.put("phone", studentInfo.get("phone"));
|
||||
|
||||
// 学院、专业、班级信息
|
||||
result.put("collegeName", studentInfo.get("college_name"));
|
||||
result.put("majorName", studentInfo.get("major_name"));
|
||||
result.put("className", studentInfo.get("class_name"));
|
||||
|
||||
// 床位信息
|
||||
result.put("bedId", studentInfo.get("bed_id"));
|
||||
|
||||
log.info("获取床位学生信息成功,床位ID: {}, 学生信息: {}({})-{}-{}-{}",
|
||||
bedId,
|
||||
result.get("studentName"),
|
||||
result.get("studentNo"),
|
||||
result.get("collegeName"),
|
||||
result.get("majorName"),
|
||||
result.get("className"));
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取床位学生信息失败,床位ID: {}", bedId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+85
-49
@@ -6,6 +6,7 @@ import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationAppointmentBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationAppointmentVo;
|
||||
import org.dromara.xljk.domain.vo.TimeSlotDetailVo;
|
||||
import org.dromara.xljk.domain.vo.ScheduleWithStatusVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationAppointmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@@ -161,52 +162,10 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
|
||||
// 从请求体中获取参数
|
||||
String status = requestBody.get("status").toString();
|
||||
Date actualVisitTime = null;
|
||||
Integer communicationDuration = null;
|
||||
String consultationContent = "";
|
||||
String counselorSuggestion = "";
|
||||
|
||||
// 处理actualVisitTime
|
||||
if (requestBody.get("actualVisitTime") != null) {
|
||||
try {
|
||||
String actualVisitTimeStr = requestBody.get("actualVisitTime").toString();
|
||||
log.info("解析实际到访时间字符串: {}", actualVisitTimeStr);
|
||||
|
||||
// 尝试多种日期格式
|
||||
SimpleDateFormat[] dateFormats = {
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy-MM-dd")
|
||||
};
|
||||
|
||||
boolean parsed = false;
|
||||
for (SimpleDateFormat sdf : dateFormats) {
|
||||
try {
|
||||
actualVisitTime = sdf.parse(actualVisitTimeStr);
|
||||
parsed = true;
|
||||
log.info("成功解析实际到访时间: {}, 使用格式: {}", actualVisitTime, sdf.toPattern());
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
// 继续尝试下一个格式
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
log.error("无法解析实际到访时间: {}", actualVisitTimeStr);
|
||||
// 使用当前时间作为默认值
|
||||
actualVisitTime = new Date();
|
||||
log.info("使用当前时间作为默认值: {}", actualVisitTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析actualVisitTime失败", e);
|
||||
// 使用当前时间作为默认值
|
||||
actualVisitTime = new Date();
|
||||
log.info("使用当前时间作为默认值: {}", actualVisitTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理communicationDuration
|
||||
if (requestBody.get("communicationDuration") != null) {
|
||||
try {
|
||||
@@ -227,8 +186,47 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
counselorSuggestion = requestBody.get("counselorSuggestion").toString();
|
||||
}
|
||||
|
||||
boolean result = service.recordConsultation(id, actualVisitTime, communicationDuration,
|
||||
consultationContent, counselorSuggestion, status);
|
||||
// 处理心理病史相关字段
|
||||
Integer psychologicalHistory = null;
|
||||
String psychologicalHistoryDetail = "";
|
||||
String basicSituation = "";
|
||||
String majorLifeEvents = "";
|
||||
Integer needReferral = null;
|
||||
|
||||
if (requestBody.get("psychologicalHistory") != null) {
|
||||
try {
|
||||
psychologicalHistory = Integer.parseInt(requestBody.get("psychologicalHistory").toString());
|
||||
} catch (Exception e) {
|
||||
log.error("解析psychologicalHistory失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestBody.get("psychologicalHistoryDetail") != null) {
|
||||
psychologicalHistoryDetail = requestBody.get("psychologicalHistoryDetail").toString();
|
||||
}
|
||||
|
||||
if (requestBody.get("basicSituation") != null) {
|
||||
basicSituation = requestBody.get("basicSituation").toString();
|
||||
}
|
||||
|
||||
if (requestBody.get("majorLifeEvents") != null) {
|
||||
majorLifeEvents = requestBody.get("majorLifeEvents").toString();
|
||||
}
|
||||
|
||||
if (requestBody.get("needReferral") != null) {
|
||||
try {
|
||||
needReferral = Integer.parseInt(requestBody.get("needReferral").toString());
|
||||
} catch (Exception e) {
|
||||
log.error("解析needReferral失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("解析的心理病史相关字段: psychologicalHistory={}, psychologicalHistoryDetail={}, basicSituation={}, majorLifeEvents={}, needReferral={}",
|
||||
psychologicalHistory, psychologicalHistoryDetail, basicSituation, majorLifeEvents, needReferral);
|
||||
|
||||
boolean result = service.recordConsultation(id, communicationDuration,
|
||||
consultationContent, counselorSuggestion, status,
|
||||
psychologicalHistory, psychologicalHistoryDetail, basicSituation, majorLifeEvents, needReferral);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
@@ -284,7 +282,7 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
XSSFSheet sheet = workbook.createSheet("预约记录");
|
||||
|
||||
// 表头
|
||||
String[] headers = {"序号", "学生姓名", "学号", "院系", "专业", "班级", "咨询原因", "咨询师", "预约日期", "预约时段", "状态", "咨询结果", "实际到访时间", "沟通时长", "咨询内容", "咨询师建议"};
|
||||
String[] headers = {"序号", "学生姓名", "学号", "院系", "专业", "班级", "咨询主题", "咨询原因", "咨询师", "预约日期", "预约时段", "状态", "咨询结果", "沟通时长", "心理病史", "心理病史详情", "基本情况", "重大生活事件", "本次咨询过程", "是否需要转介", "本学期到访次数"};
|
||||
XSSFRow headerRow = sheet.createRow(0);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
headerRow.createCell(i).setCellValue(headers[i]);
|
||||
@@ -303,6 +301,7 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
row.createCell(col++).setCellValue(vo.getCollegeName());
|
||||
row.createCell(col++).setCellValue(vo.getMajorName());
|
||||
row.createCell(col++).setCellValue(vo.getClassName());
|
||||
row.createCell(col++).setCellValue(vo.getConsultTheme() != null ? vo.getConsultTheme() : ""); // 咨询主题
|
||||
row.createCell(col++).setCellValue(vo.getReason());
|
||||
row.createCell(col++).setCellValue(vo.getCounselorName());
|
||||
row.createCell(col++).setCellValue(vo.getAppointmentDate() != null ? dateFormat.format(vo.getAppointmentDate()) : "");
|
||||
@@ -315,15 +314,43 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
case 1: status = "已到访"; break;
|
||||
case 2: status = "已取消"; break;
|
||||
case 3: status = "未到访"; break;
|
||||
case 4: status = "待审核"; break;
|
||||
case 5: status = "已驳回"; break;
|
||||
default: status = "未知状态";
|
||||
}
|
||||
}
|
||||
row.createCell(col++).setCellValue(status);
|
||||
row.createCell(col++).setCellValue(status); // 咨询结果
|
||||
row.createCell(col++).setCellValue(vo.getActualVisitTime() != null ? dateTimeFormat.format(vo.getActualVisitTime()) : "");
|
||||
row.createCell(col++).setCellValue(vo.getCommunicationDuration() != null ? vo.getCommunicationDuration().toString() : "");
|
||||
row.createCell(col++).setCellValue(vo.getConsultationContent());
|
||||
row.createCell(col++).setCellValue(vo.getCounselorSuggestion());
|
||||
row.createCell(col++).setCellValue(vo.getCommunicationDuration() != null ? vo.getCommunicationDuration().toString() + "分钟" : "");
|
||||
|
||||
// 心理病史
|
||||
String psychologicalHistory = "";
|
||||
if (vo.getPsychologicalHistory() != null) {
|
||||
psychologicalHistory = vo.getPsychologicalHistory() == 2 ? "是" : "否";
|
||||
}
|
||||
row.createCell(col++).setCellValue(psychologicalHistory);
|
||||
|
||||
// 心理病史详情
|
||||
row.createCell(col++).setCellValue(vo.getPsychologicalHistoryDetail() != null ? vo.getPsychologicalHistoryDetail() : "");
|
||||
|
||||
// 基本情况
|
||||
row.createCell(col++).setCellValue(vo.getBasicSituation() != null ? vo.getBasicSituation() : "");
|
||||
|
||||
// 重大生活事件
|
||||
row.createCell(col++).setCellValue(vo.getMajorLifeEvents() != null ? vo.getMajorLifeEvents() : "");
|
||||
|
||||
// 本次咨询过程(原咨询内容)
|
||||
row.createCell(col++).setCellValue(vo.getConsultationContent() != null ? vo.getConsultationContent() : "");
|
||||
|
||||
// 是否需要转介
|
||||
String needReferral = "";
|
||||
if (vo.getNeedReferral() != null) {
|
||||
needReferral = vo.getNeedReferral() == 2 ? "是" : "否";
|
||||
}
|
||||
row.createCell(col++).setCellValue(needReferral);
|
||||
|
||||
// 本学期到访次数
|
||||
row.createCell(col++).setCellValue(vo.getSemesterVisitCount() != null ? vo.getSemesterVisitCount().toString() + "次" : "0次");
|
||||
}
|
||||
|
||||
// 写入字节流
|
||||
@@ -350,6 +377,15 @@ public class XljkConsultationAppointmentController extends BaseController {
|
||||
.body(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日历视图的排班数据(带预约状态)
|
||||
*/
|
||||
@GetMapping("/calendar-schedules")
|
||||
public R<List<ScheduleWithStatusVo>> getCalendarSchedules(@RequestParam String startDate, @RequestParam String endDate) {
|
||||
List<ScheduleWithStatusVo> schedules = service.getCalendarSchedules(startDate, endDate);
|
||||
return R.ok(schedules);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义CSV字段中的特殊字符
|
||||
*/
|
||||
|
||||
+46
-3
@@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleSummaryVo;
|
||||
|
||||
@RestController
|
||||
@@ -57,10 +58,14 @@ public class XljkConsultationScheduleController {
|
||||
batchBo.setCounselorId(Long.valueOf(requestMap.get("counselorId").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("office")) {
|
||||
batchBo.setOffice(requestMap.get("office").toString());
|
||||
}
|
||||
|
||||
batchBo.setStartDate(requestMap.get("startDate").toString());
|
||||
batchBo.setEndDate(requestMap.get("endDate").toString());
|
||||
|
||||
// 设置上午时段
|
||||
// 设置中午时段(字段名保持morning以兼容前端)
|
||||
if (requestMap.containsKey("morningEnabled")) {
|
||||
batchBo.setMorningEnabled(Boolean.valueOf(requestMap.get("morningEnabled").toString()));
|
||||
}
|
||||
@@ -73,6 +78,26 @@ public class XljkConsultationScheduleController {
|
||||
batchBo.setMorningEndTime(requestMap.get("morningEndTime").toString());
|
||||
}
|
||||
|
||||
// 设置中午时段(新版本)
|
||||
if (requestMap.containsKey("noonEnabled")) {
|
||||
batchBo.setNoonEnabled(Boolean.valueOf(requestMap.get("noonEnabled").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("noonTimeSlots")) {
|
||||
List<Map<String, Object>> noonSlots = (List<Map<String, Object>>) requestMap.get("noonTimeSlots");
|
||||
if (noonSlots != null) {
|
||||
List<XljkConsultationScheduleBatchBo.TimeSlot> timeSlots = noonSlots.stream()
|
||||
.map(slot -> {
|
||||
XljkConsultationScheduleBatchBo.TimeSlot timeSlot = new XljkConsultationScheduleBatchBo.TimeSlot();
|
||||
timeSlot.setStartTime(slot.get("startTime").toString());
|
||||
timeSlot.setEndTime(slot.get("endTime").toString());
|
||||
return timeSlot;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
batchBo.setNoonTimeSlots(timeSlots);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置下午时段
|
||||
if (requestMap.containsKey("afternoonEnabled")) {
|
||||
batchBo.setAfternoonEnabled(Boolean.valueOf(requestMap.get("afternoonEnabled").toString()));
|
||||
@@ -86,6 +111,21 @@ public class XljkConsultationScheduleController {
|
||||
batchBo.setAfternoonEndTime(requestMap.get("afternoonEndTime").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("afternoonTimeSlots")) {
|
||||
List<Map<String, Object>> afternoonSlots = (List<Map<String, Object>>) requestMap.get("afternoonTimeSlots");
|
||||
if (afternoonSlots != null) {
|
||||
List<XljkConsultationScheduleBatchBo.TimeSlot> timeSlots = afternoonSlots.stream()
|
||||
.map(slot -> {
|
||||
XljkConsultationScheduleBatchBo.TimeSlot timeSlot = new XljkConsultationScheduleBatchBo.TimeSlot();
|
||||
timeSlot.setStartTime(slot.get("startTime").toString());
|
||||
timeSlot.setEndTime(slot.get("endTime").toString());
|
||||
return timeSlot;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
batchBo.setAfternoonTimeSlots(timeSlots);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置其他字段
|
||||
if (requestMap.containsKey("status")) {
|
||||
batchBo.setStatus(requestMap.get("status").toString());
|
||||
@@ -166,10 +206,13 @@ public class XljkConsultationScheduleController {
|
||||
*/
|
||||
@GetMapping("/options/counselors")
|
||||
public R<List<Map<String, Object>>> getCounselorOptions() {
|
||||
String sql = "SELECT u.user_id as id, u.nick_name as name FROM sys_user u " +
|
||||
String sql = "SELECT u.user_id as id, u.nick_name as name, c.office as office " +
|
||||
"FROM sys_user u " +
|
||||
"JOIN sys_user_role ur ON u.user_id = ur.user_id " +
|
||||
"JOIN sys_role r ON ur.role_id = r.role_id " +
|
||||
"WHERE r.role_key = 'xljk_consultant' AND u.del_flag = '0'";
|
||||
"LEFT JOIN xljk_consulter c ON u.user_id = c.user_id AND c.deleted = 0 " +
|
||||
"WHERE r.role_key = 'xljk_consultant' AND u.del_flag = '0' " +
|
||||
"ORDER BY u.nick_name";
|
||||
|
||||
List<Map<String, Object>> counselorOptions = jdbcTemplate.queryForList(sql);
|
||||
return R.ok(counselorOptions);
|
||||
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.xljk.domain.vo.XljkConsulterVo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsulterBo;
|
||||
import org.dromara.xljk.service.IXljkConsulterService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/xljk/consulter")
|
||||
public class XljkConsulterController extends BaseController {
|
||||
|
||||
private final IXljkConsulterService xljkConsulterService;
|
||||
private final ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XljkConsulterVo> list(XljkConsulterBo bo, PageQuery pageQuery) {
|
||||
return xljkConsulterService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出心理咨询师配置列表
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:export")
|
||||
@Log(title = "心理咨询师配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(XljkConsulterBo bo, HttpServletResponse response) {
|
||||
List<XljkConsulterVo> list = xljkConsulterService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "心理咨询师配置", XljkConsulterVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取心理咨询师配置详细信息
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XljkConsulterVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(xljkConsulterService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增心理咨询师配置
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:add")
|
||||
@Log(title = "心理咨询师配置", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody XljkConsulterBo bo) {
|
||||
return toAjax(xljkConsulterService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改心理咨询师配置
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:edit")
|
||||
@Log(title = "心理咨询师配置", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XljkConsulterBo bo) {
|
||||
return toAjax(xljkConsulterService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除心理咨询师配置
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:remove")
|
||||
@Log(title = "心理咨询师配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(xljkConsulterService.deleteWithValidByIds(List.of(ids)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加咨询师
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:add")
|
||||
@Log(title = "批量添加咨询师", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping("/batchAdd")
|
||||
public R<Void> batchAdd(@RequestBody BatchAddRequest request) {
|
||||
return toAjax(xljkConsulterService.batchAddConsulters(request.getUserIds(), request.getRemark()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我配置的咨询师列表
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:list")
|
||||
@GetMapping("/myConfig")
|
||||
public TableDataInfo<XljkConsulterVo> myConfigList(XljkConsulterBo bo, PageQuery pageQuery) {
|
||||
return xljkConsulterService.queryMyConfigList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量启用咨询师
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:edit")
|
||||
@Log(title = "启用咨询师", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/enable")
|
||||
public R<Void> enable(@RequestBody List<Long> ids) {
|
||||
return toAjax(xljkConsulterService.enableConsulters(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量停用咨询师
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:edit")
|
||||
@Log(title = "停用咨询师", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/disable")
|
||||
public R<Void> disable(@RequestBody List<Long> ids) {
|
||||
return toAjax(xljkConsulterService.disableConsulters(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID获取用户列表
|
||||
*/
|
||||
@SaCheckPermission("xljk:consulter:list")
|
||||
@GetMapping("/users/{deptId}")
|
||||
public R<List<SysUserVo>> listUserByDeptId(@PathVariable String deptId) {
|
||||
List<SysUserVo> users = sysUserService.selectUserListByDept(Long.valueOf(deptId));
|
||||
return R.ok(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加请求对象
|
||||
*/
|
||||
public static class BatchAddRequest {
|
||||
private List<Long> userIds;
|
||||
private String remark;
|
||||
|
||||
public List<Long> getUserIds() {
|
||||
return userIds;
|
||||
}
|
||||
|
||||
public void setUserIds(List<Long> userIds) {
|
||||
this.userIds = userIds;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+13
-1
@@ -3,6 +3,7 @@ package org.dromara.xljk.domain;
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationAppointment implements Serializable {
|
||||
@@ -21,9 +22,20 @@ public class XljkConsultationAppointment implements Serializable {
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
|
||||
@TableField("consult_theme")
|
||||
private String consultTheme; // 咨询主题
|
||||
|
||||
private String status;
|
||||
private Date actualVisitTime;
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
|
||||
// 新增心理健康相关字段
|
||||
private String studentName; // 学生姓名(冗余字段)
|
||||
private Integer psychologicalHistory; // 心理病史(1-否,2-是)
|
||||
private String psychologicalHistoryDetail; // 心理病史详情
|
||||
private String basicSituation; // 基本情况
|
||||
private String majorLifeEvents; // 重大生活事件
|
||||
private Integer needReferral; // 是否需要转介(1-不需要,2-需要)
|
||||
}
|
||||
+2
-1
@@ -15,8 +15,9 @@ public class XljkConsultationSchedule implements Serializable {
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String office; // 办公室
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String timeSlot; // 0中午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status; // 0正常 1停用
|
||||
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置对象 xljk_consulter
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xljk_consulter")
|
||||
public class XljkConsulter extends TenantEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 办公室
|
||||
*/
|
||||
private String office;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 心理咨询用户和部门完整信息
|
||||
* 用于批量添加咨询师时获取完整的用户数据
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Data
|
||||
public class XljkUserWithDeptInfo {
|
||||
|
||||
/** 用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** 用户账号 */
|
||||
private String userName;
|
||||
|
||||
/** 用户昵称 */
|
||||
private String nickName;
|
||||
|
||||
/** 部门ID */
|
||||
private Long deptId;
|
||||
|
||||
/** 部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/** 手机号码 */
|
||||
private String phonenumber;
|
||||
|
||||
/** 用户邮箱 */
|
||||
private String email;
|
||||
|
||||
/** 帐号状态(1正常 0停用) */
|
||||
private String status;
|
||||
|
||||
}
|
||||
+8
-1
@@ -22,12 +22,19 @@ public class XljkConsultationAppointmentBo {
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
private String consultTheme; // 咨询主题
|
||||
private String status;
|
||||
private Date actualVisitTime;
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
|
||||
// 新增心理健康相关字段
|
||||
private Integer psychologicalHistory; // 心理病史(1-否,2-是)
|
||||
private String psychologicalHistoryDetail; // 心理病史详情
|
||||
private String basicSituation; // 基本情况
|
||||
private String majorLifeEvents; // 重大生活事件
|
||||
private Integer needReferral; // 是否需要转介(1-不需要,2-需要)
|
||||
|
||||
// 查询参数字段
|
||||
private String studentName;
|
||||
private String studentNo;
|
||||
|
||||
+35
-5
@@ -2,6 +2,7 @@ package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批量创建预约时段的业务对象
|
||||
@@ -13,6 +14,11 @@ public class XljkConsultationScheduleBatchBo {
|
||||
*/
|
||||
private Long counselorId;
|
||||
|
||||
/**
|
||||
* 办公室
|
||||
*/
|
||||
private String office;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
@@ -24,35 +30,50 @@ public class XljkConsultationScheduleBatchBo {
|
||||
private String endDate;
|
||||
|
||||
/**
|
||||
* 是否启用上午时段
|
||||
* 是否启用中午时段(字段名保持morningEnabled以兼容前端)
|
||||
*/
|
||||
private Boolean morningEnabled;
|
||||
|
||||
/**
|
||||
* 上午开始时间 (HH:mm)
|
||||
* 中午开始时间 (HH:mm)(字段名保持morningStartTime以兼容前端)
|
||||
*/
|
||||
private String morningStartTime;
|
||||
|
||||
/**
|
||||
* 上午结束时间 (HH:mm)
|
||||
* 中午结束时间 (HH:mm)(字段名保持morningEndTime以兼容前端)
|
||||
*/
|
||||
private String morningEndTime;
|
||||
|
||||
/**
|
||||
* 是否启用中午时段
|
||||
*/
|
||||
private Boolean noonEnabled;
|
||||
|
||||
/**
|
||||
* 中午时段列表
|
||||
*/
|
||||
private List<TimeSlot> noonTimeSlots;
|
||||
|
||||
/**
|
||||
* 是否启用下午时段
|
||||
*/
|
||||
private Boolean afternoonEnabled;
|
||||
|
||||
/**
|
||||
* 下午开始时间 (HH:mm)
|
||||
* 下午开始时间 (HH:mm)(兼容旧版本)
|
||||
*/
|
||||
private String afternoonStartTime;
|
||||
|
||||
/**
|
||||
* 下午结束时间 (HH:mm)
|
||||
* 下午结束时间 (HH:mm)(兼容旧版本)
|
||||
*/
|
||||
private String afternoonEndTime;
|
||||
|
||||
/**
|
||||
* 下午时段列表
|
||||
*/
|
||||
private List<TimeSlot> afternoonTimeSlots;
|
||||
|
||||
/**
|
||||
* 状态 (0正常 1停用)
|
||||
*/
|
||||
@@ -67,4 +88,13 @@ public class XljkConsultationScheduleBatchBo {
|
||||
* 批次ID,用于标识同一批次创建的预约时段
|
||||
*/
|
||||
private String batchId;
|
||||
|
||||
/**
|
||||
* 时段内部类
|
||||
*/
|
||||
@Data
|
||||
public static class TimeSlot {
|
||||
private String startTime;
|
||||
private String endTime;
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -14,8 +14,9 @@ public class XljkConsultationScheduleBo {
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String office; // 办公室
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String timeSlot; // 0中午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status;
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.xljk.domain.XljkConsulter;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置业务对象 xljk_consulter
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XljkConsulter.class, reverseConvertGenerate = false)
|
||||
public class XljkConsulterBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@NotBlank(message = "用户姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@NotBlank(message = "用户昵称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@NotNull(message = "部门ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@NotBlank(message = "部门名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 办公室
|
||||
*/
|
||||
private String office;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
@NotBlank(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 搜索值
|
||||
*/
|
||||
private String searchValue;
|
||||
|
||||
/**
|
||||
* 创建时间范围
|
||||
*/
|
||||
private List<Date> createTimeRange;
|
||||
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 带预约状态的排班数据视图对象
|
||||
*/
|
||||
@Data
|
||||
public class ScheduleWithStatusVo {
|
||||
|
||||
/**
|
||||
* 排班ID
|
||||
*/
|
||||
private Long scheduleId;
|
||||
|
||||
/**
|
||||
* 咨询师ID
|
||||
*/
|
||||
private Long counselorId;
|
||||
|
||||
/**
|
||||
* 咨询师姓名
|
||||
*/
|
||||
private String counselorName;
|
||||
|
||||
/**
|
||||
* 排班日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private String date;
|
||||
|
||||
/**
|
||||
* 时段类型(0中午 1下午 2晚上)
|
||||
*/
|
||||
private String timeSlot;
|
||||
|
||||
/**
|
||||
* 开始时间(HH:mm)
|
||||
*/
|
||||
private String startTime;
|
||||
|
||||
/**
|
||||
* 结束时间(HH:mm)
|
||||
*/
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 时段显示文本(如:中午 08:30-12:00)
|
||||
*/
|
||||
private String timeDisplay;
|
||||
|
||||
/**
|
||||
* 是否已预约满
|
||||
*/
|
||||
private Boolean isFullyBooked;
|
||||
|
||||
/**
|
||||
* 是否已过期
|
||||
*/
|
||||
private Boolean isExpired;
|
||||
|
||||
/**
|
||||
* 可预约数量
|
||||
*/
|
||||
private Integer availableSlots;
|
||||
|
||||
/**
|
||||
* 总预约数量
|
||||
*/
|
||||
private Integer totalSlots;
|
||||
|
||||
// 以下是基础字段,用于避免MyBatis映射错误
|
||||
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; // 更新时间
|
||||
}
|
||||
+11
-3
@@ -30,14 +30,12 @@ public class XljkConsultationAppointmentVo {
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
private String consultTheme; // 咨询主题
|
||||
/**
|
||||
* 状态(0待咨询 1已完成 2已取消 3未到访)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualVisitTime;
|
||||
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
@@ -51,4 +49,14 @@ public class XljkConsultationAppointmentVo {
|
||||
// 新增院系和专业字段
|
||||
private String collegeName; // 院系名称
|
||||
private String majorName; // 专业名称
|
||||
|
||||
// 新增心理健康相关字段
|
||||
private Integer psychologicalHistory; // 心理病史(1-否,2-是)
|
||||
private String psychologicalHistoryDetail; // 心理病史详情
|
||||
private String basicSituation; // 基本情况
|
||||
private String majorLifeEvents; // 重大生活事件
|
||||
private Integer needReferral; // 是否需要转介(1-不需要,2-需要)
|
||||
|
||||
// 本学期到访次数(计算字段,不存储在数据库)
|
||||
private Integer semesterVisitCount;
|
||||
}
|
||||
+3
-2
@@ -18,11 +18,12 @@ public class XljkConsultationScheduleSummaryVo {
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String counselorName; // 咨询师姓名,用于前端显示
|
||||
private String office; // 办公室,用于前端显示
|
||||
|
||||
// 汇总信息
|
||||
private String dateRange; // 日期范围,如"2025-07-01 至 2025-07-10"
|
||||
private Boolean morningEnabled; // 是否启用上午时段
|
||||
private String morningTime; // 上午时间,如"08:30-12:00"
|
||||
private Boolean morningEnabled; // 是否启用中午时段(字段名保持不变以兼容前端)
|
||||
private String morningTime; // 中午时间,如"08:30-12:00"
|
||||
private Boolean afternoonEnabled; // 是否启用下午时段
|
||||
private String afternoonTime; // 下午时间,如"14:30-17:00"
|
||||
private String status; // 状态
|
||||
|
||||
+2
-1
@@ -15,8 +15,9 @@ public class XljkConsultationScheduleVo {
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String counselorName; // 咨询师姓名,用于前端显示
|
||||
private String office; // 办公室
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String timeSlot; // 0中午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status;
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import org.dromara.xljk.domain.XljkConsulter;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置视图对象 xljk_consulter
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XljkConsulter.class)
|
||||
public class XljkConsulterVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
@ExcelProperty(value = "用户姓名")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
@ExcelProperty(value = "用户昵称")
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
@ExcelProperty(value = "部门ID")
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
@ExcelProperty(value = "部门名称")
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 联系电话
|
||||
*/
|
||||
@ExcelProperty(value = "联系电话")
|
||||
private String phoneNumber;
|
||||
|
||||
/**
|
||||
* 办公室
|
||||
*/
|
||||
@ExcelProperty(value = "办公室")
|
||||
private String office;
|
||||
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
@ExcelProperty(value = "邮箱地址")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 状态(1正常 0停用)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_normal_disable")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注说明
|
||||
*/
|
||||
@ExcelProperty(value = "备注说明")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 配置人ID
|
||||
*/
|
||||
private Long configBy;
|
||||
|
||||
/**
|
||||
* 配置人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "配置人")
|
||||
private String configByName;
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者ID
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@ExcelProperty(value = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者ID
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@ExcelProperty(value = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsulter;
|
||||
import org.dromara.xljk.domain.vo.XljkConsulterVo;
|
||||
import org.dromara.xljk.domain.XljkUserWithDeptInfo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface XljkConsulterMapper extends BaseMapperPlus<XljkConsulter, XljkConsulterVo> {
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置
|
||||
*
|
||||
* @param id 心理咨询师配置主键
|
||||
* @return 心理咨询师配置
|
||||
*/
|
||||
XljkConsulterVo selectXljkConsulterVoById(Long id);
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*
|
||||
* @param xljkConsulter 心理咨询师配置
|
||||
* @return 心理咨询师配置集合
|
||||
*/
|
||||
List<XljkConsulterVo> selectXljkConsulterVoList(XljkConsulter xljkConsulter);
|
||||
|
||||
/**
|
||||
* 根据用户ID检查是否已存在咨询师配置
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 记录数
|
||||
*/
|
||||
int checkUserExists(@Param("userId") Long userId);
|
||||
|
||||
/**
|
||||
* 批量启用咨询师
|
||||
*
|
||||
* @param ids 咨询师ID列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
int enableConsultersByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量停用咨询师
|
||||
*
|
||||
* @param ids 咨询师ID列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
int disableConsultersByIds(@Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 查询完整的用户信息(包含部门信息)用于批量添加
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @return 用户和部门完整信息列表
|
||||
*/
|
||||
List<XljkUserWithDeptInfo> selectUsersWithDeptInfo(@Param("userIds") List<Long> userIds);
|
||||
|
||||
}
|
||||
+19
-4
@@ -4,6 +4,7 @@ import org.dromara.xljk.domain.XljkConsultationAppointment;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationAppointmentBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationAppointmentVo;
|
||||
import org.dromara.xljk.domain.vo.TimeSlotDetailVo;
|
||||
import org.dromara.xljk.domain.vo.ScheduleWithStatusVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import java.util.List;
|
||||
@@ -43,7 +44,7 @@ public interface IXljkConsultationAppointmentService {
|
||||
/**
|
||||
* 获取可用的详细时段列表(30分钟一个时段)
|
||||
* @param date 日期
|
||||
* @param timeSlot 时段类型(0上午 1下午)
|
||||
* @param timeSlot 时段类型(0中午 1下午)
|
||||
* @return 详细时段列表
|
||||
*/
|
||||
List<TimeSlotDetailVo> getAvailableDetailSlots(Date date, String timeSlot);
|
||||
@@ -65,15 +66,21 @@ public interface IXljkConsultationAppointmentService {
|
||||
/**
|
||||
* 记录咨询结果
|
||||
* @param id 预约ID
|
||||
* @param actualVisitTime 实际到访时间
|
||||
* @param communicationDuration 沟通时长
|
||||
* @param consultationContent 咨询内容
|
||||
* @param counselorSuggestion 咨询师建议
|
||||
* @param status 状态(1已完成/3未到访)
|
||||
* @param psychologicalHistory 心理病史(1-否,2-是)
|
||||
* @param psychologicalHistoryDetail 心理病史详情
|
||||
* @param basicSituation 基本情况
|
||||
* @param majorLifeEvents 重大生活事件
|
||||
* @param needReferral 是否需要转介(1-不需要,2-需要)
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean recordConsultation(Long id, Date actualVisitTime, Integer communicationDuration,
|
||||
String consultationContent, String counselorSuggestion, String status);
|
||||
boolean recordConsultation(Long id, Integer communicationDuration,
|
||||
String consultationContent, String counselorSuggestion, String status,
|
||||
Integer psychologicalHistory, String psychologicalHistoryDetail,
|
||||
String basicSituation, String majorLifeEvents, Integer needReferral);
|
||||
|
||||
/**
|
||||
* 获取院系选项
|
||||
@@ -95,4 +102,12 @@ public interface IXljkConsultationAppointmentService {
|
||||
* @return 班级选项列表
|
||||
*/
|
||||
List<Map<String, Object>> getClassOptions(String collegeName, String majorName);
|
||||
|
||||
/**
|
||||
* 获取日历视图的排班数据(带预约状态)
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 排班数据列表
|
||||
*/
|
||||
List<ScheduleWithStatusVo> getCalendarSchedules(String startDate, String endDate);
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.vo.XljkConsulterVo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsulterBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
public interface IXljkConsulterService {
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 心理咨询师配置
|
||||
*/
|
||||
XljkConsulterVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 心理咨询师配置集合
|
||||
*/
|
||||
TableDataInfo<XljkConsulterVo> queryPageList(XljkConsulterBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 心理咨询师配置集合
|
||||
*/
|
||||
List<XljkConsulterVo> queryList(XljkConsulterBo bo);
|
||||
|
||||
/**
|
||||
* 新增心理咨询师配置
|
||||
*
|
||||
* @param bo 心理咨询师配置
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean insertByBo(XljkConsulterBo bo);
|
||||
|
||||
/**
|
||||
* 修改心理咨询师配置
|
||||
*
|
||||
* @param bo 心理咨询师配置
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean updateByBo(XljkConsulterBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除心理咨询师配置信息
|
||||
*
|
||||
* @param ids 需要删除的主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量添加咨询师
|
||||
*
|
||||
* @param userIds 用户ID列表
|
||||
* @param remark 备注
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean batchAddConsulters(List<Long> userIds, String remark);
|
||||
|
||||
/**
|
||||
* 查询我配置的咨询师列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 咨询师列表
|
||||
*/
|
||||
TableDataInfo<XljkConsulterVo> queryMyConfigList(XljkConsulterBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 批量启用咨询师
|
||||
*
|
||||
* @param ids 咨询师ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean enableConsulters(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 批量停用咨询师
|
||||
*
|
||||
* @param ids 咨询师ID列表
|
||||
* @return 结果
|
||||
*/
|
||||
Boolean disableConsulters(List<Long> ids);
|
||||
|
||||
}
|
||||
+393
-67
@@ -10,6 +10,7 @@ import org.dromara.xljk.domain.XljkConsultationSchedule;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationAppointmentBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationAppointmentVo;
|
||||
import org.dromara.xljk.domain.vo.TimeSlotDetailVo;
|
||||
import org.dromara.xljk.domain.vo.ScheduleWithStatusVo;
|
||||
import org.dromara.xljk.mapper.XljkConsultationAppointmentMapper;
|
||||
import org.dromara.xljk.mapper.XljkConsultationScheduleMapper;
|
||||
import org.dromara.xljk.service.IXljkConsultationAppointmentService;
|
||||
@@ -38,6 +39,8 @@ import org.dromara.common.core.utils.SpringUtils;
|
||||
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 java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -71,9 +74,8 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
|
||||
// 记录关键字段
|
||||
log.info("复制后的VO对象关键字段:status={}, actualVisitTime={}, communicationDuration={}, consultationContent长度={}, counselorSuggestion长度={}",
|
||||
log.info("复制后的VO对象关键字段:status={}, communicationDuration={}, consultationContent长度={}, counselorSuggestion长度={}",
|
||||
vo.getStatus(),
|
||||
vo.getActualVisitTime(),
|
||||
vo.getCommunicationDuration(),
|
||||
vo.getConsultationContent() != null ? vo.getConsultationContent().length() : 0,
|
||||
vo.getCounselorSuggestion() != null ? vo.getCounselorSuggestion().length() : 0);
|
||||
@@ -128,23 +130,8 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
|
||||
// 再次检查关键字段
|
||||
if (vo.getStatus() != null && vo.getStatus() == 1) {
|
||||
log.info("已到访状态,检查咨询结果相关字段:actualVisitTime={}, communicationDuration={}",
|
||||
vo.getActualVisitTime(), vo.getCommunicationDuration());
|
||||
|
||||
// 如果是已到访状态但实际到访时间为空,尝试从数据库直接查询
|
||||
if (vo.getActualVisitTime() == null) {
|
||||
log.warn("已到访状态但实际到访时间为空,尝试从数据库直接查询");
|
||||
try {
|
||||
String timeSql = "SELECT actual_visit_time FROM xljk_consultation_appointment WHERE id = " + id;
|
||||
Date actualVisitTime = jdbcTemplate.queryForObject(timeSql, Date.class);
|
||||
if (actualVisitTime != null) {
|
||||
log.info("从数据库查询到实际到访时间: {}", actualVisitTime);
|
||||
vo.setActualVisitTime(actualVisitTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("查询实际到访时间失败", e);
|
||||
}
|
||||
}
|
||||
log.info("已到访状态,检查咨询结果相关字段:communicationDuration={}",
|
||||
vo.getCommunicationDuration());
|
||||
}
|
||||
|
||||
log.info("返回预约记录详情: {}", vo);
|
||||
@@ -238,6 +225,9 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
return resultList.stream().map(row -> {
|
||||
XljkConsultationAppointmentVo vo = new XljkConsultationAppointmentVo();
|
||||
|
||||
// 获取学生ID用于计算本学期到访次数
|
||||
Long studentId = row.get("student_id") != null ? ((Number) row.get("student_id")).longValue() : null;
|
||||
|
||||
// 设置基本字段
|
||||
vo.setId(((Number) row.get("id")).longValue());
|
||||
vo.setTenantId((String) row.get("tenant_id"));
|
||||
@@ -291,11 +281,44 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
vo.setStatus(0); // 默认为待咨询
|
||||
}
|
||||
|
||||
vo.setActualVisitTime(convertToDate(row.get("actual_visit_time")));
|
||||
vo.setCommunicationDuration(row.get("communication_duration") != null ? ((Number) row.get("communication_duration")).intValue() : null);
|
||||
vo.setConsultationContent((String) row.get("consultation_content"));
|
||||
vo.setCounselorSuggestion((String) row.get("counselor_suggestion"));
|
||||
|
||||
// 设置咨询主题字段
|
||||
vo.setConsultTheme((String) row.get("consult_theme"));
|
||||
|
||||
// 设置心理健康相关字段
|
||||
Object psychologicalHistoryObj = row.get("psychological_history");
|
||||
if (psychologicalHistoryObj != null) {
|
||||
if (psychologicalHistoryObj instanceof Number) {
|
||||
vo.setPsychologicalHistory(((Number) psychologicalHistoryObj).intValue());
|
||||
} else if (psychologicalHistoryObj instanceof String) {
|
||||
try {
|
||||
vo.setPsychologicalHistory(Integer.parseInt((String) psychologicalHistoryObj));
|
||||
} catch (NumberFormatException e) {
|
||||
vo.setPsychologicalHistory(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vo.setPsychologicalHistoryDetail((String) row.get("psychological_history_detail"));
|
||||
vo.setBasicSituation((String) row.get("basic_situation"));
|
||||
vo.setMajorLifeEvents((String) row.get("major_life_events"));
|
||||
|
||||
Object needReferralObj = row.get("need_referral");
|
||||
if (needReferralObj != null) {
|
||||
if (needReferralObj instanceof Number) {
|
||||
vo.setNeedReferral(((Number) needReferralObj).intValue());
|
||||
} else if (needReferralObj instanceof String) {
|
||||
try {
|
||||
vo.setNeedReferral(Integer.parseInt((String) needReferralObj));
|
||||
} catch (NumberFormatException e) {
|
||||
vo.setNeedReferral(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置关联字段
|
||||
vo.setStudentName((String) row.get("student_name"));
|
||||
vo.setStudentNo((String) row.get("student_no"));
|
||||
@@ -304,9 +327,68 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
vo.setCollegeName((String) row.get("college_name"));
|
||||
vo.setMajorName((String) row.get("major_name"));
|
||||
|
||||
// 计算本学期到访次数
|
||||
if (studentId != null) {
|
||||
vo.setSemesterVisitCount(calculateSemesterVisitCount(studentId));
|
||||
} else {
|
||||
vo.setSemesterVisitCount(0);
|
||||
}
|
||||
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算学生本学期到访次数
|
||||
* 上学期:3月1日-8月31日
|
||||
* 下学期:9月1日-2月29日
|
||||
* @param studentId 学生ID
|
||||
* @return 本学期到访次数
|
||||
*/
|
||||
private int calculateSemesterVisitCount(Long studentId) {
|
||||
try {
|
||||
// 获取当前日期
|
||||
LocalDate now = LocalDate.now();
|
||||
String startDate, endDate;
|
||||
|
||||
// 判断当前处于哪个学期
|
||||
if (now.getMonthValue() >= 3 && now.getMonthValue() <= 8) {
|
||||
// 上学期:3月1日-8月31日
|
||||
startDate = now.getYear() + "-03-01";
|
||||
endDate = now.getYear() + "-08-31";
|
||||
} else if (now.getMonthValue() >= 9) {
|
||||
// 下学期:9月1日-次年2月29日(当年9月到次年2月)
|
||||
startDate = now.getYear() + "-09-01";
|
||||
// 计算次年2月的最后一天
|
||||
int nextYear = now.getYear() + 1;
|
||||
LocalDate nextFeb = LocalDate.of(nextYear, Month.FEBRUARY, 1);
|
||||
LocalDate lastDayOfFeb = nextFeb.withDayOfMonth(nextFeb.lengthOfMonth());
|
||||
endDate = lastDayOfFeb.toString();
|
||||
} else {
|
||||
// 1月、2月属于上一学年的下学期
|
||||
int prevYear = now.getYear() - 1;
|
||||
startDate = prevYear + "-09-01";
|
||||
// 当年2月的最后一天
|
||||
LocalDate currentFeb = LocalDate.of(now.getYear(), Month.FEBRUARY, 1);
|
||||
LocalDate lastDayOfFeb = currentFeb.withDayOfMonth(currentFeb.lengthOfMonth());
|
||||
endDate = lastDayOfFeb.toString();
|
||||
}
|
||||
|
||||
// 查询该学生在当前学期内状态为已到访(status=1)的记录数
|
||||
String sql = "SELECT COUNT(*) FROM xljk_consultation_appointment " +
|
||||
"WHERE student_id = ? AND status = 1 AND deleted = 0 " +
|
||||
"AND appointment_date >= ? AND appointment_date <= ?";
|
||||
|
||||
Integer count = jdbcTemplate.queryForObject(sql, Integer.class, studentId, startDate, endDate);
|
||||
|
||||
log.debug("学生ID: {}, 学期时间段: {} - {}, 到访次数: {}", studentId, startDate, endDate, count);
|
||||
|
||||
return count != null ? count : 0;
|
||||
} catch (Exception e) {
|
||||
log.error("计算学生本学期到访次数失败,学生ID: {}", studentId, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(XljkConsultationAppointmentBo bo) {
|
||||
@@ -341,7 +423,7 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
LambdaQueryWrapper<XljkConsultationAppointment> appointmentQueryWrapper = new LambdaQueryWrapper<>();
|
||||
appointmentQueryWrapper.ge(XljkConsultationAppointment::getAppointmentDate, startDate)
|
||||
.le(XljkConsultationAppointment::getAppointmentDate, endDate)
|
||||
.in(XljkConsultationAppointment::getStatus, Arrays.asList("0", "1")); // 待咨询或已完成的
|
||||
.in(XljkConsultationAppointment::getStatus, Arrays.asList("0", "1", "4")); // 待咨询、已完成或待审核的
|
||||
|
||||
List<XljkConsultationAppointment> appointments = mapper.selectList(appointmentQueryWrapper);
|
||||
|
||||
@@ -365,9 +447,10 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(schedule.getScheduleDate());
|
||||
String key = dateStr + "_" + schedule.getId();
|
||||
|
||||
// 检查该时段的可用详细时段
|
||||
// 检查该时段的可用详细时段(用于时间判断,但总容量固定为1)
|
||||
List<TimeSlotDetailVo> detailSlots = TimeSlotUtils.generateTimeSlots(schedule.getStartTime(), schedule.getEndTime());
|
||||
int totalDetailSlots = detailSlots.size();
|
||||
int totalDetailSlots = detailSlots.size(); // 保留用于时间过期判断
|
||||
int totalSlots = 1; // 每个时段只能预约1个人
|
||||
int bookedCount = 0;
|
||||
boolean isExpired = false;
|
||||
|
||||
@@ -408,15 +491,11 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
isExpired = false;
|
||||
}
|
||||
|
||||
// 检查已预约的详细时段
|
||||
// 检查已预约数量(按整个时段计算,不再按详细时段计算)
|
||||
if (bookedDetailSlots.containsKey(key)) {
|
||||
List<String> bookedTimes = bookedDetailSlots.get(key);
|
||||
for (TimeSlotDetailVo slot : detailSlots) {
|
||||
String detailTime = slot.getStartTime() + "-" + slot.getEndTime();
|
||||
if (bookedTimes.contains(detailTime)) {
|
||||
bookedCount++;
|
||||
}
|
||||
}
|
||||
// 只要有任何预约,就算已预约1个(因为每个时段只能预约1个人)
|
||||
bookedCount = bookedTimes.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
// 创建时段信息
|
||||
@@ -427,8 +506,8 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
slot.put("timeSlot", schedule.getTimeSlot());
|
||||
slot.put("startTime", schedule.getStartTime());
|
||||
slot.put("endTime", schedule.getEndTime());
|
||||
slot.put("allBooked", bookedCount >= totalDetailSlots); // 是否全部约满
|
||||
slot.put("availableCount", totalDetailSlots - bookedCount); // 可用数量
|
||||
slot.put("allBooked", bookedCount >= totalSlots); // 是否全部约满
|
||||
slot.put("availableCount", totalSlots - bookedCount); // 可用数量
|
||||
slot.put("isExpired", isExpired); // 是否已过期
|
||||
|
||||
// 查询咨询师姓名
|
||||
@@ -463,21 +542,34 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
.eq(XljkConsultationSchedule::getTimeSlot, timeSlot)
|
||||
.eq(XljkConsultationSchedule::getStatus, "0"); // 0表示正常可用
|
||||
|
||||
XljkConsultationSchedule schedule = scheduleMapper.selectOne(scheduleQueryWrapper);
|
||||
// 修改:使用selectList()而不是selectOne(),因为可能有多条记录
|
||||
List<XljkConsultationSchedule> schedules = scheduleMapper.selectList(scheduleQueryWrapper);
|
||||
|
||||
if (schedule == null) {
|
||||
if (schedules == null || schedules.isEmpty()) {
|
||||
// 该日期没有排班
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 生成30分钟时段列表
|
||||
List<TimeSlotDetailVo> timeSlots = TimeSlotUtils.generateTimeSlots(schedule.getStartTime(), schedule.getEndTime());
|
||||
// 2. 合并所有排班的时段,生成完整的30分钟时段列表
|
||||
List<TimeSlotDetailVo> allTimeSlots = new ArrayList<>();
|
||||
Set<String> uniqueTimeSlots = new LinkedHashSet<>(); // 用于去重,保持顺序
|
||||
|
||||
// 3. 查询已预约的时段
|
||||
for (XljkConsultationSchedule schedule : schedules) {
|
||||
List<TimeSlotDetailVo> timeSlots = TimeSlotUtils.generateTimeSlots(schedule.getStartTime(), schedule.getEndTime());
|
||||
for (TimeSlotDetailVo slot : timeSlots) {
|
||||
String slotKey = slot.getStartTime() + "-" + slot.getEndTime();
|
||||
if (uniqueTimeSlots.add(slotKey)) {
|
||||
allTimeSlots.add(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 查询已预约的时段(查询所有相关排班的预约)
|
||||
List<Long> scheduleIds = schedules.stream().map(XljkConsultationSchedule::getId).collect(Collectors.toList());
|
||||
LambdaQueryWrapper<XljkConsultationAppointment> appointmentQueryWrapper = new LambdaQueryWrapper<>();
|
||||
appointmentQueryWrapper.eq(XljkConsultationAppointment::getAppointmentDate, date)
|
||||
.eq(XljkConsultationAppointment::getScheduleId, schedule.getId()) // 按排班ID过滤,确保只查询当前时段的预约
|
||||
.in(XljkConsultationAppointment::getStatus, Arrays.asList("0", "1")); // 待咨询或已完成的
|
||||
.in(XljkConsultationAppointment::getScheduleId, scheduleIds) // 按排班ID列表过滤
|
||||
.in(XljkConsultationAppointment::getStatus, Arrays.asList("0", "1", "4")); // 待咨询、已完成或待审核的
|
||||
|
||||
List<XljkConsultationAppointment> appointments = mapper.selectList(appointmentQueryWrapper);
|
||||
|
||||
@@ -491,7 +583,7 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
|
||||
for (TimeSlotDetailVo slot : timeSlots) {
|
||||
for (TimeSlotDetailVo slot : allTimeSlots) {
|
||||
String detailTime = slot.getStartTime() + "-" + slot.getEndTime();
|
||||
|
||||
// 检查是否已预约
|
||||
@@ -532,7 +624,7 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
}
|
||||
}
|
||||
|
||||
return timeSlots;
|
||||
return allTimeSlots;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -582,7 +674,7 @@ public class XljkConsultationAppointmentServiceImpl implements IXljkConsultation
|
||||
XljkConsultationAppointment entity = new XljkConsultationAppointment();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
entity.setStudentId(studentId); // 使用验证后的学生ID
|
||||
entity.setStatus("0"); // 0表示待咨询
|
||||
entity.setStatus("4"); // 4表示待审核
|
||||
entity.setCreateTime(new Date()); // 设置创建时间
|
||||
return mapper.insert(entity) > 0;
|
||||
}
|
||||
@@ -645,10 +737,6 @@ if (statusObj != null) {
|
||||
vo.setScheduleId(((Number) row.get("schedule_id")).longValue());
|
||||
}
|
||||
|
||||
if (row.get("actual_visit_time") != null) {
|
||||
vo.setActualVisitTime(convertToDate(row.get("actual_visit_time")));
|
||||
}
|
||||
|
||||
if (row.get("communication_duration") != null) {
|
||||
vo.setCommunicationDuration(((Number) row.get("communication_duration")).intValue());
|
||||
}
|
||||
@@ -691,9 +779,11 @@ if (statusObj != null) {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean recordConsultation(Long id, Date actualVisitTime, Integer communicationDuration,
|
||||
String consultationContent, String counselorSuggestion, String status) {
|
||||
log.info("记录咨询结果,ID: {}, 状态: {}, 实际到访时间: {}", id, status, actualVisitTime);
|
||||
public boolean recordConsultation(Long id, Integer communicationDuration,
|
||||
String consultationContent, String counselorSuggestion, String status,
|
||||
Integer psychologicalHistory, String psychologicalHistoryDetail,
|
||||
String basicSituation, String majorLifeEvents, Integer needReferral) {
|
||||
log.info("记录咨询结果,ID: {}, 状态: {}, 心理病史: {}, 转介: {}", id, status, psychologicalHistory, needReferral);
|
||||
|
||||
XljkConsultationAppointment entity = mapper.selectById(id);
|
||||
if (entity == null) {
|
||||
@@ -717,29 +807,42 @@ if (statusObj != null) {
|
||||
|
||||
// 只有在已到访状态(1)时,才设置咨询结果相关字段
|
||||
if (statusInt == 1) {
|
||||
if (actualVisitTime == null) {
|
||||
log.warn("实际到访时间为空,使用当前时间");
|
||||
actualVisitTime = new Date();
|
||||
}
|
||||
|
||||
entity.setActualVisitTime(actualVisitTime);
|
||||
entity.setCommunicationDuration(communicationDuration != null ? communicationDuration : 30);
|
||||
entity.setConsultationContent(consultationContent);
|
||||
entity.setCounselorSuggestion(counselorSuggestion);
|
||||
|
||||
log.info("设置咨询结果相关字段:实际到访时间={}, 沟通时长={}, 咨询内容长度={}, 咨询师建议长度={}",
|
||||
actualVisitTime,
|
||||
// 设置心理病史相关字段
|
||||
entity.setPsychologicalHistory(psychologicalHistory);
|
||||
entity.setPsychologicalHistoryDetail(psychologicalHistoryDetail);
|
||||
entity.setBasicSituation(basicSituation);
|
||||
entity.setMajorLifeEvents(majorLifeEvents);
|
||||
entity.setNeedReferral(needReferral);
|
||||
|
||||
log.info("设置咨询结果相关字段:沟通时长={}, 咨询内容长度={}, 咨询师建议长度={}",
|
||||
communicationDuration,
|
||||
consultationContent != null ? consultationContent.length() : 0,
|
||||
counselorSuggestion != null ? counselorSuggestion.length() : 0);
|
||||
|
||||
log.info("设置心理病史相关字段:心理病史={}, 心理病史详情长度={}, 基本情况长度={}, 重大生活事件长度={}, 转介={}",
|
||||
psychologicalHistory,
|
||||
psychologicalHistoryDetail != null ? psychologicalHistoryDetail.length() : 0,
|
||||
basicSituation != null ? basicSituation.length() : 0,
|
||||
majorLifeEvents != null ? majorLifeEvents.length() : 0,
|
||||
needReferral);
|
||||
} else {
|
||||
// 未到访状态,清空咨询结果相关字段
|
||||
log.info("非已到访状态,清空咨询结果相关字段");
|
||||
entity.setActualVisitTime(null);
|
||||
entity.setCommunicationDuration(0);
|
||||
entity.setConsultationContent("");
|
||||
entity.setCounselorSuggestion("");
|
||||
|
||||
// 清空心理病史相关字段
|
||||
entity.setPsychologicalHistory(null);
|
||||
entity.setPsychologicalHistoryDetail("");
|
||||
entity.setBasicSituation("");
|
||||
entity.setMajorLifeEvents("");
|
||||
entity.setNeedReferral(null);
|
||||
|
||||
// 如果是未到访状态(3),创建未到访记录
|
||||
if (statusInt == 3) {
|
||||
log.info("记录未到访,创建未到访记录");
|
||||
@@ -1323,10 +1426,19 @@ if (statusObj != null) {
|
||||
public TableDataInfo<XljkConsultationAppointmentVo> selectPageList(XljkConsultationAppointmentBo bo, PageQuery pageQuery) {
|
||||
log.info("分页查询预约记录列表,页码: {}, 每页数量: {}", pageQuery.getPageNum(), pageQuery.getPageSize());
|
||||
|
||||
// 将变量定义移到try块外,确保catch块可以访问
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
try {
|
||||
// 构建查询条件
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("SELECT a.*, s.name AS student_name, s.student_no, ");
|
||||
sqlBuilder.append("SELECT a.id, a.tenant_id, a.student_id, a.counselor_id, a.schedule_id, ");
|
||||
sqlBuilder.append("a.appointment_date, a.appointment_time, a.appointment_detail_time, ");
|
||||
sqlBuilder.append("a.reason, a.status, a.communication_duration, a.consultation_content, ");
|
||||
sqlBuilder.append("a.counselor_suggestion, a.psychological_history, a.psychological_history_detail, ");
|
||||
sqlBuilder.append("a.basic_situation, a.major_life_events, a.need_referral, ");
|
||||
sqlBuilder.append("a.create_by, a.create_time, a.update_by, a.update_time, ");
|
||||
sqlBuilder.append("s.name AS student_name, s.student_no, ");
|
||||
sqlBuilder.append("s.college_name, s.major_name, s.class_name, ");
|
||||
sqlBuilder.append("u.nick_name AS counselor_name ");
|
||||
sqlBuilder.append("FROM xljk_consultation_appointment a ");
|
||||
@@ -1334,8 +1446,6 @@ if (statusObj != null) {
|
||||
sqlBuilder.append("LEFT JOIN sys_user u ON a.counselor_id = u.user_id ");
|
||||
sqlBuilder.append("WHERE a.deleted = 0 ");
|
||||
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
// 添加查询条件
|
||||
if (bo.getStudentName() != null && !bo.getStudentName().isEmpty()) {
|
||||
sqlBuilder.append("AND s.name LIKE ? ");
|
||||
@@ -1457,10 +1567,6 @@ if (statusObj != null) {
|
||||
vo.setScheduleId(((Number) row.get("schedule_id")).longValue());
|
||||
}
|
||||
|
||||
if (row.get("actual_visit_time") != null) {
|
||||
vo.setActualVisitTime(convertToDate(row.get("actual_visit_time")));
|
||||
}
|
||||
|
||||
if (row.get("communication_duration") != null) {
|
||||
vo.setCommunicationDuration(((Number) row.get("communication_duration")).intValue());
|
||||
}
|
||||
@@ -1468,6 +1574,37 @@ if (statusObj != null) {
|
||||
vo.setConsultationContent((String) row.get("consultation_content"));
|
||||
vo.setCounselorSuggestion((String) row.get("counselor_suggestion"));
|
||||
|
||||
// 新增字段映射
|
||||
Object psychologicalHistoryObj = row.get("psychological_history");
|
||||
if (psychologicalHistoryObj != null) {
|
||||
if (psychologicalHistoryObj instanceof Number) {
|
||||
vo.setPsychologicalHistory(((Number) psychologicalHistoryObj).intValue());
|
||||
} else if (psychologicalHistoryObj instanceof String) {
|
||||
try {
|
||||
vo.setPsychologicalHistory(Integer.parseInt((String) psychologicalHistoryObj));
|
||||
} catch (NumberFormatException e) {
|
||||
vo.setPsychologicalHistory(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vo.setPsychologicalHistoryDetail((String) row.get("psychological_history_detail"));
|
||||
vo.setBasicSituation((String) row.get("basic_situation"));
|
||||
vo.setMajorLifeEvents((String) row.get("major_life_events"));
|
||||
|
||||
Object needReferralObj = row.get("need_referral");
|
||||
if (needReferralObj != null) {
|
||||
if (needReferralObj instanceof Number) {
|
||||
vo.setNeedReferral(((Number) needReferralObj).intValue());
|
||||
} else if (needReferralObj instanceof String) {
|
||||
try {
|
||||
vo.setNeedReferral(Integer.parseInt((String) needReferralObj));
|
||||
} catch (NumberFormatException e) {
|
||||
vo.setNeedReferral(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 其他通用字段
|
||||
if (row.get("create_by") != null) {
|
||||
vo.setCreateBy(((Number) row.get("create_by")).longValue());
|
||||
@@ -1485,6 +1622,13 @@ if (statusObj != null) {
|
||||
vo.setUpdateTime(convertToDate(row.get("update_time")));
|
||||
}
|
||||
|
||||
// 计算本学期到访次数
|
||||
if (vo.getStudentId() != null) {
|
||||
vo.setSemesterVisitCount(calculateSemesterVisitCount(vo.getStudentId()));
|
||||
} else {
|
||||
vo.setSemesterVisitCount(0);
|
||||
}
|
||||
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
@@ -1496,12 +1640,194 @@ if (statusObj != null) {
|
||||
return tableDataInfo;
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询预约记录列表异常", e);
|
||||
log.error("SQL: {}", sqlBuilder.toString());
|
||||
log.error("参数: {}", params);
|
||||
TableDataInfo<XljkConsultationAppointmentVo> emptyResult = new TableDataInfo<>();
|
||||
emptyResult.setRows(new ArrayList<>());
|
||||
emptyResult.setTotal(0);
|
||||
emptyResult.setCode(200);
|
||||
emptyResult.setMsg("查询失败");
|
||||
emptyResult.setMsg("查询失败: " + e.getMessage());
|
||||
return emptyResult;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ScheduleWithStatusVo> getCalendarSchedules(String startDate, String endDate) {
|
||||
try {
|
||||
// 1. 查询指定日期范围内的所有排班数据
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.ge(XljkConsultationSchedule::getScheduleDate, startDate)
|
||||
.le(XljkConsultationSchedule::getScheduleDate, endDate)
|
||||
.eq(XljkConsultationSchedule::getStatus, "0") // 0表示正常可用
|
||||
.orderByAsc(XljkConsultationSchedule::getScheduleDate)
|
||||
.orderByAsc(XljkConsultationSchedule::getTimeSlot)
|
||||
.orderByAsc(XljkConsultationSchedule::getStartTime);
|
||||
|
||||
List<XljkConsultationSchedule> schedules = scheduleMapper.selectList(queryWrapper);
|
||||
|
||||
if (schedules.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 2. 查询该日期范围内的所有预约记录
|
||||
List<Long> scheduleIds = schedules.stream().map(XljkConsultationSchedule::getId).collect(Collectors.toList());
|
||||
LambdaQueryWrapper<XljkConsultationAppointment> appointmentQueryWrapper = new LambdaQueryWrapper<>();
|
||||
appointmentQueryWrapper.in(XljkConsultationAppointment::getScheduleId, scheduleIds)
|
||||
.in(XljkConsultationAppointment::getStatus, Arrays.asList("0", "1", "4")); // 待咨询、已完成或待审核的
|
||||
|
||||
List<XljkConsultationAppointment> appointments = mapper.selectList(appointmentQueryWrapper);
|
||||
|
||||
// 3. 构建排班ID到预约记录的映射
|
||||
Map<Long, List<XljkConsultationAppointment>> appointmentMap = appointments.stream()
|
||||
.collect(Collectors.groupingBy(XljkConsultationAppointment::getScheduleId));
|
||||
|
||||
// 4. 获取咨询师信息映射
|
||||
Map<Long, String> counselorMap = getCounselorNameMap();
|
||||
|
||||
// 5. 获取当前时间
|
||||
Date now = new Date();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
|
||||
|
||||
// 6. 构建结果列表
|
||||
List<ScheduleWithStatusVo> result = new ArrayList<>();
|
||||
|
||||
for (XljkConsultationSchedule schedule : schedules) {
|
||||
ScheduleWithStatusVo vo = new ScheduleWithStatusVo();
|
||||
|
||||
// 基本信息
|
||||
vo.setScheduleId(schedule.getId());
|
||||
vo.setCounselorId(schedule.getCounselorId());
|
||||
vo.setCounselorName(counselorMap.get(schedule.getCounselorId()));
|
||||
vo.setDate(dateFormat.format(schedule.getScheduleDate()));
|
||||
vo.setTimeSlot(schedule.getTimeSlot());
|
||||
vo.setStartTime(schedule.getStartTime());
|
||||
vo.setEndTime(schedule.getEndTime());
|
||||
|
||||
// 构建时段显示文本
|
||||
String timeSlotText = getTimeSlotText(schedule.getTimeSlot());
|
||||
vo.setTimeDisplay(timeSlotText + " " + schedule.getStartTime() + "-" + schedule.getEndTime());
|
||||
|
||||
// 计算预约状态
|
||||
List<XljkConsultationAppointment> scheduleAppointments = appointmentMap.get(schedule.getId());
|
||||
int bookedCount = scheduleAppointments != null ? scheduleAppointments.size() : 0;
|
||||
|
||||
// 每个时段只能预约1个人(无论时段长度)
|
||||
// 生成30分钟时段用于详细时段显示,但总预约数量固定为1
|
||||
List<TimeSlotDetailVo> timeSlots = TimeSlotUtils.generateTimeSlots(schedule.getStartTime(), schedule.getEndTime());
|
||||
int totalSlots = 1; // 每个时段只能预约1个人
|
||||
|
||||
vo.setTotalSlots(totalSlots);
|
||||
vo.setAvailableSlots(Math.max(0, totalSlots - bookedCount));
|
||||
vo.setIsFullyBooked(bookedCount >= totalSlots);
|
||||
|
||||
// 检查是否已过期
|
||||
boolean isExpired = false;
|
||||
try {
|
||||
Date scheduleDate = schedule.getScheduleDate();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(scheduleDate);
|
||||
|
||||
// 设置具体的结束时间
|
||||
String[] endTimeParts = schedule.getEndTime().split(":");
|
||||
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(endTimeParts[0]));
|
||||
calendar.set(Calendar.MINUTE, Integer.parseInt(endTimeParts[1]));
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
|
||||
Date scheduleEndTime = calendar.getTime();
|
||||
isExpired = scheduleEndTime.before(now);
|
||||
} catch (Exception e) {
|
||||
log.warn("检查时段过期状态失败: " + schedule.getId(), e);
|
||||
}
|
||||
|
||||
vo.setIsExpired(isExpired);
|
||||
|
||||
// 设置基础字段
|
||||
vo.setCreateBy(schedule.getCreateBy());
|
||||
vo.setCreateTime(schedule.getCreateTime());
|
||||
vo.setUpdateBy(schedule.getUpdateBy());
|
||||
vo.setUpdateTime(schedule.getUpdateTime());
|
||||
|
||||
result.add(vo);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取日历排班数据失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时段类型文本
|
||||
*/
|
||||
private String getTimeSlotText(String timeSlot) {
|
||||
switch (timeSlot) {
|
||||
case "0": return "中午";
|
||||
case "1": return "下午";
|
||||
case "2": return "晚上";
|
||||
default: return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取咨询师名称映射
|
||||
*/
|
||||
private Map<Long, String> getCounselorNameMap() {
|
||||
try {
|
||||
Map<Long, String> counselorMap = new HashMap<>();
|
||||
|
||||
// 1. 查询所有已创建排班的咨询师ID
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.select(XljkConsultationSchedule::getCounselorId)
|
||||
.eq(XljkConsultationSchedule::getStatus, "0") // 只查询正常状态的
|
||||
.groupBy(XljkConsultationSchedule::getCounselorId); // 去重
|
||||
|
||||
List<XljkConsultationSchedule> schedules = scheduleMapper.selectList(queryWrapper);
|
||||
if (schedules.isEmpty()) {
|
||||
return counselorMap;
|
||||
}
|
||||
|
||||
// 2. 提取咨询师ID列表
|
||||
List<Long> counselorIds = schedules.stream()
|
||||
.map(XljkConsultationSchedule::getCounselorId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (counselorIds.isEmpty()) {
|
||||
return counselorMap;
|
||||
}
|
||||
|
||||
// 3. 批量查询咨询师信息
|
||||
List<SysUserVo> counselors = userService.selectUserByIds(counselorIds, null);
|
||||
|
||||
// 4. 构建ID到姓名的映射
|
||||
counselorMap = counselors.stream()
|
||||
.filter(user -> user.getUserId() != null)
|
||||
.collect(Collectors.toMap(
|
||||
SysUserVo::getUserId,
|
||||
user -> {
|
||||
// 优先使用昵称,如果没有昵称则使用用户名
|
||||
String name = user.getNickName();
|
||||
if (StringUtils.isBlank(name)) {
|
||||
name = user.getUserName();
|
||||
}
|
||||
if (StringUtils.isBlank(name)) {
|
||||
name = "未知咨询师";
|
||||
}
|
||||
return name;
|
||||
},
|
||||
(existing, replacement) -> existing // 如果ID重复,保留第一个
|
||||
));
|
||||
|
||||
log.info("成功加载咨询师信息映射,共{}个咨询师", counselorMap.size());
|
||||
return counselorMap;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取咨询师信息失败", e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
-28
@@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@@ -26,6 +27,7 @@ import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class XljkConsultationScheduleServiceImpl implements IXljkConsultationScheduleService {
|
||||
@Autowired
|
||||
@@ -43,11 +45,16 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
// 查询咨询师姓名
|
||||
if (entity.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, entity.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
vo.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
try {
|
||||
String counselorName = jdbcTemplate.queryForObject(sql, String.class, entity.getCounselorId());
|
||||
vo.setCounselorName(counselorName);
|
||||
} catch (Exception e) {
|
||||
log.error("查询咨询师姓名失败,counselorId: {}", entity.getCounselorId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// office字段直接从排班记录中获取
|
||||
vo.setOffice(entity.getOffice());
|
||||
return vo;
|
||||
}
|
||||
|
||||
@@ -65,11 +72,15 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
// 查询咨询师姓名
|
||||
if (entity.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, entity.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
vo.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
try {
|
||||
String counselorName = jdbcTemplate.queryForObject(sql, String.class, entity.getCounselorId());
|
||||
vo.setCounselorName(counselorName);
|
||||
} catch (Exception e) {
|
||||
log.error("查询咨询师姓名失败,counselorId: {}", entity.getCounselorId(), e);
|
||||
}
|
||||
}
|
||||
// office字段直接从排班记录中获取
|
||||
vo.setOffice(entity.getOffice());
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
@@ -87,6 +98,11 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
queryWrapper.eq(XljkConsultationSchedule::getCounselorId, bo.getCounselorId());
|
||||
}
|
||||
|
||||
// 添加办公室筛选条件
|
||||
if (bo.getOffice() != null && !bo.getOffice().isEmpty()) {
|
||||
queryWrapper.like(XljkConsultationSchedule::getOffice, bo.getOffice());
|
||||
}
|
||||
|
||||
// 按创建时间倒序查询所有记录
|
||||
queryWrapper.orderByDesc(XljkConsultationSchedule::getCreateTime);
|
||||
|
||||
@@ -144,12 +160,17 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
// 查询咨询师姓名
|
||||
if (batchGroup.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, batchGroup.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
summary.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
try {
|
||||
String counselorName = jdbcTemplate.queryForObject(sql, String.class, batchGroup.getCounselorId());
|
||||
summary.setCounselorName(counselorName);
|
||||
} catch (Exception e) {
|
||||
log.error("查询咨询师姓名失败,counselorId: {}", batchGroup.getCounselorId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// office字段直接从排班记录中获取
|
||||
summary.setOffice(batchGroup.getOffice());
|
||||
|
||||
// 确保创建时间不为空
|
||||
if (summary.getCreateTime() == null) {
|
||||
summary.setCreateTime(new Date());
|
||||
@@ -226,12 +247,17 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
// 查询咨询师姓名
|
||||
if (firstSchedule.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, firstSchedule.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
summary.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
try {
|
||||
String counselorName = jdbcTemplate.queryForObject(sql, String.class, firstSchedule.getCounselorId());
|
||||
summary.setCounselorName(counselorName);
|
||||
} catch (Exception e) {
|
||||
log.error("查询咨询师姓名失败,counselorId: {}", firstSchedule.getCounselorId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// office字段直接从排班记录中获取
|
||||
summary.setOffice(firstSchedule.getOffice());
|
||||
|
||||
summaryList.add(summary);
|
||||
}
|
||||
}
|
||||
@@ -283,9 +309,12 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查是否至少启用了一个时段
|
||||
if ((batchBo.getMorningEnabled() == null || !batchBo.getMorningEnabled()) &&
|
||||
(batchBo.getAfternoonEnabled() == null || !batchBo.getAfternoonEnabled())) {
|
||||
// 检查是否至少启用了一个时段(兼容新旧版本)
|
||||
boolean hasMorning = (batchBo.getMorningEnabled() != null && batchBo.getMorningEnabled());
|
||||
boolean hasNoon = (batchBo.getNoonEnabled() != null && batchBo.getNoonEnabled());
|
||||
boolean hasAfternoon = (batchBo.getAfternoonEnabled() != null && batchBo.getAfternoonEnabled());
|
||||
|
||||
if (!hasMorning && !hasNoon && !hasAfternoon) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -321,12 +350,13 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
|
||||
// 如果是周末且设置了跳过周末,则跳过
|
||||
if (!(isWeekend && Boolean.TRUE.equals(batchBo.getSkipWeekends()))) {
|
||||
// 创建上午时段
|
||||
// 创建中午时段(字段名保持morning以兼容前端)
|
||||
if (Boolean.TRUE.equals(batchBo.getMorningEnabled())) {
|
||||
XljkConsultationSchedule morningSchedule = new XljkConsultationSchedule();
|
||||
morningSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
morningSchedule.setOffice(batchBo.getOffice());
|
||||
morningSchedule.setScheduleDate(currentDate);
|
||||
morningSchedule.setTimeSlot("0"); // 上午
|
||||
morningSchedule.setTimeSlot("0"); // 中午
|
||||
morningSchedule.setStartTime(batchBo.getMorningStartTime());
|
||||
morningSchedule.setEndTime(batchBo.getMorningEndTime());
|
||||
morningSchedule.setStatus(batchBo.getStatus());
|
||||
@@ -335,18 +365,54 @@ public class XljkConsultationScheduleServiceImpl implements IXljkConsultationSch
|
||||
schedules.add(morningSchedule);
|
||||
}
|
||||
|
||||
// 创建下午时段
|
||||
// 创建中午时段(新版本)
|
||||
if (Boolean.TRUE.equals(batchBo.getNoonEnabled()) && batchBo.getNoonTimeSlots() != null) {
|
||||
for (XljkConsultationScheduleBatchBo.TimeSlot timeSlot : batchBo.getNoonTimeSlots()) {
|
||||
XljkConsultationSchedule noonSchedule = new XljkConsultationSchedule();
|
||||
noonSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
noonSchedule.setOffice(batchBo.getOffice());
|
||||
noonSchedule.setScheduleDate(currentDate);
|
||||
noonSchedule.setTimeSlot("0"); // 中午时段
|
||||
noonSchedule.setStartTime(timeSlot.getStartTime());
|
||||
noonSchedule.setEndTime(timeSlot.getEndTime());
|
||||
noonSchedule.setStatus(batchBo.getStatus());
|
||||
noonSchedule.setBatchId(batchId); // 设置批次ID
|
||||
noonSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(noonSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建下午时段(兼容新旧版本)
|
||||
if (Boolean.TRUE.equals(batchBo.getAfternoonEnabled())) {
|
||||
XljkConsultationSchedule afternoonSchedule = new XljkConsultationSchedule();
|
||||
afternoonSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
afternoonSchedule.setScheduleDate(currentDate);
|
||||
afternoonSchedule.setTimeSlot("1"); // 下午
|
||||
afternoonSchedule.setStartTime(batchBo.getAfternoonStartTime());
|
||||
afternoonSchedule.setEndTime(batchBo.getAfternoonEndTime());
|
||||
afternoonSchedule.setStatus(batchBo.getStatus());
|
||||
afternoonSchedule.setBatchId(batchId); // 设置批次ID
|
||||
afternoonSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(afternoonSchedule);
|
||||
if (batchBo.getAfternoonTimeSlots() != null && !batchBo.getAfternoonTimeSlots().isEmpty()) {
|
||||
// 新版本:支持多时段
|
||||
for (XljkConsultationScheduleBatchBo.TimeSlot timeSlot : batchBo.getAfternoonTimeSlots()) {
|
||||
XljkConsultationSchedule afternoonSchedule = new XljkConsultationSchedule();
|
||||
afternoonSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
afternoonSchedule.setOffice(batchBo.getOffice());
|
||||
afternoonSchedule.setScheduleDate(currentDate);
|
||||
afternoonSchedule.setTimeSlot("1"); // 下午
|
||||
afternoonSchedule.setStartTime(timeSlot.getStartTime());
|
||||
afternoonSchedule.setEndTime(timeSlot.getEndTime());
|
||||
afternoonSchedule.setStatus(batchBo.getStatus());
|
||||
afternoonSchedule.setBatchId(batchId); // 设置批次ID
|
||||
afternoonSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(afternoonSchedule);
|
||||
}
|
||||
} else if (batchBo.getAfternoonStartTime() != null && batchBo.getAfternoonEndTime() != null) {
|
||||
// 旧版本:单时段
|
||||
XljkConsultationSchedule afternoonSchedule = new XljkConsultationSchedule();
|
||||
afternoonSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
afternoonSchedule.setOffice(batchBo.getOffice());
|
||||
afternoonSchedule.setScheduleDate(currentDate);
|
||||
afternoonSchedule.setTimeSlot("1"); // 下午
|
||||
afternoonSchedule.setStartTime(batchBo.getAfternoonStartTime());
|
||||
afternoonSchedule.setEndTime(batchBo.getAfternoonEndTime());
|
||||
afternoonSchedule.setStatus(batchBo.getStatus());
|
||||
afternoonSchedule.setBatchId(batchId); // 设置批次ID
|
||||
afternoonSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(afternoonSchedule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
package org.dromara.xljk.service.impl;
|
||||
|
||||
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.dromara.xljk.domain.bo.XljkConsulterBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsulterVo;
|
||||
import org.dromara.xljk.domain.XljkConsulter;
|
||||
import org.dromara.xljk.domain.XljkUserWithDeptInfo;
|
||||
import org.dromara.xljk.mapper.XljkConsulterMapper;
|
||||
import org.dromara.xljk.service.IXljkConsulterService;
|
||||
import org.dromara.system.service.ISysUserService;
|
||||
import org.dromara.system.service.ISysRoleService;
|
||||
import org.dromara.system.domain.vo.SysUserVo;
|
||||
import org.dromara.system.domain.vo.SysRoleVo;
|
||||
import org.dromara.system.domain.SysRole;
|
||||
import org.dromara.system.domain.SysUserRole;
|
||||
import org.dromara.system.domain.bo.SysRoleBo;
|
||||
import org.dromara.system.mapper.SysUserRoleMapper;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 心理咨询师配置Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2024-01-01
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XljkConsulterServiceImpl implements IXljkConsulterService {
|
||||
|
||||
private final XljkConsulterMapper baseMapper;
|
||||
private final ISysUserService sysUserService;
|
||||
private final ISysRoleService sysRoleService;
|
||||
private final SysUserRoleMapper sysUserRoleMapper;
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置
|
||||
*/
|
||||
@Override
|
||||
public XljkConsulterVo queryById(Long id) {
|
||||
XljkConsulter entity = baseMapper.selectById(id);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
return MapstructUtils.convert(entity, XljkConsulterVo.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XljkConsulterVo> queryPageList(XljkConsulterBo bo, PageQuery pageQuery) {
|
||||
// 直接使用查询条件构建器
|
||||
LambdaQueryWrapper<XljkConsulter> lqw = buildQueryWrapper(bo);
|
||||
Page<XljkConsulter> entityPage = baseMapper.selectPage(pageQuery.build(), lqw);
|
||||
|
||||
// 转换为 VO 对象
|
||||
List<XljkConsulterVo> voList = new ArrayList<>();
|
||||
for (XljkConsulter entity : entityPage.getRecords()) {
|
||||
XljkConsulterVo vo = MapstructUtils.convert(entity, XljkConsulterVo.class);
|
||||
voList.add(vo);
|
||||
}
|
||||
|
||||
// 构建分页结果
|
||||
Page<XljkConsulterVo> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
|
||||
voPage.setRecords(voList);
|
||||
|
||||
return TableDataInfo.build(voPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询心理咨询师配置列表
|
||||
*/
|
||||
@Override
|
||||
public List<XljkConsulterVo> queryList(XljkConsulterBo bo) {
|
||||
LambdaQueryWrapper<XljkConsulter> lqw = buildQueryWrapper(bo);
|
||||
List<XljkConsulter> entityList = baseMapper.selectList(lqw);
|
||||
|
||||
// 转换为 VO 对象
|
||||
List<XljkConsulterVo> voList = new ArrayList<>();
|
||||
for (XljkConsulter entity : entityList) {
|
||||
XljkConsulterVo vo = MapstructUtils.convert(entity, XljkConsulterVo.class);
|
||||
voList.add(vo);
|
||||
}
|
||||
|
||||
return voList;
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<XljkConsulter> buildQueryWrapper(XljkConsulterBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XljkConsulter> lqw = Wrappers.<XljkConsulter>lambdaQuery();
|
||||
lqw.eq(bo.getUserId() != null, XljkConsulter::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getUserName()), XljkConsulter::getUserName, bo.getUserName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getNickName()), XljkConsulter::getNickName, bo.getNickName());
|
||||
lqw.eq(bo.getDeptId() != null, XljkConsulter::getDeptId, bo.getDeptId());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), XljkConsulter::getStatus, bo.getStatus());
|
||||
lqw.eq(bo.getConfigBy() != null, XljkConsulter::getConfigBy, bo.getConfigBy());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
XljkConsulter::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
lqw.orderByDesc(XljkConsulter::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增心理咨询师配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(XljkConsulterBo bo) {
|
||||
XljkConsulter add = MapstructUtils.convert(bo, XljkConsulter.class);
|
||||
validEntityBeforeSave(add);
|
||||
|
||||
// 设置配置人信息
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
add.setConfigBy(currentUserId);
|
||||
|
||||
// 获取当前用户信息设置配置人姓名
|
||||
try {
|
||||
SysUserVo currentUser = sysUserService.selectUserById(currentUserId);
|
||||
if (currentUser != null) {
|
||||
add.setConfigByName(currentUser.getUserName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果获取失败,使用默认值
|
||||
add.setConfigByName("系统管理员");
|
||||
}
|
||||
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改心理咨询师配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(XljkConsulterBo bo) {
|
||||
XljkConsulter update = MapstructUtils.convert(bo, XljkConsulter.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(XljkConsulter entity) {
|
||||
if (entity.getUserId() != null) {
|
||||
// 检查用户是否已存在(新增时或修改用户ID时)
|
||||
if (entity.getId() == null) {
|
||||
// 新增时检查
|
||||
int count = baseMapper.checkUserExists(entity.getUserId());
|
||||
if (count > 0) {
|
||||
throw new ServiceException("该用户已配置为咨询师,不能重复添加");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除心理咨询师配置
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids) {
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加咨询师
|
||||
*/
|
||||
@Override
|
||||
public Boolean batchAddConsulters(List<Long> userIds, String remark) {
|
||||
if (userIds == null || userIds.isEmpty()) {
|
||||
throw new ServiceException("用户ID列表不能为空");
|
||||
}
|
||||
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
String currentUserName = "系统管理员";
|
||||
|
||||
// 获取当前用户信息
|
||||
try {
|
||||
SysUserVo currentUser = sysUserService.selectUserById(currentUserId);
|
||||
if (currentUser != null) {
|
||||
currentUserName = currentUser.getUserName();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 使用默认值
|
||||
}
|
||||
|
||||
// 1. 获取完整的用户信息(包含部门信息)
|
||||
List<XljkUserWithDeptInfo> users = baseMapper.selectUsersWithDeptInfo(userIds);
|
||||
if (users.isEmpty()) {
|
||||
throw new ServiceException("没有找到有效的用户信息");
|
||||
}
|
||||
|
||||
// 2. 过滤已存在的咨询师
|
||||
List<Long> existingUserIds = baseMapper.selectList(Wrappers.<XljkConsulter>lambdaQuery()
|
||||
.in(XljkConsulter::getUserId, userIds))
|
||||
.stream().map(XljkConsulter::getUserId).collect(Collectors.toList());
|
||||
|
||||
// 3. 构建新增咨询师列表
|
||||
List<XljkConsulter> consulterList = new ArrayList<>();
|
||||
for (XljkUserWithDeptInfo user : users) {
|
||||
if (!existingUserIds.contains(user.getUserId())) {
|
||||
XljkConsulter consulter = new XljkConsulter();
|
||||
consulter.setUserId(user.getUserId());
|
||||
consulter.setUserName(user.getUserName());
|
||||
consulter.setNickName(user.getNickName());
|
||||
consulter.setDeptId(user.getDeptId());
|
||||
consulter.setDeptName(user.getDeptName() != null ? user.getDeptName() : "");
|
||||
consulter.setPhoneNumber(user.getPhonenumber());
|
||||
consulter.setEmail(user.getEmail());
|
||||
consulter.setStatus("1"); // 默认正常状态
|
||||
consulter.setRemark(remark);
|
||||
consulter.setConfigBy(currentUserId);
|
||||
consulter.setConfigByName(currentUserName);
|
||||
consulterList.add(consulter);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 批量保存
|
||||
if (consulterList.isEmpty()) {
|
||||
throw new ServiceException("所有用户都已存在,无需重复添加");
|
||||
}
|
||||
|
||||
boolean result = baseMapper.insertBatch(consulterList);
|
||||
|
||||
// 5. 为新添加的咨询师自动分配 xljk_consultant 角色
|
||||
if (result) {
|
||||
assignConsultantRole(consulterList);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为咨询师分配 xljk_consultant 角色
|
||||
*/
|
||||
private void assignConsultantRole(List<XljkConsulter> consulterList) {
|
||||
try {
|
||||
// 1. 根据角色键查询角色信息
|
||||
SysRoleBo roleBo = new SysRoleBo();
|
||||
roleBo.setRoleKey("xljk_consultant");
|
||||
List<SysRoleVo> roleList = sysRoleService.selectRoleList(roleBo);
|
||||
|
||||
if (roleList == null || roleList.isEmpty()) {
|
||||
throw new ServiceException("未找到角色键为 'xljk_consultant' 的角色,请联系管理员创建该角色");
|
||||
}
|
||||
|
||||
Long roleId = roleList.get(0).getRoleId();
|
||||
|
||||
// 2. 为每个用户分配角色
|
||||
List<SysUserRole> userRoleList = new ArrayList<>();
|
||||
for (XljkConsulter consulter : consulterList) {
|
||||
// 检查用户是否已有该角色
|
||||
Long count = sysUserRoleMapper.selectCount(
|
||||
Wrappers.<SysUserRole>lambdaQuery()
|
||||
.eq(SysUserRole::getUserId, consulter.getUserId())
|
||||
.eq(SysUserRole::getRoleId, roleId)
|
||||
);
|
||||
|
||||
// 如果用户还没有该角色,则添加
|
||||
if (count == 0) {
|
||||
SysUserRole userRole = new SysUserRole();
|
||||
userRole.setUserId(consulter.getUserId());
|
||||
userRole.setRoleId(roleId);
|
||||
userRoleList.add(userRole);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 批量插入用户角色关联
|
||||
if (!userRoleList.isEmpty()) {
|
||||
sysUserRoleMapper.insertBatch(userRoleList);
|
||||
System.out.println("成功为 " + userRoleList.size() + " 个用户分配了 'xljk_consultant' 角色");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// 记录错误但不影响主流程
|
||||
System.err.println("为咨询师分配角色失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我配置的咨询师列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XljkConsulterVo> queryMyConfigList(XljkConsulterBo bo, PageQuery pageQuery) {
|
||||
bo.setConfigBy(LoginHelper.getUserId());
|
||||
return queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量启用咨询师
|
||||
*/
|
||||
@Override
|
||||
public Boolean enableConsulters(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.enableConsultersByIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量停用咨询师
|
||||
*/
|
||||
@Override
|
||||
public Boolean disableConsulters(List<Long> ids) {
|
||||
if (ids == null || ids.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return baseMapper.disableConsultersByIds(ids) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?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.xljk.mapper.XljkConsulterMapper">
|
||||
|
||||
<resultMap type="org.dromara.xljk.domain.vo.XljkConsulterVo" id="XljkConsulterVoResult">
|
||||
<result property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="userName" column="user_name"/>
|
||||
<result property="nickName" column="nick_name"/>
|
||||
<result property="deptId" column="dept_id"/>
|
||||
<result property="deptName" column="dept_name"/>
|
||||
<result property="phoneNumber" column="phone_number"/>
|
||||
<result property="office" column="office"/>
|
||||
<result property="email" column="email"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="configBy" column="config_by"/>
|
||||
<result property="configByName" column="config_by_name"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="createDept" column="create_dept"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectXljkConsulterVo">
|
||||
select id, user_id, user_name, nick_name, dept_id, dept_name, phone_number, office, email, status, remark, config_by, config_by_name, tenant_id, create_dept, create_by, create_time, update_by, update_time from xljk_consulter
|
||||
</sql>
|
||||
|
||||
<select id="selectXljkConsulterVoById" parameterType="Long" resultMap="XljkConsulterVoResult">
|
||||
<include refid="selectXljkConsulterVo"/>
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="selectXljkConsulterVoList" parameterType="org.dromara.xljk.domain.XljkConsulter" resultMap="XljkConsulterVoResult">
|
||||
<include refid="selectXljkConsulterVo"/>
|
||||
<where>
|
||||
<if test="userId != null">and user_id = #{userId}</if>
|
||||
<if test="userName != null and userName != ''">and user_name like concat('%', #{userName}, '%')</if>
|
||||
<if test="nickName != null and nickName != ''">and nick_name like concat('%', #{nickName}, '%')</if>
|
||||
<if test="deptId != null">and dept_id = #{deptId}</if>
|
||||
<if test="status != null and status != ''">and status = #{status}</if>
|
||||
<if test="configBy != null">and config_by = #{configBy}</if>
|
||||
<if test="params.beginCreateTime != null and params.beginCreateTime != '' and params.endCreateTime != null and params.endCreateTime != ''">
|
||||
and create_time between #{params.beginCreateTime} and #{params.endCreateTime}
|
||||
</if>
|
||||
</where>
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 检查用户是否已存在 -->
|
||||
<select id="checkUserExists" resultType="int">
|
||||
SELECT COUNT(1) FROM xljk_consulter WHERE user_id = #{userId} AND deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 批量启用咨询师 -->
|
||||
<update id="enableConsultersByIds">
|
||||
UPDATE xljk_consulter SET status = '1' WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 批量停用咨询师 -->
|
||||
<update id="disableConsultersByIds">
|
||||
UPDATE xljk_consulter SET status = '0' WHERE id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 查询完整的用户信息(包含部门信息)用于批量添加 -->
|
||||
<select id="selectUsersWithDeptInfo" resultType="org.dromara.xljk.domain.XljkUserWithDeptInfo">
|
||||
SELECT
|
||||
u.user_id as userId,
|
||||
u.user_name as userName,
|
||||
u.nick_name as nickName,
|
||||
u.dept_id as deptId,
|
||||
d.dept_name as deptName,
|
||||
u.phonenumber as phonenumber,
|
||||
u.email as email,
|
||||
u.status as status
|
||||
FROM sys_user u
|
||||
LEFT JOIN sys_dept d ON u.dept_id = d.dept_id
|
||||
WHERE u.user_id IN
|
||||
<foreach collection="userIds" item="userId" open="(" separator="," close=")">
|
||||
#{userId}
|
||||
</foreach>
|
||||
AND u.del_flag = '0'
|
||||
AND u.status = '0'
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+14
-1
@@ -151,6 +151,19 @@ public class XskhDisciplineRecordController extends BaseController {
|
||||
@RequestParam String disciplineTypeIds,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime) {
|
||||
return R.ok(xskhDisciplineRecordService.getStudentDisciplineRecords(studentId, disciplineTypeIds, startTime, endTime));
|
||||
return R.ok(xskhDisciplineRecordService.getStudentDisciplineRecords(studentId, disciplineTypeIds, startTime,
|
||||
endTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
|
||||
*/
|
||||
@SaCheckPermission("disciplineRecord:disciplineRecord:query")
|
||||
@GetMapping("/getMaxScoreByTypeAndPeriod/{typeId}")
|
||||
public R<java.math.BigDecimal> getMaxScoreByTypeAndPeriod(
|
||||
@NotNull(message = "违纪类型ID不能为空") @PathVariable Long typeId,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime) {
|
||||
return R.ok(xskhDisciplineRecordService.getMaxScoreByTypeAndPeriod(typeId, startTime, endTime));
|
||||
}
|
||||
}
|
||||
+12
@@ -143,4 +143,16 @@ public class XskhRewardRecordController extends BaseController {
|
||||
@RequestParam String endTime) {
|
||||
return R.ok(xskhRewardRecordService.getStudentRewardRecords(studentId, rewardTypeIds, startTime, endTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
|
||||
*/
|
||||
@SaCheckPermission("rewardRecord:rewardRecord:query")
|
||||
@GetMapping("/getMaxScoreByTypeAndPeriod/{typeId}")
|
||||
public R<java.math.BigDecimal> getMaxScoreByTypeAndPeriod(
|
||||
@NotNull(message = "奖励类型ID不能为空") @PathVariable Long typeId,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime) {
|
||||
return R.ok(xskhRewardRecordService.getMaxScoreByTypeAndPeriod(typeId, startTime, endTime));
|
||||
}
|
||||
}
|
||||
+12
@@ -69,4 +69,16 @@ public interface XskhDisciplineRecordMapper extends BaseMapperPlus<XskhDisciplin
|
||||
*/
|
||||
int deleteHygieneCheckViolationByDisciplineRecordId(@Param("disciplineRecordId") Long disciplineRecordId);
|
||||
|
||||
/**
|
||||
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
|
||||
*
|
||||
* @param typeId 违纪类型ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 最高总扣分
|
||||
*/
|
||||
java.math.BigDecimal selectMaxScoreByTypeAndPeriod(@Param("typeId") Long typeId,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
}
|
||||
+12
@@ -51,4 +51,16 @@ public interface XskhRewardRecordMapper extends BaseMapperPlus<XskhRewardRecord,
|
||||
@Param("rewardTypeIds") List<Long> rewardTypeIds,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
/**
|
||||
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
|
||||
*
|
||||
* @param typeId 奖励类型ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 最高总加分
|
||||
*/
|
||||
java.math.BigDecimal selectMaxScoreByTypeAndPeriod(@Param("typeId") Long typeId,
|
||||
@Param("startTime") String startTime,
|
||||
@Param("endTime") String endTime);
|
||||
}
|
||||
+10
@@ -91,4 +91,14 @@ public interface IXskhDisciplineRecordService {
|
||||
*/
|
||||
List<XskhDisciplineRecordVo> getStudentDisciplineRecords(Long studentId, String disciplineTypeIds, String startTime,
|
||||
String endTime);
|
||||
|
||||
/**
|
||||
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
|
||||
*
|
||||
* @param typeId 违纪类型ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 最高总扣分
|
||||
*/
|
||||
java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime);
|
||||
}
|
||||
+10
@@ -104,4 +104,14 @@ public interface IXskhRewardRecordService {
|
||||
*/
|
||||
List<XskhRewardRecordVo> getStudentRewardRecords(Long studentId, String rewardTypeIds, String startTime,
|
||||
String endTime);
|
||||
|
||||
/**
|
||||
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
|
||||
*
|
||||
* @param typeId 奖励类型ID
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 最高总加分
|
||||
*/
|
||||
java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime);
|
||||
}
|
||||
+19
@@ -267,4 +267,23 @@ public class XskhDisciplineRecordServiceImpl implements IXskhDisciplineRecordSer
|
||||
|
||||
return baseMapper.selectStudentDisciplineRecords(studentId, typeIds, startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定违纪类型在指定时间范围内所有学生的最高总扣分
|
||||
*/
|
||||
@Override
|
||||
public java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime) {
|
||||
log.info("获取违纪类型 {} 在时间范围 {} - {} 内的最高总扣分", typeId, startTime, endTime);
|
||||
|
||||
java.math.BigDecimal maxScore = baseMapper.selectMaxScoreByTypeAndPeriod(typeId, startTime, endTime);
|
||||
|
||||
// 如果查询结果为null,返回0
|
||||
if (maxScore == null) {
|
||||
log.info("违纪类型 {} 在指定时间范围内无数据,返回0", typeId);
|
||||
return java.math.BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
log.info("违纪类型 {} 的最高总扣分为: {}", typeId, maxScore);
|
||||
return maxScore;
|
||||
}
|
||||
}
|
||||
+21
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 学生奖励记录Service业务层处理
|
||||
@@ -31,6 +32,7 @@ import java.util.Map;
|
||||
* @author ruoyi
|
||||
* @date 2025-01-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
|
||||
@@ -249,4 +251,23 @@ public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
|
||||
|
||||
return baseMapper.selectStudentRewardRecords(studentId, typeIds, startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定奖励类型在指定时间范围内所有学生的最高总加分
|
||||
*/
|
||||
@Override
|
||||
public java.math.BigDecimal getMaxScoreByTypeAndPeriod(Long typeId, String startTime, String endTime) {
|
||||
log.info("获取奖励类型 {} 在时间范围 {} - {} 内的最高总加分", typeId, startTime, endTime);
|
||||
|
||||
java.math.BigDecimal maxScore = baseMapper.selectMaxScoreByTypeAndPeriod(typeId, startTime, endTime);
|
||||
|
||||
// 如果查询结果为null,返回0
|
||||
if (maxScore == null) {
|
||||
log.info("奖励类型 {} 在指定时间范围内无数据,返回0", typeId);
|
||||
return java.math.BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
log.info("奖励类型 {} 的最高总加分为: {}", typeId, maxScore);
|
||||
return maxScore;
|
||||
}
|
||||
}
|
||||
+17
@@ -134,4 +134,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
and deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 获取指定违纪类型在指定时间范围内所有学生的最高总扣分 -->
|
||||
<select id="selectMaxScoreByTypeAndPeriod" resultType="java.math.BigDecimal">
|
||||
<![CDATA[
|
||||
SELECT MAX(student_total_score) as max_score
|
||||
FROM (
|
||||
SELECT student_id, SUM(score_deduction) as student_total_score
|
||||
FROM xskh_discipline_record
|
||||
WHERE discipline_type_id = #{typeId}
|
||||
AND discipline_date >= #{startTime}
|
||||
AND discipline_date <= #{endTime}
|
||||
AND status = '1'
|
||||
AND deleted = 0
|
||||
GROUP BY student_id
|
||||
) student_scores
|
||||
]]>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
+17
@@ -151,4 +151,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
order by create_time desc
|
||||
</select>
|
||||
|
||||
<!-- 获取指定奖励类型在指定时间范围内所有学生的最高总加分 -->
|
||||
<select id="selectMaxScoreByTypeAndPeriod" resultType="java.math.BigDecimal">
|
||||
<![CDATA[
|
||||
SELECT MAX(student_total_score) as max_score
|
||||
FROM (
|
||||
SELECT student_id, SUM(score_addition) as student_total_score
|
||||
FROM xskh_reward_record
|
||||
WHERE reward_type_id = #{typeId}
|
||||
AND reward_date >= #{startTime}
|
||||
AND reward_date <= #{endTime}
|
||||
AND status = '1'
|
||||
AND deleted = 0
|
||||
GROUP BY student_id
|
||||
) student_scores
|
||||
]]>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Loaded 100 of 164 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user