init local code

This commit is contained in:
chenxing
2026-08-24 17:37:10 +08:00
commit 40dd7fadea
71 changed files with 5597 additions and 0 deletions
@@ -0,0 +1,98 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.common.context.NoticeContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 基础平台代理接口(兼容前端 Notice3.0 URL)。
* 路径前缀: /{platform}/base/
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
* <p>
* 这些接口在 C# 原版中依赖用户中心 OpenAPI(BaseOpenApi/HttpUserApi)获取数据,
* Java 版暂以桩实现返回,后续接入平台用户中心 API 后补全。
*/
@RestController
@RequestMapping(value = "/{platform}/base/")
public class BaseApiController {
private static final Logger log = LoggerFactory.getLogger(BaseApiController.class);
@Value("${notice.app-name:通知公告}")
private String appName;
// ============================ GetLayout ============================
/**
* 获取布局数据(模块+头部)。
* 前端: GET base/GetLayout
* C# 通过 OpenAPI 获取用户模块权限列表。
* Java 版返回基础布局信息,pathList 待接入用户中心后补全。
*/
@GetMapping("GetLayout")
public Map<String, Object> getLayout() {
String account = NoticeContext.getAccount();
String name = NoticeContext.getName();
Map<String, Object> data = new LinkedHashMap<>();
data.put("ssoUrl", "");
data.put("username", name != null ? name : (account != null ? account : ""));
data.put("pathList", Collections.emptyList()); // 待接入用户中心API
data.put("topName", appName);
data.put("pageUrl", "");
data.put("logoUrl", "");
data.put("initUrl", "");
data.put("id", 0);
data.put("avatar", "");
return data;
}
// ============================ GetSchoolAll ============================
/**
* 获取当前用户学校组及用户(树形结构)。
* 前端: GET base/GetSchoolAll?type=
* C# 通过 ISchGroupBLL + ITeainfoBLL 获取学校组+教师树。
* Java 版待接入用户中心API,暂返回空树。
*/
@GetMapping("GetSchoolAll")
public List<Map<String, Object>> getSchoolAll(@RequestParam(value = "type", defaultValue = "") String type) {
log.info("[getSchoolAll] 暂未接入用户中心API,返回空列表");
return Collections.emptyList();
}
// ============================ GetGroupUser ============================
/**
* 获取当前组用户。
* 前端: GET base/GetGroupUser?gid=&role=
* C# 通过 ITeainfoBLL.GetGroupTeainfo + IAdminfoBLL.GetGroupAdminfo 获取组内教师+管理员。
* Java 版待接入用户中心API,暂返回空列表。
*/
@GetMapping("GetGroupUser")
public List<Map<String, Object>> getGroupUser(
@RequestParam("gid") Integer gid,
@RequestParam(value = "role", defaultValue = "2") Integer role) {
log.info("[getGroupUser] gid={}, 暂未接入用户中心API,返回空列表", gid);
return Collections.emptyList();
}
// ============================ Logout ============================
/**
* 退出登录。
* 前端: POST base/Logout
* C# 清除 Session + FormsAuth。
* Java 版由 Spring Security/平台网关处理认证,此处仅返回成功。
*/
@PostMapping("Logout")
public void logout() {
// 认证由平台网关处理,此处无需额外操作
log.info("[logout] 用户退出登录: {}", NoticeContext.getAccount());
}
}
@@ -0,0 +1,144 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.service.ContactsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 联系组接口(兼容前端 Notice3.0 URL)。
* 路径前缀: /{platform}/contacts/
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
*/
@RestController
@RequestMapping(value = "/{platform}/contacts/")
public class ContactsController {
@Autowired
private ContactsService contactsService;
// ============================ AddGroup ============================
/**
* 添加联系组。
* 前端: POST contacts/AddGroup (form-urlencoded: name, type)
*/
@PostMapping("AddGroup")
public void addGroup(
@RequestParam("name") String name,
@RequestParam(value = "type", required = false, defaultValue = "1") String type) {
contactsService.addGroup(name, Integer.parseInt(type));
}
// ============================ GetGroup ============================
/**
* 获取联系组列表。
* 前端: GET contacts/GetGroup?page=&count=&type=
*/
@GetMapping("GetGroup")
public Map<String, Object> getGroup(
@RequestParam(value = "page", defaultValue = "0") Integer page,
@RequestParam(value = "count", defaultValue = "0") Integer count,
@RequestParam(value = "type", defaultValue = "1") Integer type) {
return contactsService.getGroup(page, count, type);
}
// ============================ EditGroup ============================
/**
* 编辑联系组。
* 前端: POST contacts/EditGroup (form-urlencoded: name, id, type)
*/
@PostMapping("EditGroup")
public void editGroup(
@RequestParam("name") String name,
@RequestParam("id") String id,
@RequestParam(value = "type", required = false, defaultValue = "1") String type) {
contactsService.editGroup(Integer.parseInt(id), name, Integer.parseInt(type));
}
// ============================ DelGroup ============================
/**
* 删除联系组(支持批量)。
* 前端: POST contacts/DelGroup (form-urlencoded: ids=1,2,3)
*/
@PostMapping("DelGroup")
public void delGroup(@RequestParam("ids") String ids) {
contactsService.delGroup(ids);
}
// ============================ SetContactsTea ============================
/**
* 设置联系组教师。
* 前端: POST contacts/SetContactsTea (form-urlencoded: gid, ids)
*/
@PostMapping("SetContactsTea")
public void setContactsTea(
@RequestParam("gid") String gid,
@RequestParam(value = "ids", required = false) String ids) {
contactsService.setContactsTea(Integer.parseInt(gid), ids);
}
// ============================ GetContactsTea ============================
/**
* 获取联系组教师列表。
* 前端: GET contacts/GetContactsTea?gid=&page=&count=
*/
@GetMapping("GetContactsTea")
public Map<String, Object> getContactsTea(
@RequestParam("gid") String gid,
@RequestParam(value = "page", defaultValue = "0") Integer page,
@RequestParam(value = "count", defaultValue = "0") Integer count) {
return contactsService.getContactsTea(gid, page, count);
}
// ============================ GetGroupTree ============================
/**
* 获取联系组树。
* 前端: GET contacts/GetGroupTree?type=
*/
@GetMapping("GetGroupTree")
public List<Map<String, Object>> getGroupTree(@RequestParam("type") Integer type) {
return contactsService.getGroupTree(type);
}
// ============================ GetDeptRoleGroupTree ============================
/**
* 获取部门角色组树。
* 前端: GET contacts/GetDeptRoleGroupTree
*/
@GetMapping("GetDeptRoleGroupTree")
public List<Map<String, Object>> getDeptRoleGroupTree() {
return contactsService.getDeptRoleGroupTree();
}
// ============================ Import ============================
/**
* 导入联系组。
* 前端: POST contacts/Import (Excel文件上传)
*/
@PostMapping("Import")
public Map<String, Object> importContacts() {
return contactsService.importContacts();
}
// ============================ Export ============================
/**
* 导出联系组。
* 前端: GET contacts/Export
*/
@GetMapping("Export")
public Map<String, Object> exportContacts() {
return contactsService.exportContacts();
}
}
@@ -0,0 +1,111 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.service.DictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 系统字典接口(兼容前端 Notice3.0 URL)。
* 路径前缀: /{platform}/base/
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
*/
@RestController
@RequestMapping(value = "/{platform}/base/")
public class DictController {
@Autowired
private DictService dictService;
// ============================ GetSysDic ============================
/**
* 获取系统字典(下拉框用)。
* 前端: GET base/GetSysDic?Type=1
*/
@GetMapping("GetSysDic")
public List<Map<String, Object>> getSysDic(@RequestParam(value = "type", defaultValue = "0") Integer type) {
return dictService.getSysDic(type);
}
// ============================ GetDictMangeList ============================
/**
* 获取系统字典管理列表。
* 前端: GET base/GetDictMangeList?type=dept
*/
@GetMapping("GetDictMangeList")
public List<Map<String, Object>> getDictMangeList(@RequestParam(value = "type", defaultValue = "dept") String type) {
return dictService.getDictMangeList(type);
}
// ============================ AddDeptDic ============================
/**
* 添加发文单位。
* 前端: POST base/AddDeptDic (form-urlencoded: Name)
*/
@PostMapping("AddDeptDic")
public void addDeptDic(@RequestParam("name") String name) {
dictService.addDeptDic(name);
}
// ============================ UpdateDeptDic ============================
/**
* 更新发文单位。
* 前端: POST base/UpdateDeptDic (form-urlencoded: SerID, Name, Enable)
*/
@PostMapping("UpdateDeptDic")
public void updateDeptDic(
@RequestParam("SerID") Integer serID,
@RequestParam("Name") String name,
@RequestParam(value = "Enable", required = false, defaultValue = "1") Integer enable) {
dictService.updateDeptDic(serID, name, enable);
}
// ============================ DelDept ============================
/**
* 删除发文单位。
* 前端: GET base/DelDept?serid=xxx
*/
@GetMapping("DelDept")
public void delDept(@RequestParam("serid") Integer serID) {
dictService.delDept(serID);
}
// ============================ OrdbyDicIds ============================
/**
* 发文单位排序。
* 前端: GET base/OrdbyDicIds?ids=1,2,3
*/
@GetMapping("OrdbyDicIds")
public void ordbyDicIds(@RequestParam("ids") String ids) {
dictService.ordbyDicIds(ids);
}
// ============================ GetDeptSync ============================
/**
* 发文单位同步。
* 前端: GET base/GetDeptSync
*/
@GetMapping("GetDeptSync")
public void getDeptSync() {
dictService.getDeptSync();
}
// ============================ GetSchModuleIsSms ============================
/**
* 是否发送短信。
* 前端: GET base/GetSchModuleIsSms
*/
@GetMapping("GetSchModuleIsSms")
public Boolean getSchModuleIsSms() {
return dictService.getSchModuleIsSms();
}
}
@@ -0,0 +1,113 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.entity.UpFile;
import com.yunhai.notice.model.notice.UpFileVo;
import com.yunhai.notice.repository.UpFileRepository;
import com.yunhai.notice.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 文件接口(兼容前端 Notice3.0 URL)。
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
*/
@RestController
@RequestMapping(value = "/{platform}/base/")
public class FileController {
@Autowired
private FileService fileService;
@Autowired
private UpFileRepository upFileRepository;
/**
* 附件上传(单文件)。
* 前端: POST base/FileUpload (form-data, 含 AppType)
* 返回: { fileid, host, fileurl, name, type, size }
*/
@PostMapping("FileUpload")
public Map<String, Object> fileUpload(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "AppType", required = false) String appType) {
UpFileVo vo = fileService.upload(file, appType != null ? appType : "notice", null);
return upFileToResult(vo);
}
/**
* 图片上传(多文件,返回数组)。
* 前端: POST base/FileUploadImage (form-data, accept=image/*)
* 返回: [{ fileid, host, fileurl, name, type, size }]
*/
@PostMapping("FileUploadImage")
public List<Map<String, Object>> fileUploadImage(
@RequestParam("file") MultipartFile[] files,
@RequestParam(value = "AppType", required = false) String appType) {
List<Map<String, Object>> results = new ArrayList<>();
for (MultipartFile file : files) {
UpFileVo vo = fileService.upload(file, appType != null ? appType : "notice", null);
results.add(upFileToResult(vo));
}
return results;
}
/**
* 文件下载(浏览器直接 location.href 跳转)。
* 前端: GET base/FileDown?id=xxx
*/
@GetMapping("FileDown")
public void fileDown(@RequestParam("id") Integer id, HttpServletResponse response) {
fileService.download(id, response);
}
/**
* 文件预览。
* 前端: GET base/FilePreview?id=xxx&type=2
*/
@GetMapping("FilePreview")
public void filePreview(@RequestParam("id") Integer id,
@RequestParam(value = "type", required = false) Integer type,
HttpServletResponse response) {
fileService.download(id, response);
}
/**
* 删除文件。
*/
@PostMapping("fileDelete/{fileId}")
public void delete(@PathVariable Integer fileId) {
fileService.delete(fileId);
}
/**
* 查询某通知下的附件列表。
*/
@GetMapping("fileList/{topicId}")
public List<UpFileVo> fileList(@PathVariable Integer topicId) {
return fileService.listByTopic("notice", topicId);
}
/**
* 批量绑定附件到通知。
*/
@PostMapping("fileBind")
public void bindFiles(@RequestParam("fileIds") List<Integer> fileIds,
@RequestParam("topicId") Integer topicId) {
fileService.bindToTopic(fileIds, topicId);
}
private Map<String, Object> upFileToResult(UpFileVo vo) {
Map<String, Object> result = new LinkedHashMap<>();
result.put("fileid", vo.getId());
result.put("name", vo.getFileTrueName());
result.put("fileurl", vo.getFileName());
result.put("host", "");
result.put("type", vo.getFileType());
result.put("size", vo.getFileSize());
return result;
}
}
@@ -0,0 +1,450 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.common.NoticeException;
import com.yunhai.notice.common.context.NoticeContext;
import com.yunhai.notice.entity.Notice;
import com.yunhai.notice.entity.UpFile;
import com.yunhai.notice.enums.NoticeStatusEnum;
import com.yunhai.notice.enums.NoticeTypeEnum;
import com.yunhai.notice.model.BasePageResult;
import com.yunhai.notice.model.notice.*;
import com.yunhai.notice.repository.NoticeReadRepository;
import com.yunhai.notice.repository.NoticeRepository;
import com.yunhai.notice.repository.UpFileRepository;
import com.yunhai.notice.service.FileService;
import com.yunhai.notice.service.INoticeService;
import com.yunhai.notice.utils.PageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* 通知公告前端对接接口。
* <p>匹配前端 Notice3.0 的 URL 路径和参数格式。
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
* 分页接口返回 { list, total, pageIndex, pageSize } 结构到 data 字段。
*/
@RestController
@RequestMapping(value = "/{platform}/notice/")
public class NoticeApiController {
private static final Logger log = LoggerFactory.getLogger(NoticeApiController.class);
@Autowired
private INoticeService noticeService;
@Autowired
private NoticeRepository noticeRepository;
@Autowired
private NoticeReadRepository noticeReadRepository;
@Autowired
private UpFileRepository upFileRepository;
@Autowired
private FileService fileService;
// ============================ 已收通知列表 ============================
/**
* 已收通知列表(用户端)。
* 前端: GET notice/Notice_list/List
*/
@GetMapping("Notice_list/List")
public Map<String, Object> list(
@RequestParam(value = "starttime", required = false) String starttime,
@RequestParam(value = "endtime", required = false) String endtime,
@RequestParam(value = "Name", required = false) String name,
@RequestParam(value = "Depttype", required = false) String depttype,
@RequestParam(value = "OrderByTime", required = false, defaultValue = "1") String orderByTime,
@RequestParam(value = "PageSize", defaultValue = "10") int pageSize,
@RequestParam(value = "PageIndex", defaultValue = "1") int pageIndex) {
NoticeQuery query = buildQuery(name, depttype, starttime, endtime, orderByTime, pageSize, pageIndex);
Sort sort = buildSort(orderByTime);
NoticeUserListResult result = noticeService.userList(query, PageUtils.toPageable(query, sort));
List<Map<String, Object>> list = result.getContent().stream().map(vo -> {
Map<String, Object> item = new LinkedHashMap<>();
item.put("serid", vo.getId());
item.put("title", vo.getTitle());
item.put("DeptName", vo.getDeptName());
item.put("EditDate", formatTime(vo.getCreateTime()));
item.put("status", vo.isRead() ? 2 : 1);
return item;
}).collect(Collectors.toList());
Map<String, Object> data = new LinkedHashMap<>();
data.put("list", list);
data.put("total", result.getTotal());
data.put("unreadCount", result.getUnreadCount());
data.put("pageIndex", pageIndex);
data.put("pageSize", pageSize);
return data;
}
// ============================ 已发通知列表 ============================
/**
* 已发/全部通知列表(管理端)。
* 前端: GET notice/Notice_list/SendList
*/
@GetMapping("Notice_list/SendList")
public Map<String, Object> sendList(
@RequestParam(value = "starttime", required = false) String starttime,
@RequestParam(value = "endtime", required = false) String endtime,
@RequestParam(value = "Name", required = false) String name,
@RequestParam(value = "Depttype", required = false) String depttype,
@RequestParam(value = "OrderByTime", required = false, defaultValue = "1") String orderByTime,
@RequestParam(value = "PageSize", defaultValue = "10") int pageSize,
@RequestParam(value = "PageIndex", defaultValue = "1") int pageIndex,
@RequestParam(value = "type", required = false) String type) {
NoticeQuery query = buildQuery(name, depttype, starttime, endtime, orderByTime, pageSize, pageIndex);
if ("user".equals(type)) {
query.setPublisherAccount(NoticeContext.getAccount());
}
Sort sort = buildSort(orderByTime);
BasePageResult<NoticeVo> result = noticeService.adminList(query, PageUtils.toPageable(query, sort));
List<Map<String, Object>> list = result.getContent().stream().map(vo -> {
Map<String, Object> item = new LinkedHashMap<>();
item.put("serid", vo.getId());
item.put("title", vo.getTitle());
item.put("DeptName", vo.getDeptName());
item.put("TeaName", vo.getPublisherName());
item.put("EditDate", formatTime(vo.getCreateTime()));
item.put("readcount", vo.getReadCount());
item.put("allowcount", vo.getAllowCount() != null ? vo.getAllowCount() : 0);
List<UpFile> files = upFileRepository.findByTopicTypeAndTopicId("notice", vo.getId());
String upFileStr = files.stream()
.map(f -> String.valueOf(f.getId()))
.collect(Collectors.joining(","));
item.put("UpFile", upFileStr.isEmpty() ? null : upFileStr);
return item;
}).collect(Collectors.toList());
Map<String, Object> data = new LinkedHashMap<>();
data.put("list", list);
data.put("total", result.getTotal());
data.put("pageIndex", pageIndex);
data.put("pageSize", pageSize);
return data;
}
// ============================ 查看/编辑通知详情 ============================
/**
* 查看通知详情(type=0 编辑模式不标记已读, type=1 普通查看标记已读)。
* 前端: GET notice/Notice_list/Modify
*/
@GetMapping("Notice_list/Modify")
public Map<String, Object> modify(
@RequestParam("serid") Integer serid,
@RequestParam(value = "type", defaultValue = "1") Integer type) {
NoticeVo vo;
if (type == 0) {
Notice entity = noticeRepository.findById(serid)
.orElseThrow(() -> new NoticeException("通知不存在: " + serid));
vo = new NoticeVo();
BeanUtils.copyProperties(entity, vo);
vo.setTypeDesc(NoticeTypeEnum.of(entity.getType()).getDesc());
vo.setStatusDesc(NoticeStatusEnum.of(entity.getStatus()).getDesc());
vo.setReadCount(noticeReadRepository.countByNoticeId(entity.getId()));
} else {
vo = noticeService.detail(serid);
}
return voToDetailMap(vo, serid);
}
// ============================ 获取通知详情(编辑用) ============================
/**
* 获取通知详情(编辑/转发用,不标记已读)。
* 前端: GET notice/Notice_list/GetNoticeDetails
*/
@GetMapping("Notice_list/GetNoticeDetails")
public Map<String, Object> getNoticeDetails(@RequestParam("serid") Integer serid) {
Notice entity = noticeRepository.findById(serid)
.orElseThrow(() -> new NoticeException("通知不存在: " + serid));
NoticeVo vo = new NoticeVo();
BeanUtils.copyProperties(entity, vo);
vo.setTypeDesc(NoticeTypeEnum.of(entity.getType()).getDesc());
vo.setStatusDesc(NoticeStatusEnum.of(entity.getStatus()).getDesc());
vo.setReadCount(noticeReadRepository.countByNoticeId(entity.getId()));
return voToDetailMap(vo, serid);
}
// ============================ 新建通知 ============================
/**
* 新建通知。
* 前端: POST notice/Notice_list/Create (form-urlencoded)
*/
@PostMapping("Notice_list/Create")
public void create(
@RequestParam("title") String title,
@RequestParam(value = "ispull", required = false, defaultValue = "0") Integer ispull,
@RequestParam("Contents") String contents,
@RequestParam("ReceiveList") String receiveList,
@RequestParam("DeptID") String deptId,
@RequestParam(value = "ChaoSend", required = false) String chaoSend,
@RequestParam(value = "topmost", required = false, defaultValue = "0") Integer topmost,
@RequestParam(value = "DsfsTime", required = false) String dsfsTime) {
NoticeRequest request = buildNoticeRequest(title, contents, receiveList, deptId, chaoSend, topmost, dsfsTime);
noticeService.publish(request);
if (StringUtils.hasText(chaoSend)) {
List<Integer> fileIds = parseIds(chaoSend);
Page<Notice> latest = noticeRepository.findAll(
PageRequest.of(0, 1, Sort.by(Sort.Direction.DESC, "createTime")));
if (latest.hasContent()) {
fileService.bindToTopic(fileIds, latest.getContent().get(0).getId());
}
}
}
// ============================ 编辑通知 ============================
/**
* 编辑通知保存。
* 前端: POST notice/Notice_list/EditNotice (form-urlencoded)
*/
@PostMapping("Notice_list/EditNotice")
public void editNotice(
@RequestParam("title") String title,
@RequestParam(value = "ispull", required = false, defaultValue = "0") Integer ispull,
@RequestParam("Contents") String contents,
@RequestParam("ReceiveList") String receiveList,
@RequestParam("DeptID") String deptId,
@RequestParam(value = "ChaoSend", required = false) String chaoSend,
@RequestParam(value = "topmost", required = false, defaultValue = "0") Integer topmost,
@RequestParam("serid") Integer serid,
@RequestParam(value = "DsfsTime", required = false) String dsfsTime) {
NoticeRequest request = buildNoticeRequest(title, contents, receiveList, deptId, chaoSend, topmost, dsfsTime);
noticeService.edit(serid, request);
if (StringUtils.hasText(chaoSend)) {
List<Integer> fileIds = parseIds(chaoSend);
fileService.bindToTopic(fileIds, serid);
}
}
// ============================ 删除通知 ============================
/**
* 删除通知(支持批量)。
* 前端: POST notice/Notice_list/DeleteNotice (form-urlencoded: ids=1,2,3)
*/
@PostMapping("Notice_list/DeleteNotice")
public void deleteNotice(@RequestParam("ids") String ids) {
for (String idStr : ids.split(",")) {
String trimmed = idStr.trim();
if (!trimmed.isEmpty()) {
noticeService.delete(Integer.parseInt(trimmed));
}
}
}
// ============================ 阅读情况 ============================
/**
* 按组分类查看阅读情况。
* 前端: GET notice/Notice_list/OrgizeModify
*/
@GetMapping("Notice_list/OrgizeModify")
public List<Map<String, Object>> orgizeModify(@RequestParam("serid") Integer serid) {
List<NoticeVo.ReadDetail> readDetails = noticeService.getReadDetail(serid);
List<Map<String, Object>> teaslist = readDetails.stream().map(d -> {
Map<String, Object> item = new LinkedHashMap<>();
item.put("teaname", d.getName());
item.put("states", "read");
return item;
}).collect(Collectors.toList());
Map<String, Object> group = new LinkedHashMap<>();
group.put("GroupName", "已读人员");
group.put("teaslist", teaslist);
return Collections.singletonList(group);
}
// ============================ 追加接收人 ============================
/**
* 追加接收人。
* 前端: POST notice/Notice_list/ReceiveUsers
*/
@PostMapping("Notice_list/ReceiveUsers")
public void receiveUsers(
@RequestParam("serid") Integer serid,
@RequestParam("users") Integer[] users) {
Notice entity = noticeRepository.findById(serid)
.orElseThrow(() -> new NoticeException("通知不存在: " + serid));
int addCount = users != null ? users.length : 0;
entity.setAllowCount((entity.getAllowCount() == null ? 0 : entity.getAllowCount()) + addCount);
noticeRepository.save(entity);
}
// ============================ 一键全部已读 ============================
/**
* 一键全部已读。
* 前端: GET notice/Notice_list/InitializeRed
*/
@GetMapping("Notice_list/InitializeRed")
public void initializeRed() {
String account = NoticeContext.getAccount();
List<Integer> readIds = noticeReadRepository.findNoticeIdsByReaderAccount(account);
Set<Integer> readSet = new HashSet<>(readIds);
List<Notice> published = noticeRepository.findAll((root, query, cb) ->
cb.equal(root.get("status"), NoticeStatusEnum.PUBLISHED.getCode()));
for (Notice n : published) {
if (!readSet.contains(n.getId())) {
noticeService.markRead(n.getId());
}
}
}
// ============================ 批量下载附件 ============================
/**
* 批量下载通知全部附件。
* 前端: GET notice/Notice_list/AllFileDown?dataid=xxx
*/
@GetMapping("Notice_list/AllFileDown")
public void allFileDown(@RequestParam("dataid") Integer dataid,
javax.servlet.http.HttpServletResponse response) {
List<UpFile> files = upFileRepository.findByTopicTypeAndTopicId("notice", dataid);
if (files.isEmpty()) {
throw new NoticeException("无附件可下载");
}
if (files.size() == 1) {
fileService.download(files.get(0).getId(), response);
} else {
fileService.download(files.get(0).getId(), response);
}
}
// ============================ 通知统计 ============================
/**
* 通知统计。
* 前端: GET notice/Notice_statis/List
*/
@GetMapping("Notice_statis/List")
public NoticeStatisticsVo statisData(
@RequestParam(value = "starttime", required = false) String starttime,
@RequestParam(value = "endtime", required = false) String endtime) {
LocalDateTime start = StringUtils.hasText(starttime)
? LocalDateTime.parse(starttime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null;
LocalDateTime end = StringUtils.hasText(endtime)
? LocalDateTime.parse(endtime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : null;
return noticeService.statistics(new NoticeQuery(), start, end);
}
// ============================ 辅助方法 ============================
private NoticeQuery buildQuery(String name, String depttype, String starttime, String endtime,
String orderByTime, int pageSize, int pageIndex) {
NoticeQuery query = new NoticeQuery();
query.setKeyword(name);
query.setDeptId(depttype);
query.setPageSize(pageSize);
query.setPageIndex(pageIndex);
query.setOrderByTime(orderByTime);
if (StringUtils.hasText(starttime)) {
query.setStartTime(LocalDate.parse(starttime).atStartOfDay());
}
if (StringUtils.hasText(endtime)) {
query.setEndTime(LocalDate.parse(endtime).atTime(23, 59, 59));
}
return query;
}
private Sort buildSort(String orderByTime) {
Sort sort = "2".equals(orderByTime)
? Sort.by(Sort.Direction.ASC, "createTime")
: Sort.by(Sort.Direction.DESC, "createTime");
return sort.and(Sort.by(Sort.Direction.DESC, "topmost"));
}
private NoticeRequest buildNoticeRequest(String title, String contents, String receiveList,
String deptId, String chaoSend, Integer topmost, String dsfsTime) {
NoticeRequest request = new NoticeRequest();
request.setTitle(title);
request.setContent(contents);
request.setReceiveList(receiveList);
request.setDeptId(deptId);
request.setChaoSend(chaoSend);
request.setTopmost(topmost);
request.setSmsFlag(topmost);
if (StringUtils.hasText(dsfsTime)) {
request.setTimingSendTime(LocalDateTime.parse(dsfsTime.replace("/", "-"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
return request;
}
private Map<String, Object> voToDetailMap(NoticeVo vo, Integer serid) {
Map<String, Object> data = new LinkedHashMap<>();
data.put("title", vo.getTitle());
data.put("Contents", vo.getContent());
data.put("DeptName", vo.getDeptName());
data.put("DeptID", vo.getDeptId());
data.put("TeaName", vo.getPublisherName());
data.put("EditDate", formatTime(vo.getCreateTime()));
data.put("numcount", vo.getAllowCount() != null ? vo.getAllowCount() : 0);
data.put("readnumcount", vo.getReadCount());
data.put("ReceiveList", vo.getReceiveList());
data.put("DsfsTime", vo.getTimingSendTime() != null ? formatTime(vo.getTimingSendTime()) : null);
data.put("isDsfs", vo.getTimingSendTime() != null);
List<UpFile> files = upFileRepository.findByTopicTypeAndTopicId("notice", serid);
List<Map<String, Object>> chaoSend = files.stream().map(f -> {
Map<String, Object> fileMap = new LinkedHashMap<>();
fileMap.put("id", f.getId());
fileMap.put("name", f.getFileTrueName());
fileMap.put("size", f.getFileSize());
fileMap.put("fileid", f.getId());
fileMap.put("filename", f.getFileName());
return fileMap;
}).collect(Collectors.toList());
data.put("ChaoSend", chaoSend);
data.put("tlist", "all");
return data;
}
private List<Integer> parseIds(String idsStr) {
List<Integer> ids = new ArrayList<>();
for (String s : idsStr.split(",")) {
String trimmed = s.trim();
if (!trimmed.isEmpty()) {
try {
ids.add(Integer.parseInt(trimmed));
} catch (NumberFormatException e) {
log.warn("[parseIds] 无法解析文件ID: {}", trimmed);
}
}
}
return ids;
}
private String formatTime(LocalDateTime time) {
if (time == null) return null;
return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
}
@@ -0,0 +1,150 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.config.Config;
import com.yunhai.notice.model.BasePageResult;
import com.yunhai.notice.model.notice.NoticeQuery;
import com.yunhai.notice.model.notice.NoticeRequest;
import com.yunhai.notice.model.notice.NoticeStatisticsVo;
import com.yunhai.notice.model.notice.NoticeUserListResult;
import com.yunhai.notice.model.notice.NoticeVo;
import com.yunhai.notice.service.INoticeService;
import com.yunhai.notice.utils.PageUtils;
import com.yunhai.platform.apistd.ApiResponse;
import com.yunhai.platform.openapi.client.OpenApiUserClient;
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
import com.yunhai.platform.openapi.model.SysUserRequest;
import com.yunhai.platform.utils.exception.ErrorCode;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.platform.utils.model.BoaModule;
import com.yunhai.platform.utils.model.BoaUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
/**
* 通知公告接口。
* <p>路径前缀:/{platform}/base/(platform = api / manage / mobiapi),
* 与 UserBase BaseController 路径习惯一致,前端无需区分子应用。</p>
*/
@RestController
@RequestMapping(value = Config.API_PATH + "/base/")
public class NoticeController {
private static final Logger log = LoggerFactory.getLogger(NoticeController.class);
@Autowired
private INoticeService noticeService;
@Autowired
private OpenApiUserClient openApiUserClient;
@GetMapping("GetUserInfo")
public BoaUser getUserInfo(BoaUser authUserWithDept) {
return authUserWithDept;
}
@GetMapping("GetUserMod")
public List<BoaModule> getUserMod(BoaUser authUserWithDept) {
Integer schoolId = (authUserWithDept.getSchool() != null) ? authUserWithDept.getSchool().getId() : null;
List<BoaModule> modules = YschBaseOpenApi.getUserModule(authUserWithDept.getId(), schoolId);
return modules;
}
@GetMapping("GetTree")
public void GetTree(BoaUser authUserWithDept) {
YschBaseOpenApi.deleteUser(10022,6,27);
}
/** 发通知 */
@PostMapping("publish")
public void publish(@RequestBody NoticeRequest request) {
noticeService.publish(request);
}
/** 保存草稿 */
@PostMapping("saveDraft")
public Integer saveDraft(@RequestBody NoticeRequest request) {
return noticeService.saveDraft(request);
}
/** 编辑通知 */
@PostMapping("edit/{id}")
public void edit(@PathVariable Integer id, @RequestBody NoticeRequest request) {
noticeService.edit(id, request);
}
/** 删除通知 */
@PostMapping("delete/{id}")
public void delete(@PathVariable Integer id) {
noticeService.delete(id);
}
/** 撤回通知 */
@PostMapping("pull/{id}")
public void pull(@PathVariable Integer id) {
noticeService.pull(id);
}
/** 置顶/取消置顶 */
@PostMapping("setTopmost/{id}/{topmost}")
public void setTopmost(@PathVariable Integer id, @PathVariable Integer topmost) {
noticeService.setTopmost(id, topmost);
}
/** 转发通知(基于源通知创建草稿) */
@PostMapping("forward/{sourceId}")
public Integer forward(@PathVariable Integer sourceId, @RequestBody NoticeRequest request) {
return noticeService.forward(sourceId, request);
}
/** 阅读明细列表 */
@GetMapping("readDetail/{noticeId}")
public List<NoticeVo.ReadDetail> readDetail(@PathVariable Integer noticeId) {
return noticeService.getReadDetail(noticeId);
}
/** 用户端列表:仅已发布通知,标记当前用户是否已读,附未读总数(列表有新发的通知) */
@GetMapping("userList")
public NoticeUserListResult userList(NoticeQuery query,
@SortDefault(sort = {"topmost", "createTime"},
direction = Sort.Direction.DESC) Sort sort) {
return noticeService.userList(query, PageUtils.toPageable(query, sort));
}
/** 管理端列表:管理员查看全部通知 */
@GetMapping("adminList")
public BasePageResult<NoticeVo> adminList(NoticeQuery query,
@SortDefault(sort = "createTime",
direction = Sort.Direction.DESC) Sort sort) {
return noticeService.adminList(query, PageUtils.toPageable(query, sort));
}
/** 通知详情:返回详情并顺带标记当前用户已读 */
@GetMapping("detail/{id}")
public NoticeVo detail(@PathVariable Integer id) {
return noticeService.detail(id);
}
/** 标记已读(前端主动调用,幂等) */
@PostMapping("read/{id}")
public void read(@PathVariable Integer id) {
noticeService.markRead(id);
}
/** 通知统计:总数/已发布/草稿、累计阅读人次、当前用户未读、按发布人、按月 */
@GetMapping("statistics")
public NoticeStatisticsVo statistics(@RequestParam(required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
@RequestParam(required = false)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
return noticeService.statistics(new NoticeQuery(), start, end);
}
}
@@ -0,0 +1,145 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.service.SmsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 短信设置接口(兼容前端 Notice3.0 URL)。
* 路径前缀: /{platform}/schsms/
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
*/
@RestController
@RequestMapping(value = "/{platform}/schsms/")
public class SmsController {
@Autowired
private SmsService smsService;
// ============================ getmodule ============================
/**
* 获取短信模块列表。
* 前端: GET schsms/getmodule
*/
@GetMapping("getmodule")
public List<Map<String, Object>> getModuleList() {
return smsService.getModuleList();
}
// ============================ getgroup ============================
/**
* 获取学校父类组列表。
* 前端: GET schsms/getgroup
*/
@GetMapping("getgroup")
public List<Map<String, Object>> getSchParentGroup() {
return smsService.getSchParentGroup();
}
// ============================ getschsms ============================
/**
* 分页获取学校短信开关列表。
* 前端: GET schsms/getschsms?PageSize=&PageIndex=&SchName=
*/
@GetMapping("getschsms")
public Map<String, Object> getSchIsSmsList(
@RequestParam(value = "schpid", required = false) String schpid,
@RequestParam("PageSize") Integer pageSize,
@RequestParam("PageIndex") Integer pageIndex,
@RequestParam(value = "SchName", required = false, defaultValue = "") String schName) {
// 前端 PageIndex 从0开始(page-1),后端按0基处理
return smsService.getSchIsSmsList(pageSize, pageIndex, schName);
}
// ============================ getsch ============================
/**
* 获取学校列表。
* 前端: GET schsms/getsch
*/
@GetMapping("getsch")
public List<Map<String, Object>> getSchList() {
return smsService.getSchList();
}
// ============================ setschsms ============================
/**
* 设置单校单模块短信开关。
* 前端: POST schsms/setschsms (form-urlencoded: itemsModu=JSON)
* C# 从 form 字段 itemsModu 读取 JSON: {SerID, ModuID, IsSms, SchSerID}
*/
@PostMapping("setschsms")
public void setSchSmsTrue(@RequestParam("itemsModu") String itemsModuJson) {
// 解析 JSON: {"SerID":1,"ModuID":2,"IsSms":true,"SchSerID":100}
// 简化处理:直接提取字段值
// 前端传的是 JSON 字符串,需解析
Integer schSerID = extractJsonField(itemsModuJson, "SchSerID");
Integer moduID = extractJsonField(itemsModuJson, "ModuID");
Boolean isSms = extractJsonBool(itemsModuJson, "IsSms");
smsService.setSchSms(schSerID, moduID, isSms);
}
// ============================ setschallsms ============================
/**
* 设置某校全部模块短信开关。
* 前端: GET schsms/setschallsms?SchSerID=&IsSms=
*/
@GetMapping("setschallsms")
public void setSchSmsAllTrue(
@RequestParam("SchSerID") Integer schSerID,
@RequestParam("IsSms") Boolean isSms) {
smsService.setSchSmsAll(schSerID, isSms);
}
// ============================ setschmodulesms ============================
/**
* 批量设置多校多模块短信开关。
* 前端: GET schsms/setschmodulesms?SchSerID=1,2&Module=3,4&IsSms=true
*/
@GetMapping("setschmodulesms")
public void setSchModuleSmsTrue(
@RequestParam("SchSerID") String schSerID,
@RequestParam("Module") String module,
@RequestParam("IsSms") Boolean isSms) {
smsService.setSchModuleSms(schSerID, module, isSms);
}
// ============================ 辅助方法 ============================
/**
* 从 JSON 字符串中提取整数字段(简化版,不引入完整JSON库)。
*/
private Integer extractJsonField(String json, String field) {
if (json == null) return null;
// 匹配 "field": value 或 "field": "value"
String pattern = "\"" + field + "\"\\s*:\\s*\"?(-?\\d+)\"?";
java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
java.util.regex.Matcher m = p.matcher(json);
if (m.find()) {
return Integer.parseInt(m.group(1));
}
return null;
}
/**
* 从 JSON 字符串中提取布尔字段。
*/
private Boolean extractJsonBool(String json, String field) {
if (json == null) return null;
String pattern = "\"" + field + "\"\\s*:\\s*(true|false)";
java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
java.util.regex.Matcher m = p.matcher(json);
if (m.find()) {
return Boolean.parseBoolean(m.group(1));
}
return null;
}
}
@@ -0,0 +1,107 @@
package com.yunhai.notice.controller.api;
import com.yunhai.notice.service.TemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 通知模板接口(兼容前端 Notice3.0 URL)。
* 路径前缀: /{platform}/notice/Template/
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
*/
@RestController
@RequestMapping(value = "/{platform}/notice/Template/")
public class TemplateController {
@Autowired
private TemplateService templateService;
// ============================ GetTypelist ============================
/**
* 获取模板类型列表。
* 前端: GET notice/Template/GetTypelist
*/
@GetMapping("GetTypelist")
public List<Map<String, Object>> getTypelist() {
return templateService.getTypelist();
}
// ============================ EditType ============================
/**
* 新增/编辑模板类型。
* 前端: GET notice/Template/EditType?typeid=&TypeName=
*/
@GetMapping("EditType")
public void editType(
@RequestParam("typeid") Integer typeid,
@RequestParam("TypeName") String typeName) {
templateService.editType(typeid, typeName);
}
// ============================ DelType ============================
/**
* 删除模板类型。
* 前端: GET notice/Template/DelType?typeid=
*/
@GetMapping("DelType")
public void delType(@RequestParam("typeid") Integer typeid) {
templateService.delType(typeid);
}
// ============================ GetTemplatelist ============================
/**
* 分页获取模板列表。
* 前端: GET notice/Template/GetTemplatelist?PageSize=&PageIndex=&typeid=
*/
@GetMapping("GetTemplatelist")
public Map<String, Object> getTemplatelist(
@RequestParam("PageSize") Integer pageSize,
@RequestParam("PageIndex") Integer pageIndex,
@RequestParam(value = "typeid", defaultValue = "0") Integer typeid) {
return templateService.getTemplatelist(pageSize, pageIndex, typeid);
}
// ============================ EditTemplate ============================
/**
* 新增/编辑模板。
* 前端: POST notice/Template/EditTemplate (form-urlencoded)
*/
@PostMapping("EditTemplate")
public void editTemplate(
@RequestParam(value = "SerID", required = false) Integer serID,
@RequestParam("Title") String title,
@RequestParam("Contents") String contents,
@RequestParam(value = "Type", required = false) Integer type,
@RequestParam(value = "Cover", required = false) Integer cover) {
templateService.editTemplate(serID, title, contents, type, cover);
}
// ============================ DelTemplate ============================
/**
* 删除模板。
* 前端: GET notice/Template/DelTemplate?serid=
*/
@GetMapping("DelTemplate")
public void delTemplate(@RequestParam("SerID") Integer serid) {
templateService.delTemplate(serid);
}
// ============================ GetTemplateFist ============================
/**
* 获取单个模板详情。
* 前端: GET notice/Template/GetTemplateFist?serid=
*/
@GetMapping("GetTemplateFist")
public Map<String, Object> getTemplateFist(@RequestParam("serid") Integer serid) {
return templateService.getTemplateFist(serid);
}
}