重新整理环境,分支合并
This commit is contained in:
parent
acf3b9dacf
commit
b17aac0ebe
44
java-backend/.gitignore
vendored
44
java-backend/.gitignore
vendored
@ -1,44 +0,0 @@
|
|||||||
# Maven
|
|
||||||
target/
|
|
||||||
*.class
|
|
||||||
*.log
|
|
||||||
.mvn/
|
|
||||||
mvnw*
|
|
||||||
pom.xml.tag
|
|
||||||
pom.xml.releaseBackup
|
|
||||||
pom.xml.versionsBackup
|
|
||||||
pom.xml.next
|
|
||||||
release.properties
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
buildNumber.properties
|
|
||||||
.mvn/timing.properties
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
.settings/
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
# OS
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# 配置文件(敏感信息)
|
|
||||||
src/main/resources/application-local.yml
|
|
||||||
src/main/resources/application-prod.yml.local
|
|
||||||
|
|
||||||
# 日志
|
|
||||||
logs/
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# 临时文件
|
|
||||||
tmp/
|
|
||||||
temp/
|
|
||||||
*.tmp
|
|
||||||
*.bak
|
|
||||||
*.swp
|
|
||||||
*~
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
# Creation Java Backend
|
|
||||||
|
|
||||||
Spring Boot 后端基础框架
|
|
||||||
|
|
||||||
## 技术栈
|
|
||||||
|
|
||||||
| 组件 | 技术 | 版本 |
|
|
||||||
|:------|:------|:------|
|
|
||||||
| 框架 | Spring Boot | 3.2.4 |
|
|
||||||
| 持久层 | MyBatis-Plus | 3.5.5 |
|
|
||||||
| 数据库 | MySQL 8.0 | 8.0.33 |
|
|
||||||
| 迁移 | Flyway | 10.10.0 |
|
|
||||||
| 认证 | Spring Security + JWT | 0.12.3 |
|
|
||||||
| 缓存 | Redis | - |
|
|
||||||
| 连接池 | Alibaba Druid | 1.2.20 |
|
|
||||||
| 对象映射 | MapStruct | 1.5.5.Final |
|
|
||||||
| API 文档 | Knife4j | 4.4.0 |
|
|
||||||
| 日志 | Logback | - |
|
|
||||||
| JSON | FastJSON2 | 2.0.43 |
|
|
||||||
| 工具类 | Hutool | 5.8.26 |
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 环境要求
|
|
||||||
- Java 17+
|
|
||||||
- Maven 3.8+
|
|
||||||
- MySQL 8.0+
|
|
||||||
- Redis 6.0+
|
|
||||||
|
|
||||||
### 配置数据库
|
|
||||||
|
|
||||||
1. 创建数据库
|
|
||||||
```sql
|
|
||||||
CREATE DATABASE creation_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
|
||||||
```
|
|
||||||
|
|
||||||
2. 修改 `src/main/resources/application-dev.yml` 中的数据库连接信息
|
|
||||||
|
|
||||||
### 启动应用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd java-backend
|
|
||||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
|
||||||
```
|
|
||||||
|
|
||||||
启动成功后访问:
|
|
||||||
- 应用地址:http://localhost:8580
|
|
||||||
- API 文档:http://localhost:8580/swagger-ui.html
|
|
||||||
|
|
||||||
## 项目结构
|
|
||||||
|
|
||||||
```
|
|
||||||
java-backend/
|
|
||||||
├── src/main/java/com/lesingle/creation/
|
|
||||||
│ ├── CreationApplication.java # 启动类
|
|
||||||
│ ├── common/ # 公共模块
|
|
||||||
│ │ ├── config/ # 配置类
|
|
||||||
│ │ │ ├── MybatisPlusConfig.java
|
|
||||||
│ │ │ ├── SecurityConfig.java
|
|
||||||
│ │ │ └── JwtProperties.java
|
|
||||||
│ │ ├── constant/ # 常量定义
|
|
||||||
│ │ │ └── ErrorCode.java
|
|
||||||
│ │ ├── core/ # 核心类
|
|
||||||
│ │ │ └── Result.java
|
|
||||||
│ │ ├── exception/ # 异常处理
|
|
||||||
│ │ │ ├── BusinessException.java
|
|
||||||
│ │ │ └── GlobalExceptionHandler.java
|
|
||||||
│ │ ├── filter/ # 过滤器
|
|
||||||
│ │ │ └── JwtAuthenticationFilter.java
|
|
||||||
│ │ └── util/ # 工具类
|
|
||||||
│ │ └── JwtTokenUtil.java
|
|
||||||
│ ├── controller/ # 控制器
|
|
||||||
│ ├── service/ # 服务层
|
|
||||||
│ ├── mapper/ # Mapper 接口
|
|
||||||
│ ├── entity/ # 实体类
|
|
||||||
│ ├── dto/ # 数据传输对象
|
|
||||||
│ └── vo/ # 视图对象
|
|
||||||
├── src/main/resources/
|
|
||||||
│ ├── application.yml # 主配置
|
|
||||||
│ ├── application-dev.yml # 开发环境
|
|
||||||
│ ├── application-test.yml # 测试环境
|
|
||||||
│ ├── application-prod.yml # 生产环境
|
|
||||||
│ ├── db/migration/ # Flyway 迁移脚本
|
|
||||||
│ │ └── V1.0__init_schema.sql
|
|
||||||
│ └── logback-spring.xml # 日志配置
|
|
||||||
└── pom.xml # Maven 配置
|
|
||||||
```
|
|
||||||
|
|
||||||
## 默认账户
|
|
||||||
|
|
||||||
Flyway 初始迁移后会自动创建以下账户:
|
|
||||||
|
|
||||||
| 用户名 | 密码 | 角色 |
|
|
||||||
|:------|:------|:------|
|
|
||||||
| admin | admin123 | 超级管理员 |
|
|
||||||
|
|
||||||
## 开发规范
|
|
||||||
|
|
||||||
### 三层架构
|
|
||||||
|
|
||||||
| 层级 | 职责 | 数据流 |
|
|
||||||
|:------|:------|:------|
|
|
||||||
| **Controller** | 接收请求、参数校验 | DTO ↔ VO |
|
|
||||||
| **Service** | 业务逻辑、事务控制 | 使用 Entity |
|
|
||||||
| **Mapper** | 数据库 CRUD | 使用 Entity |
|
|
||||||
|
|
||||||
### 代码规范
|
|
||||||
|
|
||||||
- Java 17 严格模式
|
|
||||||
- 注释和日志使用中文
|
|
||||||
- 使用 Lombok 简化代码
|
|
||||||
- 使用 MapStruct 进行对象映射
|
|
||||||
|
|
||||||
### 日志规范
|
|
||||||
|
|
||||||
- 所有日志使用中文
|
|
||||||
- 使用 MDC 实现 TraceId 链路追踪
|
|
||||||
- 开发环境:DEBUG 级别
|
|
||||||
- 生产环境:INFO/WARN 级别
|
|
||||||
|
|
||||||
## 常用命令
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 编译
|
|
||||||
mvn clean compile
|
|
||||||
|
|
||||||
# 打包
|
|
||||||
mvn clean package
|
|
||||||
|
|
||||||
# 运行(开发环境)
|
|
||||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
|
||||||
|
|
||||||
# 运行(测试环境)
|
|
||||||
mvn spring-boot:run -Dspring-boot.run.profiles=test
|
|
||||||
|
|
||||||
# 运行(生产环境)
|
|
||||||
mvn spring-boot:run -Dspring-boot.run.profiles=prod
|
|
||||||
|
|
||||||
# 跳过测试打包
|
|
||||||
mvn clean package -DskipTests
|
|
||||||
|
|
||||||
# 查看依赖
|
|
||||||
mvn dependency:tree
|
|
||||||
```
|
|
||||||
|
|
||||||
## API 接口
|
|
||||||
|
|
||||||
### 认证相关
|
|
||||||
- `POST /api/auth/login` - 用户登录
|
|
||||||
- `POST /api/auth/logout` - 用户登出
|
|
||||||
- `POST /api/auth/register` - 用户注册
|
|
||||||
- `POST /api/auth/refresh` - 刷新 Token
|
|
||||||
|
|
||||||
### 用户相关
|
|
||||||
- `GET /api/users` - 用户列表
|
|
||||||
- `GET /api/users/{id}` - 获取用户详情
|
|
||||||
- `POST /api/users` - 创建用户
|
|
||||||
- `PUT /api/users/{id}` - 更新用户
|
|
||||||
- `DELETE /api/users/{id}` - 删除用户
|
|
||||||
|
|
||||||
## 环境变量(生产环境)
|
|
||||||
|
|
||||||
生产环境部署时需设置以下环境变量:
|
|
||||||
|
|
||||||
| 变量名 | 说明 | 示例 |
|
|
||||||
|:------|:------|:------|
|
|
||||||
| `DATABASE_URL` | 数据库连接 URL | `jdbc:mysql://host:3306/db` |
|
|
||||||
| `DB_USERNAME` | 数据库用户名 | `root` |
|
|
||||||
| `DB_PASSWORD` | 数据库密码 | `password` |
|
|
||||||
| `REDIS_HOST` | Redis 主机 | `localhost` |
|
|
||||||
| `REDIS_PORT` | Redis 端口 | `6379` |
|
|
||||||
| `REDIS_PASSWORD` | Redis 密码 | `password` |
|
|
||||||
| `JWT_SECRET` | JWT 密钥 | `your-secret-key` |
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
@ -1 +0,0 @@
|
|||||||
lombok.addLombokGeneratedAnnotation = true
|
|
||||||
@ -1,241 +0,0 @@
|
|||||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>3.2.4</version>
|
|
||||||
<relativePath/>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<groupId>com.lesingle.creation</groupId>
|
|
||||||
<artifactId>creation</artifactId>
|
|
||||||
<version>1.0.0-SNAPSHOT</version>
|
|
||||||
<name>creation</name>
|
|
||||||
<description>Lesingle Creation - Spring Boot 后端服务</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<java.version>17</java.version>
|
|
||||||
<mybatis-plus.version>3.5.5</mybatis-plus.version>
|
|
||||||
<druid.version>1.2.20</druid.version>
|
|
||||||
<mysql.version>8.0.33</mysql.version>
|
|
||||||
<mapstruct.version>1.5.5.Final</mapstruct.version>
|
|
||||||
<lombok.version>1.18.34</lombok.version>
|
|
||||||
<hutool.version>5.8.26</hutool.version>
|
|
||||||
<fastjson2.version>2.0.43</fastjson2.version>
|
|
||||||
<jjwt.version>0.12.3</jjwt.version>
|
|
||||||
<flyway.version>10.10.0</flyway.version>
|
|
||||||
<aliyun.oss.version>3.17.2</aliyun.oss.version>
|
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
|
||||||
<maven.compiler.target>17</maven.compiler.target>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<!-- 添加 Maven 仓库 -->
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>aliyun</id>
|
|
||||||
<name>Aliyun Maven</name>
|
|
||||||
<url>https://maven.aliyun.com/repository/public</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<!-- Spring Boot 核心依赖 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- MyBatis-Plus -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.baomidou</groupId>
|
|
||||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
|
||||||
<version>${mybatis-plus.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- MySQL 驱动 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
|
||||||
<version>${mysql.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Druid 连接池 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
|
||||||
<version>${druid.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Flyway 数据库迁移 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
<version>${flyway.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Flyway MySQL 支持 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-mysql</artifactId>
|
|
||||||
<version>${flyway.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringDoc OpenAPI (API 文档) -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springdoc</groupId>
|
|
||||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
|
||||||
<version>2.3.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- MapStruct 对象映射 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct</artifactId>
|
|
||||||
<version>${mapstruct.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct-processor</artifactId>
|
|
||||||
<version>${mapstruct.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Lombok -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
<version>${lombok.version}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Hutool 工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.hutool</groupId>
|
|
||||||
<artifactId>hutool-all</artifactId>
|
|
||||||
<version>${hutool.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 阿里云 OSS -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.aliyun.oss</groupId>
|
|
||||||
<artifactId>aliyun-sdk-oss</artifactId>
|
|
||||||
<version>${aliyun.oss.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- FastJSON2 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
|
||||||
<artifactId>fastjson2</artifactId>
|
|
||||||
<version>${fastjson2.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- JWT -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-api</artifactId>
|
|
||||||
<version>${jjwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-impl</artifactId>
|
|
||||||
<version>${jjwt.version}</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt-jackson</artifactId>
|
|
||||||
<version>${jjwt.version}</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 测试依赖 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.security</groupId>
|
|
||||||
<artifactId>spring-security-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<excludes>
|
|
||||||
<exclude>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>17</source>
|
|
||||||
<target>17</target>
|
|
||||||
<encoding>UTF-8</encoding>
|
|
||||||
<annotationProcessorPaths>
|
|
||||||
<path>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok</artifactId>
|
|
||||||
<version>${lombok.version}</version>
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
|
||||||
<version>0.2.0</version>
|
|
||||||
</path>
|
|
||||||
<path>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct-processor</artifactId>
|
|
||||||
<version>${mapstruct.version}</version>
|
|
||||||
</path>
|
|
||||||
</annotationProcessorPaths>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package com.lesingle.creation;
|
|
||||||
|
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring Boot 启动类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@SpringBootApplication
|
|
||||||
@MapperScan("com.lesingle.creation.mapper")
|
|
||||||
public class CreationApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(CreationApplication.class, args);
|
|
||||||
System.out.println("============================================");
|
|
||||||
System.out.println(" Creation 应用启动成功!");
|
|
||||||
System.out.println(" 端口:8580");
|
|
||||||
System.out.println(" API 文档:http://localhost:8580/doc.html");
|
|
||||||
System.out.println("============================================");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
package com.lesingle.creation.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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流注解
|
|
||||||
* <p>
|
|
||||||
* 基于 Redis 滑动窗口实现限流
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Target({ElementType.METHOD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Documented
|
|
||||||
public @interface RateLimiter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流 Key
|
|
||||||
* 支持 SpEL 表达式,如 "#username"
|
|
||||||
*/
|
|
||||||
String key() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流时间窗口(秒)
|
|
||||||
* 默认 60 秒
|
|
||||||
*/
|
|
||||||
int time() default 60;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 时间窗口内最大请求数
|
|
||||||
* 默认 100 次
|
|
||||||
*/
|
|
||||||
int count() default 100;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提示信息
|
|
||||||
*/
|
|
||||||
String message() default "请求过于频繁,请稍后再试";
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
package com.lesingle.creation.common.aspect;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.util.TraceIdUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日志切面
|
|
||||||
* <p>
|
|
||||||
* 拦截 Controller 层所有方法,记录请求日志
|
|
||||||
* 包含:TraceId、请求方法、请求路径、IP、耗时
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class LogAspect {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定义切点:拦截 Controller 层所有方法
|
|
||||||
*/
|
|
||||||
@Pointcut("execution(* com.lesingle.creation.controller..*.*(..))")
|
|
||||||
public void controllerPointcut() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 环绕通知:记录请求耗时
|
|
||||||
*/
|
|
||||||
@Around("controllerPointcut()")
|
|
||||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
|
||||||
ServletRequestAttributes attributes =
|
|
||||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
||||||
if (attributes == null) {
|
|
||||||
return joinPoint.proceed();
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpServletRequest request = attributes.getRequest();
|
|
||||||
String traceId = TraceIdUtil.getTraceId();
|
|
||||||
String method = request.getMethod();
|
|
||||||
String uri = request.getRequestURI();
|
|
||||||
String ip = getIpAddress(request);
|
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
log.info("【{}】请求开始 | 方法:{} | 路径:{} | IP:{}", traceId, method, uri, ip);
|
|
||||||
|
|
||||||
Object result;
|
|
||||||
try {
|
|
||||||
result = joinPoint.proceed();
|
|
||||||
long endTime = System.currentTimeMillis();
|
|
||||||
log.info("【{}】请求成功 | 方法:{} | 路径:{} | 耗时:{}ms",
|
|
||||||
traceId, method, uri, (endTime - startTime));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
long endTime = System.currentTimeMillis();
|
|
||||||
log.error("【{}】请求异常 | 方法:{} | 路径:{} | 耗时:{}ms | 异常:{}",
|
|
||||||
traceId, method, uri, (endTime - startTime), e.getMessage(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取请求 IP 地址
|
|
||||||
*/
|
|
||||||
private String getIpAddress(HttpServletRequest request) {
|
|
||||||
String ip = request.getHeader("x-forwarded-for");
|
|
||||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
// 如果是本地 IPv6,转换为 IPv4
|
|
||||||
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
|
|
||||||
try {
|
|
||||||
ip = InetAddress.getLocalHost().getHostAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
log.error("获取 IP 地址失败:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 多个代理时,取第一个 IP
|
|
||||||
if (ip != null && ip.contains(",")) {
|
|
||||||
ip = ip.split(",")[0].trim();
|
|
||||||
}
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
package com.lesingle.creation.common.aspect;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.annotation.RateLimiter;
|
|
||||||
import com.lesingle.creation.common.exception.BusinessException;
|
|
||||||
import com.lesingle.creation.common.util.RateLimiterUtil;
|
|
||||||
import com.lesingle.creation.common.util.TraceIdUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Before;
|
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.springframework.expression.Expression;
|
|
||||||
import org.springframework.expression.ExpressionParser;
|
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 限流切面
|
|
||||||
* <p>
|
|
||||||
* 拦截标注了 @RateLimiter 注解的方法,实现限流控制
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class RateLimiterAspect {
|
|
||||||
|
|
||||||
private static final ExpressionParser PARSER = new SpelExpressionParser();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 前置通知:执行限流检查
|
|
||||||
*/
|
|
||||||
@Before("@annotation(rateLimiter)")
|
|
||||||
public void before(JoinPoint joinPoint, RateLimiter rateLimiter) {
|
|
||||||
// 获取注解参数
|
|
||||||
String keyExpression = rateLimiter.key();
|
|
||||||
int time = rateLimiter.time();
|
|
||||||
int count = rateLimiter.count();
|
|
||||||
String message = rateLimiter.message();
|
|
||||||
|
|
||||||
// 解析 Key
|
|
||||||
String key = parseKey(keyExpression, joinPoint);
|
|
||||||
|
|
||||||
// 执行限流检查
|
|
||||||
boolean allowed = RateLimiterUtil.tryAcquire(key, time, count);
|
|
||||||
if (!allowed) {
|
|
||||||
String traceId = TraceIdUtil.getTraceId();
|
|
||||||
log.warn("【{}】请求被限流 | Key: {} | 限制:{}/{}s", traceId, key, count, time);
|
|
||||||
throw new BusinessException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.debug("限流检查通过 | Key: {} | 当前计数:{}", key, RateLimiterUtil.getCurrentCount(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析限流 Key
|
|
||||||
* 支持 SpEL 表达式
|
|
||||||
*/
|
|
||||||
private String parseKey(String keyExpression, JoinPoint joinPoint) {
|
|
||||||
if (keyExpression.isEmpty()) {
|
|
||||||
// 默认使用 IP 地址作为 key
|
|
||||||
return "rate_limit:" + getIpAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析 SpEL 表达式
|
|
||||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
|
||||||
Method method = signature.getMethod();
|
|
||||||
Object[] args = joinPoint.getArgs();
|
|
||||||
String[] paramNames = signature.getParameterNames();
|
|
||||||
|
|
||||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
|
||||||
context.setVariable(paramNames[i], args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Expression expression = PARSER.parseExpression(keyExpression);
|
|
||||||
Object value = expression.getValue(context);
|
|
||||||
return "rate_limit:" + (value != null ? value.toString() : "unknown");
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("解析限流 Key 失败:{}", keyExpression, e);
|
|
||||||
return "rate_limit:error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取请求 IP 地址
|
|
||||||
*/
|
|
||||||
private String getIpAddress() {
|
|
||||||
try {
|
|
||||||
ServletRequestAttributes attributes =
|
|
||||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
||||||
if (attributes != null) {
|
|
||||||
HttpServletRequest request = attributes.getRequest();
|
|
||||||
String ip = request.getHeader("x-forwarded-for");
|
|
||||||
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
}
|
|
||||||
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
|
|
||||||
ip = InetAddress.getLocalHost().getHostAddress();
|
|
||||||
}
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
log.error("获取 IP 地址失败:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
package com.lesingle.creation.common.aspect;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.util.TraceIdUtil;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.aspectj.lang.ProceedingJoinPoint;
|
|
||||||
import org.aspectj.lang.annotation.Around;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TraceId 日志链路追踪切面
|
|
||||||
* <p>
|
|
||||||
* 在 Controller 层拦截请求,生成 TraceId 并放入 MDC,实现全链路日志追踪
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class TraceIdAspect {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 环绕通知,拦截 Controller 层所有方法
|
|
||||||
*/
|
|
||||||
@Around("execution(* com.lesingle.creation.controller..*.*(..))")
|
|
||||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 生成 TraceId 并放入 MDC
|
|
||||||
TraceIdUtil.setTraceId();
|
|
||||||
|
|
||||||
log.debug("请求开始,TraceId: {}", TraceIdUtil.getTraceId());
|
|
||||||
|
|
||||||
// 执行目标方法
|
|
||||||
Object result = joinPoint.proceed();
|
|
||||||
|
|
||||||
long costTime = System.currentTimeMillis() - startTime;
|
|
||||||
log.debug("请求结束,TraceId: {}, 耗时:{}ms", TraceIdUtil.getTraceId(), costTime);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
// 清除 MDC,防止内存泄漏
|
|
||||||
TraceIdUtil.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
package com.lesingle.creation.common.base;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.*;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实体基类
|
|
||||||
* <p>
|
|
||||||
* 包含基础字段:id、createBy、createTime、updateBy、updateTime、deleted
|
|
||||||
* 所有实体类应继承此类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public abstract class BaseEntity implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主键 ID
|
|
||||||
*/
|
|
||||||
@TableId(type = IdType.AUTO)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建人账号
|
|
||||||
*/
|
|
||||||
@TableField(fill = FieldFill.INSERT)
|
|
||||||
private String createBy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建时间
|
|
||||||
*/
|
|
||||||
@TableField(fill = FieldFill.INSERT)
|
|
||||||
private LocalDateTime createTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新人账号
|
|
||||||
*/
|
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
|
||||||
private String updateBy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新时间
|
|
||||||
*/
|
|
||||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
|
||||||
private LocalDateTime updateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 逻辑删除标识(0-未删除,1-已删除)
|
|
||||||
*/
|
|
||||||
@TableLogic
|
|
||||||
private Integer deleted;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package com.lesingle.creation.common.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT 配置属性
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "jwt")
|
|
||||||
public class JwtProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT 密钥
|
|
||||||
*/
|
|
||||||
private String secret;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token 过期时间(毫秒)
|
|
||||||
*/
|
|
||||||
private Long expiration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token 前缀
|
|
||||||
*/
|
|
||||||
private String tokenPrefix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token 请求头名称
|
|
||||||
*/
|
|
||||||
private String header;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package com.lesingle.creation.common.config;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.DbType;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MyBatis-Plus 配置类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class MybatisPlusConfig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页插件配置
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
|
||||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
|
||||||
// 添加分页插件
|
|
||||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
|
||||||
return interceptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package com.lesingle.creation.common.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 阿里云 OSS 配置属性
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "aliyun.oss")
|
|
||||||
public class OssProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OSS Endpoint
|
|
||||||
* 如:oss-cn-hangzhou.aliyuncs.com
|
|
||||||
*/
|
|
||||||
private String endpoint;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access Key ID
|
|
||||||
*/
|
|
||||||
private String accessKeyId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access Key Secret
|
|
||||||
*/
|
|
||||||
private String accessKeySecret;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bucket 名称
|
|
||||||
*/
|
|
||||||
private String bucketName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义域名(可选)
|
|
||||||
* 如:https://cdn.example.com
|
|
||||||
*/
|
|
||||||
private String customDomain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传根目录
|
|
||||||
* 如:uploads/
|
|
||||||
*/
|
|
||||||
private String rootDir = "";
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package com.lesingle.creation.common.config;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
|
||||||
import org.springframework.cache.CacheManager;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
|
||||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
|
||||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redis 配置类
|
|
||||||
* <p>
|
|
||||||
* 配置 RedisTemplate 和 CacheManager
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableCaching
|
|
||||||
public class RedisConfig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 配置 RedisTemplate
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
|
|
||||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
|
||||||
template.setConnectionFactory(factory);
|
|
||||||
|
|
||||||
// 配置 JSON 序列化器
|
|
||||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
|
||||||
ObjectMapper om = new ObjectMapper();
|
|
||||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
|
||||||
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
|
||||||
jackson2JsonRedisSerializer.setObjectMapper(om);
|
|
||||||
|
|
||||||
// String 序列化器
|
|
||||||
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
|
|
||||||
|
|
||||||
// Key 采用 String 序列化
|
|
||||||
template.setKeySerializer(stringRedisSerializer);
|
|
||||||
template.setHashKeySerializer(stringRedisSerializer);
|
|
||||||
|
|
||||||
// Value 采用 JSON 序列化
|
|
||||||
template.setValueSerializer(jackson2JsonRedisSerializer);
|
|
||||||
template.setHashValueSerializer(jackson2JsonRedisSerializer);
|
|
||||||
|
|
||||||
template.afterPropertiesSet();
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 配置缓存管理器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public CacheManager cacheManager(RedisConnectionFactory factory) {
|
|
||||||
// JSON 序列化器
|
|
||||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
|
||||||
ObjectMapper om = new ObjectMapper();
|
|
||||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
|
||||||
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
|
|
||||||
jackson2JsonRedisSerializer.setObjectMapper(om);
|
|
||||||
|
|
||||||
// 缓存配置
|
|
||||||
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
|
|
||||||
// 缓存过期时间:默认 30 分钟
|
|
||||||
.entryTtl(Duration.ofMinutes(30))
|
|
||||||
// Key 前缀
|
|
||||||
.prefixCacheNameWith("lesingle:")
|
|
||||||
// 禁用空值缓存
|
|
||||||
.disableCachingNullValues()
|
|
||||||
// 序列化配置
|
|
||||||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
|
|
||||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
|
|
||||||
|
|
||||||
return RedisCacheManager.builder(factory)
|
|
||||||
.cacheDefaults(config)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,116 +0,0 @@
|
|||||||
package com.lesingle.creation.common.config;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.filter.JwtAuthenticationFilter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring Security 配置类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableWebSecurity
|
|
||||||
@EnableMethodSecurity
|
|
||||||
public class SecurityConfig {
|
|
||||||
|
|
||||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
|
||||||
|
|
||||||
public SecurityConfig(@org.springframework.context.annotation.Lazy JwtAuthenticationFilter jwtAuthenticationFilter) {
|
|
||||||
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码编码器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public PasswordEncoder passwordEncoder() {
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证管理器
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
|
||||||
return config.getAuthenticationManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 安全过滤链配置
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
||||||
http
|
|
||||||
// 关闭 CSRF
|
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
|
||||||
// 关闭表单登录
|
|
||||||
.formLogin(AbstractHttpConfigurer::disable)
|
|
||||||
// 关闭 HTTP Basic
|
|
||||||
.httpBasic(AbstractHttpConfigurer::disable)
|
|
||||||
// 关闭会话管理(使用 JWT)
|
|
||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
|
||||||
// 配置授权规则
|
|
||||||
.authorizeHttpRequests(auth -> auth
|
|
||||||
// 放行静态资源
|
|
||||||
.requestMatchers("/favicon.ico", "/error").permitAll()
|
|
||||||
// 放行 API 文档
|
|
||||||
.requestMatchers("/doc.html", "/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**").permitAll()
|
|
||||||
// 放行登录、注册接口(支持 Vite 代理后/auth/** 和直接访问/api/auth/**)
|
|
||||||
.requestMatchers("/auth/**", "/api/auth/**").permitAll()
|
|
||||||
// 放行菜单接口(支持 Vite 代理后/menu/** 和直接访问/api/menu/**)
|
|
||||||
.requestMatchers("/menu/**", "/api/menu/**").permitAll()
|
|
||||||
// 放行公开用户接口(支持 Vite 代理后/public/** 和直接访问/api/public/**)
|
|
||||||
.requestMatchers("/public/**", "/api/public/**").permitAll()
|
|
||||||
// 其他请求需要认证
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
)
|
|
||||||
// 配置跨域
|
|
||||||
.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
|
||||||
// 添加 JWT 过滤器(在 BasicAuthenticationFilter 之前)
|
|
||||||
.addFilterBefore(jwtAuthenticationFilter, BasicAuthenticationFilter.class);
|
|
||||||
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跨域配置
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public CorsConfigurationSource corsConfigurationSource() {
|
|
||||||
CorsConfiguration config = new CorsConfiguration();
|
|
||||||
// 允许所有来源
|
|
||||||
config.setAllowedOriginPatterns(List.of("*"));
|
|
||||||
// 允许的请求方法
|
|
||||||
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
|
||||||
// 允许的请求头
|
|
||||||
config.setAllowedHeaders(List.of("*"));
|
|
||||||
// 允许携带凭证
|
|
||||||
config.setAllowCredentials(true);
|
|
||||||
// 预检请求缓存时间
|
|
||||||
config.setMaxAge(3600L);
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
|
||||||
source.registerCorsConfiguration("/**", config);
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,121 +0,0 @@
|
|||||||
package com.lesingle.creation.common.constant;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统一错误码枚举
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ErrorCode {
|
|
||||||
|
|
||||||
// ========== 成功 ==========
|
|
||||||
SUCCESS(200, "操作成功"),
|
|
||||||
|
|
||||||
// ========== 客户端错误(4xx) ==========
|
|
||||||
BAD_REQUEST(400, "请求参数错误"),
|
|
||||||
UNAUTHORIZED(401, "未登录或 Token 已过期"),
|
|
||||||
FORBIDDEN(403, "没有访问权限"),
|
|
||||||
NOT_FOUND(404, "资源不存在"),
|
|
||||||
METHOD_NOT_ALLOWED(405, "请求方法不支持"),
|
|
||||||
CONFLICT(409, "资源冲突"),
|
|
||||||
|
|
||||||
// ========== 服务端错误(5xx) ==========
|
|
||||||
INTERNAL_ERROR(500, "系统内部错误"),
|
|
||||||
SERVICE_UNAVAILABLE(503, "服务不可用"),
|
|
||||||
|
|
||||||
// ========== 业务错误(1xxx) ==========
|
|
||||||
USER_NOT_FOUND(1001, "用户不存在"),
|
|
||||||
USER_ACCOUNT_LOCKED(1002, "用户账号已被锁定"),
|
|
||||||
USER_PASSWORD_ERROR(1003, "用户名或密码错误"),
|
|
||||||
USER_ALREADY_EXISTS(1004, "用户已存在"),
|
|
||||||
|
|
||||||
ROLE_NOT_FOUND(1101, "角色不存在"),
|
|
||||||
ROLE_ALREADY_EXISTS(1102, "角色已存在"),
|
|
||||||
|
|
||||||
PERMISSION_DENIED(1201, "权限不足"),
|
|
||||||
PERMISSION_NOT_FOUND(1202, "权限不存在"),
|
|
||||||
|
|
||||||
TOKEN_INVALID(1301, "Token 无效"),
|
|
||||||
TOKEN_EXPIRED(1302, "Token 已过期"),
|
|
||||||
|
|
||||||
DATA_NOT_FOUND(1401, "数据不存在"),
|
|
||||||
DATA_ALREADY_EXISTS(1402, "数据已存在"),
|
|
||||||
DATA_VERSION_ERROR(1403, "数据版本冲突"),
|
|
||||||
|
|
||||||
PARAMS_ERROR(1501, "参数校验失败"),
|
|
||||||
FILE_UPLOAD_ERROR(1502, "文件上传失败"),
|
|
||||||
FILE_DOWNLOAD_ERROR(1503, "文件下载失败"),
|
|
||||||
FILE_NOT_FOUND(1504, "文件不存在"),
|
|
||||||
|
|
||||||
// ========== 数据库错误(2xxx) ==========
|
|
||||||
DB_ERROR(2001, "数据库操作失败"),
|
|
||||||
DB_CONNECTION_ERROR(2002, "数据库连接失败"),
|
|
||||||
DB_QUERY_ERROR(2003, "数据库查询失败"),
|
|
||||||
DB_UPDATE_ERROR(2004, "数据库更新失败"),
|
|
||||||
DB_DELETE_ERROR(2005, "数据库删除失败"),
|
|
||||||
DB_INSERT_ERROR(2006, "数据库插入失败"),
|
|
||||||
|
|
||||||
// ========== 竞赛业务错误(3xxx) ==========
|
|
||||||
CONTEST_NOT_FOUND(3001, "竞赛不存在"),
|
|
||||||
CONTEST_ALREADY_PUBLISHED(3002, "竞赛已发布"),
|
|
||||||
CONTEST_NOT_STARTED(3003, "竞赛未开始"),
|
|
||||||
CONTEST_ALREADY_FINISHED(3004, "竞赛已结束"),
|
|
||||||
CONTEST_NAME_DUPLICATE(3005, "竞赛名称已存在"),
|
|
||||||
|
|
||||||
REGISTRATION_NOT_FOUND(3101, "报名记录不存在"),
|
|
||||||
REGISTRATION_ALREADY_EXISTS(3102, "已报名,不能重复报名"),
|
|
||||||
REGISTRATION_AUDIT_PENDING(3103, "报名待审核"),
|
|
||||||
REGISTRATION_CLOSED(3104, "报名已截止"),
|
|
||||||
REGISTRATION_NOT_ALLOWED(3105, "不允许报名"),
|
|
||||||
|
|
||||||
WORK_NOT_FOUND(3201, "作品不存在"),
|
|
||||||
WORK_SUBMISSION_CLOSED(3202, "作品提交已截止"),
|
|
||||||
WORK_ALREADY_SUBMITTED(3203, "作品已提交"),
|
|
||||||
WORK_NOT_LATEST_VERSION(3204, "不是最新版本"),
|
|
||||||
|
|
||||||
REVIEW_NOT_ASSIGNED(3301, "未分配评审任务"),
|
|
||||||
REVIEW_ALREADY_SCORED(3302, "已评分,不能重复评分"),
|
|
||||||
REVIEW_SCORE_INVALID(3303, "评分无效"),
|
|
||||||
REVIEW_NOT_STARTED(3304, "评审未开始"),
|
|
||||||
|
|
||||||
TEAM_NOT_FOUND(3401, "团队不存在"),
|
|
||||||
TEAM_MEMBER_FULL(3402, "团队成员已满"),
|
|
||||||
TEAM_MEMBER_DUPLICATE(3403, "用户已在团队中"),
|
|
||||||
|
|
||||||
JUDGE_NOT_FOUND(3501, "评委不存在"),
|
|
||||||
JUDGE_ALREADY_ASSIGNED(3502, "评委已分配"),
|
|
||||||
|
|
||||||
AWARD_NOT_FOUND(3601, "奖项不存在"),
|
|
||||||
AWARD_ALREADY_SET(3602, "奖项已设置"),
|
|
||||||
|
|
||||||
NOTICE_NOT_FOUND(3701, "公告不存在"),
|
|
||||||
|
|
||||||
// ========== 学校业务错误(4xxx) ==========
|
|
||||||
SCHOOL_NOT_FOUND(4001, "学校不存在"),
|
|
||||||
SCHOOL_CODE_DUPLICATE(4002, "学校编码已存在"),
|
|
||||||
|
|
||||||
GRADE_NOT_FOUND(4101, "年级不存在"),
|
|
||||||
GRADE_DUPLICATE(4102, "年级名称已存在"),
|
|
||||||
|
|
||||||
CLASS_NOT_FOUND(4201, "班级不存在"),
|
|
||||||
CLASS_DUPLICATE(4202, "班级名称已存在"),
|
|
||||||
|
|
||||||
TEACHER_NOT_FOUND(4301, "教师不存在"),
|
|
||||||
STUDENT_NOT_FOUND(4401, "学生不存在");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误码
|
|
||||||
*/
|
|
||||||
private final Integer code;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误消息
|
|
||||||
*/
|
|
||||||
private final String message;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
package com.lesingle.creation.common.core;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
|
||||||
import com.lesingle.creation.common.constant.ErrorCode;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 统一响应结果类
|
|
||||||
*
|
|
||||||
* @param <T> 数据类型
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class Result<T> implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 响应码
|
|
||||||
*/
|
|
||||||
private Integer code;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 响应消息
|
|
||||||
*/
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 响应数据
|
|
||||||
*/
|
|
||||||
private T data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 时间戳
|
|
||||||
*/
|
|
||||||
private Long timestamp;
|
|
||||||
|
|
||||||
public Result() {
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result(Integer code, String message, T data) {
|
|
||||||
this.code = code;
|
|
||||||
this.message = message;
|
|
||||||
this.data = data;
|
|
||||||
this.timestamp = System.currentTimeMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功响应(无数据)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> success() {
|
|
||||||
return new Result<>(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMessage(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功响应(带数据)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> success(T data) {
|
|
||||||
return new Result<>(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMessage(), data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成功响应(自定义消息)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> success(String message, T data) {
|
|
||||||
return new Result<>(ErrorCode.SUCCESS.getCode(), message, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败响应
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> fail(String message) {
|
|
||||||
return new Result<>(ErrorCode.INTERNAL_ERROR.getCode(), message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败响应(指定错误码)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> fail(ErrorCode errorCode) {
|
|
||||||
return new Result<>(errorCode.getCode(), errorCode.getMessage(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败响应(指定错误码和消息)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> fail(ErrorCode errorCode, String message) {
|
|
||||||
return new Result<>(errorCode.getCode(), message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败响应(指定错误码和数据)
|
|
||||||
*/
|
|
||||||
public static <T> Result<T> fail(Integer code, String message) {
|
|
||||||
return new Result<>(code, message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否成功
|
|
||||||
*/
|
|
||||||
public boolean isSuccess() {
|
|
||||||
return ErrorCode.SUCCESS.getCode().equals(this.code);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return JSON.toJSONString(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AI3D 生成类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AI3DGenerateTypeEnum {
|
|
||||||
|
|
||||||
NORMAL("Normal", "带纹理"),
|
|
||||||
GEOMETRY("Geometry", "白模"),
|
|
||||||
LOW_POLY("LowPoly", "低多边形"),
|
|
||||||
SKETCH("Sketch", "草图");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static AI3DGenerateTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return NORMAL;
|
|
||||||
}
|
|
||||||
for (AI3DGenerateTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NORMAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AI3D 任务状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AI3DTaskStatusEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待处理"),
|
|
||||||
PROCESSING("processing", "处理中"),
|
|
||||||
COMPLETED("completed", "已完成"),
|
|
||||||
FAILED("failed", "失败"),
|
|
||||||
TIMEOUT("timeout", "超时");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static AI3DTaskStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (AI3DTaskStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评审分配状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AssignmentStatusEnum {
|
|
||||||
|
|
||||||
ASSIGNED("assigned", "已分配"),
|
|
||||||
REVIEWING("reviewing", "评审中"),
|
|
||||||
COMPLETED("completed", "已完成");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static AssignmentStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return ASSIGNED;
|
|
||||||
}
|
|
||||||
for (AssignmentStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ASSIGNED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 奖项等级枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum AwardLevelEnum {
|
|
||||||
|
|
||||||
FIRST("first", "一等奖"),
|
|
||||||
SECOND("second", "二等奖"),
|
|
||||||
THIRD("third", "三等奖"),
|
|
||||||
EXCELLENT("excellent", "优秀奖"),
|
|
||||||
NONE("none", "无奖项");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static AwardLevelEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return NONE;
|
|
||||||
}
|
|
||||||
for (AwardLevelEnum level : values()) {
|
|
||||||
if (level.getCode().equals(code)) {
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评论状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum CommentStatusEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待审核"),
|
|
||||||
APPROVED("approved", "已通过"),
|
|
||||||
REJECTED("rejected", "已拒绝");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static CommentStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (CommentStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ContestStateEnum {
|
|
||||||
|
|
||||||
UNPUBLISHED("unpublished", "未发布"),
|
|
||||||
PUBLISHED("published", "已发布"),
|
|
||||||
REGISTERING("registering", "报名中"),
|
|
||||||
SUBMITTING("submitting", "作品提交中"),
|
|
||||||
REVIEWING("reviewing", "评审中"),
|
|
||||||
FINISHED("finished", "已完结");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ContestStateEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return UNPUBLISHED;
|
|
||||||
}
|
|
||||||
for (ContestStateEnum state : values()) {
|
|
||||||
if (state.getCode().equals(code)) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNPUBLISHED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛进度状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ContestStatusEnum {
|
|
||||||
|
|
||||||
ONGOING("ongoing", "进行中"),
|
|
||||||
FINISHED("finished", "已完结");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ContestStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return ONGOING;
|
|
||||||
}
|
|
||||||
for (ContestStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ONGOING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ContestTypeEnum {
|
|
||||||
|
|
||||||
INDIVIDUAL("individual", "个人赛"),
|
|
||||||
TEAM("team", "团队赛");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ContestTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return INDIVIDUAL;
|
|
||||||
}
|
|
||||||
for (ContestTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return INDIVIDUAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 性别枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum GenderEnum {
|
|
||||||
|
|
||||||
MALE("male", "男"),
|
|
||||||
FEMALE("female", "女");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static GenderEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for (GenderEnum gender : values()) {
|
|
||||||
if (gender.getCode().equals(code)) {
|
|
||||||
return gender;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据数字代码获取性别
|
|
||||||
* @param code 1-男,2-女
|
|
||||||
* @return 性别枚举
|
|
||||||
*/
|
|
||||||
public static GenderEnum getByIntCode(Integer code) {
|
|
||||||
if (code == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (code == 1) {
|
|
||||||
return MALE;
|
|
||||||
} else if (code == 2) {
|
|
||||||
return FEMALE;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作业状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum HomeworkStatusEnum {
|
|
||||||
|
|
||||||
UNPUBLISHED("unpublished", "未发布"),
|
|
||||||
PUBLISHED("published", "已发布");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static HomeworkStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return UNPUBLISHED;
|
|
||||||
}
|
|
||||||
for (HomeworkStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return UNPUBLISHED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作业提交状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum HomeworkSubmissionStatusEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待评审"),
|
|
||||||
REVIEWED("reviewed", "已评审"),
|
|
||||||
REJECTED("rejected", "已拒绝");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static HomeworkSubmissionStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (HomeworkSubmissionStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参与者类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ParticipantTypeEnum {
|
|
||||||
|
|
||||||
SELF("self", "自己"),
|
|
||||||
CHILD("child", "代子女");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ParticipantTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return SELF;
|
|
||||||
}
|
|
||||||
for (ParticipantTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SELF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 报名任务状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum RegisterTaskStateEnum {
|
|
||||||
|
|
||||||
STARTED("started", "已开始"),
|
|
||||||
CLOSED("closed", "已截止");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static RegisterTaskStateEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return STARTED;
|
|
||||||
}
|
|
||||||
for (RegisterTaskStateEnum state : values()) {
|
|
||||||
if (state.getCode().equals(code)) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return STARTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 报名状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum RegistrationStateEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待审核"),
|
|
||||||
PASSED("passed", "已通过"),
|
|
||||||
REJECTED("rejected", "已拒绝"),
|
|
||||||
WITHDRAWN("withdrawn", "已撤回");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static RegistrationStateEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (RegistrationStateEnum state : values()) {
|
|
||||||
if (state.getCode().equals(code)) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 举报处理动作枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ReportActionEnum {
|
|
||||||
|
|
||||||
TAKE_DOWN("takedown", "下架"),
|
|
||||||
WARN("warn", "警告"),
|
|
||||||
BAN("ban", "封禁"),
|
|
||||||
IGNORE("ignore", "忽略");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ReportActionEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return IGNORE;
|
|
||||||
}
|
|
||||||
for (ReportActionEnum action : values()) {
|
|
||||||
if (action.getCode().equals(code)) {
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IGNORE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 举报状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ReportStatusEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待处理"),
|
|
||||||
HANDLED("handled", "已处理"),
|
|
||||||
IGNORED("ignored", "已忽略");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ReportStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (ReportStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 评审状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ReviewStatusEnum {
|
|
||||||
|
|
||||||
PENDING("pending", "待评审"),
|
|
||||||
REVIEWING("reviewing", "评审中"),
|
|
||||||
COMPLETED("completed", "已完成");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ReviewStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
for (ReviewStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PENDING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 团队角色枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum TeamRoleEnum {
|
|
||||||
|
|
||||||
MEMBER("member", "队员"),
|
|
||||||
LEADER("leader", "队长"),
|
|
||||||
MENTOR("mentor", "指导老师");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static TeamRoleEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return MEMBER;
|
|
||||||
}
|
|
||||||
for (TeamRoleEnum role : values()) {
|
|
||||||
if (role.getCode().equals(code)) {
|
|
||||||
return role;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MEMBER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 租户类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum TenantTypeEnum {
|
|
||||||
|
|
||||||
PLATFORM("platform", "平台"),
|
|
||||||
LIBRARY("library", "图书馆"),
|
|
||||||
KINDERGARTEN("kindergarten", "幼儿园"),
|
|
||||||
SCHOOL("school", "学校"),
|
|
||||||
INSTITUTION("institution", "机构"),
|
|
||||||
OTHER("other", "其他");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static TenantTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return OTHER;
|
|
||||||
}
|
|
||||||
for (TenantTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OTHER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户来源枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum UserSourceEnum {
|
|
||||||
|
|
||||||
ADMIN_CREATED("admin_created", "管理员创建"),
|
|
||||||
SELF_REGISTERED("self_registered", "自主注册"),
|
|
||||||
CHILD_MIGRATED("child_migrated", "子女账号迁移");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static UserSourceEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return ADMIN_CREATED;
|
|
||||||
}
|
|
||||||
for (UserSourceEnum source : values()) {
|
|
||||||
if (source.getCode().equals(code)) {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ADMIN_CREATED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum UserStatusEnum {
|
|
||||||
|
|
||||||
ENABLED("enabled", "启用"),
|
|
||||||
DISABLED("disabled", "禁用");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static UserStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return ENABLED;
|
|
||||||
}
|
|
||||||
for (UserStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ENABLED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum UserTypeEnum {
|
|
||||||
|
|
||||||
ADULT("adult", "成人"),
|
|
||||||
CHILD("child", "子女");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static UserTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return ADULT;
|
|
||||||
}
|
|
||||||
for (UserTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ADULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UGC 作品状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum UserWorkStatusEnum {
|
|
||||||
|
|
||||||
DRAFT("draft", "草稿"),
|
|
||||||
PENDING_REVIEW("pending_review", "待审核"),
|
|
||||||
PUBLISHED("published", "已发布"),
|
|
||||||
REJECTED("rejected", "已拒绝"),
|
|
||||||
TAKEN_DOWN("taken_down", "已下架");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static UserWorkStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return DRAFT;
|
|
||||||
}
|
|
||||||
for (UserWorkStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return DRAFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 有效状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ValidStateEnum {
|
|
||||||
|
|
||||||
VALID(1, "有效"),
|
|
||||||
INVALID(2, "失效");
|
|
||||||
|
|
||||||
private final Integer code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static ValidStateEnum getByCode(Integer code) {
|
|
||||||
if (code == null) {
|
|
||||||
return VALID;
|
|
||||||
}
|
|
||||||
for (ValidStateEnum state : values()) {
|
|
||||||
if (state.getCode().equals(code)) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return VALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 可见性枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum VisibilityEnum {
|
|
||||||
|
|
||||||
PUBLIC("public", "公开"),
|
|
||||||
PRIVATE("private", "私有"),
|
|
||||||
DESIGNATED("designated", "指定"),
|
|
||||||
INTERNAL("internal", "内部"),
|
|
||||||
FRIENDS("friends", "好友可见");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static VisibilityEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return PRIVATE;
|
|
||||||
}
|
|
||||||
for (VisibilityEnum visibility : values()) {
|
|
||||||
if (visibility.getCode().equals(code)) {
|
|
||||||
return visibility;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PRIVATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作品状态枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum WorkStatusEnum {
|
|
||||||
|
|
||||||
SUBMITTED("submitted", "已提交"),
|
|
||||||
LOCKED("locked", "已锁定"),
|
|
||||||
REVIEWING("reviewing", "评审中"),
|
|
||||||
REJECTED("rejected", "已拒绝"),
|
|
||||||
ACCEPTED("accepted", "已接受");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static WorkStatusEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return SUBMITTED;
|
|
||||||
}
|
|
||||||
for (WorkStatusEnum status : values()) {
|
|
||||||
if (status.getCode().equals(code)) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return SUBMITTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
package com.lesingle.creation.common.enums;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作品类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum WorkTypeEnum {
|
|
||||||
|
|
||||||
IMAGE("image", "图片"),
|
|
||||||
VIDEO("video", "视频"),
|
|
||||||
DOCUMENT("document", "文档"),
|
|
||||||
CODE("code", "代码"),
|
|
||||||
OTHER("other", "其他");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
public static WorkTypeEnum getByCode(String code) {
|
|
||||||
if (code == null) {
|
|
||||||
return OTHER;
|
|
||||||
}
|
|
||||||
for (WorkTypeEnum type : values()) {
|
|
||||||
if (type.getCode().equals(code)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return OTHER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package com.lesingle.creation.common.exception;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.constant.ErrorCode;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 业务异常类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public class BusinessException extends RuntimeException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误码
|
|
||||||
*/
|
|
||||||
private final Integer code;
|
|
||||||
|
|
||||||
public BusinessException(String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = ErrorCode.INTERNAL_ERROR.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(Integer code, String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(ErrorCode errorCode) {
|
|
||||||
super(errorCode.getMessage());
|
|
||||||
this.code = errorCode.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(ErrorCode errorCode, String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = errorCode.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
this.code = ErrorCode.INTERNAL_ERROR.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(ErrorCode errorCode, Throwable cause) {
|
|
||||||
super(errorCode.getMessage(), cause);
|
|
||||||
this.code = errorCode.getCode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,199 +0,0 @@
|
|||||||
package com.lesingle.creation.common.exception;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.constant.ErrorCode;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
|
||||||
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
|
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.validation.BindException;
|
|
||||||
import org.springframework.validation.FieldError;
|
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
|
||||||
import org.springframework.web.bind.MissingPathVariableException;
|
|
||||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
||||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
|
||||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
|
||||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
|
||||||
|
|
||||||
import java.sql.SQLIntegrityConstraintViolationException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全局异常处理器
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@RestControllerAdvice
|
|
||||||
public class GlobalExceptionHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理业务异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(BusinessException.class)
|
|
||||||
@ResponseStatus(HttpStatus.OK)
|
|
||||||
public Result<?> handleBusinessException(BusinessException e) {
|
|
||||||
log.warn("业务异常:{}", e.getMessage());
|
|
||||||
return Result.fail(e.getCode(), e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理参数校验异常(@Validated)
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
|
||||||
FieldError fieldError = e.getBindingResult().getFieldError();
|
|
||||||
String message = fieldError != null ? fieldError.getDefaultMessage() : "参数校验失败";
|
|
||||||
log.warn("参数校验异常:{}", message);
|
|
||||||
return Result.fail(ErrorCode.PARAMS_ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理参数绑定异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(BindException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleBindException(BindException e) {
|
|
||||||
FieldError fieldError = e.getBindingResult().getFieldError();
|
|
||||||
String message = fieldError != null ? fieldError.getDefaultMessage() : "参数绑定失败";
|
|
||||||
log.warn("参数绑定异常:{}", message);
|
|
||||||
return Result.fail(ErrorCode.PARAMS_ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理参数类型不匹配异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
|
|
||||||
String message = String.format("参数 [%s] 类型错误,应为:%s", e.getName(), e.getRequiredType().getSimpleName());
|
|
||||||
log.warn("参数类型错误:{}", message);
|
|
||||||
return Result.fail(ErrorCode.PARAMS_ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理缺少请求参数异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(MissingServletRequestParameterException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
|
|
||||||
String message = String.format("缺少必填参数:%s", e.getParameterName());
|
|
||||||
log.warn("缺少请求参数:{}", message);
|
|
||||||
return Result.fail(ErrorCode.PARAMS_ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理缺少路径参数异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(MissingPathVariableException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleMissingPathVariableException(MissingPathVariableException e) {
|
|
||||||
String message = String.format("缺少路径参数:%s", e.getVariableName());
|
|
||||||
log.warn("缺少路径参数:{}", message);
|
|
||||||
return Result.fail(ErrorCode.PARAMS_ERROR, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理认证异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(AuthenticationException.class)
|
|
||||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
|
||||||
public Result<?> handleAuthenticationException(AuthenticationException e) {
|
|
||||||
String message = "认证失败:" + e.getMessage();
|
|
||||||
log.warn("认证异常:{}", message);
|
|
||||||
return Result.fail(ErrorCode.UNAUTHORIZED, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理凭证错误(如密码错误)
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(BadCredentialsException.class)
|
|
||||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
|
||||||
public Result<?> handleBadCredentialsException(BadCredentialsException e) {
|
|
||||||
log.warn("凭证错误:{}", e.getMessage());
|
|
||||||
return Result.fail(ErrorCode.UNAUTHORIZED, "用户名或密码错误");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理认证凭据未找到异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(AuthenticationCredentialsNotFoundException.class)
|
|
||||||
@ResponseStatus(HttpStatus.UNAUTHORIZED)
|
|
||||||
public Result<?> handleAuthenticationCredentialsNotFoundException(AuthenticationCredentialsNotFoundException e) {
|
|
||||||
log.warn("未提供认证凭据:{}", e.getMessage());
|
|
||||||
return Result.fail(ErrorCode.UNAUTHORIZED, "未登录或 Token 已过期");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理授权异常(权限不足)
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(AccessDeniedException.class)
|
|
||||||
@ResponseStatus(HttpStatus.FORBIDDEN)
|
|
||||||
public Result<?> handleAccessDeniedException(AccessDeniedException e) {
|
|
||||||
log.warn("权限不足:{}", e.getMessage());
|
|
||||||
return Result.fail(ErrorCode.FORBIDDEN, "没有访问权限");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理资源不存在异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(NoHandlerFoundException.class)
|
|
||||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
|
||||||
public Result<?> handleNoHandlerFoundException(NoHandlerFoundException e) {
|
|
||||||
String message = String.format("资源不存在:%s %s", e.getHttpMethod(), e.getRequestURL());
|
|
||||||
log.warn("资源不存在:{}", message);
|
|
||||||
return Result.fail(ErrorCode.NOT_FOUND, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理请求方法不支持异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
|
||||||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
|
||||||
public Result<?> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
|
|
||||||
String message = String.format("不支持的请求方法:%s", e.getMethod());
|
|
||||||
log.warn("请求方法不支持:{}", message);
|
|
||||||
return Result.fail(ErrorCode.METHOD_NOT_ALLOWED, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理文件上传大小超限异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
|
|
||||||
log.warn("文件大小超限:{}", e.getMessage());
|
|
||||||
return Result.fail(ErrorCode.FILE_UPLOAD_ERROR, "上传文件大小超过限制");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理数据库唯一约束冲突异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
|
|
||||||
@ResponseStatus(HttpStatus.CONFLICT)
|
|
||||||
public Result<?> handleSQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
|
|
||||||
String message = e.getMessage();
|
|
||||||
if (message != null && message.contains("Duplicate entry")) {
|
|
||||||
message = "数据已存在,请勿重复添加";
|
|
||||||
}
|
|
||||||
log.warn("数据库约束冲突:{}", message);
|
|
||||||
return Result.fail(ErrorCode.DATA_ALREADY_EXISTS, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理其他未知异常
|
|
||||||
*/
|
|
||||||
@ExceptionHandler(Exception.class)
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
public Result<?> handleException(Exception e) {
|
|
||||||
log.error("系统内部错误:", e);
|
|
||||||
return Result.fail(ErrorCode.INTERNAL_ERROR, "系统内部错误:" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
package com.lesingle.creation.common.filter;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.config.JwtProperties;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.common.util.JwtTokenUtil;
|
|
||||||
import jakarta.servlet.FilterChain;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT 认证过滤器
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|
||||||
|
|
||||||
private final JwtTokenUtil jwtTokenUtil;
|
|
||||||
private final UserDetailsService userDetailsService;
|
|
||||||
private final JwtProperties jwtProperties;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request,
|
|
||||||
HttpServletResponse response,
|
|
||||||
FilterChain filterChain) throws ServletException, IOException {
|
|
||||||
// 从请求头中获取 Token
|
|
||||||
String token = getTokenFromRequest(request);
|
|
||||||
|
|
||||||
if (StringUtils.hasText(token)) {
|
|
||||||
try {
|
|
||||||
// 验证 Token
|
|
||||||
String username = jwtTokenUtil.getUsernameFromToken(token);
|
|
||||||
|
|
||||||
if (StringUtils.hasText(username) && SecurityContextHolder.getContext().getAuthentication() == null) {
|
|
||||||
// 从数据库加载用户信息(UserDetailsServiceImpl 返回的是 UserPrincipal)
|
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
|
||||||
|
|
||||||
// 验证 Token 是否有效
|
|
||||||
if (jwtTokenUtil.isTokenValid(token, userDetails)) {
|
|
||||||
// 创建认证对象(principal 使用 UserPrincipal 类型)
|
|
||||||
UsernamePasswordAuthenticationToken authentication =
|
|
||||||
new UsernamePasswordAuthenticationToken(
|
|
||||||
userDetails, // 这就是 UserPrincipal 类型
|
|
||||||
null,
|
|
||||||
userDetails.getAuthorities()
|
|
||||||
);
|
|
||||||
authentication.setDetails(
|
|
||||||
new WebAuthenticationDetailsSource().buildDetails(request)
|
|
||||||
);
|
|
||||||
// 设置到 SecurityContext
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
|
||||||
log.debug("用户认证成功:{}, userId={}",
|
|
||||||
userDetails.getUsername(),
|
|
||||||
userDetails instanceof UserPrincipal ? ((UserPrincipal) userDetails).getUserId() : "unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Token 验证失败:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filterChain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从请求头中获取 Token
|
|
||||||
*/
|
|
||||||
private String getTokenFromRequest(HttpServletRequest request) {
|
|
||||||
String bearerToken = request.getHeader(jwtProperties.getHeader());
|
|
||||||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(jwtProperties.getTokenPrefix())) {
|
|
||||||
return bearerToken.substring(jwtProperties.getTokenPrefix().length()).trim();
|
|
||||||
}
|
|
||||||
// 也支持 token 作为查询参数
|
|
||||||
String token = request.getParameter("token");
|
|
||||||
if (StringUtils.hasText(token)) {
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
package com.lesingle.creation.common.handler;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
|
||||||
import com.lesingle.creation.util.SecurityUtils;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.ibatis.reflection.MetaObject;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MyBatis-Plus 自动填充处理器
|
|
||||||
* <p>
|
|
||||||
* 自动填充创建人、创建时间、更新人、更新时间字段
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
|
||||||
|
|
||||||
private final SecurityUtils securityUtils;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertFill(MetaObject metaObject) {
|
|
||||||
log.debug("执行插入操作,自动填充审计字段");
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
|
|
||||||
// 填充创建时间
|
|
||||||
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, now);
|
|
||||||
|
|
||||||
// 填充创建人(从 UserContext 获取当前用户名)
|
|
||||||
this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUsername());
|
|
||||||
|
|
||||||
// 填充更新时间
|
|
||||||
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, now);
|
|
||||||
|
|
||||||
// 填充更新人
|
|
||||||
this.strictInsertFill(metaObject, "updateBy", String.class, getCurrentUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateFill(MetaObject metaObject) {
|
|
||||||
log.debug("执行更新操作,自动填充审计字段");
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
|
|
||||||
// 填充更新时间
|
|
||||||
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, now);
|
|
||||||
|
|
||||||
// 填充更新人
|
|
||||||
this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前登录用户名
|
|
||||||
* 从 SecurityUtils 获取,非登录场景返回 "system"
|
|
||||||
*/
|
|
||||||
private String getCurrentUsername() {
|
|
||||||
try {
|
|
||||||
return securityUtils.getCurrentUsernameStr();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("获取当前用户名失败,使用默认值:{}", e.getMessage());
|
|
||||||
return "system";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
package com.lesingle.creation.common.security;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户 Principal 实现类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
public class UserPrincipal implements UserDetails {
|
|
||||||
|
|
||||||
private final Long userId;
|
|
||||||
private final String username; // 用户名(用于显示)
|
|
||||||
private final String password;
|
|
||||||
private final Collection<? extends GrantedAuthority> authorities;
|
|
||||||
private final Long tenantId;
|
|
||||||
private final String tenantCode; // 租户编码
|
|
||||||
private final boolean isSuperTenant; // 是否超级租户
|
|
||||||
|
|
||||||
public UserPrincipal(Long userId, String username, String password,
|
|
||||||
Collection<? extends GrantedAuthority> authorities,
|
|
||||||
Long tenantId, String tenantCode, boolean isSuperTenant) {
|
|
||||||
this.userId = userId;
|
|
||||||
this.username = username;
|
|
||||||
this.password = password;
|
|
||||||
this.authorities = authorities;
|
|
||||||
this.tenantId = tenantId;
|
|
||||||
this.tenantCode = tenantCode;
|
|
||||||
this.isSuperTenant = isSuperTenant;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
|
||||||
return this.authorities;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPassword() {
|
|
||||||
return this.password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername() {
|
|
||||||
return String.valueOf(this.userId); // 返回用户 ID 字符串,方便 SecurityUtils 获取
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonExpired() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonLocked() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCredentialsNonExpired() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取显示用户名(用于日志等)
|
|
||||||
*
|
|
||||||
* @return 显示用户名
|
|
||||||
*/
|
|
||||||
public String getDisplayName() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
package com.lesingle.creation.common.util;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.config.JwtProperties;
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
import io.jsonwebtoken.Jwts;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JWT Token 工具类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class JwtTokenUtil {
|
|
||||||
|
|
||||||
private final JwtProperties jwtProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取密钥
|
|
||||||
*/
|
|
||||||
private SecretKey getSigningKey() {
|
|
||||||
byte[] keyBytes = jwtProperties.getSecret().getBytes(StandardCharsets.UTF_8);
|
|
||||||
return Keys.hmacShaKeyFor(keyBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 Token 中获取用户名
|
|
||||||
*/
|
|
||||||
public String getUsernameFromToken(String token) {
|
|
||||||
return getClaimFromToken(token, Claims::getSubject);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 Token 中获取用户 ID
|
|
||||||
*
|
|
||||||
* @param token JWT Token
|
|
||||||
* @return 用户 ID
|
|
||||||
*/
|
|
||||||
public Long getUserIdFromToken(String token) {
|
|
||||||
String username = getUsernameFromToken(token);
|
|
||||||
try {
|
|
||||||
return Long.parseLong(username);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
log.warn("无法解析用户 ID:{}", username);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 Token 中获取指定声明
|
|
||||||
*/
|
|
||||||
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
|
||||||
final Claims claims = getAllClaimsFromToken(token);
|
|
||||||
return claimsResolver.apply(claims);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有声明
|
|
||||||
*/
|
|
||||||
private Claims getAllClaimsFromToken(String token) {
|
|
||||||
return Jwts.parser()
|
|
||||||
.verifyWith(getSigningKey())
|
|
||||||
.build()
|
|
||||||
.parseSignedClaims(token)
|
|
||||||
.getPayload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 Token
|
|
||||||
*/
|
|
||||||
public String generateToken(String username) {
|
|
||||||
Map<String, Object> claims = new HashMap<>();
|
|
||||||
return createToken(claims, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成带额外信息的 Token
|
|
||||||
*/
|
|
||||||
public String generateToken(String username, Map<String, Object> claims) {
|
|
||||||
return createToken(claims, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成带租户信息的 Token
|
|
||||||
*
|
|
||||||
* @param userId 用户 ID
|
|
||||||
* @param tenantId 租户 ID
|
|
||||||
* @param tenantCode 租户编码
|
|
||||||
* @return JWT Token
|
|
||||||
*/
|
|
||||||
public String generateToken(Long userId, Long tenantId, String tenantCode) {
|
|
||||||
Map<String, Object> claims = new HashMap<>();
|
|
||||||
claims.put("tenantId", tenantId);
|
|
||||||
claims.put("tenantCode", tenantCode);
|
|
||||||
return createToken(claims, String.valueOf(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成带用户名的 Token(用于公众用户)
|
|
||||||
*
|
|
||||||
* @param userId 用户 ID
|
|
||||||
* @param username 用户名
|
|
||||||
* @return JWT Token
|
|
||||||
*/
|
|
||||||
public String generateToken(Long userId, String username) {
|
|
||||||
Map<String, Object> claims = new HashMap<>();
|
|
||||||
claims.put("userId", userId);
|
|
||||||
return createToken(claims, username);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 Token 中获取租户 ID
|
|
||||||
*
|
|
||||||
* @param token JWT Token
|
|
||||||
* @return 租户 ID
|
|
||||||
*/
|
|
||||||
public Long getTenantIdFromToken(String token) {
|
|
||||||
return getClaimFromToken(token, claims -> claims.get("tenantId", Long.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 Token 中获取租户编码
|
|
||||||
*
|
|
||||||
* @param token JWT Token
|
|
||||||
* @return 租户编码
|
|
||||||
*/
|
|
||||||
public String getTenantCodeFromToken(String token) {
|
|
||||||
return getClaimFromToken(token, claims -> claims.get("tenantCode", String.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建 Token
|
|
||||||
*/
|
|
||||||
private String createToken(Map<String, Object> claims, String subject) {
|
|
||||||
Date now = new Date();
|
|
||||||
Date expirationDate = new Date(now.getTime() + jwtProperties.getExpiration());
|
|
||||||
|
|
||||||
return Jwts.builder()
|
|
||||||
.claims(claims)
|
|
||||||
.subject(subject)
|
|
||||||
.issuedAt(now)
|
|
||||||
.expiration(expirationDate)
|
|
||||||
.signWith(getSigningKey())
|
|
||||||
.compact();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证 Token 是否有效
|
|
||||||
*/
|
|
||||||
public boolean isTokenValid(String token, UserDetails userDetails) {
|
|
||||||
final String username = getUsernameFromToken(token);
|
|
||||||
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断 Token 是否过期
|
|
||||||
*/
|
|
||||||
private boolean isTokenExpired(String token) {
|
|
||||||
return extractExpiration(token).before(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 Token 过期时间
|
|
||||||
*/
|
|
||||||
public Date extractExpiration(String token) {
|
|
||||||
return getClaimFromToken(token, Claims::getExpiration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,274 +0,0 @@
|
|||||||
package com.lesingle.creation.common.util;
|
|
||||||
|
|
||||||
import com.aliyun.oss.OSS;
|
|
||||||
import com.aliyun.oss.OSSClientBuilder;
|
|
||||||
import com.aliyun.oss.model.PutObjectRequest;
|
|
||||||
import com.lesingle.creation.common.config.OssProperties;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 阿里云 OSS 文件上传工具类
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class OssUtil {
|
|
||||||
|
|
||||||
private final OssProperties ossProperties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 允许上传的文件类型
|
|
||||||
*/
|
|
||||||
private static final List<String> ALLOWED_TYPES = Arrays.asList(
|
|
||||||
"image/jpeg", "image/png", "image/gif", "image/webp",
|
|
||||||
"application/pdf", "application/msword",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最大文件大小:100MB
|
|
||||||
*/
|
|
||||||
private static final long MAX_FILE_SIZE = 100 * 1024 * 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件
|
|
||||||
*
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @return 文件访问 URL
|
|
||||||
* @throws IOException 上传失败抛出异常
|
|
||||||
*/
|
|
||||||
public String upload(MultipartFile file) throws IOException {
|
|
||||||
// 校验文件
|
|
||||||
validateFile(file);
|
|
||||||
|
|
||||||
// 生成文件名
|
|
||||||
String fileName = generateFileName(file.getOriginalFilename());
|
|
||||||
|
|
||||||
// 生成文件路径(按日期分目录)
|
|
||||||
String objectKey = buildObjectKey(fileName);
|
|
||||||
|
|
||||||
// 获取 OSS 客户端
|
|
||||||
OSS ossClient = createOssClient();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 上传文件
|
|
||||||
InputStream inputStream = file.getInputStream();
|
|
||||||
PutObjectRequest putObjectRequest = new PutObjectRequest(
|
|
||||||
ossProperties.getBucketName(),
|
|
||||||
objectKey,
|
|
||||||
inputStream
|
|
||||||
);
|
|
||||||
ossClient.putObject(putObjectRequest);
|
|
||||||
|
|
||||||
// 返回文件 URL
|
|
||||||
String fileUrl = getFileUrl(objectKey);
|
|
||||||
log.info("文件上传成功:{}, URL: {}", objectKey, fileUrl);
|
|
||||||
return fileUrl;
|
|
||||||
} finally {
|
|
||||||
// 关闭客户端
|
|
||||||
ossClient.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件(自定义路径)
|
|
||||||
*
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @param customPath 自定义路径(如:avatars/)
|
|
||||||
* @return 文件访问 URL
|
|
||||||
* @throws IOException 上传失败抛出异常
|
|
||||||
*/
|
|
||||||
public String upload(MultipartFile file, String customPath) throws IOException {
|
|
||||||
// 校验文件
|
|
||||||
validateFile(file);
|
|
||||||
|
|
||||||
// 生成文件名
|
|
||||||
String fileName = generateFileName(file.getOriginalFilename());
|
|
||||||
|
|
||||||
// 生成文件路径
|
|
||||||
String objectKey = customPath + (customPath.endsWith("/") ? "" : "/") + fileName;
|
|
||||||
|
|
||||||
// 获取 OSS 客户端
|
|
||||||
OSS ossClient = createOssClient();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 上传文件
|
|
||||||
InputStream inputStream = file.getInputStream();
|
|
||||||
PutObjectRequest putObjectRequest = new PutObjectRequest(
|
|
||||||
ossProperties.getBucketName(),
|
|
||||||
objectKey,
|
|
||||||
inputStream
|
|
||||||
);
|
|
||||||
ossClient.putObject(putObjectRequest);
|
|
||||||
|
|
||||||
// 返回文件 URL
|
|
||||||
String fileUrl = getFileUrl(objectKey);
|
|
||||||
log.info("文件上传成功:{}, URL: {}", objectKey, fileUrl);
|
|
||||||
return fileUrl;
|
|
||||||
} finally {
|
|
||||||
// 关闭客户端
|
|
||||||
ossClient.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传字节数组
|
|
||||||
*
|
|
||||||
* @param bytes 文件字节数组
|
|
||||||
* @param fileName 文件名
|
|
||||||
* @param customPath 自定义路径
|
|
||||||
* @return 文件访问 URL
|
|
||||||
* @throws IOException 上传失败抛出异常
|
|
||||||
*/
|
|
||||||
public String upload(byte[] bytes, String fileName, String customPath) throws IOException {
|
|
||||||
String finalFileName = generateFileName(fileName);
|
|
||||||
String objectKey = customPath + (customPath.endsWith("/") ? "" : "/") + finalFileName;
|
|
||||||
|
|
||||||
OSS ossClient = createOssClient();
|
|
||||||
try {
|
|
||||||
InputStream inputStream = new ByteArrayInputStream(bytes);
|
|
||||||
PutObjectRequest putObjectRequest = new PutObjectRequest(
|
|
||||||
ossProperties.getBucketName(),
|
|
||||||
objectKey,
|
|
||||||
inputStream
|
|
||||||
);
|
|
||||||
ossClient.putObject(putObjectRequest);
|
|
||||||
|
|
||||||
return getFileUrl(objectKey);
|
|
||||||
} finally {
|
|
||||||
ossClient.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文件
|
|
||||||
*
|
|
||||||
* @param fileUrl 文件 URL
|
|
||||||
*/
|
|
||||||
public void delete(String fileUrl) {
|
|
||||||
String objectKey = extractObjectKey(fileUrl);
|
|
||||||
if (objectKey == null) {
|
|
||||||
log.warn("无法解析文件 Key: {}", fileUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OSS ossClient = createOssClient();
|
|
||||||
try {
|
|
||||||
ossClient.deleteObject(ossProperties.getBucketName(), objectKey);
|
|
||||||
log.info("文件删除成功:{}", objectKey);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("文件删除失败:{}", objectKey, e);
|
|
||||||
} finally {
|
|
||||||
ossClient.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验文件
|
|
||||||
*/
|
|
||||||
private void validateFile(MultipartFile file) {
|
|
||||||
// 检查文件是否为空
|
|
||||||
if (file == null || file.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("上传文件不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查文件大小
|
|
||||||
if (file.getSize() > MAX_FILE_SIZE) {
|
|
||||||
throw new IllegalArgumentException("文件大小超过限制:" + (MAX_FILE_SIZE / 1024 / 1024) + "MB");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查文件类型
|
|
||||||
String contentType = file.getContentType();
|
|
||||||
if (contentType == null || !ALLOWED_TYPES.contains(contentType.toLowerCase())) {
|
|
||||||
throw new IllegalArgumentException("不支持的文件类型:" + contentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成文件名(使用 UUID)
|
|
||||||
*/
|
|
||||||
private String generateFileName(String originalFilename) {
|
|
||||||
if (originalFilename == null || originalFilename.isEmpty()) {
|
|
||||||
return UUID.randomUUID().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
int dotIndex = originalFilename.lastIndexOf(".");
|
|
||||||
if (dotIndex > 0) {
|
|
||||||
String extension = originalFilename.substring(dotIndex);
|
|
||||||
return UUID.randomUUID().toString() + extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UUID.randomUUID().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建文件路径(按日期分目录)
|
|
||||||
*/
|
|
||||||
private String buildObjectKey(String fileName) {
|
|
||||||
String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd/"));
|
|
||||||
String rootDir = ossProperties.getRootDir();
|
|
||||||
|
|
||||||
return (rootDir != null && !rootDir.isEmpty() ? rootDir + "/" : "")
|
|
||||||
+ datePath + fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件访问 URL
|
|
||||||
*/
|
|
||||||
private String getFileUrl(String objectKey) {
|
|
||||||
if (ossProperties.getCustomDomain() != null && !ossProperties.getCustomDomain().isEmpty()) {
|
|
||||||
return ossProperties.getCustomDomain() + "/" + objectKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "https://" + ossProperties.getBucketName() + "." + ossProperties.getEndpoint() + "/" + objectKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从 URL 中提取 Object Key
|
|
||||||
*/
|
|
||||||
private String extractObjectKey(String fileUrl) {
|
|
||||||
if (fileUrl == null || fileUrl.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从自定义域名解析
|
|
||||||
if (ossProperties.getCustomDomain() != null && fileUrl.startsWith(ossProperties.getCustomDomain())) {
|
|
||||||
return fileUrl.substring(ossProperties.getCustomDomain().length() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从 OSS 默认域名解析
|
|
||||||
String bucketDomain = ossProperties.getBucketName() + "." + ossProperties.getEndpoint();
|
|
||||||
if (fileUrl.contains(bucketDomain)) {
|
|
||||||
return fileUrl.substring(fileUrl.indexOf(bucketDomain) + bucketDomain.length() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建 OSS 客户端
|
|
||||||
*/
|
|
||||||
private OSS createOssClient() {
|
|
||||||
return new OSSClientBuilder().build(
|
|
||||||
ossProperties.getEndpoint(),
|
|
||||||
ossProperties.getAccessKeyId(),
|
|
||||||
ossProperties.getAccessKeySecret()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package com.lesingle.creation.common.util;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redis 限流工具类
|
|
||||||
* <p>
|
|
||||||
* 基于滑动窗口算法实现限流
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class RateLimiterUtil {
|
|
||||||
|
|
||||||
private static RedisTemplate<String, Object> redisTemplate;
|
|
||||||
|
|
||||||
public RateLimiterUtil(RedisTemplate<String, Object> redisTemplate) {
|
|
||||||
RateLimiterUtil.redisTemplate = redisTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否允许请求通过
|
|
||||||
*
|
|
||||||
* @param key 限流 key
|
|
||||||
* @param time 时间窗口(秒)
|
|
||||||
* @param count 时间窗口内最大请求数
|
|
||||||
* @return true-允许通过,false-拒绝请求
|
|
||||||
*/
|
|
||||||
public static boolean tryAcquire(String key, int time, int count) {
|
|
||||||
try {
|
|
||||||
Long currentCount = redisTemplate.opsForValue().increment(key);
|
|
||||||
if (currentCount == 1) {
|
|
||||||
// 第一次请求,设置过期时间
|
|
||||||
redisTemplate.expire(key, time, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
return currentCount <= count;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Redis 限流异常,key: {}", key, e);
|
|
||||||
// Redis 异常时放行
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前请求数
|
|
||||||
*
|
|
||||||
* @param key 限流 key
|
|
||||||
* @return 当前请求数
|
|
||||||
*/
|
|
||||||
public static Long getCurrentCount(String key) {
|
|
||||||
try {
|
|
||||||
String value = (String) redisTemplate.opsForValue().get(key);
|
|
||||||
return value != null ? Long.parseLong(value) : 0L;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("获取限流计数异常,key: {}", key, e);
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package com.lesingle.creation.common.util;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.IdUtil;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TraceId 工具类
|
|
||||||
* <p>
|
|
||||||
* 用于生成和管理链路追踪 ID,实现全链路日志追踪
|
|
||||||
*
|
|
||||||
* @author lesingle
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public class TraceIdUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MDC 中 TraceId 的 key
|
|
||||||
*/
|
|
||||||
private static final String TRACE_ID_KEY = "traceId";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 TraceId 并放入 MDC
|
|
||||||
*/
|
|
||||||
public static void setTraceId() {
|
|
||||||
MDC.put(TRACE_ID_KEY, IdUtil.fastSimpleUUID());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前 TraceId
|
|
||||||
*
|
|
||||||
* @return TraceId,不存在则返回 "unknown"
|
|
||||||
*/
|
|
||||||
public static String getTraceId() {
|
|
||||||
return MDC.get(TRACE_ID_KEY) != null ? MDC.get(TRACE_ID_KEY) : "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除 MDC 中的 TraceId
|
|
||||||
*/
|
|
||||||
public static void clearTraceId() {
|
|
||||||
MDC.remove(TRACE_ID_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除所有 MDC 内容
|
|
||||||
*/
|
|
||||||
public static void clear() {
|
|
||||||
MDC.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.ai3d.AI3DTaskQueryDTO;
|
|
||||||
import com.lesingle.creation.dto.ai3d.CreateAI3DTaskDTO;
|
|
||||||
import com.lesingle.creation.service.AI3DTaskService;
|
|
||||||
import com.lesingle.creation.vo.ai3d.AI3DTaskVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AI 3D 生成控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "AI 3D 生成")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/ai-3d")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class AI3DTaskController {
|
|
||||||
|
|
||||||
private final AI3DTaskService ai3dTaskService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建 AI 3D 任务")
|
|
||||||
public Result<AI3DTaskVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateAI3DTaskDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
AI3DTaskVO result = ai3dTaskService.create(dto, tenantId, userId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取任务详情")
|
|
||||||
public Result<AI3DTaskVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
AI3DTaskVO result = ai3dTaskService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "分页查询任务列表")
|
|
||||||
public Result<Page<AI3DTaskVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute AI3DTaskQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long userId = userPrincipal.getUserId(); // 查询自己的任务
|
|
||||||
Page<AI3DTaskVO> result = ai3dTaskService.pageQuery(queryDTO, tenantId, userId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}/cancel")
|
|
||||||
@Operation(summary = "取消任务")
|
|
||||||
public Result<Void> cancel(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ai3dTaskService.cancel(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}/retry")
|
|
||||||
@Operation(summary = "重试失败的任务")
|
|
||||||
public Result<AI3DTaskVO> retry(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
AI3DTaskVO result = ai3dTaskService.retry(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除 AI 3D 任务")
|
|
||||||
@PreAuthorize("hasAuthority('ai-3d:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ai3dTaskService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,102 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.auth.LoginDTO;
|
|
||||||
import com.lesingle.creation.service.AuthService;
|
|
||||||
import com.lesingle.creation.vo.auth.LoginResponseVO;
|
|
||||||
import com.lesingle.creation.vo.auth.UserInfoVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证控制器
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Tag(name = "认证管理", description = "用户登录、登出、刷新 Token 等接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/auth")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class AuthController {
|
|
||||||
|
|
||||||
private final AuthService authService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户登录
|
|
||||||
*/
|
|
||||||
@Operation(summary = "用户登录")
|
|
||||||
@PostMapping("/login")
|
|
||||||
public Result<LoginResponseVO> login(@RequestBody LoginDTO loginDTO) {
|
|
||||||
LoginResponseVO response = authService.login(loginDTO);
|
|
||||||
return Result.success(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前用户信息
|
|
||||||
*/
|
|
||||||
@Operation(summary = "获取当前用户信息")
|
|
||||||
@GetMapping("/me")
|
|
||||||
public Result<UserInfoVO> getCurrentUser() {
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
log.debug("Authentication: {}", authentication);
|
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
|
||||||
return Result.fail(401, "未授权");
|
|
||||||
}
|
|
||||||
|
|
||||||
Object principal = authentication.getPrincipal();
|
|
||||||
log.debug("Principal type: {}", principal != null ? principal.getClass().getName() : "null");
|
|
||||||
Long userId;
|
|
||||||
|
|
||||||
if (principal instanceof UserPrincipal) {
|
|
||||||
userId = ((UserPrincipal) principal).getUserId();
|
|
||||||
log.info("UserPrincipal userId: {}", userId);
|
|
||||||
} else if (principal instanceof UserDetails) {
|
|
||||||
// 从 UserDetails 获取用户名,然后通过用户名查询用户
|
|
||||||
String username = ((UserDetails) principal).getUsername();
|
|
||||||
log.debug("Principal 是 UserDetails 类型,用户名:{}", username);
|
|
||||||
// 尝试从 authorities 获取用户 ID(如果有)
|
|
||||||
userId = null;
|
|
||||||
} else {
|
|
||||||
log.warn("无法识别的 Principal 类型:{}", principal != null ? principal.getClass().getName() : "null");
|
|
||||||
return Result.fail(401, "无法获取用户信息");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userId == null) {
|
|
||||||
return Result.fail(401, "无法获取用户 ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
UserInfoVO userInfo = authService.getUserInfo(userId);
|
|
||||||
return Result.success(userInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户登出
|
|
||||||
*/
|
|
||||||
@Operation(summary = "用户登出")
|
|
||||||
@PostMapping("/logout")
|
|
||||||
public Result<Void> logout() {
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
|
|
||||||
String username = ((UserDetails) authentication.getPrincipal()).getUsername();
|
|
||||||
log.info("用户登出:{}", username);
|
|
||||||
}
|
|
||||||
// TODO: 可以将 token 加入黑名单(使用 Redis)
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新 Token
|
|
||||||
*/
|
|
||||||
@Operation(summary = "刷新 Token")
|
|
||||||
@PostMapping("/refresh-token")
|
|
||||||
public Result<LoginResponseVO> refreshToken(@RequestHeader("Authorization") String token) {
|
|
||||||
LoginResponseVO response = authService.refreshToken(token);
|
|
||||||
return Result.success(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,98 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.config.CreateConfigDTO;
|
|
||||||
import com.lesingle.creation.dto.config.UpdateConfigDTO;
|
|
||||||
import com.lesingle.creation.service.ConfigService;
|
|
||||||
import com.lesingle.creation.vo.config.ConfigDetailVO;
|
|
||||||
import com.lesingle.creation.vo.config.ConfigListVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统配置管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "系统配置管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/config")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ConfigController {
|
|
||||||
|
|
||||||
private final ConfigService configService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建配置")
|
|
||||||
@PreAuthorize("hasAuthority('config:create')")
|
|
||||||
public Result<ConfigDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateConfigDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
ConfigDetailVO result = configService.create(dto, tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "配置列表")
|
|
||||||
@PreAuthorize("hasAuthority('config:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<ConfigListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<ConfigListVO> result =
|
|
||||||
configService.pageList(tenantId, page, pageSize);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/key/{key}")
|
|
||||||
@Operation(summary = "根据键查询配置")
|
|
||||||
@PreAuthorize("hasAuthority('config:read')")
|
|
||||||
public Result<ConfigDetailVO> getByKey(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable String key) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ConfigDetailVO result = configService.getByKey(key, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "配置详情")
|
|
||||||
@PreAuthorize("hasAuthority('config:read')")
|
|
||||||
public Result<ConfigDetailVO> detail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ConfigDetailVO result = configService.detail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新配置")
|
|
||||||
@PreAuthorize("hasAuthority('config:update')")
|
|
||||||
public Result<ConfigDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateConfigDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ConfigDetailVO result = configService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除配置")
|
|
||||||
@PreAuthorize("hasAuthority('config:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
configService.delete(id, tenantId);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.contest.*;
|
|
||||||
import com.lesingle.creation.service.ContestService;
|
|
||||||
import com.lesingle.creation.vo.contest.ContestDetailVO;
|
|
||||||
import com.lesingle.creation.vo.contest.ContestListVO;
|
|
||||||
import com.lesingle.creation.vo.contest.ContestStatsVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestController {
|
|
||||||
|
|
||||||
private final ContestService contestService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建竞赛")
|
|
||||||
@PreAuthorize("hasAuthority('contest:create')")
|
|
||||||
public Result<ContestDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateContestDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.create(dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
|
||||||
@Operation(summary = "竞赛统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<ContestStatsVO> getStats() {
|
|
||||||
ContestStatsVO result = contestService.getStats();
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "竞赛列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<Page<ContestListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
ContestQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<ContestListVO> result = contestService.pageList(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/my-contests")
|
|
||||||
@Operation(summary = "我参与的活动列表")
|
|
||||||
public Result<Page<ContestListVO>> myContests(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
ContestQueryDTO queryDTO) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<ContestListVO> result = contestService.myContests(queryDTO, userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "竞赛详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<ContestDetailVO> detail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.detail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新竞赛")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<ContestDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateContestDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/{id}/publish")
|
|
||||||
@Operation(summary = "发布/取消发布竞赛")
|
|
||||||
@PreAuthorize("hasAuthority('contest:publish')")
|
|
||||||
public Result<ContestDetailVO> publish(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated PublishContestDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.publish(id, dto.getContestState(), tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/{id}/finish")
|
|
||||||
@Operation(summary = "标记竞赛为完结")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<ContestDetailVO> finish(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.finish(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/{id}/reopen")
|
|
||||||
@Operation(summary = "重新开启竞赛")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<ContestDetailVO> reopen(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ContestDetailVO result = contestService.reopen(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除竞赛")
|
|
||||||
@PreAuthorize("hasAuthority('contest:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
contestService.delete(id);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,102 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.judge.CreateJudgeDTO;
|
|
||||||
import com.lesingle.creation.dto.judge.UpdateJudgeDTO;
|
|
||||||
import com.lesingle.creation.service.ContestJudgeService;
|
|
||||||
import com.lesingle.creation.vo.judge.JudgeVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛评委管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛评委管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/judges")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestJudgeController {
|
|
||||||
|
|
||||||
private final ContestJudgeService judgeService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:create')")
|
|
||||||
public Result<JudgeVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateJudgeDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
JudgeVO result = judgeService.create(dto, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:update')")
|
|
||||||
public Result<JudgeVO> update(
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateJudgeDTO dto) {
|
|
||||||
JudgeVO result = judgeService.update(id, dto);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
judgeService.delete(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取评委详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<JudgeVO> getDetail(@PathVariable Long id) {
|
|
||||||
JudgeVO result = judgeService.getDetail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}")
|
|
||||||
@Operation(summary = "查询活动的评委列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<JudgeVO>> listByContest(@PathVariable Long contestId) {
|
|
||||||
List<JudgeVO> result = judgeService.listByContest(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/freeze")
|
|
||||||
@Operation(summary = "冻结评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:update')")
|
|
||||||
public Result<JudgeVO> freeze(@RequestBody Map<String, Long> params) {
|
|
||||||
Long id = params.get("id");
|
|
||||||
JudgeVO result = judgeService.freeze(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/unfreeze")
|
|
||||||
@Operation(summary = "解冻评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:update')")
|
|
||||||
public Result<JudgeVO> unfreeze(@RequestBody Map<String, Long> params) {
|
|
||||||
Long id = params.get("id");
|
|
||||||
JudgeVO result = judgeService.unfreeze(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/batch-delete")
|
|
||||||
@Operation(summary = "批量删除评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:judge:delete')")
|
|
||||||
public Result<Void> batchDelete(@RequestBody List<Long> ids) {
|
|
||||||
judgeService.batchDelete(ids);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.notice.CreateNoticeDTO;
|
|
||||||
import com.lesingle.creation.dto.notice.UpdateNoticeDTO;
|
|
||||||
import com.lesingle.creation.service.ContestNoticeService;
|
|
||||||
import com.lesingle.creation.vo.notice.NoticeVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛公告管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛公告管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/notices")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestNoticeController {
|
|
||||||
|
|
||||||
private final ContestNoticeService noticeService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建公告")
|
|
||||||
@PreAuthorize("hasAuthority('contest:notice:create')")
|
|
||||||
public Result<NoticeVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateNoticeDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
NoticeVO result = noticeService.create(dto, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新公告")
|
|
||||||
@PreAuthorize("hasAuthority('contest:notice:update')")
|
|
||||||
public Result<NoticeVO> update(
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateNoticeDTO dto) {
|
|
||||||
NoticeVO result = noticeService.update(id, dto);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除公告")
|
|
||||||
@PreAuthorize("hasAuthority('contest:notice:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
noticeService.delete(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/publish")
|
|
||||||
@Operation(summary = "发布公告")
|
|
||||||
@PreAuthorize("hasAuthority('contest:notice:publish')")
|
|
||||||
public Result<NoticeVO> publish(@PathVariable Long id) {
|
|
||||||
NoticeVO result = noticeService.publish(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取公告详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<NoticeVO> getDetail(@PathVariable Long id) {
|
|
||||||
NoticeVO result = noticeService.getDetail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}")
|
|
||||||
@Operation(summary = "查询活动的公告列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<NoticeVO>> listByContest(@PathVariable Long contestId) {
|
|
||||||
List<NoticeVO> result = noticeService.listByContest(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.presetcomment.CreatePresetCommentDTO;
|
|
||||||
import com.lesingle.creation.service.ContestPresetCommentService;
|
|
||||||
import com.lesingle.creation.vo.presetcomment.PresetCommentVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛预设评语管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛预设评语管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/preset-comments")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestPresetCommentController {
|
|
||||||
|
|
||||||
private final ContestPresetCommentService presetCommentService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建预设评语")
|
|
||||||
@PreAuthorize("hasAuthority('contest:preset-comment:create')")
|
|
||||||
public Result<PresetCommentVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreatePresetCommentDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
PresetCommentVO result = presetCommentService.create(dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除预设评语")
|
|
||||||
@PreAuthorize("hasAuthority('contest:preset-comment:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
presetCommentService.delete(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取预设评语详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<PresetCommentVO> getDetail(@PathVariable Long id) {
|
|
||||||
PresetCommentVO result = presetCommentService.getDetail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}")
|
|
||||||
@Operation(summary = "查询活动的预设评语列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<PresetCommentVO>> listByContest(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<PresetCommentVO> result = presetCommentService.listByContest(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/common")
|
|
||||||
@Operation(summary = "查询通用评语列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<PresetCommentVO>> listCommon(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<PresetCommentVO> result = presetCommentService.listCommon(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.registration.*;
|
|
||||||
import com.lesingle.creation.service.ContestRegistrationService;
|
|
||||||
import com.lesingle.creation.vo.registration.RegistrationStatsVO;
|
|
||||||
import com.lesingle.creation.vo.registration.RegistrationVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛报名管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛报名管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/registrations")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestRegistrationController {
|
|
||||||
|
|
||||||
private final ContestRegistrationService registrationService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建报名")
|
|
||||||
@PreAuthorize("hasAuthority('contest:register')")
|
|
||||||
public Result<RegistrationVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateRegistrationDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
RegistrationVO result = registrationService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
|
||||||
@Operation(summary = "报名统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<RegistrationStatsVO> getStats(@RequestParam(required = false) Long contestId) {
|
|
||||||
RegistrationStatsVO result = registrationService.getStats(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "分页查询报名列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<Page<RegistrationVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute RegistrationQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<RegistrationVO> result = registrationService.pageQuery(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/my/{contestId}")
|
|
||||||
@Operation(summary = "获取用户在某活动中的报名记录")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<RegistrationVO> getMyRegistration(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
RegistrationVO result = registrationService.getMyRegistration(contestId, userId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取报名详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<RegistrationVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
RegistrationVO result = registrationService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/{id}/review")
|
|
||||||
@Operation(summary = "审核报名")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<RegistrationVO> review(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated ReviewRegistrationDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
RegistrationVO result = registrationService.review(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/teachers")
|
|
||||||
@Operation(summary = "添加指导老师")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<RegistrationVO> addTeacher(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated AddTeacherDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
RegistrationVO result = registrationService.addTeacher(id, dto.getTeacherUserId(), tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}/teachers/{teacherUserId}")
|
|
||||||
@Operation(summary = "移除指导老师")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<Void> removeTeacher(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@PathVariable Long teacherUserId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
registrationService.removeTeacher(id, teacherUserId, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除报名")
|
|
||||||
@PreAuthorize("hasAuthority('contest:update')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
registrationService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.result.CreateResultDTO;
|
|
||||||
import com.lesingle.creation.service.ContestResultService;
|
|
||||||
import com.lesingle.creation.vo.result.ResultVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛结果管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛结果管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/results")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestResultController {
|
|
||||||
|
|
||||||
private final ContestResultService resultService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建竞赛结果")
|
|
||||||
@PreAuthorize("hasAuthority('contest:result:create')")
|
|
||||||
public Result<ResultVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateResultDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
ResultVO result = resultService.create(dto, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新竞赛结果")
|
|
||||||
@PreAuthorize("hasAuthority('contest:result:update')")
|
|
||||||
public Result<ResultVO> update(
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated CreateResultDTO dto) {
|
|
||||||
ResultVO result = resultService.update(id, dto);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/publish")
|
|
||||||
@Operation(summary = "发布竞赛结果")
|
|
||||||
@PreAuthorize("hasAuthority('contest:result:publish')")
|
|
||||||
public Result<ResultVO> publish(@PathVariable Long id) {
|
|
||||||
ResultVO result = resultService.publish(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除竞赛结果")
|
|
||||||
@PreAuthorize("hasAuthority('contest:result:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
resultService.delete(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取竞赛结果详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<ResultVO> getDetail(@PathVariable Long id) {
|
|
||||||
ResultVO result = resultService.getDetail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}")
|
|
||||||
@Operation(summary = "查询活动的竞赛结果列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<ResultVO>> listByContest(@PathVariable Long contestId) {
|
|
||||||
List<ResultVO> result = resultService.listByContest(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}/winners")
|
|
||||||
@Operation(summary = "查询获奖结果列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<ResultVO>> listWinners(@PathVariable Long contestId) {
|
|
||||||
List<ResultVO> result = resultService.listWinners(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,214 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.review.*;
|
|
||||||
import com.lesingle.creation.service.ContestReviewService;
|
|
||||||
import com.lesingle.creation.vo.review.ReviewAssignmentVO;
|
|
||||||
import com.lesingle.creation.vo.review.ReviewStatsVO;
|
|
||||||
import com.lesingle.creation.vo.review.WorkScoreVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛评审管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛评审管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/reviews")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestReviewController {
|
|
||||||
|
|
||||||
private final ContestReviewService reviewService;
|
|
||||||
|
|
||||||
@PostMapping("/assign")
|
|
||||||
@Operation(summary = "分配作品给评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:assign')")
|
|
||||||
public Result<List<ReviewAssignmentVO>> assignWork(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam Long contestId,
|
|
||||||
@RequestBody @Validated AssignWorkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewAssignmentVO> result = reviewService.assignWork(contestId, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/batch-assign")
|
|
||||||
@Operation(summary = "批量分配作品")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:assign')")
|
|
||||||
public Result<List<ReviewAssignmentVO>> batchAssign(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated BatchAssignDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewAssignmentVO> result = reviewService.batchAssign(dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/score")
|
|
||||||
@Operation(summary = "评分")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:score')")
|
|
||||||
public Result<WorkScoreVO> score(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateScoreDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long judgeId = userPrincipal.getUserId();
|
|
||||||
WorkScoreVO result = reviewService.score(dto, judgeId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/score/{scoreId}")
|
|
||||||
@Operation(summary = "更新评分")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:score')")
|
|
||||||
public Result<WorkScoreVO> updateScore(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long scoreId,
|
|
||||||
@RequestBody @Validated CreateScoreDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
WorkScoreVO result = reviewService.updateScore(scoreId, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/assignments/page")
|
|
||||||
@Operation(summary = "分页查询评审分配列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<Page<ReviewAssignmentVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute ReviewAssignmentQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<ReviewAssignmentVO> result = reviewService.pageQuery(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/my-assignments")
|
|
||||||
@Operation(summary = "获取评委待评审作品列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:score')")
|
|
||||||
public Result<List<ReviewAssignmentVO>> getMyAssignments(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long judgeId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewAssignmentVO> result = reviewService.getMyAssignments(judgeId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
|
||||||
@Operation(summary = "评审统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<ReviewStatsVO> getStats(@RequestParam(required = false) Long contestId) {
|
|
||||||
ReviewStatsVO result = reviewService.getStats(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/works/{workId}/scores")
|
|
||||||
@Operation(summary = "获取作品的评分列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<WorkScoreVO>> getWorkScores(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long workId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<WorkScoreVO> result = reviewService.getWorkScores(workId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/works/{workId}/average-score")
|
|
||||||
@Operation(summary = "获取作品的平均分")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<java.math.BigDecimal> getAverageScore(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long workId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
java.math.BigDecimal result = reviewService.getAverageScore(workId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/auto-assign")
|
|
||||||
@Operation(summary = "自动分配作品给评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:assign')")
|
|
||||||
public Result<String> autoAssign(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
String result = reviewService.autoAssign(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/progress/{contestId}")
|
|
||||||
@Operation(summary = "获取评审进度统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<com.lesingle.creation.vo.review.ReviewProgressVO> getReviewProgress(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.lesingle.creation.vo.review.ReviewProgressVO result =
|
|
||||||
reviewService.getReviewProgress(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/work-status/{contestId}")
|
|
||||||
@Operation(summary = "获取作品状态统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<com.lesingle.creation.vo.review.WorkStatusStatsVO> getWorkStatusStats(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.lesingle.creation.vo.review.WorkStatusStatsVO result =
|
|
||||||
reviewService.getWorkStatusStats(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/works/{workId}/final-score")
|
|
||||||
@Operation(summary = "获取作品的最终得分")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<com.lesingle.creation.vo.review.FinalScoreVO> getFinalScore(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long workId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.lesingle.creation.vo.review.FinalScoreVO result =
|
|
||||||
reviewService.getFinalScore(workId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/replace-judge")
|
|
||||||
@Operation(summary = "替换评委")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review:assign')")
|
|
||||||
public Result<Void> replaceJudge(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam Long assignmentId,
|
|
||||||
@RequestParam Long newJudgeId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
reviewService.replaceJudge(assignmentId, newJudgeId, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/judge/contests")
|
|
||||||
@Operation(summary = "获取评委参与的活动列表")
|
|
||||||
public Result<java.util.List<com.lesingle.creation.vo.review.JudgeContestVO>> getJudgeContests(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long judgeId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
java.util.List<com.lesingle.creation.vo.review.JudgeContestVO> result =
|
|
||||||
reviewService.getJudgeContests(judgeId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/judge/contests/{contestId}/works")
|
|
||||||
@Operation(summary = "获取评委在某个活动下的作品列表")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.lesingle.creation.vo.review.JudgeWorkVO>>
|
|
||||||
getJudgeContestWorks(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId,
|
|
||||||
@ModelAttribute com.lesingle.creation.dto.review.JudgeWorkQueryDTO queryDTO) {
|
|
||||||
Long judgeId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.lesingle.creation.vo.review.JudgeWorkVO> result =
|
|
||||||
reviewService.getJudgeContestWorks(contestId, judgeId, tenantId, queryDTO);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.reviewrule.CreateReviewDimensionDTO;
|
|
||||||
import com.lesingle.creation.dto.reviewrule.CreateReviewRuleDTO;
|
|
||||||
import com.lesingle.creation.service.ContestReviewRuleService;
|
|
||||||
import com.lesingle.creation.vo.reviewrule.ReviewRuleVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛评审规则管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛评审规则管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/review-rules")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestReviewRuleController {
|
|
||||||
|
|
||||||
private final ContestReviewRuleService reviewRuleService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建评审规则")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review-rule:create')")
|
|
||||||
public Result<ReviewRuleVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateReviewRuleDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
ReviewRuleVO result = reviewRuleService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除评审规则")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review-rule:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
reviewRuleService.delete(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取评审规则详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<ReviewRuleVO> getDetail(@PathVariable Long id) {
|
|
||||||
ReviewRuleVO result = reviewRuleService.getDetail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/list")
|
|
||||||
@Operation(summary = "查询评审规则列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<ReviewRuleVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewRuleVO> result = reviewRuleService.list(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/select")
|
|
||||||
@Operation(summary = "获取可选的评审规则")
|
|
||||||
public Result<List<ReviewRuleVO>> listForSelect(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewRuleVO> result = reviewRuleService.listForSelect(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/dimensions")
|
|
||||||
@Operation(summary = "添加评审维度")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review-rule:update')")
|
|
||||||
public Result<ReviewRuleVO> addDimension(@RequestBody @Validated CreateReviewDimensionDTO dto) {
|
|
||||||
ReviewRuleVO result = reviewRuleService.addDimension(dto);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/dimensions/{id}")
|
|
||||||
@Operation(summary = "删除评审维度")
|
|
||||||
@PreAuthorize("hasAuthority('contest:review-rule:update')")
|
|
||||||
public Result<Void> deleteDimension(@PathVariable Long id) {
|
|
||||||
reviewRuleService.deleteDimension(id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,133 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.team.*;
|
|
||||||
import com.lesingle.creation.service.ContestTeamService;
|
|
||||||
import com.lesingle.creation.vo.team.TeamVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛团队管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛团队管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/teams")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestTeamController {
|
|
||||||
|
|
||||||
private final ContestTeamService teamService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建团队")
|
|
||||||
@PreAuthorize("hasAuthority('contest:team:create')")
|
|
||||||
public Result<TeamVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateTeamDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
TeamVO result = teamService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新团队")
|
|
||||||
@PreAuthorize("hasAuthority('contest:team:update')")
|
|
||||||
public Result<TeamVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateTeamDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
TeamVO result = teamService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除团队")
|
|
||||||
@PreAuthorize("hasAuthority('contest:team:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
teamService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取团队详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<TeamVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
TeamVO result = teamService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/list")
|
|
||||||
@Operation(summary = "查询团队列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<TeamVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false) Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<TeamVO> result = teamService.list(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/contest/{contestId}")
|
|
||||||
@Operation(summary = "按竞赛查询团队列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<TeamVO>> listByContest(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<TeamVO> result = teamService.listByContest(contestId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/my/{contestId}")
|
|
||||||
@Operation(summary = "获取用户在某活动中的团队")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<TeamVO> getMyTeam(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long contestId) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
TeamVO result = teamService.getMyTeam(contestId, userId, tenantId);
|
|
||||||
return result != null ? Result.success(result) : Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/members")
|
|
||||||
@Operation(summary = "邀请成员")
|
|
||||||
@PreAuthorize("hasAuthority('contest:team:update')")
|
|
||||||
public Result<Void> inviteMember(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated InviteMemberDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
teamService.inviteMember(id, dto, tenantId, creatorId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}/members/{userId}")
|
|
||||||
@Operation(summary = "移除成员")
|
|
||||||
@PreAuthorize("hasAuthority('contest:team:update')")
|
|
||||||
public Result<Void> removeMember(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@PathVariable Long userId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
teamService.removeMember(id, userId, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,129 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.work.SubmitWorkDTO;
|
|
||||||
import com.lesingle.creation.dto.work.WorkQueryDTO;
|
|
||||||
import com.lesingle.creation.service.ContestWorkService;
|
|
||||||
import com.lesingle.creation.vo.work.WorkStatsVO;
|
|
||||||
import com.lesingle.creation.vo.work.WorkVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛作品管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "竞赛作品管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/contests/works")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ContestWorkController {
|
|
||||||
|
|
||||||
private final ContestWorkService workService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "提交作品")
|
|
||||||
@PreAuthorize("hasAuthority('contest:work:submit')")
|
|
||||||
public Result<WorkVO> submit(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated SubmitWorkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long submitterUserId = userPrincipal.getUserId();
|
|
||||||
WorkVO result = workService.submit(dto, tenantId, submitterUserId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
|
||||||
@Operation(summary = "作品统计")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<WorkStatsVO> getStats(@RequestParam(required = false) Long contestId) {
|
|
||||||
WorkStatsVO result = workService.getStats(contestId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "分页查询作品列表")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<Page<WorkVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute WorkQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<WorkVO> result = workService.pageQuery(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取作品详情")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<WorkVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
WorkVO result = workService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}/return")
|
|
||||||
@Operation(summary = "退回作品")
|
|
||||||
@PreAuthorize("hasAuthority('contest:work:update')")
|
|
||||||
public Result<WorkVO> returnWork(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestParam String reason) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
WorkVO result = workService.returnWork(id, tenantId, reason);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除作品")
|
|
||||||
@PreAuthorize("hasAuthority('contest:work:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
workService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/registration/{registrationId}")
|
|
||||||
@Operation(summary = "查询某报名的所有作品")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<WorkVO>> listByRegistration(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long registrationId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<WorkVO> result = workService.listByRegistration(registrationId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/registration/{registrationId}/versions")
|
|
||||||
@Operation(summary = "查询某报名的所有作品版本")
|
|
||||||
@PreAuthorize("hasAuthority('contest:read')")
|
|
||||||
public Result<List<WorkVO>> getVersionsByRegistration(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long registrationId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<WorkVO> result = workService.getVersionsByRegistration(registrationId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/guided")
|
|
||||||
@Operation(summary = "查询教师指导的作品列表")
|
|
||||||
public Result<Page<WorkVO>> getGuidedWorks(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute WorkQueryDTO queryDTO) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<WorkVO> result = workService.getGuidedWorks(queryDTO, userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,97 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.department.CreateDepartmentDTO;
|
|
||||||
import com.lesingle.creation.dto.department.UpdateDepartmentDTO;
|
|
||||||
import com.lesingle.creation.service.DepartmentService;
|
|
||||||
import com.lesingle.creation.vo.department.DepartmentVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "部门管理", description = "部门 CRUD 和树形结构接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/departments")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DepartmentController {
|
|
||||||
|
|
||||||
private final DepartmentService departmentService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建部门")
|
|
||||||
@PreAuthorize("hasAuthority('department:create')")
|
|
||||||
public Result<DepartmentVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateDepartmentDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
DepartmentVO result = departmentService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "查询部门列表")
|
|
||||||
@PreAuthorize("hasAuthority('department:read')")
|
|
||||||
public Result<List<DepartmentVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false) Long parentId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<DepartmentVO> result = departmentService.list(tenantId, parentId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/tree")
|
|
||||||
@Operation(summary = "查询部门树形结构")
|
|
||||||
@PreAuthorize("hasAuthority('department:read')")
|
|
||||||
public Result<List<DepartmentVO>> tree(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<DepartmentVO> result = departmentService.tree(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取部门详情")
|
|
||||||
@PreAuthorize("hasAuthority('department:read')")
|
|
||||||
public Result<DepartmentVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
DepartmentVO result = departmentService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新部门")
|
|
||||||
@PreAuthorize("hasAuthority('department:update')")
|
|
||||||
public Result<DepartmentVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Valid UpdateDepartmentDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
DepartmentVO result = departmentService.update(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除部门")
|
|
||||||
@PreAuthorize("hasAuthority('department:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
departmentService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.dict.CreateDictDTO;
|
|
||||||
import com.lesingle.creation.dto.dict.UpdateDictDTO;
|
|
||||||
import com.lesingle.creation.service.DictService;
|
|
||||||
import com.lesingle.creation.vo.dict.DictDetailVO;
|
|
||||||
import com.lesingle.creation.vo.dict.DictListVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字典管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "字典管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/dict")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DictController {
|
|
||||||
|
|
||||||
private final DictService dictService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建字典")
|
|
||||||
@PreAuthorize("hasAuthority('dict:create')")
|
|
||||||
public Result<DictDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateDictDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
DictDetailVO result = dictService.create(dto, tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "字典列表")
|
|
||||||
@PreAuthorize("hasAuthority('dict:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<DictListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<DictListVO> result =
|
|
||||||
dictService.pageList(tenantId, page, pageSize);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/code/{code}")
|
|
||||||
@Operation(summary = "根据编码查询字典")
|
|
||||||
@PreAuthorize("hasAuthority('dict:read')")
|
|
||||||
public Result<DictDetailVO> getByCode(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable String code) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
DictDetailVO result = dictService.getByCode(code, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "字典详情")
|
|
||||||
@PreAuthorize("hasAuthority('dict:read')")
|
|
||||||
public Result<DictDetailVO> detail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
DictDetailVO result = dictService.detail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新字典")
|
|
||||||
@PreAuthorize("hasAuthority('dict:update')")
|
|
||||||
public Result<DictDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateDictDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
DictDetailVO result = dictService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除字典")
|
|
||||||
@PreAuthorize("hasAuthority('dict:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
dictService.delete(id, tenantId);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.grade.CreateGradeDTO;
|
|
||||||
import com.lesingle.creation.dto.grade.UpdateGradeDTO;
|
|
||||||
import com.lesingle.creation.service.GradeService;
|
|
||||||
import com.lesingle.creation.vo.grade.GradeVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 年级管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "年级管理", description = "年级 CRUD 接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/grades")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GradeController {
|
|
||||||
|
|
||||||
private final GradeService gradeService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建年级")
|
|
||||||
@PreAuthorize("hasAuthority('grade:create')")
|
|
||||||
public Result<GradeVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateGradeDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
GradeVO result = gradeService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "分页查询年级列表")
|
|
||||||
@PreAuthorize("hasAuthority('grade:read')")
|
|
||||||
public Result<Page<GradeVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
|
||||||
@RequestParam(required = false, defaultValue = "10") Integer pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<GradeVO> result = gradeService.pageQuery(pageNum, pageSize, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取年级详情")
|
|
||||||
@PreAuthorize("hasAuthority('grade:read')")
|
|
||||||
public Result<GradeVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
GradeVO result = gradeService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新年级")
|
|
||||||
@PreAuthorize("hasAuthority('grade:update')")
|
|
||||||
public Result<GradeVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Valid UpdateGradeDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
GradeVO result = gradeService.update(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除年级")
|
|
||||||
@PreAuthorize("hasAuthority('grade:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
gradeService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,290 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.dto.homework.*;
|
|
||||||
import com.lesingle.creation.vo.school.ClassTreeNodeVO;
|
|
||||||
import com.lesingle.creation.service.HomeworkService;
|
|
||||||
import com.lesingle.creation.vo.homework.HomeworkDetailVO;
|
|
||||||
import com.lesingle.creation.vo.homework.HomeworkListVO;
|
|
||||||
import com.lesingle.creation.vo.homework.ReviewRuleVO;
|
|
||||||
import com.lesingle.creation.vo.homework.SubmissionVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 作业管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "作业管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/homeworks")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class HomeworkController {
|
|
||||||
|
|
||||||
private final HomeworkService homeworkService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:create')")
|
|
||||||
public Result<HomeworkDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateHomeworkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
HomeworkDetailVO result = homeworkService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:update')")
|
|
||||||
public Result<HomeworkDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateHomeworkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
HomeworkDetailVO result = homeworkService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/publish")
|
|
||||||
@Operation(summary = "发布作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:publish')")
|
|
||||||
public Result<HomeworkDetailVO> publish(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
HomeworkDetailVO result = homeworkService.publish(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
homeworkService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取作业详情")
|
|
||||||
public Result<HomeworkDetailVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
HomeworkDetailVO result = homeworkService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/page")
|
|
||||||
@Operation(summary = "分页查询作业列表")
|
|
||||||
public Result<Page<HomeworkListVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute HomeworkQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<HomeworkListVO> result = homeworkService.pageQuery(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/submit")
|
|
||||||
@Operation(summary = "提交作业")
|
|
||||||
public Result<SubmissionVO> submit(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated SubmitHomeworkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long studentId = userPrincipal.getUserId();
|
|
||||||
SubmissionVO result = homeworkService.submit(dto, tenantId, studentId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/review")
|
|
||||||
@Operation(summary = "批改作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<SubmissionVO> review(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated ReviewHomeworkDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long reviewerId = userPrincipal.getUserId();
|
|
||||||
SubmissionVO result = homeworkService.review(dto, tenantId, reviewerId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{homeworkId}/submissions")
|
|
||||||
@Operation(summary = "获取作业提交列表")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<List<SubmissionVO>> getSubmissions(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long homeworkId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<SubmissionVO> result = homeworkService.getSubmissions(homeworkId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/review-rules")
|
|
||||||
@Operation(summary = "创建评审规则")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review-rule:create')")
|
|
||||||
public Result<ReviewRuleVO> createReviewRule(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam String ruleName,
|
|
||||||
@RequestParam(required = false, defaultValue = "custom") String ruleType,
|
|
||||||
@RequestParam(required = false) java.math.BigDecimal totalScore,
|
|
||||||
@RequestParam(required = false) String description) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ReviewRuleVO result = homeworkService.createReviewRule(
|
|
||||||
ruleName, ruleType, totalScore, description, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/review-rules")
|
|
||||||
@Operation(summary = "获取评审规则列表")
|
|
||||||
public Result<List<ReviewRuleVO>> getReviewRules(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewRuleVO> result = homeworkService.getReviewRules(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/review-rules/select")
|
|
||||||
@Operation(summary = "获取可选的评审规则")
|
|
||||||
public Result<List<ReviewRuleVO>> getReviewRulesForSelect(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ReviewRuleVO> result = homeworkService.getReviewRulesForSelect(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/review-rules/{id}")
|
|
||||||
@Operation(summary = "更新评审规则")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review-rule:update')")
|
|
||||||
public Result<ReviewRuleVO> updateReviewRule(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateReviewRuleDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ReviewRuleVO result = homeworkService.updateReviewRule(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/review-rules/{id}")
|
|
||||||
@Operation(summary = "删除评审规则")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review-rule:delete')")
|
|
||||||
public Result<Void> deleteReviewRule(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
homeworkService.deleteReviewRule(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/my")
|
|
||||||
@Operation(summary = "我的作业列表(学生端)")
|
|
||||||
public Result<Page<HomeworkListVO>> getMyHomeworks(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute HomeworkQueryDTO queryDTO) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<HomeworkListVO> result = homeworkService.getMyHomeworks(queryDTO, userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/{id}/unpublish")
|
|
||||||
@Operation(summary = "取消发布作业")
|
|
||||||
@PreAuthorize("hasAuthority('homework:publish')")
|
|
||||||
public Result<HomeworkDetailVO> unpublish(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
HomeworkDetailVO result = homeworkService.unpublish(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/submissions")
|
|
||||||
@Operation(summary = "获取提交记录列表")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<Page<SubmissionVO>> getSubmissionsList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute SubmissionQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<SubmissionVO> result = homeworkService.getSubmissionsList(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/submissions/{id}")
|
|
||||||
@Operation(summary = "获取提交记录详情")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<SubmissionVO> getSubmissionDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
SubmissionVO result = homeworkService.getSubmissionDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/submissions/class-tree")
|
|
||||||
@Operation(summary = "获取班级树结构")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<List<ClassTreeNodeVO>> getClassTree(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<ClassTreeNodeVO> result = homeworkService.getClassTree(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/submissions/my/{homeworkId}")
|
|
||||||
@Operation(summary = "获取我的提交记录")
|
|
||||||
public Result<SubmissionVO> getMySubmission(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long homeworkId) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
SubmissionVO result = homeworkService.getMySubmission(homeworkId, userId, tenantId);
|
|
||||||
return result != null ? Result.success(result) : Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/scores")
|
|
||||||
@Operation(summary = "提交评分")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<SubmissionVO> createScore(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateScoreDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long reviewerId = userPrincipal.getUserId();
|
|
||||||
SubmissionVO result = homeworkService.createScore(dto, tenantId, reviewerId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/scores/{submissionId}/violation")
|
|
||||||
@Operation(summary = "标记作品违规")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<Void> markViolation(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long submissionId,
|
|
||||||
@RequestParam(required = false) String reason) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
homeworkService.markViolation(submissionId, reason, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/scores/{submissionId}/reset")
|
|
||||||
@Operation(summary = "重置评分")
|
|
||||||
@PreAuthorize("hasAuthority('homework:review')")
|
|
||||||
public Result<Void> resetScore(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long submissionId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
homeworkService.resetScore(submissionId, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.menu.CreateMenuDTO;
|
|
||||||
import com.lesingle.creation.dto.menu.UpdateMenuDTO;
|
|
||||||
import com.lesingle.creation.service.MenuService;
|
|
||||||
import com.lesingle.creation.vo.menu.MenuDetailVO;
|
|
||||||
import com.lesingle.creation.vo.menu.MenuTreeVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 菜单管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "菜单管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/menus")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class MenuController {
|
|
||||||
|
|
||||||
private final MenuService menuService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建菜单")
|
|
||||||
@PreAuthorize("hasAuthority('menu:create')")
|
|
||||||
public Result<MenuDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateMenuDTO dto) {
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
MenuDetailVO result = menuService.create(dto, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "菜单树")
|
|
||||||
@PreAuthorize("hasAuthority('menu:read')")
|
|
||||||
public Result<List<MenuTreeVO>> tree() {
|
|
||||||
List<MenuTreeVO> result = menuService.tree();
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/user-menus")
|
|
||||||
@Operation(summary = "当前用户菜单")
|
|
||||||
@PreAuthorize("hasAuthority('menu:read')")
|
|
||||||
public Result<List<MenuTreeVO>> userMenus(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<MenuTreeVO> result = menuService.getUserMenus(userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "菜单详情")
|
|
||||||
@PreAuthorize("hasAuthority('menu:read')")
|
|
||||||
public Result<MenuDetailVO> detail(@PathVariable Long id) {
|
|
||||||
MenuDetailVO result = menuService.detail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新菜单")
|
|
||||||
@PreAuthorize("hasAuthority('menu:update')")
|
|
||||||
public Result<MenuDetailVO> update(
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateMenuDTO dto) {
|
|
||||||
MenuDetailVO result = menuService.update(id, dto);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除菜单")
|
|
||||||
@PreAuthorize("hasAuthority('menu:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
menuService.delete(id);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.permission.CreatePermissionDTO;
|
|
||||||
import com.lesingle.creation.dto.permission.UpdatePermissionDTO;
|
|
||||||
import com.lesingle.creation.service.PermissionService;
|
|
||||||
import com.lesingle.creation.vo.permission.PermissionDetailVO;
|
|
||||||
import com.lesingle.creation.vo.permission.PermissionListVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "权限管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/permissions")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PermissionController {
|
|
||||||
|
|
||||||
private final PermissionService permissionService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建权限")
|
|
||||||
@PreAuthorize("hasAuthority('super_admin')")
|
|
||||||
public Result<PermissionDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreatePermissionDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
PermissionDetailVO result = permissionService.create(dto, tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "权限列表")
|
|
||||||
@PreAuthorize("hasAuthority('permission:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<PermissionListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<PermissionListVO> result =
|
|
||||||
permissionService.pageList(tenantId, page, pageSize);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/all")
|
|
||||||
@Operation(summary = "所有权限列表")
|
|
||||||
@PreAuthorize("hasAuthority('permission:read')")
|
|
||||||
public Result<List<PermissionListVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<PermissionListVO> result = permissionService.list(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "权限详情")
|
|
||||||
@PreAuthorize("hasAuthority('permission:read')")
|
|
||||||
public Result<PermissionDetailVO> detail(@PathVariable Long id) {
|
|
||||||
PermissionDetailVO result = permissionService.detail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新权限")
|
|
||||||
@PreAuthorize("hasAuthority('super_admin')")
|
|
||||||
public Result<PermissionDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdatePermissionDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
PermissionDetailVO result = permissionService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除权限")
|
|
||||||
@PreAuthorize("hasAuthority('super_admin')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@PathVariable Long id) {
|
|
||||||
permissionService.delete(id);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,176 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.child.CreateChildDTO;
|
|
||||||
import com.lesingle.creation.dto.child.UpdateChildDTO;
|
|
||||||
import com.lesingle.creation.dto.publicuser.PublicLoginDTO;
|
|
||||||
import com.lesingle.creation.dto.publicuser.PublicRegisterDTO;
|
|
||||||
import com.lesingle.creation.dto.publicuser.PublicUserUpdateDTO;
|
|
||||||
import com.lesingle.creation.service.PublicService;
|
|
||||||
import com.lesingle.creation.vo.child.ChildVO;
|
|
||||||
import com.lesingle.creation.vo.publicuser.PublicUserVO;
|
|
||||||
import com.lesingle.creation.vo.publicuser.LoginResponseVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 公共接口控制器
|
|
||||||
* 提供公众用户注册、登录、个人信息、子女管理等功能
|
|
||||||
*/
|
|
||||||
@Tag(name = "公共接口", description = "公众用户相关接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/public")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class PublicController {
|
|
||||||
|
|
||||||
private final PublicService publicService;
|
|
||||||
|
|
||||||
// ==================== 注册 & 登录(公开接口) ====================
|
|
||||||
|
|
||||||
@PostMapping("/auth/register")
|
|
||||||
@Operation(summary = "用户注册")
|
|
||||||
public Result<LoginResponseVO> register(@RequestBody @Valid PublicRegisterDTO dto) {
|
|
||||||
return Result.success(publicService.register(dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/auth/login")
|
|
||||||
@Operation(summary = "用户登录")
|
|
||||||
public Result<LoginResponseVO> login(@RequestBody @Valid PublicLoginDTO dto) {
|
|
||||||
return Result.success(publicService.login(dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 个人信息(需要登录) ====================
|
|
||||||
|
|
||||||
@GetMapping("/mine/profile")
|
|
||||||
@Operation(summary = "获取个人信息")
|
|
||||||
public Result<PublicUserVO> getProfile(@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.getUserInfo(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/mine/profile")
|
|
||||||
@Operation(summary = "更新个人信息")
|
|
||||||
public Result<PublicUserVO> updateProfile(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody PublicUserUpdateDTO dto) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.updateProfile(userId, dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 子女管理(需要登录) ====================
|
|
||||||
|
|
||||||
@GetMapping("/mine/children")
|
|
||||||
@Operation(summary = "获取子女列表")
|
|
||||||
public Result<List<ChildVO>> getChildren(@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.getChildren(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/mine/children")
|
|
||||||
@Operation(summary = "创建子女")
|
|
||||||
public Result<ChildVO> createChild(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateChildDTO dto) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.createChild(userId, dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/mine/children/{id}")
|
|
||||||
@Operation(summary = "获取子女详情")
|
|
||||||
public Result<ChildVO> getChild(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.getChild(userId, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/mine/children/{id}")
|
|
||||||
@Operation(summary = "更新子女信息")
|
|
||||||
public Result<ChildVO> updateChild(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody UpdateChildDTO dto) {
|
|
||||||
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.updateChild(userId, id, dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/mine/children/{id}")
|
|
||||||
@Operation(summary = "删除子女")
|
|
||||||
public Result<Void> deleteChild(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
publicService.deleteChild(userId, id);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 子女独立账号管理 ====================
|
|
||||||
|
|
||||||
@PostMapping("/children/create-account")
|
|
||||||
@Operation(summary = "创建子女独立账号")
|
|
||||||
public Result<ChildVO> createChildAccount(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateChildDTO dto) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.createChildAccount(userId, dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/children/accounts")
|
|
||||||
@Operation(summary = "获取子女账号列表")
|
|
||||||
public Result<List<ChildVO>> getChildAccounts(@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.getChildAccounts(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/children/accounts/{id}")
|
|
||||||
@Operation(summary = "更新子女账号信息")
|
|
||||||
public Result<ChildVO> updateChildAccount(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody UpdateChildDTO dto) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.updateChildAccount(userId, id, dto));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/mine/parent-info")
|
|
||||||
@Operation(summary = "获取监护人信息")
|
|
||||||
public Result<PublicUserVO> getParentInfo(@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long userId = userPrincipal.getUserId();
|
|
||||||
return Result.success(publicService.getParentInfo(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 活动浏览(公开接口) ====================
|
|
||||||
|
|
||||||
@GetMapping("/activities")
|
|
||||||
@Operation(summary = "获取活动列表")
|
|
||||||
public Result getActivities(
|
|
||||||
@RequestParam(defaultValue = "1") Integer page,
|
|
||||||
@RequestParam(defaultValue = "12") Integer pageSize,
|
|
||||||
@RequestParam(required = false) String keyword,
|
|
||||||
@RequestParam(required = false) String contestType,
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long userId = userPrincipal != null ? userPrincipal.getUserId() : null;
|
|
||||||
return Result.success(publicService.getPublicActivities(page, pageSize, keyword, contestType, userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/activities/{id}")
|
|
||||||
@Operation(summary = "获取活动详情")
|
|
||||||
public Result getActivityDetail(@PathVariable Long id) {
|
|
||||||
return Result.success(publicService.getActivityDetail(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,94 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.role.CreateRoleDTO;
|
|
||||||
import com.lesingle.creation.dto.role.UpdateRoleDTO;
|
|
||||||
import com.lesingle.creation.service.RoleService;
|
|
||||||
import com.lesingle.creation.vo.role.RoleDetailVO;
|
|
||||||
import com.lesingle.creation.vo.role.RoleListVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 角色管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "角色管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/roles")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RoleController {
|
|
||||||
|
|
||||||
private final RoleService roleService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建角色")
|
|
||||||
@PreAuthorize("hasAuthority('role:create')")
|
|
||||||
public Result<RoleDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateRoleDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
RoleDetailVO result = roleService.create(dto, tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "角色列表")
|
|
||||||
@PreAuthorize("hasAuthority('role:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<RoleListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<RoleListVO> result =
|
|
||||||
roleService.pageList(tenantId, page, pageSize);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/all")
|
|
||||||
@Operation(summary = "所有角色列表")
|
|
||||||
@PreAuthorize("hasAuthority('role:read')")
|
|
||||||
public Result<List<RoleListVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<RoleListVO> result = roleService.list(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "角色详情")
|
|
||||||
@PreAuthorize("hasAuthority('role:read')")
|
|
||||||
public Result<RoleDetailVO> detail(@PathVariable Long id) {
|
|
||||||
RoleDetailVO result = roleService.detail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新角色")
|
|
||||||
@PreAuthorize("hasAuthority('role:update')")
|
|
||||||
public Result<RoleDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateRoleDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
RoleDetailVO result = roleService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除角色")
|
|
||||||
@PreAuthorize("hasAuthority('role:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@PathVariable Long id) {
|
|
||||||
roleService.delete(id);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.schoolclass.CreateClassDTO;
|
|
||||||
import com.lesingle.creation.dto.schoolclass.UpdateClassDTO;
|
|
||||||
import com.lesingle.creation.service.SchoolClassService;
|
|
||||||
import com.lesingle.creation.vo.schoolclass.ClassVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 班级管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "班级管理", description = "班级 CRUD 接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/classes")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SchoolClassController {
|
|
||||||
|
|
||||||
private final SchoolClassService schoolClassService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建班级")
|
|
||||||
@PreAuthorize("hasAuthority('class:create')")
|
|
||||||
public Result<ClassVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateClassDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
ClassVO result = schoolClassService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "分页查询班级列表")
|
|
||||||
@PreAuthorize("hasAuthority('class:read')")
|
|
||||||
public Result<Page<ClassVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false, defaultValue = "1") Integer pageNum,
|
|
||||||
@RequestParam(required = false, defaultValue = "10") Integer pageSize,
|
|
||||||
@RequestParam(required = false) Long gradeId,
|
|
||||||
@RequestParam(required = false) Integer type) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<ClassVO> result = schoolClassService.pageQuery(pageNum, pageSize, tenantId, gradeId, type);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取班级详情")
|
|
||||||
@PreAuthorize("hasAuthority('class:read')")
|
|
||||||
public Result<ClassVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
ClassVO result = schoolClassService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新班级")
|
|
||||||
@PreAuthorize("hasAuthority('class:update')")
|
|
||||||
public Result<ClassVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Valid UpdateClassDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
ClassVO result = schoolClassService.update(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除班级")
|
|
||||||
@PreAuthorize("hasAuthority('class:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
schoolClassService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.school.CreateSchoolDTO;
|
|
||||||
import com.lesingle.creation.dto.school.UpdateSchoolDTO;
|
|
||||||
import com.lesingle.creation.service.SchoolService;
|
|
||||||
import com.lesingle.creation.vo.school.SchoolVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 学校管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "学校管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/schools")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SchoolController {
|
|
||||||
|
|
||||||
private final SchoolService schoolService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建学校")
|
|
||||||
@PreAuthorize("hasAuthority('school:create')")
|
|
||||||
public Result<SchoolVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateSchoolDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
SchoolVO result = schoolService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "获取学校信息")
|
|
||||||
@PreAuthorize("hasAuthority('school:read')")
|
|
||||||
public Result<SchoolVO> get(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
SchoolVO result = schoolService.getByTenantId(tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping
|
|
||||||
@Operation(summary = "更新学校")
|
|
||||||
@PreAuthorize("hasAuthority('school:update')")
|
|
||||||
public Result<SchoolVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated UpdateSchoolDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
SchoolVO result = schoolService.update(dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping
|
|
||||||
@Operation(summary = "删除学校")
|
|
||||||
@PreAuthorize("hasAuthority('school:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
schoolService.delete(tenantId);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.student.CreateStudentDTO;
|
|
||||||
import com.lesingle.creation.dto.student.UpdateStudentDTO;
|
|
||||||
import com.lesingle.creation.service.StudentService;
|
|
||||||
import com.lesingle.creation.vo.student.StudentVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 学生管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "学生管理", description = "学生 CRUD 和查询接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/students")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class StudentController {
|
|
||||||
|
|
||||||
private final StudentService studentService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建学生")
|
|
||||||
@PreAuthorize("hasAuthority('student:create')")
|
|
||||||
public Result<StudentVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateStudentDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
StudentVO result = studentService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "查询学生列表")
|
|
||||||
@PreAuthorize("hasAuthority('student:read')")
|
|
||||||
public Result<List<StudentVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(defaultValue = "1") Integer page,
|
|
||||||
@RequestParam(defaultValue = "10") Integer pageSize,
|
|
||||||
@RequestParam(required = false) Long classId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<StudentVO> result = studentService.list(tenantId, page, pageSize, classId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取学生详情")
|
|
||||||
@PreAuthorize("hasAuthority('student:read')")
|
|
||||||
public Result<StudentVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
StudentVO result = studentService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/user/{userId}")
|
|
||||||
@Operation(summary = "根据用户 ID 获取学生信息")
|
|
||||||
@PreAuthorize("hasAuthority('student:read')")
|
|
||||||
public Result<StudentVO> getByUserId(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long userId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
StudentVO result = studentService.getByUserId(userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新学生")
|
|
||||||
@PreAuthorize("hasAuthority('student:update')")
|
|
||||||
public Result<StudentVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Valid UpdateStudentDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
StudentVO result = studentService.update(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除学生")
|
|
||||||
@PreAuthorize("hasAuthority('student:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
studentService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.log.LogQueryDTO;
|
|
||||||
import com.lesingle.creation.service.SysLogService;
|
|
||||||
import com.lesingle.creation.vo.log.LogStatisticsVO;
|
|
||||||
import com.lesingle.creation.vo.log.LogVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统日志控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "系统日志", description = "日志查询、统计等接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/sys-log")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class SysLogController {
|
|
||||||
|
|
||||||
private final SysLogService sysLogService;
|
|
||||||
|
|
||||||
@Operation(summary = "分页查询日志列表")
|
|
||||||
@GetMapping("/page")
|
|
||||||
@PreAuthorize("hasAuthority('log:read')")
|
|
||||||
public Result<Page<LogVO>> pageQuery(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@ModelAttribute LogQueryDTO queryDTO) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Page<LogVO> result = sysLogService.pageQuery(queryDTO, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取日志详情
|
|
||||||
*/
|
|
||||||
@Operation(summary = "获取日志详情")
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@PreAuthorize("hasAuthority('log:read')")
|
|
||||||
public Result<LogVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
LogVO result = sysLogService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取日志统计信息
|
|
||||||
*/
|
|
||||||
@Operation(summary = "获取日志统计信息")
|
|
||||||
@GetMapping("/statistics")
|
|
||||||
@PreAuthorize("hasAuthority('log:read')")
|
|
||||||
public Result<LogStatisticsVO> getStatistics(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false, defaultValue = "7") Integer days) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
LogStatisticsVO result = sysLogService.getStatistics(days, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量删除日志
|
|
||||||
*/
|
|
||||||
@Operation(summary = "批量删除日志")
|
|
||||||
@DeleteMapping
|
|
||||||
@PreAuthorize("hasAuthority('log:delete')")
|
|
||||||
public Result<Integer> deleteByIds(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam("ids") List<Long> ids) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
int result = sysLogService.deleteByIds(ids, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理过期日志
|
|
||||||
*/
|
|
||||||
@Operation(summary = "清理过期日志")
|
|
||||||
@PostMapping("/clean")
|
|
||||||
@PreAuthorize("hasAuthority('log:delete')")
|
|
||||||
public Result<Integer> cleanOldLogs(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false) Integer days) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
int result = sysLogService.cleanOldLogs(days, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.teacher.CreateTeacherDTO;
|
|
||||||
import com.lesingle.creation.dto.teacher.UpdateTeacherDTO;
|
|
||||||
import com.lesingle.creation.service.TeacherService;
|
|
||||||
import com.lesingle.creation.vo.teacher.TeacherVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 教师管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "教师管理", description = "教师 CRUD 和查询接口")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/teachers")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class TeacherController {
|
|
||||||
|
|
||||||
private final TeacherService teacherService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建教师")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:create')")
|
|
||||||
public Result<TeacherVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Valid CreateTeacherDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
TeacherVO result = teacherService.create(dto, tenantId, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "查询教师列表")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:read')")
|
|
||||||
public Result<List<TeacherVO>> list(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false) Long departmentId,
|
|
||||||
@RequestParam(required = false) String nickname,
|
|
||||||
@RequestParam(required = false) String username) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
List<TeacherVO> result = teacherService.list(tenantId, departmentId, nickname, username);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "获取教师详情")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:read')")
|
|
||||||
public Result<TeacherVO> getDetail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
TeacherVO result = teacherService.getDetail(id, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/user/{userId}")
|
|
||||||
@Operation(summary = "根据用户 ID 获取教师信息")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:read')")
|
|
||||||
public Result<TeacherVO> getByUserId(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long userId) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
TeacherVO result = teacherService.getByUserId(userId, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新教师")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:update')")
|
|
||||||
public Result<TeacherVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Valid UpdateTeacherDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
TeacherVO result = teacherService.update(id, dto, tenantId, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除教师")
|
|
||||||
@PreAuthorize("hasAuthority('teacher:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
teacherService.delete(id, tenantId);
|
|
||||||
return Result.success(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.tenant.CreateTenantDTO;
|
|
||||||
import com.lesingle.creation.dto.tenant.UpdateTenantDTO;
|
|
||||||
import com.lesingle.creation.service.TenantService;
|
|
||||||
import com.lesingle.creation.vo.tenant.TenantDetailVO;
|
|
||||||
import com.lesingle.creation.vo.tenant.TenantListVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 租户管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "租户管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/tenants")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class TenantController {
|
|
||||||
|
|
||||||
private final TenantService tenantService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建租户")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:create')")
|
|
||||||
public Result<TenantDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateTenantDTO dto) {
|
|
||||||
Long creatorId = userPrincipal.getUserId();
|
|
||||||
TenantDetailVO result = tenantService.create(dto, creatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "租户列表")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<TenantListVO>> pageList(
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<TenantListVO> result =
|
|
||||||
tenantService.pageList(page, pageSize);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "租户详情")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:read')")
|
|
||||||
public Result<TenantDetailVO> detail(@PathVariable Long id) {
|
|
||||||
TenantDetailVO result = tenantService.detail(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新租户")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:update')")
|
|
||||||
public Result<TenantDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateTenantDTO dto) {
|
|
||||||
Long modifierId = userPrincipal.getUserId();
|
|
||||||
TenantDetailVO result = tenantService.update(id, dto, modifierId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除租户")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:delete')")
|
|
||||||
public Result<Void> delete(@PathVariable Long id) {
|
|
||||||
tenantService.delete(id);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}/menus")
|
|
||||||
@Operation(summary = "获取租户菜单")
|
|
||||||
@PreAuthorize("hasAuthority('tenant:read')")
|
|
||||||
public Result<List<?>> getTenantMenus(@PathVariable Long id) {
|
|
||||||
List<?> result = tenantService.getTenantMenus(id);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.exception.BusinessException;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.common.util.OssUtil;
|
|
||||||
import com.lesingle.creation.vo.upload.UploadResponseVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "文件上传", description = "文件上传、删除等接口")
|
|
||||||
@Slf4j
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/upload")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class UploadController {
|
|
||||||
|
|
||||||
private final OssUtil ossUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件
|
|
||||||
*/
|
|
||||||
@Operation(summary = "上传文件")
|
|
||||||
@PostMapping
|
|
||||||
public Result<UploadResponseVO> uploadFile(
|
|
||||||
@RequestParam("file") MultipartFile file,
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal) {
|
|
||||||
try {
|
|
||||||
if (file == null || file.isEmpty()) {
|
|
||||||
throw new BusinessException("请选择要上传的文件");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调用 OssUtil 上传文件
|
|
||||||
String fileUrl = ossUtil.upload(file);
|
|
||||||
|
|
||||||
// 构建响应
|
|
||||||
UploadResponseVO response = new UploadResponseVO();
|
|
||||||
response.setUrl(fileUrl);
|
|
||||||
response.setFileName(file.getOriginalFilename());
|
|
||||||
response.setSize(file.getSize());
|
|
||||||
|
|
||||||
log.info("文件上传成功,文件名={}, 大小={}", file.getOriginalFilename(), file.getSize());
|
|
||||||
|
|
||||||
return Result.success(response);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("文件上传失败", e);
|
|
||||||
throw new BusinessException("文件上传失败:" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文件
|
|
||||||
*/
|
|
||||||
@Operation(summary = "删除文件")
|
|
||||||
@DeleteMapping
|
|
||||||
public Result<Void> deleteFile(@RequestParam("url") String fileUrl) {
|
|
||||||
try {
|
|
||||||
ossUtil.delete(fileUrl);
|
|
||||||
return Result.success(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("文件删除失败", e);
|
|
||||||
throw new BusinessException("文件删除失败:" + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
package com.lesingle.creation.controller;
|
|
||||||
|
|
||||||
import com.lesingle.creation.common.core.Result;
|
|
||||||
import com.lesingle.creation.common.security.UserPrincipal;
|
|
||||||
import com.lesingle.creation.dto.user.CreateUserDTO;
|
|
||||||
import com.lesingle.creation.dto.user.UpdateUserDTO;
|
|
||||||
import com.lesingle.creation.dto.user.UserQueryDTO;
|
|
||||||
import com.lesingle.creation.service.UserService;
|
|
||||||
import com.lesingle.creation.vo.user.UserDetailVO;
|
|
||||||
import com.lesingle.creation.vo.user.UserListVO;
|
|
||||||
import com.lesingle.creation.vo.user.UserStatsVO;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户管理控制器
|
|
||||||
*/
|
|
||||||
@Tag(name = "用户管理")
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/users")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class UserController {
|
|
||||||
|
|
||||||
private final UserService userService;
|
|
||||||
|
|
||||||
@PostMapping
|
|
||||||
@Operation(summary = "创建用户")
|
|
||||||
@PreAuthorize("hasAuthority('user:create')")
|
|
||||||
public Result<UserDetailVO> create(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestBody @Validated CreateUserDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
UserDetailVO result = userService.create(dto, tenantId, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/stats")
|
|
||||||
@Operation(summary = "用户统计(仅超管)")
|
|
||||||
@PreAuthorize("hasAuthority('super_admin')")
|
|
||||||
public Result<UserStatsVO> getStats() {
|
|
||||||
UserStatsVO result = userService.getStats();
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping
|
|
||||||
@Operation(summary = "用户列表")
|
|
||||||
@PreAuthorize("hasAuthority('user:read')")
|
|
||||||
public Result<com.baomidou.mybatisplus.extension.plugins.pagination.Page<UserListVO>> pageList(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@RequestParam(required = false) String keyword,
|
|
||||||
@RequestParam(required = false) String userType,
|
|
||||||
@RequestParam(required = false) String userSource,
|
|
||||||
@RequestParam(required = false) String status,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "10") int pageSize) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
boolean isSuperTenant = userPrincipal.isSuperTenant();
|
|
||||||
|
|
||||||
UserQueryDTO queryDTO = new UserQueryDTO();
|
|
||||||
queryDTO.setKeyword(keyword);
|
|
||||||
queryDTO.setUserType(userType);
|
|
||||||
queryDTO.setUserSource(userSource);
|
|
||||||
queryDTO.setStatus(status);
|
|
||||||
queryDTO.setPage(page);
|
|
||||||
queryDTO.setPageSize(pageSize);
|
|
||||||
|
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<UserListVO> result =
|
|
||||||
userService.pageList(queryDTO, tenantId, isSuperTenant);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
|
||||||
@Operation(summary = "用户详情")
|
|
||||||
@PreAuthorize("hasAuthority('user:read')")
|
|
||||||
public Result<UserDetailVO> detail(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
boolean isSuperTenant = userPrincipal.isSuperTenant();
|
|
||||||
UserDetailVO result = userService.detail(id, tenantId, isSuperTenant);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PatchMapping("/{id}/status")
|
|
||||||
@Operation(summary = "更新用户状态")
|
|
||||||
@PreAuthorize("hasAuthority('user:manage')")
|
|
||||||
public Result<UserDetailVO> updateStatus(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestParam String status) {
|
|
||||||
Long operatorId = userPrincipal.getUserId();
|
|
||||||
UserDetailVO result = userService.updateStatus(id, status, operatorId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PutMapping("/{id}")
|
|
||||||
@Operation(summary = "更新用户")
|
|
||||||
@PreAuthorize("hasAuthority('user:update')")
|
|
||||||
public Result<UserDetailVO> update(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id,
|
|
||||||
@RequestBody @Validated UpdateUserDTO dto) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
UserDetailVO result = userService.update(id, dto, tenantId);
|
|
||||||
return Result.success(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
|
||||||
@Operation(summary = "删除用户")
|
|
||||||
@PreAuthorize("hasAuthority('user:delete')")
|
|
||||||
public Result<Void> delete(
|
|
||||||
@AuthenticationPrincipal UserPrincipal userPrincipal,
|
|
||||||
@PathVariable Long id) {
|
|
||||||
Long tenantId = userPrincipal.getTenantId();
|
|
||||||
userService.delete(id, tenantId);
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.ai3d;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* AI 3D 任务查询 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "AI 3D 任务查询参数")
|
|
||||||
public class AI3DTaskQueryDTO {
|
|
||||||
|
|
||||||
@Schema(description = "页码", example = "1")
|
|
||||||
private Integer pageNum = 1;
|
|
||||||
|
|
||||||
@Schema(description = "每页数量", example = "10")
|
|
||||||
private Integer pageSize = 10;
|
|
||||||
|
|
||||||
@Schema(description = "任务状态:pending/processing/completed/failed/timeout")
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
@Schema(description = "输入类型:text/image")
|
|
||||||
private String inputType;
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.ai3d;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建 AI 3D 任务请求 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建 AI 3D 任务请求")
|
|
||||||
public class CreateAI3DTaskDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "输入内容不能为空")
|
|
||||||
@Schema(description = "输入类型:text/image", example = "text")
|
|
||||||
private String inputType;
|
|
||||||
|
|
||||||
@NotBlank(message = "输入内容不能为空")
|
|
||||||
@Schema(description = "输入内容:文字描述或图片 URL", example = "一只可爱的小猫")
|
|
||||||
private String inputContent;
|
|
||||||
|
|
||||||
@Schema(description = "生成类型:Normal/Geometry/LowPoly/Sketch", example = "Normal")
|
|
||||||
private String generateType = "Normal";
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.auth;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录请求 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "登录请求")
|
|
||||||
public class LoginDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "用户名不能为空")
|
|
||||||
@Schema(description = "用户名")
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
@NotBlank(message = "密码不能为空")
|
|
||||||
@Schema(description = "密码")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@Schema(description = "租户编码")
|
|
||||||
private String tenantCode;
|
|
||||||
|
|
||||||
@Schema(description = "验证码")
|
|
||||||
private String captcha;
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.child;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建子女 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建子女请求")
|
|
||||||
public class CreateChildDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "子女用户名不能为空")
|
|
||||||
@Schema(description = "子女用户名")
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
@NotBlank(message = "密码不能为空")
|
|
||||||
@Schema(description = "密码")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@NotBlank(message = "昵称不能为空")
|
|
||||||
@Schema(description = "昵称")
|
|
||||||
private String nickname;
|
|
||||||
|
|
||||||
@Schema(description = "性别:male/female")
|
|
||||||
private String gender;
|
|
||||||
|
|
||||||
@Schema(description = "出生日期")
|
|
||||||
private LocalDate birthday;
|
|
||||||
|
|
||||||
@Schema(description = "所在城市")
|
|
||||||
private String city;
|
|
||||||
|
|
||||||
@Schema(description = "头像 URL")
|
|
||||||
private String avatar;
|
|
||||||
|
|
||||||
@Schema(description = "与监护人关系")
|
|
||||||
private String relationship;
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.child;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新子女 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新子女请求")
|
|
||||||
public class UpdateChildDTO {
|
|
||||||
|
|
||||||
@Schema(description = "昵称")
|
|
||||||
private String nickname;
|
|
||||||
|
|
||||||
@Schema(description = "密码")
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
@Schema(description = "性别:male/female")
|
|
||||||
private String gender;
|
|
||||||
|
|
||||||
@Schema(description = "出生日期")
|
|
||||||
private LocalDate birthday;
|
|
||||||
|
|
||||||
@Schema(description = "所在城市")
|
|
||||||
private String city;
|
|
||||||
|
|
||||||
@Schema(description = "头像 URL")
|
|
||||||
private String avatar;
|
|
||||||
|
|
||||||
@Schema(description = "管控模式:full/control/free")
|
|
||||||
private String controlMode;
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.config;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建配置 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建配置请求")
|
|
||||||
public class CreateConfigDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "配置键不能为空")
|
|
||||||
@Schema(description = "配置键", example = "system.title")
|
|
||||||
private String configKey;
|
|
||||||
|
|
||||||
@NotBlank(message = "配置值不能为空")
|
|
||||||
@Schema(description = "配置值", example = "图书馆创作平台")
|
|
||||||
private String configValue;
|
|
||||||
|
|
||||||
@Schema(description = "配置名称", example = "系统标题")
|
|
||||||
private String configName;
|
|
||||||
|
|
||||||
@Schema(description = "配置描述")
|
|
||||||
private String description;
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.config;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新配置 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新配置请求")
|
|
||||||
public class UpdateConfigDTO {
|
|
||||||
|
|
||||||
@Schema(description = "配置值")
|
|
||||||
private String configValue;
|
|
||||||
|
|
||||||
@Schema(description = "配置名称")
|
|
||||||
private String configName;
|
|
||||||
|
|
||||||
@Schema(description = "配置描述")
|
|
||||||
private String description;
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.contest;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 竞赛查询 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "竞赛查询参数")
|
|
||||||
public class ContestQueryDTO {
|
|
||||||
|
|
||||||
@Schema(description = "页码", example = "1")
|
|
||||||
private Integer page = 1;
|
|
||||||
|
|
||||||
@Schema(description = "每页大小", example = "10")
|
|
||||||
private Integer pageSize = 10;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛名称关键字")
|
|
||||||
private String contestName;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛状态:unpublished/published", example = "published")
|
|
||||||
private String contestState;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛类型:individual/team", example = "individual")
|
|
||||||
private String contestType;
|
|
||||||
|
|
||||||
@Schema(description = "可见范围:public/designated/internal", example = "designated")
|
|
||||||
private String visibility;
|
|
||||||
|
|
||||||
@Schema(description = "进度状态:ongoing/finished", example = "ongoing")
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
@Schema(description = "阶段:unpublished/registering/submitting/reviewing/finished", example = "registering")
|
|
||||||
private String stage;
|
|
||||||
|
|
||||||
@Schema(description = "创建者租户 ID")
|
|
||||||
private Long creatorTenantId;
|
|
||||||
}
|
|
||||||
@ -1,135 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.contest;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建竞赛 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建竞赛请求")
|
|
||||||
public class CreateContestDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "竞赛名称不能为空")
|
|
||||||
@Schema(description = "竞赛名称", example = "第十届创意绘画比赛")
|
|
||||||
private String contestName;
|
|
||||||
|
|
||||||
@NotBlank(message = "竞赛类型不能为空")
|
|
||||||
@Schema(description = "竞赛类型:individual-个人赛/team-团队赛", example = "individual")
|
|
||||||
private String contestType;
|
|
||||||
|
|
||||||
@Schema(description = "可见范围:public-公开/designated-指定机构/internal-仅内部", example = "designated")
|
|
||||||
private String visibility;
|
|
||||||
|
|
||||||
@Schema(description = "目标城市列表(定向推送时使用)")
|
|
||||||
private List<String> targetCities;
|
|
||||||
|
|
||||||
@Schema(description = "最小年龄限制", example = "6")
|
|
||||||
private Integer ageMin;
|
|
||||||
|
|
||||||
@Schema(description = "最大年龄限制", example = "18")
|
|
||||||
private Integer ageMax;
|
|
||||||
|
|
||||||
@NotNull(message = "竞赛开始时间不能为空")
|
|
||||||
@Schema(description = "竞赛开始时间")
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
@NotNull(message = "竞赛结束时间不能为空")
|
|
||||||
@Schema(description = "竞赛结束时间")
|
|
||||||
private LocalDateTime endTime;
|
|
||||||
|
|
||||||
@Schema(description = "线下地址")
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛详情")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
@Schema(description = "授权租户 ID 列表")
|
|
||||||
private List<Integer> contestTenants;
|
|
||||||
|
|
||||||
@Schema(description = "封面 URL")
|
|
||||||
private String coverUrl;
|
|
||||||
|
|
||||||
@Schema(description = "海报 URL")
|
|
||||||
private String posterUrl;
|
|
||||||
|
|
||||||
@Schema(description = "联系人")
|
|
||||||
private String contactName;
|
|
||||||
|
|
||||||
@Schema(description = "联系电话")
|
|
||||||
private String contactPhone;
|
|
||||||
|
|
||||||
@Schema(description = "联系人二维码")
|
|
||||||
private String contactQrcode;
|
|
||||||
|
|
||||||
@Schema(description = "主办单位")
|
|
||||||
private String organizers;
|
|
||||||
|
|
||||||
@Schema(description = "协办单位")
|
|
||||||
private String coOrganizers;
|
|
||||||
|
|
||||||
@Schema(description = "赞助单位")
|
|
||||||
private String sponsors;
|
|
||||||
|
|
||||||
@NotNull(message = "报名开始时间不能为空")
|
|
||||||
@Schema(description = "报名开始时间")
|
|
||||||
private LocalDateTime registerStartTime;
|
|
||||||
|
|
||||||
@NotNull(message = "报名结束时间不能为空")
|
|
||||||
@Schema(description = "报名结束时间")
|
|
||||||
private LocalDateTime registerEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "报名任务状态:open-开放/closed-关闭", example = "open")
|
|
||||||
private String registerState;
|
|
||||||
|
|
||||||
@Schema(description = "是否需要审核", example = "true")
|
|
||||||
private Boolean requireAudit;
|
|
||||||
|
|
||||||
@Schema(description = "允许报名的年级 ID 列表")
|
|
||||||
private List<Integer> allowedGrades;
|
|
||||||
|
|
||||||
@Schema(description = "允许报名的班级 ID 列表")
|
|
||||||
private List<Integer> allowedClasses;
|
|
||||||
|
|
||||||
@Schema(description = "团队最少成员数", example = "1")
|
|
||||||
private Integer teamMinMembers;
|
|
||||||
|
|
||||||
@Schema(description = "团队最多成员数", example = "5")
|
|
||||||
private Integer teamMaxMembers;
|
|
||||||
|
|
||||||
@Schema(description = "提交规则:once-仅一次/resubmit-可重复提交", example = "once")
|
|
||||||
private String submitRule;
|
|
||||||
|
|
||||||
@NotNull(message = "作品提交开始时间不能为空")
|
|
||||||
@Schema(description = "作品提交开始时间")
|
|
||||||
private LocalDateTime submitStartTime;
|
|
||||||
|
|
||||||
@NotNull(message = "作品提交结束时间不能为空")
|
|
||||||
@Schema(description = "作品提交结束时间")
|
|
||||||
private LocalDateTime submitEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "作品类型:image/video/document/code/other", example = "image")
|
|
||||||
private String workType;
|
|
||||||
|
|
||||||
@Schema(description = "作品要求说明")
|
|
||||||
private String workRequirement;
|
|
||||||
|
|
||||||
@Schema(description = "评审规则 ID")
|
|
||||||
private Long reviewRuleId;
|
|
||||||
|
|
||||||
@NotNull(message = "评审开始时间不能为空")
|
|
||||||
@Schema(description = "评审开始时间")
|
|
||||||
private LocalDateTime reviewStartTime;
|
|
||||||
|
|
||||||
@NotNull(message = "评审结束时间不能为空")
|
|
||||||
@Schema(description = "评审结束时间")
|
|
||||||
private LocalDateTime reviewEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "结果发布时间")
|
|
||||||
private LocalDateTime resultPublishTime;
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.contest;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布/取消发布竞赛 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "发布竞赛请求")
|
|
||||||
public class PublishContestDTO {
|
|
||||||
|
|
||||||
@Schema(description = "竞赛状态:unpublished/published", example = "published")
|
|
||||||
private String contestState;
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.contest;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新竞赛 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新竞赛请求")
|
|
||||||
public class UpdateContestDTO {
|
|
||||||
|
|
||||||
@Schema(description = "竞赛名称")
|
|
||||||
private String contestName;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛类型:individual/team")
|
|
||||||
private String contestType;
|
|
||||||
|
|
||||||
@Schema(description = "可见范围:public/designated/internal")
|
|
||||||
private String visibility;
|
|
||||||
|
|
||||||
@Schema(description = "目标城市列表")
|
|
||||||
private List<String> targetCities;
|
|
||||||
|
|
||||||
@Schema(description = "最小年龄限制")
|
|
||||||
private Integer ageMin;
|
|
||||||
|
|
||||||
@Schema(description = "最大年龄限制")
|
|
||||||
private Integer ageMax;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛开始时间")
|
|
||||||
private LocalDateTime startTime;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛结束时间")
|
|
||||||
private LocalDateTime endTime;
|
|
||||||
|
|
||||||
@Schema(description = "线下地址")
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛详情")
|
|
||||||
private String content;
|
|
||||||
|
|
||||||
@Schema(description = "授权租户 ID 列表")
|
|
||||||
private List<Integer> contestTenants;
|
|
||||||
|
|
||||||
@Schema(description = "封面 URL")
|
|
||||||
private String coverUrl;
|
|
||||||
|
|
||||||
@Schema(description = "海报 URL")
|
|
||||||
private String posterUrl;
|
|
||||||
|
|
||||||
@Schema(description = "联系人")
|
|
||||||
private String contactName;
|
|
||||||
|
|
||||||
@Schema(description = "联系电话")
|
|
||||||
private String contactPhone;
|
|
||||||
|
|
||||||
@Schema(description = "联系人二维码")
|
|
||||||
private String contactQrcode;
|
|
||||||
|
|
||||||
@Schema(description = "主办单位")
|
|
||||||
private String organizers;
|
|
||||||
|
|
||||||
@Schema(description = "协办单位")
|
|
||||||
private String coOrganizers;
|
|
||||||
|
|
||||||
@Schema(description = "赞助单位")
|
|
||||||
private String sponsors;
|
|
||||||
|
|
||||||
@Schema(description = "报名开始时间")
|
|
||||||
private LocalDateTime registerStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "报名结束时间")
|
|
||||||
private LocalDateTime registerEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "报名任务状态:open/closed")
|
|
||||||
private String registerState;
|
|
||||||
|
|
||||||
@Schema(description = "是否需要审核")
|
|
||||||
private Boolean requireAudit;
|
|
||||||
|
|
||||||
@Schema(description = "允许报名的年级 ID 列表")
|
|
||||||
private List<Integer> allowedGrades;
|
|
||||||
|
|
||||||
@Schema(description = "允许报名的班级 ID 列表")
|
|
||||||
private List<Integer> allowedClasses;
|
|
||||||
|
|
||||||
@Schema(description = "团队最少成员数")
|
|
||||||
private Integer teamMinMembers;
|
|
||||||
|
|
||||||
@Schema(description = "团队最多成员数")
|
|
||||||
private Integer teamMaxMembers;
|
|
||||||
|
|
||||||
@Schema(description = "提交规则:once/resubmit")
|
|
||||||
private String submitRule;
|
|
||||||
|
|
||||||
@Schema(description = "作品提交开始时间")
|
|
||||||
private LocalDateTime submitStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "作品提交结束时间")
|
|
||||||
private LocalDateTime submitEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "作品类型")
|
|
||||||
private String workType;
|
|
||||||
|
|
||||||
@Schema(description = "作品要求说明")
|
|
||||||
private String workRequirement;
|
|
||||||
|
|
||||||
@Schema(description = "评审规则 ID")
|
|
||||||
private Long reviewRuleId;
|
|
||||||
|
|
||||||
@Schema(description = "评审开始时间")
|
|
||||||
private LocalDateTime reviewStartTime;
|
|
||||||
|
|
||||||
@Schema(description = "评审结束时间")
|
|
||||||
private LocalDateTime reviewEndTime;
|
|
||||||
|
|
||||||
@Schema(description = "结果发布时间")
|
|
||||||
private LocalDateTime resultPublishTime;
|
|
||||||
|
|
||||||
@Schema(description = "竞赛状态:unpublished/published")
|
|
||||||
private String contestState;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.department;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建部门 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建部门请求")
|
|
||||||
public class CreateDepartmentDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "部门名称不能为空")
|
|
||||||
@Schema(description = "部门名称")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@NotBlank(message = "部门编码不能为空")
|
|
||||||
@Schema(description = "部门编码")
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
@Schema(description = "父部门 ID")
|
|
||||||
private Long parentId;
|
|
||||||
|
|
||||||
@Schema(description = "部门描述")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "排序")
|
|
||||||
private Integer sort = 0;
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.department;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新部门 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新部门请求")
|
|
||||||
public class UpdateDepartmentDTO {
|
|
||||||
|
|
||||||
@Schema(description = "部门名称")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "部门编码")
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
@Schema(description = "父部门 ID")
|
|
||||||
private Long parentId;
|
|
||||||
|
|
||||||
@Schema(description = "部门描述")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "排序")
|
|
||||||
private Integer sort;
|
|
||||||
|
|
||||||
@Schema(description = "有效状态:1-有效,2-失效")
|
|
||||||
private Integer validState;
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.dict;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建字典 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建字典请求")
|
|
||||||
public class CreateDictDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "字典名称不能为空")
|
|
||||||
@Schema(description = "字典名称", example = "性别")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@NotBlank(message = "字典编码不能为空")
|
|
||||||
@Schema(description = "字典编码", example = "gender")
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
@Schema(description = "字典描述")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "字典项列表")
|
|
||||||
private List<CreateDictItemDTO> items;
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.dict;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建字典项 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建字典项请求")
|
|
||||||
public class CreateDictItemDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "字典项标签不能为空")
|
|
||||||
@Schema(description = "字典项标签", example = "男")
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
@NotBlank(message = "字典项值不能为空")
|
|
||||||
@Schema(description = "字典项值", example = "male")
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
@Schema(description = "排序", example = "1")
|
|
||||||
private Integer sort;
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.dict;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新字典 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新字典请求")
|
|
||||||
public class UpdateDictDTO {
|
|
||||||
|
|
||||||
@Schema(description = "字典名称")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@Schema(description = "字典编码")
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
@Schema(description = "字典描述")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@Schema(description = "字典项列表")
|
|
||||||
private List<UpdateDictItemDTO> items;
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.dict;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新字典项 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "更新字典项请求")
|
|
||||||
public class UpdateDictItemDTO {
|
|
||||||
|
|
||||||
@Schema(description = "字典项 ID")
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Schema(description = "字典项标签")
|
|
||||||
private String label;
|
|
||||||
|
|
||||||
@Schema(description = "字典项值")
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
@Schema(description = "排序")
|
|
||||||
private Integer sort;
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package com.lesingle.creation.dto.grade;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建年级 DTO
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Schema(description = "创建年级请求")
|
|
||||||
public class CreateGradeDTO {
|
|
||||||
|
|
||||||
@NotBlank(message = "年级名称不能为空")
|
|
||||||
@Schema(description = "年级名称")
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
@NotBlank(message = "年级编码不能为空")
|
|
||||||
@Schema(description = "年级编码")
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
@NotNull(message = "年级级别不能为空")
|
|
||||||
@Schema(description = "年级级别")
|
|
||||||
private Integer level;
|
|
||||||
|
|
||||||
@Schema(description = "年级描述")
|
|
||||||
private String description;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user