初始化提交

This commit is contained in:
liweijie
2026-08-18 09:49:02 +08:00
commit 5a74ab0b0d
1102 changed files with 119160 additions and 0 deletions
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
# zhjx 智慧教学项目
# 项目介绍
## 技术架构
* jdk 21
* maven 3.9.6
* springboot 3.1.1
* mysql 8.0.33
* DM8
* redis 7.2.13
### 目录介绍
* admin 启动类
* common 实体等
* quartz 定时任务
* system 系统管理
* sql目录下的jwgl.sql文件是未来所有新增功能需要在数据库执行更新的脚本
## 前端框架
* 前端采用Vue、Element UI。
+12
View File
@@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 清理所有target目录文件
echo.
%~d0
cd %~dp0
cd ..
call mvn clean
pause
+12
View File
@@ -0,0 +1,12 @@
@echo off
echo.
echo [信息] 打包Web项目,生成war/jar文件
echo.
%~d0
cd %~dp0
cd ..
call mvn clean package -Dmaven.test.skip=true
pause
+14
View File
@@ -0,0 +1,14 @@
@echo off
echo.
echo [信息] 使用Jar方式启动Web项目。
echo.
cd %~dp0
cd ../roomroot-admin/target
set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
java -jar %JAVA_OPTS% roomroot-admin.jar
cd bin
pause
+225
View File
@@ -0,0 +1,225 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roomroot</groupId>
<artifactId>roomroot</artifactId>
<version>3.9.2</version>
<name>roomroot</name>
<description>风影随行管理系统</description>
<properties>
<roomroot.version>3.9.2</roomroot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
<spring-boot.version>4.0.6</spring-boot.version>
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<druid.version>1.2.28</druid.version>
<yauaa.version>8.1.1</yauaa.version>
<kaptcha.version>2.3.3</kaptcha.version>
<fastjson.version>2.0.62</fastjson.version>
<oshi.version>7.3.0</oshi.version>
<commons.io.version>2.22.0</commons.io.version>
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<springdoc.version>3.0.3</springdoc.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-4-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>nl.basjes.parse.useragent</groupId>
<artifactId>yauaa</artifactId>
<version>${yauaa.version}</version>
</dependency>
<!-- MyBatis-Plus ORM框架 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api.version}</version>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>${oshi.version}</version>
</dependency>
<!-- spring-doc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- 验证码 -->
<dependency>
<groupId>pro.fessional</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<!-- 定时任务-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-quartz</artifactId>
<version>${roomroot.version}</version>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-generator</artifactId>
<version>${roomroot.version}</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-framework</artifactId>
<version>${roomroot.version}</version>
</dependency>
<!-- 系统模块-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-system</artifactId>
<version>${roomroot.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-common</artifactId>
<version>${roomroot.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>roomroot-admin</module>
<module>roomroot-framework</module>
<module>roomroot-system</module>
<module>roomroot-quartz</module>
<module>roomroot-generator</module>
<module>roomroot-common</module>
<module>roomroot-jwgl</module>
</modules>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<parameters>true</parameters>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
+101
View File
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>roomroot</artifactId>
<groupId>com.roomroot</groupId>
<version>3.9.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>roomroot-admin</artifactId>
<description>
web服务入口
</description>
<dependencies>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- spring-doc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
<!-- 达梦数据库驱动包 -->
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>8.1.2.192</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-framework</artifactId>
</dependency>
<!-- 定时任务-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-quartz</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-generator</artifactId>
</dependency>
<dependency>
<groupId>com.github.codemonstur</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>com.roomroot</groupId>
<artifactId>roomroot-jwgl</artifactId>
<version>3.9.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>
@@ -0,0 +1,49 @@
package com.roomroot;
import com.roomroot.web.core.config.EmbeddedRedisCondition;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import redis.embedded.RedisServer;
import java.io.IOException;
@Configuration
@Conditional(EmbeddedRedisCondition.class)
public class EmbeddedRedisConfig {
private final int redisPort;
private final String maxMemory;
private RedisServer redisServer;
public EmbeddedRedisConfig(
@Value("${custom.embedded-redis.port}") int redisPort,
@Value("${custom.embedded-redis.max-memory}") String maxMemory
) {
this.redisPort = redisPort;
this.maxMemory = maxMemory;
}
@PostConstruct
public void startEmbeddedRedis() throws IOException {
try {
redisServer = new RedisServer(redisPort);
// 可变参数追加redis配置
redisServer.start(
);
System.out.println("===== 内嵌Redis启动成功,端口:" + redisPort + " =====");
} catch (Exception e) {
e.printStackTrace();
System.err.println("内嵌Redis启动失败!端口:" + redisPort);
}
}
@PreDestroy
public void stopEmbeddedRedis() throws IOException {
if (redisServer != null && redisServer.isActive()) {
redisServer.stop();
System.out.println("===== 内嵌Redis已停止 =====");
}
}
}
@@ -0,0 +1,24 @@
package com.roomroot;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
/**
* 启动程序
*
* @author roomroot
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@MapperScan({"com.roomroot.**.mapper"})
public class RoomRootApplication
{
public static void main(String[] args)
{
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RoomRootApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 风影随行启动成功 ლ(´ڡ`ლ)゙ \n");
}
}
@@ -0,0 +1,18 @@
package com.roomroot;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
* web容器中进行部署
*
* @author roomroot
*/
public class RoomRootServletInitializer extends SpringBootServletInitializer
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
{
return application.sources(RoomRootApplication.class);
}
}
@@ -0,0 +1,94 @@
package com.roomroot.web.controller.common;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import jakarta.annotation.Resource;
import javax.imageio.ImageIO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import com.roomroot.common.config.RoomRootConfig;
import com.roomroot.common.constant.CacheConstants;
import com.roomroot.common.constant.Constants;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.redis.RedisCache;
import com.roomroot.common.utils.sign.Base64;
import com.roomroot.common.utils.uuid.IdUtils;
import com.roomroot.system.service.ISysConfigService;
/**
* 验证码操作处理
*
* @author roomroot
*/
@RestController
public class CaptchaController
{
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
@Autowired
private RedisCache redisCache;
@Autowired
private ISysConfigService configService;
/**
* 生成验证码
*/
@GetMapping("/captchaImage")
public AjaxResult getCode(HttpServletResponse response) throws IOException
{
AjaxResult ajax = AjaxResult.success();
boolean captchaEnabled = configService.selectCaptchaEnabled();
ajax.put("captchaEnabled", captchaEnabled);
if (!captchaEnabled)
{
return ajax;
}
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
String capStr = null, code = null;
BufferedImage image = null;
// 生成验证码
String captchaType = RoomRootConfig.getCaptchaType();
if ("math".equals(captchaType))
{
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try
{
ImageIO.write(image, "jpg", os);
}
catch (IOException e)
{
return AjaxResult.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
}
@@ -0,0 +1,166 @@
package com.roomroot.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import com.roomroot.system.service.ISysConfigService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.roomroot.common.config.RoomRootConfig;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.file.FileUploadUtils;
import com.roomroot.common.utils.file.FileUtils;
import com.roomroot.framework.config.ServerConfig;
/**
* 通用请求处理
*
* @author roomroot
*/
@RestController
@RequestMapping("/common")
public class CommonController
{
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
@Autowired
private ServerConfig serverConfig;
private static final String FILE_DELIMITER = ",";
@Autowired
private ISysConfigService configService;
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
{
try
{
if (!FileUtils.checkAllowDownload(fileName))
{
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
}
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RoomRootConfig.getDownloadPath() + fileName;
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete)
{
FileUtils.deleteFile(filePath);
}
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
/**
* 通用上传请求(单个)
*/
@PostMapping("/upload")
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try{
// 上传文件路径
String filePath = configService.selectConfigByKey("sys.document.path");
if(StringUtils.isEmpty(filePath)){
filePath = RoomRootConfig.getUploadPath();
}
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
/**
* 通用上传请求(多个)
*/
@PostMapping("/uploads")
public AjaxResult uploadFiles(List<MultipartFile> files) {
try{
// 上传文件路径
String filePath = configService.selectConfigByKey("sys.document.path");
if(StringUtils.isEmpty(filePath)){
filePath = RoomRootConfig.getUploadPath();
}
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMITER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMITER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMITER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMITER));
return ajax;
} catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
/**
* 本地资源通用下载
*/
@GetMapping("/download/resource")
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{
try
{
if (!FileUtils.checkAllowDownload(resource))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
}
// 本地资源路径
String localPath = RoomRootConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + FileUtils.stripPrefix(resource);
// 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
}
}
@@ -0,0 +1,330 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.accountmanagement.AccountCreateDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountDisableDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountIdDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountLoginDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountLoginInformationQueryDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountMergeDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountPasswordChangeDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountPasswordResetDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountQueryDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountRoleConfigurationDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountRoleOptionQueryDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountSsoSessionResolveDTO;
import com.roomroot.jwgl.dto.accountmanagement.AccountUpdateDTO;
import com.roomroot.jwgl.service.AccountManagementService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.accountmanagement.AccountMergeResultVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountLoginCaptchaVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountLoginInformationVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountLoginVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountRoleOptionVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountRoleTypeVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountRoleVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountSsoSessionVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 账户管理接口。
*/
@RestController
@RequestMapping("/account-management")
public class AccountManagementController {
/**
* 账户管理业务服务。
*/
@Resource
private AccountManagementService accountManagementService;
/**
* 查询账户列表。
*
* @param dto 账户查询条件
* @return 符合条件的账户分页结果
*/
@GetMapping("/list")
public Result<PageResult<AccountVO>> list(
@Valid AccountQueryDTO dto) {
// 调用业务层完成账户条件筛选、数据库分页和当前页角色批量装配。
return Result.success(accountManagementService.list(dto));
}
/**
* 查询账户详情。
*
* @param dto 账户编号参数
* @return 包含角色和数据范围的账户详情
*/
@GetMapping("/get")
public Result<AccountVO> get(@Valid AccountIdDTO dto) {
// 根据账户编号查询完整信息,并确保密码和密码提示答案不向页面返回。
return Result.success(accountManagementService.get(dto));
}
/**
* 新增账户并配置初始角色。
*
* @param dto 账户新增参数
* @return 新增后的账户详情
*/
@PostMapping("/add")
public Result<AccountVO> add(
@Valid @RequestBody AccountCreateDTO dto) {
// 调用业务层完成唯一性校验、账户写入、状态初始化和初始角色配置。
return Result.success("新增成功", accountManagementService.add(dto));
}
/**
* 修改账户基本信息。
*
* @param dto 账户修改参数
* @return 修改后的账户详情
*/
@PostMapping("/update")
public Result<AccountVO> update(
@Valid @RequestBody AccountUpdateDTO dto) {
// 普通修改只维护账户资料,不在当前接口隐式修改密码、状态或角色。
return Result.success(
"修改成功", accountManagementService.update(dto));
}
/**
* 停用账户。
*
* @param dto 账户停用参数
* @return 停用后的账户详情
*/
@PostMapping("/disable")
public Result<AccountVO> disable(
@Valid @RequestBody AccountDisableDTO dto) {
// 使用账户状态表进行软停用,保留账户及历史业务引用。
return Result.success(
"停用成功", accountManagementService.disable(dto));
}
/**
* 启用普通停用账户。
*
* @param dto 账户编号参数
* @return 启用后的账户详情
*/
@PostMapping("/enable")
public Result<AccountVO> enable(
@Valid @RequestBody AccountIdDTO dto) {
// 调用业务层清除普通停用信息,已合并的源账户不允许重新启用。
return Result.success(
"启用成功", accountManagementService.enable(dto));
}
/**
* 重置账户密码。
*
* @param dto 密码重置参数
* @return 密码重置后的账户详情
*/
@PostMapping("/reset-password")
public Result<AccountVO> resetPassword(
@Valid @RequestBody AccountPasswordResetDTO dto) {
// 调用业务层重置密码,并同步清除临时登录失败次数。
return Result.success(
"密码重置成功",
accountManagementService.resetPassword(dto));
}
/**
* 当前登录账户修改自己的密码。
*
* @param dto 原密码、新密码和确认密码
* @return 密码修改后的脱敏账户信息
*/
@PostMapping("/change-password")
public Result<AccountVO> changePassword(
@Valid @RequestBody AccountPasswordChangeDTO dto) {
/*
* 账户编号只从服务端登录会话读取,不接收客户端指定的目标账户,
* 防止普通账户通过修改请求参数变更其他账户的密码。
*/
return Result.success(
"密码修改成功,请重新登录",
accountManagementService.changePassword(dto));
}
/**
* 查询当前登录账户的登录信息和成功登录历史。
*
* @param dto 登录历史分页参数
* @return 当前账户的上次、本次登录时间和成功登录历史
*/
@GetMapping("/login-information")
public Result<AccountLoginInformationVO> loginInformation(
@Valid AccountLoginInformationQueryDTO dto) {
/*
* 查询目标只从服务端当前会话取得,不接收客户端账户编号,
* 因此普通登录账户只能查看自己的登录信息和登录历史。
*/
return Result.success(
accountManagementService.getLoginInformation(dto));
}
/**
* 生成本地账户登录使用的一次性图形验证码。
*
* @param response 当前 HTTP 响应
* @return 验证码编号、PNG 图片数据和有效秒数
*/
@GetMapping("/login-captcha")
public Result<AccountLoginCaptchaVO> loginCaptcha(
HttpServletResponse response) {
/*
* 第一步:禁止浏览器和中间代理缓存验证码响应,
* 防止刷新页面时继续显示已经失效的旧验证码。
*/
response.setHeader("Cache-Control",
"no-store, no-cache, must-revalidate, max-age=0");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0L);
/*
* 第二步:生成验证码并保存到当前 Servlet Session
* 页面只会收到验证码编号和图片,不会收到验证码答案。
*/
return Result.success(
accountManagementService.generateLoginCaptcha());
}
/**
* 使用本地账号密码登录。
*
* @param dto 本地账号密码登录参数
* @return 脱敏后的本地账户信息和角色
*/
@PostMapping("/login")
public Result<AccountLoginVO> login(
@Valid @RequestBody AccountLoginDTO dto) {
/*
* 本地登录接口只负责接收登录参数并返回脱敏结果;
* 验证码、密码、账户状态检查和 Servlet Session 建立全部由业务层完成。
*/
return Result.success(
"登录成功", accountManagementService.login(dto));
}
/**
* 校验 SSO 会话、建立本地登录状态并解析唯一的本地账户。
*
* @param dto SSO 会话解析参数
* @return SSO 会话及其对应的本地账户信息;本地 Session 标识不直接返回
*/
@PostMapping("/resolve-sso-session")
public Result<AccountSsoSessionVO> resolveSsoSession(
@Valid @RequestBody AccountSsoSessionResolveDTO dto) {
/*
* 第一步:把会话标识交给业务层校验有效期。
* 第二步:同时使用 LoginID 和 UserID 解析唯一的本地统一账号。
* 第三步:仅返回不包含密码和 SSO 会话标识的核验结果。
*/
return Result.success(
accountManagementService.resolveSsoSession(dto));
}
/**
* 退出当前登录会话。
*
* @return 不包含业务数据的退出结果
*/
@PostMapping("/logout")
public Result<Void> logout() {
// 调用业务层清理当前在线记录并作废本地 Servlet Session。
accountManagementService.logout();
// 退出接口没有业务返回对象,因此使用 Result<Void> 返回统一成功结果。
return Result.success("退出登录成功", null);
}
/**
* 查询系统支持的角色类型。
*
* @return 角色类型列表
*/
@GetMapping("/role-types")
public Result<List<AccountRoleTypeVO>> roleTypes() {
// 返回与角色配置、查询和合并流程一致的七类角色定义。
return Result.success(accountManagementService.listRoleTypes());
}
/**
* 查询指定角色类型下的身份选项。
*
* @param dto 角色身份查询条件
* @return 角色身份选项分页结果
*/
@GetMapping("/role-options")
public Result<PageResult<AccountRoleOptionVO>> roleOptions(
@Valid AccountRoleOptionQueryDTO dto) {
// 调用业务层完成角色类型、关键字、绑定状态筛选和数据库分页。
return Result.success(
accountManagementService.listRoleOptions(dto));
}
/**
* 查询账户已有角色和数据范围。
*
* @param dto 账户编号参数
* @return 账户角色列表
*/
@GetMapping("/roles")
public Result<List<AccountRoleVO>> roles(
@Valid AccountIdDTO dto) {
// 查询账户现有全部身份绑定,并补充统一角色名称。
return Result.success(accountManagementService.listRoles(dto));
}
/**
* 整体配置账户角色和数据范围。
*
* @param dto 账户角色配置参数
* @return 配置完成后的账户详情
*/
@PostMapping("/configure-roles")
public Result<AccountVO> configureRoles(
@Valid @RequestBody AccountRoleConfigurationDTO dto) {
/*
* 业务层会先预校验全部身份,再在同一事务中替换角色,
* 避免部分身份无效时已经清除了账户原有角色。
*/
return Result.success(
"角色配置成功",
accountManagementService.configureRoles(dto));
}
/**
* 合并重复账户。
*
* @param dto 账户合并参数
* @return 合并后的源账户和目标账户信息
*/
@PostMapping("/merge")
public Result<AccountMergeResultVO> merge(
@Valid @RequestBody AccountMergeDTO dto) {
/*
* 合并只迁移角色和数据范围,不物理删除源账户,
* 从而保留其他历史业务表对源账户的原始引用。
*/
return Result.success(
"账户合并成功", accountManagementService.merge(dto));
}
}
@@ -0,0 +1,246 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.affiliationsetting.PersonnelAffiliationDTO;
import com.roomroot.jwgl.dto.affiliationsetting.PersonnelTransferDTO;
import com.roomroot.jwgl.dto.affiliationsetting.ResearchOfficeAffiliationAddDTO;
import com.roomroot.jwgl.dto.affiliationsetting.ResearchOfficeAffiliationIdDTO;
import com.roomroot.jwgl.dto.affiliationsetting.ResearchOfficeAffiliationQueryDTO;
import com.roomroot.jwgl.dto.affiliationsetting.ResearchOfficeOptionQueryDTO;
import com.roomroot.jwgl.dto.affiliationsetting.TeachingClassAffiliationDTO;
import com.roomroot.jwgl.service.AffiliationSettingService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.affiliationsetting.AffiliationDepartmentVO;
import com.roomroot.jwgl.vo.affiliationsetting.PersonnelAffiliationVO;
import com.roomroot.jwgl.vo.affiliationsetting.ResearchOfficeAffiliationVO;
import com.roomroot.jwgl.vo.affiliationsetting.ResearchOfficeVO;
import com.roomroot.jwgl.vo.affiliationsetting.TeachingClassAffiliationVO;
import com.roomroot.jwgl.vo.affiliationsetting.TransferHistoryVO;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 隶属关系设置统一接口。
*
* <p>该控制器统一承载教研室和教学班次两类隶属关系接口,
* 同时保留原有请求路径,避免前端调用方式发生变化。</p>
*/
@RestController
public class AffiliationSettingController {
/**
* 隶属关系设置统一业务服务。
*/
@Resource
private AffiliationSettingService affiliationSettingService;
/**
* 查询可供页面选择的启用部别。
*
* @param dto 查询条件
* @return 可选部别列表
*/
@GetMapping("/research-office-affiliation/departments")
public Result<List<AffiliationDepartmentVO>> researchOfficeDepartments(
@Valid ResearchOfficeOptionQueryDTO dto) {
// 调用业务层查询启用部别,并返回专用于页面展示的 VO 列表。
return Result.success(
affiliationSettingService.listResearchOfficeDepartments(dto));
}
/**
* 查询指定部别已经关联的教研室。
*
* @param dto 部别编号及查询条件
* @return 已建立的教研室隶属关系列表
*/
@GetMapping("/research-office-affiliation/list")
public Result<List<ResearchOfficeAffiliationVO>> researchOfficeList(
@Valid ResearchOfficeAffiliationQueryDTO dto) {
// 调用业务层查询当前部别的全部隶属关系,并返回包含教研室展示字段的 VO。
return Result.success(
affiliationSettingService.listResearchOfficeAffiliations(dto));
}
/**
* 查询尚未分配且处于启用状态的教研室。
*
* @param dto 查询条件
* @return 可添加的教研室列表
*/
@GetMapping("/research-office-affiliation/available")
public Result<List<ResearchOfficeVO>> availableResearchOffices(
@Valid ResearchOfficeOptionQueryDTO dto) {
// 调用业务层排除已经存在隶属关系的教研室,返回可添加的教研室 VO。
return Result.success(
affiliationSettingService.listAvailableResearchOffices(dto));
}
/**
* 新增教研室隶属关系。
*
* @param dto 部别编号和教研室编号
* @return 新增后的隶属关系
*/
@PostMapping("/research-office-affiliation/add")
public Result<ResearchOfficeAffiliationVO> addResearchOfficeAffiliation(
@Valid @RequestBody ResearchOfficeAffiliationAddDTO dto) {
// 调用业务层完成校验和新增,并将持久化后的关系 VO 返回给前端。
return Result.success(
"添加成功",
affiliationSettingService.addResearchOfficeAffiliation(dto));
}
/**
* 解除教研室隶属关系。
*
* @param dto 隶属关系编号
* @return 被解除的隶属关系
*/
@PostMapping("/research-office-affiliation/remove")
public Result<ResearchOfficeAffiliationVO> removeResearchOfficeAffiliation(
@Valid @RequestBody ResearchOfficeAffiliationIdDTO dto) {
// 按关系编号解除隶属关系,避免仅凭教研室编号误删其他业务数据。
return Result.success(
"解除成功",
affiliationSettingService.removeResearchOfficeAffiliation(dto));
}
/**
* 查询可供教学班次隶属关系页面选择的启用部别。
*
* @param dto 查询条件
* @return 可选部别列表
*/
@GetMapping("/teaching-class-affiliation/departments")
public Result<List<AffiliationDepartmentVO>> teachingClassDepartments(
@Valid TeachingClassAffiliationDTO dto) {
// 调用统一业务层查询启用部别,并返回与数据库实体隔离的共享部别 VO。
return Result.success(
affiliationSettingService.listTeachingClassDepartments(dto));
}
/**
* 查询指定部别已经关联的教学班次。
*
* @param dto 部别编号及查询条件
* @return 已建立的教学班次隶属关系列表
*/
@GetMapping("/teaching-class-affiliation/list")
public Result<List<TeachingClassAffiliationVO>> teachingClassList(
@Valid TeachingClassAffiliationDTO dto) {
// 调用统一业务层查询当前部别的全部教学班次关系,并组装页面展示 VO。
return Result.success(
affiliationSettingService.listTeachingClassAffiliations(dto));
}
/**
* 查询尚未分配给任何部别的教学班次。
*
* @param dto 查询条件
* @return 可添加的教学班次列表
*/
@GetMapping("/teaching-class-affiliation/available")
public Result<List<TeachingClassAffiliationVO>> availableTeachingClasses(
@Valid TeachingClassAffiliationDTO dto) {
// 调用统一业务层排除已经存在隶属关系的班次,并返回可添加的教学班次 VO。
return Result.success(
affiliationSettingService.listAvailableTeachingClasses(dto));
}
/**
* 新增教学班次隶属关系。
*
* @param dto 部别编号和教学班次编号
* @return 新增后的隶属关系
*/
@PostMapping("/teaching-class-affiliation/add")
public Result<TeachingClassAffiliationVO> addTeachingClassAffiliation(
@Valid @RequestBody TeachingClassAffiliationDTO dto) {
// 调用统一业务层完成参数校验、冲突检查和关系新增,并返回新增后的关系 VO。
return Result.success(
"添加成功",
affiliationSettingService.addTeachingClassAffiliation(dto));
}
/**
* 解除教学班次隶属关系。
*
* @param dto 部别编号和教学班次编号
* @return 被解除的隶属关系
*/
@PostMapping("/teaching-class-affiliation/remove")
public Result<TeachingClassAffiliationVO> removeTeachingClassAffiliation(
@Valid @RequestBody TeachingClassAffiliationDTO dto) {
// 按照部别编号和教学班次编号精确解除关系,避免旧页面请求误删新归属。
return Result.success(
"解除成功",
affiliationSettingService.removeTeachingClassAffiliation(dto));
}
// ============ 人员隶属关系统一接口(方向1新增)============
/**
* 查询人员当前隶属关系。
* <p>支持按人员类型+部门编号筛选,可附加关键字匹配姓名/拼音。</p>
*
* @param dto 查询条件
* @return 人员隶属关系列表
*/
@GetMapping("/affiliation/personnel/list")
public Result<List<PersonnelAffiliationVO>> personnelList(@Valid PersonnelAffiliationDTO dto) {
return Result.success(affiliationSettingService.listPersonnelAffiliations(dto));
}
/**
* 分配人员到部门/组织单元(首次归属)。
* <p>若人员已有归属,返回冲突错误,提示走异动接口。</p>
*
* @param dto 分配参数
* @return 分配后的人员隶属关系
*/
@PostMapping("/affiliation/personnel/assign")
public Result<PersonnelAffiliationVO> assignPersonnel(@Valid @RequestBody PersonnelAffiliationDTO dto) {
return Result.success("分配成功", affiliationSettingService.assignPersonnel(dto));
}
/**
* 解除人员隶属关系(清空当前归属)。
*
* @param dto 解除参数
* @return 解除后的人员隶属关系
*/
@PostMapping("/affiliation/personnel/unassign")
public Result<PersonnelAffiliationVO> unassignPersonnel(@Valid @RequestBody PersonnelAffiliationDTO dto) {
return Result.success("解除成功", affiliationSettingService.unassignPersonnel(dto));
}
/**
* 人员异动调整(核心接口)。
* <p>记录异动历史 + 更新归属 + 校验关联表,必须填写异动原因。</p>
*
* @param dto 异动参数
* @return 异动后的人员隶属关系
*/
@PostMapping("/affiliation/personnel/transfer")
public Result<PersonnelAffiliationVO> transferPersonnel(@Valid @RequestBody PersonnelTransferDTO dto) {
return Result.success("异动成功", affiliationSettingService.transferPersonnel(dto));
}
/**
* 查询人员异动历史。
*
* @param dto 查询参数
* @return 异动历史VO(含JSON原文)
*/
@GetMapping("/affiliation/personnel/history")
public Result<TransferHistoryVO> personnelHistory(@Valid PersonnelAffiliationDTO dto) {
return Result.success(affiliationSettingService.getTransferHistory(dto));
}
}
@@ -0,0 +1,76 @@
package com.roomroot.web.controller.jwgl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.jwgl.entity.BZLB;
import com.roomroot.jwgl.service.BZLBService;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 保障类别 Controller
*/
@RestController
@RequestMapping("/bzlb")
public class BZLBController {
@Resource
private BZLBService bzlbService;
/**
* 新增保障类别
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody BZLB bzlb) {
bzlbService.add(bzlb);
return Result.success();
}
/**
* 删除保障类别
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
bzlbService.delete(bh);
return Result.success();
}
/**
* 更新保障类别
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody BZLB bzlb) {
bzlbService.update(bzlb);
return Result.success();
}
/**
* 根据编号查询保障类别
*/
@GetMapping("/get")
public Result<BZLB> get(@RequestParam("bh") String bh) {
return Result.success(bzlbService.getByBh(bh));
}
/**
* 分页查询保障类别
*/
@GetMapping("/list")
public Result<Page<BZLB>> list(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
BZLB bzlb) {
return Result.success(bzlbService.list(pageNum, pageSize, bzlb));
}
/**
* 查询所有启用的保障类别
*/
@GetMapping("/all")
public Result<List<BZLB>> all() {
return Result.success(bzlbService.all());
}
}
@@ -0,0 +1,92 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JXLB;
import com.roomroot.jwgl.service.BuildService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 教学楼表控制器
*/
@RestController
@RequestMapping("/build")
public class BuildController {
@Resource
private BuildService buildService;
/**
* 新增教学楼
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JXLB jxlb) {
buildService.add(jxlb);
return Result.success();
}
/**
* 删除教学楼
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
buildService.delete(id);
return Result.success();
}
/**
* 更新教学楼
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JXLB jxlb) {
buildService.update(jxlb);
return Result.success();
}
/**
* 根据ID查询
*/
@GetMapping("/get")
public Result<JXLB> getById(@RequestParam("id") String id) {
return Result.success(buildService.getById(id));
}
/**
* 分页查询教学楼列表
*/
@GetMapping("/list")
public Result<PageResult<JXLB>> list(PageQuery query, JXLB jxlb) {
return Result.success(buildService.pageList(query, jxlb));
}
/**
* 查询所有教学楼列表
*/
@GetMapping("/all")
public Result<List<JXLB>> all(JXLB jxlb) {
return Result.success(buildService.list(jxlb));
}
/**
* 导入Excel文件
*/
@PostMapping("/import")
public Result<Integer> importExcel(@RequestParam("file") MultipartFile file) {
int count = buildService.importExcel(file);
return Result.success("导入成功", count);
}
/**
* 下载模板文件
*/
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) {
buildService.downloadTemplate(response);
}
}
@@ -0,0 +1,89 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JXCDL;
import com.roomroot.jwgl.service.ClassRoomCalendarService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 教学场地历控制器
*/
@RestController
@RequestMapping("/classroom/jxcdl")
public class ClassRoomCalendarController {
@Resource
private ClassRoomCalendarService calendarService;
/**
* 新增教学场地历
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JXCDL jxcdl) {
calendarService.add(jxcdl);
return Result.success();
}
/**
* 删除教学场地历
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
calendarService.delete(id);
return Result.success();
}
/**
* 更新教学场地历
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JXCDL jxcdl) {
calendarService.update(jxcdl);
return Result.success();
}
/**
* 根据ID查询
*/
@GetMapping("/get")
public Result<JXCDL> getById(@RequestParam("id") String id) {
return Result.success(calendarService.getById(id));
}
/**
* 分页查询教学场地历列表
*/
@GetMapping("/list")
public Result<PageResult<JXCDL>> list(PageQuery query, JXCDL jxcdl) {
return Result.success(calendarService.pageList(query, jxcdl));
}
/**
* 查询所有教学场地历列表
*/
@GetMapping("/all")
public Result<List<JXCDL>> all(JXCDL jxcdl) {
return Result.success(calendarService.list(jxcdl));
}
/**
* 根据教室编号查询教学场地历列表
*/
@GetMapping("/listByJsbh")
public Result<List<JXCDL>> listByJsbh(@RequestParam("jsbh") String jsbh) {
return Result.success(calendarService.listByJsbh(jsbh));
}
/**
* 根据日期查询教学场地历列表
*/
@GetMapping("/listByRq")
public Result<List<JXCDL>> listByRq(@RequestParam("rq") String rq) {
return Result.success(calendarService.listByRq(rq));
}
}
@@ -0,0 +1,81 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JSB;
import com.roomroot.jwgl.service.ClassRoomService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 教室表控制器
*/
@RestController
@RequestMapping("/classroom")
public class ClassRoomController {
@Resource
private ClassRoomService jsbService;
/**
* 新增教室
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JSB jsb) {
jsbService.add(jsb);
return Result.success();
}
/**
* 删除教室
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
jsbService.delete(id);
return Result.success();
}
/**
* 更新教室
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JSB jsb) {
jsbService.update(jsb);
return Result.success();
}
/**
* 根据教室编号查询
*/
@GetMapping("/get")
public Result<JSB> getById(@RequestParam("id") String id) {
return Result.success(jsbService.getById(id));
}
/**
* 分页查询教室列表
*/
@GetMapping("/list")
public Result<PageResult<JSB>> list(PageQuery query, JSB jsb) {
return Result.success(jsbService.pageList(query, jsb));
}
/**
* 查询所有教室列表
*/
@GetMapping("/all")
public Result<List<JSB>> all(JSB jsb) {
return Result.success(jsbService.list(jsb));
}
/**
* 根据教学楼代号查询教室列表
*/
@GetMapping("/listByJxldh")
public Result<List<JSB>> listByJxldh(@RequestParam("jxldh") String jxldh) {
return Result.success(jsbService.listByJxldh(jxldh));
}
}
@@ -0,0 +1,83 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JSBKCB;
import com.roomroot.jwgl.service.ClassRoomLessonService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 教室输出课程表控制器
*/
@RestController
@RequestMapping("/classRoomLesson")
public class ClassRoomLessonController {
@Resource
private ClassRoomLessonService lessonService;
/**
* 新增教室输出课程表
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JSBKCB jsbkcb) {
lessonService.add(jsbkcb);
return Result.success();
}
/**
* 删除教室输出课程表
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
lessonService.delete(id);
return Result.success();
}
/**
* 更新教室输出课程表
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JSBKCB jsbkcb) {
lessonService.update(jsbkcb);
return Result.success();
}
/**
* 根据ID查询
*/
@GetMapping("/get")
public Result<JSBKCB> getById(@RequestParam("id") String id) {
return Result.success(lessonService.getById(id));
}
/**
* 根据教室编号和年度查询
*/
@GetMapping("/getByJsbhAndNd")
public Result<JSBKCB> getByJsbhAndNd(@RequestParam("jsbh") String jsbh,
@RequestParam("nd") Integer nd) {
return Result.success(lessonService.getByJsbhAndNd(jsbh, nd));
}
/**
* 分页查询教室输出课程表列表
*/
@GetMapping("/list")
public Result<PageResult<JSBKCB>> list(PageQuery query, JSBKCB jsbkcb) {
return Result.success(lessonService.pageList(query, jsbkcb));
}
/**
* 查询所有教室输出课程表列表
*/
@GetMapping("/all")
public Result<List<JSBKCB>> all(JSBKCB jsbkcb) {
return Result.success(lessonService.list(jsbkcb));
}
}
@@ -0,0 +1,82 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XYDRWB;
import com.roomroot.jwgl.service.ClassSemesterCalendarService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* 学员队任务表控制器
*/
@RestController
@RequestMapping("/classCalendar")
public class ClassSemesterCalendarController {
@Resource
private ClassSemesterCalendarService classSemesterCalendarService;
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYDRWB xydrwb) {
classSemesterCalendarService.update(xydrwb);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<XYDRWB> getByBh(@RequestParam("bh") String bh) {
return Result.success(classSemesterCalendarService.getByBh(bh));
}
/**
* 条目批次复制
* <p>
* 根据源学员队任务表编号集合,复制到多个目标学员队期表下,
* 替换学员队学期编号和学员队编号为目标学员队期表的值
* </p>
*
* @param params 包含sourceBhList(源编号列表)和targetBhList(目标学员队期表编号列表)
* @return 复制结果
*/
@PostMapping("/batchCopy")
public Result<Map<String, Object>> batchCopy(@RequestBody Map<String, Object> params) {
List<String> sourceBhList = (List<String>) params.get("sourceBhList");
List<String> targetBhList = (List<String>) params.get("targetBhList");
Map<String, Object> result = classSemesterCalendarService.batchCopy(sourceBhList, targetBhList);
return Result.success(result);
}
/**
* 按学期批次复制
* <p>
* 根据源学员队期表编号查询其下所有任务条目,复制到多个目标学员队期表下,
* 替换学员队学期编号和学员队编号为目标学员队期表的值
* </p>
*
* @param params 包含sourceXydxqbh(源学员队期表编号)和targetBhList(目标学员队期表编号列表)
* @return 复制结果
*/
@PostMapping("/batchCopyBySemester")
public Result<Map<String, Object>> batchCopyBySemester(@RequestBody Map<String, Object> params) {
String sourceXydxqbh = (String) params.get("sourceXydxqbh");
List<String> targetBhList = (List<String>) params.get("targetBhList");
Map<String, Object> result = classSemesterCalendarService.batchCopyBySemester(sourceXydxqbh, targetBhList);
return Result.success(result);
}
/**
* 查询所有有效数据(DEL_FLAG = 0
*/
@GetMapping("/all")
public Result<List<XYDRWB>> all(XYDRWB xydrwb) {
return Result.success(classSemesterCalendarService.listAllValid(xydrwb));
}
}
@@ -0,0 +1,172 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
import com.roomroot.jwgl.service.ClassSemesterService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 班次学期控制器
*/
@RestController
@RequestMapping("/classSemester")
public class ClassSemesterController {
@Resource
private ClassSemesterService classSemesterService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XYDNDXQJBXXB xydndxqjbxxb) {
classSemesterService.add(xydndxqjbxxb);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
classSemesterService.delete(bh);
return Result.success();
}
/**
* 批量删除
*/
@PostMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> bhList) {
classSemesterService.batchDelete(bhList);
return Result.success();
}
/**
* 批量修改日期范围
* <p>
* 更新班次学期的日期范围,并同步更新班次学期日历:
* 1. 删除日期范围之外的日历记录
* 2. 补充新日期范围内缺少的日历记录
* </p>
* @return 更新数量
*/
@PostMapping("/batchUpdateDateRange")
public Result<Integer> batchUpdateDateRange(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");//编号列表
String xqkssj = (String) params.get("xqkssj");//学期开始时间
String xqjssj = (String) params.get("xqjssj");//学期结束时间
int count = classSemesterService.batchUpdateDateRange(bhList, xqkssj, xqjssj);
return Result.success(count);
}
/**
* 批量修改开放教员排课状态
*
* @param bhList XYDNDXQJBXXB编号列表
* @param kfjypk 开放教员排课(0-否,1-是)
* @return 更新数量
*/
@PostMapping("/batchUpdateKfjypk")
public Result<Integer> batchUpdateKfjypk(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
Integer kfjypk = (Integer) params.get("kfjypk");
int count = classSemesterService.batchUpdateKfjypk(bhList, kfjypk);
return Result.success(count);
}
/**
* 批量修改学期第次
*
* @param bhList XYDNDXQJBXXB编号列表
* @param xqdc 学期第次
* @return 更新数量
*/
@PostMapping("/batchUpdateXqdc")
public Result<Integer> batchUpdateXqdc(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
Integer xqdc = (Integer) params.get("xqdc");
int count = classSemesterService.batchUpdateXqdc(bhList, xqdc);
return Result.success(count);
}
/**
* 批量修改教学任务编号
*
* @return 更新数量
*/
@PostMapping("/batchUpdateJxrwbh")
public Result<Integer> batchUpdateJxrwbh(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
String jxrwbh = (String) params.get("jxrwbh");//教学任务编号
int count = classSemesterService.batchUpdateJxrwbh(bhList, jxrwbh);
return Result.success(count);
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYDNDXQJBXXB xydndxqjbxxb) {
classSemesterService.update(xydndxqjbxxb);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<XYDNDXQJBXXB> getByBh(@RequestParam("bh") String bh) {
return Result.success(classSemesterService.getByBh(bh));
}
/**
* 分页查询列表
*/
@GetMapping("/list")
public Result<PageResult<XYDNDXQJBXXB>> list(PageQuery query, XYDNDXQJBXXB xydndxqjbxxb) {
return Result.success(classSemesterService.pageList(query, xydndxqjbxxb));
}
/**
* 查询所有有效数据(DEL_FLAG = 0
*/
@GetMapping("/all")
public Result<List<XYDNDXQJBXXB>> all() {
return Result.success(classSemesterService.listAllValid());
}
/**
* 根据选修班次列表批量添加班次学期
* <p>
* 根据时间范围过滤学员队表,批量添加班次学期信息,并生成对应的班次学期日历
* 筛选条件:入学日期 <= startTime 且 毕业日期 >= endTime
* </p>
*
* @param startTime 时间范围开始
* @param endTime 时间范围结束
* @param nd 年度
* @param xqdc 学期第次
* @return 添加数量
*/
@PostMapping("/batchAddFromElective")
public Result<Integer> batchAddFromElective(
@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime,
@RequestParam("nd") String nd,
@RequestParam("xqdc") String xqdc) {
LocalDateTime start = LocalDateTime.parse(startTime + "T00:00:00");
LocalDateTime end = LocalDateTime.parse(endTime + "T23:59:59");
int count = classSemesterService.batchAddFromElective(start, end, nd, xqdc, startTime, endTime);
return Result.success(count);
}
}
@@ -0,0 +1,829 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.courserunning.ClassesImportDTO;
import com.roomroot.jwgl.dto.courserunning.ImportRemoveDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustApplyDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustStrategyDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustAuditDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustQueryDTO;
import com.roomroot.jwgl.dto.courserunning.SemesterImportDTO;
import com.roomroot.jwgl.dto.courserunning.SingleCourseImportDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingPlanBatchFillDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingPlanFillDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingPlanQueryDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingSupportBatchPlanDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingSupportConfirmDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingSupportPlanDTO;
import com.roomroot.jwgl.dto.courserunning.TeachingSupportUpdateDTO;
import com.roomroot.jwgl.dto.courserunning.StudentLeaveApplyDTO;
import com.roomroot.jwgl.dto.courserunning.StudentLeaveAuditDTO;
import com.roomroot.jwgl.dto.courserunning.StudentLeaveQueryDTO;
import com.roomroot.jwgl.dto.courserunning.OperationAnalysisQueryDTO;
import com.roomroot.jwgl.service.CourseRunningImportService;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.utils.BasicManagementConstants;
import com.roomroot.jwgl.utils.ExcelParseUtil;
import com.roomroot.jwgl.vo.courserunning.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import jakarta.annotation.Resource;
import tools.jackson.databind.ObjectMapper;
import java.util.List;
/**
* 课程教学运行管理控制器。
* <p>
* 提供课程教学运行管理的全部REST API接口,包括:<br>
* 1. 教学运行数据导入:整学期导入、教学班次导入、单门课程导入、删除已导入课程;<br>
* 2. 教学实施计划填写:课次列表查询、详情查询、单条填写、批量填写、提交;<br>
* 3. 调课管理:调课申请列表查询、详情查询、教员提交申请、教研室审批、教研室查收、机关审批、机关查收、撤销申请;<br>
* 4. 教学保障管理:保障资源查询、保障计划列表查询、单条登记、批量登记、修改、删除、确认到位、批量确认、取消确认。
* </p>
*/
@RestController
@RequestMapping("/course-running")
public class CourseRunningController {
/**
* 课程教学运行管理业务服务。
*/
@Resource
private CourseRunningImportService courseRunningImportService;
/**
* JSON 序列化工具。
*/
@Resource
private ObjectMapper objectMapper;
// ==================== 教学运行数据导入 ====================
/**
* 按学期导入课程。
* <p>
* 支持两种导入方式:<br>
* 1. JSON 方式:请求 Content-Type 为 application/json,传入 {@link SemesterImportDTO}<br>
* 2. Excel 方式:请求 Content-Type 为 multipart/form-data,上传 Excel 文件。<br>
* Excel 表头为:年度、学期第次。
* </p>
*
* @param request HTTP 请求对象
* @return 导入结果
*/
@PostMapping("/import/semester")
public Result<CourseRunningImportResultVO> importBySemester(HttpServletRequest request) throws Exception {
String contentType = request.getContentType();
if (contentType != null && contentType.toLowerCase().contains("multipart")) {
MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空", BasicManagementConstants.BAD_REQUEST);
}
List<SemesterImportDTO> paramsList = ExcelParseUtil.parseCourseSemesterImportExcel(
file.getInputStream(), file.getOriginalFilename());
if (paramsList.isEmpty()) {
throw new ServiceException("Excel 中无有效导入数据", BasicManagementConstants.BAD_REQUEST);
}
return Result.success("Excel导入成功",
courseRunningImportService.importBySemester(paramsList.get(0)));
}
SemesterImportDTO dto = objectMapper.readValue(request.getInputStream(), SemesterImportDTO.class);
return Result.success("导入成功", courseRunningImportService.importBySemester(dto));
}
/**
* 按教学班次导入课程。
* <p>
* 支持两种导入方式:<br>
* 1. JSON 方式:请求 Content-Type 为 application/json,传入 {@link ClassesImportDTO}<br>
* 2. Excel 方式:请求 Content-Type 为 multipart/form-data,上传 Excel 文件。<br>
* Excel 表头为:教学班次编号、年度。
* </p>
*
* @param request HTTP 请求对象
* @return 导入结果
*/
@PostMapping("/import/classes")
public Result<CourseRunningImportResultVO> importByClasses(HttpServletRequest request) throws Exception {
String contentType = request.getContentType();
if (contentType != null && contentType.toLowerCase().contains("multipart")) {
MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空", BasicManagementConstants.BAD_REQUEST);
}
List<ClassesImportDTO> paramsList = ExcelParseUtil.parseCourseClassesImportExcel(
file.getInputStream(), file.getOriginalFilename());
if (paramsList.isEmpty()) {
throw new ServiceException("Excel 中无有效导入数据", BasicManagementConstants.BAD_REQUEST);
}
return Result.success("Excel导入成功",
courseRunningImportService.importByClasses(paramsList.get(0)));
}
ClassesImportDTO dto = objectMapper.readValue(request.getInputStream(), ClassesImportDTO.class);
return Result.success("导入成功", courseRunningImportService.importByClasses(dto));
}
/**
* 导入单门课程。
* <p>
* 支持两种导入方式:<br>
* 1. JSON 方式:请求 Content-Type 为 application/json,传入 {@link SingleCourseImportDTO}<br>
* 2. Excel 方式:请求 Content-Type 为 multipart/form-data,上传 Excel 文件。<br>
* Excel 表头为:课程编号、教学班次编号、年度。
* </p>
*
* @param request HTTP 请求对象
* @return 导入结果
*/
@PostMapping("/import/single")
public Result<CourseRunningImportResultVO> importSingleCourse(HttpServletRequest request) throws Exception {
String contentType = request.getContentType();
if (contentType != null && contentType.toLowerCase().contains("multipart")) {
MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空", BasicManagementConstants.BAD_REQUEST);
}
List<SingleCourseImportDTO> paramsList = ExcelParseUtil.parseCourseSingleImportExcel(
file.getInputStream(), file.getOriginalFilename());
if (paramsList.isEmpty()) {
throw new ServiceException("Excel 中无有效导入数据", BasicManagementConstants.BAD_REQUEST);
}
return Result.success("Excel导入成功",
courseRunningImportService.importSingleCourse(paramsList.get(0)));
}
SingleCourseImportDTO dto = objectMapper.readValue(request.getInputStream(), SingleCourseImportDTO.class);
return Result.success("导入成功", courseRunningImportService.importSingleCourse(dto));
}
/**
* 删除已导入课程。
* <p>
* 删除已导入到课程教学运行管理子系统的课次数据,支持按学期、班次或单个课次删除。
* </p>
*
* @param params 删除参数(包含删除范围、课次编号列表和年度)
* @return 操作结果
*/
@DeleteMapping("/import/remove")
public Result<Void> removeImportedCourses(@Valid @RequestBody ImportRemoveDTO params) {
courseRunningImportService.removeImportedCourses(params);
return Result.success();
}
// ==================== 教学实施计划填写 ====================
/**
* 分页查询待填写或已填写的课次列表。
* <p>
* 根据查询条件分页查询课次列表,支持按实施课程编号、年度、教学方法、
* 日期范围和填写状态筛选,返回课次基本信息及填写状态。
* </p>
*
* @param query 查询参数(包含分页信息和筛选条件)
* @return 分页课次列表
*/
@GetMapping("/plan/list")
public Result<PageResult<TeachingPlanLessonVO>> queryLessonList(TeachingPlanQueryDTO query) {
return Result.success(courseRunningImportService.queryLessonList(query));
}
/**
* 按当前查询条件导出课次数据为 Excel 文件。
*
* @param query 查询参数
* @return Excel 文件下载响应
*/
@GetMapping("/plan/export")
public ResponseEntity<byte[]> exportLessonList(TeachingPlanQueryDTO query) {
byte[] excelBytes = courseRunningImportService.exportLessonListToExcel(query);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", "课次数据.xlsx");
return ResponseEntity.ok()
.headers(headers)
.body(excelBytes);
}
/**
* 查询单个课次的教学实施计划详情。
* <p>
* 根据课次编号查询该课次的完整教学实施计划信息。
* </p>
*
* @param sskcbbh 实施_课程表编号(课次编号)
* @return 教学实施计划详情
*/
@GetMapping("/plan/detail")
public Result<TeachingPlanDetailVO> getTeachingPlanDetail(@RequestParam("sskcbbh") String sskcbbh) {
return Result.success(courseRunningImportService.getTeachingPlanDetail(sskcbbh));
}
/**
* 单条填写教学实施计划。
* <p>
* 对单个课次填写教学实施计划内容,保存后填写状态更新为"已填写"。
* </p>
*
* @param dto 教学实施计划填写参数
* @return 填写结果
*/
@PostMapping("/plan/fill")
public Result<TeachingPlanFillResultVO> fillTeachingPlan(@Valid @RequestBody TeachingPlanFillDTO dto) {
return Result.success("填写成功", courseRunningImportService.fillTeachingPlan(dto));
}
/**
* 批量填写教学实施计划。
* <p>
* 一次性提交多个课次的教学实施计划填写数据。
* </p>
*
* @param dto 批量教学实施计划填写参数
* @return 批量填写结果
*/
@PostMapping("/plan/fill/batch")
public Result<TeachingPlanFillResultVO> batchFillTeachingPlan(@Valid @RequestBody TeachingPlanBatchFillDTO dto) {
return Result.success("批量填写完成", courseRunningImportService.batchFillTeachingPlan(dto));
}
/**
* 提交教学实施计划。
* <p>
* 将已填写的教学实施计划提交审核,提交后填写状态更新为"已提交"。
* </p>
*
* @param sskcbbh 实施_课程表编号(课次编号)
* @return 操作结果
*/
@PostMapping("/plan/submit")
public Result<Void> submitTeachingPlan(@RequestParam("sskcbbh") String sskcbbh) {
courseRunningImportService.submitTeachingPlan(sskcbbh);
return Result.success();
}
// ==================== 调课管理 ====================
/**
* 分页查询调课申请列表。
* <p>
* 根据查询条件分页查询调课申请列表,支持按实施_课程表编号、申请教员、
* 年度、审批状态、查收状态、删除状态、申请日期范围筛选。
* </p>
*
* @param query 查询参数(包含分页信息和筛选条件)
* @return 分页调课申请列表
*/
@GetMapping("/adjust/list")
public Result<PageResult<ScheduleAdjustApplyVO>> queryScheduleAdjustList(ScheduleAdjustQueryDTO query) {
return Result.success(courseRunningImportService.queryScheduleAdjustList(query));
}
/**
* 查询单个调课申请的完整详情。
* <p>
* 根据调课申请编号查询该申请的完整信息,包括申请信息、调整后的内容、
* 教研室审批状态、机关审批记录、关联的教室、辅助教员、学员队、保障明细等。
* </p>
*
* @param ssdksqbh 调课申请编号
* @return 调课申请详情
*/
@GetMapping("/adjust/detail")
public Result<ScheduleAdjustDetailVO> getScheduleAdjustDetail(@RequestParam("ssdksqbh") String ssdksqbh) {
return Result.success(courseRunningImportService.getScheduleAdjustDetail(ssdksqbh));
}
/**
* 提交调课申请。
* <p>
* 教员提交调课申请,包含课次编号、调课事由、新的日期节次、新的教室、
* 辅助教员、学员队、保障明细等完整信息。
* </p>
*
* @param dto 调课申请参数
* @return 调课申请编号
*/
@PostMapping("/adjust/submit")
public Result<String> submitScheduleAdjust(@Valid @RequestBody ScheduleAdjustApplyDTO dto) {
return Result.success("申请提交成功", courseRunningImportService.submitScheduleAdjust(dto));
}
/**
* 教研室审批调课申请。
* <p>
* 教研室审批教员提交的调课申请,包含同意、发回、拒绝三种处理方式。
* </p>
*
* @param dto 教研室审批参数(auditRole 传 "jys"
* @return 操作结果
*/
@PostMapping("/adjust/audit/jys")
public Result<Void> auditByTeachingOffice(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为教研室
dto.setAuditRole("jys");
courseRunningImportService.auditByTeachingOffice(dto);
return Result.success();
}
/**
* 教研室查收调课申请。
* <p>
* 教研室查收调课申请,标记查收状态和查收时间。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param csrbh 查收人编号
* @return 操作结果
*/
@PostMapping("/adjust/receive/jys")
public Result<Void> receiveByTeachingOffice(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("csrbh") String csrbh) {
courseRunningImportService.receiveByTeachingOffice(ssdksqbh, csrbh);
return Result.success();
}
/**
* 教学系审批调课申请。
* <p>
* 教学系审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。
* 构成三级审批流程的中间环节(教研室→教学系→机关)。
* </p>
*
* @param dto 教学系审批参数(auditRole 传 "jxx"
* @return 操作结果
*/
@PostMapping("/adjust/audit/jxx")
public Result<Void> auditByTeachingDepartment(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为教学系
dto.setAuditRole("jxx");
courseRunningImportService.auditByTeachingDepartment(dto);
return Result.success();
}
/**
* 机关审批调课申请。
* <p>
* 机关审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。
* </p>
*
* @param dto 机关审批参数(auditRole 传 "jg",需传 jgbh
* @return 操作结果
*/
@PostMapping("/adjust/audit/jg")
public Result<Void> auditByAuthority(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为机关
dto.setAuditRole("jg");
courseRunningImportService.auditByAuthority(dto);
return Result.success();
}
/**
* 机关查收调课申请。
* <p>
* 机关查收调课申请,标记查收状态和查收时间。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param jgbh 机关编号
* @param csrbh 查收人编号
* @return 操作结果
*/
@PostMapping("/adjust/receive/jg")
public Result<Void> receiveByAuthority(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("jgbh") String jgbh,
@RequestParam("csrbh") String csrbh) {
courseRunningImportService.receiveByAuthority(ssdksqbh, jgbh, csrbh);
return Result.success();
}
/**
* 撤销调课申请。
* <p>
* 教员撤销自己提交的、未经过审批的调课申请。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param sqjybh 申请教员编号
* @return 操作结果
*/
@DeleteMapping("/adjust/cancel")
public Result<Void> cancelScheduleAdjust(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("sqjybh") String sqjybh) {
courseRunningImportService.cancelScheduleAdjust(ssdksqbh, sqjybh);
return Result.success();
}
// ==================== 调课策略管理 ====================
/**
* 查询调课策略列表。
* <p>
* 支持按策略类型筛选,返回所有策略(含停用)。
* </p>
*
* @param cllx 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批,为空时查询全部
* @return 调课策略列表
*/
@GetMapping("/adjust/strategy/list")
public Result<List<ScheduleAdjustStrategyVO>> listScheduleAdjustStrategies(
@RequestParam(required = false) String cllx) {
return Result.success(courseRunningImportService.listScheduleAdjustStrategies(cllx));
}
/**
* 保存调课策略(新增或修改)。
* <p>
* 策略编号为空时执行新增,非空时执行修改。
* </p>
*
* @param dto 策略参数
* @return 策略编号
*/
@PostMapping("/adjust/strategy/save")
public Result<String> saveScheduleAdjustStrategy(@Valid @RequestBody ScheduleAdjustStrategyDTO dto) {
return Result.success("保存成功", courseRunningImportService.saveScheduleAdjustStrategy(dto));
}
/**
* 删除调课策略。
*
* @param clbh 策略编号
* @return 操作结果
*/
@DeleteMapping("/adjust/strategy/delete")
public Result<Void> deleteScheduleAdjustStrategy(@RequestParam("clbh") String clbh) {
courseRunningImportService.deleteScheduleAdjustStrategy(clbh);
return Result.success();
}
// ==================== 教学保障管理 ====================
/**
* 查询教学保障提供资源列表。
* <p>
* 从保障提供明细表中查询可供选择的保障资源,支持按保障类别编号筛选。
* </p>
*
* @param bzlbbh 保障类别编号,为空时查询全部
* @return 保障提供资源列表
*/
@GetMapping("/support/resource")
public Result<List<TeachingSupportResourceVO>> querySupportResourceList(@RequestParam(required = false) String bzlbbh) {
return Result.success(courseRunningImportService.querySupportResourceList(bzlbbh));
}
/**
* 查询课次的教学保障计划列表。
* <p>
* 根据课次编号查询该课次已登记的教学保障计划明细,包括保障名称、单位、
* 数量、备注、确认状态及确认信息等。
* </p>
*
* @param sskcbbh 实施_课程表编号(课次编号)
* @return 教学保障计划列表
*/
@GetMapping("/support/plan")
public Result<List<TeachingSupportPlanVO>> queryTeachingSupportPlanList(@RequestParam("sskcbbh") String sskcbbh) {
return Result.success(courseRunningImportService.queryTeachingSupportPlanList(sskcbbh));
}
/**
* 登记单条教学保障计划。
* <p>
* 为指定课次登记一条教学保障需求,指定保障提供明细、数量、备注等信息。
* </p>
*
* @param dto 教学保障计划登记参数
* @return 课程表_保障明细编号
*/
@PostMapping("/support/plan")
public Result<String> saveTeachingSupportPlan(@Valid @RequestBody TeachingSupportPlanDTO dto) {
return Result.success("登记成功", courseRunningImportService.saveTeachingSupportPlan(dto));
}
/**
* 批量登记教学保障计划。
* <p>
* 一次性为指定课次登记多条教学保障需求。
* </p>
*
* @param dto 教学保障计划批量登记参数
* @return 操作结果
*/
@PostMapping("/support/plan/batch")
public Result<Void> batchSaveTeachingSupportPlan(@Valid @RequestBody TeachingSupportBatchPlanDTO dto) {
courseRunningImportService.batchSaveTeachingSupportPlan(dto);
return Result.success();
}
/**
* 修改教学保障计划。
* <p>
* 修改已登记的教学保障计划,包括调整数量和备注信息。
* 已确认的教学保障计划不允许修改,如需修改需先取消确认。
* </p>
*
* @param dto 教学保障计划修改参数
* @return 操作结果
*/
@PutMapping("/support/plan")
public Result<Void> updateTeachingSupportPlan(@Valid @RequestBody TeachingSupportUpdateDTO dto) {
courseRunningImportService.updateTeachingSupportPlan(dto);
return Result.success();
}
/**
* 删除教学保障计划。
* <p>
* 删除已登记的教学保障计划。
* 已确认的教学保障计划不允许删除,如需删除需先取消确认。
* </p>
*
* @param kcbbzmxbh 课程表_保障明细编号
* @return 操作结果
*/
@DeleteMapping("/support/plan")
public Result<Void> deleteTeachingSupportPlan(@RequestParam("kcbbzmxbh") String kcbbzmxbh) {
courseRunningImportService.deleteTeachingSupportPlan(kcbbzmxbh);
return Result.success();
}
/**
* 确认教学保障到位。
* <p>
* 确认某条教学保障计划已经落实到位,记录确认人、确认时间和确认备注。
* 已确认的保障计划不允许重复确认。
* </p>
*
* @param dto 教学保障到位确认参数
* @return 操作结果
*/
@PostMapping("/support/confirm")
public Result<Void> confirmTeachingSupport(@Valid @RequestBody TeachingSupportConfirmDTO dto) {
courseRunningImportService.confirmTeachingSupport(dto);
return Result.success();
}
/**
* 批量确认教学保障到位。
* <p>
* 一次性确认多条教学保障计划已经落实到位,逐条处理并返回整体执行结果。
* </p>
*
* @param dtoList 教学保障到位确认参数列表
* @return 批量确认结果
*/
@PostMapping("/support/confirm/batch")
public Result<TeachingSupportConfirmResultVO> batchConfirmTeachingSupport(@Valid @RequestBody List<TeachingSupportConfirmDTO> dtoList) {
return Result.success("批量确认完成", courseRunningImportService.batchConfirmTeachingSupport(dtoList));
}
/**
* 取消教学保障到位确认。
* <p>
* 取消某条教学保障计划的到位确认,恢复为未确认状态。
* </p>
*
* @param kcbbzmxbh 课程表_保障明细编号
* @return 操作结果
*/
@DeleteMapping("/support/confirm")
public Result<Void> cancelConfirmTeachingSupport(@RequestParam("kcbbzmxbh") String kcbbzmxbh) {
courseRunningImportService.cancelConfirmTeachingSupport(kcbbzmxbh);
return Result.success();
}
/**
* 查询教学保障历史联想列表。
* <p>
* 根据当前课次编号,查询同一实施课程下其他历史课次已登记过的保障物资,
* 按保障提供明细编号聚合去重,统计历史使用次数、最近登记时间和平均数量,
* 供教师在登记新保障时快速联想选择,避免重复录入。
* </p>
*
* @param sskcbbh 当前课次编号(实施_课程表编号)
* @return 历史联想保障物资列表
*/
@GetMapping("/support/history")
public Result<List<TeachingSupportHistoryVO>> listTeachingSupportHistory(@RequestParam("sskcbbh") String sskcbbh) {
return Result.success(courseRunningImportService.listTeachingSupportHistory(sskcbbh));
}
// ==================== 学员正课请假 ====================
/**
* 分页查询学员请假申请列表。
* <p>
* 根据查询条件分页查询学员正课请假申请记录,支持按请假编号、学员编号、
* 学员姓名、学员队编号、审批状态、年度、创建时间范围等多条件筛选。
* </p>
*
* @param query 查询参数(包含分页信息和筛选条件)
* @return 分页学员请假申请列表
*/
@PostMapping("/leave/list")
public Result<PageResult<StudentLeaveApplyVO>> queryStudentLeaveList(@Valid @RequestBody StudentLeaveQueryDTO query) {
return Result.success(courseRunningImportService.queryStudentLeaveList(query));
}
/**
* 查询学员请假申请详情。
* <p>
* 根据请假编号查询该申请的完整信息,包括学员信息、请假时间范围、
* 审批状态、审批记录及关联课次列表。
* </p>
*
* @param qjbh 请假编号
* @return 学员请假申请详情
*/
@GetMapping("/leave/detail")
public Result<StudentLeaveDetailVO> getStudentLeaveDetail(@RequestParam("qjbh") String qjbh) {
return Result.success(courseRunningImportService.getStudentLeaveDetail(qjbh));
}
/**
* 学员提交请假申请。
* <p>
* 学员在线提交正课请假申请,包含请假原因、时间范围、请假类型、
* 关联课次等信息。系统自动生成请假编号并记录申请时间。
* </p>
*
* @param dto 学员请假申请参数
* @return 请假编号
*/
@PostMapping("/leave/apply")
public Result<String> submitStudentLeave(@Valid @RequestBody StudentLeaveApplyDTO dto) {
return Result.success("申请提交成功", courseRunningImportService.submitStudentLeave(dto));
}
/**
* 教师审批学员请假申请。
* <p>
* 教师审批学员提交的正课请假申请,包含同意、拒绝、发回修改三种处理方式。
* 审批通过后联动更新考勤记录。
* </p>
*
* @param dto 教师审批参数
* @return 操作结果
*/
@PostMapping("/leave/audit")
public Result<Void> auditStudentLeave(@Valid @RequestBody StudentLeaveAuditDTO dto) {
courseRunningImportService.auditStudentLeave(dto);
return Result.success();
}
/**
* 学员撤回请假申请。
* <p>
* 学员撤回自己提交的、未经过审批的请假申请。
* </p>
*
* @param qjbh 请假编号
* @param xybh 学员编号(用于权限校验)
* @return 操作结果
*/
@DeleteMapping("/leave")
public Result<Void> cancelStudentLeave(@RequestParam("qjbh") String qjbh, @RequestParam("xybh") String xybh) {
courseRunningImportService.cancelStudentLeave(qjbh, xybh);
return Result.success();
}
/**
* 学员查询自己的请假申请列表。
* <p>
* 学员自助查询接口,只能查看自己提交的请假记录,支持分页和按审批状态筛选。
* </p>
*
* @param xybh 学员编号(必填)
* @param pageNum 页码(必填)
* @param pageSize 每页记录数(必填)
* @param spzt 审批状态(可选:0待审批/1已同意/2已拒绝/3已发回)
* @param qjlx 请假类型(可选)
* @param nd 年度(可选)
* @return 分页学员请假申请列表
*/
@GetMapping("/leave/my-list")
public Result<PageResult<StudentLeaveApplyVO>> queryStudentOwnLeaveList(
@RequestParam("xybh") String xybh,
@RequestParam("pageNum") Integer pageNum,
@RequestParam("pageSize") Integer pageSize,
@RequestParam(value = "spzt", required = false) Integer spzt,
@RequestParam(value = "qjlx", required = false) String qjlx,
@RequestParam(value = "nd", required = false) Integer nd) {
StudentLeaveQueryDTO query = new StudentLeaveQueryDTO();
query.setXybh(xybh);
query.setPageNum(pageNum);
query.setPageSize(pageSize);
query.setSpzt(spzt);
query.setQjlx(qjlx);
query.setNd(nd);
return Result.success(courseRunningImportService.queryStudentOwnLeaveList(query));
}
// ==================== 运行分析 ====================
/**
* 获取教学运行概览指标。
* <p>
* 返回教学运行关键指标的汇总数据,包括整体排课完成率、学员缺勤率、
* 场地平均使用率、教师周均课时等核心指标。
* </p>
*
* @param query 查询参数(包含年度、学期筛选条件)
* @return 运行概览指标
*/
@PostMapping("/analysis/overview")
public Result<OperationOverviewVO> getOperationOverview(@RequestBody OperationAnalysisQueryDTO query) {
return Result.success(courseRunningImportService.getOperationOverview(query));
}
/**
* 获取各教学系排课完成率对比数据。
* <p>
* 返回各教学系的排课完成率,用于柱状图展示。
* </p>
*
* @param query 查询参数(包含年度、学期筛选条件)
* @return 各教学系排课完成率列表
*/
@PostMapping("/analysis/course-completion")
public Result<List<CourseCompletionByDeptVO>> getCourseCompletionByDept(@RequestBody OperationAnalysisQueryDTO query) {
return Result.success(courseRunningImportService.getCourseCompletionByDept(query));
}
/**
* 获取场地使用率分布数据。
* <p>
* 返回不同场地类型的使用率分布情况,用于饼图展示。
* </p>
*
* @param query 查询参数(包含年度、学期筛选条件)
* @return 场地使用率分布列表
*/
@PostMapping("/analysis/venue-usage")
public Result<List<VenueUsageRateVO>> getVenueUsageRate(@RequestBody OperationAnalysisQueryDTO query) {
return Result.success(courseRunningImportService.getVenueUsageRate(query));
}
/**
* 获取学期调课频次趋势数据。
* <p>
* 返回学期内各时间段的调课频次变化趋势,用于折线图展示。
* </p>
*
* @param query 查询参数(包含年度、学期筛选条件)
* @return 调课频次趋势列表
*/
@PostMapping("/analysis/adjust-trend")
public Result<List<ScheduleAdjustTrendVO>> getScheduleAdjustTrend(@RequestBody OperationAnalysisQueryDTO query) {
return Result.success(courseRunningImportService.getScheduleAdjustTrend(query));
}
/**
* 导出运行分析报表为 Excel 文件。
* <p>
* 汇总运行概览、各教学系排课完成率、场地使用率分布、调课频次趋势四类数据,
* 分别写入同一 Excel 文件的四个工作表,便于教学管理决策存档与汇报。
* </p>
*
* @param query 查询参数(包含年度、学期筛选条件)
* @return Excel 文件字节数组
*/
@PostMapping("/analysis/export")
public ResponseEntity<byte[]> exportAnalysisReport(@RequestBody OperationAnalysisQueryDTO query) {
byte[] excelBytes = courseRunningImportService.exportAnalysisToExcel(query);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", "运行分析报表.xlsx");
return ResponseEntity.ok()
.headers(headers)
.body(excelBytes);
}
}
@@ -0,0 +1,87 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.KCBZ;
import com.roomroot.jwgl.service.CourseTeachingService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
/**
* 课程教学管理控制器
* <p>
* 提供课程标准(KCBZ)的增删改查及多版本管理接口。
* 删除逻辑:填写撤回原因(非空=已撤回),不物理删除。
* 查询自动附带课堂列表(ktList)。
* </p>
*/
@RestController
@RequestMapping("/course-teaching")
public class CourseTeachingController {
@Resource
private CourseTeachingService courseTeachingService;
/**
* 新增课程标准(ktList 内嵌课堂列表)
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody KCBZ kcbz) {
courseTeachingService.add(kcbz);
return Result.success();
}
/**
* 撤回(删除)课程标准——填写撤回原因
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh,
@RequestParam("chyy") String chyy) {
courseTeachingService.delete(bh, chyy);
return Result.success();
}
/**
* 更新课程标准(ktList 内嵌课堂列表,先删后插)
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody KCBZ kcbz) {
courseTeachingService.update(kcbz);
return Result.success();
}
/**
* 查询课程标准详情(含课堂列表)
*/
@GetMapping("/get")
public Result<KCBZ> getById(@RequestParam("bh") String bh) {
return Result.success(courseTeachingService.getById(bh));
}
/**
* 分页查询课程标准列表(每项含课堂列表)
*/
@GetMapping("/list")
public Result<PageResult<KCBZ>> list(PageQuery query, KCBZ kcbz) {
return Result.success(courseTeachingService.pageList(query, kcbz));
}
/**
* 查询某课程的所有版本
*/
@GetMapping("/versions")
public Result<java.util.List<KCBZ>> getVersions(@RequestParam("kbh") String kbh) {
return Result.success(courseTeachingService.getVersionsByCourse(kbh));
}
/**
* 从课程表自动生成课程标准
*/
@PostMapping("/generate")
public Result<String> generateFromCourse(@RequestParam("kbh") String kbh) {
String bh = courseTeachingService.generateFromCourse(kbh);
return Result.success("生成成功", bh);
}
}
@@ -0,0 +1,130 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.department.DepartmentCreateDTO;
import com.roomroot.jwgl.dto.department.DepartmentIdDTO;
import com.roomroot.jwgl.dto.department.DepartmentQueryDTO;
import com.roomroot.jwgl.dto.department.DepartmentUpdateDTO;
import com.roomroot.jwgl.service.DepartmentManagementService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.department.DepartmentTreeVO;
import com.roomroot.jwgl.vo.department.DepartmentVO;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 部别管理接口。
*/
@RestController
@RequestMapping("/department")
public class DepartmentManagementController {
/**
* 部别管理业务服务。
*/
@Resource
private DepartmentManagementService departmentManagementService;
/**
* 新增部别。
*
* @param dto 部别新增参数
* @return 新增后的部别信息
*/
@PostMapping("/add")
public Result<DepartmentVO> add(@Valid @RequestBody DepartmentCreateDTO dto) {
// 调用业务层完成新增,并将新增后的 VO 返回给前端。
return Result.success("新增成功", departmentManagementService.add(dto));
}
/**
* 修改部别。
*
* @param dto 部别修改参数
* @return 修改后的部别信息
*/
@PostMapping("/update")
public Result<DepartmentVO> update(@Valid @RequestBody DepartmentUpdateDTO dto) {
// 调用业务层完成修改,并将修改后的 VO 返回给前端。
return Result.success("修改成功", departmentManagementService.update(dto));
}
/**
* 停用部别。
*
* @param dto 部别编号参数
* @return 停用后的部别信息
*/
@PostMapping("/disable")
public Result<DepartmentVO> disable(@Valid @RequestBody DepartmentIdDTO dto) {
// 调用业务层执行逻辑停用,不物理删除数据库记录。
return Result.success("停用成功", departmentManagementService.disable(dto));
}
/**
* 启用部别。
*
* @param dto 部别编号参数
* @return 启用后的部别信息
*/
@PostMapping("/enable")
public Result<DepartmentVO> enable(@Valid @RequestBody DepartmentIdDTO dto) {
// 调用业务层恢复部别的启用状态。
return Result.success("启用成功", departmentManagementService.enable(dto));
}
/**
* 删除部别(逻辑删除)。
* <p>删除前会检查下级部别和业务引用,确认无依赖后才执行逻辑删除。</p>
*
* @param dto 部别编号参数
* @return 被删除的部别信息
*/
@PostMapping("/delete")
public Result<DepartmentVO> delete(@Valid @RequestBody DepartmentIdDTO dto) {
// 调用业务层执行逻辑删除,已删除的部别不再出现在列表和树形结构中。
return Result.success("删除成功", departmentManagementService.delete(dto));
}
/**
* 根据编号查询部别详情。
*
* @param dto 部别编号参数
* @return 部别详情
*/
@GetMapping("/get")
public Result<DepartmentVO> get(DepartmentIdDTO dto) {
// 根据 DTO 中的编号查询并返回部别 VO。
return Result.success(departmentManagementService.get(dto));
}
/**
* 查询部别平铺列表。
*
* @param dto 查询条件
* @return 符合条件的部别列表
*/
@GetMapping("/list")
public Result<List<DepartmentVO>> list(DepartmentQueryDTO dto) {
// 返回适用于表格展示的平铺数据。
return Result.success(departmentManagementService.list(dto));
}
/**
* 查询部别树。
*
* @param dto 查询条件
* @return 符合条件并保留祖先节点的部别树
*/
@GetMapping("/tree")
public Result<List<DepartmentTreeVO>> tree(DepartmentQueryDTO dto) {
// 返回适用于树形控件展示的层级数据。
return Result.success(departmentManagementService.tree(dto));
}
}
@@ -0,0 +1,199 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelCreateDTO;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelIdDTO;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelImportDTO;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelQueryDTO;
import com.roomroot.jwgl.dto.departmentpersonnel.DepartmentPersonnelUpdateDTO;
import com.roomroot.jwgl.service.DepartmentPersonnelService;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.utils.BasicManagementConstants;
import com.roomroot.jwgl.vo.departmentpersonnel.DepartmentPersonnelDepartmentVO;
import com.roomroot.jwgl.vo.departmentpersonnel.DepartmentPersonnelVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import tools.jackson.databind.ObjectMapper;
import java.util.List;
/**
* 部别人员管理接口。
*/
@RestController
@RequestMapping("/department-personnel")
public class DepartmentPersonnelController {
/**
* 部别人员管理业务服务。
*/
@Resource
private DepartmentPersonnelService departmentPersonnelService;
/**
* JSON 序列化工具。
*/
@Resource
private ObjectMapper objectMapper;
/**
* 查询可供人员管理页面选择的启用部别。
*
* @param dto 部别查询条件
* @return 启用部别列表
*/
@GetMapping("/departments")
public Result<List<DepartmentPersonnelDepartmentVO>> departments(
@Valid DepartmentPersonnelQueryDTO dto) {
// 调用业务层过滤停用部别,并返回与数据库实体隔离的部别 VO。
return Result.success(departmentPersonnelService.listDepartments(dto));
}
/**
* 查询部别人员列表。
*
* @param dto 人员查询条件
* @return 符合条件的人员列表
*/
@GetMapping("/list")
public Result<List<DepartmentPersonnelVO>> list(
@Valid DepartmentPersonnelQueryDTO dto) {
// 调用业务层应用部别、关键字、离职状态和主官状态筛选。
return Result.success(departmentPersonnelService.list(dto));
}
/**
* 查询部别人员详情。
*
* @param dto 人员编号参数
* @return 人员详情
*/
@GetMapping("/get")
public Result<DepartmentPersonnelVO> get(
@Valid DepartmentPersonnelIdDTO dto) {
// 按人员编号查询完整信息,并补充所属部别名称和简称。
return Result.success(departmentPersonnelService.get(dto));
}
/**
* 新增部别人员。
*
* @param dto 人员新增参数
* @return 新增后的人员信息
*/
@PostMapping("/add")
public Result<DepartmentPersonnelVO> add(
@Valid @RequestBody DepartmentPersonnelCreateDTO dto) {
// 调用业务层完成部别状态校验、实体转换和数据库新增。
return Result.success("新增成功", departmentPersonnelService.add(dto));
}
/**
* 修改部别人员,并支持人员调整到其他部别。
*
* @param dto 人员修改参数
* @return 修改后的人员信息
*/
@PostMapping("/update")
public Result<DepartmentPersonnelVO> update(
@Valid @RequestBody DepartmentPersonnelUpdateDTO dto) {
// 调用业务层更新人员基本信息和所属部别,不在此接口修改离职状态。
return Result.success("修改成功", departmentPersonnelService.update(dto));
}
/**
* 将部别人员标记为离职。
*
* @param dto 人员编号参数
* @return 离职后的人员信息
*/
@PostMapping("/leave")
public Result<DepartmentPersonnelVO> leave(
@Valid @RequestBody DepartmentPersonnelIdDTO dto) {
// 使用离职状态进行软管理,不物理删除被业务表引用的人员记录。
return Result.success("离职处理成功", departmentPersonnelService.leave(dto));
}
/**
* 将离职人员恢复为在职。
*
* @param dto 人员编号参数
* @return 复职后的人员信息
*/
@PostMapping("/restore")
public Result<DepartmentPersonnelVO> restore(
@Valid @RequestBody DepartmentPersonnelIdDTO dto) {
// 调用业务层校验所属部别仍然启用后恢复在职状态。
return Result.success("复职处理成功", departmentPersonnelService.restore(dto));
}
/**
* 批量导入部别人员。
* <p>
* 支持两种导入方式:<br>
* 1. JSON 方式:请求 Content-Type 为 application/json,传入 {@link DepartmentPersonnelImportDTO}<br>
* 2. Excel 方式:请求 Content-Type 为 multipart/form-data,上传 Excel 文件。<br>
* 两种方式共用同一 URL,由请求类型自动区分。
* </p>
*
* @param request HTTP 请求对象
* @return 本次成功导入的人员列表
*/
@PostMapping("/batch-import")
public Result<List<DepartmentPersonnelVO>> batchImport(HttpServletRequest request) throws Exception {
String contentType = request.getContentType();
// 判断是否为 multipart/form-data 请求,处理 Excel 文件导入
if (contentType != null && contentType.toLowerCase().contains("multipart")) {
MultipartFile file = ((MultipartHttpServletRequest) request).getFile("file");
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空", BasicManagementConstants.BAD_REQUEST);
}
return Result.success(
"Excel导入成功",
departmentPersonnelService.importFromExcel(
file.getInputStream(), file.getOriginalFilename()));
}
// 否则按 JSON 方式处理
DepartmentPersonnelImportDTO dto = objectMapper.readValue(
request.getInputStream(), DepartmentPersonnelImportDTO.class);
return Result.success(
"批量导入成功", departmentPersonnelService.batchImport(dto));
}
/**
* 按当前查询条件导出部别人员数据为 Excel 文件。
*
* @param dto 导出筛选条件
* @return Excel 文件下载响应
*/
@GetMapping("/export")
public ResponseEntity<byte[]> export(
@Valid DepartmentPersonnelQueryDTO dto) {
// 复用列表的统一筛选和排序规则,保证导出与页面结果一致。
byte[] excelBytes = departmentPersonnelService.exportToExcel(dto);
// 构建文件下载响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", "部别人员数据.xlsx");
return ResponseEntity.ok()
.headers(headers)
.body(excelBytes);
}
}
@@ -0,0 +1,154 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.dict.DictDataBatchQueryDTO;
import com.roomroot.jwgl.dto.dict.DictDataQueryDTO;
import com.roomroot.jwgl.dto.dict.DictDataSaveDTO;
import com.roomroot.jwgl.service.DictDataService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.dict.DictDataVO;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 字典数据接口。
* <p>
* 提供字典数据的查询(单类型、分页、批量)、保存(新增/编辑)和删除功能。
* 字典数据是字典类型下的具体选项,用于前端下拉框、单选、多选等场景。
* </p>
*/
@RestController
@RequestMapping("/dict-data")
public class DictDataController {
/**
* 字典数据业务服务。
*/
@Resource
private DictDataService dictDataService;
/**
* 按类型编码查询全部启用的字典数据。
* <p>
* 返回指定字典类型下所有状态为启用的数据项,按排序号升序排列。
* 主要用于前端业务页面的下拉框、单选、多选等场景。
* </p>
*
* @param dictTypeCode 字典类型编码
* @return 该类型下启用的字典数据列表
*/
@GetMapping("/list/{dictTypeCode}")
public Result<List<DictDataVO>> listByType(
@PathVariable String dictTypeCode) {
return Result.success(dictDataService.listByType(dictTypeCode));
}
/**
* 分页查询字典数据列表(管理页面用)。
* <p>
* 支持按字典类型编码、关键字(匹配标签或值)、状态进行筛选,
* 按排序号升序排列。可查看启用和停用的全部数据项。
* </p>
*
* @param dto 查询条件,包含分页参数和筛选条件
* @return 符合条件的字典数据分页结果
*/
@PostMapping("/page")
public Result<PageResult<DictDataVO>> page(
@Valid @RequestBody DictDataQueryDTO dto) {
return Result.success(dictDataService.page(dto));
}
/**
* 批量查询多个类型的字典数据。
* <p>
* 一次请求查询多个字典类型的数据,返回结果按类型编码分组。
* 用于页面初始化时需要同时加载多个下拉框数据的场景,减少前端请求次数。
* </p>
*
* @param dto 批量查询参数,包含字典类型编码列表
* @return 按类型编码分组的数据字典
*/
@PostMapping("/batch-list")
public Result<Map<String, List<DictDataVO>>> batchList(
@Valid @RequestBody DictDataBatchQueryDTO dto) {
return Result.success(dictDataService.batchList(dto));
}
/**
* 保存字典数据(新增或编辑)。
* <p>
* 当 {@code dto.dictDataId} 为空时执行新增操作,
* 当 {@code dto.dictDataId} 有值时执行编辑操作。
* 保存时会校验关联的字典类型是否存在,
* 若设置为默认值会自动取消该类型下其他数据的默认标记。
* </p>
*
* @param dto 字典数据保存参数
* @return 保存后的字典数据详情
*/
@PostMapping("/save")
public Result<DictDataVO> save(
@Valid @RequestBody DictDataSaveDTO dto) {
return Result.success("保存成功", dictDataService.save(dto));
}
/**
* 删除字典数据。
* <p>
* 根据字典数据ID删除单条记录,删除前会校验数据是否存在。
* </p>
*
* @param dictDataId 字典数据ID
* @return 删除成功提示
*/
@DeleteMapping("/{dictDataId}")
public Result<Void> delete(
@PathVariable Long dictDataId) {
dictDataService.delete(dictDataId);
return Result.success("删除成功", null);
}
/**
* 获取字典数据的历史版本列表。
* <p>
* 返回该字典数据所有的历史快照信息,用于版本回溯查看。
* </p>
*
* @param dictDataId 字典数据ID
* @return 历史版本快照列表
*/
@GetMapping("/history/{dictDataId}")
public Result<List<Map<String, Object>>> getHistory(
@PathVariable Long dictDataId) {
return Result.success(dictDataService.getHistory(dictDataId));
}
/**
* 回滚字典数据到指定版本。
* <p>
* 根据目标版本号,从历史快照中恢复数据,并创建新的版本记录。
* </p>
*
* @param dictDataId 字典数据ID
* @param targetVersion 目标版本号
* @return 回滚后的字典数据详情
*/
@PostMapping("/rollback")
public Result<DictDataVO> rollback(
@RequestParam Long dictDataId,
@RequestParam Integer targetVersion) {
return Result.success("回滚成功", dictDataService.rollback(dictDataId, targetVersion));
}
}
@@ -0,0 +1,121 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.dict.DictTypeQueryDTO;
import com.roomroot.jwgl.dto.dict.DictTypeSaveDTO;
import com.roomroot.jwgl.service.DictTypeService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.dict.DictTypeVO;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* 字典类型接口。
* <p>
* 提供字典类型的分页查询、保存(新增/编辑)和删除功能。
* 字典类型用于对系统字典进行分类管理,如课程类型、职称等级等。
* </p>
*/
@RestController
@RequestMapping("/dict-type")
public class DictTypeController {
/**
* 字典类型业务服务。
*/
@Resource
private DictTypeService dictTypeService;
/**
* 分页查询字典类型列表。
* <p>
* 支持按关键字(匹配类型编码或名称)、所属分组、状态进行筛选,
* 按创建时间降序排列。
* </p>
*
* @param dto 查询条件,包含分页参数和筛选条件
* @return 符合条件的字典类型分页结果
*/
@PostMapping("/page")
public Result<PageResult<DictTypeVO>> page(
@Valid @RequestBody DictTypeQueryDTO dto) {
return Result.success(dictTypeService.page(dto));
}
/**
* 保存字典类型(新增或编辑)。
* <p>
* 当 {@code dto.dictTypeId} 为空时执行新增操作,
* 当 {@code dto.dictTypeId} 有值时执行编辑操作。
* 新增时校验字典类型编码全局唯一性,编辑时允许修改除编码外的其他字段。
* </p>
*
* @param dto 字典类型保存参数
* @return 保存后的字典类型详情
*/
@PostMapping("/save")
public Result<DictTypeVO> save(
@Valid @RequestBody DictTypeSaveDTO dto) {
return Result.success("保存成功", dictTypeService.save(dto));
}
/**
* 删除字典类型。
* <p>
* 删除前会校验该字典类型下是否存在关联的字典数据项,
* 若存在数据项则不允许删除,防止误删导致业务数据异常。
* </p>
*
* @param dictTypeId 字典类型ID
* @return 删除成功提示
*/
@DeleteMapping("/{dictTypeId}")
public Result<Void> delete(
@PathVariable Long dictTypeId) {
dictTypeService.delete(dictTypeId);
return Result.success("删除成功", null);
}
/**
* 获取字典类型的历史版本列表。
* <p>
* 返回该字典类型所有的历史快照信息,用于版本回溯查看。
* </p>
*
* @param dictTypeId 字典类型ID
* @return 历史版本快照列表
*/
@GetMapping("/history/{dictTypeId}")
public Result<List<Map<String, Object>>> getHistory(
@PathVariable Long dictTypeId) {
return Result.success(dictTypeService.getHistory(dictTypeId));
}
/**
* 回滚字典类型到指定版本。
* <p>
* 根据目标版本号,从历史快照中恢复数据,并创建新的版本记录。
* </p>
*
* @param dictTypeId 字典类型ID
* @param targetVersion 目标版本号
* @return 回滚后的字典类型详情
*/
@PostMapping("/rollback")
public Result<DictTypeVO> rollback(
@RequestParam Long dictTypeId,
@RequestParam Integer targetVersion) {
return Result.success("回滚成功", dictTypeService.rollback(dictTypeId, targetVersion));
}
}
@@ -0,0 +1,120 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XKZYXX;
import com.roomroot.jwgl.service.DisciplineService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
/**
* 学科专业管理控制器
* <p>
* 提供学科、专业的增加、删除(逻辑删除)、更新、查询等功能管理接口。
* 对应数据表:学科专业信息
* </p>
* <p>
* 接口规范:仅使用 GET 和 POST 两种方法,参数通过请求体或查询参数传递,不拼接在路径中。
* </p>
*
* @author management
*/
@RestController
@RequestMapping("/discipline")
public class DisciplineManagementController {
@Resource
private DisciplineService disciplineService;
/**
* 新增学科专业
*
* @param entity 学科专业实体
* @return 操作结果
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XKZYXX entity) {
disciplineService.add(entity);
return Result.success();
}
/**
* 停用(逻辑删除)学科专业
* <p>将指定记录的 停用 字段置为 1(停用=0为启用,停用=1为已停用/删除)。</p>
*
* @param bsh 标识号
* @return 操作结果
*/
@PostMapping("/disable")
public Result<Void> disable(@RequestParam("bsh") String bsh) {
disciplineService.disable(bsh);
return Result.success();
}
/**
* 更新学科专业
*
* @param entity 学科专业实体(含标识号)
* @return 操作结果
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XKZYXX entity) {
disciplineService.update(entity);
return Result.success();
}
/**
* 根据标识号查询学科专业详情
*
* @param bsh 标识号
* @return 学科专业详情
*/
@GetMapping("/get")
public Result<XKZYXX> getById(@RequestParam("bsh") String bsh) {
XKZYXX entity = disciplineService.getById(bsh);
return Result.success(entity);
}
/**
* 分页条件查询学科专业列表
* <p>
* 支持模糊查询参数:
* <ul>
* <li>zYMC — 专业名称(模糊匹配)</li>
* <li>zYFX — 专业方向(模糊匹配)</li>
* </ul>
* </p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param zymc 专业名称(可选)
* @param zyfx 专业方向(可选)
* @return 分页结果
*/
@GetMapping("/list")
public Result<PageResult<XKZYXX>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String zymc,
@RequestParam(required = false) String zyfx,
@RequestParam(required = false) String zydm,
@RequestParam(required = false) Integer ty,
@RequestParam(required = false) String pxlx2,
@RequestParam(required = false) String xnz) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
XKZYXX cond = new XKZYXX();
cond.setZymc(zymc);
cond.setZyfx(zyfx);
cond.setZydm(zydm);
cond.setTy(ty);
cond.setPxlx2(pxlx2);
cond.setXnz(xnz);
PageResult<XKZYXX> pageResult = disciplineService.pageList(query, cond);
return Result.success(pageResult);
}
}
@@ -0,0 +1,373 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.elective.AddClassDTO;
import com.roomroot.jwgl.entity.JSB;
import com.roomroot.jwgl.entity.JXLB;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
import com.roomroot.jwgl.entity.XYDQB;
import com.roomroot.jwgl.entity.XYXX;
import com.roomroot.jwgl.service.ElectiveService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.elective.*;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 教学班次管理控制器
* <p>
* 提供教学班次(学员队表)的完整管理功能,包括:
* <ul>
* <li>教学班次的增加、删除(停用)、更新、查询</li>
* <li>支持选修课临时教学班次的管理(通过学员队类型 xydlx 区分)</li>
* <li>教学班与管理班的区别管理</li>
* <li>学员自行注册开关设置</li>
* <li>学号前缀和学号自动累加位数配置</li>
* </ul>
* 涉及数据表:学员队表(XYDB)、学员队期表(XYDQB)。
* </p>
*/
@RestController
@RequestMapping("/elective")
public class ElectiveController {
@Resource
private ElectiveService electiveService;
// ======================== 教学班次 CRUD ========================
/**
* 新增教学班次(学员队)
* <p>
* 创建一个新的教学班次,支持设置名称、专业、年级、计划人数、
* 任务类别(规划内/其他)、入学日期、毕业日期等信息。
* </p>
* @return 操作结果
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody AddClassDTO dto) {
electiveService.add(dto);
return Result.success();
}
/**
* 删除教学班次(物理删除)
* <p>
* 直接删除指定教学班次及其关联的学员队期记录(学号规则、注册设置等)。
* </p>
*
* @param xydbh 学员队编号
* @return 操作结果
*/
@PostMapping("/disable")
public Result<Void> disable(@RequestParam("xydbh") String xydbh) {
electiveService.disable(xydbh);
return Result.success();
}
/**
* 更新教学班次信息
* <p>
* 支持修改班次名称、专业、年级、计划人数、任务类别、
* 入学日期、毕业日期等信息。
* </p>
*
* @param entity 教学班次实体(需含学员队编号)
* @return 操作结果
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYDB entity) {
electiveService.update(entity);
return Result.success();
}
/**
* 根据编号查询教学班次详情
*
* @param xydbh 学员队编号
* @return 教学班次信息
*/
@GetMapping("/get")
public Result<XYDB> getById(@RequestParam("xydbh") String xydbh) {
return Result.success(electiveService.getById(xydbh));
}
/**
* 分页条件查询教学班次列表(双表联查)
* <p>
* 左连接学员队期表,展示字段包括:
* <ul>
* <li>名称、专业、年级、计划人数</li>
* <li>任务类别(规划内、其他)</li>
* <li>入学日期、毕业日期</li>
* <li>学员学号前缀、学员学号自动累加位数</li>
* <li>是否允许学员自行注册开关</li>
* </ul>
* </p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param xydmc 班次名称(模糊匹配,可选)
* @param nj 年级(精确匹配,可选)
* @param zydh 专业代号(精确匹配,可选)
* @param rwlb 任务类别(规划内/其他,可选)
* @param xydlx 学员队类型(教学班/管理班/选修班,可选)
* @return 分页结果(含学号规则、注册开关)
*/
@GetMapping("/list")
public Result<PageResult<ElectiveClassVO>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String xydmc,
@RequestParam(required = false) String nj,
@RequestParam(required = false) String zydh,
@RequestParam(required = false) String rwlb,
@RequestParam(required = false) String xydlx,
@RequestParam(required = false) String xq,
@RequestParam(required = false) String pxrwbsh,
@RequestParam(required = false) Integer xslx,
@RequestParam(required = false) String zxzt,
@RequestParam(required = false) String pxlx,
@RequestParam(required = false) String pxcc,
@RequestParam(required = false) String pxlx2,
@RequestParam(required = false) String rxrqStart,
@RequestParam(required = false) String rxrqEnd,
@RequestParam(required = false) String byrqStart,
@RequestParam(required = false) String byrqEnd) {
PageQuery query = new PageQuery(pageNum, pageSize);
ElectiveClassVO cond = new ElectiveClassVO();
cond.setXydmc(xydmc);
cond.setNj(nj);
cond.setZydh(zydh);
cond.setRwlb(rwlb);
cond.setXydlx(xydlx);
cond.setXq(xq);
cond.setPxrwbsh(pxrwbsh);
cond.setXslx(xslx);
cond.setZxzt(zxzt);
cond.setPxlx(pxlx);
cond.setPxcc(pxcc);
cond.setPxlx2(pxlx2);
if (rxrqStart != null) cond.setRxrqStart(java.time.LocalDateTime.parse(rxrqStart + "T00:00:00"));
if (rxrqEnd != null) cond.setRxrqEnd(java.time.LocalDateTime.parse(rxrqEnd + "T23:59:59"));
if (byrqStart != null) cond.setByrqStart(java.time.LocalDateTime.parse(byrqStart + "T00:00:00"));
if (byrqEnd != null) cond.setByrqEnd(java.time.LocalDateTime.parse(byrqEnd + "T23:59:59"));
return Result.success(electiveService.pageListWithPeriod(query, cond));
}
// ======================== 学员队期/注册设置 ========================
/**
* 查询教学班次的学号规则与注册设置
* <p>
* 返回指定班次在学员队期表中的附加信息,包括:
* 学号前缀、学号自动累加位数、允许自行注册开关等。
* </p>
*
* @param xydbh 学员队编号
* @return 学员队期信息(含学号规则、注册设置)
*/
@GetMapping("/period/get")
public Result<XYDQB> getPeriod(@RequestParam("xydbh") String xydbh) {
return Result.success(electiveService.getPeriodByXydbh(xydbh));
}
/**
* 更新教学班次的学号规则与注册设置
* <p>
* 支持修改学号前缀(xhqz)、学号自动累加位数(xhws)、
* 入学日期、毕业日期、允许注册开关(yxzc)等配置。
* </p>
*
* @param entity 学员队期实体(需含编号)
* @return 操作结果
*/
@PostMapping("/period/update")
public Result<Void> updatePeriod(@RequestBody XYDQB entity) {
electiveService.updatePeriod(entity);
return Result.success();
}
/**
* 生成下一个学员学号
* <p>
* 格式:入学年份年月日 + 三位流水号,如 20240301001、202403010002。
* 流水号位数通过学员队期表的学号自动累加位数(xhws)控制,默认3位。
* </p>
*
* @param xydbh 学员队编号
* @return 生成的学号
*/
@GetMapping("/generate-student-number")
public Result<String> generateStudentNumber(@RequestParam("xydbh") String xydbh) {
return Result.success(electiveService.generateNextStudentNumber(xydbh));
}
/**
* 设置是否允许学员自行注册
* <p>
* 控制该教学班次是否允许学员通过网络自行注册。
* 0 = 关闭(不允许注册),1 = 开启(允许注册)。
* </p>
*
* @param xydbh 学员队编号
* @param enabled 注册开关(0-关闭,1-开启)
* @return 操作结果
*/
@PostMapping("/period/set-registration")
public Result<Void> setRegistration(
@RequestParam("xydbh") String xydbh,
@RequestParam("enabled") Integer enabled) {
electiveService.setRegistrationEnabled(xydbh, enabled);
return Result.success();
}
// ======================== 关联信息查询 ========================
/**
* 查询教学班次的课程列表
* <p>通过实施_课程学员队关联查询班次的课程安排。</p>
*
* @param xydbh 学员队编号
* @param nd 年度(可选)
* @return 课程列表
*/
@GetMapping("/courses")
public Result<List<ClassScheduleVO>> getCourses(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) Integer nd) {
return Result.success(electiveService.getClassCourses(xydbh, nd));
}
/**
* 查询教学班次的学期课程表
*
* @param xydbh 学员队编号
* @param nd 年度(可选)
* @return 课程表列表
*/
@GetMapping("/schedule")
public Result<List<ClassScheduleVO>> getSchedule(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) Integer nd) {
return Result.success(electiveService.getClassSchedule(xydbh, nd));
}
/**
* 查询教学班次的学员列表
*
* @param xydbh 学员队编号
* @return 学员列表
*/
@GetMapping("/students")
public Result<List<XYXX>> getStudents(@RequestParam("xydbh") String xydbh) {
return Result.success(electiveService.getClassStudents(xydbh));
}
/**
* 查询教学班次的学员成绩
*
* @param xydbh 学员队编号
* @param kmbh 科目编号(可选,按科目筛选)
* @return 成绩列表
*/
@GetMapping("/grades")
public Result<List<StudentGradeVO>> getGrades(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) String kmbh) {
return Result.success(electiveService.getClassGrades(xydbh, kmbh));
}
/**
* 查询教学班次的学员缺勤记录
* <p>关联学员教学请假表和请假学员表,返回请假学员明细。</p>
*
* @param xydbh 学员队编号
* @param nd 年度(可选)
* @return 缺勤记录列表(含学员姓名学号)
*/
@GetMapping("/absences")
public Result<List<StudentAbsenceVO>> getAbsences(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) Integer nd) {
return Result.success(electiveService.getClassAbsences(xydbh, nd));
}
// ======================== 教学班次学期信息设置 ========================
/**
* 查询教学楼列表(教学班次学期信息设置窗口 - 教学楼下拉框)
*
* @return 教学楼列表
*/
@GetMapping("/semester/buildings")
public Result<List<JXLB>> semesterBuildings() {
return Result.success(electiveService.listBuildings());
}
/**
* 查询教室列表(教学班次学期信息设置窗口 - 专用教室选择)
* <p>支持按教学楼代号过滤;在【查找教室】输入框输入教室名称拼音首字母可快速查找。</p>
*
* @param jxldh 教学楼代号(可选)
* @param py 教室名称拼音首字母(可选)
* @return 教室列表
*/
@GetMapping("/semester/rooms")
public Result<List<JSB>> semesterRooms(
@RequestParam(required = false) String jxldh,
@RequestParam(required = false) String py) {
return Result.success(electiveService.listRooms(jxldh, py));
}
/**
* 获取教学班次学期信息设置窗口的初始化默认值
* <p>
* 根据班次学制自动给出默认值:
* <ul>
* <li>学制半年以内:学期第次固定为第一学期,开学日期=入学日期,结束日期=毕业日期</li>
* <li>学制半年以上:按入学日期智能推断当前学期第次(可手动指定),
* 开学/结束日期默认取窗口预设日期</li>
* <li>第二以上学期:默认预设上学期的专用教室</li>
* </ul>
* </p>
*
* @param xydbh 班次编号(学员队编号)
* @param presetKxrq 窗口预设开学日期(yyyy-MM-dd,可选)
* @param presetJsrq 窗口预设结束日期(yyyy-MM-dd,可选)
* @return 初始化默认值
*/
@GetMapping("/semester/init")
public Result<SemesterInitVO> semesterInit(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) String presetKxrq,
@RequestParam(required = false) String presetJsrq) {
return Result.success(electiveService.getSemesterInit(xydbh, presetKxrq, presetJsrq));
}
/**
* 创建教学班次学期信息(教学班次学期信息设置窗口 - 确定按钮)
* <p>
* 服务端自动处理:
* <ul>
* <li>学制半年以内:学期第次强制为第一学期(传入其他值校验失败),
* 开学/结束日期为空时默认取班次的入学/毕业日期</li>
* <li>学制半年以上:学期第次为空时按入学日期智能推断;
* 开学/结束日期使用窗口预设值,不允许为空</li>
* <li>第二以上学期:专用教室为空时默认预设上学期的专用教室</li>
* <li>同一班次+年度+学期第次已存在时拒绝重复创建</li>
* </ul>
* </p>
*
* @param xydndxqjbxxb 班次学期信息(必填:学员队编号;可选:年度、学期第次、开学/结束日期、专用教室编号、节次类别、备注等)
* @return 操作结果
*/
@PostMapping("/semester/add")
public Result<Void> semesterAdd(@RequestBody XYDNDXQJBXXB xydndxqjbxxb) {
electiveService.addSemester(xydndxqjbxxb);
return Result.success();
}
}
@@ -0,0 +1,247 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.faculty.AddTeacherDTO;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.service.FacultyService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.faculty.TeacherListVO;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
/**
* 教研室与教师信息管理控制器
* <p>
* 提供教研室和教师信息的增加、删除(停用/离职)、更新、查询等管理接口。
* 覆盖教研室管理、教员档案管理、教员属性维护、年度综合评定查询、课程表查询等功能。
* </p>
* <p>
* 接口规范:仅使用 GET 和 POST 两种方法,参数通过请求体或查询参数传递,不拼接在路径中。
* </p>
*
* @author management
*/
@RestController
@RequestMapping("/faculty")
public class FacultyController {
@Resource
private FacultyService facultyService;
// ======================== 教研室管理 ========================
/**
* 新增教研室
*/
@PostMapping("/office/add")
public Result<Void> addOffice(@RequestBody JYSB entity) {
facultyService.addJYSB(entity);
return Result.success();
}
/**
* 停用(逻辑删除)教研室
*
* @param jysdh 教研室代号
*/
@PostMapping("/office/disable")
public Result<Void> disableOffice(@RequestParam("jysdh") String jysdh) {
facultyService.disableJYSB(jysdh);
return Result.success();
}
/**
* 更新教研室
*/
@PostMapping("/office/update")
public Result<Void> updateOffice(@RequestBody JYSB entity) {
facultyService.updateJYSB(entity);
return Result.success();
}
/**
* 根据代号查询教研室详情
*
* @param jysdh 教研室代号
*/
@GetMapping("/office/get")
public Result<JYSB> getOffice(@RequestParam("jysdh") String jysdh) {
JYSB entity = facultyService.getJYSBById(jysdh);
return Result.success(entity);
}
/**
* 分页条件查询教研室列表
* <p>
* 支持模糊查询参数:
* <ul>
* <li>jysmc — 教研室名称(模糊匹配)</li>
* <li>bx — 部系(模糊匹配)</li>
* </ul>
* </p>
*/
@GetMapping("/office/list")
public Result<PageResult<JYSB>> listOffice(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jysdh,
@RequestParam(required = false) String jysmc,
@RequestParam(required = false) String bx) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
JYSB cond = new JYSB();
cond.setJysdh(jysdh);
cond.setJysmc(jysmc);
cond.setBx(bx);
PageResult<JYSB> pageResult = facultyService.pageJYSB(query, cond);
return Result.success(pageResult);
}
// ======================== 教员管理 ========================
/**
* 新增教员(同时写入教员表和教员属性表)
* <p>教员属性中的非空字段由前端一并传入。</p>
*/
@PostMapping("/teacher/add")
public Result<Void> addTeacher(@RequestBody AddTeacherDTO dto) {
facultyService.addJYB(dto);
return Result.success();
}
/**
* 离职(逻辑删除)教员
*
* @param jybh 教员编号
*/
@PostMapping("/teacher/disable")
public Result<Void> disableTeacher(@RequestParam("jybh") String jybh) {
facultyService.disableJYB(jybh);
return Result.success();
}
/**
* 更新教员基本信息
* <p>支持教学单位调整(修改教研室代号)、职称调整(修改职称、专业技术职务等级)。</p>
*/
@PostMapping("/teacher/update")
public Result<Void> updateTeacher(@RequestBody JYB entity) {
facultyService.updateJYB(entity);
return Result.success();
}
/**
* 根据编号查询教员详情
*
* @param jybh 教员编号
*/
@GetMapping("/teacher/get")
public Result<JYB> getTeacher(@RequestParam("jybh") String jybh) {
JYB entity = facultyService.getJYBById(jybh);
return Result.success(entity);
}
/**
* 分页条件查询教员列表
* <p>
* 支持模糊查询参数:
* <ul>
* <li>jyxm — 教员姓名(模糊匹配)</li>
* <li>jysdh — 教研室代号(精确匹配)</li>
* <li>zc — 职称(模糊匹配)</li>
* <li>jylb — 教员类别(精确匹配)</li>
* </ul>
* </p>
*/
@GetMapping("/teacher/list")
public Result<PageResult<TeacherListVO>> listTeacher(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jyxm,
@RequestParam(required = false) String jysdh,
@RequestParam(required = false) String zc,
@RequestParam(required = false) String jylb) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
JYB cond = new JYB();
cond.setJyxm(jyxm);
cond.setJysdh(jysdh);
cond.setZc(zc);
cond.setJylb(jylb);
PageResult<TeacherListVO> pageResult = facultyService.pageJYBDetail(query, cond);
return Result.success(pageResult);
}
// ======================== 教员属性管理 ========================
/**
* 查询教员属性
*
* @param jybh 教员编号
*/
@GetMapping("/teacher/attribute/get")
public Result<JYSX> getTeacherAttribute(@RequestParam("jybh") String jybh) {
JYSX entity = facultyService.getJYSXByJYBH(jybh);
return Result.success(entity);
}
/**
* 更新教员属性
* <p>支持岗位调整(修改职务、职务时间)和技术等级调整(修改技术等级、技术等级时间)。</p>
*/
@PostMapping("/teacher/attribute/update")
public Result<Void> updateTeacherAttribute(@RequestBody JYSX entity) {
facultyService.updateJYSX(entity);
return Result.success();
}
// ======================== 年度综合评定查询 ========================
/**
* 分页查询年度综合评定_教员
*/
@GetMapping("/evaluation/list")
public Result<PageResult<NDZHPDJY>> listEvaluation(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jybh,
@RequestParam(required = false) String ndzhpdjysbh) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
NDZHPDJY cond = new NDZHPDJY();
cond.setJybh(jybh);
cond.setNdzhpd_jysbh(ndzhpdjysbh);
PageResult<NDZHPDJY> pageResult = facultyService.pageNDZHPDJY(query, cond);
return Result.success(pageResult);
}
// ======================== 教员课程表查询 ========================
/**
* 分页查询教员输出课程表
* <p>
* 支持按年度和教员编号筛选。
* </p>
*/
@GetMapping("/timetable/list")
public Result<PageResult<JYSCKCB>> listTimetable(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) Integer nd,
@RequestParam(required = false) String jybh) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
JYSCKCB cond = new JYSCKCB();
cond.setNd(nd);
cond.setJybh(jybh);
PageResult<JYSCKCB> pageResult = facultyService.pageJYSCKCB(query, cond);
return Result.success(pageResult);
}
}
@@ -0,0 +1,72 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.KCB;
import com.roomroot.jwgl.service.KCBService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 课程表控制器
*/
@RestController
@RequestMapping("/kcb")
public class KCBController {
@Resource
private KCBService kcbService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody KCB kcb) {
kcbService.add(kcb);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("kbh") String kbh) {
kcbService.delete(kbh);
return Result.success();
}
/**
* 批量删除
*/
@PostMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> kbhList) {
kcbService.batchDelete(kbhList);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody KCB kcb) {
kcbService.update(kcb);
return Result.success();
}
/**
* 根据课编号查询
*/
@GetMapping("/get")
public Result<KCB> getByKbh(@RequestParam("kbh") String kbh) {
return Result.success(kcbService.getByKbh(kbh));
}
/**
* 查询所有数据
*/
@GetMapping("/list")
public Result<List<KCB>> list() {
return Result.success(kcbService.list());
}
}
@@ -0,0 +1,134 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.LeaveDTO;
import com.roomroot.jwgl.dto.LeaveQueryDTO;
import com.roomroot.jwgl.entity.XYJXQJB;
import com.roomroot.jwgl.entity.XYQJSPB;
import com.roomroot.jwgl.service.LeaveService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 请假控制器
*/
@RestController
@RequestMapping("/leave")
public class LeaveController {
@Resource
private LeaveService leaveService;
// ===== 请假主表 =====
/**
* 新增请假(主表+课堂+学员)
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody LeaveDTO dto) {
leaveService.add(dto);
return Result.success();
}
/**
* 更新请假主表
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYJXQJB xyjxqjb) {
if (!leaveService.update(xyjxqjb)) {
return Result.error("该请假已有审批记录,不允许修改");
}
return Result.success();
}
/**
* 删除请假(级联删除课堂+学员+审批)
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
if (!leaveService.delete(bh)) {
return Result.error("该请假已有审批记录,不允许删除");
}
return Result.success();
}
/**
* 根据编号查询请假
*/
@GetMapping("/get")
public Result<XYJXQJB> getByBh(@RequestParam("bh") String bh) {
return Result.success(leaveService.getByBh(bh));
}
/**
* 查询所有请假
* 支持按编号、名称、状态、学员队编号查询,起始时间、结束时间、创建时间支持范围查询
*/
@GetMapping("/list")
public Result<List<XYJXQJB>> list(LeaveQueryDTO queryDTO) {
return Result.success(leaveService.list(queryDTO));
}
/**
* 根据请假编号查询课堂编号列表
*/
@GetMapping("/classrooms")
public Result<List<String>> listClassrooms(@RequestParam("qjbh") String qjbh) {
return Result.success(leaveService.listClassroomBhsByQjbh(qjbh));
}
/**
* 根据请假编号查询学员编号列表
*/
@GetMapping("/students")
public Result<List<String>> listStudents(@RequestParam("qjbh") String qjbh) {
return Result.success(leaveService.listStudentBhsByQjbh(qjbh));
}
// ===== 审批表 =====
/**
* 新增审批
*/
@PostMapping("/approval/add")
public Result<Void> addApproval(@RequestBody XYQJSPB xyqjspb) {
leaveService.addApproval(xyqjspb);
return Result.success();
}
/**
* 删除审批
*/
@PostMapping("/approval/delete")
public Result<Void> deleteApproval(@RequestParam("bh") String bh) {
leaveService.deleteApproval(bh);
return Result.success();
}
/**
* 更新审批
*/
@PostMapping("/approval/update")
public Result<Void> updateApproval(@RequestBody XYQJSPB xyqjspb) {
leaveService.updateApproval(xyqjspb);
return Result.success();
}
/**
* 根据编号查询审批
*/
@GetMapping("/approval/get")
public Result<XYQJSPB> getApproval(@RequestParam("bh") String bh) {
return Result.success(leaveService.getApprovalByBh(bh));
}
/**
* 根据请假编号查询审批列表
*/
@GetMapping("/approval/list")
public Result<List<XYQJSPB>> listApprovals(@RequestParam("qjbh") String qjbh) {
return Result.success(leaveService.listApprovalsByQjbh(qjbh));
}
}
@@ -0,0 +1,883 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.entity.*;
import com.roomroot.jwgl.service.LogService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.log.TeacherHoursVO;
import com.roomroot.jwgl.vo.log.TeachingLogListVO;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 教学日志管理控制器
* <p>
* 覆盖教学日志核心管理、课时核算标准、课时补助标准、联教联训、教师工作量等全功能。
* 接口路径前缀:/log
* </p>
*/
@RestController
@RequestMapping("/log")
public class LogController {
@Resource private LogService logService;
// ======================== 教学日志核心 ========================
/**
* 新增教学日志
* <p>记录单次课堂教学情况,包含授课信息、学员出勤、教学效果等。</p>
*
* @param entity 教学日志实体(班次课堂教学日志)
* @return 操作结果
*/
@PostMapping("/teaching-log/add")
public Result<Void> addLog(@RequestBody SSKCB_RZ entity) {
logService.addLog(entity);
return Result.success();
}
/**
* 分页条件查询教学日志列表(待上报视图)
* <p>未指定状态 rzzt 时默认过滤已上报、已审核,仅展示系统创建/已退回的教学日志(含历史空状态);指定状态时按状态精确过滤。</p>
*/
@GetMapping("/teaching-log/list")
public Result<PageResult<TeachingLogListVO>> listTeachingLog(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String ksrq,
@RequestParam(required = false) String jsrq,
@RequestParam(required = false) String kcmc,
@RequestParam(required = false) String jys,
@RequestParam(required = false) String jxff,
@RequestParam(required = false) String skjy,
@RequestParam(required = false) String rzzt,
@RequestParam(required = false) String pxqb,
@RequestParam(required = false) String gdqk,
@RequestParam(required = false) String gdxxqk,
@RequestParam(required = false) String rwlb) {
PageQuery query = new PageQuery(pageNum, pageSize);
TeachingLogListVO cond = buildTeachingLogCond(ksrq, jsrq, kcmc, jys, jxff, skjy, rzzt, pxqb, gdqk, gdxxqk, rwlb);
return Result.success(logService.pageTeachingLogDetail(query, cond));
}
/**
* 分页条件查询已上报的全部教学日志列表
* <p>查询条件与 /teaching-log/list 一致,状态固定为已上报。</p>
*/
@GetMapping("/teaching-log/reported/list")
public Result<PageResult<TeachingLogListVO>> listReportedTeachingLog(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String ksrq,
@RequestParam(required = false) String jsrq,
@RequestParam(required = false) String kcmc,
@RequestParam(required = false) String jys,
@RequestParam(required = false) String jxff,
@RequestParam(required = false) String skjy,
@RequestParam(required = false) String rzzt,
@RequestParam(required = false) String pxqb,
@RequestParam(required = false) String gdqk,
@RequestParam(required = false) String gdxxqk,
@RequestParam(required = false) String rwlb) {
PageQuery query = new PageQuery(pageNum, pageSize);
TeachingLogListVO cond = buildTeachingLogCond(ksrq, jsrq, kcmc, jys, jxff, skjy, rzzt, pxqb, gdqk, gdxxqk, rwlb);
cond.setZt("已上报");
return Result.success(logService.pageTeachingLogDetail(query, cond));
}
/**
* 分页条件查询已审核的教学日志列表
* <p>查询条件与 /teaching-log/list 一致,状态固定为已审核。</p>
*/
@GetMapping("/teaching-log/audited/list")
public Result<PageResult<TeachingLogListVO>> listAuditedTeachingLog(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String ksrq,
@RequestParam(required = false) String jsrq,
@RequestParam(required = false) String kcmc,
@RequestParam(required = false) String jys,
@RequestParam(required = false) String jxff,
@RequestParam(required = false) String skjy,
@RequestParam(required = false) String rzzt,
@RequestParam(required = false) String pxqb,
@RequestParam(required = false) String gdqk,
@RequestParam(required = false) String gdxxqk,
@RequestParam(required = false) String rwlb) {
PageQuery query = new PageQuery(pageNum, pageSize);
TeachingLogListVO cond = buildTeachingLogCond(ksrq, jsrq, kcmc, jys, jxff, skjy, rzzt, pxqb, gdqk, gdxxqk, rwlb);
cond.setZt("已审核");
return Result.success(logService.pageTeachingLogDetail(query, cond));
}
/**
* 批量上报教学日志
* <p>根据主键编号组(bh)将状态修改为已上报,仅对待上报(系统创建/已退回)数据生效,返回实际更新条数。</p>
*/
@PostMapping("/teaching-log/batch-report")
public Result<Integer> batchReportLogs(@RequestBody List<String> bhList) {
return Result.success(logService.batchReportLogs(bhList));
}
/**
* 批量审核教学日志
* <p>根据主键编号组(bh)将状态修改为已审核,仅对已上报数据生效,返回实际更新条数。</p>
*/
@PostMapping("/teaching-log/batch-audit")
public Result<Integer> batchAuditLogs(@RequestBody List<String> bhList) {
return Result.success(logService.batchAuditLogs(bhList));
}
/**
* 构建教学日志列表查询条件(参数与 /teaching-log/list 保持一致)
*/
private TeachingLogListVO buildTeachingLogCond(String ksrq, String jsrq, String kcmc, String jys, String jxff, String skjy, String rzzt, String pxqb, String gdqk, String gdxxqk, String rwlb) {
TeachingLogListVO cond = new TeachingLogListVO();
cond.setKcmc(kcmc); cond.setJys(jys); cond.setJsfs(jxff);
cond.setSkjy(skjy); cond.setZt(rzzt); cond.setPxqbxx(pxqb);
cond.setGdqk(gdqk); cond.setGdxxqk(gdxxqk); cond.setRwlb(rwlb);
if (gdqk != null && !gdqk.isEmpty()) cond.setGdqkList(java.util.Arrays.asList(gdqk.split(",")));
if (gdxxqk != null && !gdxxqk.isEmpty()) cond.setGdxxqkList(java.util.Arrays.asList(gdxxqk.split(",")));
if (ksrq != null && !ksrq.isEmpty()) cond.setKsrq(java.time.LocalDate.parse(ksrq).atStartOfDay());
if (jsrq != null && !jsrq.isEmpty()) cond.setJsrq(java.time.LocalDate.parse(jsrq).atTime(23, 59, 59));
return cond;
}
/**
* 退回教学日志
*/
@PostMapping("/teaching-log/reject")
public Result<Void> rejectLog(
@RequestParam("bh") String bh,
@RequestParam("thyj") String thyj) {
logService.rejectLog(bh, thyj);
return Result.success();
}
/**
* 根据课表自动创建教学日志
*/
@PostMapping("/teaching-log/auto-create")
public Result<SSKCB_RZ> autoCreateLog(@RequestParam("tybh") String tybh) {
return Result.success(logService.autoCreateLog(tybh));
}
/**
* 批量导入教学日志
*/
@PostMapping("/teaching-log/import")
public Result<Void> importLog(@RequestBody List<SSKCB_RZ> list) {
logService.importLog(list);
return Result.success();
}
@PostMapping("/teaching-log/import-excel")
public Result<Void> importLogExcel(@RequestParam("file") MultipartFile file) {
logService.importLogFromExcel(file);
return Result.success();
}
/**
* 导出教学日志 Excel
*/
@GetMapping("/teaching-log/export")
public void exportLog(TeachingLogListVO cond, HttpServletResponse response) {
logService.exportLogExcel(cond, response);
}
/**
* 下载导入模板
*/
@GetMapping("/teaching-log/download-template")
public void downloadTemplate(HttpServletResponse response) {
try {
java.io.InputStream is = getClass().getClassLoader().getResourceAsStream("template/导入教学日志模板.xls");
if (is == null) {
response.setStatus(404);
return;
}
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=导入教学日志模板.xls");
org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
response.getOutputStream().flush();
is.close();
} catch (Exception e) {
throw new RuntimeException("下载模板失败", e);
}
}
// ======================== 教学日志授课教员 ========================
/**
* 新增教学日志授课教员
* <p>为教学日志添加主讲教师或辅讲教师(通过主教员字段zjy区分)。</p>
*
* @param entity 授课教员关联实体
* @return 操作结果
*/
@PostMapping("/teaching-log/teacher/add")
public Result<Void> addLogTeacher(@RequestBody BCKTJXRZSKJY entity) {
logService.addLogTeacher(entity);
return Result.success();
}
/**
* 分页查询教学日志授课教员列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param bcktjxrzbh 教学日志编号(可选)
* @param fzjybh 辅助教员编号(可选)
* @return 分页结果
*/
@GetMapping("/teaching-log/teacher/list")
public Result<PageResult<BCKTJXRZSKJY>> listLogTeacher(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String bcktjxrzbh,
@RequestParam(required = false) String fzjybh) {
PageQuery query = new PageQuery(pageNum, pageSize);
BCKTJXRZSKJY cond = new BCKTJXRZSKJY();
cond.setBcktjxrzbh(bcktjxrzbh); cond.setFzjybh(fzjybh);
return Result.success(logService.pageLogTeacher(query, cond));
}
// ======================== 教学日志学员学习情况 ========================
/**
* 新增学员学习情况记录
* <p>记录教学日志中每位学员的学习效果(A-优秀 B-良好 C-合格 D-不合格)、到课和请假情况。</p>
*
* @param entity 学员学习情况实体
* @return 操作结果
*/
@PostMapping("/teaching-log/student-status/add")
public Result<Void> addStudentStatus(@RequestBody JXRZXYXXQK entity) {
logService.addStudentLearningStatus(entity);
return Result.success();
}
/**
* 分页查询学员学习情况列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param jxrzbh 教学日志编号(可选)
* @return 分页结果
*/
@GetMapping("/teaching-log/student-status/list")
public Result<PageResult<JXRZXYXXQK>> listStudentStatus(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jxrzbh) {
return Result.success(logService.pageStudentLearningStatus(new PageQuery(pageNum, pageSize), jxrzbh));
}
// ======================== 课时核算标准 ========================
/**
* 新增课时核算标准
* <p>定义主讲教师课时系数、辅讲教师课时系数、讲授方式系数列表等核算参数。
* 可单独设置考试主讲系数和考试指导教师系数。</p>
*
* @param entity 课时核算标准实体
* @return 操作结果
*/
@PostMapping("/calc-standard/add")
public Result<Void> addCalcStandard(@RequestBody KSHBZ entity) {
logService.addCalculationStandard(entity);
return Result.success();
}
/**
* 更新课时核算标准
*
* @param entity 课时核算标准实体(需含编号)
* @return 操作结果
*/
@PostMapping("/calc-standard/update")
public Result<Void> updateCalcStandard(@RequestBody KSHBZ entity) {
logService.updateCalculationStandard(entity);
return Result.success();
}
/**
* 根据编号查询课时核算标准详情
*
* @param bh 编号
* @return 课时核算标准
*/
@GetMapping("/calc-standard/get")
public Result<KSHBZ> getCalcStandard(@RequestParam("bh") String bh) {
return Result.success(logService.getCalculationStandardById(bh));
}
/**
* 分页查询课时核算标准列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param mc 名称(模糊匹配,可选)
* @return 分页结果
*/
@GetMapping("/calc-standard/list")
public Result<PageResult<KSHBZ>> listCalcStandard(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String mc) {
KSHBZ cond = new KSHBZ(); cond.setMc(mc);
return Result.success(logService.pageCalculationStandard(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 课时系数方案 ========================
/**
* 新增课时系数方案
* <p>定义主讲/辅讲课时系数、班级系数、合班系数、各时段课时量等核算参数。</p>
*
* @param entity 课时系数方案实体
* @return 操作结果
*/
@PostMapping("/coefficient-plan/add")
public Result<Void> addCoefficientPlan(@RequestBody KSXSFA entity) {
logService.addCoefficientPlan(entity);
return Result.success();
}
/**
* 更新课时系数方案
*
* @param entity 课时系数方案实体(需含编号)
* @return 操作结果
*/
@PostMapping("/coefficient-plan/update")
public Result<Void> updateCoefficientPlan(@RequestBody KSXSFA entity) {
logService.updateCoefficientPlan(entity);
return Result.success();
}
/**
* 根据编号查询课时系数方案详情
*
* @param bh 编号
* @return 课时系数方案
*/
@GetMapping("/coefficient-plan/get")
public Result<KSXSFA> getCoefficientPlan(@RequestParam("bh") String bh) {
return Result.success(logService.getCoefficientPlanById(bh));
}
/**
* 分页查询课时系数方案列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param mc 名称(模糊匹配,可选)
* @return 分页结果
*/
@GetMapping("/coefficient-plan/list")
public Result<PageResult<KSXSFA>> listCoefficientPlan(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String mc) {
KSXSFA cond = new KSXSFA(); cond.setMc(mc);
return Result.success(logService.pageCoefficientPlan(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 课时费标准 ========================
/**
* 新增课时费标准
* <p>定义绩效等级对应的课时费标准,包括优秀/良好/中等/及格/不及格各档补助金额。</p>
*
* @param entity 课时费标准实体
* @return 操作结果
*/
@PostMapping("/fee-standard/add")
public Result<Void> addFeeStandard(@RequestBody KSFBZ entity) {
logService.addFeeStandard(entity);
return Result.success();
}
/**
* 更新课时费标准
*
* @param entity 课时费标准实体(需含编号)
* @return 操作结果
*/
@PostMapping("/fee-standard/update")
public Result<Void> updateFeeStandard(@RequestBody KSFBZ entity) {
logService.updateFeeStandard(entity);
return Result.success();
}
/**
* 根据编号查询课时费标准详情
*
* @param bh 编号
* @return 课时费标准
*/
@GetMapping("/fee-standard/get")
public Result<KSFBZ> getFeeStandard(@RequestParam("bh") String bh) {
return Result.success(logService.getFeeStandardById(bh));
}
/**
* 分页查询课时费标准列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param mc 名称(模糊匹配,可选)
* @return 分页结果
*/
@GetMapping("/fee-standard/list")
public Result<PageResult<KSFBZ>> listFeeStandard(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String mc) {
KSFBZ cond = new KSFBZ(); cond.setMc(mc);
return Result.success(logService.pageFeeStandard(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 技术职务课时费标准 ========================
/**
* 新增技术职务课时费标准
* <p>按技术职务(教授、副教授、讲师等)定义标准课时量、课时费和超量课时费。</p>
*
* @param entity 技术职务课时费标准实体
* @return 操作结果
*/
@PostMapping("/tech-pos-fee/add")
public Result<Void> addTechPosFee(@RequestBody JSZWKSFBZ entity) {
logService.addTechPosFeeStandard(entity);
return Result.success();
}
/**
* 更新技术职务课时费标准
*
* @param entity 技术职务课时费标准实体(需含编号)
* @return 操作结果
*/
@PostMapping("/tech-pos-fee/update")
public Result<Void> updateTechPosFee(@RequestBody JSZWKSFBZ entity) {
logService.updateTechPosFeeStandard(entity);
return Result.success();
}
/**
* 根据编号查询技术职务课时费标准详情
*
* @param bh 编号
* @return 技术职务课时费标准
*/
@GetMapping("/tech-pos-fee/get")
public Result<JSZWKSFBZ> getTechPosFee(@RequestParam("bh") String bh) {
return Result.success(logService.getTechPosFeeStandardById(bh));
}
/**
* 分页查询技术职务课时费标准列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param jszwbh 技术职务编号(可选)
* @return 分页结果
*/
@GetMapping("/tech-pos-fee/list")
public Result<PageResult<JSZWKSFBZ>> listTechPosFee(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jszwbh) {
JSZWKSFBZ cond = new JSZWKSFBZ(); cond.setJszwbh(jszwbh);
return Result.success(logService.pageTechPosFeeStandard(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 课时补助标准 ========================
/**
* 新增课时补助项目
* <p>定义课时补助项目,支持联教联训等不同类型的补助。</p>
*
* @param entity 课时补助项目实体
* @return 操作结果
*/
@PostMapping("/subsidy-project/add")
public Result<Void> addSubsidyProject(@RequestBody KSBZXM entity) {
logService.addSubsidyProject(entity);
return Result.success();
}
/**
* 更新课时补助项目
*
* @param entity 课时补助项目实体(需含编号)
* @return 操作结果
*/
@PostMapping("/subsidy-project/update")
public Result<Void> updateSubsidyProject(@RequestBody KSBZXM entity) {
logService.updateSubsidyProject(entity);
return Result.success();
}
/**
* 根据编号查询课时补助项目详情
*
* @param bh 编号
* @return 课时补助项目
*/
@GetMapping("/subsidy-project/get")
public Result<KSBZXM> getSubsidyProject(@RequestParam("bh") String bh) {
return Result.success(logService.getSubsidyProjectById(bh));
}
/**
* 分页查询课时补助项目列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param mc 名称(模糊匹配,可选)
* @return 分页结果
*/
@GetMapping("/subsidy-project/list")
public Result<PageResult<KSBZXM>> listSubsidyProject(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String mc) {
KSBZXM cond = new KSBZXM(); cond.setMc(mc);
return Result.success(logService.pageSubsidyProject(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 教学日志课时补助审批表(汇总) ========================
/**
* 新增教学日志课时补助审批表(汇总)
* <p>创建一个核算周期内的课时补助汇总,包含学期、任务类别、核算起止日期等。</p>
*
* @param entity 汇总审批表实体
* @return 操作结果
*/
@PostMapping("/summary/add")
public Result<Void> addSummary(@RequestBody JXRZKSBZSPB entity) {
logService.addSubsidyApproval(entity);
return Result.success();
}
/**
* 更新教学日志课时补助审批表(汇总)
*
* @param entity 汇总审批表实体(需含编号)
* @return 操作结果
*/
@PostMapping("/summary/update")
public Result<Void> updateSummary(@RequestBody JXRZKSBZSPB entity) {
logService.updateSubsidyApproval(entity);
return Result.success();
}
/**
* 根据编号查询教学日志课时补助审批表详情
*
* @param bh 编号
* @return 汇总审批表
*/
@GetMapping("/summary/get")
public Result<JXRZKSBZSPB> getSummary(@RequestParam("bh") String bh) {
return Result.success(logService.getSubsidyApprovalById(bh));
}
/**
* 分页查询教学日志课时补助审批表列表
* <p>支持按状态和任务类别筛选。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param zt 状态(可选)
* @param rwlb 任务类别(可选)
* @return 分页结果
*/
@GetMapping("/summary/list")
public Result<PageResult<JXRZKSBZSPB>> listSummary(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String zt,
@RequestParam(required = false) String rwlb) {
JXRZKSBZSPB cond = new JXRZKSBZSPB(); cond.setZt(zt); cond.setRwlb(rwlb);
return Result.success(logService.pageSubsidyApproval(new PageQuery(pageNum, pageSize), cond));
}
/**
* 自动核算汇总数据
* <p>根据教学日志教员课时补助明细,自动计算总课时量、优质课时量、优质课时量占比、总补助金额。</p>
*
* @param bh 汇总审批表编号
* @return 操作结果
*/
@PostMapping("/summary/calculate")
public Result<Void> calculateSummary(@RequestParam("bh") String bh) {
logService.calculateSummary(bh);
return Result.success();
}
// ======================== 教学日志教员课时补助明细 ========================
/**
* 分页查询教学日志教员课时补助明细
* <p>返回每位教员的课时补助明细,包括课时量、基本标准、增发标准、补助金额等。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20)
* @param jxrzksbzspbh 汇总审批表编号(可选)
* @param jybh 教员编号(可选)
* @return 分页结果
*/
@GetMapping("/summary/detail/list")
public Result<PageResult<JXRZJYKSBZ>> listSummaryDetail(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jxrzksbzspbh,
@RequestParam(required = false) String jybh) {
JXRZJYKSBZ cond = new JXRZJYKSBZ(); cond.setJxrzksbzspbh(jxrzksbzspbh); cond.setJybh(jybh);
return Result.success(logService.pageSubsidyDetail(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 教员课时补助 ========================
/**
* 新增教员课时补助记录
*
* @param entity 教员课时补助实体
* @return 操作结果
*/
@PostMapping("/teacher-subsidy/add")
public Result<Void> addTeacherSubsidy(@RequestBody JYKSBZ entity) {
logService.addTeacherSubsidy(entity);
return Result.success();
}
/**
* 分页查询教员课时补助列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param jybh 教员编号(可选)
* @return 分页结果
*/
@GetMapping("/teacher-subsidy/list")
public Result<PageResult<JYKSBZ>> listTeacherSubsidy(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jybh) {
JYKSBZ cond = new JYKSBZ(); cond.setJybh(jybh);
return Result.success(logService.pageTeacherSubsidy(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 年终课时费 ========================
/**
* 新增年终课时费
* <p>创建学年课时费核算主表,按学期统计总课时量。</p>
*
* @param entity 年终课时费实体
* @return 操作结果
*/
@PostMapping("/year-end-fee/add")
public Result<Void> addYearEndFee(@RequestBody NZKSF entity) {
logService.addYearEndFee(entity);
return Result.success();
}
/**
* 更新年终课时费
*
* @param entity 年终课时费实体(需含编号)
* @return 操作结果
*/
@PostMapping("/year-end-fee/update")
public Result<Void> updateYearEndFee(@RequestBody NZKSF entity) {
logService.updateYearEndFee(entity);
return Result.success();
}
/**
* 根据编号查询年终课时费详情
*
* @param bh 编号
* @return 年终课时费
*/
@GetMapping("/year-end-fee/get")
public Result<NZKSF> getYearEndFee(@RequestParam("bh") String bh) {
return Result.success(logService.getYearEndFeeById(bh));
}
/**
* 分页查询年终课时费列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param mc 名称(模糊匹配,可选)
* @return 分页结果
*/
@GetMapping("/year-end-fee/list")
public Result<PageResult<NZKSF>> listYearEndFee(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String mc) {
NZKSF cond = new NZKSF(); cond.setMc(mc);
return Result.success(logService.pageYearEndFee(new PageQuery(pageNum, pageSize), cond));
}
/**
* 分页查询教员年终课时费明细
* <p>每位教员的课时费核算明细,包含学期课时量、超课时量、计算公式、课时费金额等。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param jybh 教员编号(可选)
* @param nzksfbh 年终课时费编号(可选)
* @return 分页结果
*/
@GetMapping("/year-end-fee/teacher/list")
public Result<PageResult<JYNZKSF>> listTeacherYearEndFee(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jybh,
@RequestParam(required = false) String nzksfbh) {
JYNZKSF cond = new JYNZKSF(); cond.setJybh(jybh); cond.setNzksfbh(nzksfbh);
return Result.success(logService.pageTeacherYearEndFee(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 教师工作量 ========================
/**
* 新增教师工作量记录
* <p>支持录入五类工作量:课程教学、科研学术、指导学员、教学建设、咨询服务。</p>
*
* @param entity 教师工作量实体
* @return 操作结果
*/
@PostMapping("/workload/add")
public Result<Void> addWorkload(@RequestBody JZGZL entity) {
logService.addWorkload(entity);
return Result.success();
}
/**
* 更新教师工作量记录
*
* @param entity 教师工作量实体(需含编号)
* @return 操作结果
*/
@PostMapping("/workload/update")
public Result<Void> updateWorkload(@RequestBody JZGZL entity) {
logService.updateWorkload(entity);
return Result.success();
}
/**
* 根据编号查询教师工作量详情
*
* @param bh 编号
* @return 教师工作量
*/
@GetMapping("/workload/get")
public Result<JZGZL> getWorkload(@RequestParam("bh") String bh) {
return Result.success(logService.getWorkloadById(bh));
}
/**
* 分页查询教师工作量列表
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param jybh 教员编号(可选)
* @param nd 年度(可选)
* @param xq 学期(可选)
* @return 分页结果
*/
@GetMapping("/workload/list")
public Result<PageResult<JZGZL>> listWorkload(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jybh,
@RequestParam(required = false) Integer nd,
@RequestParam(required = false) String xq) {
JZGZL cond = new JZGZL(); cond.setJybh(jybh); cond.setNd(nd); cond.setXq(xq);
return Result.success(logService.pageWorkload(new PageQuery(pageNum, pageSize), cond));
}
/**
* 比对各类教师工作量情况
* <p>按总工作量降序排列,支持按年度和学期筛选,用于分析教师工作量分布。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param nd 年度(可选)
* @param xq 学期(可选)
* @return 排序后的工作量列表
*/
@GetMapping("/workload/compare")
public Result<?> compareWorkload(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) Integer nd,
@RequestParam(required = false) String xq) {
return Result.success(logService.compareWorkload(new PageQuery(pageNum, pageSize), nd, xq));
}
// ======================== 教员课时查询管理 ========================
/**
* 分页查询教员课时信息
* <p>
* 数据来源:学期教员信息表 JOIN 教员表 JOIN 教研室表。
* 列表展示:教研室名称、教员姓名、教员类别、当前职称、学期职称、
* 当前专业技术职务等级、学期专业技术职务等级、主讲课时、辅讲课时、
* 课程总课时、课程折算总课时、项目补助课时、总课时。
* </p>
* <p>查询条件(均为可选):教员姓名(模糊)、教研室(代号精确)、教研室名称(模糊)、
* 当前职称/职务、学期职称、当前/学期专业技术职务等级、部系名称(模糊)、年度(学期);
* 各课时量支持数字范围(xx课时至xx课时):主讲课时、辅讲课时、课程总课时、
* 课程折算总课时、项目补助课时、总课时(传 xxxMin/xxxMax 参数)。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param cond 查询条件对象(GET 参数自动绑定)
* @return 分页结果
*/
@GetMapping("/teacher-hours/list")
public Result<PageResult<TeacherHoursVO>> listTeacherHours(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
TeacherHoursVO cond) {
return Result.success(logService.pageTeacherHours(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 教学实施计划统计 ========================
/**
* 分页查询教学实施计划统计数据
* <p>按天统计教学运行数据,包括教学日志填写数、审核数、听查课数、调课数、缺课人次等。</p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param rq 日期(可选)
* @return 分页结果
*/
@GetMapping("/stats/list")
public Result<PageResult<JXSSJHTJB>> listStats(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String rq) {
JXSSJHTJB cond = new JXSSJHTJB();
return Result.success(logService.pageTeachingStats(new PageQuery(pageNum, pageSize), cond));
}
}
@@ -0,0 +1,132 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.accountmanagement.AccountLoginDTO;
import com.roomroot.jwgl.dto.login.LoginDTO;
import com.roomroot.jwgl.entity.SSJG;
import com.roomroot.jwgl.mapper.SSJGMapper;
import com.roomroot.jwgl.service.AccountManagementService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.utils.AccountManagementConstants;
import com.roomroot.jwgl.vo.accountmanagement.AccountLoginVO;
import com.roomroot.jwgl.vo.accountmanagement.AccountRoleVO;
import com.roomroot.jwgl.vo.login.LoginResultVO;
import com.roomroot.common.annotation.Anonymous;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* 登录认证控制器
* <p>
* 支持行政、教员、学员、管理员四种用户类型登录。
* 管理员登录不需要单位(orgId),其余类型需选择单位。
* 使用数据表:登录信息表(用户凭证)、教学管理机构/实施_机关(单位信息)。
* </p>
*/
@RestController
@RequestMapping("/auth")
@Anonymous
public class LoginController {
@Resource
private AccountManagementService accountManagementService;
@Resource
private SSJGMapper ssjgMapper;
/**
* 用户登录
* <p>
* 根据登录名和密码验证身份,返回用户信息、角色和单位信息。
* </p>
*/
@PostMapping("/login")
public Result<LoginResultVO> login(@RequestBody LoginDTO loginDTO) {
// 1. 参数校验
if (loginDTO.getLoginName() == null || loginDTO.getLoginName().isEmpty()) {
return Result.error(400, "登录名不能为空");
}
if (loginDTO.getPassword() == null || loginDTO.getPassword().isEmpty()) {
return Result.error(400, "密码不能为空");
}
if (loginDTO.getUserType() == null || loginDTO.getUserType().isEmpty()) {
return Result.error(400, "用户类型不能为空");
}
// 管理员登录不需要单位
if (!"MANAGER".equals(loginDTO.getUserType()) && (loginDTO.getOrgId() == null || loginDTO.getOrgId().isEmpty())) {
return Result.error(400, "单位不能为空");
}
// 2. 参数转换(LoginDTO → AccountLoginDTO
AccountLoginDTO accountLoginDTO = new AccountLoginDTO();
accountLoginDTO.setLoginName(loginDTO.getLoginName());
accountLoginDTO.setPassword(loginDTO.getPassword());
// 3. 委托 AccountManagementService 处理登录
AccountLoginVO loginVO = accountManagementService.login(accountLoginDTO);
// 4. 匹配用户类型
String roleTypeCode = mapUserTypeToRoleCode(loginDTO.getUserType());
List<AccountRoleVO> roles = loginVO.getRoles();
boolean hasRole = roles.stream().anyMatch(r -> roleTypeCode.equals(r.getRoleType()));
if (!hasRole) {
return Result.error(403, "当前用户没有" + loginDTO.getUserType() + "权限");
}
// 5. 查询单位信息
String orgName = null;
if (!"MANAGER".equals(loginDTO.getUserType())) {
for (AccountRoleVO role : roles) {
if (roleTypeCode.equals(role.getRoleType())) {
SSJG org = ssjgMapper.selectById(role.getTargetId());
if (org != null) {
orgName = org.getJGMC();
}
break;
}
}
}
// 6. 返回值转换(AccountLoginVO → LoginResultVO
LoginResultVO result = new LoginResultVO();
result.setUserId(loginVO.getAccountId());
result.setUserName(loginVO.getUserName());
result.setLoginName(loginVO.getLoginName());
result.setUserType(loginDTO.getUserType());
result.setOrgId(loginDTO.getOrgId());
result.setOrgName(orgName);
List<LoginResultVO.RoleInfo> roleInfos = roles.stream().map(r -> {
LoginResultVO.RoleInfo ri = new LoginResultVO.RoleInfo();
ri.setRoleType(r.getRoleType());
ri.setRoleName(r.getRoleName());
ri.setTargetId(r.getTargetId());
ri.setTargetName(r.getTargetName());
return ri;
}).collect(Collectors.toList());
result.setRoles(roleInfos);
return Result.success(result);
}
/**
* 将前端用户类型映射为角色编码
*/
private String mapUserTypeToRoleCode(String userType) {
switch (userType) {
case "ADMIN":
return AccountManagementConstants.ROLE_DEPARTMENT_PERSONNEL;
case "TEACHER":
return AccountManagementConstants.ROLE_TEACHER;
case "STUDENT":
return AccountManagementConstants.ROLE_STUDENT;
case "MANAGER":
return AccountManagementConstants.ROLE_DEPARTMENT_PERSONNEL;
default:
return userType;
}
}
}
@@ -0,0 +1,200 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementCreateDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementIdDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementPriorityDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementPublishDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementQueryDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementRecipientQueryDTO;
import com.roomroot.jwgl.dto.noticeannouncement.NoticeAnnouncementUpdateDTO;
import com.roomroot.jwgl.dto.noticeannouncement.UserNoticeAnnouncementQueryDTO;
import com.roomroot.jwgl.service.NoticeAnnouncementService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementDetailVO;
import com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementPublishResultVO;
import com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementRecipientVO;
import com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementStatisticsVO;
import com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementVO;
import com.roomroot.jwgl.vo.noticeannouncement.UserNoticeAnnouncementDetailVO;
import com.roomroot.jwgl.vo.noticeannouncement.UserNoticeAnnouncementVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
/**
* 通知公告管理接口。
*
* <p>后台公告维护、发布统计和用户阅读入口统一保留在当前控制器中,
* 不为同一通知公告功能重复创建控制器。</p>
*/
@RestController
@RequestMapping("/notice-announcement")
public class NoticeAnnouncementController {
/**
* 通知公告管理业务服务。
*/
@Resource
private NoticeAnnouncementService noticeAnnouncementService;
/**
* 分页查询后台通知公告。
*/
@GetMapping("/list")
public Result<PageResult<NoticeAnnouncementVO>> list(
@Valid NoticeAnnouncementQueryDTO dto) {
// 调用业务层完成筛选、接收阅读统计和分页结果封装。
return Result.success(
noticeAnnouncementService.list(dto));
}
/**
* 查询通知公告后台详情。
*/
@GetMapping("/get")
public Result<NoticeAnnouncementDetailVO> get(
@Valid NoticeAnnouncementIdDTO dto) {
// 调用业务层查询公告内容、状态、发布范围和阅读统计。
return Result.success(
noticeAnnouncementService.get(dto));
}
/**
* 新增一条拟制公告。
*/
@PostMapping("/add")
public Result<NoticeAnnouncementDetailVO> add(
@Valid @RequestBody
NoticeAnnouncementCreateDTO dto) {
// 调用业务层固定创建拟制状态公告。
return Result.success(
"新增成功",
noticeAnnouncementService.add(dto));
}
/**
* 修改拟制或已下架公告。
*/
@PostMapping("/update")
public Result<NoticeAnnouncementDetailVO> update(
@Valid @RequestBody
NoticeAnnouncementUpdateDTO dto) {
// 调用业务层校验状态并修改公告可编辑内容。
return Result.success(
"修改成功",
noticeAnnouncementService.update(dto));
}
/**
* 发布或重新发布公告。
*/
@PostMapping("/publish")
public Result<NoticeAnnouncementPublishResultVO> publish(
@Valid @RequestBody
NoticeAnnouncementPublishDTO dto) {
/*
* 业务层会解析全校、全体教员或指定部别账户,
* 在同一事务中替换接收人快照并更新公告状态。
*/
return Result.success(
"发布成功",
noticeAnnouncementService.publish(dto));
}
/**
* 下架已发布公告。
*/
@PostMapping("/down")
public Result<NoticeAnnouncementDetailVO> down(
@Valid @RequestBody
NoticeAnnouncementIdDTO dto) {
// 调用业务层锁定公告并执行已发布到已下架状态流转。
return Result.success(
"下架成功",
noticeAnnouncementService.down(dto));
}
/**
* 删除拟制或已下架公告。
*/
@PostMapping("/delete")
public Result<Void> delete(
@Valid @RequestBody
NoticeAnnouncementIdDTO dto) {
// 第一步:调用业务层校验状态并删除接收人快照和公告主体。
noticeAnnouncementService.delete(dto);
// 第二步:删除操作没有业务返回对象,返回统一成功结果。
return Result.success("删除成功", null);
}
/**
* 调整公告优先级或取消置顶。
*/
@PostMapping("/priority")
public Result<NoticeAnnouncementDetailVO> priority(
@Valid @RequestBody
NoticeAnnouncementPriorityDTO dto) {
// 优先级为0表示取消置顶,大于0时参与公告列表优先排序。
return Result.success(
"优先级调整成功",
noticeAnnouncementService
.updatePriority(dto));
}
/**
* 分页查询公告接收和阅读明细。
*/
@GetMapping("/recipients")
public Result<PageResult<NoticeAnnouncementRecipientVO>>
recipients(
@Valid NoticeAnnouncementRecipientQueryDTO dto) {
// 调用业务层按账户去重查询接收时间、阅读状态和首次阅读时间。
return Result.success(
noticeAnnouncementService.recipients(dto));
}
/**
* 查询公告接收和阅读统计。
*/
@GetMapping("/statistics")
public Result<NoticeAnnouncementStatisticsVO> statistics(
@Valid NoticeAnnouncementIdDTO dto) {
// 调用业务层计算接收、已读、未读人数和阅读率。
return Result.success(
noticeAnnouncementService.statistics(dto));
}
/**
* 分页查询当前登录账户可见的已发布公告。
*/
@GetMapping("/user/list")
public Result<PageResult<UserNoticeAnnouncementVO>>
userList(
@Valid UserNoticeAnnouncementQueryDTO dto) {
// 查询账户身份只从服务端 Session 读取,不接收客户端账户编号。
return Result.success(
noticeAnnouncementService.userList(dto));
}
/**
* 当前登录账户打开并阅读公告。
*/
@PostMapping("/user/read")
public Result<UserNoticeAnnouncementDetailVO> read(
@Valid @RequestBody
NoticeAnnouncementIdDTO dto) {
/*
* 首次打开会记录阅读状态和首次阅读时间;
* 重复打开只增加公告累计阅读次数,不重复增加阅读人数。
*/
return Result.success(
noticeAnnouncementService.read(dto));
}
}
@@ -0,0 +1,122 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.notificationlog.NotificationLogExportDTO;
import com.roomroot.jwgl.dto.notificationlog.NotificationLogIdDTO;
import com.roomroot.jwgl.dto.notificationlog.NotificationLogQueryDTO;
import com.roomroot.jwgl.dto.notificationlog.NotificationLogRecipientQueryDTO;
import com.roomroot.jwgl.service.NotificationLogService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.utils.NotificationLogUtil;
import com.roomroot.jwgl.vo.notificationlog.NotificationLogDetailVO;
import com.roomroot.jwgl.vo.notificationlog.NotificationLogRecipientVO;
import com.roomroot.jwgl.vo.notificationlog.NotificationLogStatisticsVO;
import com.roomroot.jwgl.vo.notificationlog.NotificationLogVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.util.List;
import static com.roomroot.jwgl.utils.NotificationLogUtil.writeNotificationLogExcel;
/**
* 通知日志管理接口。
*
* <p>当前控制器统一承载通知发送历史追踪接口,
* 不修改通知公告管理已有的发布和阅读入口。</p>
*/
@RestController
@RequestMapping("/notification-log")
public class NotificationLogController {
/**
* 通知日志管理业务服务。
*/
@Resource
private NotificationLogService notificationLogService;
/**
* 分页查询通知发送历史。
*
* @param dto 通知日志查询条件
* @return 通知发送历史分页结果
*/
@GetMapping("/list")
public Result<PageResult<NotificationLogVO>> list(
@Valid NotificationLogQueryDTO dto) {
// 调用业务层完成筛选、发送接收统计和统一分页结果封装。
return Result.success(
notificationLogService.list(dto));
}
/**
* 根据通知编号查询发送日志详情。
*
* @param dto 通知日志编号参数
* @return 通知主体和完整发送、阅读统计
*/
@GetMapping("/get")
public Result<NotificationLogDetailVO> get(
@Valid NotificationLogIdDTO dto) {
// 调用业务层校验日志编号并查询完整发送日志详情。
return Result.success(
notificationLogService.get(dto));
}
/**
* 分页查询指定通知的接收对象和阅读明细。
*
* @param dto 通知编号、分页和接收阅读筛选条件
* @return 按账户去重的接收与阅读明细
*/
@GetMapping("/recipients")
public Result<PageResult<NotificationLogRecipientVO>>
recipients(
@Valid NotificationLogRecipientQueryDTO dto) {
// 调用业务层完成日志存在性校验、账户去重和分页结果封装。
return Result.success(
notificationLogService.recipients(dto));
}
/**
* 按当前筛选条件汇总通知发送和阅读情况。
*
* @param dto 通知日志筛选条件
* @return 通知数量、发送结果和阅读情况汇总
*/
@GetMapping("/statistics")
public Result<NotificationLogStatisticsVO> statistics(
@Valid NotificationLogExportDTO dto) {
// 调用业务层复用列表筛选规则并计算完整汇总结果。
return Result.success(
notificationLogService.statistics(dto));
}
/**
* 按当前筛选条件导出全部通知日志。
*
* @param dto 通知日志导出筛选条件
* @param response 当前 HTTP 响应
*/
@GetMapping("/export")
public void export(
@Valid NotificationLogExportDTO dto,
HttpServletResponse response) {
/*
* 第一步:调用业务层按照固定批次查询全部符合条件的通知日志,
* 并复用列表的筛选、稳定排序和统计字段补全规则。
*/
List<NotificationLogVO> records =
notificationLogService.export(dto);
/*
* 第二步:由通知日志工具类统一生成 Excel 并写入响应,
* 控制器不重复维护工作簿样式、文件名编码和安全文本规则。
*/
NotificationLogUtil.writeNotificationLogExcel(response, records);
}
}
@@ -0,0 +1,90 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JYSRWS;
import com.roomroot.jwgl.service.OfficeTaskBookService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 教研室任务书控制器
*/
@RestController
@RequestMapping("/officeTaskBook")
public class OfficeTaskBookController {
@Resource
private OfficeTaskBookService officeTaskBookService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JYSRWS jysrws) {
officeTaskBookService.add(jysrws);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
officeTaskBookService.delete(bh);
return Result.success();
}
/**
* 批量删除
*/
@PostMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> bhList) {
officeTaskBookService.batchDelete(bhList);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JYSRWS jysrws) {
officeTaskBookService.update(jysrws);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<JYSRWS> getByBh(@RequestParam("bh") String bh) {
return Result.success(officeTaskBookService.getByBh(bh));
}
/**
* 分页查询列表
*/
@GetMapping("/list")
public Result<PageResult<JYSRWS>> list(PageQuery query, JYSRWS jysrws) {
return Result.success(officeTaskBookService.pageList(query, jysrws));
}
/**
* 根据教学任务编号查询
*/
@GetMapping("/listByJxrwbh")
public Result<List<JYSRWS>> listByJxrwbh(@RequestParam("jxrwbh") String jxrwbh) {
return Result.success(officeTaskBookService.listByJxrwbh(jxrwbh));
}
/**
* 根据教研室代号查询
*/
@GetMapping("/listByJysdh")
public Result<List<JYSRWS>> listByJysdh(@RequestParam("jysdh") String jysdh) {
return Result.success(officeTaskBookService.listByJysdh(jysdh));
}
}
@@ -0,0 +1,99 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.operationlog.OperationLogExportDTO;
import com.roomroot.jwgl.dto.operationlog.OperationLogIdDTO;
import com.roomroot.jwgl.dto.operationlog.OperationLogQueryDTO;
import com.roomroot.jwgl.service.OperationLogService;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.utils.OperationLogUtil;
import com.roomroot.jwgl.vo.operationlog.OperationLogDetailVO;
import com.roomroot.jwgl.vo.operationlog.OperationLogModuleVO;
import com.roomroot.jwgl.vo.operationlog.OperationLogVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.util.List;
/**
* 操作日志管理接口。
*
* <p>统一提供分页查询、详情查询和 Excel 导出接口,
* 操作日志自动采集由请求拦截器完成,不拆分重复的业务控制器。</p>
*/
@RestController
@RequestMapping("/operation-log")
public class OperationLogController {
/**
* 操作日志管理业务服务。
*/
@Resource
private OperationLogService operationLogService;
/**
* 分页查询操作日志。
*
* @param dto 查询条件
* @return 操作日志分页结果
*/
@GetMapping("/list")
public Result<PageResult<OperationLogVO>> list(
@Valid OperationLogQueryDTO dto) {
// 调用业务层完成参数校验、三表联查、模块识别和分页结果封装。
return Result.success(operationLogService.list(dto));
}
/**
* 查询操作日志页面可使用的模块选项。
*
* @return 与模块筛选白名单保持一致的模块选项
*/
@GetMapping("/modules")
public Result<List<OperationLogModuleVO>> modules() {
// 调用业务层取得按系统业务顺序排列的操作日志模块选项。
return Result.success(operationLogService.modules());
}
/**
* 根据编号查询操作日志详情。
*
* @param dto 操作日志编号参数
* @return 操作日志详情
*/
@GetMapping("/get")
public Result<OperationLogDetailVO> get(
@Valid OperationLogIdDTO dto) {
// 调用业务层校验日志编号并查询完整的操作、登录和账户信息。
return Result.success(operationLogService.get(dto));
}
/**
* 按当前筛选条件导出全部操作日志数据。
*
* @param dto 导出筛选条件
* @param response 当前 HTTP 响应
*/
@GetMapping("/export")
public void export(
@Valid OperationLogExportDTO dto,
HttpServletResponse response) {
/*
* 第一步:调用业务层复用列表筛选、稳定排序和模块识别规则,
* 查询全部符合当前导出条件的操作日志。
*/
List<OperationLogVO> records =
operationLogService.export(dto);
/*
* 第二步:由操作日志工具类统一生成 Excel 文件并写入响应,
* 控制器不重复维护工作簿样式、文件名编码和安全文本处理。
*/
OperationLogUtil.writeOperationLogExcel(response, records);
}
}
@@ -0,0 +1,74 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XQXLB;
import com.roomroot.jwgl.service.SemesterCalendarService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 学期校历表控制器
*/
@RestController
@RequestMapping("/xqxlb")
public class SemesterCalendarController {
@Resource
private SemesterCalendarService semesterCalendarService;
/**
* 新增学期校历
*/
@PostMapping("/add")
public Result<Void> add(@RequestParam("startDate") String startDate,@RequestParam("endDate") String endDate) {
semesterCalendarService.add(startDate,endDate);
return Result.success();
}
/**
* 删除学期校历
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
semesterCalendarService.delete(bh);
return Result.success();
}
/**
* 更新学期校历
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XQXLB xqxlb) {
semesterCalendarService.update(xqxlb);
return Result.success();
}
/**
* 根据编号查询学期校历
*/
@GetMapping("/get")
public Result<XQXLB> getById(@RequestParam("bh") String bh) {
return Result.success(semesterCalendarService.getById(bh));
}
/**
* 根据年度查询学期校历列表(全量)
*/
@GetMapping("/list")
public Result<List<XQXLB>> list(@RequestParam("nd") Integer nd) {
return Result.success(semesterCalendarService.listByNd(nd));
}
/**
* 导入Excel文件
*/
@PostMapping("/import")
public Result<Integer> importExcel(@RequestParam("file") MultipartFile file) {
int count = semesterCalendarService.importExcel(file);
return Result.success("导入成功", count);
}
}
@@ -0,0 +1,73 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XQ;
import com.roomroot.jwgl.service.SemesterService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 学期控制器
*/
@RestController
@RequestMapping("/semester")
public class SemesterController {
@Resource
private SemesterService semesterService;
/**
* 新增学期
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XQ xq) {
semesterService.add(xq);
return Result.success();
}
/**
* 删除学期
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("nd") Integer nd) {
semesterService.delete(nd);
return Result.success();
}
/**
* 更新学期
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XQ xq) {
semesterService.update(xq);
return Result.success();
}
/**
* 根据年度查询
*/
@GetMapping("/get")
public Result<XQ> getByNd(@RequestParam("nd") Integer nd) {
return Result.success(semesterService.getByNd(nd));
}
/**
* 分页查询学期列表
*/
@GetMapping("/list")
public Result<PageResult<XQ>> list(PageQuery query, XQ xq) {
return Result.success(semesterService.pageList(query, xq));
}
/**
* 查询所有学期列表
*/
@GetMapping("/all")
public Result<List<XQ>> all() {
return Result.success(semesterService.list());
}
}
@@ -0,0 +1,114 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XYXX;
import com.roomroot.jwgl.entity.XYKCCJ;
import com.roomroot.jwgl.entity.XYKCGCCJ;
import com.roomroot.jwgl.service.StudentRecordsService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 学员档案管理控制器
* <p>
* 提供学员信息的增删改查、学籍异动管理,
* 以及学员课程成绩查询、课程过程成绩查询、课程表查询和 Excel 导出功能。
* </p>
*/
@RestController
@RequestMapping("/student-records")
public class StudentRecordsController {
@Resource
private StudentRecordsService studentRecordsService;
// ======================== 学员 CRUD ========================
@PostMapping("/add")
public Result<Void> add(@RequestBody XYXX xyxx) {
studentRecordsService.add(xyxx);
return Result.success();
}
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
studentRecordsService.delete(bh);
return Result.success();
}
@PostMapping("/update")
public Result<Void> update(@RequestBody XYXX xyxx) {
studentRecordsService.update(xyxx);
return Result.success();
}
@GetMapping("/get")
public Result<XYXX> getById(@RequestParam("bh") String bh) {
return Result.success(studentRecordsService.getById(bh));
}
@GetMapping("/list")
public Result<PageResult<XYXX>> list(PageQuery query, XYXX xyxx) {
return Result.success(studentRecordsService.pageList(query, xyxx));
}
// ======================== 学籍异动 ========================
@PostMapping("/retain-grade")
public Result<Void> retainGrade(@RequestParam("bh") String bh) {
studentRecordsService.retainGrade(bh);
return Result.success();
}
@PostMapping("/downgrade")
public Result<Void> downgrade(@RequestParam("bh") String bh) {
studentRecordsService.downgrade(bh);
return Result.success();
}
@PostMapping("/drop-out")
public Result<Void> dropOut(@RequestParam("bh") String bh) {
studentRecordsService.dropOut(bh);
return Result.success();
}
// ======================== 课程成绩查询 ========================
/**
* 查询学员的课程成绩列表JW
*
* @param xybh 学员编号
*/
@GetMapping("/grades")
public Result<List<XYKCCJ>> getGrades(@RequestParam("xybh") String xybh) {
return Result.success(studentRecordsService.getCourseGrades(xybh));
}
/**
* 查询学员的课程过程成绩列表
*
* @param xybh 学员编号
*/
@GetMapping("/process-grades")
public Result<List<XYKCGCCJ>> getProcessGrades(@RequestParam("xybh") String xybh) {
return Result.success(studentRecordsService.getCourseProcessGrades(xybh));
}
// ======================== Excel 导出 ========================
/**
* 导出学员课程成绩 Excel
*
* @param xybh 学员编号
* @param response HTTP 响应
*/
@GetMapping("/export-grades")
public void exportGrades(@RequestParam("xybh") String xybh, HttpServletResponse response) {
studentRecordsService.exportGradesExcel(xybh, response);
}
}
@@ -0,0 +1,89 @@
package com.roomroot.web.controller.jwgl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.jwgl.entity.XYDSCKCB;
import com.roomroot.jwgl.service.StudentTeamOutputScheduleService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 学员队输出课程表 Controller
*/
@RestController
@RequestMapping("/studentTeamOutputSchedule")
public class StudentTeamOutputScheduleController {
@Autowired
private StudentTeamOutputScheduleService studentTeamOutputScheduleService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XYDSCKCB xydsckcb) {
studentTeamOutputScheduleService.add(xydsckcb);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
studentTeamOutputScheduleService.delete(bh);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYDSCKCB xydsckcb) {
studentTeamOutputScheduleService.update(xydsckcb);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<XYDSCKCB> get(@RequestParam("bh") String bh) {
XYDSCKCB xydsckcb = studentTeamOutputScheduleService.getByBh(bh);
return Result.success(xydsckcb);
}
/**
* 根据年度和学员队编号查询
*/
@GetMapping("/getByNdAndXydbh")
public Result<XYDSCKCB> getByNdAndXydbh(
@RequestParam("nd") Integer nd,
@RequestParam("xydbh") String xydbh) {
XYDSCKCB xydsckcb = studentTeamOutputScheduleService.getByNdAndXydbh(nd, xydbh);
return Result.success(xydsckcb);
}
/**
* 分页查询
*/
@GetMapping("/list")
public Result<Page<XYDSCKCB>> list(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
XYDSCKCB xydsckcb) {
Page<XYDSCKCB> page = studentTeamOutputScheduleService.list(pageNum, pageSize, xydsckcb);
return Result.success(page);
}
/**
* 查询所有
*/
@GetMapping("/all")
public Result<List<XYDSCKCB>> all() {
List<XYDSCKCB> list = studentTeamOutputScheduleService.all();
return Result.success(list);
}
}
@@ -0,0 +1,162 @@
package com.roomroot.web.controller.jwgl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.jwgl.entity.XYDRWB;
import com.roomroot.jwgl.service.StudentTeamTaskService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 学员队任务表 Controller
*/
@RestController
@RequestMapping("/studentTeamTask")
public class StudentTeamTaskController {
@Autowired
private StudentTeamTaskService studentTeamTaskService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XYDRWB xydrwb) {
studentTeamTaskService.add(xydrwb);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
studentTeamTaskService.delete(bh);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XYDRWB xydrwb) {
studentTeamTaskService.update(xydrwb);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<XYDRWB> get(@RequestParam("bh") String bh) {
XYDRWB xydrwb = studentTeamTaskService.getByBh(bh);
return Result.success(xydrwb);
}
/**
* 分页查询(按序号标识排序)
*/
@GetMapping("/list")
public Result<Page<XYDRWB>> list(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
XYDRWB xydrwb) {
Page<XYDRWB> page = studentTeamTaskService.list(pageNum, pageSize, xydrwb);
return Result.success(page);
}
/**
* 分页查询(按计划课次序号排序)
*/
@GetMapping("/groupList")
public Result<Page<XYDRWB>> groupList(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
XYDRWB xydrwb) {
Page<XYDRWB> page = studentTeamTaskService.groupList(pageNum, pageSize, xydrwb);
return Result.success(page);
}
/**
* 批量预设合班
* <p>
* 根据编号列表,按年度排序生成统一的计划课次序号
* </p>
*
* @param params 包含bhList(编号列表)
* @return 更新数量
*/
@PostMapping("/batchPresetMerge")
public Result<Integer> batchPresetMerge(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
int count = studentTeamTaskService.batchPresetMerge(bhList);
return Result.success(count);
}
/**
* 批量预设拆班
* <p>
* 根据编号列表,清空计划课次序号
* </p>
*
* @param params 包含bhList(编号列表)
* @return 更新数量
*/
@PostMapping("/batchPresetSplit")
public Result<Integer> batchPresetSplit(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
int count = studentTeamTaskService.batchPresetSplit(bhList);
return Result.success(count);
}
/**
* 查询所有
*/
@GetMapping("/all")
public Result<List<XYDRWB>> all() {
List<XYDRWB> list = studentTeamTaskService.all();
return Result.success(list);
}
/**
* 自动生成必修课程
* <p>
* 根据学员队编号从学员队表获取专业代号,
* 再根据专业代号和学期第次查询专业教学计划表,
* 为当前班次自动生成必修课程,插入到学员队任务表。
* 已存在的课程(按课编号判断)不会重复添加。
* </p>
*
* @param xydbh 学员队编号
* @param xqdc 学期第次
* @return 新增数量
*/
@PostMapping("/autoGenerateRequiredCourses")
public Result<Integer> autoGenerateRequiredCourses(
@RequestParam("xydbh") String xydbh,
@RequestParam("xqdc") Integer xqdc) {
int count = studentTeamTaskService.autoGenerateRequiredCourses(xydbh, xqdc);
return Result.success(count);
}
/**
* 批量复制课程
* <p>
* 根据传入的学员队任务表编号集合,复制课程信息,
* 替换学员队编号为新的值
* </p>
*
* @param params 包含bhList(源编号集合)和xydbh(新学员队编号)
* @return 新生成的编号集合
*/
@PostMapping("/copy")
public Result<List<String>> copy(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
String newXydbh = (String) params.get("xydbh");
List<String> newBhList = studentTeamTaskService.copy(bhList, newXydbh);
return Result.success(newBhList);
}
}
@@ -0,0 +1,149 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.systeminitialization.SemesterInitializationSaveDTO;
import com.roomroot.jwgl.dto.systeminitialization.SystemInitializationConfigurationSaveDTO;
import com.roomroot.jwgl.dto.systeminitialization.SystemInitializationExecutionDTO;
import com.roomroot.jwgl.dto.systeminitialization.SystemInitializationHistoricalImportDTO;
import com.roomroot.jwgl.service.SystemInitializationService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.systeminitialization.SemesterInitializationVO;
import com.roomroot.jwgl.vo.systeminitialization.SystemInitializationConfigurationVO;
import com.roomroot.jwgl.vo.systeminitialization.SystemInitializationExecutionResultVO;
import com.roomroot.jwgl.vo.systeminitialization.SystemInitializationHistoricalImportResultVO;
import com.roomroot.jwgl.vo.systeminitialization.SystemInitializationPrecheckVO;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
/**
* 系统初始化管理接口。
*
* <p>系统基础参数、学期参数、历史数据导入、预检查和最终执行确认
* 统一保留在同一个控制器中,不为同一业务菜单重复创建控制器。</p>
*/
@RestController
@RequestMapping("/system-initialization")
public class SystemInitializationController {
/**
* 系统初始化业务服务。
*/
@Resource
private SystemInitializationService systemInitializationService;
/**
* 查询当前系统基础参数。
*
* @return 当前生效的系统基础参数
*/
@GetMapping("/configuration")
public Result<SystemInitializationConfigurationVO> configuration() {
// 调用业务层查询当前生效配置,并使用统一结果对象返回给前端。
return Result.success(
systemInitializationService.getCurrentConfiguration());
}
/**
* 保存新的系统基础参数版本。
*
* @param dto 系统基础参数
* @return 保存后立即生效的新版本
*/
@PostMapping("/configuration/save")
public Result<SystemInitializationConfigurationVO>
saveConfiguration(
@Valid @RequestBody
SystemInitializationConfigurationSaveDTO dto) {
// 调用业务层校验期望版本并新增一条系统配置版本记录。
return Result.success(
"系统基础参数保存成功",
systemInitializationService.saveConfiguration(dto));
}
/**
* 查询当前学期初始化参数。
*
* @return 当前学期
*/
@GetMapping("/semester")
public Result<SemesterInitializationVO> semester() {
// 调用业务层读取当前学期并补充统一展示名称。
return Result.success(
systemInitializationService.getCurrentSemester());
}
/**
* 新增或修改指定年度和序号的学期参数。
*
* @param dto 学期初始化参数
* @return 保存后的学期
*/
@PostMapping("/semester/save")
public Result<SemesterInitializationVO> saveSemester(
@Valid @RequestBody
SemesterInitializationSaveDTO dto) {
// 调用业务层完成日期冲突检查、当前学期切换和学期保存。
return Result.success(
"学期参数保存成功",
systemInitializationService.saveSemester(dto));
}
/**
* 导入历史部别、教研室隶属关系和部别人员基础数据。
*
* @param dto 历史数据 Excel 文件
* @return 各类数据实际导入数量
*/
@PostMapping(
value = "/history/import",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Result<SystemInitializationHistoricalImportResultVO>
importHistoricalData(
@Valid SystemInitializationHistoricalImportDTO dto) {
/*
* 调用业务层解析并预校验整份工作簿,
* 全部数据通过后在同一事务中写入四张基础数据表。
*/
return Result.success(
"历史基础数据导入成功",
systemInitializationService
.importHistoricalData(dto));
}
/**
* 执行系统初始化前的完整预检查。
*
* @return 配置、学期、组织数据和引用完整性检查结果
*/
@GetMapping("/precheck")
public Result<SystemInitializationPrecheckVO> precheck() {
// 调用业务层汇总所有初始化必需检查项。
return Result.success(
systemInitializationService.precheck());
}
/**
* 在明确确认且预检查通过后完成系统初始化确认。
*
* @param dto 页面预检查快照和确认标志
* @return 初始化执行结果
*/
@PostMapping("/execute")
public Result<SystemInitializationExecutionResultVO> execute(
@Valid @RequestBody
SystemInitializationExecutionDTO dto) {
/*
* 调用业务层重新执行预检查,
* 同时校验配置版本和当前学期未在页面确认后发生变化。
*/
return Result.success(
"系统初始化完成",
systemInitializationService.execute(dto));
}
}
@@ -0,0 +1,100 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JCXX;
import com.roomroot.jwgl.service.TeachingMaterialService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 教材信息控制器
*/
@RestController
@RequestMapping("/teachingMaterial")
public class TeachingMaterialController {
@Resource
private TeachingMaterialService teachingMaterialService;
/**
* 新增教材信息
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JCXX jcxx) {
teachingMaterialService.add(jcxx);
return Result.success();
}
/**
* 删除教材信息
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
teachingMaterialService.delete(id);
return Result.success();
}
/**
* 更新教材信息
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JCXX jcxx) {
teachingMaterialService.update(jcxx);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/getByBh")
public Result<JCXX> getByBh(@RequestParam("bh") String bh) {
return Result.success(teachingMaterialService.getByBh(bh));
}
/**
* 根据ID查询
*/
@GetMapping("/getById")
public Result<JCXX> getById(@RequestParam("id") String id) {
return Result.success(teachingMaterialService.getById(id));
}
/**
* 分页查询教材信息列表
*/
@GetMapping("/list")
public Result<PageResult<JCXX>> list(PageQuery query, JCXX jcxx) {
return Result.success(teachingMaterialService.pageList(query, jcxx));
}
/**
* 查询所有教材信息列表
*/
@GetMapping("/all")
public Result<List<JCXX>> all(JCXX jcxx) {
return Result.success(teachingMaterialService.list(jcxx));
}
/**
* 导入Excel文件
*/
@PostMapping("/import")
public Result<Integer> importExcel(@RequestParam("file") MultipartFile file) {
int count = teachingMaterialService.importExcel(file);
return Result.success("导入成功", count);
}
/**
* 下载模板文件
*/
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) {
teachingMaterialService.downloadTemplate(response);
}
}
@@ -0,0 +1,110 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JXSSJH;
import com.roomroot.jwgl.service.TeachingPlanService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
/**
* 导入数据表-教学实施计划控制器
*/
@RestController
@RequestMapping("/teachingPlan")
public class TeachingPlanController {
@Resource
private TeachingPlanService teachingPlanService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JXSSJH jxssjh) {
teachingPlanService.add(jxssjh);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bsh") String bsh) {
teachingPlanService.delete(bsh);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JXSSJH drsjbjxssjh) {
teachingPlanService.update(drsjbjxssjh);
return Result.success();
}
/**
* 根据标识号查询
*/
@GetMapping("/get")
public Result<JXSSJH> getByBsh(@RequestParam("bsh") String bsh) {
return Result.success(teachingPlanService.getByBsh(bsh));
}
/**
* 分页查询列表
*/
@GetMapping("/list")
public Result<PageResult<JXSSJH>> list(PageQuery query, JXSSJH jxssjh) {
return Result.success(teachingPlanService.pageList(query, jxssjh));
}
/**
* 查询所有列表
*/
@GetMapping("/all")
public Result<List<JXSSJH>> all(JXSSJH jxssjh) {
return Result.success(teachingPlanService.list(jxssjh));
}
/**
* Excel导入教学实施计划。
* 标识号和登录编号自动生成,其他字段从Excel读取。
*/
@PostMapping("/import")
public Result<Integer> importFromExcel(@RequestParam("file") MultipartFile file) throws Exception {
int count = teachingPlanService.importFromExcel(file);
return Result.success("导入成功,共" + count + "条记录", count);
}
/**
* 下载教学实施计划导入模板
*/
@GetMapping("/template")
public ResponseEntity<org.springframework.core.io.Resource> downloadTemplate() throws IOException {
ClassPathResource resource = new ClassPathResource("template/教学实施计划导入模板.xlsx");
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
String fileName = URLEncoder.encode("教学实施计划导入模板.xlsx", "UTF-8");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
return ResponseEntity.ok()
.headers(headers)
.body(resource);
}
}
@@ -0,0 +1,81 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JCKCD;
import com.roomroot.jwgl.service.TeachingStockService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 教材库存单控制器
*/
@RestController
@RequestMapping("/teachingStock")
public class TeachingStockController {
@Resource
private TeachingStockService teachingStockService;
/**
* 新增教材库存单
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JCKCD jckcd) {
teachingStockService.add(jckcd);
return Result.success();
}
/**
* 删除教材库存单
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
teachingStockService.delete(id);
return Result.success();
}
/**
* 更新教材库存单
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JCKCD jckcd) {
teachingStockService.update(jckcd);
return Result.success();
}
/**
* 根据ID查询
*/
@GetMapping("/get")
public Result<JCKCD> getById(@RequestParam("id") String id) {
return Result.success(teachingStockService.getById(id));
}
/**
* 根据编号查询
*/
@GetMapping("/getByBh")
public Result<JCKCD> getByBh(@RequestParam("bh") String bh) {
return Result.success(teachingStockService.getByBh(bh));
}
/**
* 分页查询教材库存单列表
*/
@GetMapping("/list")
public Result<PageResult<JCKCD>> list(PageQuery query, JCKCD jckcd) {
return Result.success(teachingStockService.pageList(query, jckcd));
}
/**
* 查询所有教材库存单列表
*/
@GetMapping("/all")
public Result<List<JCKCD>> all(JCKCD jckcd) {
return Result.success(teachingStockService.list(jckcd));
}
}
@@ -0,0 +1,89 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JCKCMXX;
import com.roomroot.jwgl.service.TeachingStockDetailService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 教材库存明细项控制器
*/
@RestController
@RequestMapping("/teachingStock/detail")
public class TeachingStockDetailController {
@Resource
private TeachingStockDetailService teachingStockDetailService;
/**
* 新增教材库存明细项
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JCKCMXX jckcmxx) {
teachingStockDetailService.add(jckcmxx);
return Result.success();
}
/**
* 删除教材库存明细项
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("id") String id) {
teachingStockDetailService.delete(id);
return Result.success();
}
/**
* 更新教材库存明细项
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JCKCMXX jckcmxx) {
teachingStockDetailService.update(jckcmxx);
return Result.success();
}
/**
* 根据ID查询
*/
@GetMapping("/get")
public Result<JCKCMXX> getById(@RequestParam("id") String id) {
return Result.success(teachingStockDetailService.getById(id));
}
/**
* 根据编号查询
*/
@GetMapping("/getByBh")
public Result<JCKCMXX> getByBh(@RequestParam("bh") String bh) {
return Result.success(teachingStockDetailService.getByBh(bh));
}
/**
* 根据教材库存单编号查询
*/
@GetMapping("/getByJckcdbbh")
public Result<List<JCKCMXX>> getByJckcdbbh(@RequestParam("jckcdbbh") String jckcdbbh) {
return Result.success(teachingStockDetailService.getByJckcdbbh(jckcdbbh));
}
/**
* 分页查询教材库存明细项列表
*/
@GetMapping("/list")
public Result<PageResult<JCKCMXX>> list(PageQuery query, JCKCMXX jckcmxx) {
return Result.success(teachingStockDetailService.pageList(query, jckcmxx));
}
/**
* 查询所有教材库存明细项列表
*/
@GetMapping("/all")
public Result<List<JCKCMXX>> all(JCKCMXX jckcmxx) {
return Result.success(teachingStockDetailService.list(jckcmxx));
}
}
@@ -0,0 +1,95 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JXRW;
import com.roomroot.jwgl.service.TeachingTaskService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 教学任务控制器
*/
@RestController
@RequestMapping("/teachingTask")
public class TeachingTaskController {
@Resource
private TeachingTaskService teachingTaskService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody JXRW jxrw) {
teachingTaskService.add(jxrw);
return Result.success();
}
/**
* 删除
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
teachingTaskService.delete(bh);
return Result.success();
}
/**
* 批量删除
*/
@PostMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> bhList) {
teachingTaskService.batchDelete(bhList);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody JXRW jxrw) {
teachingTaskService.update(jxrw);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<JXRW> getByBh(@RequestParam("bh") String bh) {
return Result.success(teachingTaskService.getByBh(bh));
}
/**
* 分页查询列表
*/
@GetMapping("/list")
public Result<PageResult<JXRW>> list(PageQuery query, JXRW jxrw) {
return Result.success(teachingTaskService.pageList(query, jxrw));
}
/**
* 查询所有有效数据(DEL_FLAG = 0
*/
@GetMapping("/all")
public Result<List<JXRW>> all() {
return Result.success(teachingTaskService.listAllValid());
}
/**
* 发布教学任务及教研室任务书
* 根据教学任务编号修改状态为"发布",并批量更新所有关联的教研室任务书状态为"发布"
*
* @param bh 教学任务编号
* @return 更新数量
*/
@PostMapping("/batchPublish")
public Result<Integer> batchPublish(@RequestParam("bh") String bh) {
int count = teachingTaskService.batchPublish(bh);
return Result.success(count);
}
}
@@ -0,0 +1,118 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.ZYB;
import com.roomroot.jwgl.service.TrainingProgramService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
/**
* 培养方案管理控制器
* <p>
* 提供专业/培养方案的增加、删除(逻辑删除)、更新、查询等功能管理接口。
* 对应数据表:专业表
* 多版本通过培训类型(培训类型)字段区分。
* </p>
* <p>
* 接口规范:仅使用 GET 和 POST 两种方法,参数通过请求体或查询参数传递,不拼接在路径中。
* </p>
*/
@RestController
@RequestMapping("/training")
public class TrainingProgramController {
@Resource
private TrainingProgramService trainingProgramService;
/**
* 新增培养方案(专业)
*
* @param entity 专业表实体
* @return 操作结果
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody ZYB entity) {
trainingProgramService.add(entity);
return Result.success();
}
/**
* 停用(逻辑删除)培养方案
* <p>将指定记录的 停用 字段置为 true(停用=false为启用,停用=true为已停用/删除)。</p>
*
* @param zydh 专业代号
* @return 操作结果
*/
@PostMapping("/disable")
public Result<Void> disable(@RequestParam("zydh") String zydh) {
trainingProgramService.disable(zydh);
return Result.success();
}
/**
* 更新培养方案
*
* @param entity 专业表实体(含专业代号)
* @return 操作结果
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody ZYB entity) {
trainingProgramService.update(entity);
return Result.success();
}
/**
* 根据专业代号查询培养方案详情
*
* @param zydh 专业代号
* @return 培养方案详情
*/
@GetMapping("/get")
public Result<ZYB> getById(@RequestParam("zydh") String zydh) {
ZYB entity = trainingProgramService.getById(zydh);
return Result.success(entity);
}
/**
* 分页条件查询培养方案列表
* <p>
* 支持模糊查询参数:
* <ul>
* <li>zymc — 专业名称(模糊匹配)</li>
* <li>zydm — 专业代码(模糊匹配)</li>
* <li>pxlx — 培训类型(精确匹配,用于版本筛选)</li>
* <li>pxcc — 培训层次(精确匹配)</li>
* </ul>
* </p>
*
* @param pageNum 页码(默认1
* @param pageSize 每页条数(默认20
* @param zymc 专业名称(可选)
* @param zydm 专业代码(可选)
* @param pxlx 培训类型(可选)
* @param pxcc 培训层次(可选)
* @return 分页结果
*/
@GetMapping("/list")
public Result<PageResult<ZYB>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String zymc,
@RequestParam(required = false) String zydm,
@RequestParam(required = false) String pxlx,
@RequestParam(required = false) String pxcc) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
ZYB cond = new ZYB();
cond.setZymc(zymc);
cond.setZydm(zydm);
cond.setPxlx(pxlx);
cond.setPxcc(pxcc);
PageResult<ZYB> pageResult = trainingProgramService.pageList(query, cond);
return Result.success(pageResult);
}
}
@@ -0,0 +1,84 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.ZYJXJHB;
import com.roomroot.jwgl.service.ZYJXJHBService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 专业教学计划表控制器
*/
@RestController
@RequestMapping("/zyjxjhb")
public class ZYJXJHBController {
@Resource
private ZYJXJHBService zyjxjhbService;
/**
* 新增
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody ZYJXJHB zyjxjhb) {
zyjxjhbService.add(zyjxjhb);
return Result.success();
}
/**
* 删除(停用)
*/
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
zyjxjhbService.delete(bh);
return Result.success();
}
/**
* 批量删除(停用)
*/
@PostMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> bhList) {
zyjxjhbService.batchDelete(bhList);
return Result.success();
}
/**
* 更新
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody ZYJXJHB zyjxjhb) {
zyjxjhbService.update(zyjxjhb);
return Result.success();
}
/**
* 根据编号查询
*/
@GetMapping("/get")
public Result<ZYJXJHB> getByBh(@RequestParam("bh") String bh) {
return Result.success(zyjxjhbService.getByBh(bh));
}
/**
* 查询所有数据
*/
@GetMapping("/list")
public Result<List<ZYJXJHB>> list() {
return Result.success(zyjxjhbService.list());
}
/**
* 根据专业代号和停用标识查询
*
* @param zydh 专业代号
* @param ty 停用标识(0-正常,1-停用)
*/
@GetMapping("/listByZydhAndTy")
public Result<List<ZYJXJHB>> listByZydhAndTy(@RequestParam("zydh") String zydh,
@RequestParam("ty") Integer ty) {
return Result.success(zyjxjhbService.listByZydhAndTy(zydh, ty));
}
}
@@ -0,0 +1,122 @@
package com.roomroot.web.controller.monitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.constant.CacheConstants;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.system.domain.SysCache;
/**
* 缓存监控
*
* @author roomroot
*/
@RestController
@RequestMapping("/monitor/cache")
public class CacheController
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final static List<SysCache> caches = new ArrayList<SysCache>();
{
caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
}
@SuppressWarnings("deprecation")
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getNames")
public AjaxResult cache()
{
return AjaxResult.success(caches);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getKeys/{cacheName}")
public AjaxResult getCacheKeys(@PathVariable String cacheName)
{
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
return AjaxResult.success(new TreeSet<>(cacheKeys));
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping("/getValue/{cacheName}/{cacheKey}")
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
{
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
return AjaxResult.success(sysCache);
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheName/{cacheName}")
public AjaxResult clearCacheName(@PathVariable String cacheName)
{
Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheKey/{cacheKey}")
public AjaxResult clearCacheKey(@PathVariable String cacheKey)
{
redisTemplate.delete(cacheKey);
return AjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@DeleteMapping("/clearCacheAll")
public AjaxResult clearCacheAll()
{
Collection<String> cacheKeys = redisTemplate.keys("*");
redisTemplate.delete(cacheKeys);
return AjaxResult.success();
}
}
@@ -0,0 +1,27 @@
package com.roomroot.web.controller.monitor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.framework.web.domain.Server;
/**
* 服务器监控
*
* @author roomroot
*/
@RestController
@RequestMapping("/monitor/server")
public class ServerController
{
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Server server = new Server();
server.copyTo();
return AjaxResult.success(server);
}
}
@@ -0,0 +1,92 @@
package com.roomroot.web.controller.monitor;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Anonymous;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.framework.web.service.SysPasswordService;
import com.roomroot.system.domain.SysLogininfor;
import com.roomroot.system.service.ISysLogininforService;
/**
* 系统访问记录
*
* @author roomroot
*/
@RestController
@RequestMapping("/monitor/logininfor")
public class SysLogininforController extends BaseController
{
@Autowired
private ISysLogininforService logininforService;
@Autowired
private SysPasswordService passwordService;
@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
@GetMapping("/list")
public TableDataInfo list(SysLogininfor logininfor)
{
startPage();
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
return getDataTable(list);
}
@Anonymous
@GetMapping("/homeList")
public TableDataInfo homeList(SysLogininfor logininfor)
{
startPage();
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
return getDataTable(list);
}
@Log(title = "登录日志", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysLogininfor logininfor)
{
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
util.exportExcel(response, list, "登录日志");
}
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "登录日志", businessType = BusinessType.DELETE)
@DeleteMapping("/{infoIds}")
public AjaxResult remove(@PathVariable Long[] infoIds)
{
return toAjax(logininforService.deleteLogininforByIds(infoIds));
}
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "登录日志", businessType = BusinessType.CLEAN)
@DeleteMapping("/clean")
public AjaxResult clean()
{
logininforService.cleanLogininfor();
return success();
}
@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
@GetMapping("/unlock/{userName}")
public AjaxResult unlock(@PathVariable("userName") String userName)
{
passwordService.clearLoginRecordCache(userName);
return success();
}
}
@@ -0,0 +1,69 @@
package com.roomroot.web.controller.monitor;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.domain.SysOperLog;
import com.roomroot.system.service.ISysOperLogService;
/**
* 操作日志记录
*
* @author roomroot
*/
@RestController
@RequestMapping("/monitor/operlog")
public class SysOperlogController extends BaseController
{
@Autowired
private ISysOperLogService operLogService;
@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
@GetMapping("/list")
public TableDataInfo list(SysOperLog operLog)
{
startPage();
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
return getDataTable(list);
}
@Log(title = "操作日志", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysOperLog operLog)
{
List<SysOperLog> list = operLogService.selectOperLogList(operLog);
ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
util.exportExcel(response, list, "操作日志");
}
@Log(title = "操作日志", businessType = BusinessType.DELETE)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/{operIds}")
public AjaxResult remove(@PathVariable Long[] operIds)
{
return toAjax(operLogService.deleteOperLogByIds(operIds));
}
@Log(title = "操作日志", businessType = BusinessType.CLEAN)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/clean")
public AjaxResult clean()
{
operLogService.cleanOperLog();
return success();
}
}
@@ -0,0 +1,83 @@
package com.roomroot.web.controller.monitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.constant.CacheConstants;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.model.LoginUser;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.core.redis.RedisCache;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.system.domain.SysUserOnline;
import com.roomroot.system.service.ISysUserOnlineService;
/**
* 在线用户监控
*
* @author roomroot
*/
@RestController
@RequestMapping("/monitor/online")
public class SysUserOnlineController extends BaseController
{
@Autowired
private ISysUserOnlineService userOnlineService;
@Autowired
private RedisCache redisCache;
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
@GetMapping("/list")
public TableDataInfo list(String ipaddr, String userName)
{
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
for (String key : keys)
{
LoginUser user = redisCache.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
else if (StringUtils.isNotEmpty(ipaddr))
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
else
{
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
}
}
Collections.reverse(userOnlineList);
userOnlineList.removeAll(Collections.singleton(null));
return getDataTable(userOnlineList);
}
/**
* 强退用户
*/
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
@Log(title = "在线用户", businessType = BusinessType.FORCE)
@DeleteMapping("/{tokenId}")
public AjaxResult forceLogout(@PathVariable String tokenId)
{
redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
return success();
}
}
@@ -0,0 +1,133 @@
package com.roomroot.web.controller.system;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.domain.SysConfig;
import com.roomroot.system.service.ISysConfigService;
/**
* 参数配置 信息操作处理
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/config")
public class SysConfigController extends BaseController
{
@Autowired
private ISysConfigService configService;
/**
* 获取参数配置列表
*/
@PreAuthorize("@ss.hasPermi('system:config:list')")
@GetMapping("/list")
public TableDataInfo list(SysConfig config)
{
startPage();
List<SysConfig> list = configService.selectConfigList(config);
return getDataTable(list);
}
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:config:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysConfig config)
{
List<SysConfig> list = configService.selectConfigList(config);
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
util.exportExcel(response, list, "参数数据");
}
/**
* 根据参数编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:config:query')")
@GetMapping(value = "/{configId}")
public AjaxResult getInfo(@PathVariable Long configId)
{
return success(configService.selectConfigById(configId));
}
/**
* 根据参数键名查询参数值
*/
@GetMapping(value = "/configKey/{configKey}")
public AjaxResult getConfigKey(@PathVariable String configKey)
{
return success(configService.selectConfigByKey(configKey));
}
/**
* 新增参数配置
*/
@PreAuthorize("@ss.hasPermi('system:config:add')")
@Log(title = "参数管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysConfig config)
{
if (!configService.checkConfigKeyUnique(config))
{
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setCreateBy(getUsername());
return toAjax(configService.insertConfig(config));
}
/**
* 修改参数配置
*/
@PreAuthorize("@ss.hasPermi('system:config:edit')")
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config)
{
if (!configService.checkConfigKeyUnique(config))
{
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
config.setUpdateBy(getUsername());
return toAjax(configService.updateConfig(config));
}
/**
* 删除参数配置
*/
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{configIds}")
public AjaxResult remove(@PathVariable Long[] configIds)
{
configService.deleteConfigByIds(configIds);
return success();
}
/**
* 刷新参数缓存
*/
@PreAuthorize("@ss.hasPermi('system:config:remove')")
@Log(title = "参数管理", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult refreshCache()
{
configService.resetConfigCache();
return success();
}
}
@@ -0,0 +1,147 @@
package com.roomroot.web.controller.system;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.constant.UserConstants;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysDept;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.system.service.ISysDeptService;
/**
* 部门信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/dept")
public class SysDeptController extends BaseController
{
@Autowired
private ISysDeptService deptService;
/**
* 获取部门列表
*/
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list")
public AjaxResult list(SysDept dept)
{
List<SysDept> depts = deptService.selectDeptList(dept);
return success(depts);
}
/**
* 查询部门列表(排除节点)
*/
@PreAuthorize("@ss.hasPermi('system:dept:list')")
@GetMapping("/list/exclude/{deptId}")
public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
{
List<SysDept> depts = deptService.selectDeptList(new SysDept());
depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
return success(depts);
}
/**
* 根据部门编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:dept:query')")
@GetMapping(value = "/{deptId}")
public AjaxResult getInfo(@PathVariable Long deptId)
{
deptService.checkDeptDataScope(deptId);
return success(deptService.selectDeptById(deptId));
}
/**
* 新增部门
*/
@PreAuthorize("@ss.hasPermi('system:dept:add')")
@Log(title = "部门管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept)
{
if (!deptService.checkDeptNameUnique(dept))
{
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
dept.setCreateBy(getUsername());
return toAjax(deptService.insertDept(dept));
}
/**
* 修改部门
*/
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept)
{
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (!deptService.checkDeptNameUnique(dept))
{
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
else if (dept.getParentId().equals(deptId))
{
return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
}
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
{
return error("该部门包含未停用的子部门!");
}
dept.setUpdateBy(getUsername());
return toAjax(deptService.updateDept(dept));
}
/**
* 保存部门排序
*/
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
@Log(title = "保存部门排序", businessType = BusinessType.UPDATE)
@PutMapping("/updateSort")
public AjaxResult updateSort(@RequestBody Map<String, String> params)
{
String[] deptIds = params.get("deptIds").split(",");
String[] orderNums = params.get("orderNums").split(",");
deptService.updateDeptSort(deptIds, orderNums);
return success();
}
/**
* 删除部门
*/
@PreAuthorize("@ss.hasPermi('system:dept:remove')")
@Log(title = "部门管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{deptId}")
public AjaxResult remove(@PathVariable Long deptId)
{
if (deptService.hasChildByDeptId(deptId))
{
return warn("存在下级部门,不允许删除");
}
if (deptService.checkDeptExistUser(deptId))
{
return warn("部门存在用户,不允许删除");
}
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId));
}
}
@@ -0,0 +1,121 @@
package com.roomroot.web.controller.system;
import java.util.ArrayList;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysDictData;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.service.ISysDictDataService;
import com.roomroot.system.service.ISysDictTypeService;
/**
* 数据字典信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/dict/data")
public class SysDictDataController extends BaseController
{
@Autowired
private ISysDictDataService dictDataService;
@Autowired
private ISysDictTypeService dictTypeService;
@PreAuthorize("@ss.hasPermi('system:dict:list')")
@GetMapping("/list")
public TableDataInfo list(SysDictData dictData)
{
startPage();
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
return getDataTable(list);
}
@Log(title = "字典数据", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:dict:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysDictData dictData)
{
List<SysDictData> list = dictDataService.selectDictDataList(dictData);
ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
util.exportExcel(response, list, "字典数据");
}
/**
* 查询字典数据详细
*/
@PreAuthorize("@ss.hasPermi('system:dict:query')")
@GetMapping(value = "/{dictCode}")
public AjaxResult getInfo(@PathVariable Long dictCode)
{
return success(dictDataService.selectDictDataById(dictCode));
}
/**
* 根据字典类型查询字典数据信息
*/
@GetMapping(value = "/type/{dictType}")
public AjaxResult dictType(@PathVariable String dictType)
{
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
if (StringUtils.isNull(data))
{
data = new ArrayList<SysDictData>();
}
return success(data);
}
/**
* 新增字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:add')")
@Log(title = "字典数据", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDictData dict)
{
dict.setCreateBy(getUsername());
return toAjax(dictDataService.insertDictData(dict));
}
/**
* 修改保存字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
@Log(title = "字典数据", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictData dict)
{
dict.setUpdateBy(getUsername());
return toAjax(dictDataService.updateDictData(dict));
}
/**
* 删除字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{dictCodes}")
public AjaxResult remove(@PathVariable Long[] dictCodes)
{
dictDataService.deleteDictDataByIds(dictCodes);
return success();
}
}
@@ -0,0 +1,131 @@
package com.roomroot.web.controller.system;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysDictType;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.service.ISysDictTypeService;
/**
* 数据字典信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/dict/type")
public class SysDictTypeController extends BaseController
{
@Autowired
private ISysDictTypeService dictTypeService;
@PreAuthorize("@ss.hasPermi('system:dict:list')")
@GetMapping("/list")
public TableDataInfo list(SysDictType dictType)
{
startPage();
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
return getDataTable(list);
}
@Log(title = "字典类型", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:dict:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysDictType dictType)
{
List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
util.exportExcel(response, list, "字典类型");
}
/**
* 查询字典类型详细
*/
@PreAuthorize("@ss.hasPermi('system:dict:query')")
@GetMapping(value = "/{dictId}")
public AjaxResult getInfo(@PathVariable Long dictId)
{
return success(dictTypeService.selectDictTypeById(dictId));
}
/**
* 新增字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:add')")
@Log(title = "字典类型", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDictType dict)
{
if (!dictTypeService.checkDictTypeUnique(dict))
{
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setCreateBy(getUsername());
return toAjax(dictTypeService.insertDictType(dict));
}
/**
* 修改字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:edit')")
@Log(title = "字典类型", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictType dict)
{
if (!dictTypeService.checkDictTypeUnique(dict))
{
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
dict.setUpdateBy(getUsername());
return toAjax(dictTypeService.updateDictType(dict));
}
/**
* 删除字典类型
*/
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.DELETE)
@DeleteMapping("/{dictIds}")
public AjaxResult remove(@PathVariable Long[] dictIds)
{
dictTypeService.deleteDictTypeByIds(dictIds);
return success();
}
/**
* 刷新字典缓存
*/
@PreAuthorize("@ss.hasPermi('system:dict:remove')")
@Log(title = "字典类型", businessType = BusinessType.CLEAN)
@DeleteMapping("/refreshCache")
public AjaxResult refreshCache()
{
dictTypeService.resetDictCache();
return success();
}
/**
* 获取字典选择框列表
*/
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
return success(dictTypes);
}
}
@@ -0,0 +1,64 @@
package com.roomroot.web.controller.system;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.config.RoomRootConfig;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.system.service.ISysUserService;
/**
* 首页
*
* @author roomroot
*/
@RestController
public class SysIndexController
{
/** 系统基础配置 */
@Autowired
private RoomRootConfig RoomRootConfig;
@Autowired
private ISysUserService userService;
/**
* 访问首页,提示语
*/
@RequestMapping("/")
public String index()
{
return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", RoomRootConfig.getName(), RoomRootConfig.getVersion());
}
/**
* 解锁屏幕
*/
@PostMapping("/unlockscreen")
public AjaxResult unlockScreen(@RequestBody Map<String, String> body)
{
String password = body.get("password");
if (StringUtils.isEmpty(password))
{
return AjaxResult.error("密码不能为空");
}
String username = SecurityUtils.getUsername();
SysUser user = userService.selectUserByUserName(username);
if (user == null)
{
return AjaxResult.error("服务器超时,请重新登录");
}
if (!SecurityUtils.matchesPassword(password, user.getPassword()))
{
return AjaxResult.error("密码错误,请重新输入");
}
return AjaxResult.success("解锁成功");
}
}
@@ -0,0 +1,138 @@
package com.roomroot.web.controller.system;
import java.util.Date;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.constant.Constants;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysMenu;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.core.domain.model.LoginBody;
import com.roomroot.common.core.domain.model.LoginUser;
import com.roomroot.common.core.text.Convert;
import com.roomroot.common.utils.DateUtils;
import com.roomroot.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.framework.web.service.SysLoginService;
import com.roomroot.framework.web.service.SysPermissionService;
import com.roomroot.framework.web.service.TokenService;
import com.roomroot.system.service.ISysConfigService;
import com.roomroot.system.service.ISysMenuService;
/**
* 登录验证
*
* @author roomroot
*/
@RestController
public class SysLoginController
{
@Autowired
private SysLoginService loginService;
@Autowired
private ISysMenuService menuService;
@Autowired
private SysPermissionService permissionService;
@Autowired
private TokenService tokenService;
@Autowired
private ISysConfigService configService;
/**
* 登录方法
*
* @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
ajax.put(Constants.TOKEN, token);
return ajax;
}
/**
* 获取用户信息
*
* @return 用户信息
*/
@GetMapping("getInfo")
public AjaxResult getInfo()
{
LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser user = loginUser.getUser();
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
AjaxResult ajax = AjaxResult.success();
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("pwdChrtype", getSysAccountChrtype());
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
return ajax;
}
/**
* 获取路由信息
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));
}
// 获取用户密码自定义配置规则
public String getSysAccountChrtype()
{
return Convert.toStr(configService.selectConfigByKey("sys.account.chrtype"), "0");
}
// 检查初始密码是否提醒修改
public boolean initPasswordIsModify(Date pwdUpdateDate)
{
Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
}
// 检查密码是否过期
public boolean passwordIsExpiration(Date pwdUpdateDate)
{
Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
if (passwordValidateDays != null && passwordValidateDays > 0)
{
if (StringUtils.isNull(pwdUpdateDate))
{
// 如果从未修改过初始密码,直接提醒过期
return true;
}
Date nowDate = DateUtils.getNowDate();
return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
}
return false;
}
}
@@ -0,0 +1,165 @@
package com.roomroot.web.controller.system;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.constant.UserConstants;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysMenu;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.system.service.ISysMenuService;
/**
* 菜单信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/menu")
public class SysMenuController extends BaseController
{
@Autowired
private ISysMenuService menuService;
/**
* 获取菜单列表
*/
@PreAuthorize("@ss.hasPermi('system:menu:list')")
@GetMapping("/list")
public AjaxResult list(SysMenu menu)
{
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menus);
}
/**
* 根据菜单编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping(value = "/{menuId}")
public AjaxResult getInfo(@PathVariable Long menuId)
{
return success(menuService.selectMenuById(menuId));
}
/**
* 获取菜单下拉树列表
*/
@GetMapping("/treeselect")
public AjaxResult treeselect(SysMenu menu)
{
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menuService.buildMenuTreeSelect(menus));
}
/**
* 加载对应角色菜单列表树
*/
@GetMapping(value = "/roleMenuTreeselect/{roleId}")
public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
{
List<SysMenu> menus = menuService.selectMenuList(getUserId());
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
ajax.put("menus", menuService.buildMenuTreeSelect(menus));
return ajax;
}
/**
* 新增菜单
*/
@PreAuthorize("@ss.hasPermi('system:menu:add')")
@Log(title = "菜单管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu)
{
if (!menuService.checkMenuNameUnique(menu))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
}
else if (!menuService.checkRouteConfigUnique(menu))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
menu.setCreateBy(getUsername());
return toAjax(menuService.insertMenu(menu));
}
/**
* 修改菜单
*/
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@Log(title = "菜单管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu)
{
if (!menuService.checkMenuNameUnique(menu))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
}
else if (menu.getMenuId().equals(menu.getParentId()))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
}
else if (!menuService.checkRouteConfigUnique(menu))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
menu.setUpdateBy(getUsername());
return toAjax(menuService.updateMenu(menu));
}
/**
* 保存菜单排序
*/
@PreAuthorize("@ss.hasPermi('system:menu:edit')")
@Log(title = "保存菜单排序", businessType = BusinessType.UPDATE)
@PutMapping("/updateSort")
public AjaxResult updateSort(@RequestBody Map<String, String> params)
{
String[] menuIds = params.get("menuIds").split(",");
String[] orderNums = params.get("orderNums").split(",");
menuService.updateMenuSort(menuIds, orderNums);
return success();
}
/**
* 删除菜单
*/
@PreAuthorize("@ss.hasPermi('system:menu:remove')")
@Log(title = "菜单管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{menuId}")
public AjaxResult remove(@PathVariable("menuId") Long menuId)
{
if (menuService.hasChildByMenuId(menuId))
{
return warn("存在子菜单,不允许删除");
}
if (menuService.checkMenuExistRole(menuId))
{
return warn("菜单已分配,不允许删除");
}
return toAjax(menuService.deleteMenuById(menuId));
}
}
@@ -0,0 +1,150 @@
package com.roomroot.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.core.text.Convert;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.system.domain.SysNotice;
import com.roomroot.system.service.ISysNoticeReadService;
import com.roomroot.system.service.ISysNoticeService;
/**
* 公告 信息操作处理
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/notice")
public class SysNoticeController extends BaseController
{
@Autowired
private ISysNoticeService noticeService;
@Autowired
private ISysNoticeReadService noticeReadService;
/**
* 获取通知公告列表
*/
@PreAuthorize("@ss.hasPermi('system:notice:list')")
@GetMapping("/list")
public TableDataInfo list(SysNotice notice)
{
startPage();
List<SysNotice> list = noticeService.selectNoticeList(notice);
return getDataTable(list);
}
/**
* 根据通知公告编号获取详细信息
*/
@GetMapping(value = "/{noticeId}")
public AjaxResult getInfo(@PathVariable Long noticeId)
{
return success(noticeService.selectNoticeById(noticeId));
}
/**
* 新增通知公告
*/
@PreAuthorize("@ss.hasPermi('system:notice:add')")
@Log(title = "通知公告", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysNotice notice)
{
notice.setCreateBy(getUsername());
return toAjax(noticeService.insertNotice(notice));
}
/**
* 修改通知公告
*/
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
@Log(title = "通知公告", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysNotice notice)
{
notice.setUpdateBy(getUsername());
return toAjax(noticeService.updateNotice(notice));
}
/**
* 首页顶部公告列表(返回全部正常公告,带当前用户已读标记,最多5条)
*/
@GetMapping("/listTop")
@ResponseBody
public AjaxResult listTop()
{
Long userId = getUserId();
List<SysNotice> list = noticeReadService.selectNoticeListWithReadStatus(userId, 5);
long unreadCount = list.stream().filter(n -> !n.getIsRead()).count();
AjaxResult result = AjaxResult.success(list);
result.put("unreadCount", unreadCount);
return result;
}
/**
* 标记公告已读
*/
@PostMapping("/markRead")
@ResponseBody
public AjaxResult markRead(Long noticeId)
{
Long userId = getUserId();
noticeReadService.markRead(noticeId, userId);
return success();
}
/**
* 批量标记已读
*/
@PostMapping("/markReadAll")
@ResponseBody
public AjaxResult markReadAll(String ids)
{
Long userId = getUserId();
Long[] noticeIds = Convert.toLongArray(ids);
noticeReadService.markReadBatch(userId, noticeIds);
return success();
}
/**
* 已读用户列表数据
*/
@PreAuthorize("@ss.hasPermi('system:notice:list')")
@GetMapping("/readUsers/list")
@ResponseBody
public TableDataInfo readUsersList(Long noticeId, String searchValue)
{
startPage();
List<?> list = noticeReadService.selectReadUsersByNoticeId(noticeId, searchValue);
return getDataTable(list);
}
/**
* 删除通知公告
*/
@PreAuthorize("@ss.hasPermi('system:notice:remove')")
@Log(title = "通知公告", businessType = BusinessType.DELETE)
@DeleteMapping("/{noticeIds}")
public AjaxResult remove(@PathVariable Long[] noticeIds)
{
noticeReadService.deleteByNoticeIds(noticeIds);
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
}
}
@@ -0,0 +1,129 @@
package com.roomroot.web.controller.system;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.domain.SysPost;
import com.roomroot.system.service.ISysPostService;
/**
* 岗位信息操作处理
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/post")
public class SysPostController extends BaseController
{
@Autowired
private ISysPostService postService;
/**
* 获取岗位列表
*/
@PreAuthorize("@ss.hasPermi('system:post:list')")
@GetMapping("/list")
public TableDataInfo list(SysPost post)
{
startPage();
List<SysPost> list = postService.selectPostList(post);
return getDataTable(list);
}
@Log(title = "岗位管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:post:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysPost post)
{
List<SysPost> list = postService.selectPostList(post);
ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
util.exportExcel(response, list, "岗位数据");
}
/**
* 根据岗位编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:post:query')")
@GetMapping(value = "/{postId}")
public AjaxResult getInfo(@PathVariable Long postId)
{
return success(postService.selectPostById(postId));
}
/**
* 新增岗位
*/
@PreAuthorize("@ss.hasPermi('system:post:add')")
@Log(title = "岗位管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysPost post)
{
if (!postService.checkPostNameUnique(post))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (!postService.checkPostCodeUnique(post))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setCreateBy(getUsername());
return toAjax(postService.insertPost(post));
}
/**
* 修改岗位
*/
@PreAuthorize("@ss.hasPermi('system:post:edit')")
@Log(title = "岗位管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post)
{
if (!postService.checkPostNameUnique(post))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (!postService.checkPostCodeUnique(post))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
post.setUpdateBy(getUsername());
return toAjax(postService.updatePost(post));
}
/**
* 删除岗位
*/
@PreAuthorize("@ss.hasPermi('system:post:remove')")
@Log(title = "岗位管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{postIds}")
public AjaxResult remove(@PathVariable Long[] postIds)
{
return toAjax(postService.deletePostByIds(postIds));
}
/**
* 获取岗位选择框列表
*/
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
List<SysPost> posts = postService.selectPostAll();
return success(posts);
}
}
@@ -0,0 +1,156 @@
package com.roomroot.web.controller.system;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.config.RoomRootConfig;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.core.domain.model.LoginUser;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.DateUtils;
import com.roomroot.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.file.FileUploadUtils;
import com.roomroot.common.utils.file.FileUtils;
import com.roomroot.common.utils.file.MimeTypeUtils;
import com.roomroot.framework.web.service.TokenService;
import com.roomroot.system.service.ISysUserService;
import com.roomroot.system.service.ISysLogininforService;
/**
* 个人信息 业务处理
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/user/profile")
public class SysProfileController extends BaseController
{
@Autowired
private ISysUserService userService;
@Autowired
private TokenService tokenService;
@Autowired
private ISysLogininforService logininforService;
/**
* 个人信息
*/
@GetMapping
public AjaxResult profile()
{
LoginUser loginUser = getLoginUser();
SysUser user = loginUser.getUser();
AjaxResult ajax = AjaxResult.success(user);
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
// 查询登录统计信息
Map<String, Object> loginStats = logininforService.selectLoginStatsByUserName(loginUser.getUsername());
ajax.put("loginStats", loginStats);
return ajax;
}
/**
* 修改用户
*/
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult updateProfile(@RequestBody SysUser user)
{
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
currentUser.setNickName(user.getNickName());
currentUser.setEmail(user.getEmail());
currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
{
return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
{
return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
}
if (userService.updateUserProfile(currentUser) > 0)
{
// 更新缓存用户信息
tokenService.setLoginUser(loginUser);
return success();
}
return error("修改个人信息异常,请联系管理员");
}
/**
* 重置密码
*/
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd")
public AjaxResult updatePwd(@RequestBody Map<String, String> params)
{
String oldPassword = params.get("oldPassword");
String newPassword = params.get("newPassword");
LoginUser loginUser = getLoginUser();
Long userId = loginUser.getUserId();
SysUser user = userService.selectUserById(userId);
String password = user.getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password))
{
return error("修改密码失败,旧密码错误");
}
if (SecurityUtils.matchesPassword(newPassword, password))
{
return error("新密码不能与旧密码相同");
}
newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userId, newPassword) > 0)
{
// 更新缓存用户密码&密码最后更新时间
loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
loginUser.getUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser);
return success();
}
return error("修改密码异常,请联系管理员");
}
/**
* 头像上传
*/
@Log(title = "用户头像", businessType = BusinessType.UPDATE)
@PostMapping("/avatar")
public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
{
if (!file.isEmpty())
{
LoginUser loginUser = getLoginUser();
String avatar = FileUploadUtils.upload(RoomRootConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true);
if (userService.updateUserAvatar(loginUser.getUserId(), avatar))
{
String oldAvatar = loginUser.getUser().getAvatar();
if (StringUtils.isNotEmpty(oldAvatar))
{
FileUtils.deleteFile(RoomRootConfig.getProfile() + FileUtils.stripPrefix(oldAvatar));
}
AjaxResult ajax = AjaxResult.success();
ajax.put("imgUrl", avatar);
// 更新缓存用户头像
loginUser.getUser().setAvatar(avatar);
tokenService.setLoginUser(loginUser);
return ajax;
}
}
return error("上传图片异常,请联系管理员");
}
}
@@ -0,0 +1,38 @@
package com.roomroot.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.model.RegisterBody;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.framework.web.service.SysRegisterService;
import com.roomroot.system.service.ISysConfigService;
/**
* 注册验证
*
* @author roomroot
*/
@RestController
public class SysRegisterController extends BaseController
{
@Autowired
private SysRegisterService registerService;
@Autowired
private ISysConfigService configService;
@PostMapping("/register")
public AjaxResult register(@RequestBody RegisterBody user)
{
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
{
return error("当前系统没有开启注册功能!");
}
String msg = registerService.register(user);
return StringUtils.isEmpty(msg) ? success() : error(msg);
}
}
@@ -0,0 +1,254 @@
package com.roomroot.web.controller.system;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysDept;
import com.roomroot.common.core.domain.entity.SysRole;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.framework.web.service.SysPermissionService;
import com.roomroot.framework.web.service.TokenService;
import com.roomroot.system.domain.SysUserRole;
import com.roomroot.system.service.ISysDeptService;
import com.roomroot.system.service.ISysRoleService;
import com.roomroot.system.service.ISysUserService;
/**
* 角色信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/role")
public class SysRoleController extends BaseController
{
@Autowired
private ISysRoleService roleService;
@Autowired
private TokenService tokenService;
@Autowired
private SysPermissionService permissionService;
@Autowired
private ISysUserService userService;
@Autowired
private ISysDeptService deptService;
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/list")
public TableDataInfo list(SysRole role)
{
startPage();
List<SysRole> list = roleService.selectRoleList(role);
return getDataTable(list);
}
@Log(title = "角色管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:role:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysRole role)
{
List<SysRole> list = roleService.selectRoleList(role);
ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
util.exportExcel(response, list, "角色数据");
}
/**
* 根据角色编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/{roleId}")
public AjaxResult getInfo(@PathVariable Long roleId)
{
roleService.checkRoleDataScope(roleId);
return success(roleService.selectRoleById(roleId));
}
/**
* 新增角色
*/
@PreAuthorize("@ss.hasPermi('system:role:add')")
@Log(title = "角色管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysRole role)
{
if (!roleService.checkRoleNameUnique(role))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (!roleService.checkRoleKeyUnique(role))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setCreateBy(getUsername());
return toAjax(roleService.insertRole(role));
}
/**
* 修改保存角色
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
if (!roleService.checkRoleNameUnique(role))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (!roleService.checkRoleKeyUnique(role))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
role.setUpdateBy(getUsername());
if (roleService.updateRole(role) > 0)
{
// 刷新所有持有该角色的在线用户权限
tokenService.refreshPermissionByRoleId(role.getRoleId(), permissionService);
return success();
}
return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
}
/**
* 修改保存数据权限
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/dataScope")
public AjaxResult dataScope(@RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
return toAjax(roleService.authDataScope(role));
}
/**
* 状态修改
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody SysRole role)
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
role.setUpdateBy(getUsername());
return toAjax(roleService.updateRoleStatus(role));
}
/**
* 删除角色
*/
@PreAuthorize("@ss.hasPermi('system:role:remove')")
@Log(title = "角色管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{roleIds}")
public AjaxResult remove(@PathVariable Long[] roleIds)
{
return toAjax(roleService.deleteRoleByIds(roleIds));
}
/**
* 获取角色选择框列表
*/
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping("/optionselect")
public AjaxResult optionselect()
{
return success(roleService.selectRoleAll());
}
/**
* 查询已分配用户角色列表
*/
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/allocatedList")
public TableDataInfo allocatedList(SysUser user)
{
startPage();
List<SysUser> list = userService.selectAllocatedList(user);
return getDataTable(list);
}
/**
* 查询未分配用户角色列表
*/
@PreAuthorize("@ss.hasPermi('system:role:list')")
@GetMapping("/authUser/unallocatedList")
public TableDataInfo unallocatedList(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUnallocatedList(user);
return getDataTable(list);
}
/**
* 取消授权用户
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancel")
public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
{
return toAjax(roleService.deleteAuthUser(userRole));
}
/**
* 批量取消授权用户
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/cancelAll")
public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
{
return toAjax(roleService.deleteAuthUsers(roleId, userIds));
}
/**
* 批量选择用户授权
*/
@PreAuthorize("@ss.hasPermi('system:role:edit')")
@Log(title = "角色管理", businessType = BusinessType.GRANT)
@PutMapping("/authUser/selectAll")
public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
{
roleService.checkRoleDataScope(roleId);
return toAjax(roleService.insertAuthUsers(roleId, userIds));
}
/**
* 获取对应角色部门树列表
*/
@PreAuthorize("@ss.hasPermi('system:role:query')")
@GetMapping(value = "/deptTree/{roleId}")
public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
{
AjaxResult ajax = AjaxResult.success();
ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
return ajax;
}
}
@@ -0,0 +1,256 @@
package com.roomroot.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.roomroot.common.annotation.Log;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.entity.SysDept;
import com.roomroot.common.core.domain.entity.SysRole;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.poi.ExcelUtil;
import com.roomroot.system.service.ISysDeptService;
import com.roomroot.system.service.ISysPostService;
import com.roomroot.system.service.ISysRoleService;
import com.roomroot.system.service.ISysUserService;
/**
* 用户信息
*
* @author roomroot
*/
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController
{
@Autowired
private ISysUserService userService;
@Autowired
private ISysRoleService roleService;
@Autowired
private ISysDeptService deptService;
@Autowired
private ISysPostService postService;
/**
* 获取用户列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user)
{
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
@Log(title = "用户管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:user:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysUser user)
{
List<SysUser> list = userService.selectUserList(user);
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
util.exportExcel(response, list, "用户数据");
}
@Log(title = "用户管理", businessType = BusinessType.IMPORT)
@PreAuthorize("@ss.hasPermi('system:user:import')")
@PostMapping("/importData")
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
List<SysUser> userList = util.importExcel(file.getInputStream());
String operName = getUsername();
String message = userService.importUser(userList, updateSupport, operName);
return success(message);
}
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response)
{
ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
util.importTemplateExcel(response, "用户数据");
}
/**
* 根据用户编号获取详细信息
*/
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{
AjaxResult ajax = AjaxResult.success();
if (StringUtils.isNotNull(userId))
{
userService.checkUserDataScope(userId);
SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
}
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
return ajax;
}
/**
* 新增用户
*/
@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user)
{
deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setCreateBy(getUsername());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
return toAjax(userService.insertUser(user));
}
/**
* 修改用户
*/
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
deptService.checkDeptDataScope(user.getDeptId());
roleService.checkRoleDataScope(user.getRoleIds());
if (!userService.checkUserNameUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
user.setUpdateBy(getUsername());
return toAjax(userService.updateUser(user));
}
/**
* 删除用户
*/
@PreAuthorize("@ss.hasPermi('system:user:remove')")
@Log(title = "用户管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{userIds}")
public AjaxResult remove(@PathVariable Long[] userIds)
{
if (ArrayUtils.contains(userIds, getUserId()))
{
return error("当前用户不能删除");
}
return toAjax(userService.deleteUserByIds(userIds));
}
/**
* 重置密码
*/
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd")
public AjaxResult resetPwd(@RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
user.setUpdateBy(getUsername());
return toAjax(userService.resetPwd(user));
}
/**
* 状态修改
*/
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")
public AjaxResult changeStatus(@RequestBody SysUser user)
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
user.setUpdateBy(getUsername());
return toAjax(userService.updateUserStatus(user));
}
/**
* 根据用户编号获取授权角色
*/
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping("/authRole/{userId}")
public AjaxResult authRole(@PathVariable("userId") Long userId)
{
AjaxResult ajax = AjaxResult.success();
SysUser user = userService.selectUserById(userId);
List<SysRole> roles = roleService.selectRolesByUserId(userId);
ajax.put("user", user);
ajax.put("roles", SecurityUtils.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
return ajax;
}
/**
* 用户授权角色
*/
@PreAuthorize("@ss.hasPermi('system:user:edit')")
@Log(title = "用户管理", businessType = BusinessType.GRANT)
@PutMapping("/authRole")
public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
{
userService.checkUserDataScope(userId);
roleService.checkRoleDataScope(roleIds);
userService.insertUserAuth(userId, roleIds);
return success();
}
/**
* 获取部门树列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/deptTree")
public AjaxResult deptTree(SysDept dept)
{
return success(deptService.selectDeptTreeList(dept));
}
}
@@ -0,0 +1,175 @@
package com.roomroot.web.controller.tool;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.roomroot.common.core.controller.BaseController;
import com.roomroot.common.core.domain.R;
import com.roomroot.common.utils.StringUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* swagger 用户测试方法
*
* @author roomroot
*/
@Tag(name = "用户信息管理")
@RestController
@RequestMapping("/test/user")
public class TestController extends BaseController
{
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
{
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
}
@Operation(summary = "获取用户列表")
@GetMapping("/list")
public R<List<UserEntity>> userList()
{
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return R.ok(userList);
}
@Operation(summary = "获取用户详细")
@GetMapping("/{userId}")
public R<UserEntity> getUser(@PathVariable(name = "userId")
Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
return R.ok(users.get(userId));
}
else
{
return R.fail("用户不存在");
}
}
@Operation(summary = "新增用户")
@PostMapping("/save")
public R<String> save(UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
users.put(user.getUserId(), user);
return R.ok();
}
@Operation(summary = "更新用户")
@PutMapping("/update")
public R<String> update(@RequestBody
UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
if (users.isEmpty() || !users.containsKey(user.getUserId()))
{
return R.fail("用户不存在");
}
users.remove(user.getUserId());
users.put(user.getUserId(), user);
return R.ok();
}
@Operation(summary = "删除用户信息")
@DeleteMapping("/{userId}")
public R<String> delete(@PathVariable(name = "userId")
Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
users.remove(userId);
return R.ok();
}
else
{
return R.fail("用户不存在");
}
}
}
@Schema(description = "用户实体")
class UserEntity
{
@Schema(title = "用户ID")
private Integer userId;
@Schema(title = "用户名称")
private String username;
@Schema(title = "用户密码")
private String password;
@Schema(title = "用户手机")
private String mobile;
public UserEntity()
{
}
public UserEntity(Integer userId, String username, String password, String mobile)
{
this.userId = userId;
this.username = username;
this.password = password;
this.mobile = mobile;
}
public Integer getUserId()
{
return userId;
}
public void setUserId(Integer userId)
{
this.userId = userId;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getMobile()
{
return mobile;
}
public void setMobile(String mobile)
{
this.mobile = mobile;
}
}
@@ -0,0 +1,14 @@
package com.roomroot.web.core.config;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class EmbeddedRedisCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 读取yml开关,true才启用内嵌Redis
String enable = context.getEnvironment().getProperty("custom.embedded-redis.enable", "false");
return Boolean.parseBoolean(enable);
}
}
@@ -0,0 +1,64 @@
package com.roomroot.web.core.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.roomroot.common.config.RoomRootConfig;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
/**
* Swagger2的接口配置
*
* @author roomroot
*/
@Configuration
public class SwaggerConfig
{
/** 系统基础配置 */
@Autowired
private RoomRootConfig RoomRootConfig;
/**
* 自定义的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenApi()
{
return new OpenAPI().components(new Components()
// 设置认证的请求头
.addSecuritySchemes("apikey", securityScheme()))
.addSecurityItem(new SecurityRequirement().addList("apikey"))
.info(getApiInfo());
}
@Bean
public SecurityScheme securityScheme()
{
return new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.name("Authorization")
.in(SecurityScheme.In.HEADER)
.scheme("Bearer");
}
/**
* 添加摘要信息
*/
public Info getApiInfo()
{
return new Info()
// 设置标题
.title("标题:风影随行管理系统_接口文档")
// 描述
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
// 作者信息
.contact(new Contact().name(RoomRootConfig.getName()))
// 版本
.version("版本号:" + RoomRootConfig.getVersion());
}
}
@@ -0,0 +1 @@
restart.include.json=/com.alibaba.fastjson2.*.jar
@@ -0,0 +1,56 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 达梦连接串:ip:端口,schema指定默认模式
url: jdbc:dm://192.168.1.27:5236?schema=JIAOWU&useUnicode=true&characterEncoding=utf-8
username: JIAOWU
password: Jiaowu123
driver-class-name: dm.jdbc.driver.DmDriver
# Druid 基础参数
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: roomroot
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
db-type: dm
@@ -0,0 +1,149 @@
# 项目相关配置
roomroot:
# 名称
name: roomroot
# 版本
version: 3.9.2
# 版权年份
copyrightYear: 2026
# 文件路径 示例( Windows配置D:/roomroot/uploadPathLinux配置 /home/roomroot/uploadPath
profile: D:/roomroot/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /api
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 1000
threads:
# tomcat最大线程数,默认为200
max: 800
# Tomcat启动初始化的线程数,默认值10
min-spare: 100
# 日志配置
logging:
level:
com.roomroot: debug
#org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
data:
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 30
# MyBatis-Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.roomroot.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# Springdoc配置
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui.html
tags-sorter: alpha
group-configs:
- group: 'default'
display-name: '测试模块'
paths-to-match: '/**'
packages-to-scan: com.roomroot.web.controller.tool
# 防盗链配置
referer:
# 防盗链开关
enabled: false
# 允许的域名列表
allowed-domains: localhost,127.0.0.1,roomroot.vip,www.roomroot.vip
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 自定义内嵌Redis开关
custom:
embedded-redis:
# dev环境true自动启动内嵌Redisprod改为false使用外部Redis
enable: false
port: 6379
max-memory: 128M
@@ -0,0 +1,5 @@
Application Version: ${roomroot.version}
Spring Boot Version: ${spring-boot.version}
////////////////////////////////////////////////////////////////////
// 启动开始 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////
@@ -0,0 +1,38 @@
#错误消息
not.null=* 必须填写
user.jcaptcha.error=验证码错误
user.jcaptcha.expire=验证码已失效
user.not.exists=用户不存在/密码错误
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
login.blocked=很遗憾,访问IP已被列入系统黑名单
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
user.password.not.valid=* 5-50个字符
user.email.not.valid=邮箱格式错误
user.mobile.phone.number.not.valid=手机号格式错误
user.login.success=登录成功
user.register.success=注册成功
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
##权限
no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/roomroot/logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.roomroot" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="info">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局参数 -->
<settings>
<!-- 使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 允许JDBC 支持自动生成主键 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="SLF4J" />
<!-- 使用驼峰命名法转换字段 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
</settings>
</configuration>
+129
View File
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>roomroot</artifactId>
<groupId>com.roomroot</groupId>
<version>3.9.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>roomroot-common</artifactId>
<description>
common通用工具
</description>
<dependencies>
<!-- Spring框架基本的核心工具 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- SpringWeb模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- spring security 安全认证 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- MyBatis-Plus ORM框架 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- JSON工具类 -->
<dependency>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- Jaxb -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<!-- redis 缓存操作 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- pool 对象池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- MyBatis-Plus ORM框架 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>nl.basjes.parse.useragent</groupId>
<artifactId>yauaa</artifactId>
</dependency>
<!-- servlet包 -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
</component>
</module>
@@ -0,0 +1,19 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 匿名访问不鉴权注解
*
* @author roomroot
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Anonymous
{
}
@@ -0,0 +1,43 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据权限过滤注解
*
* @author roomroot
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{
/**
* 用户表的别名
*/
public String userAlias() default "";
/**
* 部门表的别名
*/
public String deptAlias() default "";
/**
* 用户字段名
*/
public String userField() default "user_id";
/**
* 部门字段名
*/
public String deptField() default "dept_id";
/**
* 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
*/
public String permission() default "";
}
@@ -0,0 +1,28 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.roomroot.common.enums.DataSourceType;
/**
* 自定义多数据源切换注解
*
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
*
* @author roomroot
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{
/**
* 切换数据源名称
*/
public DataSourceType value() default DataSourceType.MASTER;
}
@@ -0,0 +1,198 @@
package com.roomroot.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.roomroot.common.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出Excel数据注解
*
* @author roomroot
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
/**
* 导出时在excel中排序
*/
public int sort() default Integer.MAX_VALUE;
/**
* 导出到Excel中的名字.
*/
public String name() default "";
/**
* 日期格式, 如: yyyy-MM-dd
*/
public String dateFormat() default "";
/**
* 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
*/
public String dictType() default "";
/**
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
*/
public String readConverterExp() default "";
/**
* 分隔符,读取字符串组内容
*/
public String separator() default ",";
/**
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
*/
public int scale() default -1;
/**
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
*/
@SuppressWarnings("deprecation")
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出时在excel中每个列的高度
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽度
*/
public double width() default 16;
/**
* 文字后缀,如% 90 变成90%
*/
public String suffix() default "";
/**
* 当值为空时,字段的默认值
*/
public String defaultValue() default "";
/**
* 提示信息
*/
public String prompt() default "";
/**
* 是否允许内容换行
*/
public boolean wrapText() default false;
/**
* 设置只能选择不能输入的列内容.
*/
public String[] combo() default {};
/**
* 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
*/
public boolean comboReadDict() default false;
/**
* 是否需要纵向合并单元格,应对需求:含有list集合单元格)
*/
public boolean needMerge() default false;
/**
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
*/
public boolean isExport() default true;
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
public String targetAttr() default "";
/**
* 是否自动统计数据,在最后追加一行统计数据总和
*/
public boolean isStatistics() default false;
/**
* 导出类型(0数字 1字符串 2图片)
*/
public ColumnType cellType() default ColumnType.STRING;
/**
* 导出列头背景颜色
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
/**
* 导出列头字体颜色
*/
public IndexedColors headerColor() default IndexedColors.WHITE;
/**
* 导出单元格背景颜色
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;
/**
* 导出单元格字体颜色
*/
public IndexedColors color() default IndexedColors.BLACK;
/**
* 导出字段对齐方式
*/
public HorizontalAlignment align() default HorizontalAlignment.CENTER;
/**
* 自定义数据处理器
*/
public Class<?> handler() default ExcelHandlerAdapter.class;
/**
* 自定义数据处理器参数
*/
public String[] args() default {};
/**
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
*/
Type type() default Type.ALL;
public enum Type
{
ALL(0), EXPORT(1), IMPORT(2);
private final int value;
Type(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
public enum ColumnType
{
NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
private final int value;
ColumnType(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
}
@@ -0,0 +1,18 @@
package com.roomroot.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Excel注解集
*
* @author roomroot
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Excels
{
public Excel[] value();
}
@@ -0,0 +1,51 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.roomroot.common.enums.BusinessType;
import com.roomroot.common.enums.OperatorType;
/**
* 自定义操作日志记录注解
*
* @author roomroot
*
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{
/**
* 模块
*/
public String title() default "";
/**
* 功能
*/
public BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
public OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
public boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
/**
* 排除指定的请求参数
*/
public String[] excludeParamNames() default {};
}
@@ -0,0 +1,40 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.roomroot.common.constant.CacheConstants;
import com.roomroot.common.enums.LimitType;
/**
* 限流注解
*
* @author roomroot
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter
{
/**
* 限流key
*/
public String key() default CacheConstants.RATE_LIMIT_KEY;
/**
* 限流时间,单位秒
*/
public int time() default 60;
/**
* 限流次数
*/
public int count() default 100;
/**
* 限流类型
*/
public LimitType limitType() default LimitType.DEFAULT;
}
@@ -0,0 +1,31 @@
package com.roomroot.common.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解防止表单重复提交
*
* @author roomroot
*
*/
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmit
{
/**
* 间隔时间(ms),小于此时间视为重复提交
*/
public int interval() default 5000;
/**
* 提示消息
*/
public String message() default "不允许重复提交,请稍候再试";
}
@@ -0,0 +1,24 @@
package com.roomroot.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import tools.jackson.databind.annotation.JsonSerialize;
import com.roomroot.common.config.serializer.SensitiveJsonSerializer;
import com.roomroot.common.enums.DesensitizedType;
/**
* 数据脱敏注解
*
* @author roomroot
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive
{
DesensitizedType desensitizedType();
}
@@ -0,0 +1,122 @@
package com.roomroot.common.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author roomroot
*/
@Component
@ConfigurationProperties(prefix = "roomroot")
public class RoomRootConfig
{
/** 项目名称 */
private String name;
/** 版本 */
private String version;
/** 版权年份 */
private String copyrightYear;
/** 上传路径 */
private static String profile;
/** 获取地址开关 */
private static boolean addressEnabled;
/** 验证码类型 */
private static String captchaType;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getCopyrightYear()
{
return copyrightYear;
}
public void setCopyrightYear(String copyrightYear)
{
this.copyrightYear = copyrightYear;
}
public static String getProfile()
{
return profile;
}
public void setProfile(String profile)
{
RoomRootConfig.profile = profile;
}
public static boolean isAddressEnabled()
{
return addressEnabled;
}
public void setAddressEnabled(boolean addressEnabled)
{
RoomRootConfig.addressEnabled = addressEnabled;
}
public static String getCaptchaType() {
return captchaType;
}
public void setCaptchaType(String captchaType) {
RoomRootConfig.captchaType = captchaType;
}
/**
* 获取导入上传路径
*/
public static String getImportPath()
{
return getProfile() + "/import";
}
/**
* 获取头像上传路径
*/
public static String getAvatarPath()
{
return getProfile() + "/avatar";
}
/**
* 获取下载路径
*/
public static String getDownloadPath()
{
return getProfile() + "/download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getProfile() + "/upload";
}
}
@@ -0,0 +1,77 @@
package com.roomroot.common.config.serializer;
import java.util.Objects;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.databind.BeanProperty;
import tools.jackson.databind.DatabindException;
import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ValueSerializer;
import tools.jackson.databind.ser.std.StdSerializer;
import com.roomroot.common.annotation.Sensitive;
import com.roomroot.common.core.domain.model.LoginUser;
import com.roomroot.common.enums.DesensitizedType;
import com.roomroot.common.utils.SecurityUtils;
/**
* 数据脱敏序列化过滤
*
* @author roomroot
*/
public class SensitiveJsonSerializer extends StdSerializer<String>
{
private final DesensitizedType desensitizedType;
public SensitiveJsonSerializer()
{
super(String.class);
this.desensitizedType = null;
}
public SensitiveJsonSerializer(DesensitizedType desensitizedType)
{
super(String.class);
this.desensitizedType = desensitizedType;
}
@Override
public void serialize(String value, JsonGenerator gen, SerializationContext ctxt) throws JacksonException
{
if (desensitizedType != null && desensitization())
{
gen.writeString(desensitizedType.desensitizer().apply(value));
}
else
{
gen.writeString(value);
}
}
@Override
public ValueSerializer<?> createContextual(SerializationContext ctxt, BeanProperty property) throws DatabindException
{
Sensitive annotation = property.getAnnotation(Sensitive.class);
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
{
return new SensitiveJsonSerializer(annotation.desensitizedType());
}
return ctxt.findValueSerializer(property.getType());
}
/**
* 是否需要脱敏处理
*/
private boolean desensitization()
{
try
{
LoginUser securityUser = SecurityUtils.getLoginUser();
// 管理员不脱敏
return !securityUser.getUser().isAdmin();
}
catch (Exception e)
{
return true;
}
}
}
@@ -0,0 +1,44 @@
package com.roomroot.common.constant;
/**
* 缓存的key 常量
*
* @author roomroot
*/
public class CacheConstants
{
/**
* 登录用户 redis key
*/
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
/**
* 验证码 redis key
*/
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
/**
* 参数管理 cache key
*/
public static final String SYS_CONFIG_KEY = "sys_config:";
/**
* 字典管理 cache key
*/
public static final String SYS_DICT_KEY = "sys_dict:";
/**
* 防重提交 redis key
*/
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
/**
* 限流 redis key
*/
public static final String RATE_LIMIT_KEY = "rate_limit:";
/**
* 登录账户密码错误次数 redis key
*/
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
}
@@ -0,0 +1,204 @@
package com.roomroot.common.constant;
import java.util.Locale;
import io.jsonwebtoken.Claims;
/**
* 通用常量信息
*
* @author roomroot
*/
public class Constants
{
/**
* UTF-8 字符集
*/
public static final String UTF8 = "UTF-8";
/**
* GBK 字符集
*/
public static final String GBK = "GBK";
/**
* 系统语言
*/
public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
/**
* www主域
*/
public static final String WWW = "www.";
/**
* http请求
*/
public static final String HTTP = "http://";
/**
* https请求
*/
public static final String HTTPS = "https://";
/**
* 通用成功标识
*/
public static final String SUCCESS = "0";
/**
* 通用失败标识
*/
public static final String FAIL = "1";
/**
* 登录成功
*/
public static final String LOGIN_SUCCESS = "Success";
/**
* 注销
*/
public static final String LOGOUT = "Logout";
/**
* 注册
*/
public static final String REGISTER = "Register";
/**
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMITER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMITER = ",";
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/**
* 用户ID
*/
public static final String JWT_USERID = "userid";
/**
* 用户名称
*/
public static final String JWT_USERNAME = Claims.SUBJECT;
/**
* 用户头像
*/
public static final String JWT_AVATAR = "avatar";
/**
* 创建时间
*/
public static final String JWT_CREATED = "created";
/**
* 用户权限
*/
public static final String JWT_AUTHORITIES = "authorities";
/**
* 资源映射路径 前缀
*/
public static final String RESOURCE_PREFIX = "/profile";
/**
* RMI 远程方法调用
*/
public static final String LOOKUP_RMI = "rmi:";
/**
* LDAP 远程方法调用
*/
public static final String LOOKUP_LDAP = "ldap:";
/**
* LDAPS 远程方法调用
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
*/
public static final String[] JSON_WHITELIST_STR = { "com.roomroot" };
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/
public static final String[] JOB_WHITELIST_STR = { "com.roomroot.quartz.task" };
/**
* 定时任务违规的字符
*/
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
"org.springframework", "org.apache", "com.roomroot.common.utils.file", "com.roomroot.common.config", "com.roomroot.generator" };
/**
* 部门相关常量
*/
public static class Dept
{
/**
* 全部数据权限
*/
public static final String DATA_SCOPE_ALL = "1";
/**
* 自定数据权限
*/
public static final String DATA_SCOPE_CUSTOM = "2";
/**
* 部门数据权限
*/
public static final String DATA_SCOPE_DEPT = "3";
/**
* 部门及以下数据权限
*/
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
/**
* 仅本人数据权限
*/
public static final String DATA_SCOPE_SELF = "5";
}
}
@@ -0,0 +1,120 @@
package com.roomroot.common.constant;
/**
* 代码生成通用常量
*
* @author roomroot
*/
public class GenConstants
{
/** 单表(增删改查) */
public static final String TPL_CRUD = "crud";
/** 树表(增删改查) */
public static final String TPL_TREE = "tree";
/** 主子表(增删改查) */
public static final String TPL_SUB = "sub";
/** 树编码字段 */
public static final String TREE_CODE = "treeCode";
/** 树父编码字段 */
public static final String TREE_PARENT_CODE = "treeParentCode";
/** 树名称字段 */
public static final String TREE_NAME = "treeName";
/** 上级菜单ID字段 */
public static final String PARENT_MENU_ID = "parentMenuId";
/** 上级菜单名称字段 */
public static final String PARENT_MENU_NAME = "parentMenuName";
/** 生成详情页开关 */
public static final String GEN_VIEW = "genView";
/** 数据库字符串类型 */
public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
/** 数据库文本类型 */
public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
/** 数据库时间类型 */
public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
/** 数据库数字类型 */
public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "bigint", "float", "double", "decimal" };
/** 页面不需要编辑字段 */
public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
/** 页面不需要显示的列表字段 */
public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
"update_time" };
/** 页面不需要查询字段 */
public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
"update_time", "remark" };
/** Entity基类字段 */
public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
/** Tree基类字段 */
public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
/** 文本框 */
public static final String HTML_INPUT = "input";
/** 文本域 */
public static final String HTML_TEXTAREA = "textarea";
/** 下拉框 */
public static final String HTML_SELECT = "select";
/** 单选框 */
public static final String HTML_RADIO = "radio";
/** 复选框 */
public static final String HTML_CHECKBOX = "checkbox";
/** 日期控件 */
public static final String HTML_DATETIME = "datetime";
/** 图片上传控件 */
public static final String HTML_IMAGE_UPLOAD = "imageUpload";
/** 文件上传控件 */
public static final String HTML_FILE_UPLOAD = "fileUpload";
/** 富文本控件 */
public static final String HTML_EDITOR = "editor";
/** 字符串类型 */
public static final String TYPE_STRING = "String";
/** 整型 */
public static final String TYPE_INTEGER = "Integer";
/** 长整型 */
public static final String TYPE_LONG = "Long";
/** 浮点型 */
public static final String TYPE_DOUBLE = "Double";
/** 高精度计算类型 */
public static final String TYPE_BIGDECIMAL = "BigDecimal";
/** 时间类型 */
public static final String TYPE_DATE = "Date";
/** 模糊查询 */
public static final String QUERY_LIKE = "LIKE";
/** 相等查询 */
public static final String QUERY_EQ = "EQ";
/** 需要 */
public static final String REQUIRE = "1";
}
@@ -0,0 +1,94 @@
package com.roomroot.common.constant;
/**
* 返回状态码
*
* @author roomroot
*/
public class HttpStatus
{
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 对象创建成功
*/
public static final int CREATED = 201;
/**
* 请求已经被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已经执行成功,但是没有返回数据
*/
public static final int NO_CONTENT = 204;
/**
* 资源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400;
/**
* 未授权
*/
public static final int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
public static final int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
public static final int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static final int ERROR = 500;
/**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
public static final int WARN = 601;
}
@@ -0,0 +1,50 @@
package com.roomroot.common.constant;
/**
* 任务调度通用常量
*
* @author roomroot
*/
public class ScheduleConstants
{
public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
/** 执行目标key */
public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
/** 默认 */
public static final String MISFIRE_DEFAULT = "0";
/** 立即触发执行 */
public static final String MISFIRE_IGNORE_MISFIRES = "1";
/** 触发一次执行 */
public static final String MISFIRE_FIRE_AND_PROCEED = "2";
/** 不触发立即执行 */
public static final String MISFIRE_DO_NOTHING = "3";
public enum Status
{
/**
* 正常
*/
NORMAL("0"),
/**
* 暂停
*/
PAUSE("1");
private String value;
private Status(String value)
{
this.value = value;
}
public String getValue()
{
return value;
}
}
}
@@ -0,0 +1,81 @@
package com.roomroot.common.constant;
/**
* 用户常量信息
*
* @author roomroot
*/
public class UserConstants
{
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
/** 正常状态 */
public static final String NORMAL = "0";
/** 异常状态 */
public static final String EXCEPTION = "1";
/** 用户封禁状态 */
public static final String USER_DISABLE = "1";
/** 角色正常状态 */
public static final String ROLE_NORMAL = "0";
/** 角色封禁状态 */
public static final String ROLE_DISABLE = "1";
/** 部门正常状态 */
public static final String DEPT_NORMAL = "0";
/** 部门停用状态 */
public static final String DEPT_DISABLE = "1";
/** 字典正常状态 */
public static final String DICT_NORMAL = "0";
/** 是否为系统默认(是) */
public static final String YES = "Y";
/** 是否菜单外链(是) */
public static final String YES_FRAME = "0";
/** 是否菜单外链(否) */
public static final String NO_FRAME = "1";
/** 菜单类型(目录) */
public static final String TYPE_DIR = "M";
/** 菜单类型(菜单) */
public static final String TYPE_MENU = "C";
/** 菜单类型(按钮) */
public static final String TYPE_BUTTON = "F";
/** Layout组件标识 */
public final static String LAYOUT = "Layout";
/** ParentView组件标识 */
public final static String PARENT_VIEW = "ParentView";
/** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink";
/** 校验是否唯一的返回标识 */
public final static boolean UNIQUE = true;
public final static boolean NOT_UNIQUE = false;
/**
* 用户名长度限制
*/
public static final int USERNAME_MIN_LENGTH = 2;
public static final int USERNAME_MAX_LENGTH = 20;
/**
* 密码长度限制
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
}
@@ -0,0 +1,216 @@
package com.roomroot.common.core.controller;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.roomroot.common.constant.HttpStatus;
import com.roomroot.common.core.domain.AjaxResult;
import com.roomroot.common.core.domain.model.LoginUser;
import com.roomroot.common.core.page.PageDomain;
import com.roomroot.common.core.page.TableDataInfo;
import com.roomroot.common.core.page.TableSupport;
import com.roomroot.common.utils.DateUtils;
import com.roomroot.common.utils.PageUtils;
import com.roomroot.common.utils.SecurityUtils;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.common.utils.sql.SqlUtil;
/**
* web层通用数据处理
*
* @author roomroot
*/
public class BaseController
{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(DateUtils.parseDate(text));
}
});
}
/**
* 设置请求分页数据
*/
protected void startPage()
{
PageUtils.startPage();
}
/**
* 设置请求排序数据
*/
protected void startOrderBy()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Page<?> page = PageUtils.getPage();
if (page != null)
{
String[] orderParts = orderBy.split("\\s+");
if (orderParts.length > 0)
{
String column = orderParts[0];
boolean isAsc = orderParts.length <= 1 || !"desc".equalsIgnoreCase(orderParts[1]);
OrderItem orderItem = new OrderItem();
orderItem.setColumn(column);
orderItem.setAsc(isAsc);
page.addOrder(orderItem);
}
}
}
}
/**
* 清理分页的线程变量
*/
protected void clearPage()
{
PageUtils.clearPage();
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setMsg("查询成功");
rspData.setRows(list);
Page<?> page = PageUtils.getPage();
rspData.setTotal(page != null ? page.getTotal() : list.size());
return rspData;
}
/**
* 返回成功
*/
public AjaxResult success()
{
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
return AjaxResult.success(message);
}
/**
* 返回成功消息
*/
public AjaxResult success(Object data)
{
return AjaxResult.success(data);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
return AjaxResult.error(message);
}
/**
* 返回警告消息
*/
public AjaxResult warn(String message)
{
return AjaxResult.warn(message);
}
/**
* 响应返回结果
*
* @param rows 影响行数
* @return 操作结果
*/
protected AjaxResult toAjax(int rows)
{
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 页面跳转
*/
public String redirect(String url)
{
return StringUtils.format("redirect:{}", url);
}
/**
* 获取用户缓存信息
*/
public LoginUser getLoginUser()
{
return SecurityUtils.getLoginUser();
}
/**
* 获取登录用户id
*/
public Long getUserId()
{
return getLoginUser().getUserId();
}
/**
* 获取登录部门id
*/
public Long getDeptId()
{
return getLoginUser().getDeptId();
}
/**
* 获取登录用户名
*/
public String getUsername()
{
return getLoginUser().getUsername();
}
}
@@ -0,0 +1,216 @@
package com.roomroot.common.core.domain;
import java.util.HashMap;
import java.util.Objects;
import com.roomroot.common.constant.HttpStatus;
import com.roomroot.common.utils.StringUtils;
/**
* 操作消息提醒
*
* @author roomroot
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
/**
* 返回成功数据
*
* @return 成功消息
*/
public static AjaxResult success(Object data)
{
return AjaxResult.success("操作成功", data);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static AjaxResult success(String msg)
{
return AjaxResult.success(msg, null);
}
/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static AjaxResult success(String msg, Object data)
{
return new AjaxResult(HttpStatus.SUCCESS, msg, data);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static AjaxResult warn(String msg)
{
return AjaxResult.warn(msg, null);
}
/**
* 返回警告消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static AjaxResult warn(String msg, Object data)
{
return new AjaxResult(HttpStatus.WARN, msg, data);
}
/**
* 返回错误消息
*
* @return 错误消息
*/
public static AjaxResult error()
{
return AjaxResult.error("操作失败");
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(String msg)
{
return AjaxResult.error(msg, null);
}
/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 错误消息
*/
public static AjaxResult error(String msg, Object data)
{
return new AjaxResult(HttpStatus.ERROR, msg, data);
}
/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 错误消息
*/
public static AjaxResult error(int code, String msg)
{
return new AjaxResult(code, msg, null);
}
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess()
{
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn()
{
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError()
{
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/**
* 方便链式调用
*
* @param key 键
* @param value 值
* @return 数据对象
*/
@Override
public AjaxResult put(String key, Object value)
{
super.put(key, value);
return this;
}
}

Some files were not shown because too many files have changed in this diff Show More