commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
target/
|
||||
.idea/
|
||||
*.iml
|
||||
*.log
|
||||
.DS_Store
|
||||
@@ -0,0 +1,18 @@
|
||||
# 由 projman 注入的 Spring Boot 运行镜像(单阶段,jar 预构建)
|
||||
# CI 已先 mvn package,并在容器内把产物 cp 成固定名 target/app.jar
|
||||
# 构建上下文 = 仓库根:docker build -f docker/Dockerfile .
|
||||
# 健康检查依赖 curl(projman 部署用 curl 探 /actuator/health)——应用需含 spring-boot-starter-actuator
|
||||
# 时区 Asia/Shanghai;JAVA_OPTS 由 projman 部署 env 注入(默认 -Xms512m -Xmx1024m)
|
||||
FROM eclipse-temurin:8-jre
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl tzdata \
|
||||
&& ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY target/app.jar /app/app.jar
|
||||
|
||||
EXPOSE 10002
|
||||
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS:--Xms512m -Xmx1024m} -Dfile.encoding=UTF-8 -jar /app/app.jar"]
|
||||
@@ -0,0 +1,57 @@
|
||||
# ClassHomework 生产配置(线上以 nacos 的 classhomework.yaml 为准,本文件是 nacos 不可达时的兜底)
|
||||
# 真正上线请在 Nacos 新建 dataId=classhomework.yaml、group=OA_APP 的配置覆盖以下项
|
||||
# (尤其 datasource 的库名/账号、yh.sso.client-host-url)。
|
||||
server:
|
||||
port: 8070
|
||||
servlet:
|
||||
# 对外经 caddy 暴露为 http://base.yunhaixingtong.com/classhomework
|
||||
context-path: /classhomework
|
||||
|
||||
spring:
|
||||
mvc:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
jackson:
|
||||
time-zone: GMT+8
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
datasource:
|
||||
# 与 UserBase 共用同一台 mysql8;库名为 classhomework(需先在 mysql8 上建库)
|
||||
url: jdbc:mysql://mysql8:3306/classhomework?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: 'CVf^x$sW*b6CGHxh'
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
min-idle: 10
|
||||
max-active: 30
|
||||
jpa:
|
||||
database: MySQL
|
||||
show-sql: false
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
properties:
|
||||
hibernate.order_by.default_null_ordering: last
|
||||
open-in-view: true
|
||||
|
||||
# 单点登录 / 应用间签名鉴权(基础平台 yh-auth / yh-app-auth)
|
||||
yh:
|
||||
env-config:
|
||||
source:
|
||||
# 前端运行时配置(JSON 字符串),线上由 Nacos/projman 下发。
|
||||
# 端点 /api/env-config 由平台 yh-env-config-spring-boot-starter 提供(免登录 SSO 旁路)。
|
||||
front: ""
|
||||
sso:
|
||||
server-url-prefix: http://sso.yunhaixingtong.com
|
||||
client-host-url: http://base.yunhaixingtong.com/classhomework
|
||||
allow-headers: all
|
||||
allow-origins: all
|
||||
url-pattern: /api/*
|
||||
app-auth:
|
||||
enabled: true
|
||||
# 本应用自身身份(客户端签名用)
|
||||
app-key: 100617
|
||||
app-secret: 2a3b4c5d6e7f8091a2b3c4d5e6f70819
|
||||
# 受信应用(服务端验签用):appKey -> appSecret
|
||||
trusted-apps:
|
||||
100617: 2a3b4c5d6e7f8091a2b3c4d5e6f70819
|
||||
|
||||
# 上传文件落容器卷,compose 里挂到宿主机 ./upload-data
|
||||
FILE_PATH: /data/upload
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# ClassHomework 启动入口:配置统一由 Nacos 配置中心在 bootstrap 阶段下发(见 bootstrap.yml)
|
||||
# 不再需要手动 curl 拉取;若 nacos 不可达,bootstrap 中 fail-fast=false 会自动回退到
|
||||
# 镜像内烤好的 application-prod.yml 兜底默认。
|
||||
set -e
|
||||
|
||||
echo "[run-app] starting ClassHomework (profile=prod, nacos=${NACOS_ADDR:-nacos.yunhaixingtong.com:8848}) ..."
|
||||
exec java ${JAVA_OPTS:--Xms512m -Xmx1024m} -Dfile.encoding=UTF-8 -jar /app/classhomework.jar \
|
||||
--spring.profiles.active=prod
|
||||
@@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.18</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<groupId>com.yunhai</groupId>
|
||||
<artifactId>classhomework</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<name>ClassHomework</name>
|
||||
<description>课堂作业子应用</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<!-- 基础平台版本管理(含 yh-* 架包与 spring-boot-dependencies 对齐) -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yunhai.platform</groupId>
|
||||
<artifactId>yh-platform-dependencies</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- Spring Cloud Alibaba(Nacos 配置中心,对齐 Boot 2.7) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
|
||||
<version>2021.0.5.0</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</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-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 仅引入 Spring Security 的加密模块(BCryptPasswordEncoder),不引入整套安全框架 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos 配置中心(替代 Spring Cloud Config)。Spring Cloud Alibaba 2021.0.5 适配 Spring Boot 2.7 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
<!-- Boot 2.4+ 默认不再处理 bootstrap.yml,需显式引入以继续从 Nacos 拉取配置 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-bootstrap</artifactId>
|
||||
<version>3.1.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON 序列化(fastjson,主类开启安全模式) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.80</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger / OpenAPI 文档(springdoc,兼容 Boot 2.7) -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 基础平台全家桶(聚合 starter):认证(CAS/会话/SSO)+ 应用间签名鉴权 + 用户中心静态门面
|
||||
+ 统一响应 + actuator 健康探活,一行带齐(模块构成见 BasePlatform/后端项目知识库.md)。
|
||||
约定:标准业务服务一律引聚合 starter;平台能力提供方(如 UserBase)按需单引。 -->
|
||||
<dependency>
|
||||
<groupId>com.yunhai.platform</groupId>
|
||||
<artifactId>yh-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- CAS 客户端(浏览器 SSO 重定向 / ticket 校验 / getRemoteUser 包装)。
|
||||
版本 3.5.1 已在本地 .m2 仓库。 -->
|
||||
<dependency>
|
||||
<groupId>org.jasig.cas.client</groupId>
|
||||
<artifactId>cas-client-core</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Excel 导入导出(EasyExcel 3.x,注解驱动、流式写入内存友好) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 不引 spring-boot-starter-data-redis / cache:代码零使用,data-redis 会自动装配
|
||||
RedisHealthIndicator,连不上 redis 会把 /actuator/health 整体拉成 DOWN(503)。 -->
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>classhomework</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- 关闭增量编译,避免 Windows 下 maven-status 状态文件被锁导致
|
||||
"Error while storing the mojo status / 拒绝访问" -->
|
||||
<useIncrementalCompilation>false</useIncrementalCompilation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- 打可执行 fat jar(Docker 镜像直接 java -jar 启动) -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>com.yunhai.homework.HomeworkApplication</mainClass>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>nexus-public</id>
|
||||
<name>bsch/nexus public</name>
|
||||
<url>http://nexus.yunhaixingtong.com/repository/maven-public/</url>
|
||||
<releases><enabled>true</enabled></releases>
|
||||
<snapshots><enabled>true</enabled></snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
<!--
|
||||
ci 构建档案:将构建产物重定向到 IDE(IntelliJ/Eclipse)索引目录之外,
|
||||
避免 IDE 后台进程持续锁定 target/maven-status/.../createdFiles.lst 导致
|
||||
"Error while storing the mojo status / 拒绝访问"。
|
||||
输出目录需从未被 IDE 打开过。常规本地构建无需激活此 profile。
|
||||
-->
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>ci</id>
|
||||
<build>
|
||||
<directory>C:/classhomework-build/classhomework</directory>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yunhai.homework;
|
||||
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "com.yunhai.homework")
|
||||
@EnableTransactionManagement
|
||||
public class HomeworkApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 开启 fastjson 安全模式
|
||||
ParserConfig.getGlobalInstance().setSafeMode(true);
|
||||
SpringApplication.run(HomeworkApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.yunhai.homework.common.listener;
|
||||
|
||||
import com.yunhai.homework.entity.BaseEntity;
|
||||
import com.yunhai.homework.utils.UserContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.PreUpdate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* JPA 审计监听器:在实体持久化/更新前自动填充创建人/更新人(平台当前登录人)与时间戳。
|
||||
* 对应 {@link BaseEntity} 的 createBy / updateBy / createTime / updateTime 字段。
|
||||
* 当前登录人取自 {@link UserContext}(用户中心数字ID,字符串形式落审计列)。
|
||||
*/
|
||||
@Component
|
||||
public class HomeworkAuditListener {
|
||||
|
||||
@PrePersist
|
||||
public void prePersist(BaseEntity entity) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
entity.setCreateTime(now);
|
||||
entity.setUpdateTime(now);
|
||||
Integer userId = UserContext.getUserId();
|
||||
if (userId != null) {
|
||||
if (entity.getCreateBy() == null) {
|
||||
entity.setCreateBy(String.valueOf(userId));
|
||||
}
|
||||
entity.setUpdateBy(String.valueOf(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate(BaseEntity entity) {
|
||||
entity.setUpdateTime(LocalDateTime.now());
|
||||
Integer userId = UserContext.getUserId();
|
||||
if (userId != null) {
|
||||
entity.setUpdateBy(String.valueOf(userId));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.yunhai.homework.common.validation;
|
||||
|
||||
/**
|
||||
* JSR-303 分组校验标记接口(对齐 UserBase 规范)。
|
||||
* Create:新建场景必填字段;Update:编辑场景必填字段(通常含 id)。
|
||||
*/
|
||||
public interface ValidationGroups {
|
||||
interface Create {}
|
||||
interface Update {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.yunhai.homework.config;
|
||||
|
||||
/**
|
||||
* 全局路径常量。与 UserBase 一致:API 统一挂在 /{platform}/ 之下(platform = api / manage / mobiapi)。
|
||||
*/
|
||||
public enum Config {
|
||||
Inst;
|
||||
|
||||
public static final String API_PATH = "/{platform}"; // manage / api / mobiapi,前面有/后面无/,拼接子路径时用"/"分隔
|
||||
public static final String OPEN_API_PATH = "/oapi";
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.yunhai.homework.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Jackson 时间序列化全局约定(对齐旧 .NET 版 "yyyy-MM-dd HH:mm:ss"):
|
||||
* 接口出入参中的 LocalDateTime/LocalDate 统一使用该格式,避免 ISO 的 "T" 分隔符
|
||||
* (如 2026-09-01T16:38:40)直接暴露给前端表格。
|
||||
*/
|
||||
@Configuration
|
||||
public class JacksonConfig {
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
|
||||
return builder -> builder
|
||||
.serializers(
|
||||
new LocalDateTimeSerializer(DATE_TIME),
|
||||
new LocalDateSerializer(DATE))
|
||||
.deserializers(
|
||||
new LocalDateTimeDeserializer(DATE_TIME),
|
||||
new LocalDateDeserializer(DATE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.yunhai.homework.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 开启 @Scheduled 定时任务(作业定时发布 / 到点截止 / 截止提醒 / 名册同步)。
|
||||
* 单实例假设;多实例部署前需引入分布式锁(计划 §13-7)。
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
public class SchedulingConfig {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.homework.config;
|
||||
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 接口文档(springdoc-openapi,替代旧 Springfox)。
|
||||
*/
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI homeworkOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("课程作业接口文档")
|
||||
.description("课程作业子应用:发作业、列表、删除、编辑、管理员查看、统计(springdoc-openapi)")
|
||||
.version("1.0"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.yunhai.homework.config;
|
||||
|
||||
import com.yunhai.homework.utils.UserContext;
|
||||
import com.yunhai.platform.auth.spring.CurrentBoaUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* {@link UserContext} 生命周期配置:
|
||||
* 启动时向 UserContext 注入平台 BoaUser 供应器(取值在首次访问时惰性解析),
|
||||
* 并注册拦截器在每个请求结束后清理 ThreadLocal(Tomcat 线程复用防串号)。
|
||||
*/
|
||||
@Configuration
|
||||
public class UserContextConfig {
|
||||
|
||||
@Autowired
|
||||
private CurrentBoaUser currentBoaUser;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
UserContext.init(currentBoaUser);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HandlerInterceptor userContextCleanInterceptor() {
|
||||
return new HandlerInterceptor() {
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) {
|
||||
UserContext.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer userContextConfigurer(HandlerInterceptor userContextCleanInterceptor) {
|
||||
return new WebMvcConfigurer() {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(userContextCleanInterceptor).addPathPatterns("/**");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.model.homework.UpFileResultVo;
|
||||
import com.yunhai.homework.service.IFileService;
|
||||
import com.yunhai.homework.service.IUserCenterService;
|
||||
import com.yunhai.platform.auth.LoginUser;
|
||||
import com.yunhai.platform.auth.UserContextHolder;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 平台代理域接口(base/)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/base/"}(原硬编码已修正)。
|
||||
* 承载平台代理接口:GetUserInfo / GetUserMod / GetSchoolAll / GetGroupUser / Logout,
|
||||
* 业务逻辑已下沉 {@link IUserCenterService},本控制器仅做"取参 → 调 Service → 返回"。
|
||||
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。</p>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/base/")
|
||||
public class BaseApiController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseApiController.class);
|
||||
|
||||
@Autowired
|
||||
private IUserCenterService userCenterService;
|
||||
|
||||
@Autowired
|
||||
private IFileService fileService;
|
||||
|
||||
// ============================ FileUpload ============================
|
||||
|
||||
/**
|
||||
* 附件上传(单文件)。
|
||||
* 前端: POST base/FileUpload (form-data: file)
|
||||
* 返回: { fileid, host, fileurl, name, type, size }
|
||||
*/
|
||||
@PostMapping("FileUpload")
|
||||
public UpFileResultVo fileUpload(@RequestParam("file") MultipartFile file) {
|
||||
return fileService.uploadToResult(file, "homework");
|
||||
}
|
||||
|
||||
// ============================ GetUserInfo ============================
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息(CAS 会话注入)。
|
||||
*/
|
||||
@GetMapping("GetUserInfo")
|
||||
public BoaUser getUserInfo(BoaUser authUserWithDept) {
|
||||
return authUserWithDept;
|
||||
}
|
||||
|
||||
// ============================ GetUserMod ============================
|
||||
|
||||
/**
|
||||
* 获取当前用户已授权的模块列表(左侧菜单树)。
|
||||
* 模块树组装已下沉 IUserCenterService。
|
||||
*/
|
||||
@GetMapping("GetUserMod")
|
||||
public List<Map<String, Object>> getUserMod(BoaUser authUserWithDept) {
|
||||
Integer schId = authUserWithDept.getCurrentRole() != null
|
||||
? authUserWithDept.getCurrentRole().getSchId() : null;
|
||||
return userCenterService.getUserModuleTree(authUserWithDept.getId(), schId);
|
||||
}
|
||||
|
||||
// ============================ GetSchoolAll ============================
|
||||
|
||||
/**
|
||||
* 获取当前用户学校组及用户(树形结构)。
|
||||
* 组树组装/教师挂组/递归建树逻辑已下沉 IUserCenterService。
|
||||
*/
|
||||
@GetMapping("GetSchoolAll")
|
||||
public List<Map<String, Object>> getSchoolAll(BoaUser authUserWithDept) {
|
||||
Integer schId = authUserWithDept.getCurrentRole() != null
|
||||
? authUserWithDept.getCurrentRole().getSchId() : null;
|
||||
return userCenterService.getSchoolAllTree(schId);
|
||||
}
|
||||
|
||||
// ============================ GetGroupUser ============================
|
||||
|
||||
/**
|
||||
* 获取指定组内用户(教师 + 管理员)。
|
||||
* 空桩已改为显式报错(避免前端误以为组内无用户),由 IUserCenterService 统一处理。
|
||||
*/
|
||||
@GetMapping("GetGroupUser")
|
||||
public List<Map<String, Object>> getGroupUser(
|
||||
@RequestParam("gid") Integer gid,
|
||||
@RequestParam(value = "role", defaultValue = "2") Integer role) {
|
||||
return userCenterService.getGroupUser(gid, role);
|
||||
}
|
||||
|
||||
// ============================ Logout ============================
|
||||
|
||||
/**
|
||||
* 退出登录。
|
||||
* 认证由平台网关处理,此处仅返回成功。
|
||||
*/
|
||||
@PostMapping("Logout")
|
||||
public void logout() {
|
||||
LoginUser user = UserContextHolder.get();
|
||||
log.info("[logout] 用户退出登录: {}", user == null ? null : user.getLoginName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.service.IContactsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 联系组接口(contacts/)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/contacts/"}(原硬编码已修正为 Config 拼接)。
|
||||
* 方法名已为 PascalCase 且写操作已是 POST,保持不动。
|
||||
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。</p>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/contacts/")
|
||||
public class ContactsController {
|
||||
|
||||
@Autowired
|
||||
private IContactsService contactsService;
|
||||
|
||||
/**
|
||||
* 添加联系组。
|
||||
*/
|
||||
@PostMapping("AddGroup")
|
||||
public void addGroup(
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam(value = "type", required = false, defaultValue = "1") String type) {
|
||||
contactsService.addGroup(name, Integer.parseInt(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系组列表。
|
||||
*/
|
||||
@GetMapping("GetGroup")
|
||||
public Map<String, Object> getGroup(
|
||||
@RequestParam(value = "page", defaultValue = "0") Integer page,
|
||||
@RequestParam(value = "count", defaultValue = "0") Integer count,
|
||||
@RequestParam(value = "type", defaultValue = "1") Integer type) {
|
||||
return contactsService.getGroup(page, count, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑联系组。
|
||||
*/
|
||||
@PostMapping("EditGroup")
|
||||
public void editGroup(
|
||||
@RequestParam("name") String name,
|
||||
@RequestParam("id") String id,
|
||||
@RequestParam(value = "type", required = false, defaultValue = "1") String type) {
|
||||
contactsService.editGroup(Integer.parseInt(id), name, Integer.parseInt(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除联系组(支持批量)。
|
||||
*/
|
||||
@PostMapping("DelGroup")
|
||||
public void delGroup(@RequestParam("ids") String ids) {
|
||||
contactsService.delGroup(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置联系组教师。
|
||||
*/
|
||||
@PostMapping("SetContactsTea")
|
||||
public void setContactsTea(
|
||||
@RequestParam("gid") String gid,
|
||||
@RequestParam(value = "ids", required = false) String ids) {
|
||||
contactsService.setContactsTea(Integer.parseInt(gid), ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系组教师列表。
|
||||
*/
|
||||
@GetMapping("GetContactsTea")
|
||||
public Map<String, Object> getContactsTea(
|
||||
@RequestParam("gid") String gid,
|
||||
@RequestParam(value = "page", defaultValue = "0") Integer page,
|
||||
@RequestParam(value = "count", defaultValue = "0") Integer count) {
|
||||
return contactsService.getContactsTea(gid, page, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系组树。
|
||||
*/
|
||||
@GetMapping("GetGroupTree")
|
||||
public List<Map<String, Object>> getGroupTree(@RequestParam("type") Integer type) {
|
||||
return contactsService.getGroupTree(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门角色组树。
|
||||
*/
|
||||
@GetMapping("GetDeptRoleGroupTree")
|
||||
public List<Map<String, Object>> getDeptRoleGroupTree() {
|
||||
return contactsService.getDeptRoleGroupTree();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.service.IDictService;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统字典接口(发文部门域)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/dict/"}(原 base/ 前缀已修正)。
|
||||
* 写操作一律 POST(原 DelDept/OrdbyDicIds 为 GET 写操作,已 POST 化)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/dict/")
|
||||
public class DictController {
|
||||
|
||||
@Autowired
|
||||
private IDictService dictService;
|
||||
|
||||
/**
|
||||
* 获取系统字典(下拉框用)。
|
||||
*/
|
||||
@GetMapping("List")
|
||||
public List<Map<String, Object>> list(@RequestParam(value = "type", defaultValue = "0") Integer type) {
|
||||
return dictService.getSysDic(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统字典管理列表。
|
||||
*/
|
||||
@GetMapping("ManageList")
|
||||
public List<Map<String, Object>> manageList(@RequestParam(value = "type", defaultValue = "dept") String type) {
|
||||
return dictService.getDictMangeList(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加发文单位。
|
||||
*/
|
||||
@PostMapping("Add")
|
||||
public void add(@RequestParam("name") String name) {
|
||||
dictService.addDeptDic(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新发文单位。
|
||||
*/
|
||||
@PostMapping("Update")
|
||||
public void update(
|
||||
@RequestParam("SerID") Integer serID,
|
||||
@RequestParam("Name") String name,
|
||||
@RequestParam(value = "Enable", required = false, defaultValue = "1") Integer enable) {
|
||||
dictService.updateDeptDic(serID, name, enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除发文单位(原 GET DelDept,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("Delete")
|
||||
public void delete(@RequestParam("serid") Integer serID) {
|
||||
dictService.delDept(serID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发文单位排序(原 GET OrdbyDicIds,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("Sort")
|
||||
public void sort(@RequestParam("ids") String ids) {
|
||||
dictService.ordbyDicIds(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 本校是否开通短信模块(前端用作"本校是否开通短信")。
|
||||
* 取当前登录用户角色所属学校,查 sms_school_config 是否开通本应用模块。
|
||||
*/
|
||||
@GetMapping("Sync")
|
||||
public Boolean sync(BoaUser authUserWithDept) {
|
||||
Integer schId = authUserWithDept != null && authUserWithDept.getCurrentRole() != null
|
||||
? authUserWithDept.getCurrentRole().getSchId() : null;
|
||||
return dictService.getSchModuleIsSms(schId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.model.homework.UpFileResultVo;
|
||||
import com.yunhai.homework.model.homework.UpFileVo;
|
||||
import com.yunhai.homework.service.IFileService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 附件域接口(file/)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/file/"}(原 base/ 前缀已修正为独立文件域)。
|
||||
* 方法名统一 PascalCase;写操作一律 POST。
|
||||
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。</p>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/file/")
|
||||
public class FileController {
|
||||
|
||||
@Autowired
|
||||
private IFileService fileService;
|
||||
|
||||
/**
|
||||
* 附件上传(单文件)。
|
||||
* 前端: POST file/Upload (form-data)
|
||||
* 返回: { fileid, host, fileurl, name, type, size }
|
||||
*/
|
||||
@PostMapping("Upload")
|
||||
public UpFileResultVo upload(@RequestParam("file") MultipartFile file) {
|
||||
return fileService.uploadToResult(file, "homework");
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传(多文件,返回数组)。
|
||||
* 前端: POST file/UploadImage (form-data, accept=image/*)
|
||||
*/
|
||||
@PostMapping("UploadImage")
|
||||
public List<UpFileVo> uploadImage(@RequestParam("file") MultipartFile[] files) {
|
||||
return fileService.uploadImages(files, "homework");
|
||||
}
|
||||
/**
|
||||
* 文件下载(浏览器直接 location.href 跳转)。
|
||||
*/
|
||||
@GetMapping("Down")
|
||||
public void down(@RequestParam("id") Integer id, HttpServletResponse response) {
|
||||
fileService.download(id, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件在线预览(inline 输出,前端取 Blob 交给 open-file-viewer 渲染)。
|
||||
*/
|
||||
@GetMapping("Preview")
|
||||
public void preview(@RequestParam("id") Integer id,
|
||||
@RequestParam(value = "type", required = false) Integer type,
|
||||
HttpServletResponse response) {
|
||||
fileService.preview(id, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除文件。
|
||||
*/
|
||||
@PostMapping("Delete")
|
||||
public void delete(@RequestParam("fileId") Integer fileId) {
|
||||
fileService.delete(fileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询某作业下的附件列表。
|
||||
*/
|
||||
@GetMapping("List")
|
||||
public List<UpFileVo> list(@RequestParam("topicId") Integer topicId) {
|
||||
return fileService.listByTopic("homework", topicId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量绑定附件到作业。
|
||||
*/
|
||||
@PostMapping("Bind")
|
||||
public void bind(@RequestParam("fileIds") List<Integer> fileIds,
|
||||
@RequestParam("topicId") Integer topicId) {
|
||||
fileService.bindToTopic(fileIds, topicId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.common.validation.ValidationGroups;
|
||||
import com.yunhai.homework.model.BasePageResult;
|
||||
import com.yunhai.homework.model.homework.*;
|
||||
import com.yunhai.homework.service.IHomeworkService;
|
||||
import com.yunhai.homework.utils.PageUtils;
|
||||
import com.yunhai.platform.utils.model.BoaUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 课程作业接口(合并 HomeworkApiController + 旧 HomeworkController)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/homework/"}(platform = api / manage / mobiapi)。
|
||||
* 方法动词式 PascalCase(对齐 UserBase);写操作一律 POST。
|
||||
* 返回裸对象,由 ApiResponseAdvice 自动包装为 {code, msg, data}。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/homework/")
|
||||
public class HomeworkController {
|
||||
|
||||
@Autowired
|
||||
private IHomeworkService homeworkService;
|
||||
|
||||
// ============================ 收件箱列表 ============================
|
||||
|
||||
/**
|
||||
* 已收作业列表(用户端)。
|
||||
*/
|
||||
@GetMapping("List")
|
||||
public HomeworkPageResult<HomeworkVo> list(HomeworkQuery query,
|
||||
@SortDefault(sort = {"topmost", "createTime"},
|
||||
direction = Sort.Direction.DESC) Sort sort) {
|
||||
return homeworkService.userList(query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 已发/全部作业列表 ============================
|
||||
|
||||
/**
|
||||
* 已发/全部作业列表(管理端)。type=user 只看自己。
|
||||
*/
|
||||
@GetMapping("SendList")
|
||||
public BasePageResult<HomeworkVo> sendList(HomeworkQuery query,
|
||||
@SortDefault(sort = "createTime",
|
||||
direction = Sort.Direction.DESC) Sort sort) {
|
||||
return homeworkService.adminList(query, PageUtils.toPageable(query, sort));
|
||||
}
|
||||
|
||||
// ============================ 查看详情(标读) ============================
|
||||
|
||||
/**
|
||||
* 查看作业详情(type=1 普通查看标记已读, type=0 编辑模式不标记已读)。
|
||||
*/
|
||||
@GetMapping("Detail")
|
||||
public HomeworkDetailVo detail(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "type", defaultValue = "1") Integer type) {
|
||||
return homeworkService.detailMap(serid, type);
|
||||
}
|
||||
|
||||
// ============================ 编辑回显(不标读) ============================
|
||||
|
||||
/**
|
||||
* 获取作业详情(编辑/转发用,不标记已读)。
|
||||
*/
|
||||
@GetMapping("GetDetail")
|
||||
public HomeworkDetailVo getDetail(@RequestParam("serid") Integer serid) {
|
||||
return homeworkService.getDetailMap(serid);
|
||||
}
|
||||
|
||||
// ============================ 新建 ============================
|
||||
|
||||
/**
|
||||
* 新建作业(JSON body)。fileIds 为附件ID逗号串,smsFlag 为短信标记。
|
||||
*/
|
||||
@PostMapping("Create")
|
||||
public Integer create(@RequestBody @Validated(ValidationGroups.Create.class) HomeworkRequest request) {
|
||||
return homeworkService.publish(request);
|
||||
}
|
||||
|
||||
// ============================ 编辑 ============================
|
||||
|
||||
/**
|
||||
* 编辑作业(JSON body,含 id)。
|
||||
*/
|
||||
@PostMapping("Edit")
|
||||
public void edit(@RequestBody @Validated(ValidationGroups.Update.class) HomeworkRequest request) {
|
||||
homeworkService.edit(request.getSourceId() != null ? request.getSourceId() : 0, request);
|
||||
}
|
||||
|
||||
// ============================ 批量删除 ============================
|
||||
|
||||
/**
|
||||
* 批量删除作业(ids 数组)。
|
||||
*/
|
||||
@PostMapping("Delete")
|
||||
public void delete(@RequestBody List<Integer> ids) {
|
||||
homeworkService.deleteBatch(ids);
|
||||
}
|
||||
|
||||
// ============================ 撤回 ============================
|
||||
|
||||
/**
|
||||
* 撤回作业。
|
||||
*/
|
||||
@PostMapping("UserPull")
|
||||
public void userPull(@RequestParam("serid") Integer serid) {
|
||||
homeworkService.pull(serid);
|
||||
}
|
||||
|
||||
// ============================ 置顶 ============================
|
||||
|
||||
/**
|
||||
* 置顶/取消置顶。
|
||||
*/
|
||||
@PostMapping("SetTopmost")
|
||||
public void setTopmost(@RequestParam("serid") Integer serid,
|
||||
@RequestParam(value = "topmost", defaultValue = "1") Integer topmost) {
|
||||
homeworkService.setTopmost(serid, topmost);
|
||||
}
|
||||
|
||||
// ============================ 追加接收人 ============================
|
||||
|
||||
/**
|
||||
* 追加接收人。
|
||||
*/
|
||||
@PostMapping("ReceiveUsers")
|
||||
public void receiveUsers(@RequestParam("serid") Integer serid,
|
||||
@RequestParam("users") String users) {
|
||||
homeworkService.receiveUsers(serid, users);
|
||||
}
|
||||
|
||||
// ============================ 催收 ============================
|
||||
|
||||
/**
|
||||
* 催收未读。
|
||||
*/
|
||||
@PostMapping("Expedite")
|
||||
public void expedite(@RequestParam("serid") Integer serid) {
|
||||
homeworkService.expedite(serid);
|
||||
}
|
||||
|
||||
// ============================ 一键已读 ============================
|
||||
|
||||
/**
|
||||
* 一键全部已读(POST 化,原为 GET 写操作)。
|
||||
*/
|
||||
@PostMapping("InitializeRed")
|
||||
public InitializeRedVo initializeRed() {
|
||||
return homeworkService.initializeRedResult();
|
||||
}
|
||||
|
||||
// ============================ 阅读情况 ============================
|
||||
|
||||
/**
|
||||
* 阅读情况(按已读/未读分组)。
|
||||
*/
|
||||
@GetMapping("ReadDetail")
|
||||
public List<Map<String, Object>> readDetail(@RequestParam("serid") Integer serid) {
|
||||
return homeworkService.getReadDetailGrouped(serid);
|
||||
}
|
||||
|
||||
// ============================ 上一篇/下一篇 ============================
|
||||
|
||||
/**
|
||||
* 上一篇/下一篇作业ID。
|
||||
*/
|
||||
@GetMapping("GetNextPrev")
|
||||
public Map<String, Object> getNextPrev(@RequestParam("serid") Integer serid,
|
||||
@RequestParam("type") String type) {
|
||||
return homeworkService.getNextPrev(serid, type);
|
||||
}
|
||||
|
||||
// ============================ 附件打包下载 ============================
|
||||
|
||||
/**
|
||||
* 批量下载作业全部附件(打包 zip)。
|
||||
*/
|
||||
@GetMapping("AllFileDown")
|
||||
public void allFileDown(@RequestParam("dataid") Integer dataid,
|
||||
HttpServletResponse response) {
|
||||
homeworkService.downloadAllFiles(dataid, response);
|
||||
}
|
||||
|
||||
// ============================ 统计 ============================
|
||||
|
||||
/**
|
||||
* 作业统计。
|
||||
*/
|
||||
@GetMapping("Statis")
|
||||
public HomeworkStatisticsVo statis(
|
||||
@RequestParam(value = "starttime", required = false)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime start,
|
||||
@RequestParam(value = "endtime", required = false)
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime end) {
|
||||
return homeworkService.statistics(new HomeworkQuery(), start, end);
|
||||
}
|
||||
|
||||
// ============================ 转发(合并旧 REST 壳 forward) ============================
|
||||
|
||||
/**
|
||||
* 转发作业(基于源作业创建新作业)。sourceId 在 request body 中传递。
|
||||
*/
|
||||
@PostMapping("Forward")
|
||||
public Integer forward(@RequestBody @Validated(ValidationGroups.Create.class) HomeworkRequest request) {
|
||||
return homeworkService.forward(request.getSourceId(), request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.model.v2.NotificationPageResult;
|
||||
import com.yunhai.homework.model.v2.NotificationQuery;
|
||||
import com.yunhai.homework.service.impl.NotificationService;
|
||||
import com.yunhai.homework.utils.UserContext;
|
||||
import com.yunhai.platform.apistd.BizException;
|
||||
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 站内通知接口(PRD §18 未列,按计划 §7.3 补充)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/notifications")
|
||||
public class NotificationController {
|
||||
|
||||
@Autowired
|
||||
private NotificationService notificationService;
|
||||
|
||||
/** 我的通知分页(含未读数;type/isRead 过滤) */
|
||||
@GetMapping
|
||||
public NotificationPageResult page(NotificationQuery query) {
|
||||
return notificationService.page(currentUserId(), query);
|
||||
}
|
||||
|
||||
/** 标记单条已读 */
|
||||
@PostMapping("/{id}/read")
|
||||
public void markRead(@PathVariable("id") Integer id) {
|
||||
notificationService.markRead(id, currentUserId());
|
||||
}
|
||||
|
||||
/** 全部已读 */
|
||||
@PostMapping("/read-all")
|
||||
public void markAllRead() {
|
||||
notificationService.markAllRead(currentUserId());
|
||||
}
|
||||
|
||||
/** 当前登录人ID(用户中心数字ID),无登录态时拒绝 */
|
||||
private static Integer currentUserId() {
|
||||
Integer userId = UserContext.getUserId();
|
||||
if (userId == null) {
|
||||
throw new BizException(ErrorCode.FORBIDDEN, "未获取到登录身份");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.service.ISmsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 短信设置接口(短信域)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/sms/"}(原 schsms/ 已修正)。
|
||||
* 方法名 PascalCase(原全小写已修正);写操作一律 POST(原 setschallsms/setschmodulesms 为 GET 写操作,已 POST 化)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/sms/")
|
||||
public class SmsController {
|
||||
|
||||
@Autowired
|
||||
private ISmsService smsService;
|
||||
|
||||
/**
|
||||
* 获取短信模块列表。
|
||||
*/
|
||||
@GetMapping("GetModule")
|
||||
public List<Map<String, Object>> getModule() {
|
||||
return smsService.getModuleList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学校父类组列表。
|
||||
*/
|
||||
@GetMapping("GetGroup")
|
||||
public List<Map<String, Object>> getGroup() {
|
||||
return smsService.getSchParentGroup();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取学校短信开关列表。
|
||||
*/
|
||||
@GetMapping("GetSchoolSms")
|
||||
public Map<String, Object> getSchoolSms(
|
||||
@RequestParam(value = "schpid", required = false) String schpid,
|
||||
@RequestParam("PageSize") Integer pageSize,
|
||||
@RequestParam("PageIndex") Integer pageIndex,
|
||||
@RequestParam(value = "SchName", required = false, defaultValue = "") String schName) {
|
||||
return smsService.getSchIsSmsList(pageSize, pageIndex, schName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学校列表。
|
||||
*/
|
||||
@GetMapping("GetSchool")
|
||||
public List<Map<String, Object>> getSchool() {
|
||||
return smsService.getSchList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置单校单模块短信开关。
|
||||
*/
|
||||
@PostMapping("SetSchoolSms")
|
||||
public void setSchoolSms(@RequestParam("itemsModu") String itemsModuJson) {
|
||||
smsService.setSchSmsFromJson(itemsModuJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置某校全部模块短信开关(原 GET setschallsms,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("SetAllSchoolSms")
|
||||
public void setAllSchoolSms(
|
||||
@RequestParam("SchSerID") Integer schSerID,
|
||||
@RequestParam("IsSms") Boolean isSms) {
|
||||
smsService.setSchSmsAll(schSerID, isSms);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置多校多模块短信开关(原 GET setschmodulesms,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("SetSchoolModuleSms")
|
||||
public void setSchoolModuleSms(
|
||||
@RequestParam("SchSerID") String schSerID,
|
||||
@RequestParam("Module") String module,
|
||||
@RequestParam("IsSms") Boolean isSms) {
|
||||
smsService.setSchModuleSms(schSerID, module, isSms);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.model.BasePageQuery;
|
||||
import com.yunhai.homework.model.BasePageResult;
|
||||
import com.yunhai.homework.model.v2.StudentHomeworkDetailVo;
|
||||
import com.yunhai.homework.model.v2.StudentHomeworkVo;
|
||||
import com.yunhai.homework.model.v2.StudentResultVo;
|
||||
import com.yunhai.homework.model.v2.StudentSubmitRequest;
|
||||
import com.yunhai.homework.model.v2.SubmissionActionRequest;
|
||||
import com.yunhai.homework.service.impl.StudentHomeworkService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 课堂作业 V2 学生端接口(PRD §18 路径一字对齐:/student/homeworks…)。
|
||||
* <p>
|
||||
* 身份:当前登录用户ID ↔ class_student 名册;仅可见本人班级作业,禁 IDOR。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/student/homeworks")
|
||||
public class StudentHomeworkController {
|
||||
|
||||
@Autowired
|
||||
private StudentHomeworkService studentHomeworkService;
|
||||
|
||||
/** 我的作业列表(tab=all/todo/done/closed) */
|
||||
@GetMapping
|
||||
public BasePageResult<StudentHomeworkVo> list(
|
||||
@RequestParam(value = "tab", defaultValue = "all") String tab,
|
||||
BasePageQuery query) {
|
||||
return studentHomeworkService.list(tab, query);
|
||||
}
|
||||
|
||||
/** 作业详情 */
|
||||
@GetMapping("/{id}")
|
||||
public StudentHomeworkDetailVo detail(@PathVariable("id") Integer id) {
|
||||
return studentHomeworkService.detail(id);
|
||||
}
|
||||
|
||||
/** 阅读上报(前端停留 ≥3 秒后调用;幂等) */
|
||||
@PostMapping("/{id}/read")
|
||||
public void read(@PathVariable("id") Integer id) {
|
||||
studentHomeworkService.read(id);
|
||||
}
|
||||
|
||||
/** 提交作业,返回新提交行 id */
|
||||
@PostMapping("/{id}/submissions")
|
||||
public Map<String, Integer> submit(@PathVariable("id") Integer id,
|
||||
@RequestBody @Validated StudentSubmitRequest request) {
|
||||
Integer submissionId = studentHomeworkService.submit(id, request);
|
||||
return java.util.Collections.singletonMap("submissionId", submissionId);
|
||||
}
|
||||
|
||||
/** 撤回 / 打回后重交(action=withdraw|resubmit),返回新提交行 id */
|
||||
@PutMapping("/{id}/submissions/{submissionId}")
|
||||
public Map<String, Integer> action(@PathVariable("id") Integer id,
|
||||
@PathVariable("submissionId") Integer submissionId,
|
||||
@RequestBody @Validated SubmissionActionRequest request) {
|
||||
Integer newId = studentHomeworkService.action(id, submissionId, request);
|
||||
return java.util.Collections.singletonMap("submissionId", newId);
|
||||
}
|
||||
|
||||
/** 批阅结果(当前版本 + 历史版本) */
|
||||
@GetMapping("/{id}/result")
|
||||
public StudentResultVo result(@PathVariable("id") Integer id) {
|
||||
return studentHomeworkService.result(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.model.BasePageResult;
|
||||
import com.yunhai.homework.model.v2.ClassTreeNode;
|
||||
import com.yunhai.homework.model.v2.ExtendRequest;
|
||||
import com.yunhai.homework.model.v2.HomeworkStatsVo;
|
||||
import com.yunhai.homework.model.v2.HomeworkV2Request;
|
||||
import com.yunhai.homework.model.v2.HomeworkV2Vo;
|
||||
import com.yunhai.homework.model.v2.RemindRequest;
|
||||
import com.yunhai.homework.model.v2.ReturnRequest;
|
||||
import com.yunhai.homework.model.v2.ReviewRequest;
|
||||
import com.yunhai.homework.model.v2.ScheduleRequest;
|
||||
import com.yunhai.homework.model.v2.StudentMatrixQuery;
|
||||
import com.yunhai.homework.model.v2.StudentMatrixVo;
|
||||
import com.yunhai.homework.model.v2.SubmissionVersionVo;
|
||||
import com.yunhai.homework.model.v2.SubjectDto;
|
||||
import com.yunhai.homework.model.v2.TeacherHomeworkQuery;
|
||||
import com.yunhai.homework.model.v2.TeachingClassVo;
|
||||
import com.yunhai.homework.service.impl.ClassStudentService;
|
||||
import com.yunhai.homework.service.impl.TeacherHomeworkV2Service;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 课堂作业 V2 教师端接口(PRD §18 路径一字对齐:/teacher/homeworks…)。
|
||||
* <p>
|
||||
* 与 notice 语义的旧接口(/{platform}/homework/*)并存:旧接口冻结维护,
|
||||
* 新业务一律走本控制器;返回裸对象由 ApiResponseAdvice 包装 {code,msg,data}。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/teacher/homeworks")
|
||||
public class TeacherHomeworkV2Controller {
|
||||
|
||||
@Autowired
|
||||
private TeacherHomeworkV2Service teacherHomeworkV2Service;
|
||||
|
||||
@Autowired
|
||||
private ClassStudentService classStudentService;
|
||||
|
||||
// ============================ 页 1:发布作业 ============================
|
||||
|
||||
/** 创建作业(落草稿) */
|
||||
@PostMapping
|
||||
public Integer create(@RequestBody @Validated HomeworkV2Request request) {
|
||||
return teacherHomeworkV2Service.create(request);
|
||||
}
|
||||
|
||||
/** 编辑作业(仅草稿) */
|
||||
@PutMapping("/{id}")
|
||||
public void edit(@PathVariable("id") Integer id,
|
||||
@RequestBody @Validated HomeworkV2Request request) {
|
||||
teacherHomeworkV2Service.edit(id, request);
|
||||
}
|
||||
|
||||
/** 删除作业(仅草稿) */
|
||||
@DeleteMapping("/{id}")
|
||||
public void delete(@PathVariable("id") Integer id) {
|
||||
teacherHomeworkV2Service.delete(id);
|
||||
}
|
||||
|
||||
/** 立即发布(草稿 → 进行中) */
|
||||
@PostMapping("/{id}/publish")
|
||||
public void publish(@PathVariable("id") Integer id) {
|
||||
teacherHomeworkV2Service.publish(id);
|
||||
}
|
||||
|
||||
/** 定时发布 / 取消定时(body: {scheduledAt} 或 {cancel:true}) */
|
||||
@PostMapping("/{id}/schedule")
|
||||
public void schedule(@PathVariable("id") Integer id, @RequestBody ScheduleRequest request) {
|
||||
teacherHomeworkV2Service.schedule(id, request);
|
||||
}
|
||||
|
||||
// ============================ 页 2:草稿箱 ============================
|
||||
|
||||
/** 草稿箱分页 */
|
||||
@GetMapping("/drafts")
|
||||
public BasePageResult<HomeworkV2Vo> drafts(TeacherHomeworkQuery query,
|
||||
@SortDefault(sort = "updateTime", direction = Sort.Direction.DESC) Sort sort) {
|
||||
return teacherHomeworkV2Service.drafts(query, sort);
|
||||
}
|
||||
|
||||
// ============================ 页 3:已发布列表 ============================
|
||||
|
||||
/** 已发布列表分页(含应交/已读/已交/未读未交聚合) */
|
||||
@GetMapping("/published")
|
||||
public BasePageResult<HomeworkV2Vo> published(TeacherHomeworkQuery query,
|
||||
@SortDefault(sort = "publishedAt", direction = Sort.Direction.DESC) Sort sort) {
|
||||
return teacherHomeworkV2Service.published(query, sort);
|
||||
}
|
||||
|
||||
/** 提醒未读/未交学生,返回实际提醒人数 */
|
||||
@PostMapping("/{id}/remind")
|
||||
public Map<String, Integer> remind(@PathVariable("id") Integer id, @RequestBody RemindRequest request) {
|
||||
int reminded = teacherHomeworkV2Service.remind(id, request);
|
||||
return java.util.Collections.singletonMap("reminded", reminded);
|
||||
}
|
||||
|
||||
/** 延长截止时间 */
|
||||
@PostMapping("/{id}/extend")
|
||||
public void extend(@PathVariable("id") Integer id, @RequestBody @Validated ExtendRequest request) {
|
||||
teacherHomeworkV2Service.extend(id, request);
|
||||
}
|
||||
|
||||
/** 复制为新草稿,返回新作业 id */
|
||||
@PostMapping("/{id}/copy")
|
||||
public Integer copy(@PathVariable("id") Integer id) {
|
||||
return teacherHomeworkV2Service.copy(id);
|
||||
}
|
||||
|
||||
/** 归档(只读,不再触发任何提醒) */
|
||||
@PostMapping("/{id}/archive")
|
||||
public void archive(@PathVariable("id") Integer id) {
|
||||
teacherHomeworkV2Service.archive(id);
|
||||
}
|
||||
|
||||
/** 导出学生矩阵 Excel */
|
||||
@GetMapping("/{id}/export")
|
||||
public void export(@PathVariable("id") Integer id, HttpServletResponse response) throws IOException {
|
||||
teacherHomeworkV2Service.export(id, response);
|
||||
}
|
||||
|
||||
// ============================ 页 4:详情 / 统计 ============================
|
||||
|
||||
/** 作业详情 */
|
||||
@GetMapping("/{id}")
|
||||
public HomeworkV2Vo detail(@PathVariable("id") Integer id) {
|
||||
return teacherHomeworkV2Service.detail(id);
|
||||
}
|
||||
|
||||
/** 汇总统计卡片(总进度 + 分班进度) */
|
||||
@GetMapping("/{id}/stats")
|
||||
public HomeworkStatsVo stats(@PathVariable("id") Integer id) {
|
||||
return teacherHomeworkV2Service.stats(id);
|
||||
}
|
||||
|
||||
// ============================ 页 5:学生矩阵 ============================
|
||||
|
||||
/** 学生矩阵分页(阅读/提交/批阅状态,未交学生生成占位行) */
|
||||
@GetMapping("/{id}/students")
|
||||
public BasePageResult<StudentMatrixVo> students(@PathVariable("id") Integer id,
|
||||
StudentMatrixQuery query) {
|
||||
return teacherHomeworkV2Service.students(id, query);
|
||||
}
|
||||
|
||||
// ============================ 页 6:批阅 / 打回 / 版本 ============================
|
||||
|
||||
/** 保存批阅(→ REVIEWED,推送批阅完成通知) */
|
||||
@PostMapping("/{id}/submissions/{studentId}/review")
|
||||
public void review(@PathVariable("id") Integer id, @PathVariable("studentId") Integer studentId,
|
||||
@RequestBody @Validated ReviewRequest request) {
|
||||
teacherHomeworkV2Service.review(id, studentId, request);
|
||||
}
|
||||
|
||||
/** 打回(→ RETURNED,推送打回通知) */
|
||||
@PostMapping("/{id}/submissions/{studentId}/return")
|
||||
public void returnSubmission(@PathVariable("id") Integer id, @PathVariable("studentId") Integer studentId,
|
||||
@RequestBody @Validated ReturnRequest request) {
|
||||
teacherHomeworkV2Service.returnSubmission(id, studentId, request);
|
||||
}
|
||||
|
||||
/** 历史提交版本(批阅弹窗切换版本) */
|
||||
@GetMapping("/{id}/submissions/{studentId}/versions")
|
||||
public List<SubmissionVersionVo> versions(@PathVariable("id") Integer id,
|
||||
@PathVariable("studentId") Integer studentId) {
|
||||
return teacherHomeworkV2Service.versions(id, studentId);
|
||||
}
|
||||
|
||||
// ============================ 辅助:学科 ============================
|
||||
|
||||
/** 我布置过的学科(本人已发布及之后作业的学科 ∪ 我的任教学科,合并去重;草稿不计) */
|
||||
@GetMapping("/subjects/assigned")
|
||||
public List<SubjectDto> assignedSubjects() {
|
||||
return teacherHomeworkV2Service.assignedSubjects();
|
||||
}
|
||||
|
||||
/** 我的任教学科(bschclass 任教关系去重,名称取本校学科字典) */
|
||||
@GetMapping("/subjects/teaching")
|
||||
public List<SubjectDto> teachingSubjects() {
|
||||
return teacherHomeworkV2Service.teachingSubjects();
|
||||
}
|
||||
|
||||
/** 按学科筛选我的任教班级(subId=学科编码;班级名称取学校班级列表) */
|
||||
@GetMapping("/subjects/classes")
|
||||
public List<TeachingClassVo> teachingClasses(@RequestParam("subId") String subId) {
|
||||
return teacherHomeworkV2Service.teachingClasses(subId);
|
||||
}
|
||||
|
||||
// ============================ 辅助:班级树 / 名册同步 ============================
|
||||
|
||||
/** 年级→班级树(发布选班;名册快照聚合) */
|
||||
@GetMapping("/classes")
|
||||
public List<ClassTreeNode> classTree() {
|
||||
return teacherHomeworkV2Service.classTree();
|
||||
}
|
||||
|
||||
/** 手动触发名册同步(bschclass 接口就绪前为空操作) */
|
||||
@PostMapping("/classes/sync")
|
||||
public Map<String, Integer> syncClasses() {
|
||||
int synced = classStudentService.syncAll();
|
||||
return java.util.Collections.singletonMap("synced", synced);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.yunhai.homework.controller.api;
|
||||
|
||||
import com.yunhai.homework.config.Config;
|
||||
import com.yunhai.homework.service.ITemplateService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 作业模板接口(模板域)。
|
||||
* <p>路径前缀:{@code Config.API_PATH + "/template/"}(原 homework/Template/ 三级路径已修正)。
|
||||
* 写操作一律 POST(原 EditType/DelTemplate 为 GET 写操作,已 POST 化)。
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(value = Config.API_PATH + "/template/")
|
||||
public class TemplateController {
|
||||
|
||||
@Autowired
|
||||
private ITemplateService templateService;
|
||||
|
||||
/**
|
||||
* 获取模板类型列表。
|
||||
*/
|
||||
@GetMapping("Typelist")
|
||||
public List<Map<String, Object>> getTypelist() {
|
||||
return templateService.getTypelist();
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增/编辑模板类型(原 GET EditType,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("TypeEdit")
|
||||
public void typeEdit(
|
||||
@RequestParam("typeid") Integer typeid,
|
||||
@RequestParam("TypeName") String typeName) {
|
||||
templateService.editType(typeid, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除模板类型(原 GET DelType,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("TypeDelete")
|
||||
public void typeDelete(@RequestParam("typeid") Integer typeid) {
|
||||
templateService.delType(typeid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取模板列表。
|
||||
*/
|
||||
@GetMapping("List")
|
||||
public Map<String, Object> list(
|
||||
@RequestParam("PageSize") Integer pageSize,
|
||||
@RequestParam("PageIndex") Integer pageIndex,
|
||||
@RequestParam(value = "typeid", defaultValue = "0") Integer typeid) {
|
||||
return templateService.getTemplatelist(pageSize, pageIndex, typeid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增/编辑模板。
|
||||
*/
|
||||
@PostMapping("TemplateEdit")
|
||||
public void templateEdit(
|
||||
@RequestParam(value = "SerID", required = false) Integer serID,
|
||||
@RequestParam("Title") String title,
|
||||
@RequestParam("Contents") String contents,
|
||||
@RequestParam(value = "Type", required = false) Integer type,
|
||||
@RequestParam(value = "Cover", required = false) Integer cover) {
|
||||
templateService.editTemplate(serID, title, contents, type, cover);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除模板(原 GET DelTemplate,已 POST 化)。
|
||||
*/
|
||||
@PostMapping("TemplateDelete")
|
||||
public void templateDelete(@RequestParam("SerID") Integer serid) {
|
||||
templateService.delTemplate(serid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个模板详情。
|
||||
*/
|
||||
@GetMapping("TemplateFirst")
|
||||
public Map<String, Object> templateFirst(@RequestParam("serid") Integer serid) {
|
||||
return templateService.getTemplateFist(serid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import com.yunhai.homework.common.listener.HomeworkAuditListener;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 所有实体的公共基类:自增主键 + 创建人/时间 + 更新人/时间(由 {@link HomeworkAuditListener} 自动填充)。
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@Getter
|
||||
@Setter
|
||||
@EntityListeners(HomeworkAuditListener.class)
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 创建人ID(平台用户ID)
|
||||
*/
|
||||
@Column(name = "create_by", updatable = false)
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Column(name = "create_time", updatable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新人ID(平台用户ID)
|
||||
*/
|
||||
@Column(name = "update_by")
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@Column(name = "update_time")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 班级学生名册快照(PRD class_student)。
|
||||
* <p>
|
||||
* 由同步任务从 bschclass 拉取(接口未就绪前用种子数据),每日全量刷 + 手动触发;
|
||||
* 同步不物理删,转出置 status=0。学生身份口径:用户中心数字ID(UserContext.getUserId())
|
||||
* ↔ student_id(SchStudent.UserStuSerID),名册仅存学生ID + 姓名快照。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "class_student",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_class_student", columnNames = {"class_id", "student_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class ClassStudent extends BaseEntity {
|
||||
|
||||
/** 学校ID */
|
||||
@Column(name = "school_id", nullable = false)
|
||||
private Integer schoolId;
|
||||
|
||||
/** 班级ID */
|
||||
@Column(name = "class_id", nullable = false, length = 64)
|
||||
private String classId;
|
||||
|
||||
/** 班级名快照 */
|
||||
@Column(name = "class_name", length = 50)
|
||||
private String className;
|
||||
|
||||
/** 年级名快照 */
|
||||
@Column(name = "grade_name", length = 50)
|
||||
private String gradeName;
|
||||
|
||||
/** 学生ID(用户中心数字ID,即 SchStudent.UserStuSerID) */
|
||||
@Column(name = "student_id", nullable = false)
|
||||
private Integer studentId;
|
||||
|
||||
/** 学生姓名 */
|
||||
@Column(name = "student_name", nullable = false, length = 50)
|
||||
private String studentName;
|
||||
|
||||
/** 在班状态:1 在班 / 0 已转出退课 */
|
||||
@Column(name = "status", nullable = false)
|
||||
private Integer status = 1;
|
||||
|
||||
/** 离班时间 */
|
||||
@Column(name = "leave_at")
|
||||
private LocalDateTime leaveAt;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 联系组。对应原 .NET Contacts_Group 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "contacts_group")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class ContactsGroup extends BaseEntity {
|
||||
|
||||
/** 组名称 */
|
||||
@Column(name = "group_name", length = 200)
|
||||
private String groupName;
|
||||
|
||||
/** 创建人ID(用户中心数字ID,同教师ID空间) */
|
||||
@Column(name = "creator_id")
|
||||
private Integer creatorId;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* 联系组-用户关联。对应原 .NET Contacts_Tea 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "contacts_group_user",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_group_user",
|
||||
columnNames = {"group_id", "user_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class ContactsGroupUser extends BaseEntity {
|
||||
|
||||
/** 联系组ID */
|
||||
@Column(name = "group_id", nullable = false)
|
||||
private Integer groupId;
|
||||
|
||||
/** 用户ID(基础平台用户ID) */
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Integer userId;
|
||||
|
||||
/** 用户姓名 */
|
||||
@Column(name = "user_name", length = 64)
|
||||
private String userName;
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 课程作业主表。对应原 .NET Notify_Message(已剔除短信/模板/门户等无关字段)。
|
||||
* <p>
|
||||
* 阅读状态不落主表:采用「懒标记」模型——读者首次查看时写入 {@link HomeworkRead},
|
||||
* 不存在阅读记录即视为未读,从而无需在发作业时枚举全校用户预插接收行。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class Homework extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 作业标题
|
||||
*/
|
||||
@Column(name = "title", nullable = false, length = 200)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 学校ID(多租户隔离:发布时从当前用户角色填充,查询时按校过滤)。
|
||||
*/
|
||||
@Column(name = "sch_id")
|
||||
private Integer schId;
|
||||
|
||||
/**
|
||||
* 作业内容
|
||||
*/
|
||||
@Column(name = "content", columnDefinition = "LONGTEXT")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 作业类型:1 普通 / 2 重要(见 {@link com.yunhai.homework.enums.HomeworkTypeEnum})
|
||||
*/
|
||||
@Column(name = "type", nullable = false)
|
||||
private Integer type = 1;
|
||||
|
||||
/**
|
||||
* 发布人ID(用户中心数字ID,同教师ID空间)
|
||||
*/
|
||||
@Column(name = "publisher_id")
|
||||
private Integer publisherId;
|
||||
|
||||
/**
|
||||
* 发布人姓名
|
||||
*/
|
||||
@Column(name = "publisher_name", length = 64)
|
||||
private String publisherName;
|
||||
|
||||
/**
|
||||
* 发布部门ID(原 DeptID)
|
||||
*/
|
||||
@Column(name = "dept_id", length = 64)
|
||||
private String deptId;
|
||||
|
||||
/**
|
||||
* 发布部门名称
|
||||
*/
|
||||
@Column(name = "dept_name", length = 128)
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 状态:1 已发布(无草稿态,见 {@link com.yunhai.homework.enums.HomeworkStatusEnum})
|
||||
*/
|
||||
@Column(name = "status", nullable = false)
|
||||
private Integer status = 1;
|
||||
|
||||
/**
|
||||
* 是否置顶:0 否 / 1 是(原 topmost)
|
||||
*/
|
||||
@Column(name = "topmost")
|
||||
private Integer topmost = 0;
|
||||
|
||||
// ==================== 迁移补全字段(对应 C# Notify_Message) ====================
|
||||
|
||||
/**
|
||||
* 接收人列表(JSON 数组,如 ["10012","10013"] 或接收组ID列表)。
|
||||
* 对应 C# Notify_Message.ReceiveList
|
||||
*/
|
||||
@Column(name = "receive_list", columnDefinition = "LONGTEXT")
|
||||
private String receiveList;
|
||||
|
||||
/**
|
||||
* 密码发送(对应 C# Notify_Message.PwdSend)
|
||||
*/
|
||||
@Column(name = "pwd_send", length = 255)
|
||||
private String pwdSend;
|
||||
|
||||
/**
|
||||
* 抄送人列表(对应 C# Notify_Message.ChaoSend)
|
||||
*/
|
||||
@Column(name = "chao_send", length = 2000)
|
||||
private String chaoSend;
|
||||
|
||||
/**
|
||||
* 已读数(发送时初始化为 0,也可由 HomeworkRead 表 COUNT 实时计算)。
|
||||
* 对应 C# Notify_Message.readcount
|
||||
*/
|
||||
@Column(name = "read_count")
|
||||
private Integer readCount = 0;
|
||||
|
||||
/**
|
||||
* 应读数(接收人总数)。对应 C# Notify_Message.allowcount
|
||||
*/
|
||||
@Column(name = "allow_count")
|
||||
private Integer allowCount = 0;
|
||||
|
||||
/**
|
||||
* 父作业ID(转发时关联原作业)。对应 C# Notify_Message.fkid
|
||||
*/
|
||||
@Column(name = "parent_id")
|
||||
private Integer parentId;
|
||||
|
||||
/**
|
||||
* 回复ID。对应 C# Notify_Message.reid
|
||||
*/
|
||||
@Column(name = "reply_id", length = 255)
|
||||
private String replyId;
|
||||
|
||||
/**
|
||||
* 是否撤回:0 否 / 1 是。对应 C# Notify_Message.ispull
|
||||
*/
|
||||
@Column(name = "is_pulled")
|
||||
private Integer isPulled = 0;
|
||||
|
||||
/**
|
||||
* 定时发送时间(到时间后自动发布)。对应 C# Notify_Message.DsfsTime。
|
||||
* PRD 语义中的 scheduled_at 复用本列。
|
||||
*/
|
||||
@Column(name = "timing_send_time")
|
||||
private LocalDateTime timingSendTime;
|
||||
|
||||
/**
|
||||
* 短信发送标记:0 不发短信 / 1 发短信。对应 C# Notify_Message.dxbit
|
||||
*/
|
||||
@Column(name = "sms_flag")
|
||||
private Integer smsFlag = 0;
|
||||
|
||||
// ==================== 课堂作业 V3(PRD V1.0)扩展列 ====================
|
||||
|
||||
/**
|
||||
* 学科(字典值)。
|
||||
*/
|
||||
@Column(name = "subject", length = 50)
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* 截止时间(精确到分钟;空 = 仅查阅型,不设截止,到点关闭任务跳过)。
|
||||
*/
|
||||
@Column(name = "deadline_at")
|
||||
private LocalDateTime deadlineAt;
|
||||
|
||||
/**
|
||||
* 作业流程状态(PRD 五态,见 {@link com.yunhai.homework.enums.HwStatusEnum})。
|
||||
* notice 原 status 列继续承载发布/撤回语义,两者并存。
|
||||
*/
|
||||
@Column(name = "hw_status", nullable = false, length = 20)
|
||||
private String hwStatus = com.yunhai.homework.enums.HwStatusEnum.DRAFT_UNPUBLISHED.getCode();
|
||||
|
||||
/**
|
||||
* 发布时间(立即发布或定时到点发布时写入)。
|
||||
*/
|
||||
@Column(name = "published_at")
|
||||
private LocalDateTime publishedAt;
|
||||
|
||||
/**
|
||||
* 提交方式,JSON 数组文本,如 ["image","attach"]。
|
||||
* 取值:text / image / attach / none(PRD 的 图片/文件/两者 映射为
|
||||
* ["image"] / ["attach"] / ["image","attach"])。
|
||||
*/
|
||||
@Column(name = "submit_type", length = 100)
|
||||
private String submitType;
|
||||
|
||||
/**
|
||||
* 截止后是否允许逾期提交:0 否 / 1 是。
|
||||
*/
|
||||
@Column(name = "allow_late", nullable = false)
|
||||
private Integer allowLate = 0;
|
||||
|
||||
/**
|
||||
* 提醒设置:截止前 1 天提醒(0 关 / 1 开)。
|
||||
*/
|
||||
@Column(name = "remind_1d", nullable = false)
|
||||
private Integer remind1d = 1;
|
||||
|
||||
/**
|
||||
* 提醒设置:截止前 1 小时提醒(0 关 / 1 开)。
|
||||
*/
|
||||
@Column(name = "remind_1h", nullable = false)
|
||||
private Integer remind1h = 1;
|
||||
|
||||
/**
|
||||
* 归档时间(教师手动归档时写入;归档后只读,所有提醒任务跳过)。
|
||||
*/
|
||||
@Column(name = "archived_at")
|
||||
private LocalDateTime archivedAt;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 作业附件表(PRD homework_attachment)。文件实体仍存 up_file(file_id 关联 + file_url 冗余)。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_attachment")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkAttachment extends BaseEntity {
|
||||
|
||||
/** 作业ID */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** up_file.id(可空:允许外部 URL 附件) */
|
||||
@Column(name = "file_id")
|
||||
private Integer fileId;
|
||||
|
||||
/** 文件访问 URL */
|
||||
@Column(name = "file_url", nullable = false, length = 500)
|
||||
private String fileUrl;
|
||||
|
||||
/** 文件类型:image / file / ... */
|
||||
@Column(name = "file_type", length = 20)
|
||||
private String fileType;
|
||||
|
||||
/** 文件名 */
|
||||
@Column(name = "file_name", length = 200)
|
||||
private String fileName;
|
||||
|
||||
/** 排序号(越小越靠前) */
|
||||
@Column(name = "sort", nullable = false)
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* 作业-班级关联表(PRD homework_class)。
|
||||
* 发布/编辑时由 receiveList("all" 或班级 id 串)解析写入,是应交名单与统计的权威关联。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_class",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_hw_class", columnNames = {"homework_id", "class_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkClass extends BaseEntity {
|
||||
|
||||
/** 作业ID */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 班级ID */
|
||||
@Column(name = "class_id", nullable = false, length = 64)
|
||||
private String classId;
|
||||
|
||||
/** 班级名快照 */
|
||||
@Column(name = "class_name", length = 50)
|
||||
private String className;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 作业阅读记录(懒标记)。对应原 .NET Notify_ReceiveList 的「逐用户阅读状态」语义,
|
||||
* 但仅在读者首次查看时落库,避免发作业时预插全员。
|
||||
* <p>
|
||||
* 唯一约束 (homework_id, reader_id):同一用户对同一作业只记一条已读。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_read",
|
||||
uniqueConstraints = @UniqueConstraint(
|
||||
name = "uk_homework_reader",
|
||||
columnNames = {"homework_id", "reader_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkRead extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 作业ID(关联 homework.id)
|
||||
*/
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/**
|
||||
* 读者ID(用户中心数字ID,同教师ID空间)
|
||||
*/
|
||||
@Column(name = "reader_id", nullable = false)
|
||||
private Integer readerId;
|
||||
|
||||
/**
|
||||
* 读者姓名
|
||||
*/
|
||||
@Column(name = "reader_name", length = 64)
|
||||
private String readerName;
|
||||
|
||||
/**
|
||||
* 阅读时间
|
||||
*/
|
||||
@Column(name = "read_time")
|
||||
private LocalDateTime readTime;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 学生作业阅读记录(PRD homework_read_record)。
|
||||
* <p>
|
||||
* 学生维度,含首次/最近阅读时间,与 notice 语义的 {@link HomeworkRead}(教师/阅读者已读)互不影响。
|
||||
* 行仅在判定已读时写入;未读名单 = 名册左连本表(无记录或 is_read=0)。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_read_record",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_hw_student", columnNames = {"homework_id", "student_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkReadRecord extends BaseEntity {
|
||||
|
||||
/** 作业ID */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 学生ID(用户中心数字ID,即 SchStudent.UserStuSerID) */
|
||||
@Column(name = "student_id", nullable = false)
|
||||
private Integer studentId;
|
||||
|
||||
/** 学生姓名快照 */
|
||||
@Column(name = "student_name", length = 50)
|
||||
private String studentName;
|
||||
|
||||
/** 班级ID */
|
||||
@Column(name = "class_id", length = 64)
|
||||
private String classId;
|
||||
|
||||
/** 阅读状态:0 UNREAD / 1 READ */
|
||||
@Column(name = "is_read", nullable = false)
|
||||
private Integer isRead = 0;
|
||||
|
||||
/** 首次阅读时间(写入后不再变更) */
|
||||
@Column(name = "first_read_at")
|
||||
private LocalDateTime firstReadAt;
|
||||
|
||||
/** 最近阅读时间(每次上报刷新) */
|
||||
@Column(name = "last_read_at")
|
||||
private LocalDateTime lastReadAt;
|
||||
|
||||
/** 阅读次数 */
|
||||
@Column(name = "read_count", nullable = false)
|
||||
private Integer readCount = 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 作业接收人关联表(替代旧 receive_list JSON 字符串存储)。
|
||||
* <p>
|
||||
* 每条记录代表一个作业的一个接收人(用户ID + 姓名快照,不含账号)。
|
||||
* 全员作业(receive_list="ALL")不写明细行,
|
||||
* 读取时按 receive_list="ALL" 标识走旧逻辑兜底。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_receiver",
|
||||
indexes = {
|
||||
@Index(name = "idx_homework_id", columnList = "homework_id"),
|
||||
@Index(name = "idx_receiver", columnList = "receiver_id")
|
||||
})
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkReceiver extends BaseEntity {
|
||||
|
||||
/** 作业ID(关联 homework.id) */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 接收人ID(用户中心数字ID) */
|
||||
@Column(name = "receiver_id", nullable = false)
|
||||
private Integer receiverId;
|
||||
|
||||
/** 接收人姓名快照 */
|
||||
@Column(name = "receiver_name", length = 64)
|
||||
private String receiverName;
|
||||
|
||||
/** 接收类型:1 接收 / 2 抄送 */
|
||||
@Column(name = "receive_type", nullable = false)
|
||||
private Integer receiveType = 1;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import com.yunhai.homework.enums.ReviewStatusEnum;
|
||||
import com.yunhai.homework.enums.SubmitStatusEnum;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 作业提交表,多版本建模(PRD homework_submission)。
|
||||
* <p>
|
||||
* 同一学生 (homework_id, student_id) 下 version 单调递增;提交/打回重交/撤回均新增行,
|
||||
* 旧行 is_latest 置 0 保留历史;is_latest=1 的行是当前有效版本。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_submission",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_hw_student_ver",
|
||||
columnNames = {"homework_id", "student_id", "version"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkSubmission extends BaseEntity {
|
||||
|
||||
/** 作业ID */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 学生ID(用户中心数字ID,即 SchStudent.UserStuSerID) */
|
||||
@Column(name = "student_id", nullable = false)
|
||||
private Integer studentId;
|
||||
|
||||
/** 学生姓名快照 */
|
||||
@Column(name = "student_name", nullable = false, length = 50)
|
||||
private String studentName;
|
||||
|
||||
/** 班级ID */
|
||||
@Column(name = "class_id", nullable = false, length = 64)
|
||||
private String classId;
|
||||
|
||||
/** 班级名快照 */
|
||||
@Column(name = "class_name", nullable = false, length = 50)
|
||||
private String className;
|
||||
|
||||
/** 提交版本,同一学生单调递增(撤回/重交均 +1) */
|
||||
@Column(name = "version", nullable = false)
|
||||
private Integer version = 1;
|
||||
|
||||
/** 是否当前版本:1 是 / 0 历史 */
|
||||
@Column(name = "is_latest", nullable = false)
|
||||
private Integer isLatest = 1;
|
||||
|
||||
/** 提交状态(见 {@link SubmitStatusEnum}) */
|
||||
@Column(name = "status", nullable = false, length = 20)
|
||||
private String status = SubmitStatusEnum.SUBMITTED.getCode();
|
||||
|
||||
/** 是否逾期:0 否 / 1 是 */
|
||||
@Column(name = "is_late", nullable = false)
|
||||
private Integer isLate = 0;
|
||||
|
||||
/** 提交时间(NOT_SUBMITTED 空行为空) */
|
||||
@Column(name = "submitted_at")
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
/** 文本作业内容 */
|
||||
@Column(name = "text", columnDefinition = "TEXT")
|
||||
private String text;
|
||||
|
||||
/** 评分 */
|
||||
@Column(name = "score", precision = 6, scale = 2)
|
||||
private BigDecimal score;
|
||||
|
||||
/** 评语(打回时 = 订正原因,必填) */
|
||||
@Column(name = "comment", columnDefinition = "TEXT")
|
||||
private String comment;
|
||||
|
||||
/** 批阅状态(见 {@link ReviewStatusEnum}) */
|
||||
@Column(name = "review_status", nullable = false, length = 20)
|
||||
private String reviewStatus = ReviewStatusEnum.PENDING.getCode();
|
||||
|
||||
/** 批阅人ID(用户中心数字ID,同教师ID空间) */
|
||||
@Column(name = "reviewed_by")
|
||||
private Integer reviewedBy;
|
||||
|
||||
/** 批阅人姓名快照 */
|
||||
@Column(name = "reviewed_by_name", length = 64)
|
||||
private String reviewedByName;
|
||||
|
||||
/** 批阅时间 */
|
||||
@Column(name = "reviewed_at")
|
||||
private LocalDateTime reviewedAt;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 作业模板。对应原 .NET Notify_Template 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "homework_template")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class HomeworkTemplate extends BaseEntity {
|
||||
|
||||
/** 模板标题 */
|
||||
@Column(name = "title", length = 200)
|
||||
private String title;
|
||||
|
||||
/** 模板内容(HTML) */
|
||||
@Column(name = "content", columnDefinition = "LONGTEXT")
|
||||
private String content;
|
||||
|
||||
/** 封面图片文件ID */
|
||||
@Column(name = "cover")
|
||||
private Integer cover;
|
||||
|
||||
/** 引用次数 */
|
||||
@Column(name = "ref_count")
|
||||
private Integer refCount = 0;
|
||||
|
||||
/** 模板类型ID */
|
||||
@Column(name = "type_id")
|
||||
private Integer typeId;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 站内通知(PRD notification)。六类通知的统一落表 + 已读状态。
|
||||
* 通知已读独立于作业阅读记录(本表 is_read 只反映通知列表已读)。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "notification",
|
||||
indexes = {
|
||||
@Index(name = "idx_receiver", columnList = "receiver_id, is_read"),
|
||||
@Index(name = "idx_hw_type", columnList = "homework_id, type")
|
||||
})
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class Notification extends BaseEntity {
|
||||
|
||||
/** 通知类型(见 {@link com.yunhai.homework.enums.NotificationTypeEnum}) */
|
||||
@Column(name = "type", nullable = false, length = 30)
|
||||
private String type;
|
||||
|
||||
/** 关联作业ID */
|
||||
@Column(name = "homework_id")
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 关联业务ID(如 submissionId) */
|
||||
@Column(name = "related_id")
|
||||
private Integer relatedId;
|
||||
|
||||
/** 通知标题 */
|
||||
@Column(name = "title", nullable = false, length = 200)
|
||||
private String title;
|
||||
|
||||
/** 通知内容 */
|
||||
@Column(name = "content", length = 1000)
|
||||
private String content;
|
||||
|
||||
/** 接收人ID(学生 = student_id,教师 = 用户中心数字ID,同一 ID 空间) */
|
||||
@Column(name = "receiver_id", nullable = false)
|
||||
private Integer receiverId;
|
||||
|
||||
/** 接收人姓名快照 */
|
||||
@Column(name = "receiver_name", length = 64)
|
||||
private String receiverName;
|
||||
|
||||
/** 接收人角色:student / teacher */
|
||||
@Column(name = "receiver_role", nullable = false, length = 20)
|
||||
private String receiverRole = "student";
|
||||
|
||||
/** 是否已读:0 未读 / 1 已读 */
|
||||
@Column(name = "is_read", nullable = false)
|
||||
private Integer isRead = 0;
|
||||
|
||||
/** 已读时间 */
|
||||
@Column(name = "read_at")
|
||||
private LocalDateTime readAt;
|
||||
|
||||
/** 发送通道:inapp 站内 / sms 短信 */
|
||||
@Column(name = "send_channel", nullable = false, length = 20)
|
||||
private String sendChannel = "inapp";
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
/**
|
||||
* 班级任教关系快照(bschclass sch_class_teach 本地镜像,PRD 口径同 class_student)。
|
||||
* <p>
|
||||
* 由同步任务从 bschclass 拉取(接口未就绪前用种子数据);bschclass 任教接口
|
||||
* 不可用时,任教学科链路降级读本表。教师口径:用户中心数字ID(UserContext.getUserId());
|
||||
* class_id 与 class_student.class_id 同一取值域。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "sch_class_teach",
|
||||
uniqueConstraints = @UniqueConstraint(name = "uk_sch_class_teach", columnNames = {"school_id", "class_id", "tea_id", "sub_id"}))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SchClassTeach extends BaseEntity {
|
||||
|
||||
/** 学校ID */
|
||||
@Column(name = "school_id", nullable = false)
|
||||
private Integer schoolId;
|
||||
|
||||
/** 班级ID(与 class_student.class_id 同一取值域) */
|
||||
@Column(name = "class_id", nullable = false, length = 64)
|
||||
private String classId;
|
||||
|
||||
/** 教师ID(用户中心数字ID) */
|
||||
@Column(name = "tea_id", nullable = false)
|
||||
private Integer teaId;
|
||||
|
||||
/** 学科编码(bschclass SubID;本地无字典时编码即展示名) */
|
||||
@Column(name = "sub_id", nullable = false, length = 64)
|
||||
private String subId;
|
||||
|
||||
/** 有效状态:1 有效 / 0 失效 */
|
||||
@Column(name = "status", nullable = false)
|
||||
private Integer status = 1;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 短信模块配置。对应原 .NET SchSms 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "sms_module")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SmsModule extends BaseEntity {
|
||||
|
||||
/** 模块名称 */
|
||||
@Column(name = "module_name", length = 100)
|
||||
private String moduleName;
|
||||
|
||||
/** 模块标识 */
|
||||
@Column(name = "module_code", length = 50)
|
||||
private String moduleCode;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 学校短信开通配置。对应原 .NET SchSms_Set 表。
|
||||
* 记录某学校某模块是否开通短信。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "sms_school_config")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SmsSchoolConfig extends BaseEntity {
|
||||
|
||||
/** 学校ID */
|
||||
@Column(name = "school_id", nullable = false)
|
||||
private Integer schoolId;
|
||||
|
||||
/** 学校名称 */
|
||||
@Column(name = "school_name", length = 200)
|
||||
private String schoolName;
|
||||
|
||||
/** 模块ID */
|
||||
@Column(name = "module_id")
|
||||
private Integer moduleId;
|
||||
|
||||
/** 是否开通短信 */
|
||||
@Column(name = "is_sms")
|
||||
private Boolean isSms = false;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 提交附件表(PRD submission_attachment)。替代 JSON 方案,支撑矩阵缩略图与批阅大图预览。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "submission_attachment",
|
||||
indexes = @Index(name = "idx_sub", columnList = "submission_id"))
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SubmissionAttachment extends BaseEntity {
|
||||
|
||||
/** 提交行ID(homework_submission.id) */
|
||||
@Column(name = "submission_id", nullable = false)
|
||||
private Integer submissionId;
|
||||
|
||||
/** 作业ID(冗余,便于统计与清理) */
|
||||
@Column(name = "homework_id", nullable = false)
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 学生ID(用户中心数字ID) */
|
||||
@Column(name = "student_id")
|
||||
private Integer studentId;
|
||||
|
||||
/** up_file.id(可空:允许外部 URL) */
|
||||
@Column(name = "file_id")
|
||||
private Integer fileId;
|
||||
|
||||
/** 文件访问 URL */
|
||||
@Column(name = "file_url", nullable = false, length = 500)
|
||||
private String fileUrl;
|
||||
|
||||
/** 文件类型:image / file */
|
||||
@Column(name = "file_type", length = 20)
|
||||
private String fileType;
|
||||
|
||||
/** 文件名 */
|
||||
@Column(name = "file_name", length = 200)
|
||||
private String fileName;
|
||||
|
||||
/** 排序号 */
|
||||
@Column(name = "sort", nullable = false)
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 系统字典(发文部门等)。对应原 .NET Common_DeptDic 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "sys_dict")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class SysDict extends BaseEntity {
|
||||
|
||||
/** 字典类型(如 "dept"=发文部门) */
|
||||
@Column(name = "dict_type", length = 50)
|
||||
private String dictType;
|
||||
|
||||
/** 字典 key(原 CodeID) */
|
||||
@Column(name = "dict_key", length = 100)
|
||||
private String dictKey;
|
||||
|
||||
/** 字典 value(显示名称,原 Name) */
|
||||
@Column(name = "dict_value", length = 200)
|
||||
private String dictValue;
|
||||
|
||||
/** 排序号 */
|
||||
@Column(name = "sort_order")
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
/** 是否启用:0 禁用 / 1 启用(原 Enable) */
|
||||
@Column(name = "enable_flag")
|
||||
private Integer enableFlag = 1;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 作业模板类型。对应原 .NET Notify_TemplateType 表。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "template_type")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class TemplateType extends BaseEntity {
|
||||
|
||||
/** 类型名称 */
|
||||
@Column(name = "type_name", length = 100)
|
||||
private String typeName;
|
||||
|
||||
/** 排序号 */
|
||||
@Column(name = "sort_order")
|
||||
private Integer sortOrder = 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.yunhai.homework.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 附件文件记录。对应原 .NET Common_UpFiles 表。
|
||||
* <p>
|
||||
* 存储文件元信息(真实文件名、存储路径、大小、类型),物理文件存储在
|
||||
* application.yml 的 file.upload-path 目录下。
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "up_file")
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
|
||||
public class UpFile extends BaseEntity {
|
||||
|
||||
/** 应用类型(如 "homework"),用于区分不同业务的附件 */
|
||||
@Column(name = "topic_type", length = 50)
|
||||
private String topicType;
|
||||
|
||||
/** 关联主题ID(如作业 serid) */
|
||||
@Column(name = "topic_id")
|
||||
private Integer topicId;
|
||||
|
||||
/** 文件真实名称(用户上传时的原始文件名) */
|
||||
@Column(name = "file_true_name", length = 255)
|
||||
private String fileTrueName;
|
||||
|
||||
/** 文件存储路径(相对路径,如 homework/20260823/uuid.pdf) */
|
||||
@Column(name = "file_name", length = 500)
|
||||
private String fileName;
|
||||
|
||||
/** 文件大小(字节) */
|
||||
@Column(name = "file_size")
|
||||
private Integer fileSize;
|
||||
|
||||
/** 文件后缀名(如 pdf, docx, jpg) */
|
||||
@Column(name = "file_type", length = 20)
|
||||
private String fileType;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 作业状态。无草稿态:发作业一律置为「已发布」,
|
||||
* 定时发送通过 timingSendTime + 查询侧「已到点」过滤控制可见性。
|
||||
* 对应原 .NET Notify_Message.status(原系统已发布=2,此处归一化为 1)。
|
||||
*/
|
||||
@Getter
|
||||
public enum HomeworkStatusEnum {
|
||||
|
||||
PUBLISHED(1, "已发布");
|
||||
|
||||
private final int code;
|
||||
private final String desc;
|
||||
|
||||
HomeworkStatusEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static HomeworkStatusEnum of(Integer code) {
|
||||
if (code == null) {
|
||||
return PUBLISHED;
|
||||
}
|
||||
for (HomeworkStatusEnum e : values()) {
|
||||
if (e.code == code) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return PUBLISHED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 作业类型。对应原 .NET Notify_Message.type(原系统作业类=2,此处归一化)。
|
||||
*/
|
||||
@Getter
|
||||
public enum HomeworkTypeEnum {
|
||||
|
||||
NORMAL(1, "普通作业"),
|
||||
IMPORTANT(2, "重要作业");
|
||||
|
||||
private final int code;
|
||||
private final String desc;
|
||||
|
||||
HomeworkTypeEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static HomeworkTypeEnum of(Integer code) {
|
||||
if (code == null) {
|
||||
return NORMAL;
|
||||
}
|
||||
for (HomeworkTypeEnum e : values()) {
|
||||
if (e.code == code) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return NORMAL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 作业流程状态(PRD 五态,存 homework.hw_status)。
|
||||
* <p>
|
||||
* 与 notice 原 status(Integer,发布/撤回语义)并存:本枚举承载课堂作业业务流转,
|
||||
* 流转收敛在 HomeworkStateService,条件更新保证幂等。
|
||||
*/
|
||||
@Getter
|
||||
public enum HwStatusEnum {
|
||||
|
||||
/** 草稿 - 未发布 */
|
||||
DRAFT_UNPUBLISHED("DRAFT_UNPUBLISHED", "草稿-未发布"),
|
||||
/** 草稿 - 定时待发布 */
|
||||
DRAFT_SCHEDULED("DRAFT_SCHEDULED", "草稿-定时待发布"),
|
||||
/** 已发布 - 进行中 */
|
||||
PUBLISHED("PUBLISHED", "已发布-进行中"),
|
||||
/** 已截止 */
|
||||
CLOSED("CLOSED", "已截止"),
|
||||
/** 已归档(只读,不再触发任何提醒) */
|
||||
ARCHIVED("ARCHIVED", "已归档");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
HwStatusEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static HwStatusEnum of(String code) {
|
||||
if (code == null) {
|
||||
return DRAFT_UNPUBLISHED;
|
||||
}
|
||||
for (HwStatusEnum e : values()) {
|
||||
if (e.code.equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return DRAFT_UNPUBLISHED;
|
||||
}
|
||||
|
||||
public boolean isDraft() {
|
||||
return this == DRAFT_UNPUBLISHED || this == DRAFT_SCHEDULED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 站内通知类型(PRD 六类,存 notification.type)。
|
||||
*/
|
||||
@Getter
|
||||
public enum NotificationTypeEnum {
|
||||
|
||||
/** 作业发布(对应班级学生) */
|
||||
HOMEWORK_PUBLISHED("HOMEWORK_PUBLISHED", "作业发布"),
|
||||
/** 截止提醒(截止前 1 天 / 1 小时) */
|
||||
DEADLINE_REMINDER("DEADLINE_REMINDER", "截止提醒"),
|
||||
/** 未交提醒(教师手动) */
|
||||
NOT_SUBMITTED("NOT_SUBMITTED", "未交提醒"),
|
||||
/** 未读提醒(教师手动) */
|
||||
NOT_READ("NOT_READ", "未读提醒"),
|
||||
/** 批阅完成 */
|
||||
REVIEW_DONE("REVIEW_DONE", "批阅完成"),
|
||||
/** 打回通知 */
|
||||
RETURNED("RETURNED", "打回通知"),
|
||||
/**
|
||||
* 定时发布失败回退(PRD §17.1 教师泳道要求通知教师,但 PRD 枚举表未列——
|
||||
* 按 classwork-homework-plan-v3 §13-2 建议补充,待产品确认命名)。
|
||||
*/
|
||||
SCHEDULE_FAILED("SCHEDULE_FAILED", "定时发布失败"),
|
||||
/**
|
||||
* 截止时间变更(PRD §17.1 延长截止要求通知学生,PRD 枚举表未列——同上补充)。
|
||||
*/
|
||||
DEADLINE_CHANGED("DEADLINE_CHANGED", "截止时间变更");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
NotificationTypeEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static NotificationTypeEnum of(String code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (NotificationTypeEnum e : values()) {
|
||||
if (e.code.equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 批阅状态(PRD 三态,存 homework_submission.review_status)。
|
||||
* 与 SubmitStatusEnum 同源联动:批阅保存 → status=REVIEWED + review_status=REVIEWED;
|
||||
* 打回 → status=RETURNED + review_status=RETURNED。
|
||||
*/
|
||||
@Getter
|
||||
public enum ReviewStatusEnum {
|
||||
|
||||
/** 待批阅 */
|
||||
PENDING("PENDING", "待批阅"),
|
||||
/** 已批阅 */
|
||||
REVIEWED("REVIEWED", "已批阅"),
|
||||
/** 已打回 */
|
||||
RETURNED("RETURNED", "已打回");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
ReviewStatusEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static ReviewStatusEnum of(String code) {
|
||||
if (code == null) {
|
||||
return PENDING;
|
||||
}
|
||||
for (ReviewStatusEnum e : values()) {
|
||||
if (e.code.equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return PENDING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.yunhai.homework.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 学生提交状态(PRD 五态,存 homework_submission.status)。
|
||||
* <p>
|
||||
* NOT_SUBMITTED 空行仅由「撤回」产生;未提交学生本身不落行(统计时由名册左连补位)。
|
||||
*/
|
||||
@Getter
|
||||
public enum SubmitStatusEnum {
|
||||
|
||||
/** 未提交(撤回后产生的空提交行) */
|
||||
NOT_SUBMITTED("NOT_SUBMITTED", "未提交"),
|
||||
/** 已提交(含打回后重新提交) */
|
||||
SUBMITTED("SUBMITTED", "已提交"),
|
||||
/** 逾期提交(截止后提交,is_late=1) */
|
||||
LATE_SUBMITTED("LATE_SUBMITTED", "逾期提交"),
|
||||
/** 已打回(待重新提交) */
|
||||
RETURNED("RETURNED", "已打回"),
|
||||
/** 已批阅 */
|
||||
REVIEWED("REVIEWED", "已批阅");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
SubmitStatusEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static SubmitStatusEnum of(String code) {
|
||||
if (code == null) {
|
||||
return NOT_SUBMITTED;
|
||||
}
|
||||
for (SubmitStatusEnum e : values()) {
|
||||
if (e.code.equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return NOT_SUBMITTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否计入「已交」口径:打回未重交也算已交(PRD 学生矩阵口径)。
|
||||
*/
|
||||
public boolean countsAsSubmitted() {
|
||||
return this != NOT_SUBMITTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.yunhai.homework.job;
|
||||
|
||||
import com.yunhai.homework.entity.Homework;
|
||||
import com.yunhai.homework.enums.HwStatusEnum;
|
||||
import com.yunhai.homework.enums.NotificationTypeEnum;
|
||||
import com.yunhai.homework.repository.HomeworkClassRepository;
|
||||
import com.yunhai.homework.repository.HomeworkRepository;
|
||||
import com.yunhai.homework.service.impl.ClassStudentService;
|
||||
import com.yunhai.homework.service.impl.HomeworkStateService;
|
||||
import com.yunhai.homework.service.impl.NotificationService;
|
||||
import com.yunhai.homework.service.impl.TeacherHomeworkV2Service;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 课堂作业定时任务(PRD §17.1 调度泳道)。
|
||||
* <p>
|
||||
* 全部基于状态机 CAS 条件更新,天然幂等,可安全重复执行;
|
||||
* ARCHIVED 作业被显式跳过(归档后不再触发任何提醒)。
|
||||
*/
|
||||
@Component
|
||||
public class HomeworkScheduledJobs {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HomeworkScheduledJobs.class);
|
||||
|
||||
@Autowired
|
||||
private HomeworkRepository homeworkRepository;
|
||||
|
||||
@Autowired
|
||||
private HomeworkClassRepository homeworkClassRepository;
|
||||
|
||||
@Autowired
|
||||
private HomeworkStateService stateService;
|
||||
|
||||
@Autowired
|
||||
private NotificationService notificationService;
|
||||
|
||||
@Autowired
|
||||
private TeacherHomeworkV2Service teacherHomeworkV2Service;
|
||||
|
||||
@Autowired
|
||||
private ClassStudentService classStudentService;
|
||||
|
||||
/**
|
||||
* 定时发布:每分钟扫描到点的 DRAFT_SCHEDULED 作业 → PUBLISHED + 作业发布通知;
|
||||
* 失败回退 DRAFT_UNPUBLISHED 并站内通知教师。
|
||||
*/
|
||||
@Scheduled(cron = "0 * * * * ?")
|
||||
public void scheduledPublish() {
|
||||
List<Homework> due = homeworkRepository
|
||||
.findByHwStatusAndTimingSendTimeLessThanEqual(HwStatusEnum.DRAFT_SCHEDULED.getCode(),
|
||||
LocalDateTime.now());
|
||||
if (due.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
log.info("[scheduledPublish] 到点作业 {} 个", due.size());
|
||||
for (Homework homework : due) {
|
||||
Integer id = homework.getId();
|
||||
try {
|
||||
teacherHomeworkV2Service.publishInternal(id, HwStatusEnum.DRAFT_SCHEDULED);
|
||||
log.info("[scheduledPublish] 发布成功 homeworkId={}", id);
|
||||
} catch (Exception e) {
|
||||
log.error("[scheduledPublish] 发布失败,回退草稿 homeworkId={}", id, e);
|
||||
try {
|
||||
boolean rolledBack = stateService.rollbackFromSchedule(id);
|
||||
if (rolledBack) {
|
||||
notificationService.send(NotificationTypeEnum.SCHEDULE_FAILED, id, null,
|
||||
homework.getPublisherId(), homework.getPublisherName(),
|
||||
NotificationService.ROLE_TEACHER,
|
||||
"定时发布失败:《" + homework.getTitle() + "》",
|
||||
"定时发布任务执行异常,作业已回退为「草稿-未发布」,请重新发布。");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.error("[scheduledPublish] 回退失败 homeworkId={}", id, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 到点截止:每分钟扫描已过截止时间的 PUBLISHED 作业 → CLOSED(无对应通知类型,不推送)。
|
||||
*/
|
||||
@Scheduled(cron = "30 * * * * ?")
|
||||
public void deadlineClose() {
|
||||
List<Homework> overdue = homeworkRepository
|
||||
.findByHwStatusAndDeadlineAtBefore(HwStatusEnum.PUBLISHED.getCode(), LocalDateTime.now());
|
||||
for (Homework homework : overdue) {
|
||||
if (stateService.cas(homework.getId(), HwStatusEnum.PUBLISHED, HwStatusEnum.CLOSED)) {
|
||||
log.info("[deadlineClose] 作业已截止 homeworkId={}", homework.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 截止提醒:每分钟扫描截止时间在 24h 内的 PUBLISHED 作业,
|
||||
* 命中「1 天档 / 1 小时档」窗口且开关开启时向未交学生推送 DEADLINE_REMINDER;
|
||||
* 档位去重(related_id:1=1 天档 2=1 小时档),每作业每档至多发一轮。
|
||||
*/
|
||||
@Scheduled(cron = "40 * * * * ?")
|
||||
public void deadlineReminder() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
List<Homework> window = homeworkRepository
|
||||
.findByHwStatusAndDeadlineAtBetween(HwStatusEnum.PUBLISHED.getCode(), now, now.plusHours(24));
|
||||
for (Homework homework : window) {
|
||||
if (homework.getDeadlineAt() == null) {
|
||||
continue;
|
||||
}
|
||||
// 1 小时档:截止前 [55, 60) 分钟窗口
|
||||
if (homework.getRemind1h() != null && homework.getRemind1h() == 1
|
||||
&& inWindow(homework.getDeadlineAt(), now, 55, 60)
|
||||
&& !notificationService.alreadySentSlot(homework.getId(), NotificationTypeEnum.DEADLINE_REMINDER, 2)) {
|
||||
sendReminder(homework, 2, "1 小时");
|
||||
}
|
||||
// 1 天档:截止前 [23, 24) 小时窗口
|
||||
if (homework.getRemind1d() != null && homework.getRemind1d() == 1
|
||||
&& inWindow(homework.getDeadlineAt(), now, 23 * 60, 24 * 60)
|
||||
&& !notificationService.alreadySentSlot(homework.getId(), NotificationTypeEnum.DEADLINE_REMINDER, 1)) {
|
||||
sendReminder(homework, 1, "1 天");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean inWindow(LocalDateTime deadline, LocalDateTime now, int fromMinutes, int toMinutes) {
|
||||
long minutes = java.time.Duration.between(now, deadline).toMinutes();
|
||||
return minutes >= fromMinutes && minutes < toMinutes;
|
||||
}
|
||||
|
||||
private void sendReminder(Homework homework, int slot, String slotDesc) {
|
||||
// 通知接收人直接使用学生ID(名册口径:student_id = 平台用户ID)
|
||||
List<Integer> targets = teacherHomeworkV2Service.notSubmittedStudentIds(homework.getId()).stream()
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (targets.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int sent = notificationService.sendBatch(NotificationTypeEnum.DEADLINE_REMINDER, homework.getId(), slot,
|
||||
NotificationService.distinct(targets),
|
||||
NotificationService.deadlineReminderTitle(homework),
|
||||
NotificationService.deadlineReminderContent(homework) + "(剩余不足 " + slotDesc + ")");
|
||||
log.info("[deadlineReminder] homeworkId={}, slot={}, sent={}", homework.getId(), slot, sent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 名册同步:每日 02:00 全量刷新 class_student(bschclass 接口就绪前仅日志)。
|
||||
*/
|
||||
@Scheduled(cron = "${homework.sync.class-data-cron:0 0 2 * * ?}")
|
||||
public void classDataSync() {
|
||||
try {
|
||||
classStudentService.syncAll();
|
||||
} catch (Exception e) {
|
||||
log.error("[classDataSync] 名册同步失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.yunhai.homework.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 统一分页查询入参。pageIndex 从 1 起。
|
||||
*/
|
||||
@Data
|
||||
public class BasePageQuery {
|
||||
private int pageIndex = 1;
|
||||
private int pageSize = 10;
|
||||
/** 通用模糊搜索关键词 */
|
||||
private String keyword;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.yunhai.homework.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 统一分页响应外壳。
|
||||
*/
|
||||
@Data
|
||||
public class BasePageResult<T> {
|
||||
/** 总记录数 */
|
||||
private int total;
|
||||
/** 当前页数据 */
|
||||
private List<T> content;
|
||||
/** 当前页码(从 1 起) */
|
||||
private int pageIndex;
|
||||
/** 每页条数 */
|
||||
private int pageSize;
|
||||
/** 总页数 */
|
||||
private int totalPages;
|
||||
/** 是否还有下一页 */
|
||||
private boolean hasNext;
|
||||
|
||||
public BasePageResult(List<T> content, int total, int pageIndex, int pageSize, int totalPages, boolean hasNext) {
|
||||
this.content = content;
|
||||
this.total = total;
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageSize = pageSize;
|
||||
this.totalPages = totalPages;
|
||||
this.hasNext = hasNext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.yunhai.homework.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 班级管理接口-教师(bschclass {@code /oapi/DbClass/GetSchteaList} 响应项)。
|
||||
* 对应 C# BestSchool.Entity.Model.SchTeaList。
|
||||
*/
|
||||
public class SchTeaList {
|
||||
|
||||
/** 学校 GUID(SchSerID) */
|
||||
@JsonProperty("SchSerID")
|
||||
private String schSerID;
|
||||
|
||||
@JsonProperty("TeaTel")
|
||||
private String teaTel;
|
||||
|
||||
/** 教师姓名 */
|
||||
@JsonProperty("TeaName")
|
||||
private String teaName;
|
||||
|
||||
/** 教师用户ID */
|
||||
@JsonProperty("UserTeaSerID")
|
||||
private Integer userTeaSerID;
|
||||
|
||||
@JsonProperty("TeaIDCard")
|
||||
private String teaIDCard;
|
||||
|
||||
/** 教师工号 */
|
||||
@JsonProperty("TeaNo")
|
||||
private String teaNo;
|
||||
|
||||
/** 教师所属组ID列表(兼容旧字段 GroupIds) */
|
||||
@JsonProperty("GroupIds")
|
||||
private List<Integer> groupIds;
|
||||
|
||||
/** 教师所属组ID(接口现行字段 GroupID,单个) */
|
||||
@JsonProperty("GroupID")
|
||||
private Integer groupId;
|
||||
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public String getSchSerID() {
|
||||
return schSerID;
|
||||
}
|
||||
|
||||
public void setSchSerID(String schSerID) {
|
||||
this.schSerID = schSerID;
|
||||
}
|
||||
|
||||
public String getTeaTel() {
|
||||
return teaTel;
|
||||
}
|
||||
|
||||
public void setTeaTel(String teaTel) {
|
||||
this.teaTel = teaTel;
|
||||
}
|
||||
|
||||
public String getTeaName() {
|
||||
return teaName;
|
||||
}
|
||||
|
||||
public void setTeaName(String teaName) {
|
||||
this.teaName = teaName;
|
||||
}
|
||||
|
||||
public Integer getUserTeaSerID() {
|
||||
return userTeaSerID;
|
||||
}
|
||||
|
||||
public void setUserTeaSerID(Integer userTeaSerID) {
|
||||
this.userTeaSerID = userTeaSerID;
|
||||
}
|
||||
|
||||
public String getTeaIDCard() {
|
||||
return teaIDCard;
|
||||
}
|
||||
|
||||
public void setTeaIDCard(String teaIDCard) {
|
||||
this.teaIDCard = teaIDCard;
|
||||
}
|
||||
|
||||
public String getTeaNo() {
|
||||
return teaNo;
|
||||
}
|
||||
|
||||
public void setTeaNo(String teaNo) {
|
||||
this.teaNo = teaNo;
|
||||
}
|
||||
|
||||
public List<Integer> getGroupIds() {
|
||||
return groupIds;
|
||||
}
|
||||
|
||||
public void setGroupIds(List<Integer> groupIds) {
|
||||
this.groupIds = groupIds;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 班级 DTO(/oapi/VSchClass/GetVClassList,SchClass 视图)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchClassDto {
|
||||
|
||||
/** 班级业务ID(sch_class.class_id,scopeType=班级 的 scopeId;学生 ClassID 指向它) */
|
||||
@JsonProperty("ClassID")
|
||||
private Integer classId;
|
||||
|
||||
/** 班级名称 */
|
||||
@JsonProperty("ClassName")
|
||||
private String className;
|
||||
|
||||
/** 年级ID(= gradeId) */
|
||||
@JsonProperty("Levell")
|
||||
private Integer gradeId;
|
||||
|
||||
/** 排序号 */
|
||||
@JsonProperty("sx")
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 年级 DTO(/oapi/Schoolen/GetSchLenLevellist,BaseSchsystemGrade)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchGradeDto {
|
||||
|
||||
/** 年级ID(=gradeId,scopeType=年级 的 scopeId;班级 Levell 指向它) */
|
||||
@JsonProperty("Id")
|
||||
private Integer id;
|
||||
|
||||
/** 年级名称(gradeNickname,如「初一」) */
|
||||
@JsonProperty("Name")
|
||||
private String name;
|
||||
|
||||
/** 所属学段(学制)ID */
|
||||
@JsonProperty("OwnerId")
|
||||
private Integer ownerId;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 学校信息 DTO(/oapi/SchInfo/GetUserSchFirst)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchInfoDto {
|
||||
|
||||
/** 学校 GUID(bschclass 侧 SchSerId) */
|
||||
@JsonProperty("SchSerId")
|
||||
private String schSerId;
|
||||
|
||||
/** 用户中心学校组ID(与 CampusNotice schId 同域) */
|
||||
@JsonProperty("UserSchSerId")
|
||||
private Integer userSchSerId;
|
||||
|
||||
/** 学校名称 */
|
||||
@JsonProperty("SchName")
|
||||
private String schName;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 学生 DTO(/oapi/OAStu/*,SchStudent 视图)。
|
||||
* account 仅为上游接口契约字段(兼容反序列化),本系统落库/身份映射不再使用;
|
||||
* 学生身份以 stuId(UserStuSerID,= 平台用户ID)+ stuName 承载。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchStudentDto {
|
||||
|
||||
/** 学员登录账号(上游契约字段,仅兼容保留,不落库) */
|
||||
@JsonProperty("Account")
|
||||
private String account;
|
||||
|
||||
/** 学生ID */
|
||||
@JsonProperty("UserStuSerID")
|
||||
private Integer stuId;
|
||||
|
||||
/** 学生姓名 */
|
||||
@JsonProperty("StuName")
|
||||
private String stuName;
|
||||
|
||||
/** 所在班级ID(sch_class.class_id) */
|
||||
@JsonProperty("ClassID")
|
||||
private Integer classId;
|
||||
|
||||
/** 所在组ID */
|
||||
@JsonProperty("GroupID")
|
||||
private Integer groupId;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 学校学科 DTO(/oapi/SubInfo/GetSchSublist)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchSubjectDto {
|
||||
|
||||
/** 学校 GUID(bschclass 侧 SchSerId) */
|
||||
@JsonProperty("SchSerID")
|
||||
private String schSerId;
|
||||
|
||||
/** 学科ID(学科编码;字典无编码时为字典ID字符串) */
|
||||
@JsonProperty("SubID")
|
||||
private String subId;
|
||||
|
||||
/** 学科名称 */
|
||||
@JsonProperty("SubName")
|
||||
private String subName;
|
||||
|
||||
/** 排序号 */
|
||||
@JsonProperty("No")
|
||||
private Integer no;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* bschclass 学段(学制)DTO(/oapi/Schoolen/GetSchLenlist,BaseSchsystem)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchSystemDto {
|
||||
|
||||
/** 学制ID(scopeType=学部 的 scopeId) */
|
||||
@JsonProperty("Id")
|
||||
private Integer id;
|
||||
|
||||
/** 学段名称(如「小学部」「初中部」) */
|
||||
@JsonProperty("Name")
|
||||
private String name;
|
||||
|
||||
/** 学制类型 */
|
||||
@JsonProperty("Type")
|
||||
private Integer type;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* bschclass 任教关系 DTO(/oapi/TeachInfo/*,sch_class_teach 视图)。
|
||||
* 一条记录 = 某学校某班级中某教师任教某学科。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchTeachDto {
|
||||
|
||||
/** 任教记录ID(sch_class_teach.id) */
|
||||
@JsonProperty("SerID")
|
||||
private Integer serId;
|
||||
|
||||
/** 学校 GUID(bschclass 侧 SchSerId) */
|
||||
@JsonProperty("SchSerID")
|
||||
private String schSerId;
|
||||
|
||||
/** 教师ID(= 平台用户ID) */
|
||||
@JsonProperty("UserTeaSerID")
|
||||
private Integer teaId;
|
||||
|
||||
/** 学科ID(学科编码) */
|
||||
@JsonProperty("SubID")
|
||||
private String subId;
|
||||
|
||||
/** 班级业务ID(sch_class.class_id) */
|
||||
@JsonProperty("ClassID")
|
||||
private Integer classId;
|
||||
|
||||
/** 班级ID(与 ClassID 同值,上游兼容字段) */
|
||||
@JsonProperty("UserClassID")
|
||||
private Integer userClassId;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonProperty("CreationTime")
|
||||
private Date creationTime;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.yunhai.homework.model.bsch;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bschclass 组织树节点 DTO(/oapi/SchGroup/GetTeaTree、GetStuTree,TeaTreeVO 视图)。
|
||||
* type=1 组节点(学校/学段/年级/班级、教师组),type=2 人员叶子(学生/教师)。
|
||||
*/
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class SchTreeNodeDto {
|
||||
|
||||
/** 节点ID(学校/学段/年级/班级为对应业务ID,叶子为学生 stuId 或教师 teaId) */
|
||||
private Integer id;
|
||||
|
||||
/** 节点名称 */
|
||||
private String name;
|
||||
|
||||
/** 父节点ID(根节点为 0) */
|
||||
private Integer pid;
|
||||
|
||||
/** 排序号(组取 sort,叶子固定 0) */
|
||||
private Integer no;
|
||||
|
||||
/** 1=组节点,2=人员叶子 */
|
||||
private Integer type;
|
||||
|
||||
/** 是否父节点(组 true,叶子 false) */
|
||||
@JsonProperty("isParent")
|
||||
private Boolean isParent;
|
||||
|
||||
/** 头像(当前固定空串) */
|
||||
private String photo;
|
||||
|
||||
/** 子节点(叶子为 null,组节点非 null) */
|
||||
private List<SchTreeNodeDto> children;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 作业详情视图对象(替代原 Map<String,Object> 返回)。
|
||||
* 使用 @JsonProperty 保持旧字段名兼容前端渲染。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkDetailVo {
|
||||
|
||||
@JsonProperty("serid")
|
||||
private Integer serid;
|
||||
|
||||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("Contents")
|
||||
private String contents;
|
||||
|
||||
@JsonProperty("DeptID")
|
||||
private String deptId;
|
||||
|
||||
@JsonProperty("DeptName")
|
||||
private String deptName;
|
||||
|
||||
@JsonProperty("TeaName")
|
||||
private String publisherName;
|
||||
|
||||
@JsonProperty("EditDate")
|
||||
private String editDate;
|
||||
|
||||
@JsonProperty("numcount")
|
||||
private Integer numCount;
|
||||
|
||||
@JsonProperty("readnumcount")
|
||||
private Long readNumCount;
|
||||
|
||||
@JsonProperty("ReceiveList")
|
||||
private String receiveList;
|
||||
|
||||
@JsonProperty("DsfsTime")
|
||||
private String dsfsTime;
|
||||
|
||||
@JsonProperty("isDsfs")
|
||||
private Boolean isDsfs;
|
||||
|
||||
@JsonProperty("ChaoSend")
|
||||
private List<FileItem> chaoSend;
|
||||
|
||||
/** 接收人列表:"all" 或用户ID列表 */
|
||||
@JsonProperty("tlist")
|
||||
private Object tlist;
|
||||
|
||||
/**
|
||||
* 接收对象可读文本("全部班级" 或班级名顿号串)。
|
||||
* 详情页「接收班级」标签直接展示,避免前端拿 ReceiveList 的 id 串渲染。
|
||||
*/
|
||||
@JsonProperty("receiveText")
|
||||
private String receiveText;
|
||||
|
||||
/**
|
||||
* 附件项(旧 ChaoSend 数组元素)。
|
||||
*/
|
||||
@Data
|
||||
public static class FileItem {
|
||||
@JsonProperty("id")
|
||||
private Integer id;
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
@JsonProperty("size")
|
||||
private Integer size;
|
||||
@JsonProperty("fileid")
|
||||
private Integer fileid;
|
||||
@JsonProperty("filename")
|
||||
private String filename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import com.yunhai.homework.model.BasePageResult;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 作业分页结果(扩展 BasePageResult,额外携带 unreadCount)。
|
||||
* <p>
|
||||
* 对齐方案 M7:unreadCount 并入分页外壳扩展子类,不改基类契约。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class HomeworkPageResult<T> extends BasePageResult<T> {
|
||||
|
||||
/** 当前用户未读作业总数 */
|
||||
private long unreadCount;
|
||||
|
||||
public HomeworkPageResult(List<T> content, int total, int pageIndex, int pageSize,
|
||||
int totalPages, boolean hasNext, long unreadCount) {
|
||||
super(content, total, pageIndex, pageSize, totalPages, hasNext);
|
||||
this.unreadCount = unreadCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import com.yunhai.homework.model.BasePageQuery;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 作业列表查询条件。
|
||||
* <p>
|
||||
* - 管理端(adminList):用 status / type / deptId / publisherId / 时间范围过滤;
|
||||
* - 用户端(userList):额外用 readType 过滤未读/已读(0 全部 / 1 未读 / 2 已读)。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class HomeworkQuery extends BasePageQuery {
|
||||
|
||||
/** 状态过滤:null 不过滤;1 已发布 */
|
||||
private Integer status;
|
||||
|
||||
/** 类型过滤:1 普通 / 2 重要 */
|
||||
private Integer type;
|
||||
|
||||
/** 列表范围(管理端):"user" 只看自己发布的,null 看全部 */
|
||||
private String scope;
|
||||
|
||||
/** 发布部门ID */
|
||||
private String deptId;
|
||||
|
||||
/** 发布人ID(用户中心数字ID,管理端按发布人查) */
|
||||
private Integer publisherId;
|
||||
|
||||
/** 开始时间(创建时间 >=,前端传 yyyy-MM-dd 短日期) */
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate startTime;
|
||||
|
||||
/** 结束时间(创建时间 <= 当天 23:59:59,前端传 yyyy-MM-dd 短日期) */
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate endTime;
|
||||
|
||||
/** 阅读状态过滤(仅用户端):0 全部 / 1 未读 / 2 已读 */
|
||||
private Integer readType = 0;
|
||||
|
||||
/** 排序:1 时间倒序(默认)/ 2 时间正序 */
|
||||
private String orderByTime = "1";
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import com.yunhai.homework.common.validation.ValidationGroups;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 作业发布/编辑入参。发布人由当前登录用户上下文填充,不在此入参中传递。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkRequest {
|
||||
|
||||
/** 作业标题 */
|
||||
@NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}, message = "作业标题不得为空")
|
||||
private String title;
|
||||
|
||||
/** 作业内容 */
|
||||
private String content;
|
||||
|
||||
/** 作业类型:1 普通 / 2 重要 */
|
||||
@NotNull(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}, message = "作业类型不得为空")
|
||||
private Integer type = 1;
|
||||
|
||||
/** 发布部门ID(原 DeptID,必填——对应原系统「发布部门不得为空」校验) */
|
||||
@NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}, message = "发布部门不得为空")
|
||||
private String deptId;
|
||||
|
||||
/** 发布部门名称 */
|
||||
private String deptName;
|
||||
|
||||
/** 是否置顶:0 否 / 1 是 */
|
||||
private Integer topmost = 0;
|
||||
|
||||
/** 接收人列表(JSON 数组字符串,如 ["10012","10013"]——用户中心数字ID,或 "ALL" 表示全员) */
|
||||
private String receiveList;
|
||||
|
||||
/** 附件文件ID列表(逗号分隔串,如 "1,2,3");旧名 chaoSend,已更名 fileIds(M6) */
|
||||
private String fileIds;
|
||||
|
||||
/** 定时发送时间(为空表示立即发布) */
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime timingSendTime;
|
||||
|
||||
/** 短信发送标记:0 不发短信 / 1 发短信(旧名 topmost 实指发短信,已正名 smsFlag,M6) */
|
||||
private Integer smsFlag = 0;
|
||||
|
||||
/** 转发源作业ID(非空时表示转发创建,对应旧 REST 壳 forward/{sourceId}) */
|
||||
private Integer sourceId;
|
||||
|
||||
// ==================== 课堂作业 V1/V2 扩展(前端契约字段,兼容层同步写新列) ====================
|
||||
|
||||
/** 学科(字典值) */
|
||||
private String subject;
|
||||
|
||||
/** 截止时间 */
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime deadline;
|
||||
|
||||
/** 提交方式:text/image/attach/none 组合 */
|
||||
private java.util.List<String> submitType;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 作业统计视图(对应原系统 GetStatisData / 按发布人统计)。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkStatisticsVo {
|
||||
|
||||
/** 作业总数(全部已发布) */
|
||||
private long total;
|
||||
|
||||
/** 已发布数 */
|
||||
private long publishedCount;
|
||||
|
||||
/** 阅读记录总数(累计已读人次) */
|
||||
private long totalReadRecords;
|
||||
|
||||
/** 当前用户未读数(已到点的已发布 - 当前用户已读) */
|
||||
private long unreadForCurrentUser;
|
||||
|
||||
/** 按发布人统计 */
|
||||
private List<PublisherStat> byPublisher;
|
||||
|
||||
/** 按月统计(已发布作业数) */
|
||||
private List<MonthStat> byMonth;
|
||||
|
||||
// ==================== 课程作业口径(前端 /stats 页消费) ====================
|
||||
|
||||
/** 我布置的作业数(当前登录人发布的全部作业,含草稿) */
|
||||
private long myAssignCount;
|
||||
|
||||
/** 我的作业待批改总量(已交未批的当前版本行合计) */
|
||||
private long pendingGrade;
|
||||
|
||||
/** 各作业平均提交率(%,仅统计需收集提交的作业;无样本时为 0) */
|
||||
private double avgSubmitRate;
|
||||
|
||||
/** 按作业的提交与批改进度明细(草稿与仅查阅型不计) */
|
||||
private List<HomeworkStat> byHomework = new ArrayList<>();
|
||||
|
||||
/** 已批阅提交的分数分布(四档) */
|
||||
private List<ScoreBucket> scoreDist = new ArrayList<>();
|
||||
|
||||
/** 单作业进度条目(口径对齐前端 HomeworkProgress 契约) */
|
||||
@Data
|
||||
public static class HomeworkStat {
|
||||
private Integer id;
|
||||
private String title;
|
||||
private String subject;
|
||||
/** 旧契约四态派生值:draft / collecting / closed / done */
|
||||
private String hwStatus;
|
||||
private String hwStatusDesc;
|
||||
/** 应交人数 */
|
||||
private long should;
|
||||
/** 已读人数 */
|
||||
private long read;
|
||||
/** 已交人数 */
|
||||
private long submitted;
|
||||
/** 已批阅人数 */
|
||||
private long graded;
|
||||
/** 待批改人数 */
|
||||
private long pendingGrade;
|
||||
/** 未交人数 */
|
||||
private long unsubmitted;
|
||||
/** 提交率(%) */
|
||||
private double submitRate;
|
||||
/** 批阅率(%) */
|
||||
private double gradeRate;
|
||||
}
|
||||
|
||||
/** 分数分布档(key 供前端配色映射:excellent/good/pass/fail) */
|
||||
@Data
|
||||
public static class ScoreBucket {
|
||||
private String label;
|
||||
private String key;
|
||||
private long count;
|
||||
|
||||
public ScoreBucket(String label, String key, long count) {
|
||||
this.label = label;
|
||||
this.key = key;
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class PublisherStat {
|
||||
private String publisherName;
|
||||
private long count;
|
||||
|
||||
public PublisherStat(String publisherName, long count) {
|
||||
this.publisherName = publisherName;
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MonthStat {
|
||||
private int year;
|
||||
private int month;
|
||||
private long count;
|
||||
|
||||
public MonthStat(int year, int month, long count) {
|
||||
this.year = year;
|
||||
this.month = month;
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户端作业列表结果:在分页数据之外额外携带「当前用户未读总数」,
|
||||
* 供前端展示未读角标(对应原系统 OtherData.unReadCount)。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkUserListResult {
|
||||
|
||||
private int total;
|
||||
private List<HomeworkVo> content;
|
||||
private int pageIndex;
|
||||
private int pageSize;
|
||||
private int totalPages;
|
||||
private boolean hasNext;
|
||||
|
||||
/** 当前用户未读作业总数 */
|
||||
private long unreadCount;
|
||||
|
||||
public HomeworkUserListResult(List<HomeworkVo> content, int total, int pageIndex, int pageSize,
|
||||
int totalPages, boolean hasNext, long unreadCount) {
|
||||
this.content = content;
|
||||
this.total = total;
|
||||
this.pageIndex = pageIndex;
|
||||
this.pageSize = pageSize;
|
||||
this.totalPages = totalPages;
|
||||
this.hasNext = hasNext;
|
||||
this.unreadCount = unreadCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 作业视图对象(列表/详情返回)。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkVo {
|
||||
|
||||
private Integer id;
|
||||
private String title;
|
||||
private String content;
|
||||
private Integer type;
|
||||
private String typeDesc;
|
||||
/** 发布人ID(用户中心数字ID) */
|
||||
private Integer publisherId;
|
||||
private String publisherName;
|
||||
private String deptId;
|
||||
private String deptName;
|
||||
private Integer status;
|
||||
private String statusDesc;
|
||||
private Integer topmost;
|
||||
|
||||
/** 已读人数(基于阅读记录实时统计) */
|
||||
private Long readCount = 0L;
|
||||
|
||||
/** 应读人数 */
|
||||
private Integer allowCount;
|
||||
|
||||
/** 当前用户是否已读(用户端列表使用;管理端恒为 false 或不关注) */
|
||||
private boolean read = false;
|
||||
|
||||
/** 是否撤回:0 否 / 1 是 */
|
||||
private Integer isPulled;
|
||||
|
||||
/** 定时发送时间 */
|
||||
private LocalDateTime timingSendTime;
|
||||
|
||||
/** 父作业ID(转发时关联原作业) */
|
||||
private Integer parentId;
|
||||
|
||||
/** 短信发送标记 */
|
||||
private Integer smsFlag;
|
||||
|
||||
/** 接收人列表(JSON) */
|
||||
private String receiveList;
|
||||
|
||||
/** 附件ID串("1,2,3",列表页下载入口使用;对齐旧 .NET UpFile 字段) */
|
||||
private String UpFile;
|
||||
|
||||
// ==================== 课堂作业 V1/V2 扩展(前端 types/homework.ts 契约) ====================
|
||||
|
||||
/** 学科(字典值) */
|
||||
private String subject;
|
||||
|
||||
/** 截止时间(前端契约字段名 deadline) */
|
||||
private LocalDateTime deadline;
|
||||
|
||||
/** 提交方式数组:text/image/attach/none */
|
||||
private java.util.List<String> submitType;
|
||||
|
||||
/** 作业流程状态——旧契约四态派生值(draft/collecting/closed/done),权威五态见 homework.hw_status */
|
||||
private String hwStatus;
|
||||
|
||||
private String hwStatusDesc;
|
||||
|
||||
/**
|
||||
* 提交/批改进度(管理端列表页「提交进度 / 未读未交 / 批改」列使用)。
|
||||
* 草稿或仅查阅型为 null;列表场景由 HomeworkProgressCalculator 批量聚合回填。
|
||||
*/
|
||||
private com.yunhai.homework.model.v2.ProgressVo progress;
|
||||
|
||||
private String createBy;
|
||||
private LocalDateTime createTime;
|
||||
private String updateBy;
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 阅读明细视图(阅读列表查询用)。
|
||||
*/
|
||||
@Data
|
||||
public static class ReadDetail {
|
||||
/** 读者ID(用户中心数字ID) */
|
||||
private Integer id;
|
||||
private String name;
|
||||
private boolean read;
|
||||
private LocalDateTime readTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 一键已读结果视图对象(替代原 Map<String,Object> 返回)。
|
||||
*/
|
||||
@Data
|
||||
public class InitializeRedVo {
|
||||
|
||||
@JsonProperty("count")
|
||||
private Integer count;
|
||||
|
||||
public InitializeRedVo() {}
|
||||
|
||||
public InitializeRedVo(Integer count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 文件上传结果视图对象(替代原 Map<String,Object> 返回)。
|
||||
* 使用 @JsonProperty 保持旧字段名兼容前端渲染。
|
||||
*/
|
||||
@Data
|
||||
public class UpFileResultVo {
|
||||
|
||||
@JsonProperty("fileid")
|
||||
private Integer fileid;
|
||||
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
|
||||
@JsonProperty("fileurl")
|
||||
private String fileurl;
|
||||
|
||||
@JsonProperty("host")
|
||||
private String host;
|
||||
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
@JsonProperty("size")
|
||||
private Integer size;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 附件视图对象(对应原 .NET FileObj)。
|
||||
*/
|
||||
@Data
|
||||
public class UpFileVo {
|
||||
|
||||
/** 文件记录ID */
|
||||
private Integer id;
|
||||
|
||||
/** 文件真实名称 */
|
||||
private String fileTrueName;
|
||||
|
||||
/** 文件存储路径(相对路径) */
|
||||
private String fileName;
|
||||
|
||||
/** 文件大小(字节) */
|
||||
private Integer fileSize;
|
||||
|
||||
/** 文件后缀名 */
|
||||
private String fileType;
|
||||
|
||||
/** 关联主题ID */
|
||||
private Integer topicId;
|
||||
|
||||
/** 应用类型 */
|
||||
private String topicType;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.yunhai.homework.model.homework;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户可访问模块(左菜单)视图对象。
|
||||
* <p>将基础平台返回的扁平 {@code List<BoaModule>} 转换为前端 layout(参考 UserBase)期望的树结构:
|
||||
* {@code modId}(路由高亮匹配)/{@code page}(跳转路径)/{@code children}(子菜单)。</p>
|
||||
*/
|
||||
public class UserModuleVo {
|
||||
|
||||
/** 模块主键 id(基础平台 module id) */
|
||||
private Integer id;
|
||||
|
||||
/** 菜单高亮匹配用:等价于后端模块 id */
|
||||
private Integer modId;
|
||||
|
||||
/** 模块名称 */
|
||||
private String name;
|
||||
|
||||
/** 父级模块 id(0 表示根节点) */
|
||||
private Integer parentId;
|
||||
|
||||
/** 前端路由路径(由 BoaModule.path 映射而来) */
|
||||
private String page;
|
||||
|
||||
/** 层级(0=根分组) */
|
||||
private Integer level;
|
||||
|
||||
/** 菜单图标 */
|
||||
private String icon;
|
||||
|
||||
/** 排序号 */
|
||||
private Integer orderNumber;
|
||||
|
||||
/** 是否可用 */
|
||||
private Boolean usable;
|
||||
|
||||
/** 子菜单 */
|
||||
private List<UserModuleVo> children = new ArrayList<>();
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getModId() {
|
||||
return modId;
|
||||
}
|
||||
|
||||
public void setModId(Integer modId) {
|
||||
this.modId = modId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Integer parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(String page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public Integer getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public void setLevel(Integer level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public Integer getOrderNumber() {
|
||||
return orderNumber;
|
||||
}
|
||||
|
||||
public void setOrderNumber(Integer orderNumber) {
|
||||
this.orderNumber = orderNumber;
|
||||
}
|
||||
|
||||
public Boolean getUsable() {
|
||||
return usable;
|
||||
}
|
||||
|
||||
public void setUsable(Boolean usable) {
|
||||
this.usable = usable;
|
||||
}
|
||||
|
||||
public List<UserModuleVo> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List<UserModuleVo> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 附件条目(作业附件与提交附件共用)。fileUrl 必传;fileId 为 file/Upload 产物时回传。
|
||||
*/
|
||||
@Data
|
||||
public class AttachmentItem {
|
||||
|
||||
/** up_file.id */
|
||||
private Integer fileId;
|
||||
|
||||
/** 文件访问 URL */
|
||||
private String fileUrl;
|
||||
|
||||
/** 文件类型:image / file */
|
||||
private String fileType;
|
||||
|
||||
/** 文件名 */
|
||||
private String fileName;
|
||||
|
||||
/** 排序号 */
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 班级条目(作业参与班级展示)。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ClassItem {
|
||||
|
||||
private String classId;
|
||||
|
||||
private String className;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 年级→班级树(发布作业选班 + 应交名单基数来源)。
|
||||
* 叶子节点 id = 班级 id(class_student 快照聚合)。
|
||||
*/
|
||||
@Data
|
||||
public class ClassTreeNode {
|
||||
|
||||
/** 年级节点为 gradeName,班级叶子为 classId */
|
||||
private String id;
|
||||
|
||||
/** 展示名 */
|
||||
private String name;
|
||||
|
||||
/** 是否父节点(年级) */
|
||||
private Boolean isParent;
|
||||
|
||||
/** 叶子节点:在班学生数 */
|
||||
private Integer studentCount;
|
||||
|
||||
private List<ClassTreeNode> children = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 延长截止请求(新截止时间必须晚于当前时间)。
|
||||
*/
|
||||
@Data
|
||||
public class ExtendRequest {
|
||||
|
||||
@NotNull(message = "新截止时间不得为空")
|
||||
private LocalDateTime deadlineAt;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 作业详情汇总统计卡片(PRD §18 页 4 stats 接口出参)。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkStatsVo {
|
||||
|
||||
private Integer homeworkId;
|
||||
|
||||
private String title;
|
||||
|
||||
private String hwStatus;
|
||||
|
||||
private String hwStatusDesc;
|
||||
|
||||
/** 总进度 */
|
||||
private ProgressVo total;
|
||||
|
||||
/** 分班进度 */
|
||||
private List<ByClass> byClass;
|
||||
|
||||
@Data
|
||||
public static class ByClass {
|
||||
|
||||
private String classId;
|
||||
|
||||
private String className;
|
||||
|
||||
private ProgressVo progress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 创建/编辑作业请求(PRD §18 页 1 表单)。
|
||||
* 创建一律落草稿(DRAFT_UNPUBLISHED),发布/定时走独立接口。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkV2Request {
|
||||
|
||||
/** 作业标题(必填 ≤50 字) */
|
||||
@NotBlank(message = "作业标题不得为空")
|
||||
@Size(max = 50, message = "作业标题不超过50字")
|
||||
private String title;
|
||||
|
||||
/** 学科(字典值) */
|
||||
private String subject;
|
||||
|
||||
/** 作业说明(富文本) */
|
||||
private String description;
|
||||
|
||||
/** 参与班级 id 列表 */
|
||||
private List<String> classIds;
|
||||
|
||||
/** 附件列表 */
|
||||
private List<AttachmentItem> attachments;
|
||||
|
||||
/** 截止时间(精确到分钟;空 = 仅查阅型) */
|
||||
private LocalDateTime deadlineAt;
|
||||
|
||||
/** 提交方式:image / attach / text / none 的组合(PRD 图片/文件/两者) */
|
||||
private List<String> submitType;
|
||||
|
||||
/** 截止后是否允许逾期提交:0 否 / 1 是 */
|
||||
private Integer allowLate;
|
||||
|
||||
/** 提醒设置:截止前 1 天提醒(0 关 / 1 开) */
|
||||
private Integer remind1d;
|
||||
|
||||
/** 提醒设置:截止前 1 小时提醒(0 关 / 1 开) */
|
||||
private Integer remind1h;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 作业视图对象 V2(草稿箱/已发布列表/详情共用)。
|
||||
* 列表场景 attachments/classes 可按需填充;progress 仅非草稿且非仅查阅型作业返回。
|
||||
*/
|
||||
@Data
|
||||
public class HomeworkV2Vo {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String title;
|
||||
|
||||
/** 学科 */
|
||||
private String subject;
|
||||
|
||||
/** 作业说明(富文本;列表场景可置空省流) */
|
||||
private String description;
|
||||
|
||||
/** 作业状态(PRD 五态) */
|
||||
private String hwStatus;
|
||||
|
||||
private String hwStatusDesc;
|
||||
|
||||
/** 定时发布时间(复用 timing_send_time) */
|
||||
private LocalDateTime scheduledAt;
|
||||
|
||||
/** 发布时间 */
|
||||
private LocalDateTime publishedAt;
|
||||
|
||||
/** 截止时间 */
|
||||
private LocalDateTime deadlineAt;
|
||||
|
||||
/** 归档时间 */
|
||||
private LocalDateTime archivedAt;
|
||||
|
||||
/** 提交方式数组 */
|
||||
private List<String> submitType;
|
||||
|
||||
/** 截止后允许逾期提交:0/1 */
|
||||
private Integer allowLate;
|
||||
|
||||
/** 提醒设置:截止前 1 天 */
|
||||
private Integer remind1d;
|
||||
|
||||
/** 提醒设置:截止前 1 小时 */
|
||||
private Integer remind1h;
|
||||
|
||||
/** 参与班级 */
|
||||
private List<ClassItem> classes;
|
||||
|
||||
/** 附件列表(详情场景填充) */
|
||||
private List<AttachmentItem> attachments;
|
||||
|
||||
/** 发布人ID(用户中心数字ID) */
|
||||
private Integer publisherId;
|
||||
|
||||
/** 发布人姓名 */
|
||||
private String publisherName;
|
||||
|
||||
/** 创建/更新时间(审计) */
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/** 汇总进度(草稿或仅查阅型为 null) */
|
||||
private ProgressVo progress;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import com.yunhai.homework.model.BasePageResult;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 通知分页结果(含当前用户未读数)。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NotificationPageResult extends BasePageResult<NotificationVo> {
|
||||
|
||||
/** 当前用户未读通知总数 */
|
||||
private long unreadCount;
|
||||
|
||||
public NotificationPageResult(BasePageResult<NotificationVo> page, long unreadCount) {
|
||||
super(page.getContent(), page.getTotal(), page.getPageIndex(), page.getPageSize(),
|
||||
page.getTotalPages(), page.isHasNext());
|
||||
this.unreadCount = unreadCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import com.yunhai.homework.model.BasePageQuery;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 通知列表查询。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class NotificationQuery extends BasePageQuery {
|
||||
|
||||
/** 类型过滤(NotificationTypeEnum code) */
|
||||
private String type;
|
||||
|
||||
/** 已读过滤:0 未读 / 1 已读(空 = 全部) */
|
||||
private Integer isRead;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通知列表项。
|
||||
*/
|
||||
@Data
|
||||
public class NotificationVo {
|
||||
|
||||
private Integer id;
|
||||
|
||||
/** 通知类型 */
|
||||
private String type;
|
||||
|
||||
private String typeDesc;
|
||||
|
||||
private String title;
|
||||
|
||||
private String content;
|
||||
|
||||
private Integer homeworkId;
|
||||
|
||||
private Integer relatedId;
|
||||
|
||||
/** 是否已读:0/1 */
|
||||
private Integer isRead;
|
||||
|
||||
private LocalDateTime readAt;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 提交/批阅/阅读进度(PRD §18 页 3 汇总口径)。
|
||||
* should(应交)为分母;打回未重交计入已交。
|
||||
*/
|
||||
@Data
|
||||
public class ProgressVo {
|
||||
|
||||
/** 应交人数(参与班级在班学生去重) */
|
||||
private int should;
|
||||
|
||||
/** 已读人数 */
|
||||
private int read;
|
||||
|
||||
/** 已交人数(含逾期/打回/已批阅) */
|
||||
private int submitted;
|
||||
|
||||
/** 已批阅人数 */
|
||||
private int graded;
|
||||
|
||||
/** 待批阅人数(submitted - graded) */
|
||||
private int pendingGrade;
|
||||
|
||||
/** 未交人数 */
|
||||
private int unsubmitted;
|
||||
|
||||
/** 未读人数 */
|
||||
private int unread;
|
||||
|
||||
/** 未读且未交人数(高亮口径:should - 已读∪已交) */
|
||||
private int unreadUndone;
|
||||
|
||||
/** 阅读率(百分数,一位小数) */
|
||||
private double readRate;
|
||||
|
||||
/** 提交率(百分数,一位小数) */
|
||||
private double submitRate;
|
||||
|
||||
/** 批阅率(已批阅 / 已交,百分数一位小数;submitted=0 时为 0) */
|
||||
private double gradeRate;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 教师手动提醒请求:type = NOT_READ / NOT_SUBMITTED,studentIds 为空时提醒全部未读/未交学生。
|
||||
*/
|
||||
@Data
|
||||
public class RemindRequest {
|
||||
|
||||
/** 提醒类型:NOT_READ / NOT_SUBMITTED */
|
||||
@NotBlank(message = "提醒类型不得为空")
|
||||
private String type;
|
||||
|
||||
/** 定向学生ID(用户中心数字ID;空 = 全部未读/未交) */
|
||||
private List<Integer> studentIds;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 打回请求(PRD 页 6)。comment 为订正原因,必填。
|
||||
*/
|
||||
@Data
|
||||
public class ReturnRequest {
|
||||
|
||||
@NotBlank(message = "打回须填写订正原因")
|
||||
private String comment;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 批阅保存请求(PRD 页 6)。score 与 comment 至少一项有值。
|
||||
*/
|
||||
@Data
|
||||
public class ReviewRequest {
|
||||
|
||||
/** 评分 */
|
||||
private BigDecimal score;
|
||||
|
||||
/** 评语 */
|
||||
private String comment;
|
||||
|
||||
/** 圈划标注图片(P2,先收参) */
|
||||
private List<String> markedImages;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 定时发布 / 取消定时请求。
|
||||
* cancel=true 时忽略 scheduledAt,作业回退草稿-未发布并清空定时时间。
|
||||
*/
|
||||
@Data
|
||||
public class ScheduleRequest {
|
||||
|
||||
/** 定时发布时间(cancel=false 时必填且须晚于当前时间) */
|
||||
private LocalDateTime scheduledAt;
|
||||
|
||||
/** 是否取消定时 */
|
||||
private Boolean cancel = false;
|
||||
|
||||
@NotNull
|
||||
public Boolean getCancel() {
|
||||
return cancel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生端作业详情(PRD §18 学生页 2)。进入详情后由前端停留 ≥3 秒再调 read 上报。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class StudentHomeworkDetailVo extends StudentHomeworkVo {
|
||||
|
||||
/** 作业说明(富文本) */
|
||||
private String description;
|
||||
|
||||
/** 作业附件 */
|
||||
private List<AttachmentItem> attachments;
|
||||
|
||||
/** 参与班级(学生所属班级视角) */
|
||||
private List<ClassItem> classes;
|
||||
|
||||
/** 我当前版本的提交附件(未提交为 null) */
|
||||
private List<AttachmentItem> myAttachments;
|
||||
|
||||
/** 我的文本内容(当前版本) */
|
||||
private String myText;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 学生端作业列表项(PRD §18 学生页 1)。
|
||||
*/
|
||||
@Data
|
||||
public class StudentHomeworkVo {
|
||||
|
||||
private Integer id;
|
||||
|
||||
private String title;
|
||||
|
||||
/** 学科 */
|
||||
private String subject;
|
||||
|
||||
/** 任课教师(发布人姓名) */
|
||||
private String teacherName;
|
||||
|
||||
/** 截止时间(前端做倒计时) */
|
||||
private LocalDateTime deadlineAt;
|
||||
|
||||
/** 提交方式 */
|
||||
private java.util.List<String> submitType;
|
||||
|
||||
/** 作业状态 */
|
||||
private String hwStatus;
|
||||
|
||||
private String hwStatusDesc;
|
||||
|
||||
/** 截止后是否允许逾期补交:0 否 / 1 是(学生端据此决定是否渲染「补交」入口) */
|
||||
private Integer allowLate;
|
||||
|
||||
/** 我的提交概要(未提交为 null) */
|
||||
private MySubmission my;
|
||||
|
||||
@Data
|
||||
public static class MySubmission {
|
||||
|
||||
/** 当前版本提交行ID */
|
||||
private Integer submissionId;
|
||||
|
||||
/** 提交状态(PRD 五态) */
|
||||
private String submitStatus;
|
||||
|
||||
private String submitStatusDesc;
|
||||
|
||||
/** 提交时间 */
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
/** 是否逾期 */
|
||||
private Integer isLate;
|
||||
|
||||
/** 版本号 */
|
||||
private Integer version;
|
||||
|
||||
/** 批阅状态 */
|
||||
private String reviewStatus;
|
||||
|
||||
/** 评分(已批阅才有) */
|
||||
private java.math.BigDecimal score;
|
||||
|
||||
/** 评语 */
|
||||
private String comment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import com.yunhai.homework.model.BasePageQuery;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 学生矩阵查询(PRD §18 页 5)。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class StudentMatrixQuery extends BasePageQuery {
|
||||
|
||||
/** 班级筛选(空 = 全部参与班级) */
|
||||
private String classId;
|
||||
|
||||
/** 提交状态筛选:NOT_SUBMITTED/SUBMITTED/LATE_SUBMITTED/RETURNED/REVIEWED */
|
||||
private String submitStatus;
|
||||
|
||||
/** 批阅状态筛选:PENDING/REVIEWED/RETURNED */
|
||||
private String reviewStatus;
|
||||
|
||||
/** 只看待批阅(reviewStatus=PENDING 且已提交)快捷过滤 */
|
||||
private Boolean pendingGrade;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生矩阵行(PRD §18 页 5)。未交学生也生成占位行(submissionId=0)。
|
||||
*/
|
||||
@Data
|
||||
public class StudentMatrixVo {
|
||||
|
||||
/** 当前版本提交行ID(未交占位为 0) */
|
||||
private Integer submissionId;
|
||||
|
||||
/** 学生ID(用户中心数字ID) */
|
||||
private Integer studentId;
|
||||
|
||||
/** 姓名 */
|
||||
private String studentName;
|
||||
|
||||
private String classId;
|
||||
|
||||
private String className;
|
||||
|
||||
/** 阅读状态:0 未读 / 1 已读 */
|
||||
private Integer isRead;
|
||||
|
||||
/** 首次阅读时间 */
|
||||
private LocalDateTime firstReadAt;
|
||||
|
||||
/** 最近阅读时间 */
|
||||
private LocalDateTime lastReadAt;
|
||||
|
||||
/** 提交状态(PRD 五态;未交为 NOT_SUBMITTED) */
|
||||
private String submitStatus;
|
||||
|
||||
/** 提交时间 */
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
/** 是否逾期:0/1 */
|
||||
private Integer isLate;
|
||||
|
||||
/** 批阅状态 */
|
||||
private String reviewStatus;
|
||||
|
||||
/** 评分 */
|
||||
private BigDecimal score;
|
||||
|
||||
/** 最新提交附件 URL 列表(缩略图) */
|
||||
private List<String> thumbnails;
|
||||
|
||||
/** 提交内容类型摘要:image=拍照/图片、attach=上传附件、text=文字作答(未交为空列表) */
|
||||
private List<String> contentTypes;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生查看批阅结果(PRD §18 学生页 2 result 接口)。
|
||||
*/
|
||||
@Data
|
||||
public class StudentResultVo {
|
||||
|
||||
private Integer homeworkId;
|
||||
|
||||
private String homeworkTitle;
|
||||
|
||||
/** 当前版本批阅结果(未批阅为 null) */
|
||||
private SubmissionVersionVo latest;
|
||||
|
||||
/** 全部版本(含各版评语,新→旧) */
|
||||
private List<SubmissionVersionVo> versions;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生提交作业请求(PRD §18 学生页 3)。附件只接受 file/Upload 产物(fileId 或平台 URL),拒绝 dataURL。
|
||||
*/
|
||||
@Data
|
||||
public class StudentSubmitRequest {
|
||||
|
||||
/** 文本内容(submitType 含 text 时有效) */
|
||||
@Size(max = 20000, message = "文本内容过长")
|
||||
private String text;
|
||||
|
||||
/** 附件列表(图片/文件) */
|
||||
private List<AttachmentItem> attachments;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 学科 DTO(布置过的学科 / 我的任教学科共用返回结构)。
|
||||
*/
|
||||
@Data
|
||||
public class SubjectDto {
|
||||
|
||||
/** 学科编码(homework.subject 字典值 / bschclass SubID) */
|
||||
private String subId;
|
||||
|
||||
/** 学科名称(本校学科字典解析;字典缺失时回退为编码) */
|
||||
private String subName;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 撤回重交动作(PUT /student/homeworks/{id}/submissions/{submissionId})。
|
||||
* withdraw = 撤回(截止前,产生 NOT_SUBMITTED 新版本行);resubmit = 打回后重交(走提交语义)。
|
||||
*/
|
||||
@Data
|
||||
public class SubmissionActionRequest {
|
||||
|
||||
@NotBlank(message = "action 不得为空")
|
||||
private String action;
|
||||
|
||||
/** resubmit 时的提交内容(等同 StudentSubmitRequest) */
|
||||
private String text;
|
||||
|
||||
/** resubmit 时的附件 */
|
||||
private java.util.List<AttachmentItem> attachments;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 提交版本条目(历史版本/批阅弹窗/学生结果页共用)。
|
||||
*/
|
||||
@Data
|
||||
public class SubmissionVersionVo {
|
||||
|
||||
private Integer submissionId;
|
||||
|
||||
private Integer homeworkId;
|
||||
|
||||
/** 学生ID(用户中心数字ID) */
|
||||
private Integer studentId;
|
||||
|
||||
private String studentName;
|
||||
|
||||
/** 版本号 */
|
||||
private Integer version;
|
||||
|
||||
/** 是否当前版本:0/1 */
|
||||
private Integer isLatest;
|
||||
|
||||
/** 提交状态 */
|
||||
private String submitStatus;
|
||||
|
||||
private String submitStatusDesc;
|
||||
|
||||
/** 提交时间 */
|
||||
private LocalDateTime submittedAt;
|
||||
|
||||
/** 是否逾期 */
|
||||
private Integer isLate;
|
||||
|
||||
/** 文本内容 */
|
||||
private String text;
|
||||
|
||||
/** 附件 */
|
||||
private List<AttachmentItem> attachments;
|
||||
|
||||
/** 评分 */
|
||||
private BigDecimal score;
|
||||
|
||||
/** 评语 */
|
||||
private String comment;
|
||||
|
||||
/** 批阅状态 */
|
||||
private String reviewStatus;
|
||||
|
||||
private String reviewStatusDesc;
|
||||
|
||||
/** 批阅人(展示姓名快照,缺失时回退ID) */
|
||||
private String reviewedBy;
|
||||
|
||||
/** 批阅时间 */
|
||||
private LocalDateTime reviewedAt;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import com.yunhai.homework.model.BasePageQuery;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 教师端作业列表查询(草稿箱/已发布列表共用)。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TeacherHomeworkQuery extends BasePageQuery {
|
||||
|
||||
/** 学科筛选 */
|
||||
private String subject;
|
||||
|
||||
/** 作业状态筛选(已发布列表:PUBLISHED/CLOSED/ARCHIVED) */
|
||||
private String hwStatus;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yunhai.homework.model.v2;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 任教班级 VO(按学科筛选任教班级返回结构)。
|
||||
*/
|
||||
@Data
|
||||
public class TeachingClassVo {
|
||||
|
||||
/** 班级业务ID(bschclass sch_class.class_id) */
|
||||
private String classId;
|
||||
|
||||
/** 班级名称(学校班级列表映射;缺失时回退为班级ID) */
|
||||
private String className;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.yunhai.homework.repository;
|
||||
|
||||
import com.yunhai.homework.entity.ClassStudent;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 班级学生名册仓储。
|
||||
*/
|
||||
public interface ClassStudentRepository extends JpaRepository<ClassStudent, Integer> {
|
||||
|
||||
/** 按学生ID(用户中心数字ID)反查学生身份(学生端接口入口) */
|
||||
List<ClassStudent> findByStudentIdAndStatus(Integer studentId, Integer status);
|
||||
|
||||
/** 班级在班学生 */
|
||||
List<ClassStudent> findByClassIdAndStatus(String classId, Integer status);
|
||||
|
||||
/** 指定班级集合的全部在班学生(应交名单) */
|
||||
List<ClassStudent> findByClassIdInAndStatus(List<String> classIds, Integer status);
|
||||
|
||||
/** 指定学校的全部名册(同步任务全量刷新用) */
|
||||
List<ClassStudent> findBySchoolId(Integer schoolId);
|
||||
|
||||
/** 年级→班级树:按学校去重班级(class_student 快照聚合),列序:classId, className, gradeName */
|
||||
@Query("select distinct c.classId, c.className, c.gradeName from ClassStudent c " +
|
||||
"where c.schoolId = :schoolId and c.status = 1")
|
||||
List<Object[]> findDistinctClasses(@Param("schoolId") Integer schoolId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.yunhai.homework.repository;
|
||||
|
||||
import com.yunhai.homework.entity.ContactsGroup;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ContactsGroupRepository extends JpaRepository<ContactsGroup, Integer> {
|
||||
Page<ContactsGroup> findAllByOrderByCreateTimeDesc(Pageable pageable);
|
||||
|
||||
/**
|
||||
* 按创建人ID(用户中心数字ID)查询联系组列表。
|
||||
*/
|
||||
List<ContactsGroup> findByCreatorId(Integer creatorId);
|
||||
|
||||
/**
|
||||
* 按创建人ID查询联系组列表(分页)。
|
||||
*/
|
||||
Page<ContactsGroup> findByCreatorId(Integer creatorId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* 查询全部联系组(按创建时间降序)。
|
||||
*/
|
||||
List<ContactsGroup> findAllByOrderByCreateTimeDesc();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user