+385
@@ -0,0 +1,385 @@
|
||||
package com.yunhai.campusnotice.controller.api;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.yunhai.campusnotice.config.Config;
|
||||
import com.yunhai.campusnotice.common.validation.ValidationGroups;
|
||||
import com.yunhai.campusnotice.model.BasePageResult;
|
||||
import com.yunhai.campusnotice.model.notice.*;
|
||||
import com.yunhai.campusnotice.service.INoticeService;
|
||||
import com.yunhai.campusnotice.utils.OtherUtil;
|
||||
import com.yunhai.campusnotice.utils.PageUtils;
|
||||
import com.yunhai.platform.apistd.BizException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.print.attribute.standard.MediaSize;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通知公告接口(合并 NoticeApiController + 旧 NoticeController)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/notice/"}(platform = api / manage / mobiapi)。
|
||||
* 方法动词式 PascalCase(对齐 UserBase);写操作一律 POST。
|
||||
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/notice/")
|
||||
public class NoticeController {
|
||||
|
||||
@Autowired
|
||||
private INoticeService noticeService;
|
||||
// ============================ 收件箱列表 ============================
|
||||
|
||||
/**
|
||||
* 已收通知列表(用户端)。
|
||||
*/
|
||||
@GetMapping("List")
|
||||
public NoticePageResult<NoticeVo> list(NoticeQuery query,
|
||||
@SortDefault(sort = {"topmost", "createTime"},
|
||||
direction = Sort.Direction.DESC) Sort sort) {
|
||||
return noticeService.userList(query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 已发/全部通知列表 ============================
|
||||
|
||||
/**
|
||||
* 已发/全部通知列表(管理端)。type=user 只看自己。
|
||||
*/
|
||||
@GetMapping("SendList")
|
||||
public BasePageResult<NoticeVo> sendList(NoticeQuery query,
|
||||
@SortDefault(sort = "createTime",
|
||||
direction = Sort.Direction.DESC) Sort sort) {
|
||||
return noticeService.adminList(query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 查看详情(标读) ============================
|
||||
|
||||
/**
|
||||
* 查看通知详情(type=1 普通查看标记已读, type=0 编辑模式不标记已读)。
|
||||
*/
|
||||
@GetMapping("Detail")
|
||||
public NoticeDetailVo detail(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "type", defaultValue = "1") Integer type) {
|
||||
return noticeService.detailMap(serid, type);
|
||||
}
|
||||
|
||||
// ============================ 编辑回显(不标读) ============================
|
||||
|
||||
/**
|
||||
* 获取通知详情(编辑/转发用,不标记已读)。
|
||||
*/
|
||||
@GetMapping("GetDetail")
|
||||
public NoticeDetailVo getDetail(@RequestParam("serid") Integer serid) {
|
||||
return noticeService.getDetailMap(serid);
|
||||
}
|
||||
|
||||
// ============================ 新建 ============================
|
||||
|
||||
/**
|
||||
* 新建通知(JSON body)。fileIds 为附件ID逗号串,smsFlag 为短信标记。
|
||||
*/
|
||||
@PostMapping("Create")
|
||||
public Integer create(@RequestBody @Validated(ValidationGroups.Create.class) NoticeRequest request) {
|
||||
return noticeService.publish(request);
|
||||
}
|
||||
|
||||
// ============================ 编辑 ============================
|
||||
|
||||
/**
|
||||
* 编辑通知(JSON body,含 id)。
|
||||
*/
|
||||
@PostMapping("Edit")
|
||||
public void edit(@RequestBody @Validated(ValidationGroups.Update.class) NoticeRequest request) {
|
||||
noticeService.edit(request.getSourceId() != null ? request.getSourceId() : 0, request);
|
||||
}
|
||||
|
||||
// ============================ 批量删除 ============================
|
||||
|
||||
/**
|
||||
* 批量删除通知(ids 数组)。
|
||||
*/
|
||||
@PostMapping("Delete")
|
||||
public void delete(@RequestBody List<Integer> ids) {
|
||||
noticeService.deleteBatch(ids);
|
||||
}
|
||||
|
||||
// ============================ 撤回 ============================
|
||||
|
||||
/**
|
||||
* 撤回通知。
|
||||
*/
|
||||
@PostMapping("UserPull")
|
||||
public void userPull(@RequestParam("serid") Integer serid) {
|
||||
noticeService.pull(serid);
|
||||
}
|
||||
|
||||
// ============================ 置顶 ============================
|
||||
|
||||
/**
|
||||
* 置顶/取消置顶。
|
||||
*/
|
||||
@PostMapping("SetTopmost")
|
||||
public void setTopmost(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "topmost", defaultValue = "1") Integer topmost) {
|
||||
noticeService.setTopmost(serid, topmost);
|
||||
}
|
||||
|
||||
// ============================ 追加接收人 ============================
|
||||
|
||||
/**
|
||||
* 追加接收人。
|
||||
*/
|
||||
@PostMapping("ReceiveUsers")
|
||||
public void receiveUsers(@RequestParam("serid") Integer serid,
|
||||
@RequestParam("users") String users) {
|
||||
noticeService.receiveUsers(serid, users);
|
||||
}
|
||||
|
||||
// ============================ 催收 ============================
|
||||
|
||||
/**
|
||||
* 催收未读。
|
||||
*/
|
||||
@PostMapping("Expedite")
|
||||
public void expedite(@RequestParam("serid") Integer serid) {
|
||||
noticeService.expedite(serid);
|
||||
}
|
||||
|
||||
// ============================ 一键已读 ============================
|
||||
|
||||
/**
|
||||
* 一键全部已读(POST 化,原为 GET 写操作)。
|
||||
*/
|
||||
@PostMapping("InitializeRed")
|
||||
public InitializeRedVo initializeRed() {
|
||||
return noticeService.initializeRedResult();
|
||||
}
|
||||
|
||||
// ============================ 阅读情况 ============================
|
||||
|
||||
/**
|
||||
* 阅读情况(按已读/未读分组)。
|
||||
*/
|
||||
@GetMapping("ReadDetail")
|
||||
public List<Map<String, Object>> readDetail(@RequestParam("serid") Integer serid) {
|
||||
return noticeService.getReadDetailGrouped(serid);
|
||||
}
|
||||
|
||||
// ============================ 上一篇/下一篇 ============================
|
||||
|
||||
/**
|
||||
* 上一篇/下一篇通知ID。
|
||||
*/
|
||||
@GetMapping("GetNextPrev")
|
||||
public Map<String, Object> getNextPrev(@RequestParam("serid") Integer serid,
|
||||
@RequestParam("type") String type) {
|
||||
return noticeService.getNextPrev(serid, type);
|
||||
}
|
||||
|
||||
// ============================ 附件打包下载 ============================
|
||||
|
||||
/**
|
||||
* 批量下载通知全部附件(打包 zip)。
|
||||
*/
|
||||
@GetMapping("AllFileDown")
|
||||
public void allFileDown(@RequestParam("dataid") Integer dataid,
|
||||
HttpServletResponse response) {
|
||||
noticeService.downloadAllFiles(dataid, response);
|
||||
}
|
||||
|
||||
// ============================ 统计 ============================
|
||||
|
||||
/**
|
||||
* 通知统计。
|
||||
*/
|
||||
@GetMapping("Statis")
|
||||
public NoticeStatisticsVo statis(
|
||||
@RequestParam(value = "starttime", required = false)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
|
||||
@RequestParam(value = "endtime", required = false)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
|
||||
return noticeService.statistics(new NoticeQuery(), start, end);
|
||||
}
|
||||
|
||||
// ============================ 转发(合并旧 REST 壳 forward) ============================
|
||||
|
||||
/**
|
||||
* 转发通知(基于源通知创建新通知)。sourceId 在 request body 中传递。
|
||||
*/
|
||||
@PostMapping("Forward")
|
||||
public Integer forward(@RequestBody @Validated(ValidationGroups.Create.class) NoticeRequest request) {
|
||||
return noticeService.forward(request.getSourceId(), request);
|
||||
}
|
||||
|
||||
// ============================ 推送范围树(新版发布表单,改造方案 3.1) ============================
|
||||
|
||||
/**
|
||||
* 当前学校学员推送范围树:全校根 + 学段→年级→班级(数据源 bschclass),
|
||||
* 供表单「推送范围」胶囊按钮渲染。节点结构:{scopeType, scopeId, name, children}。
|
||||
*/
|
||||
@GetMapping("ScopeTree")
|
||||
public List<Map<String, Object>> scopeTree() {
|
||||
return noticeService.scopeTree();
|
||||
}
|
||||
|
||||
// ============================ 推送范围预估 ============================
|
||||
|
||||
/**
|
||||
* 按已选范围预估接收人数(学员 = 范围展开去重账号数 + 教师 = receiveList 定向名单数)。
|
||||
* scopes 为 JSON 数组:[{"scopeType":3,"scopeId":5,"scopeName":"初一"}]
|
||||
*/
|
||||
@GetMapping("ScopePreview")
|
||||
public ScopePreviewVo scopePreview(@RequestParam(value = "scopes", required = false) String scopes,
|
||||
@RequestParam(value = "receiveList", required = false) String receiveList) {
|
||||
return noticeService.scopePreview(parseScopes(scopes), receiveList);
|
||||
}
|
||||
|
||||
// ============================ 存为草稿 ============================
|
||||
|
||||
/**
|
||||
* 存为草稿(status=0):不圈人、不发短信、不落接收人,仅存内容 + 范围快照 + 附件。
|
||||
*/
|
||||
@PostMapping("SaveDraft")
|
||||
public Integer saveDraft(@RequestBody NoticeRequest request) {
|
||||
return noticeService.saveDraft(request);
|
||||
}
|
||||
|
||||
// ============================ 草稿箱列表 ============================
|
||||
|
||||
/**
|
||||
* 草稿箱列表(status=0 本人草稿):重要程度 type/typeDesc、定时标注与 timingSendTime。
|
||||
*/
|
||||
@GetMapping("DraftList")
|
||||
public BasePageResult<NoticeVo> draftList(NoticeQuery query,
|
||||
@SortDefault(sort = "updateTime",
|
||||
direction = Sort.Direction.DESC) Sort sort) {
|
||||
return noticeService.draftList(query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 已发送阅读回执 ============================
|
||||
|
||||
/**
|
||||
* 已发送通知阅读回执:按 年级→班级→学生 分组返回(身份快照),
|
||||
* 学生带已读/未读状态与阅读时间(前端着色),教师接收行归「教师」组。
|
||||
*/
|
||||
@GetMapping("ReadReceipt")
|
||||
public ReadReceiptVo readReceipt(@RequestParam("serid") Integer serid) {
|
||||
return noticeService.readReceipt(serid);
|
||||
}
|
||||
|
||||
// ============================ 审批人记忆回显 ============================
|
||||
|
||||
/**
|
||||
* 审批人记忆回显:当前发布人最近一次所选审批人组合(无记忆返回空)。
|
||||
*/
|
||||
@GetMapping("ApproverSuggest")
|
||||
public ApproverSuggestVo approverSuggest() {
|
||||
return noticeService.approverSuggest();
|
||||
}
|
||||
|
||||
// ============================ 审批教师绑定(教师树ID→姓名/头像) ============================
|
||||
|
||||
/**
|
||||
* 审批教师绑定:按学校教师列表(bschclass)绑定教师树选中ID → 姓名/头像。
|
||||
* ids=101,102(教师树叶子节点ID);schId 缺省取当前登录人学校;
|
||||
* 未命中的ID保留、name 为 null,由前端提示。
|
||||
*/
|
||||
@GetMapping("ApproverResolve")
|
||||
public List<ApproverResolveVo> approverResolve(
|
||||
@RequestParam(value = "ids", required = false) String ids,
|
||||
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||
if (ids == null || ids.trim().isEmpty()) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "ids 不允许为空");
|
||||
}
|
||||
return noticeService.approverResolve(Arrays.asList(OtherUtil.convertToArray(ids)), schId);
|
||||
}
|
||||
|
||||
// ============================ 提交审批(多步流程) ============================
|
||||
|
||||
/**
|
||||
* 提交审批(status: 0/3→2):steps 多步审批流 [{name, vote, approvers:[登录账号]}] 优先,
|
||||
* 缺省时旧 approverTeaIds 包装为单步或签。步骤落 notice_approval_step,
|
||||
* 处理动作落 notice_approval_record,并 upsert 审批人记忆表。
|
||||
*/
|
||||
@PostMapping("Submit")
|
||||
public void submit(@RequestBody SubmitRequest request) {
|
||||
noticeService.submit(request);
|
||||
}
|
||||
|
||||
// ============================ 审批通过(当前步) ============================
|
||||
|
||||
/**
|
||||
* 审批通过:或签任一通过/会签全部通过后流转下一步,末步通过即真实发布;
|
||||
* 被他人先审或已处理过时返回冲突提示。兼容 form 提交(serid/opinion)。
|
||||
*/
|
||||
@PostMapping("Approve")
|
||||
public void approve(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "opinion", required = false) String opinion) {
|
||||
noticeService.approve(serid, opinion);
|
||||
}
|
||||
|
||||
// ============================ 审批驳回(当前步) ============================
|
||||
|
||||
/**
|
||||
* 审批驳回:任一步驳回即 status→3,意见必填(remark 为前端别名);发布人可改后重新提交。
|
||||
*/
|
||||
@PostMapping("Reject")
|
||||
public void reject(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "opinion", required = false) String opinion,
|
||||
@RequestParam(value = "remark", required = false) String remark) {
|
||||
noticeService.reject(serid, StringUtils.hasText(opinion) ? opinion : remark);
|
||||
}
|
||||
|
||||
// ============================ 审批列表(待审/已审合一) ============================
|
||||
|
||||
/**
|
||||
* 审批列表:auditState/status=pending(默认) 待我审批 / approved 走流程已发布 /
|
||||
* rejected 已驳回 / all|reviewed 已审合一。行 VO 为 NoticeVo,多步审批字段:
|
||||
* approvalStatus/approvalStatusDesc(进度文本)/approvalLevel/canApprove。
|
||||
*/
|
||||
@GetMapping("ApprovalList")
|
||||
public BasePageResult<NoticeVo> approvalList(
|
||||
@RequestParam(value = "auditState", required = false) String auditState,
|
||||
@RequestParam(value = "status", required = false) String status,
|
||||
NoticeQuery query,
|
||||
@SortDefault(sort = "updateTime", direction = Sort.Direction.DESC) Sort sort) {
|
||||
return noticeService.approvalList(
|
||||
StringUtils.hasText(auditState) ? auditState : status, query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 待我审批数量(菜单角标) ============================
|
||||
|
||||
/**
|
||||
* 待我审批数量:待审批且当前步审批人快照含当前登录人(账号或教师ID)。
|
||||
*/
|
||||
@GetMapping("ApprovalCount")
|
||||
public int approvalCount() {
|
||||
return noticeService.approvalCount();
|
||||
}
|
||||
|
||||
/** 解析 scopes JSON 参数为范围列表(空/非法返回 null = 无范围) */
|
||||
private List<PushScopeItem> parseScopes(String scopes) {
|
||||
if (scopes == null || scopes.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new ObjectMapper().readValue(scopes, new TypeReference<List<PushScopeItem>>() {
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "scopes 参数格式错误,应为 JSON 数组:[{\"scopeType\":3,\"scopeId\":5}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
package com.yunhai.campusnotice.service;
|
||||
|
||||
import com.yunhai.campusnotice.entity.Notice;
|
||||
import com.yunhai.campusnotice.model.BasePageResult;
|
||||
import com.yunhai.campusnotice.model.notice.*;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通知公告业务接口。
|
||||
*/
|
||||
public interface INoticeService {
|
||||
|
||||
/**
|
||||
* 发通知:以当前登录用户为发布人入库。
|
||||
* 按 request.publishType 分流(改造方案 4.1):
|
||||
* direct/空 = 直接发布(兼容旧 Create 链路;携带未来 timingSendTime 时置 status=1 待调度);
|
||||
* draft = 存为草稿;approve = 提交审批(request.approverTeaIds 选教师,或签)。
|
||||
*
|
||||
* @return 新建通知 ID(用于后续回填附件 TopicID 等)
|
||||
*/
|
||||
Integer publish(NoticeRequest request);
|
||||
|
||||
/**
|
||||
* 存为草稿(status=0):仅存内容 + 范围快照 + 附件,不圈人、不发短信、不落接收人。
|
||||
*/
|
||||
Integer saveDraft(NoticeRequest request);
|
||||
|
||||
/**
|
||||
* 草稿箱列表(status=0,本人草稿):返回重要程度 type/typeDesc、定时标注与 timingSendTime。
|
||||
*/
|
||||
BasePageResult<NoticeVo> draftList(NoticeQuery query, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 提交审批(status: 0/3 → 2):request.steps 多步审批流([{name, vote, approvers:[登录账号]}])
|
||||
* 优先;缺省时旧 approverTeaIds 包装为单步或签(兼容链路)。
|
||||
* 步骤落 notice_approval_step,处理动作落 notice_approval_record。
|
||||
*/
|
||||
void submit(SubmitRequest request);
|
||||
|
||||
/**
|
||||
* 审批通过:当前步审批人处理;或签任一通过/会签全部通过后流转下一步,
|
||||
* 末步通过 status: 2→1(CAS)并触发真实发布。已被他人先行处理时抛业务冲突提示。
|
||||
*/
|
||||
void approve(Integer serid, String opinion);
|
||||
|
||||
/**
|
||||
* 审批驳回:任一步驳回即 status: 2→3(CAS),记录意见;发布人可改后重新提交。
|
||||
*/
|
||||
void reject(Integer serid, String opinion);
|
||||
|
||||
/**
|
||||
* 审批列表:pending(默认)=待我审批 status=2;approved=走流程已发布;rejected=已驳回;
|
||||
* all/reviewed=已审合一。行 VO 为 NoticeVo(多步审批字段:approvalStatus/approvalStatusDesc/
|
||||
* approvalLevel/canApprove)。
|
||||
*/
|
||||
BasePageResult<NoticeVo> approvalList(String auditState, NoticeQuery query, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 待我审批数量(菜单角标):待审批且当前步审批人快照含当前登录人。
|
||||
*/
|
||||
int approvalCount();
|
||||
|
||||
/**
|
||||
* 审批人记忆回显:当前发布人最近一次所选审批教师ID组合,无记忆返回空。
|
||||
*/
|
||||
ApproverSuggestVo approverSuggest();
|
||||
|
||||
/**
|
||||
* 审批教师绑定:按学校教师列表(bschclass)绑定教师树选中ID → 姓名/头像。
|
||||
* schId 为空取当前登录人学校;未命中的ID保留、name 为 null 由调用方提示。
|
||||
*/
|
||||
List<ApproverResolveVo> approverResolve(List<Integer> ids, Integer schId);
|
||||
|
||||
/**
|
||||
* 编辑通知:草稿/已驳回/已发布(旧链路,无推送范围)可编辑;
|
||||
* 待审批禁止编辑;新版表单已发布(存在范围快照)禁止编辑(先撤回后重发)。
|
||||
*/
|
||||
void edit(Integer id, NoticeRequest request);
|
||||
|
||||
/**
|
||||
* 批量删除通知:仅草稿、已驳回、已发布(本人)可删,待审批不可删;
|
||||
* 级联清理阅读记录、接收人、推送范围、审批记录、附件关联。
|
||||
*/
|
||||
void deleteBatch(List<Integer> ids);
|
||||
|
||||
/**
|
||||
* 撤回通知:仅已发布且未撤回的通知可撤回,置 isPulled=1。
|
||||
*/
|
||||
void pull(Integer id);
|
||||
|
||||
/**
|
||||
* 置顶/取消置顶。
|
||||
*/
|
||||
void setTopmost(Integer id, Integer topmost);
|
||||
|
||||
/**
|
||||
* 转发通知:基于源通知创建新通知(已发布),parentId 关联源通知。
|
||||
*/
|
||||
Integer forward(Integer sourceId, NoticeRequest request);
|
||||
|
||||
/**
|
||||
* 用户端列表:仅展示已发布、已到点、且对当前账号可见的通知。
|
||||
* 可见性(改造方案 3.2):无推送范围维持「全校广播」现状;
|
||||
* 存在范围的通知须 notice_receiver 快照命中当前账号(学员 receive_type=2 / 教师 receive_type=1)。
|
||||
*/
|
||||
NoticePageResult<NoticeVo> userList(NoticeQuery query, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 管理端列表:按条件查询全部通知(管理员查看全部)。
|
||||
*/
|
||||
BasePageResult<NoticeVo> adminList(NoticeQuery query, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 学员推送范围树(学段→年级→班级 + 全校根,数据源 bschclass),
|
||||
* 供表单「推送范围」胶囊按钮渲染。
|
||||
*/
|
||||
List<Map<String, Object>> scopeTree();
|
||||
|
||||
/**
|
||||
* 按已选范围预估接收人数(学员=范围展开去重账号数 + 教师=receiveList 定向名单数)。
|
||||
*/
|
||||
ScopePreviewVo scopePreview(List<PushScopeItem> scopes, String receiveList);
|
||||
|
||||
/**
|
||||
* 已发送通知阅读回执:按 年级→班级→学生 分组返回(身份快照),
|
||||
* 学生带已读/未读状态与阅读时间(前端着色),教师接收行归「教师」组。
|
||||
*/
|
||||
ReadReceiptVo readReceipt(Integer serid);
|
||||
|
||||
/**
|
||||
* 通知详情:返回视图对象,并顺带为当前用户标记已读(打开即视为已读)。
|
||||
* 草稿/待审批/已驳回态仅发布人本人或该轮审批人可打开(改造方案 3.2 访问校验补口)。
|
||||
*/
|
||||
NoticeVo detail(Integer id);
|
||||
|
||||
/**
|
||||
* 编辑回显详情(不标记已读,访问校验同 {@link #detail})。
|
||||
*/
|
||||
NoticeVo getDetail(Integer id);
|
||||
|
||||
/**
|
||||
* 标记已读:为当前用户写入(幂等)该通知的阅读记录,
|
||||
* 学员阅读时按接收快照(缺失时 bschclass 实时兜底)写入学校/年级/班级身份快照。
|
||||
*/
|
||||
void markRead(Integer id);
|
||||
|
||||
/**
|
||||
* 一键全部已读(批量化):当前用户所有可见的已发布通知批量插入阅读记录。
|
||||
*
|
||||
* @return 已读条数
|
||||
*/
|
||||
int initializeRed();
|
||||
|
||||
/**
|
||||
* 追加接收人(事务化):并入接收人列表并重算 allowcount(范围通知含学员数)。
|
||||
*/
|
||||
void receiveUsers(Integer noticeId, String users);
|
||||
|
||||
/**
|
||||
* 上一篇/下一篇通知ID(SQL 相邻查询)。
|
||||
*
|
||||
* @param serid 当前通知ID
|
||||
* @param type 0 已发(当前用户发布的序列)/ 1 已收(阅读记录序列)
|
||||
* @return {prevId, nextId}
|
||||
*/
|
||||
Map<String, Object> getNextPrev(Integer serid, String type);
|
||||
|
||||
/**
|
||||
* 获取某通知的阅读明细列表。
|
||||
*/
|
||||
List<NoticeVo.ReadDetail> getReadDetail(Integer noticeId);
|
||||
|
||||
/**
|
||||
* 阅读情况分组(已读/未读,旧接口保留过渡;新版表单走 {@link #readReceipt})。
|
||||
*/
|
||||
List<Map<String, Object>> getReadDetailGrouped(Integer serid);
|
||||
|
||||
/**
|
||||
* 催收未读:仅 receiptFlag=1 的通知可用;
|
||||
* 催收对象优先 notice_receiver 快照(含学员),回退 receiveList JSON(历史数据)。
|
||||
*/
|
||||
void expedite(Integer serid);
|
||||
|
||||
/**
|
||||
* 定时发送调度(TimingPublishJob 每分钟触发):
|
||||
* 扫描 status=1 且 timingSendTime<=now 且 timing_published=0 的通知,
|
||||
* 逐条 CAS 抢占(幂等)后执行真实发布。
|
||||
*
|
||||
* @return 本次真实发布条数
|
||||
*/
|
||||
int timingPublishDue();
|
||||
|
||||
/**
|
||||
* 通知统计:总数/已发布、累计阅读人次、当前用户未读、按发布人、按月。
|
||||
*/
|
||||
NoticeStatisticsVo statistics(NoticeQuery query, LocalDateTime start, LocalDateTime end);
|
||||
|
||||
/**
|
||||
* 通知详情视图(含附件、接收人、推送范围、审批轨迹),供 Controller 返回。
|
||||
*/
|
||||
NoticeDetailVo getDetailMap(Integer serid);
|
||||
|
||||
/**
|
||||
* 已发列表附件批量查询(消除 N+1)。
|
||||
*/
|
||||
Map<Integer, List<Integer>> batchFileIds(List<Integer> noticeIds);
|
||||
|
||||
/**
|
||||
* 查看通知详情视图(含附件、接收人)。
|
||||
* type=1 时先标记已读再返回,type=0 时直接返回不标记。
|
||||
*/
|
||||
NoticeDetailVo detailMap(Integer serid, Integer type);
|
||||
|
||||
/**
|
||||
* 一键全部已读并返回结果(count = 已读条数)。
|
||||
*/
|
||||
InitializeRedVo initializeRedResult();
|
||||
|
||||
/**
|
||||
* 批量下载通知全部附件(打包 zip):查通知标题后调文件域打包下载。
|
||||
*/
|
||||
void downloadAllFiles(Integer dataid, HttpServletResponse response);
|
||||
}
|
||||
+2786
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
package com.yunhai.campusnotice.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知审核记录表 notice_approval_record。
|
||||
* <p>
|
||||
* 每位审批人在每一步的通过/驳回动作各落一行(会签逐步留痕),含步骤名/表决方式快照,
|
||||
* 驳回重提产生新一轮(round 递增),历史轮次永久保留。唯一约束防同一人同轮同步重复处理。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "notice_approval_record",
|
||||
indexes = @Index(name = "idx_approval_record_notice", columnList = "notice_id"),
|
||||
uniqueConstraints = @UniqueConstraint(
|
||||
name = "uk_approval_record_round_step_account",
|
||||
columnNames = {"notice_id", "round", "step_no", "approver_account"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class NoticeApprovalRecord extends BaseEntity {
|
||||
|
||||
/** 审批动作:1 通过 / 2 驳回 */
|
||||
public static final int ACTION_APPROVE = 1;
|
||||
public static final int ACTION_REJECT = 2;
|
||||
|
||||
/** 通知ID(关联 notice.id) */
|
||||
@Column(name = "notice_id", nullable = false)
|
||||
private Integer noticeId;
|
||||
|
||||
/** 送审轮次(1 起,每次提交审批递增) */
|
||||
@Column(name = "round", nullable = false)
|
||||
private Integer round;
|
||||
|
||||
/** 步骤序号(1 起) */
|
||||
@Column(name = "step_no", nullable = false)
|
||||
private Integer stepNo;
|
||||
|
||||
/** 步骤名称快照 */
|
||||
@Column(name = "step_name", length = 64)
|
||||
private String stepName;
|
||||
|
||||
/** 步骤表决方式快照:any 或签 / all 会签 */
|
||||
@Column(name = "vote", length = 8)
|
||||
private String vote;
|
||||
|
||||
/** 审批人登录账号 */
|
||||
@Column(name = "approver_account", length = 64, nullable = false)
|
||||
private String approverAccount;
|
||||
|
||||
/** 审批人姓名 */
|
||||
@Column(name = "approver_name", length = 64)
|
||||
private String approverName;
|
||||
|
||||
/** 审批人同步教师ID(用户中心 teaId,与 notice_approval_step.approver_tea_ids 同一 ID 空间;v15 新增) */
|
||||
@Column(name = "approver_tea_id")
|
||||
private Integer approverTeaId;
|
||||
|
||||
/** 审批动作:1 通过 / 2 驳回 */
|
||||
@Column(name = "action", nullable = false)
|
||||
private Integer action;
|
||||
|
||||
/** 审批意见 */
|
||||
@Column(name = "opinion", length = 1000)
|
||||
private String opinion;
|
||||
|
||||
/** 操作时间 */
|
||||
@Column(name = "action_time")
|
||||
private LocalDateTime actionTime;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.yunhai.campusnotice.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知审批步骤表 notice_approval_step。
|
||||
* <p>
|
||||
* 一次送审的有序多步流程快照:每步一个审批人组(会签=全部通过 / 或签=任一通过),
|
||||
* 依次流转,任一步驳回整单退回发布人。驳回重提时旧步骤行删除重建(当前流程定义),
|
||||
* 历史处理痕迹由 {@link NoticeApprovalRecord}(含步骤名/表决方式快照)永久保留。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "notice_approval_step",
|
||||
indexes = @Index(name = "idx_approval_step_notice", columnList = "notice_id"))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class NoticeApprovalStep extends BaseEntity {
|
||||
|
||||
/** 步骤状态:0 待流转 / 1 审批中 / 2 已通过 / 3 已驳回 */
|
||||
public static final int STATUS_WAITING = 0;
|
||||
public static final int STATUS_ACTIVE = 1;
|
||||
public static final int STATUS_APPROVED = 2;
|
||||
public static final int STATUS_REJECTED = 3;
|
||||
|
||||
/** 通知ID(关联 notice.id) */
|
||||
@Column(name = "notice_id", nullable = false)
|
||||
private Integer noticeId;
|
||||
|
||||
/** 步骤序号(1 起,按流转顺序) */
|
||||
@Column(name = "step_no", nullable = false)
|
||||
private Integer stepNo;
|
||||
|
||||
/** 步骤名称(如「校级审核」,前端未填时按「第N步」兜底) */
|
||||
@Column(name = "step_name", length = 64)
|
||||
private String stepName;
|
||||
|
||||
/** 表决方式:any 或签(任一通过)/ all 会签(全部通过) */
|
||||
@Column(name = "vote", length = 8, nullable = false)
|
||||
private String vote = "any";
|
||||
|
||||
/** 审批人登录账号快照 JSON ["zhd","lwj"] */
|
||||
@Column(name = "approver_accounts", columnDefinition = "LONGTEXT")
|
||||
private String approverAccounts;
|
||||
|
||||
/** 审批人教师ID快照 JSON [101,102](旧 teaId 链路兼容,账号不可得时允许为空) */
|
||||
@Column(name = "approver_tea_ids", columnDefinition = "LONGTEXT")
|
||||
private String approverTeaIds;
|
||||
|
||||
/** 审批人姓名快照 JSON(提交时点姓名,展示不受后续改名影响) */
|
||||
@Column(name = "approver_names", columnDefinition = "LONGTEXT")
|
||||
private String approverNames;
|
||||
|
||||
/** 状态:0 待流转 / 1 审批中 / 2 已通过 / 3 已驳回 */
|
||||
@Column(name = "status", nullable = false)
|
||||
private Integer status = STATUS_WAITING;
|
||||
|
||||
/** 步骤办结时间(通过/驳回落定时间) */
|
||||
@Column(name = "handle_time")
|
||||
private LocalDateTime handleTime;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.yunhai.campusnotice.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* 审批人池 sys_approver(审核设置页维护,发布选人数据源)。
|
||||
* <p>
|
||||
* 按学校维护可被选为审批人的名单(登录账号为身份主键),停用后不出现在
|
||||
* 「发公告」审批人候选池,已有流程不受影响。Submit 时按本校启用名单校验,
|
||||
* 防止表单传入池外账号。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "sys_approver",
|
||||
uniqueConstraints = @UniqueConstraint(
|
||||
name = "uk_approver_sch_account",
|
||||
columnNames = {"sch_id", "account"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SysApprover extends BaseEntity {
|
||||
|
||||
/** 学校ID(多租户隔离) */
|
||||
@Column(name = "sch_id", nullable = false)
|
||||
private Integer schId;
|
||||
|
||||
/** 登录账号(审批身份主键,Approve/Reject 按当前登录账号匹配) */
|
||||
@Column(name = "account", length = 64, nullable = false)
|
||||
private String account;
|
||||
|
||||
/** 姓名 */
|
||||
@Column(name = "name", length = 64)
|
||||
private String name;
|
||||
|
||||
/** 所属部门ID(发文部门字典 sys_dict) */
|
||||
@Column(name = "dept_id", length = 64)
|
||||
private String deptId;
|
||||
|
||||
/** 所属部门名称快照 */
|
||||
@Column(name = "dept_name", length = 128)
|
||||
private String deptName;
|
||||
|
||||
/** 教师用户ID(用户中心,兼容旧 teaId 链路,可空) */
|
||||
@Column(name = "tea_id")
|
||||
private Integer teaId;
|
||||
|
||||
/** 状态:0 停用 / 1 启用 */
|
||||
@Column(name = "enabled", nullable = false)
|
||||
private Integer enabled = 1;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.yunhai.campusnotice.job;
|
||||
|
||||
import com.yunhai.campusnotice.service.INoticeService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 历史审批身份回填(v15 一次性任务,默认不执行)。
|
||||
*
|
||||
* <p>背景:平台 {@code DefaultLoginUserProvider} 曾把登录名同时当作 displayName 落库,
|
||||
* 历史审批轨迹/审核记录里 {@code operator_name / approver_name / publisher_name} 全是登录名,
|
||||
* 且留痕表没有教师ID列。v15 已修写入链并补列,本任务负责把存量数据一次性换过来。</p>
|
||||
*
|
||||
* <p>触发方式(二选一,跑完即可去掉):</p>
|
||||
* <ul>
|
||||
* <li>IDEA 运行配置 VM options:{@code -Dcampus-notice.backfill-approver-identity=true}</li>
|
||||
* <li>环境变量:{@code CAMPUS_NOTICE_BACKFILL_APPROVER_IDENTITY=true}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>幂等:只改「姓名为空/等于登录名」与「teaId 为 NULL」的行,重复执行无副作用;
|
||||
* devtools 热重启时重复执行同样安全。</p>
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(name = "campus-notice.backfill-approver-identity", havingValue = "true")
|
||||
public class ApproverIdentityBackfillRunner implements ApplicationRunner {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApproverIdentityBackfillRunner.class);
|
||||
|
||||
@Autowired
|
||||
private INoticeService noticeService;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
try {
|
||||
Map<String, Integer> stat = noticeService.backfillApproverIdentity();
|
||||
log.info("[ApproverIdentityBackfill] 回填完成: {}", stat);
|
||||
} catch (Exception e) {
|
||||
// 回填失败不阻断应用启动;修正数据源(用户中心可达)后可再次执行
|
||||
log.error("[ApproverIdentityBackfill] 回填失败,请检查用户中心连通性后重跑", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.yunhai.campusnotice.model.notice;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 多步审批流步骤 VO(详情 approvalFlow / 编辑回显,对齐前端 ApprovalFlowStep 契约)。
|
||||
* <p>
|
||||
* status:approved 已通过 / pending 审批中 / rejected 已驳回 / waiting 待流转;
|
||||
* records 为该步全部审核动作(会签多人逐步留痕);pending 为当前步尚未处理姓名。
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.ALWAYS)
|
||||
public class ApprovalFlowVo {
|
||||
|
||||
/** 步骤名称 */
|
||||
private String name;
|
||||
|
||||
/** 表决方式:any 或签 / all 会签 */
|
||||
private String vote = "any";
|
||||
|
||||
/** 审批人账号(编辑回显用) */
|
||||
private List<String> approvers = new ArrayList<>();
|
||||
|
||||
/** 审批人教师ID(教师树选人回显用,如 api-test 测试台) */
|
||||
private List<Integer> approverTeaIds = new ArrayList<>();
|
||||
|
||||
/** 审批人姓名(展示用,与 approvers 顺序一致) */
|
||||
private List<String> approverNames = new ArrayList<>();
|
||||
|
||||
/** 步骤状态:approved / pending / rejected / waiting */
|
||||
private String status;
|
||||
|
||||
/** 该步审核记录 */
|
||||
private List<Record> records = new ArrayList<>();
|
||||
|
||||
/** 当前步待签人姓名(仅审批中步骤返回,其余为空列表) */
|
||||
private List<String> pending = new ArrayList<>();
|
||||
|
||||
/** 单步审核动作 */
|
||||
@Data
|
||||
public static class Record {
|
||||
|
||||
/** 审批人账号 */
|
||||
private String account;
|
||||
|
||||
/** 审批人姓名 */
|
||||
private String name;
|
||||
|
||||
/** 结果:approved 通过 / rejected 驳回 */
|
||||
private String result;
|
||||
|
||||
/** 操作时间(yyyy-MM-dd HH:mm:ss) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime time;
|
||||
|
||||
/** 审批意见 */
|
||||
private String remark;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yunhai.campusnotice.model.notice;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 审批中心标签页统计数字(v13-E3)。
|
||||
* <p>
|
||||
* 口径与 GET /api/notice/ApprovalList 各 tab 的默认过滤一致(不含 keyword 搜索条件):
|
||||
* pending=待审批(当前步审批人快照含当前登录人)/ approved=走审批流已发布 /
|
||||
* rejected=已驳回 / all=已通过+已驳回合一。
|
||||
*/
|
||||
@Data
|
||||
public class ApprovalTabCountVo {
|
||||
|
||||
/** 待审批(需我处理)条数 */
|
||||
private int pending;
|
||||
|
||||
/** 已通过(走流程发布)条数 */
|
||||
private int approved;
|
||||
|
||||
/** 已驳回条数 */
|
||||
private int rejected;
|
||||
|
||||
/** 全部(已审合一)条数 */
|
||||
private int all;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yunhai.campusnotice.model.notice;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 审批流程步骤入参(NoticeRequest.flow / SubmitRequest.steps 元素)。
|
||||
* <p>
|
||||
* 前端「发公告」多步审批流编辑器产出:每步一个审批人组(登录账号列表),
|
||||
* vote=any 或签(任一通过进入下一步)/ all 会签(全部通过进入下一步);
|
||||
* name 可缺省,后端按「第N步」兜底。
|
||||
*/
|
||||
@Data
|
||||
public class FlowStepItem {
|
||||
|
||||
/** 步骤名称(可空,缺省「第N步」) */
|
||||
private String name;
|
||||
|
||||
/** 表决方式:any 或签(默认)/ all 会签 */
|
||||
private String vote = "any";
|
||||
|
||||
/** 审批人登录账号列表(与审批人池配合;api-test 测试台走教师树时用 approverTeaIds) */
|
||||
private List<String> approvers = new ArrayList<>();
|
||||
|
||||
/** 审批人教师ID列表(教师树叶子节点ID;与 approvers 二选一,按学校教师名单绑定) */
|
||||
private List<Integer> approverTeaIds;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.campusnotice.model.notice;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 「已收到」三 tab 统计数字(v17-B1)。
|
||||
* <p>
|
||||
* 口径 = {@code GET /api/notice/List} 在<b>同一</b> keyword / type / deptId / 时间范围过滤下,
|
||||
* 分别取 readType=0(全部)、1(未读)、2(已读)的总数;readType 不作为入参(它就是被统计的三个桶),
|
||||
* 因此恒满足 {@code all = unread + read}。
|
||||
* <p>
|
||||
* 与 {@link ApprovalTabCountVo}(v13,审批中心四 tab)同范式:三者都来自列表谓词,不另立统计 SQL。
|
||||
*/
|
||||
@Data
|
||||
public class ReadTabCountVo {
|
||||
|
||||
/** 全部(可见已收公告总数) */
|
||||
private int all;
|
||||
|
||||
/** 未读(可见且无本人阅读记录) */
|
||||
private int unread;
|
||||
|
||||
/** 已读(可见且已有本人阅读记录) */
|
||||
private int read;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yunhai.campusnotice.repository;
|
||||
|
||||
import com.yunhai.campusnotice.entity.NoticeApprovalRecord;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通知审核记录仓储。
|
||||
*/
|
||||
public interface NoticeApprovalRecordRepository extends JpaRepository<NoticeApprovalRecord, Integer> {
|
||||
|
||||
/** 某通知全量审核记录(按落库顺序,跨轮次时间线) */
|
||||
List<NoticeApprovalRecord> findByNoticeIdOrderByIdAsc(Integer noticeId);
|
||||
|
||||
/** 批量查 N 个通知的审核记录(列表页批量装配) */
|
||||
@Query("select r from NoticeApprovalRecord r where r.noticeId in :noticeIds order by r.id asc")
|
||||
List<NoticeApprovalRecord> findByNoticeIds(@Param("noticeIds") Collection<Integer> noticeIds);
|
||||
|
||||
/** 某轮某步已处理记录(会签进度判定) */
|
||||
List<NoticeApprovalRecord> findByNoticeIdAndRoundAndStepNo(Integer noticeId, Integer round, Integer stepNo);
|
||||
|
||||
/** 按通知ID删除全部审核记录(通知删除时级联清理) */
|
||||
void deleteByNoticeId(Integer noticeId);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.yunhai.campusnotice.repository;
|
||||
|
||||
import com.yunhai.campusnotice.entity.NoticeApprovalStep;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通知审批步骤仓储。
|
||||
*/
|
||||
public interface NoticeApprovalStepRepository extends JpaRepository<NoticeApprovalStep, Integer> {
|
||||
|
||||
/** 某通知全部步骤(按序号升序) */
|
||||
List<NoticeApprovalStep> findByNoticeIdOrderByStepNoAsc(Integer noticeId);
|
||||
|
||||
/** 批量查 N 个通知的步骤(列表页批量装配) */
|
||||
@Query("select s from NoticeApprovalStep s where s.noticeId in :noticeIds order by s.noticeId asc, s.stepNo asc")
|
||||
List<NoticeApprovalStep> findByNoticeIds(@Param("noticeIds") Collection<Integer> noticeIds);
|
||||
|
||||
/** 某通知某步 */
|
||||
NoticeApprovalStep findByNoticeIdAndStepNo(Integer noticeId, Integer stepNo);
|
||||
|
||||
/** 删除某通知全部步骤(重新送审流程重置 / 通知删除级联) */
|
||||
@Modifying
|
||||
void deleteByNoticeId(Integer noticeId);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.campusnotice.repository;
|
||||
|
||||
import com.yunhai.campusnotice.entity.SysApprover;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 审批人池仓储(审核设置页维护,发布选人数据源)。
|
||||
*/
|
||||
public interface SysApproverRepository extends JpaRepository<SysApprover, Integer> {
|
||||
|
||||
/** 某学校全部审批人(管理页,按姓名排序) */
|
||||
List<SysApprover> findBySchIdOrderByNameAsc(Integer schId);
|
||||
|
||||
/** 某学校启用中的审批人(发布选人候选池) */
|
||||
List<SysApprover> findBySchIdAndEnabledOrderByNameAsc(Integer schId, Integer enabled);
|
||||
|
||||
/** 按学校+账号定位(送审绑定校验) */
|
||||
Optional<SysApprover> findBySchIdAndAccount(Integer schId, String account);
|
||||
}
|
||||
Reference in New Issue
Block a user