Compare commits
207
Commits
698d612797
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e063e67822 | ||
|
|
e0c9e14ab9 | ||
|
|
3fa52f21af | ||
|
|
a0c6a27f55 | ||
|
|
cee411472a | ||
|
|
a669bb67ec | ||
|
|
064c855a55 | ||
|
|
d633609306 | ||
|
|
1c19e3d2ef | ||
|
|
aecab2fd91 | ||
|
|
9f3b49c30a | ||
|
|
3e18856c0c | ||
|
|
43484a8936 | ||
|
|
8a61c77b12 | ||
|
|
0b1d8a3ecf | ||
|
|
700d6526b3 | ||
|
|
dde2a147b0 | ||
|
|
0462c772e4 | ||
|
|
086e0bbf39 | ||
|
|
b9782faeae | ||
|
|
2d4f3db219 | ||
|
|
2cf8334d74 | ||
|
|
d9604b3798 | ||
|
|
1b45924003 | ||
|
|
f73d9da730 | ||
|
|
eb734c5fea | ||
|
|
076524218f | ||
|
|
8a54bd7dc5 | ||
|
|
d1a748c0ff | ||
|
|
2aefd1175b | ||
|
|
391fab5c11 | ||
|
|
875f96ac3c | ||
|
|
79074a8537 | ||
|
|
b7192bd103 | ||
|
|
482f5891f5 | ||
|
|
81ffaa0842 | ||
|
|
656e44a0bb | ||
|
|
4e37597ac9 | ||
|
|
4a49e78997 | ||
|
|
1f03cdf040 | ||
|
|
4bd8126a63 | ||
|
|
369d87f6fd | ||
|
|
626686b851 | ||
|
|
2317574942 | ||
|
|
57c330ce1e | ||
|
|
826de16bd1 | ||
|
|
ce2222f939 | ||
|
|
c1e47a60cb | ||
|
|
69057e236d | ||
|
|
d42b9bea6c | ||
|
|
b66d3debb5 | ||
|
|
7b494ce839 | ||
|
|
38015816ac | ||
|
|
5aa13e8d25 | ||
|
|
1448e2ee90 | ||
|
|
bf5277ef7c | ||
|
|
c27dde7a52 | ||
|
|
d3a9930751 | ||
|
|
7c6f93e68d | ||
|
|
762e880a41 | ||
|
|
84f1e9d4fd | ||
|
|
582ab7101a | ||
|
|
afbd19522e | ||
|
|
e027a033b4 | ||
|
|
23f1c2f8ae | ||
|
|
290af59e9b | ||
|
|
0565faa3d3 | ||
|
|
711e3b150c | ||
|
|
88cc1857c8 | ||
|
|
ed056b73d4 | ||
|
|
511c4319ca | ||
|
|
c83a4d78f0 | ||
|
|
929fe71be4 | ||
|
|
9121f5bd69 | ||
|
|
ac18366bfb | ||
|
|
13409be869 | ||
|
|
8226f36cb5 | ||
|
|
3220ad3013 | ||
|
|
c1ea8bc25a | ||
|
|
d7588b8cea | ||
|
|
f055c07c99 | ||
|
|
2314a1adac | ||
|
|
f01ee5765a | ||
|
|
b3eaf4ede5 | ||
|
|
b29f92cecc | ||
|
|
8a10bd2099 | ||
|
|
c038026121 | ||
|
|
cb51543aff | ||
|
|
e37d060d27 | ||
|
|
5d8be1fd7e | ||
|
|
544038fd35 | ||
|
|
284bc94357 | ||
|
|
a49c28b5b2 | ||
|
|
503cbdf3f8 | ||
|
|
da148823a7 | ||
|
|
505a47d048 | ||
|
|
431a1415fe | ||
|
|
dcb51347dd | ||
|
|
af7d17c9c5 | ||
|
|
f69a5c2182 | ||
|
|
98b8ec5bc9 | ||
|
|
340c22e6a4 | ||
|
|
8010b5014d | ||
|
|
690a82aa4c | ||
|
|
e4014873bb | ||
|
|
8a7118d278 | ||
|
|
803483432a | ||
|
|
c0dd74318c | ||
|
|
d923649a8d | ||
|
|
ec306f0a98 | ||
|
|
0d82bd4c76 | ||
|
|
b4b660f60d | ||
|
|
ecc217ba86 | ||
|
|
f39a42dcf7 | ||
|
|
54317837a9 | ||
|
|
b54e1ad6e9 | ||
|
|
6af3319f0e | ||
|
|
8e89d9473a | ||
|
|
1636915510 | ||
|
|
c5744d7388 | ||
|
|
7592f471f7 | ||
|
|
d8c8d1cb20 | ||
|
|
736c21bb21 | ||
|
|
5f184f4b4b | ||
|
|
01e19df4fd | ||
|
|
8d4a32c75c | ||
|
|
0e859f2c87 | ||
|
|
fceb5c56bb | ||
|
|
6ce9a00528 | ||
|
|
f12851acc3 | ||
|
|
e281915fa4 | ||
|
|
276a21c12a | ||
|
|
fd79b09c3b | ||
|
|
caa551d33a | ||
|
|
61902f6943 | ||
|
|
14244729ee | ||
|
|
be754dc22c | ||
|
|
25b4d6ba1f | ||
|
|
ba845f3b0e | ||
|
|
833d3c6c2c | ||
|
|
300cbb807b | ||
|
|
3ed16db9e6 | ||
|
|
1302ec09b5 | ||
|
|
86ff348805 | ||
|
|
6ff09a5d02 | ||
|
|
14a37f4cc1 | ||
|
|
ddee1b68fa | ||
|
|
3b0e5190c3 | ||
|
|
ea9fde7979 | ||
|
|
27f00b61ff | ||
|
|
34a55668e5 | ||
|
|
72baf66d59 | ||
|
|
1f7705546d | ||
|
|
e4c11b6fcd | ||
|
|
c71c334a84 | ||
|
|
d9aa173b3d | ||
|
|
28efba14df | ||
|
|
a594494639 | ||
|
|
30461621b3 | ||
|
|
6976d1d9a5 | ||
|
|
1b3a457dba | ||
|
|
96dd81860e | ||
|
|
db7176c236 | ||
|
|
0d4b3936cb | ||
|
|
88f3c488bd | ||
|
|
29195e77d4 | ||
|
|
77a629ee64 | ||
|
|
cf33feb7d0 | ||
|
|
7d843d8c1b | ||
|
|
823330cdfb | ||
|
|
ae554d7aa2 | ||
|
|
b72976bd6e | ||
|
|
58cb64814f | ||
|
|
397e89d723 | ||
|
|
9ae303a29d | ||
|
|
2c058cfa35 | ||
|
|
259690f96c | ||
|
|
afd7c9d704 | ||
|
|
ce0812211c | ||
|
|
7a549c87c6 | ||
|
|
7b257d3056 | ||
|
|
3e7d2c1714 | ||
|
|
ea13c4ea7c | ||
|
|
863c4f5c13 | ||
|
|
6f957cad93 | ||
|
|
0501dec9b0 | ||
|
|
d279c699a6 | ||
|
|
ed48da0a78 | ||
|
|
62045af22b | ||
|
|
74dd0a6af2 | ||
|
|
4ed52b1607 | ||
|
|
00ef5cf0c1 | ||
|
|
d75e43cb81 | ||
|
|
470835a7dd | ||
|
|
4835612261 | ||
|
|
43c77e642b | ||
|
|
5210ad34f3 | ||
|
|
aa0308b386 | ||
|
|
23c1c9e875 | ||
|
|
2ee98e1e90 | ||
|
|
ff1a2e75e9 | ||
|
|
158924a223 | ||
|
|
28e8124947 | ||
|
|
be1c05ea31 | ||
|
|
dc217ca7a9 | ||
|
|
66cd0f1515 | ||
|
|
9e06e21b9d |
@@ -0,0 +1,2 @@
|
|||||||
|
/mvnw text eol=lf
|
||||||
|
*.cmd text eol=crlf
|
||||||
+25
-10
@@ -24,8 +24,17 @@ jobs:
|
|||||||
image: docker:24
|
image: docker:24
|
||||||
options: --network infra-infra-net
|
options: --network infra-infra-net
|
||||||
steps:
|
steps:
|
||||||
- name: 安装 git / curl(alpine)
|
# dl-cdn 在 CI 容器内被出口防火墙拒(apk 报 Permission denied,索引拉不下来即 curl no such package),
|
||||||
run: apk add --no-cache git curl
|
# 切国内镜像源安装;aliyun 不通再退 ustc,最后兜底官方源
|
||||||
|
- name: 安装 git / curl(alpine,国内镜像源)
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
for m in mirrors.aliyun.com mirrors.ustc.edu.cn dl-cdn.alpinelinux.org; do
|
||||||
|
sed -i "s#https://[^/]*#https://$m#" /etc/apk/repositories
|
||||||
|
echo ">> trying mirror: $m"
|
||||||
|
if apk add --no-cache git curl; then break; fi
|
||||||
|
done
|
||||||
|
git --version && curl --version | head -1
|
||||||
|
|
||||||
# 内网 Gitea 无法访问 GitHub 拉 actions/checkout,手动 clone 本仓库
|
# 内网 Gitea 无法访问 GitHub 拉 actions/checkout,手动 clone 本仓库
|
||||||
- name: 拉取源码(内网无 GitHub,手动 clone 本仓库)
|
- name: 拉取源码(内网无 GitHub,手动 clone 本仓库)
|
||||||
@@ -55,18 +64,24 @@ jobs:
|
|||||||
- name: 构建 jar(maven 容器,复用宿主 m2 缓存)
|
- name: 构建 jar(maven 容器,复用宿主 m2 缓存)
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
docker rm -f mavenbuild 2>/dev/null || true
|
# 构建容器名必须全局唯一:runner 挂的是宿主 docker.sock,容器名在整个 daemon 上共享
|
||||||
docker run -d --name mavenbuild \
|
# 命名空间。固定名会在多仓/多条 workflow 并发时互相 docker rm -f 掉对方正在构建的
|
||||||
|
# 容器,表现为无编译报错的 exit 137(SIGKILL,2026-10-21 实测复现)。
|
||||||
|
# GITHUB_RUN_ID 实例级唯一,再拼时间戳兜底。
|
||||||
|
BUILD_CONTAINER="mavenbuild-${GITHUB_RUN_ID:-0}-$(date +%s)"
|
||||||
|
echo "BUILD_CONTAINER=${BUILD_CONTAINER}"
|
||||||
|
docker rm -f "$BUILD_CONTAINER" 2>/dev/null || true
|
||||||
|
docker run -d --name "$BUILD_CONTAINER" \
|
||||||
--network infra-infra-net \
|
--network infra-infra-net \
|
||||||
-v /opt/docker/projman-m2:/root/.m2 \
|
-v /opt/docker/projman-m2:/root/.m2 \
|
||||||
-w /build maven:3.6.3-jdk-8 sleep 3600
|
-w /build maven:3.6.3-jdk-8 sleep 3600
|
||||||
docker cp "${PWD}/." mavenbuild:/build/
|
docker cp "${PWD}/." "$BUILD_CONTAINER":/build/
|
||||||
docker exec mavenbuild sh -c "printf '%s' '<settings><profiles><profile><id>nexus-repo</id><repositories><repository><id>nexus-internal</id><url>http://nexus:8081/repository/maven-public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled><updatePolicy>always</updatePolicy></snapshots></repository></repositories></profile></profiles><activeProfiles><activeProfile>nexus-repo</activeProfile></activeProfiles></settings>' > /root/.m2/settings.xml"
|
docker exec "$BUILD_CONTAINER" sh -c "printf '%s' '<settings><profiles><profile><id>nexus-repo</id><repositories><repository><id>nexus-internal</id><url>http://nexus:8081/repository/maven-public/</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled><updatePolicy>always</updatePolicy></snapshots></repository></repositories></profile></profiles><activeProfiles><activeProfile>nexus-repo</activeProfile></activeProfiles></settings>' > /root/.m2/settings.xml"
|
||||||
docker exec mavenbuild sh -c 'cd /build && mvn -B -DskipTests clean package'
|
docker exec "$BUILD_CONTAINER" sh -c 'cd /build && mvn -B -DskipTests clean package'
|
||||||
docker exec mavenbuild sh -c 'cd /build/target && cp *.jar app.jar'
|
docker exec "$BUILD_CONTAINER" sh -c 'cd /build/target && cp *.jar app.jar'
|
||||||
mkdir -p "${PWD}/target"
|
mkdir -p "${PWD}/target"
|
||||||
docker cp mavenbuild:/build/target/app.jar "${PWD}/target/app.jar"
|
docker cp "$BUILD_CONTAINER":/build/target/app.jar "${PWD}/target/app.jar"
|
||||||
docker rm -f mavenbuild
|
docker rm -f "$BUILD_CONTAINER"
|
||||||
|
|
||||||
- name: 构建并推送镜像
|
- name: 构建并推送镜像
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# 2026-08-12
|
||||||
|
|
||||||
|
## 项目:bschclassmanage(原 classicalchinese 重构)
|
||||||
|
|
||||||
|
### 包重命名(17:18 左右)
|
||||||
|
- 根包由 `com.bestsch.bschclassmanage` 重命名为 `com.yunhai.bschclassmanage`(git mv 目录 + 255 文件 package/import 替换,共 1064 处)。
|
||||||
|
- pom.xml 设 `<groupId>com.yunhai</groupId>` 对齐。
|
||||||
|
- 注意:`bschclassmanage.iml` 中的 `com.bestsch:bsch-*` 是外部依赖坐标(bsch-sso / bsch-spring-boot-starter 等),**不能改**。
|
||||||
|
- 环境无 maven(mvnw wrapper 缺 .mvn/wrapper 配置),无法本地编译验证;改用「package 声明 vs 目录路径」脚本校验,255 文件全部一致。
|
||||||
|
|
||||||
|
### 已修复的三类启动/路由问题
|
||||||
|
1. **CORS 启动失败**:Spring Boot 2.7.18 (Spring 5.3) 校验 `allowCredentials=true` 时 `allowedOrigins` 不能含 `*`。已将 23 个 Controller 的 `@CrossOrigin(origins={"*","*"}, allowCredentials="true")` 改为 `originPatterns={"*"}`。
|
||||||
|
2. **/api/* 与 /oapi/* 接口 404**:`Config.API_PATH="/api/"` 与 `Config.OAPI="/oapi/"` 常量尾部带斜杠,拼接 `API_PATH+"/subject/"` 产生 `/api//subject/`(双斜杠)。Spring Boot 2.7 默认 PathPatternParser 不折叠双斜杠导致匹配失败。已将常量尾斜杠去掉(`/api`、`/oapi`、`/mobiapi`)。`LoginUserController` 单独用 `Config.API_PATH` 无拼接故正常。
|
||||||
|
3. **currentrole 取不到(500/NPE)**:`UserSysRoleArgumentResolver` 原只从请求头 `currentrole` 取身份 JSON(childId/roleId/schId),URL 参数被忽略导致 `curRole` 为 null。已改为「Header 优先,查不到退回 URL 参数 currentrole」,便于本地调试,生产仍走 Header。
|
||||||
|
|
||||||
|
### Git
|
||||||
|
- 提交 `66cd0f1`:包重命名为 `com.yunhai.bschclassmanage`,含以上修复。
|
||||||
|
- 远程 origin 指向 `http://gitea.yunhaixingtong.com/wanghu/BSChClassManage.git`(原 classicalchinese 旧地址已替换)。
|
||||||
|
- 已 `git push -u origin master` 成功。本地仓库级身份:Allen <allen@yunhaixingtong.com>。
|
||||||
|
- 注意:gitea http push 需账号密码;URL 中 `&` 须编码为 `%26`。
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 2026-08-13
|
||||||
|
|
||||||
|
## 项目:bschclassmanage — UserContext 重构(去掉 authUserWithDept / curRole 参数)
|
||||||
|
|
||||||
|
### 目标
|
||||||
|
从所有 controller 方法签名中移除 `BoaUser authUserWithDept` 与 `UserSysRole curRole` 两个参数,身份改为通过 `UserContext` ThreadLocal 工具类获取。Service 层约定:「显式接收 `UserContext.UserInfo user` 参数」(沿用用户示例 `saveSchSub(UserContext.getCurrentUser(), model)`)。
|
||||||
|
|
||||||
|
### 改动清单(已落地)
|
||||||
|
- `utils/UserContext.java`:新增 `type` 字段(ThreadLocal<Integer> TYPE)+ `setType/getType`,`@Value UserInfo` 加 `Integer type`,`getCurrentUser()` 改 6 参构造,`setUserInfo()`/`clear()` 同步处理 TYPE。原因:`SchsystemController` 原用 `authUserWithDept.getType()` 做超管判断,无对应字段。
|
||||||
|
- 17 个 `controller/api/*Controller.java`:删除两个参数,调用处 getter 改为 `UserContext.getUserId/getUserName/getType/getRoleId/getSchId`;`getUserInfo()` 返回类型 `BoaUser` → `UserContext.UserInfo`;清理失效 `BoaUser`/`UserSysRole` import,补 `UserContext` import。由临时 Python 脚本批量转换。
|
||||||
|
- `aspect/ControllerUserContextAspect.java`:populate 逻辑补 `UserContext.setType(...)`;删除一处指向已删解析器的过时注释。
|
||||||
|
- `interceptor/UserContextInterceptor.java`:修正原 `UserContext.se(...)`(不存在)编译错误,改为 `setUserId/setUserName/setType`。
|
||||||
|
- `config/DWebMvcConfig.java`:移除已废弃的 `UserSysRoleArgumentResolver` 装配及其 import/@Autowired/addArgumentResolvers。
|
||||||
|
- 删除 `controller/Handler/UserSysRoleArgumentResolver.java`(仅被 DWebMvcConfig 与 aspect 注释引用)。
|
||||||
|
|
||||||
|
### 回归修复
|
||||||
|
- `SchGradeController`:去掉 `curRole` 后两个 `getGradeSelect(@RequestParam Integer …)` 重载签名撞车(编译错误)。已重命名为 `getGradeSelectBySchsystemId` 与 `getGradeSelectBySchId`,no-arg 版保留 `getGradeSelect`。
|
||||||
|
|
||||||
|
### 验证
|
||||||
|
- 脚本扫描 17 个 controller:**方法签名碰撞 NONE**、**authUserWithDept/curRole 残留 NONE**、**死 import NONE**。
|
||||||
|
- `pom.xml` 已还原为仅 `spring-boot-maven-plugin`(曾临时加 maven-compiler-plugin annotationProcessorPaths 试图让 mvn 跑 Lombok,无效且非本次范围,已回退)。
|
||||||
|
|
||||||
|
### 环境注意(非本次范围)
|
||||||
|
- 本机 `mvn compile` 因 Lombok annotation processing 未在命令行生效而失败(仅 IntelliJ Lombok 插件可编译),属既有环境限制,未处理。
|
||||||
|
- 临时文件 `C:\Users\Allen\refactor_usercontext.py` / `build*.log` / `verify_refactor.py` 因安全策略拦截未能自动清理,仍在用户 home 目录,待用户确认后删除。
|
||||||
|
|
||||||
|
### 线上 500(code 6 内部服务错误)根因与修复
|
||||||
|
- 现象:`POST http://192.168.10.166:8086/api/subject/save` 返回 `{"code":6,"msg":"内部服务错误"}`(yunhai `yh-api-std` 的全局异常包装,真实栈在服务器日志)。
|
||||||
|
- 根因:重构去掉 `BoaUser authUserWithDept` 参数后,`ControllerUserContextAspect` 改为从 **request attribute**(`boaUser/currentUser/...`)取身份,但框架 yunhai 从来不把 BoaUser 放进 request attribute。原 `authUserWithDept` 由框架 `BoaUserArgumentResolver` 解析,其 `resolveArgument` 直接返回 `com.yunhai.platform.auth.BoaUserContext.get()`(一个静态 ThreadLocal<BoaUser>,由框架 `PathBasedAuthInterceptor.preHandle` 每请求 `set`、afterCompletion `clear`)。
|
||||||
|
- 后果:`UserContext` 的 userId/type 拿不到 → `OtherUtil.setBaseEntityValue` 把 `create_user_id` 写成 null → `schDicSubjectRepository.save` 触发 NOT NULL 约束 → `DataIntegrityViolationException` → code 6。
|
||||||
|
- 修复:`ControllerUserContextAspect.setUserContext` 改为优先 `BoaUserContext.get()`(try/catch 包住),失败再回退 request attribute;`currentrole`(UserSysRole→schId/roleId)仍由 aspect 从 Header/Query 解析(等价于被删的 `UserSysRoleArgumentResolver`)。新增 import `com.yunhai.platform.auth.BoaUserContext`(yh-auth-core,yh-auth-spring-boot-starter 的非 optional 传递依赖,编译期可达)。
|
||||||
|
- 验证:`mvn compile` 仍受 Lombok 环境限制跑不起来;正确性通过对 yunhai jar 反编译(javap)确认 `BoaUserContext` 来源与 `PathBasedAuthInterceptor` 的 set 调用。临时解压目录 `C:\Users\Allen\_jarx`、`_jarx2` 为分析用,待清理。
|
||||||
|
- 若修复后该接口仍 500:下一步排查前端是否发送 `currentrole`(提供 schId);可由 `saveSchSub` 在 `user.getSchId()==null` 时抛明确 `IllegalArgumentException` 来定位。
|
||||||
|
|
||||||
|
### @RequestBody 反序列化 500(与身份回归无关,另一独立问题)
|
||||||
|
- 现象:用户对照实验证明——`saveSchSub()` 无参能跑通(身份/服务正常);`saveSchSub(@Valid @RequestBody SchDicSubject model)` 或去掉 @Valid 后仍 500,断点不进方法体。
|
||||||
|
- 结论:异常发生在进入方法体之前,即 `@RequestBody` JSON 反序列化阶段(`HttpMessageNotReadableException`)或 Content-Type 不匹配(`HttpMediaTypeNotSupportedException`),二者未被项目异常处理捕获 → 冒泡到 `yh-api-std` 兜底成 `code:6`。
|
||||||
|
- 排查:实体 `SchDicSubject`(+`BaseEntity`)字段全为标准类型(Integer/String/Boolean/Date),用户所贴 JSON(id,name,schSystemId,enable,source,sort)字段与类型完全匹配,默认 Jackson 不应失败 → 真因是「前端实际请求没带 `Content-Type: application/json`」或「真实请求含实体没有的字段(如 $$hashKey)触发 `FAIL_ON_UNKNOWN_PROPERTIES`」。
|
||||||
|
- `application.yml` 仅设 `spring.jackson.time-zone/date-format`,无 `fail-on-unknown-properties` → 默认 true。
|
||||||
|
- 修复(双保险):
|
||||||
|
1. `entity/SchDicSubject.java` 的 `@JsonIgnoreProperties` 加 `ignoreUnknown = true`(容忍前端多余字段)。
|
||||||
|
2. `ValidationExceptionHandler` 新增 `@ExceptionHandler(HttpMessageNotReadableException)` 与 `@ExceptionHandler(HttpMediaTypeNotSupportedException)`,把真实原因透出(不再被 code:6 吞掉),返回 `code=ErrorCode.ERROR`、`msg` 含具体原因。
|
||||||
|
- 验证手段:用 `curl -H "Content-Type: application/json" -d '{...}'` 直连;或部署后看返回 msg 是否直接点出「Content-Type 不被支持」/「JSON 解析失败: Unrecognized field ...」。
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# 2026-08-14
|
||||||
|
|
||||||
|
## UserContext schId 超管置 0
|
||||||
|
- 需求:全局设置 `UserContext.schId`,若用户 `TYPE=1`(超级管理员)则强制赋值 0(`UserType.SUPER_ADMINISTRATOR`)。
|
||||||
|
- 改动文件:`src/main/java/com/yunhai/bschclassmanage/aspect/ControllerUserContextAspect.java`
|
||||||
|
- `populateUserContext()` 末尾在 `setType` 后增加判断:超管则 `UserContext.setSchId(0)`,覆盖 currentrole 带入的 schId。
|
||||||
|
- 新增 import `com.yunhai.bschclassmanage.enums.UserType`。
|
||||||
|
- 说明:该 Aspect(@Order(1),覆盖所有 controller)是实际填充 schId 的位置;UserContextInterceptor 的 resolveUser 仍返回 null,未设置 schId。未能本地编译(无 mvn、wrapper 缺 properties)。
|
||||||
|
|
||||||
|
## ComSchTreeService:BaseTree → BoaGroup 迁移
|
||||||
|
- 需求:将 `ComSchTreeService` 中树模型由 `com.yunhai.bschclassmanage.model.tool.BaseTree` 换成平台 `com.yunhai.platform.utils.model.BoaGroup`。
|
||||||
|
- 改动文件:`service/com/ComSchTreeService.java`、`service/IComSchTreeService.java`、`controller/api/SchTreeController.java`、`service/impl/SchTeacherService.java`(toTeacherGroupSelect + 私有 flattenTree)。
|
||||||
|
- 字段映射要点:
|
||||||
|
- BoaGroup 无 `expand`/`code`/`order`;有 `parentId`/`sort`(Integer)。
|
||||||
|
- 删除教师树节点上的 `setExpand`/`setCode`;`setOrder(String)` → `setSort(teacher.getSort())`;`sortTreeNodes` 排序改为按 `getSort()`(Integer, nullsLast)。
|
||||||
|
- `SchSystemTreeVO` 的 `setExpand`/`setSort` 保持不变(那是年级/班级树,另一套模型)。
|
||||||
|
- 接口 `getGroupTree()` 原声明为 `BoaGroup`(与实现 `List<BoaGroup>` 不匹配),改为 `List<BoaGroup>`。
|
||||||
|
- 红缓存 `SCHOOL_TREE_{schId}` 读取端由 BaseTree 改为 BoaGroup 解析;写入端未在本次仓库内找到(疑似外部/平台写入),解析向后兼容(缺字段为 null,多余字段忽略)。
|
||||||
|
- 注意:`BaseTree.java` 现已无引用,可删除(本次未删)。`expand` 字段消失会影响前端教师树自动展开,需前端确认。
|
||||||
|
- 未能本地编译(无 JDK)。
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
## 根因
|
||||||
|
|
||||||
|
`TeainfoController.convertToTeaInfoVO`(TeainfoController.java:84-86)检查 `teacher.getGroupList()`,但它是一个 `@Transient` 字段,而 `getSchTeacherList` 查询链路(SchTeacherCacheService.java:36-44)只查 `sch_teacher` 本表、从不填充它。因此**每个教师都在第 86 行 `return null`**,`stream().map()` 不过滤 null,接口最终返回 `200 OK + [null, null, ...]`。`GetTeainfo` 和 `GetArrTeainfo` 共用同一转换方法,有一模一样的 bug。
|
||||||
|
|
||||||
|
## 修复方案
|
||||||
|
|
||||||
|
### 改动 1:TeainfoController.java(修复 null 元素)
|
||||||
|
|
||||||
|
1. **注入 `SchTeacherGroupRepository`**(新增 `@Autowired` 字段 + import:`SchTeacherGroupRepository`、`java.util.Map`、`java.util.Collections`、`java.util.Objects`)。
|
||||||
|
|
||||||
|
2. **新增私有方法 `fillGroupList(List<SchTeacher> teachers, Integer schId)`**:批量查询组关系并回填到每个教师的 `@Transient groupList` 字段,复用项目既有模式(SchTeacherService.java:96-98 的 `findByTeaIdIn` + `groupingBy`):
|
||||||
|
|
||||||
|
```java
|
||||||
|
private void fillGroupList(List<SchTeacher> teachers, Integer schId) {
|
||||||
|
if (teachers == null || teachers.isEmpty()) return;
|
||||||
|
List<Integer> teaIds = teachers.stream()
|
||||||
|
.map(SchTeacher::getTeaId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (teaIds.isEmpty()) return;
|
||||||
|
List<SchTeacherGroup> relations = (schId != null)
|
||||||
|
? schTeacherGroupRepository.findByTeaIdInAndSchId(teaIds, schId)
|
||||||
|
: schTeacherGroupRepository.findByTeaIdIn(teaIds);
|
||||||
|
Map<Integer, List<SchTeacherGroup>> groupMap = relations.stream()
|
||||||
|
.filter(g -> g.getTeaId() != null)
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherGroup::getTeaId));
|
||||||
|
teachers.forEach(t -> t.setGroupList(groupMap.getOrDefault(t.getTeaId(), Collections.emptyList())));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **三个接口调用处**:
|
||||||
|
- `getSchTeainfo`(:143-147):查询后调用 `fillGroupList(teachers, resolvedSchId)`(按学校过滤组关系,保证 GroupID/SchSerID 取的是本校分组),流上加 `.filter(Objects::nonNull)` 兜底。
|
||||||
|
- `getArrTeainfo`(:107-110):调用 `fillGroupList(teachers, null)`(无学校上下文,按教师ID查全部分组),流上加 `.filter(Objects::nonNull)`。
|
||||||
|
- `getTeainfo`(:52-55):`Optional.map` 内对单个教师调用 `fillGroupList(Collections.singletonList(teacher), null)`(Java 8,不用 `List.of`)。
|
||||||
|
|
||||||
|
### 改动 2:TeaInfoVO.java(锁定 JSON 键名)
|
||||||
|
|
||||||
|
每个字段加 `@JsonProperty("原始字段名")`(如 `@JsonProperty("SchSerID") private String SchSerID;`),与同包 SchInfoVO 的写法一致,确保输出键名为 `SchSerID`/`TeaIDCard`/`GroupID` 等原始大写形式,而不是 Jackson 默认推导的 `schSerID`/`teaIDCard`。新增 import `com.fasterxml.jackson.annotation.JsonProperty`。
|
||||||
|
|
||||||
|
## 保持现状(不在本次范围)
|
||||||
|
|
||||||
|
- `TeaNo` 映射的是 `sort` 排序号、其余 12 个字段(SchName、Photo 等)从不赋值恒为 null —— 属于字段映射契约问题,另行确认。
|
||||||
|
- `findTeaIdsBySchId` 不过滤 `transfer_status`(已转出教师也会出现在列表中)—— 与其他接口口径不一致,保持现状。
|
||||||
|
- 文件中历史遗留的乱码注释不动;新增代码 UTF-8 + CRLF 与文件一致。
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
- `mvn -q compile` 编译通过。
|
||||||
|
- 如有条件,本地起服务后请求 `/oapi/OATea/GetSchTeainfo?schId=xxx`,确认返回教师数组(元素为对象而非 null,且键名为原始大写形式)。
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
#
|
||||||
|
# Optional ENV vars
|
||||||
|
# -----------------
|
||||||
|
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
||||||
|
# MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
set -euf
|
||||||
|
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
||||||
|
|
||||||
|
# OS specific support.
|
||||||
|
native_path() { printf %s\\n "$1"; }
|
||||||
|
case "$(uname)" in
|
||||||
|
CYGWIN* | MINGW*)
|
||||||
|
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
||||||
|
native_path() { cygpath --path --windows "$1"; }
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# set JAVACMD and JAVACCMD
|
||||||
|
set_java_home() {
|
||||||
|
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
||||||
|
if [ -n "${JAVA_HOME-}" ]; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
JAVACCMD="$JAVA_HOME/bin/javac"
|
||||||
|
|
||||||
|
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
||||||
|
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
||||||
|
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v java
|
||||||
|
)" || :
|
||||||
|
JAVACCMD="$(
|
||||||
|
'set' +e
|
||||||
|
'unset' -f command 2>/dev/null
|
||||||
|
'command' -v javac
|
||||||
|
)" || :
|
||||||
|
|
||||||
|
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
||||||
|
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash string like Java String::hashCode
|
||||||
|
hash_string() {
|
||||||
|
str="${1:-}" h=0
|
||||||
|
while [ -n "$str" ]; do
|
||||||
|
char="${str%"${str#?}"}"
|
||||||
|
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
||||||
|
str="${str#?}"
|
||||||
|
done
|
||||||
|
printf %x\\n $h
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose() { :; }
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf %s\\n "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
# MWRAPPER-139:
|
||||||
|
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
||||||
|
# Needed for removing poorly interpreted newline sequences when running in more
|
||||||
|
# exotic environments such as mingw bash on Windows.
|
||||||
|
printf "%s" "${1}" | tr -d '[:space:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
while IFS="=" read -r key value; do
|
||||||
|
case "${key-}" in
|
||||||
|
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
||||||
|
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
||||||
|
esac
|
||||||
|
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
|
||||||
|
case "${distributionUrl##*/}" in
|
||||||
|
maven-mvnd-*bin.*)
|
||||||
|
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
||||||
|
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
||||||
|
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
||||||
|
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
||||||
|
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
||||||
|
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
||||||
|
*)
|
||||||
|
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
||||||
|
distributionPlatform=linux-amd64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
||||||
|
;;
|
||||||
|
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
||||||
|
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
distributionUrlNameMain="${distributionUrlName%.*}"
|
||||||
|
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
||||||
|
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
||||||
|
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
||||||
|
|
||||||
|
exec_maven() {
|
||||||
|
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
||||||
|
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -d "$MAVEN_HOME" ]; then
|
||||||
|
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
exec_maven "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "${distributionUrl-}" in
|
||||||
|
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
||||||
|
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
||||||
|
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
||||||
|
trap clean HUP INT TERM EXIT
|
||||||
|
else
|
||||||
|
die "cannot create temp dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p -- "${MAVEN_HOME%/*}"
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
verbose "Downloading from: $distributionUrl"
|
||||||
|
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
# select .zip or .tar.gz
|
||||||
|
if ! command -v unzip >/dev/null; then
|
||||||
|
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
||||||
|
distributionUrlName="${distributionUrl##*/}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# verbose opt
|
||||||
|
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
||||||
|
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
||||||
|
|
||||||
|
# normalize http auth
|
||||||
|
case "${MVNW_PASSWORD:+has-password}" in
|
||||||
|
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
||||||
|
verbose "Found wget ... using wget"
|
||||||
|
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
||||||
|
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
||||||
|
verbose "Found curl ... using curl"
|
||||||
|
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
||||||
|
elif set_java_home; then
|
||||||
|
verbose "Falling back to use Java to download"
|
||||||
|
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
||||||
|
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
cat >"$javaSource" <<-END
|
||||||
|
public class Downloader extends java.net.Authenticator
|
||||||
|
{
|
||||||
|
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
||||||
|
{
|
||||||
|
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
||||||
|
}
|
||||||
|
public static void main( String[] args ) throws Exception
|
||||||
|
{
|
||||||
|
setDefault( new Downloader() );
|
||||||
|
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END
|
||||||
|
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
||||||
|
verbose " - Compiling Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
||||||
|
verbose " - Running Downloader.java ..."
|
||||||
|
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
if [ -n "${distributionSha256Sum-}" ]; then
|
||||||
|
distributionSha256Result=false
|
||||||
|
if [ "$MVN_CMD" = mvnd.sh ]; then
|
||||||
|
echo "Checksum validation is not supported for maven-mvnd." >&2
|
||||||
|
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
elif command -v sha256sum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
elif command -v shasum >/dev/null; then
|
||||||
|
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
||||||
|
distributionSha256Result=true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
||||||
|
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ $distributionSha256Result = false ]; then
|
||||||
|
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
||||||
|
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
if command -v unzip >/dev/null; then
|
||||||
|
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
||||||
|
else
|
||||||
|
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
||||||
|
fi
|
||||||
|
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
||||||
|
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
||||||
|
|
||||||
|
clean || :
|
||||||
|
exec_maven "$@"
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<# : batch portion
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
@REM or more contributor license agreements. See the NOTICE file
|
||||||
|
@REM distributed with this work for additional information
|
||||||
|
@REM regarding copyright ownership. The ASF licenses this file
|
||||||
|
@REM to you under the Apache License, Version 2.0 (the
|
||||||
|
@REM "License"); you may not use this file except in compliance
|
||||||
|
@REM with the License. You may obtain a copy of the License at
|
||||||
|
@REM
|
||||||
|
@REM http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@REM
|
||||||
|
@REM Unless required by applicable law or agreed to in writing,
|
||||||
|
@REM software distributed under the License is distributed on an
|
||||||
|
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
@REM KIND, either express or implied. See the License for the
|
||||||
|
@REM specific language governing permissions and limitations
|
||||||
|
@REM under the License.
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
||||||
|
@REM
|
||||||
|
@REM Optional ENV vars
|
||||||
|
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
||||||
|
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
||||||
|
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
||||||
|
@REM ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
||||||
|
@SET __MVNW_CMD__=
|
||||||
|
@SET __MVNW_ERROR__=
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
||||||
|
@SET PSModulePath=
|
||||||
|
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
||||||
|
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
||||||
|
)
|
||||||
|
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
||||||
|
@SET __MVNW_PSMODULEP_SAVE=
|
||||||
|
@SET __MVNW_ARG0_NAME__=
|
||||||
|
@SET MVNW_USERNAME=
|
||||||
|
@SET MVNW_PASSWORD=
|
||||||
|
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
||||||
|
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
||||||
|
@GOTO :EOF
|
||||||
|
: end batch / begin powershell #>
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
if ($env:MVNW_VERBOSE -eq "true") {
|
||||||
|
$VerbosePreference = "Continue"
|
||||||
|
}
|
||||||
|
|
||||||
|
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
||||||
|
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
||||||
|
if (!$distributionUrl) {
|
||||||
|
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
||||||
|
"maven-mvnd-*" {
|
||||||
|
$USE_MVND = $true
|
||||||
|
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
||||||
|
$MVN_CMD = "mvnd.cmd"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
$USE_MVND = $false
|
||||||
|
$MVN_CMD = $script -replace '^mvnw','mvn'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
||||||
|
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
||||||
|
if ($env:MVNW_REPOURL) {
|
||||||
|
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
||||||
|
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
||||||
|
}
|
||||||
|
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
||||||
|
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
||||||
|
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
if ($env:MAVEN_USER_HOME) {
|
||||||
|
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
||||||
|
}
|
||||||
|
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
||||||
|
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
||||||
|
|
||||||
|
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
||||||
|
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
|
exit $?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
||||||
|
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare tmp dir
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
||||||
|
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
||||||
|
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
||||||
|
trap {
|
||||||
|
if ($TMP_DOWNLOAD_DIR.Exists) {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
||||||
|
|
||||||
|
# Download and Install Apache Maven
|
||||||
|
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
||||||
|
Write-Verbose "Downloading from: $distributionUrl"
|
||||||
|
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
||||||
|
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
||||||
|
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
||||||
|
}
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
||||||
|
|
||||||
|
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
||||||
|
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
||||||
|
if ($distributionSha256Sum) {
|
||||||
|
if ($USE_MVND) {
|
||||||
|
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
||||||
|
}
|
||||||
|
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
||||||
|
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
||||||
|
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unzip and move
|
||||||
|
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
||||||
|
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
||||||
|
try {
|
||||||
|
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
||||||
|
} catch {
|
||||||
|
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
||||||
|
Write-Error "fail to move MAVEN_HOME"
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
||||||
|
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<!-- <version>2.2.4.RELEASE</version>-->
|
||||||
|
<version>2.7.18</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>com.yunhai</groupId>
|
||||||
|
<!-- <groupId>com.bestsch.previewUnit</groupId>-->
|
||||||
|
<artifactId>BschClass</artifactId>
|
||||||
|
<version>0.1</version>
|
||||||
|
<name>BschClass</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<tomcat.version>9.0.63</tomcat.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>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 显式引入 JDBC(提供 JdbcTemplate,用于 backupAllSnapshot 的批量快照插入) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 健康检查:projman 平台探活/compose healthcheck 默认探 {contextPath}/actuator/health -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.36</version> <!-- 加上这行 -->
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>mysql</groupId>-->
|
||||||
|
<!-- <artifactId>mysql-connector-java</artifactId>-->
|
||||||
|
<!-- <scope>runtime</scope>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>8.0.33</version> <!-- 明确指定版本 -->
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!--bsch-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>com.bestsch</groupId>-->
|
||||||
|
<!-- <artifactId>bsch-spring-boot-starter</artifactId>-->
|
||||||
|
<!-- <version>1.2.5-SNAPSHOT</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>5.0.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.validator</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
<version>6.2.0.Final</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish</groupId>
|
||||||
|
<artifactId>jakarta.el</artifactId>
|
||||||
|
<version>3.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 对象转换工具-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.modelmapper</groupId>
|
||||||
|
<artifactId>modelmapper</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- fastjson-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.80</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.coobird</groupId>
|
||||||
|
<artifactId>thumbnailator</artifactId>
|
||||||
|
<version>0.4.20</version> <!-- 检查最新版本 -->
|
||||||
|
</dependency>
|
||||||
|
<!--post-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.13</version> <!-- 使用最新的稳定版本 -->
|
||||||
|
</dependency>
|
||||||
|
<!-- CommonMark-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.commonmark</groupId>
|
||||||
|
<artifactId>commonmark</artifactId>
|
||||||
|
<version>0.21.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>16.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20210307</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>3.14.9</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Apache POI -->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.afterturn</groupId>
|
||||||
|
<artifactId>easypoi-base</artifactId>
|
||||||
|
<version>4.1.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-aop</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringDoc OpenAPI UI:为 Spring Boot 2.7 提供 OpenAPI 文档和 Swagger UI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springdoc</groupId>
|
||||||
|
<artifactId>springdoc-openapi-ui</artifactId>
|
||||||
|
<version>1.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- easypoi style -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.afterturn</groupId>
|
||||||
|
<artifactId>easypoi-spring-boot-starter</artifactId>
|
||||||
|
<version>4.2.0</version> <!-- 或其他稳定版本,如 4.1.0、4.2.0 -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 基础平台架包:认证(CAS/会话/SSO)+ 应用间签名鉴权 + 用户中心静态门面 + 统一响应 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-auth-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-app-auth-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-openapi-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- openapi 依赖必须成套:starter 与 client 的 SNAPSHOT 需来自平台同一次发布批次(当前批次 20260820.011053:
|
||||||
|
starter-21 调 3 参构造器,client-31 提供之;且 YschBaseOpenApi 仅存在于新 client)。
|
||||||
|
版本由 yh-platform-dependencies BOM 统一管理,无需手工锁版本;构建用 mvn -U 刷新快照。 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-api-std</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 前端运行时配置端点 GET /api/env-config(免登录,starter 自带 SSO 旁路过滤器):
|
||||||
|
数据源默认 FileEnvConfigSource 读 /app/config/env-config-{target}.json(projman 逐文件 bind mount)。
|
||||||
|
注意本端不在聚合包上,聚合里的 env-config 不会传递进来,必须显式引入 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-env-config-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<!-- 外观偏好同源读端点 GET /api/appearance(三态 proxy/local/off,默认 proxy 经 YschOpenCall
|
||||||
|
代理 UserHome /oapi/appearance)。平台件刻意不进聚合包(防本地同名控制器双注册),必须显式引入。
|
||||||
|
生效条件=@ConditionalOnBean(YschOpenCall),本端 yh.open.base-host 已配即满足 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.yunhai.platform</groupId>
|
||||||
|
<artifactId>yh-appearance-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>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<!-- 显式声明 Lombok 为注解处理器:避免 'mvn package' 时 Lombok 未运行,
|
||||||
|
导致全工程 @Getter/@Setter/@AllArgsConstructor/@Slf4j 等生成的
|
||||||
|
方法/字段全部“找不到符号”(IDEA 自带 Lombok 插件不报此问题)。 -->
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.36</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</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。
|
||||||
|
-->
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,500 @@
|
|||||||
|
/*
|
||||||
|
Navicat Premium Data Transfer
|
||||||
|
|
||||||
|
Source Server : 本地
|
||||||
|
Source Server Type : MySQL
|
||||||
|
Source Server Version : 80044
|
||||||
|
Source Host : localhost:3306
|
||||||
|
Source Schema : dbschoolclass
|
||||||
|
|
||||||
|
Target Server Type : MySQL
|
||||||
|
Target Server Version : 80044
|
||||||
|
File Encoding : 65001
|
||||||
|
|
||||||
|
Date: 17/06/2026 10:30:52
|
||||||
|
*/
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for base_dic_grade
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `base_dic_grade`;
|
||||||
|
CREATE TABLE `base_dic_grade` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`code` int(0) NULL DEFAULT NULL COMMENT '年级编码',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '年级名称',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of base_dic_grade
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (1, 1, '一年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (2, 2, '二年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (3, 3, '三年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (4, 4, '四年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (5, 5, '五年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (6, 6, '六年级');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (7, 7, '初一');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (8, 8, '初二');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (9, 9, '初三');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (10, 10, '高一');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (11, 11, '高二');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (12, 12, '高三');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (13, -4, '幼托');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (14, -3, '幼小');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (15, -2, '幼中');
|
||||||
|
INSERT INTO `base_dic_grade` VALUES (16, -1, '幼大');
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for base_dic_subject
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `base_dic_subject`;
|
||||||
|
CREATE TABLE `base_dic_subject` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编码',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名称',
|
||||||
|
`sort` int(0) NULL DEFAULT NULL COMMENT '序号',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of base_dic_subject
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (1, 'SUB01', '语文', 1);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (2, 'SUB02', '数学', 2);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (3, 'SUB03', '英语', 3);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (4, 'SUB04', '物理', 4);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (5, 'SUB05', '化学', 5);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (6, 'SUB06', '生物', 6);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (7, 'SUB07', '历史', 7);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (8, 'SUB08', '地理', 8);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (9, 'SUB09', '政治', 9);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (10, 'SUB10', '艺术', 10);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (11, 'SUB11', '体育', 11);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (12, 'SUB12', '心理', 12);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (13, 'SUB13', '信息', 13);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (14, 'SUB14', '劳技', 14);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (15, 'SUB15', '跨学科', 15);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (16, 'SUB16', '美术', 16);
|
||||||
|
INSERT INTO `base_dic_subject` VALUES (17, 'SUB17', '音乐', 17);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for base_sch_system
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `base_sch_system`;
|
||||||
|
CREATE TABLE `base_sch_system` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '名称 ',
|
||||||
|
`academic_stage` int(0) NULL DEFAULT NULL COMMENT '学段(0学前 1小学 2初中 3高中 4高等)',
|
||||||
|
`start_grade_code` int(0) NULL DEFAULT NULL COMMENT '开班年级编码',
|
||||||
|
`end_grade_code` int(0) NULL DEFAULT NULL COMMENT '毕业年级编码',
|
||||||
|
`graduation_leng` int(0) NULL DEFAULT NULL COMMENT '毕业年长度',
|
||||||
|
`type` int(0) NULL DEFAULT NULL COMMENT '类型(1学前教育 2职业教育)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of base_sch_system
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `base_sch_system` VALUES (1, '学前教育', 0, -3, -1, 3, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (2, '学前4年', 0, -4, -1, 4, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (3, '小学六年', 1, 1, 6, 6, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (4, '小学五年', 1, 1, 5, 5, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (5, '初中三年', 2, 7, 9, 3, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (6, '初中四年', 2, 6, 9, 4, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (7, '九年一贯制', 2, 1, 9, 9, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (8, '高中三年', 3, 10, 12, 3, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (9, '初高中七年制', 3, 6, 12, 7, 1);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (10, '职高', 3, 0, 0, 3, 2);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (11, '\r\n专科三年制', 4, 0, 0, 3, 2);
|
||||||
|
INSERT INTO `base_sch_system` VALUES (12, '\r\n专科五年制', 4, 0, 0, 5, 2);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for base_sch_system_grade
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `base_sch_system_grade`;
|
||||||
|
CREATE TABLE `base_sch_system_grade` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`grade_id` int(0) NULL DEFAULT NULL COMMENT '年级id',
|
||||||
|
`grade_nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '年级别名',
|
||||||
|
`sch_system_id` int(0) NULL DEFAULT NULL COMMENT '学制id',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 44 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of base_sch_system_grade
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (1, -3, '幼小', 1);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (2, -2, '幼中', 1);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (3, -1, '幼大', 1);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (4, -4, '幼托', 2);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (5, -3, '幼小', 2);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (6, -2, '幼中', 2);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (7, -1, '幼大', 2);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (8, 1, '小一', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (9, 2, '小二', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (10, 3, '小三', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (11, 4, '小四', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (12, 5, '小五', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (13, 6, '小六', 3);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (14, 1, '小一', 4);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (15, 2, '小二', 4);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (16, 3, '小三', 4);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (17, 4, '小四', 4);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (18, 5, '小五', 4);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (19, 7, '初一', 5);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (20, 8, '初二', 5);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (21, 9, '初三', 5);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (22, 6, '预备', 6);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (23, 7, '初一', 6);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (24, 8, '初二', 6);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (25, 9, '初三', 6);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (26, 1, '小一', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (27, 2, '小二', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (28, 3, '小三', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (29, 4, '小四', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (30, 5, '小五', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (31, 6, '小六', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (32, 7, '初一', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (33, 8, '初二', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (34, 9, '初三', 7);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (35, 10, '高一', 8);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (36, 11, '高二', 8);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (37, 12, '高三', 8);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (38, 6, '预备', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (39, 7, '初一', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (40, 8, '初二', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (41, 9, '初三', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (42, 10, '高一', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (43, 11, '高二', 9);
|
||||||
|
INSERT INTO `base_sch_system_grade` VALUES (44, 12, '高三', 9);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for base_year_term
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `base_year_term`;
|
||||||
|
CREATE TABLE `base_year_term` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`year` int(0) NULL DEFAULT NULL COMMENT '学年',
|
||||||
|
`year_start_date` date NULL DEFAULT NULL COMMENT '学年开始日期',
|
||||||
|
`year_end_date` date NULL DEFAULT NULL COMMENT '学年结束日期',
|
||||||
|
`first_term_start_date` date NULL DEFAULT NULL COMMENT '第一学期开始日期',
|
||||||
|
`first_term_end_date` date NULL DEFAULT NULL COMMENT '第一学期结束日期',
|
||||||
|
`second_term_start_date` date NOT NULL COMMENT '第二学期开始日期',
|
||||||
|
`second_term_end_date` date NULL DEFAULT NULL COMMENT '第二学期结束日期',
|
||||||
|
`upgrade_date` date NULL DEFAULT NULL COMMENT '毕业时间',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`, `second_term_start_date`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of base_year_term
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `base_year_term` VALUES (1, 2025, '2025-09-01', '2026-07-10', '2025-09-01', '2026-01-15', '2026-02-20', '2026-07-05', '2026-07-15', '2026-06-15 10:11:06', NULL, 100000, NULL);
|
||||||
|
INSERT INTO `base_year_term` VALUES (2, 2024, '2024-09-01', '2025-07-10', '2024-09-01', '2025-01-15', '2025-02-20', '2025-07-05', '2025-07-15', '2026-06-15 10:19:53', NULL, 100000, NULL);
|
||||||
|
INSERT INTO `base_year_term` VALUES (3, 2023, '2023-09-01', '2024-07-10', '2023-09-01', '2024-01-15', '2024-02-20', '2024-07-05', '2024-07-15', '2026-06-15 10:20:58', NULL, 100000, NULL);
|
||||||
|
INSERT INTO `base_year_term` VALUES (4, 2022, '2022-09-01', '2023-07-10', '2022-09-01', '2023-01-15', '2023-02-20', '2023-07-05', '2023-07-15', '2026-06-15 10:21:51', NULL, 100000, NULL);
|
||||||
|
INSERT INTO `base_year_term` VALUES (5, 2021, '2021-09-01', '2022-07-10', '2021-09-01', '2022-01-15', '2022-02-20', '2022-07-05', '2022-07-15', '2026-06-15 10:22:00', NULL, 100000, NULL);
|
||||||
|
INSERT INTO `base_year_term` VALUES (6, 2020, '2020-09-01', '2021-07-10', '2020-09-01', '2021-01-15', '2021-02-20', '2021-07-05', '2021-07-15', '2026-06-15 10:23:22', NULL, 100000, NULL);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_bin_sch_system
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_bin_sch_system`;
|
||||||
|
CREATE TABLE `sch_bin_sch_system` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT,
|
||||||
|
`sch_system_id` int(0) NOT NULL COMMENT '学制id',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_bin_sch_system
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_bin_sch_system` VALUES (5, 6, 3260, '2026-06-11 15:21:34', 100000, '2026-06-11 15:21:34', 100000);
|
||||||
|
INSERT INTO `sch_bin_sch_system` VALUES (6, 8, 3260, '2026-06-11 15:21:34', 100000, '2026-06-11 15:21:34', 100000);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_class
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_class`;
|
||||||
|
CREATE TABLE `sch_class` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`code` int(10) UNSIGNED ZEROFILL NULL DEFAULT NULL COMMENT '编码',
|
||||||
|
`grade_id` int(0) NULL DEFAULT NULL COMMENT '年级id',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '名称',
|
||||||
|
`cname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '别称',
|
||||||
|
`group_class_id` int(0) UNSIGNED NOT NULL COMMENT '班级组id',
|
||||||
|
`group_grade_id` int(0) NOT NULL COMMENT '年级组id',
|
||||||
|
`first_teacher_id` int(0) NULL DEFAULT NULL COMMENT '班主任',
|
||||||
|
`second_teacher_id` int(0) NULL DEFAULT NULL COMMENT '副班主任',
|
||||||
|
`campus_id` int(0) NULL DEFAULT NULL COMMENT '校区',
|
||||||
|
`division_id` int(0) NULL DEFAULT NULL COMMENT '系部',
|
||||||
|
`majors_id` int(0) NULL DEFAULT NULL COMMENT '专业',
|
||||||
|
`graduate` bit(1) NULL DEFAULT NULL COMMENT '毕业',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_class_teach
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_class_teach`;
|
||||||
|
CREATE TABLE `sch_class_teach` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`grade_id` int(0) NULL DEFAULT NULL COMMENT '年级id',
|
||||||
|
`class_id` int(0) NULL DEFAULT NULL COMMENT '班级id',
|
||||||
|
`sub_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '学科id',
|
||||||
|
`tea_id` int(0) NULL DEFAULT NULL COMMENT '教师id',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_campus
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_campus`;
|
||||||
|
CREATE TABLE `sch_dic_campus` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '校区',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`sort` int(0) NULL DEFAULT NULL COMMENT '序号',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '编辑日期',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '编辑用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_campus
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_campus` VALUES (1, '新渔区', 3260, 2, '2026-06-16 10:06:49', 209169, '2026-06-16 10:10:47', 209169);
|
||||||
|
INSERT INTO `sch_dic_campus` VALUES (2, '名宿区', 3260, 1, '2026-06-16 10:08:08', 209169, '2026-06-16 10:10:47', 209169);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_course
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_course`;
|
||||||
|
CREATE TABLE `sch_dic_course` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编码',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '课程名称',
|
||||||
|
`nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '别名',
|
||||||
|
`type` int(0) NULL DEFAULT NULL COMMENT '类型(1基础课程 2选修课程 3专业课程)',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_course
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_course` VALUES (1, 'MATH101', '高等数学', '高数', 3, 3260, '2026-06-16 22:11:35', '2026-06-17 00:40:54', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_course` VALUES (2, 'MATH102', '就业指导', NULL, 1, 3260, '2026-06-16 22:29:21', '2026-06-17 00:39:55', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_course` VALUES (3, 'MATH103', '中餐冷菜制作', NULL, 2, 3260, '2026-06-16 22:30:02', '2026-06-17 00:39:15', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_course` VALUES (4, NULL, '计算机应用基础', NULL, 1, 3260, '2026-06-16 22:30:17', '2026-06-16 22:30:17', 209169, 209169);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_course_division
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_course_division`;
|
||||||
|
CREATE TABLE `sch_dic_course_division` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT,
|
||||||
|
`course_id` int(0) NULL DEFAULT NULL,
|
||||||
|
`division_id` int(0) NULL DEFAULT NULL,
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_course_division
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (3, 3, 5, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (4, 3, 6, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (5, 2, 3, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (6, 2, 4, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (9, 1, 1, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_division` VALUES (10, 1, 2, 3260);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_course_majors
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_course_majors`;
|
||||||
|
CREATE TABLE `sch_dic_course_majors` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT,
|
||||||
|
`course_id` int(0) NULL DEFAULT NULL,
|
||||||
|
`majors_id` int(0) NULL DEFAULT NULL,
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_course_majors
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_course_majors` VALUES (2, 3, 4, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_majors` VALUES (3, 2, 2, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_majors` VALUES (6, 1, 1, 3260);
|
||||||
|
INSERT INTO `sch_dic_course_majors` VALUES (7, 1, 5, 3260);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_division
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_division`;
|
||||||
|
CREATE TABLE `sch_dic_division` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '系部',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`sort` int(0) NULL DEFAULT NULL COMMENT '序号',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_division
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (1, '中文系', 3260, 6, '2026-06-16 10:33:45', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (2, '历史系', 3260, 5, '2026-06-16 10:34:02', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (3, '外国语学院', 3260, 4, '2026-06-16 10:34:23', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (4, '新闻传播学院', 3260, 3, '2026-06-16 10:34:32', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (5, '哲学系', 3260, 2, '2026-06-16 10:34:41', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
INSERT INTO `sch_dic_division` VALUES (6, '经济学院', 3260, 1, '2026-06-16 10:34:49', 209169, '2026-06-16 10:41:12', 209169);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_majors
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_majors`;
|
||||||
|
CREATE TABLE `sch_dic_majors` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '专业 ',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`sort` int(0) NULL DEFAULT NULL COMMENT '序号',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_majors
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (1, '哲学', 3260, 7, '2026-06-16 16:23:06', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (2, '逻辑学', 3260, 6, '2026-06-16 16:23:31', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (3, '宗教学', 3260, 5, '2026-06-16 16:23:44', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (4, '经济学', 3260, 4, '2026-06-16 16:23:59', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (5, '经济统计学', 3260, 3, '2026-06-16 16:24:12', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (6, '法学', 3260, 2, '2026-06-16 16:24:24', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
INSERT INTO `sch_dic_majors` VALUES (7, '新闻学', 3260, 1, '2026-06-16 16:24:38', '2026-06-16 16:25:13', 209169, 209169);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_dic_subject
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_dic_subject`;
|
||||||
|
CREATE TABLE `sch_dic_subject` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编码',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '学科',
|
||||||
|
`enable` bit(1) NULL DEFAULT NULL COMMENT '是否启用',
|
||||||
|
`sort` int(0) NULL DEFAULT NULL COMMENT '序号',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改日期',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
`source` int(0) NULL DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 42 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of sch_dic_subject
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (5, 'SUB1001', '机器人', b'1', 1, 3260, '2026-06-15 18:00:05', '2026-06-15 22:23:27', 209169, 209169, 1);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (6, 'SUB1002', 'AI', b'1', 2, 3260, '2026-06-15 18:50:10', '2026-06-15 22:22:41', 209169, 209169, 1);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (7, 'SUB01', '语文', b'0', 3, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (26, 'SUB02', '数学', b'0', 4, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (27, 'SUB03', '英语', b'0', 5, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (28, 'SUB04', '物理', b'0', 6, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (29, 'SUB05', '化学', b'0', 7, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (30, 'SUB06', '生物', b'0', 8, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (31, 'SUB07', '历史', b'0', 9, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (32, 'SUB08', '地理', b'0', 10, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (33, 'SUB09', '政治', b'0', 11, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (34, 'SUB10', '艺术', b'0', 12, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (35, 'SUB11', '体育', b'0', 13, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (36, 'SUB12', '心理', b'0', 14, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (37, 'SUB13', '信息', b'0', 15, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (38, 'SUB14', '劳技', b'0', 16, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (39, 'SUB15', '跨学科', b'0', 17, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (40, 'SUB16', '美术', b'0', 18, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
INSERT INTO `sch_dic_subject` VALUES (41, 'SUB17', '音乐', b'0', 19, 3260, '2026-06-15 22:04:42', '2026-06-15 22:22:41', 209169, 209169, 0);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_student
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_student`;
|
||||||
|
CREATE TABLE `sch_student` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '账户',
|
||||||
|
`group_id` int(0) NULL DEFAULT NULL COMMENT '组id',
|
||||||
|
`class_id` int(0) NULL DEFAULT NULL COMMENT '班级id',
|
||||||
|
`stu_id` int(0) NOT NULL COMMENT '学生id',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '学生',
|
||||||
|
`gender` int(0) NULL DEFAULT NULL COMMENT '性别',
|
||||||
|
`status` int(0) NULL DEFAULT NULL COMMENT '状态',
|
||||||
|
`abnormal_status` int(0) NULL DEFAULT NULL COMMENT '异常状态',
|
||||||
|
`invitation_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邀请码',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for sch_teacher
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `sch_teacher`;
|
||||||
|
CREATE TABLE `sch_teacher` (
|
||||||
|
`id` int(0) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
|
`account` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '账户',
|
||||||
|
`group_id` int(0) NULL DEFAULT NULL COMMENT '组id',
|
||||||
|
`tea_id` int(0) NOT NULL COMMENT '教师id',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '教师',
|
||||||
|
`tel` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '联系电话',
|
||||||
|
`gender` int(0) NULL DEFAULT NULL COMMENT '性别 0女 1男',
|
||||||
|
`status` int(0) NULL DEFAULT NULL COMMENT '状态 (0 禁用 1正常)',
|
||||||
|
`sch_id` int(0) NULL DEFAULT NULL COMMENT '学校id',
|
||||||
|
`create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_date` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
|
||||||
|
`create_user_id` int(0) NULL DEFAULT NULL COMMENT '创建用户',
|
||||||
|
`update_user_id` int(0) NULL DEFAULT NULL COMMENT '修改用户',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
-- 系统审计日志表(双轨之审计轨,与业务日志表 operation_log 物理隔离)
|
||||||
|
CREATE TABLE `sys_operation_log` (
|
||||||
|
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||||
|
`log_level` TINYINT NOT NULL COMMENT '1-重要(删除) 2-次要(新增/编辑) 3-一般(查询)',
|
||||||
|
`operation_type` VARCHAR(16) NOT NULL COMMENT 'DELETE/CREATE/UPDATE/QUERY',
|
||||||
|
`user_id` INT DEFAULT NULL COMMENT '操作人ID(来自UserContext)',
|
||||||
|
`user_name` VARCHAR(64) DEFAULT NULL COMMENT '操作人姓名(来自UserContext)',
|
||||||
|
`sch_id` INT DEFAULT NULL COMMENT '学校ID(多校隔离)',
|
||||||
|
`request_ip` VARCHAR(64) NOT NULL COMMENT '客户端IP',
|
||||||
|
`request_uri` VARCHAR(512) NOT NULL COMMENT '请求URI',
|
||||||
|
`request_method` VARCHAR(16) NOT NULL COMMENT 'HTTP方法',
|
||||||
|
`class_method` VARCHAR(512) NOT NULL COMMENT '类名.方法名',
|
||||||
|
`request_params` TEXT COMMENT '请求参数(脱敏后)',
|
||||||
|
`response_data` MEDIUMBLOB COMMENT 'GZIP压缩后的响应JSON',
|
||||||
|
`status_code` INT NOT NULL COMMENT '业务状态码 0成功 非0失败',
|
||||||
|
`cost_time` BIGINT NOT NULL COMMENT '耗时ms',
|
||||||
|
`user_agent` VARCHAR(512) DEFAULT NULL,
|
||||||
|
`error_msg` TEXT COMMENT '异常信息(截断2000)',
|
||||||
|
`retry_count` INT DEFAULT 0 COMMENT '重试次数',
|
||||||
|
`last_retry_status` TINYINT DEFAULT NULL COMMENT '上次重试状态: 1 成功 / 0 失败',
|
||||||
|
`last_retry_time` DATETIME(3) DEFAULT NULL COMMENT '上次重试时间',
|
||||||
|
`create_time` DATETIME(3) NOT NULL COMMENT '记录时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_sol_create_time` (`create_time`),
|
||||||
|
KEY `idx_sol_user_time` (`user_id`, `create_time`),
|
||||||
|
KEY `idx_sol_sch_time` (`sch_id`, `create_time`),
|
||||||
|
KEY `idx_sol_uri_time` (`request_uri`, `create_time`),
|
||||||
|
KEY `idx_sol_level_time` (`log_level`, `create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统审计日志(HTTP接口级,全量记录)';
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE `dbschoolclass`.`sch_dic_campus`
|
||||||
|
ADD COLUMN `create_date` datetime(0) NULL COMMENT '创建时间' AFTER `sch_id`,
|
||||||
|
ADD COLUMN `update_date` datetime(0) NULL COMMENT '修改时间' AFTER `create_date`,
|
||||||
|
ADD COLUMN `create_user_id` int(0) NULL COMMENT '创建用户' AFTER `update_date`,
|
||||||
|
ADD COLUMN `update_user_id` int(0) NULL COMMENT '修改用户' AFTER `create_user_id`;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.yunhai.bschclassmanage;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@EnableAsync
|
||||||
|
@EnableScheduling
|
||||||
|
public class ClassicalchineseApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(ClassicalchineseApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseDicGrade;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface BaseDicGradeRepository extends JpaRepository<BaseDicGrade, Integer>, JpaSpecificationExecutor<BaseDicGrade> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseDicSubject;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface BaseDicSubjectRepository extends JpaRepository<BaseDicSubject, Integer>, JpaSpecificationExecutor<BaseDicSubject> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseSchsystemGrade;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface BaseSchsystemGradeRepository extends JpaRepository<BaseSchsystemGrade, Integer>, JpaSpecificationExecutor<BaseSchsystemGrade> {
|
||||||
|
|
||||||
|
List<BaseSchsystemGrade> findBySchSystemId(Integer schSystemId);
|
||||||
|
|
||||||
|
List<BaseSchsystemGrade> findBySchSystemIdIn(List<Integer> schSystemIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseSchsystem;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface BaseSchsystemRepository extends JpaRepository<BaseSchsystem, Integer>, JpaSpecificationExecutor<BaseSchsystem> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseYearTerm;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface BaseYearTermRepository extends JpaRepository<BaseYearTerm, Integer>, JpaSpecificationExecutor<BaseYearTerm> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.OperationLogRecord;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface OperationLogRecordRepository extends JpaRepository<OperationLogRecord, Integer>, JpaSpecificationExecutor<OperationLogRecord> {
|
||||||
|
Page<OperationLogRecord> findByModule(String module, Pageable pageable);
|
||||||
|
Page<OperationLogRecord> findAllByOrderByOperateTimeDesc(Pageable pageable);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseSchsystemGrade;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchBinSchsystem;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchBinSchsystemRepository extends JpaRepository<SchBinSchsystem, Integer>, JpaSpecificationExecutor<SchBinSchsystem> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClassHistory;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchClassHistoryRepository extends JpaRepository<SchClassHistory, Integer>, JpaSpecificationExecutor<SchClassHistory> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校、班级组(classId=group_class_id)、学年、学期查询班级历史快照
|
||||||
|
* 历史任教统一取第二学期(term=2)
|
||||||
|
*/
|
||||||
|
List<SchClassHistory> findBySchIdAndClassIdAndYearAndTerm(Integer schId, Integer classId, Integer year, Integer term);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取某班级最新学年的第二学期(term=2)历史快照,用于“历史学生”页班级头信息
|
||||||
|
*/
|
||||||
|
SchClassHistory findTopBySchIdAndClassIdAndTermOrderByYearDesc(Integer schId, Integer classId, Integer term);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchClassRepository extends JpaRepository<SchClass, Integer>, JpaSpecificationExecutor<SchClass> {
|
||||||
|
|
||||||
|
Optional<SchClass> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
|
||||||
|
Optional<SchClass> findByClassIdAndSchId(Integer classId, Integer schId);
|
||||||
|
|
||||||
|
@Query(value = "SELECT MAX(sort) FROM sch_class WHERE grade_id = :gradeId AND sch_id = :schId AND graduate = 0", nativeQuery = true)
|
||||||
|
Integer findMaxCodeNumber(@Param("gradeId") Integer gradeId, @Param("schId") Integer schId);
|
||||||
|
|
||||||
|
@Query("SELECT c FROM SchClass c " +
|
||||||
|
"WHERE c.schId = :schId " +
|
||||||
|
"AND (:campusId IS NULL OR c.campusId = :campusId) " +
|
||||||
|
"AND (:divisionId IS NULL OR c.divisionId = :divisionId) " +
|
||||||
|
"AND (:majorsId IS NULL OR c.majorsId = :majorsId) " +
|
||||||
|
"AND (:years IS NULL OR c.enrollYear IN :years) " +
|
||||||
|
"AND (:keyword IS NULL OR :keyword = '' " +
|
||||||
|
" OR c.name LIKE CONCAT('%', :keyword, '%') " +
|
||||||
|
" OR c.cname LIKE CONCAT('%', :keyword, '%')) " +
|
||||||
|
"AND c.enrollYear = c.gradeId AND c.graduate = 0")
|
||||||
|
Page<SchClass> findClassesByConditions(@Param("schId") Integer schId,
|
||||||
|
@Param("campusId") Integer campusId,
|
||||||
|
@Param("divisionId") Integer divisionId,
|
||||||
|
@Param("majorsId") Integer majorsId,
|
||||||
|
@Param("years") List<Integer> years,
|
||||||
|
@Param("keyword") String keyword,
|
||||||
|
Pageable pageable);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean existsBySchIdAndGroupIdAndName(Integer schId, Integer groupId, String name);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndGroupIdAndNameAndIdNot(Integer schId, Integer groupId, String name, Integer id);
|
||||||
|
|
||||||
|
long countByFirstTeacherIdOrSecondTeacherId(Integer firstTeacherId, Integer secondTeacherId);
|
||||||
|
|
||||||
|
long countByCampusId(Integer campusId);
|
||||||
|
|
||||||
|
long countByDivisionId(Integer divisionId);
|
||||||
|
|
||||||
|
long countByMajorsId(Integer majorsId);
|
||||||
|
|
||||||
|
List<SchClass> findBySchIdAndEnrollYear(Integer schId, Integer enrollYear);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据学校ID和班级组ID列表查询班级
|
||||||
|
* @param schId 学校ID
|
||||||
|
* @param classIds 班级组ID列表(group_class_id,即 SchClass.classId)
|
||||||
|
* @return 匹配的班级列表(与入参顺序无关,按库内顺序返回)
|
||||||
|
*/
|
||||||
|
@Query("SELECT c FROM SchClass c WHERE c.schId = :schId AND c.classId IN :classIds")
|
||||||
|
List<SchClass> findBySchIdAndClassIds(@Param("schId") Integer schId, @Param("classIds") List<Integer> classIds);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndClassId(Integer schId, Integer classId);
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(c) FROM SchClass c WHERE (c.firstTeacherId IN (:ids) OR c.secondTeacherId IN (:ids)) AND c.schId = :schId AND c.graduate = 0")
|
||||||
|
long countByFirstTeacherIdInOrSecondTeacherIdInAndSchId(
|
||||||
|
@Param("ids") List<Integer> ids,
|
||||||
|
@Param("schId") Integer schId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据学校ID和年级ID列表,查询最小的注册年份
|
||||||
|
* @param schId 学校ID
|
||||||
|
* @param gradeIds 年级ID列表(可为空)
|
||||||
|
* @return 最小注册年份,如果没有匹配记录则返回 null
|
||||||
|
*/
|
||||||
|
@Query("SELECT MIN(c.enrollYear) FROM SchClass c WHERE c.schId = :schId AND c.gradeId IN :gradeIds")
|
||||||
|
Integer findMinEnrollYear(@Param("schId") Integer schId, @Param("gradeIds") List<Integer> gradeIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学年升级:指定学校下、给定年级(非最高年级)的未毕业班级整体升一级
|
||||||
|
* 使用 grade_id = grade_id + 1 的 SET 语义,单次语句原子完成,避免逐班加载与保存
|
||||||
|
* @param schId 学校ID(安全过滤)
|
||||||
|
* @param gradeIds 需要升级的年级ID列表(非最高年级)
|
||||||
|
* @param now 修改时间
|
||||||
|
* @return 实际受影响行数
|
||||||
|
*/
|
||||||
|
@Modifying(clearAutomatically = true)
|
||||||
|
@Query("UPDATE SchClass c SET c.gradeId = c.gradeId + 1, c.updateDate = :now, c.updateUserId = 0 " +
|
||||||
|
"WHERE c.schId = :schId AND c.gradeId IN :gradeIds AND c.graduate = false")
|
||||||
|
int batchUpgradeGrade(@Param("schId") Integer schId, @Param("gradeIds") List<Integer> gradeIds, @Param("now") Date now);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学年升级:指定学校下、最高年级的未毕业班级标记为毕业
|
||||||
|
* @param schId 学校ID(安全过滤)
|
||||||
|
* @param maxGrade 最高年级ID
|
||||||
|
* @param now 修改时间
|
||||||
|
* @return 实际受影响行数
|
||||||
|
*/
|
||||||
|
@Modifying(clearAutomatically = true)
|
||||||
|
@Query("UPDATE SchClass c SET c.graduate = true, c.updateDate = :now, c.updateUserId = 0 " +
|
||||||
|
"WHERE c.schId = :schId AND c.gradeId = :maxGrade AND c.graduate = false")
|
||||||
|
int batchGraduate(@Param("schId") Integer schId, @Param("maxGrade") Integer maxGrade, @Param("now") Date now);
|
||||||
|
|
||||||
|
|
||||||
|
Optional<SchClass> findByGroupId(Integer groupId);
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseDicGrade;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClassTeachHistory;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchClassTeachHistoryRepository extends JpaRepository<SchClassTeachHistory, Integer>, JpaSpecificationExecutor<SchClassTeachHistory> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校、班级组(classId=group_class_id)、学年、学期查询班级任教历史
|
||||||
|
* 历史任教统一取第二学期(term=2)
|
||||||
|
*/
|
||||||
|
List<SchClassTeachHistory> findBySchIdAndClassIdAndYearAndTerm(Integer schId, Integer classId, Integer year, Integer term);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClassTeach;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchClassTeachRepository extends JpaRepository<SchClassTeach, Integer>, JpaSpecificationExecutor<SchClassTeach> {
|
||||||
|
|
||||||
|
|
||||||
|
List<SchClassTeach> findBySchIdAndClassIdIn(Integer schId, List<Integer> classIds);
|
||||||
|
|
||||||
|
Optional<SchClassTeach> findBySchIdAndClassIdAndSubId(Integer schId, Integer classId, String subId);
|
||||||
|
|
||||||
|
Optional<SchClassTeach> findBySchIdAndId(Integer schId, Integer id);
|
||||||
|
|
||||||
|
List<SchClassTeach> findBySchIdAndClassId(Integer schId, Integer classId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCampus;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicCampusRepository extends JpaRepository<SchDicCampus, Integer>, JpaSpecificationExecutor<SchDicCampus> {
|
||||||
|
|
||||||
|
boolean existsBySchIdAndName(Integer schId, String name);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndNameAndIdNot(Integer schId, String name, Integer id);
|
||||||
|
|
||||||
|
Optional<SchDicCampus> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCourseDivision;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicCourseDivisionRepository extends JpaRepository<SchDicCourseDivision, Integer>, JpaSpecificationExecutor<SchDicCourseDivision> {
|
||||||
|
|
||||||
|
List<SchDicCourseDivision> findByCourseIdAndSchId(Integer courseId, Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据课程 ID 列表和学校 ID 批量查询关联的学部关系
|
||||||
|
* @param courseIds 课程 ID 列表
|
||||||
|
* @param schId 学校 ID
|
||||||
|
* @return 匹配的关联关系列表
|
||||||
|
*/
|
||||||
|
List<SchDicCourseDivision> findByCourseIdInAndSchId(List<Integer> courseIds, Integer schId);
|
||||||
|
|
||||||
|
void deleteByCourseIdAndSchId(Integer courseId, Integer schId);
|
||||||
|
|
||||||
|
Optional<SchDicCourseDivision> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCourseMajors;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicCourseMajorsRepository extends JpaRepository<SchDicCourseMajors, Integer>, JpaSpecificationExecutor<SchDicCourseMajors> {
|
||||||
|
|
||||||
|
List<SchDicCourseMajors> findByCourseIdAndSchId(Integer courseId, Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据课程 ID 列表和学校 ID 批量查询关联的学部关系
|
||||||
|
* @param courseIds 课程 ID 列表
|
||||||
|
* @param schId 学校 ID
|
||||||
|
* @return 匹配的关联关系列表
|
||||||
|
*/
|
||||||
|
List<SchDicCourseMajors> findByCourseIdInAndSchId(List<Integer> courseIds, Integer schId);
|
||||||
|
|
||||||
|
void deleteByCourseIdAndSchId(Integer courseId, Integer schId);
|
||||||
|
|
||||||
|
Optional<SchDicCourseMajors> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCampus;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCourse;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicCourseRepository extends JpaRepository<SchDicCourse, Integer>, JpaSpecificationExecutor<SchDicCourse> {
|
||||||
|
boolean existsBySchIdAndName(Integer schId, String name);
|
||||||
|
boolean existsBySchIdAndNameAndIdNot(Integer schId, String name, Integer id);
|
||||||
|
Optional<SchDicCourse> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
@Query(value = "SELECT c FROM SchDicCourse c " +
|
||||||
|
"WHERE c.schId = :schId " +
|
||||||
|
"AND (:type IS NULL OR c.type = :type) " +
|
||||||
|
"AND (:keyword IS NULL OR (c.name LIKE CONCAT('%', :keyword, '%') " +
|
||||||
|
" OR c.nickname LIKE CONCAT('%', :keyword, '%') " +
|
||||||
|
" OR c.code LIKE CONCAT('%', :keyword, '%'))) " +
|
||||||
|
"AND (:divisionId IS NULL OR EXISTS (SELECT 1 FROM SchDicCourseDivision d WHERE d.courseId = c.id AND d.divisionId = :divisionId)) " +
|
||||||
|
"AND (:majorsId IS NULL OR EXISTS (SELECT 1 FROM SchDicCourseMajors m WHERE m.courseId = c.id AND m.majorsId = :majorsId))",
|
||||||
|
countQuery = "SELECT COUNT(c) FROM SchDicCourse c " +
|
||||||
|
"WHERE c.schId = :schId " +
|
||||||
|
"AND (:type IS NULL OR c.type = :type) " +
|
||||||
|
"AND (:keyword IS NULL OR (c.name LIKE CONCAT('%', :keyword, '%') " +
|
||||||
|
" OR c.nickname LIKE CONCAT('%', :keyword, '%') " +
|
||||||
|
" OR c.code LIKE CONCAT('%', :keyword, '%'))) " +
|
||||||
|
"AND (:divisionId IS NULL OR EXISTS (SELECT 1 FROM SchDicCourseDivision d WHERE d.courseId = c.id AND d.divisionId = :divisionId)) " +
|
||||||
|
"AND (:majorsId IS NULL OR EXISTS (SELECT 1 FROM SchDicCourseMajors m WHERE m.courseId = c.id AND m.majorsId = :majorsId))")
|
||||||
|
Page<SchDicCourse> findCoursesByConditions(@Param("schId") Integer schId,
|
||||||
|
@Param("type") Integer type,
|
||||||
|
@Param("keyword") String keyword,
|
||||||
|
@Param("divisionId") Integer divisionId,
|
||||||
|
@Param("majorsId") Integer majorsId,
|
||||||
|
Pageable pageable);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicDivision;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicDivisionRepository extends JpaRepository<SchDicDivision, Integer>, JpaSpecificationExecutor<SchDicDivision> {
|
||||||
|
boolean existsBySchIdAndName(Integer schId, String name);
|
||||||
|
boolean existsBySchIdAndNameAndIdNot(Integer schId, String name, Integer id);
|
||||||
|
Optional<SchDicDivision> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicMajors;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicMajorsRepository extends JpaRepository<SchDicMajors, Integer>, JpaSpecificationExecutor<SchDicMajors> {
|
||||||
|
boolean existsBySchIdAndName(Integer schId, String name);
|
||||||
|
boolean existsBySchIdAndNameAndIdNot(Integer schId, String name, Integer id);
|
||||||
|
Optional<SchDicMajors> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
|
||||||
|
@Query("SELECT MAX(m.schsystemLeng) FROM SchDicMajors m WHERE m.schId = :schId")
|
||||||
|
Optional<Integer> findMaxSchsystemLengBySchId(Integer schId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseDicGrade;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicSubject;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchDicSubjectRepository extends JpaRepository<SchDicSubject, Integer>, JpaSpecificationExecutor<SchDicSubject> {
|
||||||
|
|
||||||
|
@Query(value = "SELECT MAX(CAST(SUBSTRING(code, 4) AS UNSIGNED)) FROM sch_dic_subject WHERE code LIKE 'SUB%' AND sch_id = ?1", nativeQuery = true)
|
||||||
|
Integer findMaxSubjectCodeNumber(Integer schId);
|
||||||
|
|
||||||
|
Optional<SchDicSubject> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndSchSystemIdAndName(Integer schId, Integer schSystemId, String name);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndSchSystemIdAndNameAndIdNot(Integer schId, Integer schSystemId, String name, Integer id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchInfo;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchInfoRepository extends JpaRepository<SchInfo, Integer>, JpaSpecificationExecutor<SchInfo> {
|
||||||
|
|
||||||
|
Optional<SchInfo> findBySchId(Integer schId);
|
||||||
|
|
||||||
|
Optional<SchInfo> findBySchSerId(String schSerId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClassTeachHistory;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchStudentHistory;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchStudentHistoryRepository extends JpaRepository<SchStudentHistory, Integer>, JpaSpecificationExecutor<SchStudentHistory> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校、班级、学年、学期查询历史学生(term=2 为学年快照)
|
||||||
|
*/
|
||||||
|
List<SchStudentHistory> findBySchIdAndClassIdAndYearAndTerm(Integer schId, Integer classId, Integer year, Integer term);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校、学生(stuId)查询历史学生记录,用于解析学生所属班级
|
||||||
|
*/
|
||||||
|
List<SchStudentHistory> findBySchIdAndStuId(Integer schId, Integer stuId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchStudentRepository extends JpaRepository<SchStudent, Integer>, JpaSpecificationExecutor<SchStudent> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stu_id 是用户中心用户ID(非本表主键),学生在多所学校各有一条就学记录,
|
||||||
|
* 同一 stu_id 可能存在多行,必须返回 List;返回 Optional 会在多行时抛 NonUniqueResultException
|
||||||
|
*/
|
||||||
|
List<SchStudent> findByStuId(Integer stuId);
|
||||||
|
|
||||||
|
List<SchStudent> findByStuIdIn(List<Integer> stuIds);
|
||||||
|
|
||||||
|
boolean existsByAccount(String account);
|
||||||
|
|
||||||
|
Optional<SchStudent> findByAccount(String account);
|
||||||
|
|
||||||
|
Optional<SchStudent> findByIdAndSchId(Integer Id, Integer schId);
|
||||||
|
|
||||||
|
@Query("SELECT s FROM SchStudent s WHERE s.schId = :schId AND s.classId = :classId AND s.abnormalStatus = 0 AND s.transferStatus= 0 AND s.status = 0")
|
||||||
|
List<SchStudent> findBySchIdAndClassId(@Param("schId") Integer schId, @Param("classId") Integer classId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据学校、班级和转入状态查询学生实体
|
||||||
|
* 适用场景:同步回收时定位某班当前“转入/转出”的学生,用于把用户中心已移除的学生标记为转出
|
||||||
|
*/
|
||||||
|
@Query("SELECT s FROM SchStudent s WHERE s.schId = :schId AND s.classId = :classId AND s.transferStatus = :transferStatus")
|
||||||
|
List<SchStudent> findBySchIdAndClassIdAndTransferStatus(@Param("schId") Integer schId,
|
||||||
|
@Param("classId") Integer classId,
|
||||||
|
@Param("transferStatus") Integer transferStatus);
|
||||||
|
|
||||||
|
List<SchStudent> findAllByIdInAndSchId(List<Integer> ids, Integer schId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
boolean existsBySchIdAndClassIdAndName(Integer schId,Integer classId, String name);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndClassIdAndNameAndIdNot(Integer schId,Integer classId, String name, Integer id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断同一班级内是否已存在相同学号的学生(排除自身,用于学号导入时的重复校验)
|
||||||
|
*/
|
||||||
|
boolean existsBySchIdAndClassIdAndStuClassNoAndIdNot(Integer schId, Integer classId, String stuClassNo, Integer id);
|
||||||
|
|
||||||
|
@Modifying(clearAutomatically = true)
|
||||||
|
@Query("UPDATE SchStudent s SET s.classId = :newClassId, s.groupId = :newClassId, s.updateDate = :updateDate, s.updateUserId = :updateUserId WHERE s.id IN (:ids) AND s.schId = :schId")
|
||||||
|
int batchUpdateClassId(@Param("ids") List<Integer> ids,
|
||||||
|
@Param("newClassId") Integer newClassId,
|
||||||
|
@Param("schId") Integer schId,
|
||||||
|
@Param("updateDate") Date updateDate,
|
||||||
|
@Param("updateUserId") Integer updateUserId);
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("UPDATE SchStudent s SET s.schId = :schId, s.classId = :newClassId,s.groupId = :newClassId, s.updateDate = :updateDate, s.updateUserId = :updateUserId , s.transferStatus = 0 WHERE s.id IN :ids")
|
||||||
|
int batchUpdateSchIdAndClassId(@Param("ids") List<Integer> ids,
|
||||||
|
@Param("schId") Integer schId, // 目标学校ID
|
||||||
|
@Param("newClassId") Integer newClassId,
|
||||||
|
@Param("updateDate") Date updateDate,
|
||||||
|
@Param("updateUserId") Integer updateUserId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新学生异常状态,同时记录异常发生时间和修改时间(两者相同)
|
||||||
|
*
|
||||||
|
* @param ids 学生ID列表
|
||||||
|
* @param abnormalStatus 异常状态值
|
||||||
|
* @param schId 学校ID(安全过滤)
|
||||||
|
* @param commonDate 异常时间 / 修改时间
|
||||||
|
* @param updateUserId 操作用户ID
|
||||||
|
* @return 实际更新的行数
|
||||||
|
*/
|
||||||
|
@Modifying(clearAutomatically = true)
|
||||||
|
@Query("UPDATE SchStudent s SET " +
|
||||||
|
"s.abnormalStatus = :abnormalStatus, " +
|
||||||
|
"s.abnormalDate = :commonDate, " +
|
||||||
|
"s.updateDate = :commonDate, " +
|
||||||
|
"s.updateUserId = :updateUserId " +
|
||||||
|
"WHERE s.id IN (:ids) AND s.schId = :schId")
|
||||||
|
int batchUpdateAbnormalStatus(@Param("ids") List<Integer> ids,
|
||||||
|
@Param("abnormalStatus") Integer abnormalStatus,
|
||||||
|
@Param("schId") Integer schId,
|
||||||
|
@Param("commonDate") Date commonDate,
|
||||||
|
@Param("updateUserId") Integer updateUserId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新学生异常状态,同时记录异常发生时间和修改时间(两者相同)
|
||||||
|
*
|
||||||
|
* @param ids 学生ID列表
|
||||||
|
* @param transferStatus 转出状态值
|
||||||
|
* @param schId 学校ID(安全过滤)
|
||||||
|
* @param commonDate 异常时间 / 修改时间
|
||||||
|
* @param updateUserId 操作用户ID
|
||||||
|
* @return 实际更新的行数
|
||||||
|
*/
|
||||||
|
@Modifying(clearAutomatically = true)
|
||||||
|
@Query("UPDATE SchStudent s SET " +
|
||||||
|
"s.transferStatus = :transferStatus, " +
|
||||||
|
"s.abnormalDate = :commonDate, " +
|
||||||
|
"s.updateDate = :commonDate, " +
|
||||||
|
"s.updateUserId = :updateUserId, " +
|
||||||
|
"s.stuClassNo = null " +
|
||||||
|
"WHERE s.id IN (:ids) AND s.schId = :schId")
|
||||||
|
int batchUpdateTransferStatus(@Param("ids") List<Integer> ids,
|
||||||
|
@Param("transferStatus") Integer transferStatus,
|
||||||
|
@Param("schId") Integer schId,
|
||||||
|
@Param("commonDate") Date commonDate,
|
||||||
|
@Param("updateUserId") Integer updateUserId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有转出学生的学校ID(去重)
|
||||||
|
* 转出条件:transfer_status = 1
|
||||||
|
* 关联:s.class_id = c.group_class_id
|
||||||
|
*/
|
||||||
|
@Query(value = "SELECT DISTINCT c.sch_id FROM sch_student s " +
|
||||||
|
"INNER JOIN sch_class c ON s.class_id = c.group_class_id " +
|
||||||
|
"WHERE s.transfer_status = 0 AND s.sch_id = c.sch_id AND s.status= 0 ", nativeQuery = true)
|
||||||
|
List<Integer> findDistinctSchIdsByTransferOut();
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInGrade;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherCustomGroupInGradeRepository extends JpaRepository<SchTeacherCustomGroupInGrade, Integer>, JpaSpecificationExecutor<SchTeacherCustomGroupInGrade> {
|
||||||
|
List<SchTeacherCustomGroupInGrade> findByCgGroupIdIn(List<Integer> groupIds);
|
||||||
|
|
||||||
|
void deleteByCgGroupId(Integer groupId);
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInSubject;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherCustomGroupInSubjectRepository extends JpaRepository<SchTeacherCustomGroupInSubject, Integer>, JpaSpecificationExecutor<SchTeacherCustomGroupInSubject> {
|
||||||
|
List<SchTeacherCustomGroupInSubject> findByCgGroupIdIn(List<Integer> groupIds);
|
||||||
|
|
||||||
|
void deleteByCgGroupId(Integer groupId);
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroup;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInTeacher;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherCustomGroupInTeacherRepository extends JpaRepository<SchTeacherCustomGroupInTeacher, Integer>, JpaSpecificationExecutor<SchTeacherCustomGroupInTeacher> {
|
||||||
|
/**
|
||||||
|
* 根据组ID列表查询所有教师关联
|
||||||
|
* @param groupIds 组ID列表
|
||||||
|
* @return 教师关联列表
|
||||||
|
*/
|
||||||
|
List<SchTeacherCustomGroupInTeacher> findByCgGroupIdIn(List<Integer> groupIds);
|
||||||
|
|
||||||
|
List<SchTeacherCustomGroupInTeacher> findByCgGroupId(Integer groupId);
|
||||||
|
|
||||||
|
List<SchTeacherCustomGroupInTeacher> findByCgGroupIdAndGroupType(Integer groupId, Integer groupType);
|
||||||
|
|
||||||
|
void deleteByCgGroupIdAndGroupType(Integer groupId, Integer groupType);
|
||||||
|
|
||||||
|
void deleteByCgGroupIdAndTeaIdInAndGroupType(Integer groupId, List<Integer> teaIds, Integer groupType);
|
||||||
|
|
||||||
|
void deleteByCgGroupId(Integer groupId);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroup;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherCustomGroupRepository extends JpaRepository<SchTeacherCustomGroup, Integer>, JpaSpecificationExecutor<SchTeacherCustomGroup> {
|
||||||
|
|
||||||
|
List<SchTeacherCustomGroup> findBySchId(Integer schId);
|
||||||
|
|
||||||
|
List<SchTeacherCustomGroup> findBySchIdAndGroupType(Integer schId, Integer groupType);
|
||||||
|
|
||||||
|
List<SchTeacherCustomGroup> findBySchIdAndGroupTypeAndGroupName(Integer schId, Integer groupType, String groupName);
|
||||||
|
|
||||||
|
boolean existsBySchIdAndGroupTypeAndGroupName(Integer schId, Integer groupType, String groupName);
|
||||||
|
boolean existsBySchIdAndGroupTypeAndGroupNameAndIdNot(Integer schId, Integer groupType, String groupName, Integer id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherGroupRepository extends JpaRepository<SchTeacherGroup, Integer>, JpaSpecificationExecutor<SchTeacherGroup> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 teaId 列表查询所有组关联(不限学校)
|
||||||
|
* 适用场景:全局查询(如跨校操作前校验)
|
||||||
|
*/
|
||||||
|
List<SchTeacherGroup> findByTeaIdIn(List<Integer> teaIds);
|
||||||
|
|
||||||
|
|
||||||
|
List<SchTeacherGroup> findByGroupIdAndSchId(Integer groupId, Integer schId);
|
||||||
|
|
||||||
|
|
||||||
|
List<SchTeacherGroup> findByTeaIdAndSchId(Integer teaId, Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 teaId 列表和学校 ID 查询组关联
|
||||||
|
* 适用场景:查询某教师在指定学校的组归属
|
||||||
|
*/
|
||||||
|
List<SchTeacherGroup> findByTeaIdInAndSchId(List<Integer> teaIds, Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 teaId 列表、学校 ID 和转入状态查询组关联
|
||||||
|
* 适用场景:只查询转入状态的记录(transferStatus = 0)
|
||||||
|
*/
|
||||||
|
List<SchTeacherGroup> findByTeaIdInAndSchIdAndTransferStatus(List<Integer> teaIds, Integer schId, Integer transferStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据学校 ID 和转入状态查询教师分组实体
|
||||||
|
* 适用场景:同步回收时定位某校当前“转入/转出”的教师分组,用于把用户中心已移除的教师标记为转出
|
||||||
|
*/
|
||||||
|
List<SchTeacherGroup> findBySchIdAndTransferStatus(Integer schId, Integer transferStatus);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据学校 ID 查询该学校所有教师的 teaId(去重)
|
||||||
|
* 适用场景:获取该校所有教师列表
|
||||||
|
*/
|
||||||
|
@Query("SELECT DISTINCT t.teaId FROM SchTeacherGroup t WHERE t.schId = :schId")
|
||||||
|
List<Integer> findTeaIdsBySchId(@Param("schId") Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验某教师是否属于某学校(根据 teaId 和 schId)
|
||||||
|
*/
|
||||||
|
boolean existsByTeaIdAndSchId(Integer teaId, Integer schId);
|
||||||
|
|
||||||
|
// ==================== 删除方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 teaId 列表删除所有学校的关联(谨慎使用)
|
||||||
|
* 适用场景:全局删除(如教师彻底注销)
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM SchTeacherGroup g WHERE g.teaId IN :teaIds AND g.groupId = :groupId")
|
||||||
|
int deleteByGroupIdAndTeaIds(@Param("teaIds") List<Integer> teaIds,Integer groupId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 teaId 列表和学校 ID 删除关联(推荐)
|
||||||
|
* 适用场景:转出/删除时只移除该教师在当前学校的组归属
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM SchTeacherGroup g WHERE g.teaId IN :teaIds AND g.schId = :schId")
|
||||||
|
int deleteByTeaIdInAndSchId(@Param("teaIds") List<Integer> teaIds, @Param("schId") Integer schId);
|
||||||
|
|
||||||
|
// ==================== 批量更新方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新某学校下教师的转入状态
|
||||||
|
* 适用场景:批量转出/转入
|
||||||
|
*/
|
||||||
|
@Modifying
|
||||||
|
@Query("UPDATE SchTeacherGroup g SET g.transferStatus = :status WHERE g.teaId IN :teaIds AND g.schId = :schId")
|
||||||
|
int batchUpdateTransferStatus(@Param("teaIds") List<Integer> teaIds,
|
||||||
|
@Param("schId") Integer schId,
|
||||||
|
@Param("status") Integer status);
|
||||||
|
|
||||||
|
// 根据学校ID和组ID查询教师 teaId 列表
|
||||||
|
@Query("SELECT DISTINCT t.teaId FROM SchTeacherGroup t WHERE t.schId = :schId AND t.groupId = :groupId")
|
||||||
|
List<Integer> findTeaIdsBySchIdAndGroupId(@Param("schId") Integer schId, @Param("groupId") Integer groupId);
|
||||||
|
|
||||||
|
// 查询某学校下所有不同的组ID
|
||||||
|
@Query("SELECT DISTINCT t.groupId FROM SchTeacherGroup t WHERE t.schId = :schId")
|
||||||
|
List<Integer> findGroupIdsBySchId(@Param("schId") Integer schId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据状态获取学校ID(去重)
|
||||||
|
*/
|
||||||
|
@Query("SELECT DISTINCT g.schId FROM SchTeacherGroup g WHERE g.transferStatus = 0")
|
||||||
|
List<Integer> findSchoolIdsByTransferOut();
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.TeacherSchVO;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SchTeacherRepository extends JpaRepository<SchTeacher, Integer>, JpaSpecificationExecutor<SchTeacher> {
|
||||||
|
|
||||||
|
List<SchTeacher> findByTeaIdIn(List<Integer> teaIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tea_id 是用户中心用户ID(非本表主键),教师在多所学校各有一条记录,
|
||||||
|
* 同一 tea_id 可能存在多行,必须返回 List;返回 Optional 会在多行时抛 NonUniqueResultException
|
||||||
|
*/
|
||||||
|
List<SchTeacher> findByTeaId(Integer teaId);
|
||||||
|
|
||||||
|
|
||||||
|
@Query(value = "SELECT DISTINCT t.* FROM sch_teacher t " +
|
||||||
|
"INNER JOIN sch_teacher_group g ON t.tea_id = g.tea_id " +
|
||||||
|
"WHERE g.sch_id = :schId " +
|
||||||
|
"AND g.transfer_status = 0 " + // 只查转入状态的教师
|
||||||
|
"AND (:groupId IS NULL OR g.group_id = :groupId) " +
|
||||||
|
"AND (:keyword IS NULL OR t.name LIKE CONCAT('%', :keyword, '%') OR t.account LIKE CONCAT('%', :keyword, '%')) " ,
|
||||||
|
countQuery = "SELECT COUNT(DISTINCT t.id) FROM sch_teacher t " +
|
||||||
|
"INNER JOIN sch_teacher_group g ON t.tea_id = g.tea_id " +
|
||||||
|
"WHERE g.sch_id = :schId " +
|
||||||
|
"AND g.transfer_status = 0 " +
|
||||||
|
"AND (:groupId IS NULL OR g.group_id = :groupId) " +
|
||||||
|
"AND (:keyword IS NULL OR t.name LIKE CONCAT('%', :keyword, '%') OR t.account LIKE CONCAT('%', :keyword, '%'))",
|
||||||
|
nativeQuery = true)
|
||||||
|
Page<SchTeacher> searchTeachersBySchIdAndGroupId(@Param("schId") Integer schId,
|
||||||
|
@Param("groupId") Integer groupId,
|
||||||
|
@Param("keyword") String keyword,
|
||||||
|
Pageable pageable);
|
||||||
|
|
||||||
|
|
||||||
|
@Query(value = "SELECT DISTINCT g.tea_id AS teaId, g.sch_id AS schId, t.name AS teaName, t.id_card AS idCard " +
|
||||||
|
"FROM sch_teacher_group g " +
|
||||||
|
"INNER JOIN sch_teacher t ON t.tea_id = g.tea_id " +
|
||||||
|
"WHERE g.transfer_status = 1 " +
|
||||||
|
"AND t.status = 0 " +
|
||||||
|
"AND (:schId IS NULL OR g.sch_id = :schId) " +
|
||||||
|
"AND (:groupId IS NULL OR g.group_id = :groupId) " +
|
||||||
|
"AND (:keyword IS NULL OR t.name LIKE CONCAT('%', :keyword, '%') OR t.account LIKE CONCAT('%', :keyword, '%')) " +
|
||||||
|
"ORDER BY t.name", //只按教师姓名排序,避免引用未选择列
|
||||||
|
countQuery = "SELECT COUNT(DISTINCT CONCAT(g.tea_id, '_', g.sch_id)) " +
|
||||||
|
"FROM sch_teacher_group g " +
|
||||||
|
"INNER JOIN sch_teacher t ON t.tea_id = g.tea_id " +
|
||||||
|
"WHERE g.transfer_status = 1 " +
|
||||||
|
"AND t.status = 0 " +
|
||||||
|
"AND (:schId IS NULL OR g.sch_id = :schId) " +
|
||||||
|
"AND (:groupId IS NULL OR g.group_id = :groupId) " +
|
||||||
|
"AND (:keyword IS NULL OR t.name LIKE CONCAT('%', :keyword, '%') OR t.account LIKE CONCAT('%', :keyword, '%'))",
|
||||||
|
nativeQuery = true)
|
||||||
|
Page<TeacherSchVO> searchTransferredOutTeachers(@Param("schId") Integer schId,
|
||||||
|
@Param("groupId") Integer groupId,
|
||||||
|
@Param("keyword") String keyword,
|
||||||
|
Pageable pageable);
|
||||||
|
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("UPDATE SchTeacher t SET t.status = :status, t.updateDate = :updateDate, t.updateUserId = :updateUserId WHERE t.id IN :ids")
|
||||||
|
int batchUpdateStatus(@Param("ids") List<Integer> ids,
|
||||||
|
@Param("status") Integer status,
|
||||||
|
@Param("updateDate") Date updateDate,
|
||||||
|
@Param("updateUserId") Integer updateUserId);
|
||||||
|
|
||||||
|
|
||||||
|
List<SchTeacher> findByAccountIn(List<String> accountList);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SyncLog;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SyncLogRepository
|
||||||
|
extends JpaRepository<SyncLog, Long>, JpaSpecificationExecutor<SyncLog> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SysOperationLog;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface SysOperationLogRepository
|
||||||
|
extends JpaRepository<SysOperationLog, Long>, JpaSpecificationExecutor<SysOperationLog> {
|
||||||
|
|
||||||
|
/** 按级别 + 截止时间批量删除(单条 DELETE,定时清理用) */
|
||||||
|
long deleteByLogLevelAndCreateTimeBefore(Integer logLevel, LocalDateTime time);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.UpgradeLog;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UpgradeLogRepository extends JpaRepository<UpgradeLog, Integer>, JpaSpecificationExecutor<UpgradeLog> {
|
||||||
|
boolean existsBySchIdAndSysIdAndYearAndStatus(
|
||||||
|
Integer schId, Integer sysId, Integer year,Boolean status
|
||||||
|
);
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository.specification;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.OperationLogRecord;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.persistence.criteria.Predicate;
|
||||||
|
|
||||||
|
public class OperationLogSpecifications {
|
||||||
|
|
||||||
|
public static Specification<OperationLogRecord> schIdEquals(Integer schId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (schId == null || schId < 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("schId"), schId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<OperationLogRecord> IsSystem(boolean IsSystem) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (IsSystem) {
|
||||||
|
return cb.equal(root.get("module"), "系统管理");
|
||||||
|
}else{
|
||||||
|
return cb.notEqual(root.get("module"), "系统管理");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Specification<OperationLogRecord> keywordLike(String keyword) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (!StringUtils.hasText(keyword)) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
String likePattern = "%" + keyword.trim() + "%";
|
||||||
|
Predicate p1 = cb.like(root.get("operator"), likePattern);
|
||||||
|
Predicate p2 = cb.like(root.get("module"), likePattern);
|
||||||
|
Predicate p3 = cb.like(root.get("content"), likePattern);
|
||||||
|
return cb.or(p1, p2, p3);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository.specification;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.persistence.criteria.Join;
|
||||||
|
import javax.persistence.criteria.JoinType;
|
||||||
|
import javax.persistence.criteria.Predicate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SchClassSpecifications {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校 ID 查询(班级表中直接存储了 schId)
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> schIdEquals(Integer schId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (schId == null || schId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("schId"), schId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按年级 ID 查询
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> gradeIdEquals(Integer gradeId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (gradeId == null || gradeId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("gradeId"), gradeId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按班级名称模糊查询
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> classNameLike(String className) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (!StringUtils.hasText(className)) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.like(root.get("className"), "%" + className + "%");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按班主任教师 ID 查询(firstTeacherId)
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> firstTeacherIdEquals(Integer teacherId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (teacherId == null || teacherId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("firstTeacherId"), teacherId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按副班主任教师 ID 查询(secondTeacherId)
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> secondTeacherIdEquals(Integer teacherId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (teacherId == null || teacherId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("secondTeacherId"), teacherId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按班主任或副班主任教师 ID 查询(任意一个匹配)
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> teacherIsHeadOrAssistant(Integer teacherId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (teacherId == null || teacherId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
Predicate p1 = cb.equal(root.get("firstTeacherId"), teacherId);
|
||||||
|
Predicate p2 = cb.equal(root.get("secondTeacherId"), teacherId);
|
||||||
|
return cb.or(p1, p2);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按年级名称模糊查询(需关联年级表,假设有 @ManyToOne 关系)
|
||||||
|
* 注意:SchClass 实体中需有 grade 关联字段,例如:@ManyToOne @JoinColumn(name = "grade_id") private SchGrade grade;
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> gradeNameLike(String gradeName) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (!StringUtils.hasText(gradeName)) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
Join<Object, Object> gradeJoin = root.join("grade", JoinType.INNER);
|
||||||
|
return cb.like(gradeJoin.get("name"), "%" + gradeName + "%");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态组合查询(多条件),便于一次性传入多个参数
|
||||||
|
*/
|
||||||
|
public static Specification<SchClass> dynamicQuery(Integer schId, Integer gradeId, String keyword,
|
||||||
|
Integer teacherId, Boolean isHeadTeacher) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
List<Predicate> predicates = new ArrayList<>();
|
||||||
|
|
||||||
|
if (schId != null && schId > 0) {
|
||||||
|
predicates.add(cb.equal(root.get("schId"), schId));
|
||||||
|
}
|
||||||
|
if (gradeId != null && gradeId > 0) {
|
||||||
|
predicates.add(cb.equal(root.get("gradeId"), gradeId));
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(keyword)) {
|
||||||
|
predicates.add(cb.like(root.get("className"), "%" + keyword + "%"));
|
||||||
|
}
|
||||||
|
if (teacherId != null && teacherId > 0) {
|
||||||
|
if (isHeadTeacher != null && isHeadTeacher) {
|
||||||
|
predicates.add(cb.equal(root.get("firstTeacherId"), teacherId));
|
||||||
|
} else if (isHeadTeacher != null && !isHeadTeacher) {
|
||||||
|
predicates.add(cb.equal(root.get("secondTeacherId"), teacherId));
|
||||||
|
} else {
|
||||||
|
// 没有指定角色,默认查班主任或副班主任任意一个
|
||||||
|
Predicate p1 = cb.equal(root.get("firstTeacherId"), teacherId);
|
||||||
|
Predicate p2 = cb.equal(root.get("secondTeacherId"), teacherId);
|
||||||
|
predicates.add(cb.or(p1, p2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query.distinct(true);
|
||||||
|
return cb.and(predicates.toArray(new Predicate[0]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
package com.yunhai.bschclassmanage.Repository.specification;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||||
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import javax.persistence.criteria.Join;
|
||||||
|
import javax.persistence.criteria.JoinType;
|
||||||
|
import javax.persistence.criteria.Predicate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SchTeacherSpecifications {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按姓名模糊查询
|
||||||
|
*/
|
||||||
|
public static Specification<SchTeacher> nameLike(String keyword) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (!StringUtils.hasText(keyword)) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.like(root.get("name"), "%" + keyword + "%");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按状态精确查询(0-正常, 1-禁用等)
|
||||||
|
*/
|
||||||
|
public static Specification<SchTeacher> statusEquals(Integer status) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (status == null || status < 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
return cb.equal(root.get("status"), status);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按学校 ID 查询(通过关联表 SchTeacherGroup)
|
||||||
|
*/
|
||||||
|
public static Specification<SchTeacher> belongsToSchool(Integer schId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (schId == null || schId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
Join<SchTeacher, SchTeacherGroup> groupJoin = root.join("schTeacherGroups", JoinType.INNER);
|
||||||
|
query.distinct(true); // 避免因关联导致重复记录
|
||||||
|
return cb.equal(groupJoin.get("schId"), schId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按组 ID 查询(通过关联表)
|
||||||
|
*/
|
||||||
|
public static Specification<SchTeacher> belongsToGroup(Integer groupId) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
if (groupId == null || groupId <= 0) {
|
||||||
|
return cb.conjunction();
|
||||||
|
}
|
||||||
|
Join<SchTeacher, SchTeacherGroup> groupJoin = root.join("schTeacherGroups", JoinType.INNER);
|
||||||
|
query.distinct(true);
|
||||||
|
return cb.equal(groupJoin.get("groupId"), groupId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组合查询:支持多条件动态组合(用于复杂搜索)
|
||||||
|
*/
|
||||||
|
public static Specification<SchTeacher> dynamicQuery(Integer schId, Integer groupId, String keyword, Integer status) {
|
||||||
|
return (root, query, cb) -> {
|
||||||
|
List<Predicate> predicates = new ArrayList<>();
|
||||||
|
|
||||||
|
if (schId != null && schId > 0) {
|
||||||
|
Join<SchTeacher, SchTeacherGroup> groupJoin = root.join("schTeacherGroups", JoinType.INNER);
|
||||||
|
predicates.add(cb.equal(groupJoin.get("schId"), schId));
|
||||||
|
}
|
||||||
|
if (groupId != null && groupId > 0) {
|
||||||
|
Join<SchTeacher, SchTeacherGroup> groupJoin = root.join("schTeacherGroups", JoinType.INNER);
|
||||||
|
predicates.add(cb.equal(groupJoin.get("groupId"), groupId));
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(keyword)) {
|
||||||
|
predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
|
||||||
|
}
|
||||||
|
if (status != null && status >= 0) {
|
||||||
|
predicates.add(cb.equal(root.get("status"), status));
|
||||||
|
}
|
||||||
|
|
||||||
|
query.distinct(true);
|
||||||
|
return cb.and(predicates.toArray(new Predicate[0]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.yunhai.bschclassmanage.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface OperationLog {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作所属模块,如 "教师信息管理"
|
||||||
|
*/
|
||||||
|
String module() default "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志内容模板,支持 SpEL 表达式
|
||||||
|
* 例如:"将教师 #{#teacherName} 的姓名从 #{#oldName} 改为 #{#newName}"
|
||||||
|
* 方法参数可以通过 #参数名 引用,返回值通过 #result 引用
|
||||||
|
*/
|
||||||
|
String description() default "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.yunhai.bschclassmanage.annotation;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.enums.SyncDataType;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记一个方法需要记录"用户同步调用日志"。
|
||||||
|
* 由 SyncLogAspect 拦截,按 dataType 写入 sync_log 表。
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface SyncOpLog {
|
||||||
|
/** 该操作对应的同步数据类型枚举(作为默认的 value 元素,可用 @SyncOpLog(SyncDataType.X) 简写) */
|
||||||
|
SyncDataType value();
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package com.yunhai.bschclassmanage.aspect;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.model.tool.UserSysRole;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.auth.BoaUserContext;
|
||||||
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(1)
|
||||||
|
public class ControllerUserContextAspect {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ControllerUserContextAspect.class);
|
||||||
|
|
||||||
|
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部认证框架(yunhai platform)把解析好的 BoaUser 放进 request attribute 的候选 key。
|
||||||
|
* 如果实际 key 不在此列表中,请在配置/网关侧确认后补充,或改用 Header 解析。
|
||||||
|
*/
|
||||||
|
private static final List<String> BOA_USER_ATTR_KEYS = Arrays.asList(
|
||||||
|
"boaUser", "boauser", "currentUser", "user", "authUser", "loginUser"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Around("execution(* com.yunhai.bschclassmanage.controller..*.*(..))")
|
||||||
|
public Object setUserContext(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||||
|
// 1. 优先从方法参数中提取 BoaUser 和 UserSysRole(兼容旧写法)
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
BoaUser boaUser = null;
|
||||||
|
UserSysRole userSysRole = null;
|
||||||
|
|
||||||
|
for (Object arg : args) {
|
||||||
|
if (arg instanceof BoaUser) {
|
||||||
|
boaUser = (BoaUser) arg;
|
||||||
|
} else if (arg instanceof UserSysRole) {
|
||||||
|
userSysRole = (UserSysRole) arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 参数缺失时,优先从框架静态持有者 BoaUserContext 取身份(等价于原 BoaUser 参数解析器),
|
||||||
|
// 再回退到请求属性 / currentrole,确保去掉方法参数后仍能正确填充 UserContext。
|
||||||
|
if (boaUser == null) {
|
||||||
|
try {
|
||||||
|
boaUser = BoaUserContext.get();
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
boaUser = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HttpServletRequest request = getCurrentHttpRequest();
|
||||||
|
if (request != null) {
|
||||||
|
if (boaUser == null) {
|
||||||
|
boaUser = resolveBoaUserFromRequest(request);
|
||||||
|
}
|
||||||
|
if (userSysRole == null) {
|
||||||
|
userSysRole = resolveUserSysRoleFromRequest(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 填充 UserContext
|
||||||
|
populateUserContext(boaUser, userSysRole);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return joinPoint.proceed();
|
||||||
|
} finally {
|
||||||
|
UserContext.clear();
|
||||||
|
log.debug("UserContext cleared for {}", joinPoint.getSignature().toShortString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 currentrole(URL 编码,Header 或 Query 参数)解析 UserSysRole。
|
||||||
|
*/
|
||||||
|
private UserSysRole resolveUserSysRoleFromRequest(HttpServletRequest request) {
|
||||||
|
String raw = request.getHeader("currentrole");
|
||||||
|
boolean fromQuery = false;
|
||||||
|
if (raw == null) {
|
||||||
|
raw = request.getParameter("currentrole");
|
||||||
|
fromQuery = true;
|
||||||
|
}
|
||||||
|
if (raw == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
String decoded = fromQuery ? raw : URLDecoder.decode(raw, StandardCharsets.UTF_8.name());
|
||||||
|
return MAPPER.readValue(decoded, UserSysRole.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解析 currentrole 失败: {}", e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 request attribute(外部框架注入的 BoaUser)回退解析。
|
||||||
|
* 如需要时也可改为从某个固定 Header 解析,请按实际接入方式调整。
|
||||||
|
*/
|
||||||
|
private BoaUser resolveBoaUserFromRequest(HttpServletRequest request) {
|
||||||
|
for (String key : BOA_USER_ATTR_KEYS) {
|
||||||
|
Object attr = request.getAttribute(key);
|
||||||
|
if (attr instanceof BoaUser) {
|
||||||
|
return (BoaUser) attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpServletRequest getCurrentHttpRequest() {
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
return attributes != null ? attributes.getRequest() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateUserContext(BoaUser boaUser, UserSysRole userSysRole) {
|
||||||
|
if (boaUser != null) {
|
||||||
|
UserContext.setUserId(boaUser.getId());
|
||||||
|
UserContext.setUserName(boaUser.getName() != null ? boaUser.getName() : "unknown");
|
||||||
|
UserContext.setSchId(boaUser.getSchool()==null?null:boaUser.getSchool().getId());
|
||||||
|
log.debug("UserContext set from parameter/session: id={}, name={}", boaUser.getId(), boaUser.getName());
|
||||||
|
} else {
|
||||||
|
UserContext.setUserName("anonymous");
|
||||||
|
log.warn("No BoaUser found, using anonymous");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSysRole != null) {
|
||||||
|
// UserContext.setRoleId(userSysRole.getRoleId());
|
||||||
|
// UserContext.setSchId(userSysRole.getSchId());
|
||||||
|
log.debug("UserContext set roleId={}, schId={}", userSysRole.getRoleId(), userSysRole.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
UserContext.setType(boaUser != null ? boaUser.getType() : null);
|
||||||
|
|
||||||
|
// 超级管理员(TYPE = 1)不绑定具体学校,schId 统一置 0,
|
||||||
|
// 覆盖 currentrole 中可能带入的学校ID,保证数据隔离逻辑对超管一致识别
|
||||||
|
if (UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType())) {
|
||||||
|
UserContext.setSchId(0);
|
||||||
|
log.debug("Super admin detected(TYPE=1), force schId = 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
String clientIp = OtherUtil.getClientIp();
|
||||||
|
UserContext.setIp(clientIp);
|
||||||
|
log.debug("Client IP set: {}", clientIp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.yunhai.bschclassmanage.aspect;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.annotation.OperationLog;
|
||||||
|
import com.yunhai.bschclassmanage.entity.OperationLogRecord;
|
||||||
|
import com.yunhai.bschclassmanage.service.ILogService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.LogContextHolder;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.expression.EvaluationContext;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.expression.ExpressionParser;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(2)
|
||||||
|
public class OperationLogAspect {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ILogService logService;
|
||||||
|
|
||||||
|
private final ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
|
||||||
|
|
||||||
|
@Around("@annotation(operationLog)")
|
||||||
|
public Object logAround(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
|
||||||
|
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||||
|
Method method = signature.getMethod();
|
||||||
|
Object[] args = joinPoint.getArgs();
|
||||||
|
|
||||||
|
// 从 UserContext 获取用户信息(由 ControllerAspect 设置)
|
||||||
|
String ip = UserContext.getIp();
|
||||||
|
String operator = UserContext.getUserName();
|
||||||
|
Integer userId = UserContext.getUserId();
|
||||||
|
Integer schId = UserContext.getSchId();
|
||||||
|
|
||||||
|
Object result = null;
|
||||||
|
String content = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 先执行业务方法(内部会调用 LogContextHolder.setDescription)
|
||||||
|
result = joinPoint.proceed();
|
||||||
|
|
||||||
|
// 2. 业务方法执行后,尝试获取动态描述
|
||||||
|
String dynamicDesc = LogContextHolder.getDescription();
|
||||||
|
if (StringUtils.hasText(dynamicDesc)) {
|
||||||
|
content = dynamicDesc;
|
||||||
|
} else {
|
||||||
|
// 无动态描述,则解析 SpEL 模板(此时 result 可用于 #result)
|
||||||
|
content = resolveDescription(operationLog.description(), method, args, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
// 3. 清理 ThreadLocal(在业务方法执行后)
|
||||||
|
LogContextHolder.clear();
|
||||||
|
|
||||||
|
// 4. 保存日志(确保 content 非空)
|
||||||
|
if (content != null) {
|
||||||
|
saveLogAsync(ip, operator, userId, schId, operationLog.module(), content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析日志描述:优先从 ThreadLocal 获取动态描述,否则解析 SpEL 模板
|
||||||
|
*/
|
||||||
|
private String resolveDescription(String template, Method method, Object[] args, Object result) {
|
||||||
|
// 优先从 ThreadLocal 获取动态描述
|
||||||
|
String dynamicDesc = LogContextHolder.getDescription();
|
||||||
|
if (StringUtils.hasText(dynamicDesc)) {
|
||||||
|
return dynamicDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有动态描述,则解析 SpEL
|
||||||
|
if (!StringUtils.hasText(template)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
EvaluationContext context = new StandardEvaluationContext();
|
||||||
|
String[] paramNames = discoverer.getParameterNames(method);
|
||||||
|
if (paramNames != null) {
|
||||||
|
for (int i = 0; i < paramNames.length; i++) {
|
||||||
|
context.setVariable(paramNames[i], args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result != null) {
|
||||||
|
context.setVariable("result", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
org.springframework.expression.common.TemplateParserContext parserContext =
|
||||||
|
new org.springframework.expression.common.TemplateParserContext("#{", "}");
|
||||||
|
Expression exp = parser.parseExpression(template, parserContext);
|
||||||
|
return exp.getValue(context, String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Async
|
||||||
|
public void saveLogAsync(String ip,String operator,Integer operatorId,Integer schId, String module, String content) {
|
||||||
|
try { OperationLogRecord log = new OperationLogRecord();
|
||||||
|
log.setOperator(operator);
|
||||||
|
log.setOperatorId(operatorId);
|
||||||
|
log.setIp(ip);
|
||||||
|
log.setSchId(schId);
|
||||||
|
log.setModule(module);
|
||||||
|
log.setContent(content);
|
||||||
|
log.setOperateTime(LocalDateTime.now());
|
||||||
|
logService.save(log);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(); // 生产环境建议用日志输出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package com.yunhai.bschclassmanage.aspect;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.yunhai.bschclassmanage.annotation.SyncOpLog;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SyncLog;
|
||||||
|
import com.yunhai.bschclassmanage.enums.SyncDataType;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISyncLogService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.SensitiveDataUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.SyncLogRetryContext;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.reflect.MethodSignature;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步调用日志切面。
|
||||||
|
* 拦截所有标注 @SyncLog 的方法(当前仅 SyncUserBaseService),
|
||||||
|
* 统一采集:枚举类型 / 大类(Sync-Send) / 类名.方法名 / 操作人 / 学校 / IP / 脱敏入参 / 异常,
|
||||||
|
* 并在 finally 中异步落库(不影响主流程、异常照常抛出)。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(10)
|
||||||
|
public class SyncLogAspect {
|
||||||
|
|
||||||
|
private static final int MAX_ERROR_MSG = 2000;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISyncLogService syncLogService;
|
||||||
|
|
||||||
|
@Around("@annotation(syncLog)")
|
||||||
|
public Object around(ProceedingJoinPoint pjp,SyncOpLog syncLog) throws Throwable {
|
||||||
|
SyncDataType dataType = syncLog.value();
|
||||||
|
String classMethod = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
|
||||||
|
String jsonData = buildJsonData(pjp);
|
||||||
|
|
||||||
|
SyncLog entity = new SyncLog();
|
||||||
|
// 枚举类型 key/name
|
||||||
|
entity.setSyncDataTypeKey(dataType.getKey());
|
||||||
|
String typeName = dataType.getName();
|
||||||
|
if (SyncLogRetryContext.isRetry()) {
|
||||||
|
// 重试重放时,在同步类型名上追加"(重试)"标记,便于与首次调用区分
|
||||||
|
typeName = (typeName == null ? "" : typeName) + "(重试)";
|
||||||
|
}
|
||||||
|
entity.setSyncDataTypeName(typeName);
|
||||||
|
// 大类:Send / Sync(由 key 前缀推导)
|
||||||
|
boolean isSend = dataType.getKey() != null && dataType.getKey().startsWith("Send");
|
||||||
|
entity.setSyncType(isSend ? "Send" : "Sync");
|
||||||
|
entity.setSyncTypeName(isSend ? "推送" : "同步");
|
||||||
|
|
||||||
|
entity.setClassMethod(classMethod);
|
||||||
|
entity.setUserId(UserContext.getUserId());
|
||||||
|
entity.setUserName(UserContext.getUserName());
|
||||||
|
entity.setSchId(UserContext.getSchId());
|
||||||
|
entity.setRequestIp(StringUtils.hasText(UserContext.getIp())
|
||||||
|
? UserContext.getIp() : OtherUtil.getClientIp());
|
||||||
|
entity.setJsonData(jsonData);
|
||||||
|
|
||||||
|
Object result;
|
||||||
|
try {
|
||||||
|
result = pjp.proceed();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
String msg = t.getMessage();
|
||||||
|
if (msg == null || msg.trim().isEmpty()) {
|
||||||
|
msg = t.getClass().getName();
|
||||||
|
}
|
||||||
|
entity.setErrorMsg(truncate(msg, MAX_ERROR_MSG));
|
||||||
|
entity.setStatus(0);
|
||||||
|
syncLogService.saveAsync(entity);
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
entity.setStatus(1);
|
||||||
|
syncLogService.saveAsync(entity);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将方法参数按"参数名->值"序列化为 JSON,并用 SensitiveDataUtil 脱敏 pwd/idCard/phone 等。
|
||||||
|
*/
|
||||||
|
private String buildJsonData(ProceedingJoinPoint pjp) {
|
||||||
|
try {
|
||||||
|
MethodSignature ms = (MethodSignature) pjp.getSignature();
|
||||||
|
String[] names = ms.getParameterNames();
|
||||||
|
Object[] args = pjp.getArgs();
|
||||||
|
if (names == null || args == null) return "";
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
for (int i = 0; i < args.length && i < names.length; i++) {
|
||||||
|
map.put(names[i], args[i]);
|
||||||
|
}
|
||||||
|
return SensitiveDataUtil.mask(JSON.toJSONString(map));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String truncate(String s, int max) {
|
||||||
|
return s != null && s.length() > max ? s.substring(0, max) : s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
package com.yunhai.bschclassmanage.aspect;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SysOperationLog;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISysOperationLogService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.GzipUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OperationLogResolver;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.SensitiveDataUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.SyncLogRetryContext;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.apistd.ApiResponse;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||||
|
import com.yunhai.platform.utils.exception.IErrorCode;
|
||||||
|
import com.yunhai.platform.utils.http.ApiResult;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统审计日志切面(双轨之审计轨)
|
||||||
|
* - 全量拦截 controller 包所有方法,不依赖注解
|
||||||
|
* - 排除日志查询控制器自身(防递归)
|
||||||
|
* - 与业务日志切面 OperationLogAspect(Order 2) 物理隔离,互不影响
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Order(3)
|
||||||
|
public class SysOperationLogAspect {
|
||||||
|
|
||||||
|
/** 排除的控制器(日志查询自身,防递归刷屏) */
|
||||||
|
private static final List<String> EXCLUDE_CONTROLLERS = Arrays.asList(
|
||||||
|
"com.yunhai.bschclassmanage.controller.api.LogController", // 业务日志查询
|
||||||
|
"com.yunhai.bschclassmanage.controller.api.SysOperationLogController" // 审计日志查询
|
||||||
|
);
|
||||||
|
private static final int DEFAULT_MAX_RESPONSE_SIZE = 10240;
|
||||||
|
private static final int MAX_ERROR_MSG = 8000;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysOperationLogService sysOperationLogService;
|
||||||
|
|
||||||
|
@Around("execution(* com.yunhai.bschclassmanage.controller..*.*(..))")
|
||||||
|
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||||
|
// 1. 排除日志控制器
|
||||||
|
String declType = point.getSignature().getDeclaringTypeName();
|
||||||
|
if (EXCLUDE_CONTROLLERS.contains(declType)) {
|
||||||
|
return point.proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServletRequest request = getRequest();
|
||||||
|
String httpMethod = request != null ? request.getMethod() : "";
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
SysOperationLog entity = buildEntity(point, request, httpMethod);
|
||||||
|
|
||||||
|
Object result = null;
|
||||||
|
try {
|
||||||
|
result = point.proceed();
|
||||||
|
entity.setStatusCode(resolveSuccessCode(result));
|
||||||
|
fillResponse(entity, result, DEFAULT_MAX_RESPONSE_SIZE);
|
||||||
|
return result;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
entity.setStatusCode(resolveErrorCode(e));
|
||||||
|
entity.setErrorMsg(buildErrorMsg(e));
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
entity.setCostTime(System.currentTimeMillis() - start);
|
||||||
|
sysOperationLogService.saveAsync(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysOperationLog buildEntity(ProceedingJoinPoint point, HttpServletRequest request, String httpMethod) {
|
||||||
|
SysOperationLog e = new SysOperationLog();
|
||||||
|
e.setCreateTime(LocalDateTime.now());
|
||||||
|
|
||||||
|
// 用户信息(来自 UserContext,由 ControllerUserContextAspect Order1 已填充)
|
||||||
|
e.setUserId(UserContext.getUserId());
|
||||||
|
e.setUserName(StringUtils.hasText(UserContext.getUserName()) ? UserContext.getUserName() : "anonymous");
|
||||||
|
e.setSchId(UserContext.getSchId());
|
||||||
|
e.setRequestIp(StringUtils.hasText(UserContext.getIp()) ? UserContext.getIp() : OtherUtil.getClientIp());
|
||||||
|
|
||||||
|
String uri = request != null ? request.getRequestURI() : "";
|
||||||
|
String methodName = point.getSignature().getName();
|
||||||
|
e.setRequestUri(uri);
|
||||||
|
e.setRequestMethod(httpMethod);
|
||||||
|
e.setClassMethod(point.getTarget().getClass().getName() + "." + methodName);
|
||||||
|
e.setLogLevel(OperationLogResolver.resolveLevel(httpMethod, uri, methodName).getCode());
|
||||||
|
String opType = OperationLogResolver.resolveOperationType(httpMethod, uri, methodName);
|
||||||
|
if (SyncLogRetryContext.isRetry()) {
|
||||||
|
// 重试重放时,在操作类型上追加"(重试)"标记,便于与首次调用区分
|
||||||
|
opType = (opType == null ? "" : opType) + "(重试)";
|
||||||
|
}
|
||||||
|
e.setOperationType(opType);
|
||||||
|
if (request != null) {
|
||||||
|
e.setUserAgent(request.getHeader("User-Agent"));
|
||||||
|
e.setRequestParams(SensitiveDataUtil.mask(buildRequestParams(point, request)));
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
if (request != null && "GET".equalsIgnoreCase(request.getMethod())) {
|
||||||
|
String qs = request.getQueryString();
|
||||||
|
if (StringUtils.hasText(qs)) return qs;
|
||||||
|
}
|
||||||
|
Object[] args = point.getArgs();
|
||||||
|
if (args == null || args.length == 0) return "";
|
||||||
|
List<Object> filtered = new ArrayList<>();
|
||||||
|
for (Object arg : args) {
|
||||||
|
if (arg == null) continue;
|
||||||
|
if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse
|
||||||
|
|| arg instanceof HttpSession) continue;
|
||||||
|
filtered.add(arg);
|
||||||
|
}
|
||||||
|
return filtered.isEmpty() ? "" : JSON.toJSONString(filtered);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillResponse(SysOperationLog e, Object result, int max) {
|
||||||
|
if (result == null) return;
|
||||||
|
try {
|
||||||
|
String resp = SensitiveDataUtil.mask(JSON.toJSONString(result));
|
||||||
|
if (resp.length() > max) resp = resp.substring(0, max) + "...[截断]";
|
||||||
|
e.setResponseData(GzipUtil.compress(resp));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.warn("审计日志响应序列化失败, uri={}", e.getRequestUri(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功路径:提取全局返回对象的业务状态码。
|
||||||
|
* - Controller 直接返回 ApiResponse / ApiResult 时取其 code;
|
||||||
|
* - 其余(普通对象 / void / null)由平台 ApiResponseAdvice 统一包装为 success,code = SUCCESS(0)。
|
||||||
|
*/
|
||||||
|
private int resolveSuccessCode(Object result) {
|
||||||
|
if (result instanceof ApiResponse) {
|
||||||
|
return ((ApiResponse<?>) result).getCode();
|
||||||
|
}
|
||||||
|
if (result instanceof ApiResult) {
|
||||||
|
return ((ApiResult<?>) result).getCode();
|
||||||
|
}
|
||||||
|
return ErrorCode.SUCCESS.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常路径:从业务异常提取错误码,兜底 INTERNAL_SERVER_ERROR。
|
||||||
|
* DException.getCode() 返回 IErrorCode(可能为 null),需二次取 int code。
|
||||||
|
*/
|
||||||
|
private int resolveErrorCode(Throwable e) {
|
||||||
|
if (e instanceof DException) {
|
||||||
|
IErrorCode ec = ((DException) e).getCode();
|
||||||
|
if (ec != null) {
|
||||||
|
return ec.getCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrorCode.INTERNAL_SERVER_ERROR.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpServletRequest getRequest() {
|
||||||
|
ServletRequestAttributes a = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
return a != null ? a.getRequest() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildErrorMsg(Throwable e) {
|
||||||
|
String msg = e.getMessage();
|
||||||
|
String head = (msg == null || msg.trim().isEmpty()) ? e.getClass().getName() : msg;
|
||||||
|
return truncate(head + System.lineSeparator() + ExceptionUtils.getStackTrace(e), MAX_ERROR_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String truncate(String s, int max) {
|
||||||
|
return s != null && s.length() > max ? s.substring(0, max) : s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.yunhai.bschclassmanage.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync // 启用异步处理
|
||||||
|
public class AsyncConfig {
|
||||||
|
|
||||||
|
@Bean(name = "logExecutor")
|
||||||
|
public Executor logExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||||
|
executor.setCorePoolSize(2); // 核心线程数
|
||||||
|
executor.setMaxPoolSize(5); // 最大线程数
|
||||||
|
executor.setQueueCapacity(100); // 任务队列容量
|
||||||
|
executor.setThreadNamePrefix("log-"); // 线程名称前缀
|
||||||
|
executor.initialize(); // 初始化
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增:审计日志异步池(独立,避免与业务日志互相挤压;量大所以池更大) */
|
||||||
|
@Bean(name = "auditLogExecutor")
|
||||||
|
public Executor auditLogExecutor() {
|
||||||
|
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
|
||||||
|
ex.setCorePoolSize(4);
|
||||||
|
ex.setMaxPoolSize(16);
|
||||||
|
ex.setQueueCapacity(2000);
|
||||||
|
ex.setThreadNamePrefix("audit-log-");
|
||||||
|
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); // 队列满丢弃,不拖垮主流程
|
||||||
|
ex.initialize();
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.yunhai.bschclassmanage.config;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
public enum Config {
|
||||||
|
|
||||||
|
Inst;
|
||||||
|
|
||||||
|
public static final String API_PATH = "/api";
|
||||||
|
public static final String MOBILEAPI_PATH = "/mobiapi";
|
||||||
|
public static final String OAPI = "/oapi";
|
||||||
|
|
||||||
|
@Value("${FILE_WEB_PATH}")
|
||||||
|
public String FILE_WEB_PATH;
|
||||||
|
|
||||||
|
@Value("${FILE_PATH}")
|
||||||
|
public String FILE_PATH;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String getString(String key)
|
||||||
|
{
|
||||||
|
ResourceBundle resource = ResourceBundle.getBundle("config");
|
||||||
|
return resource.getString(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt(String key)
|
||||||
|
{
|
||||||
|
String value = getString(key);
|
||||||
|
return Integer.parseInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.yunhai.bschclassmanage.config;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.interceptor.UserContextInterceptor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class DWebMvcConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserContextInterceptor userContextInterceptor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
|
registry.addInterceptor(userContextInterceptor).addPathPatterns("/**");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.yunhai.bschclassmanage.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author luona
|
||||||
|
* @date 2021-02-22 10:31
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class FileConfig {
|
||||||
|
|
||||||
|
@Value("${FILE_PATH}")
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Value("${FILE_WEB_PATH}")
|
||||||
|
private String webPath;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package com.yunhai.bschclassmanage.config;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.parser.ParserConfig;
|
||||||
|
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.cache.interceptor.KeyGenerator;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.core.RedisOperations;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||||
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author min
|
||||||
|
* @description
|
||||||
|
* @date 2019-07-06
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
// 自动配置
|
||||||
|
@ConditionalOnClass(RedisOperations.class)
|
||||||
|
@EnableConfigurationProperties(RedisProperties.class)
|
||||||
|
public class RedisConfig extends CachingConfigurerSupport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 redis 数据默认过期时间,默认1天
|
||||||
|
* 设置@cacheable 序列化方式
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RedisCacheConfiguration redisCacheConfiguration(){
|
||||||
|
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||||
|
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||||||
|
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(1));
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "redisTemplate")
|
||||||
|
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||||
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||||
|
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||||
|
|
||||||
|
// 使用 FastJsonRedisSerializer(会自动存储 @type 字段)
|
||||||
|
FastJsonRedisSerializer<Object> fastJsonSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||||
|
// 允许反序列化 com.bestsch 包下的类(安全)
|
||||||
|
ParserConfig.getGlobalInstance().addAccept("com.bestsch");
|
||||||
|
|
||||||
|
template.setValueSerializer(fastJsonSerializer);
|
||||||
|
template.setHashValueSerializer(fastJsonSerializer);
|
||||||
|
// key 使用 String 序列化
|
||||||
|
template.setKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setHashKeySerializer(new StringRedisSerializer());
|
||||||
|
template.setConnectionFactory(redisConnectionFactory);
|
||||||
|
|
||||||
|
log.info("RedisTemplate value serializer: {}", fastJsonSerializer.getClass());
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义缓存key生成策略
|
||||||
|
* 使用方法 @Cacheable(keyGenerator="keyGenerator")
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
public KeyGenerator keyGenerator() {
|
||||||
|
return (target, method, params) -> {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(target.getClass().getName());
|
||||||
|
sb.append(method.getName());
|
||||||
|
for (Object obj : params) {
|
||||||
|
sb.append(JSON.toJSONString(obj).hashCode());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.yunhai.bschclassmanage.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 configuration for the class management service.
|
||||||
|
* The application exposes OpenAPI JSON and Swagger UI endpoints.
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SwaggerConfig {
|
||||||
|
/**
|
||||||
|
* Registers the metadata shown in the generated API documentation.
|
||||||
|
*
|
||||||
|
* @return OpenAPI metadata for this application
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public OpenAPI bschClassOpenAPI() {
|
||||||
|
return new OpenAPI().info(new Info()
|
||||||
|
.title("BschClass OpenAPI") // Documentation title
|
||||||
|
.description("School, class, teacher and student management APIs") // Documentation description
|
||||||
|
.version("1.0.0")); // Documentation version
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class BaseController {
|
||||||
|
/**
|
||||||
|
* 根据请求参数构建PageVO对象,设置当前页和每页大小,并提供默认值。
|
||||||
|
* @param page 页码字符串(从1开始)
|
||||||
|
* @param pageSize 每页大小字符串
|
||||||
|
* @return PageVO对象
|
||||||
|
*/
|
||||||
|
protected PageVO getPageVO(String page, String pageSize) {
|
||||||
|
int defaultPage = 1;
|
||||||
|
int defaultSize = 10;
|
||||||
|
int maxSize = 100; // 可配置
|
||||||
|
|
||||||
|
int current = defaultPage;
|
||||||
|
int size = defaultSize;
|
||||||
|
|
||||||
|
if (StringUtils.isNumeric(page)) {
|
||||||
|
try {
|
||||||
|
current = Integer.parseInt(page);
|
||||||
|
if (current < 1) {
|
||||||
|
current = defaultPage;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// 保持默认
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isNumeric(pageSize)) {
|
||||||
|
try {
|
||||||
|
size = Integer.parseInt(pageSize);
|
||||||
|
if (size < 1) {
|
||||||
|
size = defaultSize;
|
||||||
|
} else if (size > maxSize) {
|
||||||
|
size = maxSize;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// 保持默认
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PageVO pageVO = new PageVO();
|
||||||
|
pageVO.setCurrent(current);
|
||||||
|
pageVO.setPageSize(size);
|
||||||
|
return pageVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全地将字符串转换为Integer,若转换失败返回null。
|
||||||
|
* @param str 待转换字符串
|
||||||
|
* @return Integer值或null
|
||||||
|
*/
|
||||||
|
public static Integer getIntByString(String str) {
|
||||||
|
if (str == null || str.trim().isEmpty() || "null".equalsIgnoreCase(str.trim())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(str.trim());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return null; // 静默失败,不抛异常
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.Handler;
|
||||||
|
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import com.yunhai.platform.utils.exception.ErrorCode;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||||
|
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@RestControllerAdvice
|
||||||
|
public class ValidationExceptionHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兜底 DException:平台 GlobalExceptionHandler 只返回 code/msg,会丢掉 data。
|
||||||
|
* 本项目优先捕获,把业务异常里的 data(如导入错误列表)透传给前端。
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(DException.class)
|
||||||
|
public ResponseEntity<Map<String, Object>> handleDException(DException ex) {
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("code", ex.getCode() != null ? ex.getCode().getCode() : ErrorCode.CUSTOM.getCode());
|
||||||
|
response.put("msg", ex.getMessage());
|
||||||
|
response.put("data", ex.getData());
|
||||||
|
response.put("timeNow", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
return new ResponseEntity<>(response, HttpStatus.OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public ResponseEntity<Map<String, Object>> handleValidationExceptions(MethodArgumentNotValidException ex) {
|
||||||
|
List<String> msgList = new ArrayList<>();
|
||||||
|
ex.getBindingResult().getAllErrors().forEach(error -> {
|
||||||
|
String errorMessage = error.getDefaultMessage();
|
||||||
|
msgList.add(errorMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("code", ErrorCode.ERROR.getCode());
|
||||||
|
response.put("msg", String.join(";", msgList));
|
||||||
|
response.put("data", null);
|
||||||
|
response.put("timeNow", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
|
||||||
|
return new ResponseEntity(response, HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RequestBody 反序列化失败(JSON 格式错 / 字段类型不符 / 未知字段被拒)。
|
||||||
|
* 不捕获会被平台兜底成 code:6 / 内部服务错误,这里把真实原因透出来。
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||||
|
public ResponseEntity<Map<String, Object>> handleNotReadable(HttpMessageNotReadableException ex) {
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("code", ErrorCode.ERROR.getCode());
|
||||||
|
response.put("msg", "请求体(JSON)解析失败: " + (ex.getRootCause() != null ? ex.getRootCause().getMessage() : ex.getMessage()));
|
||||||
|
response.put("data", null);
|
||||||
|
response.put("timeNow", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
return new ResponseEntity(response, HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Content-Type 不是 application/json(如 text/plain、form 表单、缺省),@RequestBody 无法选择转换器。
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
|
||||||
|
public ResponseEntity<Map<String, Object>> handleMediaType(HttpMediaTypeNotSupportedException ex) {
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("code", ErrorCode.ERROR.getCode());
|
||||||
|
response.put("msg", "请求 Content-Type 不被支持: " + ex.getMessage());
|
||||||
|
response.put("data", null);
|
||||||
|
response.put("timeNow", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||||
|
return new ResponseEntity(response, HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.utils.RedisUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存查看接口
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH + "/cache/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class CacheController extends BaseController {
|
||||||
|
|
||||||
|
/** 匹配全部 key 的通配符,禁止用于清空全部 */
|
||||||
|
private static final String ALL_KEYS_PATTERN = "*";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超管校验:非超级管理员直接抛异常阻断
|
||||||
|
*/
|
||||||
|
private void denyIfNotSuperAdmin() {
|
||||||
|
boolean isSuperAdmin = UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType());
|
||||||
|
if (!isSuperAdmin) {
|
||||||
|
throw new DException("无权限:仅超级管理员可执行缓存操作");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 key 查看缓存内容
|
||||||
|
* 返回 key 是否存在、数据类型、剩余过期时间(秒)以及对应的值
|
||||||
|
* 支持 string / hash / list / set / zset 五种类型
|
||||||
|
*
|
||||||
|
* @param key 缓存 key
|
||||||
|
*/
|
||||||
|
@GetMapping("get")
|
||||||
|
public Map<String, Object> getByKey(@RequestParam String key) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
throw new DException("key不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean exists = redisTemplate.hasKey(key);
|
||||||
|
if (exists == null || !exists) {
|
||||||
|
throw new DException("缓存不存在或已过期");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("key", key);
|
||||||
|
result.put("exists", true);
|
||||||
|
String type = redisTemplate.type(key).name().toLowerCase();
|
||||||
|
result.put("type", type);
|
||||||
|
result.put("expire", redisTemplate.getExpire(key, TimeUnit.SECONDS)); // -1 永不过期,-2 不存在
|
||||||
|
|
||||||
|
Object value;
|
||||||
|
switch (type) {
|
||||||
|
case "string":
|
||||||
|
value = redisTemplate.opsForValue().get(key);
|
||||||
|
break;
|
||||||
|
case "hash":
|
||||||
|
value = redisTemplate.opsForHash().entries(key);
|
||||||
|
break;
|
||||||
|
case "list":
|
||||||
|
value = redisTemplate.opsForList().range(key, 0, -1);
|
||||||
|
break;
|
||||||
|
case "set":
|
||||||
|
value = redisTemplate.opsForSet().members(key);
|
||||||
|
break;
|
||||||
|
case "zset":
|
||||||
|
value = redisTemplate.opsForZSet().rangeWithScores(key, 0, -1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.put("value", value);
|
||||||
|
|
||||||
|
// 缓存值大小(字节):用 ValueSerializer 重新序列化得到实际存储体积
|
||||||
|
long size = 0;
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
RedisSerializer<Object> valueSerializer = (RedisSerializer<Object>) redisTemplate.getValueSerializer();
|
||||||
|
if (valueSerializer != null && value != null) {
|
||||||
|
byte[] raw = valueSerializer.serialize(value);
|
||||||
|
size = (raw != null) ? raw.length : 0;
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
result.put("size", size);
|
||||||
|
|
||||||
|
// 可读过期时间(expire 仍为原始秒:-1 永不过期,-2 不存在)
|
||||||
|
long ttl = redisTemplate.getExpire(key, TimeUnit.SECONDS);
|
||||||
|
result.put("expireText", formatTtl(ttl));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将剩余秒数格式化为可读文本
|
||||||
|
*/
|
||||||
|
private String formatTtl(long ttl) {
|
||||||
|
if (ttl == -1) {
|
||||||
|
return "永不过期";
|
||||||
|
}
|
||||||
|
if (ttl == -2) {
|
||||||
|
return "已过期/不存在";
|
||||||
|
}
|
||||||
|
if (ttl < 60) {
|
||||||
|
return ttl + " 秒";
|
||||||
|
}
|
||||||
|
if (ttl < 3600) {
|
||||||
|
return (ttl / 60) + " 分 " + (ttl % 60) + " 秒";
|
||||||
|
}
|
||||||
|
if (ttl < 86400) {
|
||||||
|
return (ttl / 3600) + " 小时 " + ((ttl % 3600) / 60) + " 分";
|
||||||
|
}
|
||||||
|
return (ttl / 86400) + " 天 " + ((ttl % 86400) / 3600) + " 小时";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据模式匹配查询 key 列表(如 school_class_*),方便先找到 key 再查看内容
|
||||||
|
*
|
||||||
|
* @param pattern 匹配模式,默认 * 表示所有 key
|
||||||
|
*/
|
||||||
|
@GetMapping("keys")
|
||||||
|
public Set<String> keys(@RequestParam(required = false, defaultValue = "*") String pattern) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
return redisUtil.keys(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================================ 清除缓存 ================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定 key 的缓存(支持多个 key,逗号分隔)
|
||||||
|
*
|
||||||
|
* @param key 缓存 key,多个用逗号分隔,如 "a,b,c"
|
||||||
|
*/
|
||||||
|
@PostMapping("delete")
|
||||||
|
public Map<String, Object> delete(@RequestParam String key) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
if (StringUtils.isBlank(key)) {
|
||||||
|
throw new DException("key不能为空");
|
||||||
|
}
|
||||||
|
List<String> keys = Arrays.stream(key.split(","))
|
||||||
|
.map(String::trim)
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (keys.isEmpty()) {
|
||||||
|
throw new DException("key不能为空");
|
||||||
|
}
|
||||||
|
long count = redisTemplate.delete(keys);
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("deleted", count);
|
||||||
|
result.put("msg", "已清除 " + count + " 个 key");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据模式匹配批量删除缓存(如 school_class_*)
|
||||||
|
* 注意:生产大库下 keys 会阻塞,仅在明确范围内使用
|
||||||
|
*
|
||||||
|
* @param pattern 匹配模式,不能为 *
|
||||||
|
*/
|
||||||
|
@PostMapping("deletePattern")
|
||||||
|
public Map<String, Object> deletePattern(@RequestParam String pattern) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
if (StringUtils.isBlank(pattern) || ALL_KEYS_PATTERN.equals(pattern.trim())) {
|
||||||
|
throw new DException("禁止用 * 清空全部,请指定明确的 key 前缀");
|
||||||
|
}
|
||||||
|
Set<String> keys = redisUtil.keys(pattern.trim());
|
||||||
|
if (keys == null || keys.isEmpty()) {
|
||||||
|
throw new DException("未匹配到任何 key");
|
||||||
|
}
|
||||||
|
redisTemplate.delete(keys);
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("success", true);
|
||||||
|
result.put("deleted", keys.size());
|
||||||
|
result.put("msg", "已清除 " + keys.size() + " 个 key");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.entity.OperationLogRecord;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ILogService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/log/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class LogController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ILogService logService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("systemSearch")
|
||||||
|
public PageVO<OperationLogRecord> systemSearch(@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return logService.search(UserContext.getSchId(),keyword,true,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("search")
|
||||||
|
public PageVO<OperationLogRecord> search(@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return logService.search(UserContext.getSchId(),keyword,false,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.platform.openapi.base.YschBaseOpenApi;
|
||||||
|
import com.yunhai.platform.utils.model.BoaGroup;
|
||||||
|
import com.yunhai.platform.utils.model.BoaModule;
|
||||||
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH)
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class LoginUserController {
|
||||||
|
|
||||||
|
@GetMapping("GetUserMod")
|
||||||
|
public List<BoaModule> getUserMod(BoaUser authUserWithDept) {
|
||||||
|
Integer schoolId = Optional.ofNullable(authUserWithDept.getSchool())
|
||||||
|
.map(BoaGroup::getId)
|
||||||
|
.orElse(null);
|
||||||
|
return YschBaseOpenApi.getUserModule(authUserWithDept.getId(), schoolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetUserInfo")
|
||||||
|
public BoaUser getUserInfo(BoaUser authUserWithDept) {
|
||||||
|
return authUserWithDept;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否登录:已登录则重定向到运维工作台 /work-view.html(兼容 context-path);
|
||||||
|
* 未登录返回 401(通常 CAS 拦截器会先行 302 到 CAS 登录页)。
|
||||||
|
*/
|
||||||
|
@GetMapping("checkLogin")
|
||||||
|
public void checkLogin(BoaUser authUserWithDept, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
if (authUserWithDept != null) {
|
||||||
|
response.sendRedirect(request.getContextPath() + "/work-view.html");
|
||||||
|
} else {
|
||||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
response.setContentType("application/json;charset=UTF-8");
|
||||||
|
response.getWriter().write("{\"code\":401,\"msg\":\"未登录\"}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("Logout")
|
||||||
|
protected void logout(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
Enumeration<String> names = session.getAttributeNames();
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
System.out.print(names.nextElement() + ",");
|
||||||
|
}
|
||||||
|
session.invalidate();
|
||||||
|
System.out.println("logout over");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.ImportRuleExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.SchClassExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.SchHeightClassExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.BaseSchClassVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.HigherSchClassVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
|
import com.yunhai.bschclassmanage.utils.EasyPoiUtils;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/schclass/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchClassController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchClassService schClassService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicCampusService schDicCampusService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicDivisionService schDicDivisionService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicMajorsService schDicMajorsService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("searcBaseSchClass")
|
||||||
|
public List<BaseSchClassVO> searcBaseSchClass(@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId) {
|
||||||
|
return schClassService.searcBaseSchClass(UserContext.getSchId(),schsystemId,gradeId,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("addBaseSchClass")
|
||||||
|
public void addBaseSchClass(Integer gradeId, Integer number) {
|
||||||
|
schClassService.addBaseSchClass(UserContext.getCurrentUser(),gradeId,number);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("editClassName")
|
||||||
|
public void editClassName(Integer id,String cname) {
|
||||||
|
schClassService.editClassName(UserContext.getCurrentUser(),id,cname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("editClassFirstTeacher")
|
||||||
|
public void editClassfirstTeacher(Integer id,Integer firstTeacherId) {
|
||||||
|
schClassService.editClassFirstTeacher(UserContext.getCurrentUser(),id,firstTeacherId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("editClassSecondTeacher")
|
||||||
|
public void editClassSecondTeacher(Integer id,Integer secondTeacherId) {
|
||||||
|
schClassService.editClassSecondTeacher(UserContext.getCurrentUser(),id,secondTeacherId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("editClassCampus")
|
||||||
|
public void editClassCampus(Integer id,Integer campusId) {
|
||||||
|
schClassService.editClassCampus(UserContext.getCurrentUser(),id,campusId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("searcHigherSchClass")
|
||||||
|
public PageVO<HigherSchClassVO> searcHigherSchClass(@RequestParam(required = false) Integer year,
|
||||||
|
@RequestParam(required = false) Integer campusId,
|
||||||
|
@RequestParam(required = false) Integer divisionId,
|
||||||
|
@RequestParam(required = false) Integer majorsId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schClassService.searcHigherSchClass(UserContext.getSchId(),year,campusId,divisionId,majorsId,keyword,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("saveHigherSchClass")
|
||||||
|
public void addHigherSchClass(@RequestBody SchClass model) {
|
||||||
|
schClassService.saveHigherSchClass(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void deleteSchClass(@PathVariable Integer id) {
|
||||||
|
schClassService.deleteSchClass(UserContext.getCurrentUser(),id,UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> getClassSelect(@RequestParam Integer gradeId) {
|
||||||
|
return schClassService.getClassSelect(UserContext.getSchId(),gradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("selectBySchIdAndGradeId")
|
||||||
|
public List<SelectIntVO> getClassSelect(@RequestParam Integer schId, @RequestParam Integer gradeId) {
|
||||||
|
return schClassService.getClassSelect(schId,gradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("downloadTemplate")
|
||||||
|
public void downloadTemplate(HttpServletResponse response,Integer schId) {
|
||||||
|
String fileName="班级导入模板";
|
||||||
|
List<Map<String, Object>> sheets = new ArrayList<>();
|
||||||
|
|
||||||
|
List<SchClassExcelColumn> classList=new ArrayList<>();
|
||||||
|
{
|
||||||
|
SchClassExcelColumn column=new SchClassExcelColumn();
|
||||||
|
column.setGradeName("示例:初一");
|
||||||
|
column.setClazzName("示例:1班");
|
||||||
|
column.setClazzCName("示例:一班");
|
||||||
|
column.setBzr("示例:张三");
|
||||||
|
classList.add(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> gradeNames=baseSchsystemGradeService.getGradeSelect(schId,null,null)
|
||||||
|
.stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> teaNames=schTeacherService.getSchTeacherList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<ImportRuleExcelColumn> ruleList = new ArrayList<>();
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule1 = new ImportRuleExcelColumn();
|
||||||
|
rule1.setRuleItem("年级");
|
||||||
|
rule1.setDescription("必填");
|
||||||
|
rule1.setContent(String.join("、",gradeNames));
|
||||||
|
ruleList.add(rule1);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule2 = new ImportRuleExcelColumn();
|
||||||
|
rule2.setRuleItem("班级");
|
||||||
|
rule2.setDescription("必填");
|
||||||
|
rule2.setContent("1班、2班、3班~n班");
|
||||||
|
ruleList.add(rule2);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule3 = new ImportRuleExcelColumn();
|
||||||
|
rule3.setRuleItem("班主任、副班主任");
|
||||||
|
rule3.setDescription("选填");
|
||||||
|
rule3.setContent(String.join("、",teaNames));
|
||||||
|
ruleList.add(rule3);
|
||||||
|
|
||||||
|
ExportParams params1 = new ExportParams("班级导入",comSchTreeService.getSchoolName(schId));
|
||||||
|
Map<String, Object> sheet1 = new HashMap<>();
|
||||||
|
sheet1.put("title",params1);
|
||||||
|
sheet1.put("entity", SchClassExcelColumn.class);
|
||||||
|
sheet1.put("data", classList);
|
||||||
|
sheets.add(sheet1);
|
||||||
|
|
||||||
|
ExportParams params2 = new ExportParams("导入规则", "导入规则");
|
||||||
|
|
||||||
|
Map<String, Object> sheet2 = new HashMap<>();
|
||||||
|
sheet2.put("title", params2);
|
||||||
|
sheet2.put("entity", ImportRuleExcelColumn.class);
|
||||||
|
sheet2.put("data", ruleList);
|
||||||
|
sheets.add(sheet2);
|
||||||
|
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(sheets, ExcelType.HSSF);
|
||||||
|
EasyPoiUtils.downLoadExcel(fileName + ".xls", response, workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importClasses")
|
||||||
|
public void importClasses(@RequestPart("file") MultipartFile file) {
|
||||||
|
schClassService.importClasses(UserContext.getCurrentUser(),file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("downloadHeightTemplate")
|
||||||
|
public void downloadHeightTemplate(HttpServletResponse response,Integer schId) {
|
||||||
|
String fileName="班级导入模板";
|
||||||
|
List<Map<String, Object>> sheets = new ArrayList<>();
|
||||||
|
|
||||||
|
List<SchHeightClassExcelColumn> classList=new ArrayList<>();
|
||||||
|
{
|
||||||
|
SchHeightClassExcelColumn column=new SchHeightClassExcelColumn();
|
||||||
|
column.setGradeName("示例:2026级");
|
||||||
|
column.setClazzCode("");
|
||||||
|
column.setClazzName("示例:南校1班");
|
||||||
|
column.setClazzCName("");
|
||||||
|
column.setCampus("示例:南校区");
|
||||||
|
column.setDivistion("示例:信息工程");
|
||||||
|
column.setMajors("示例:软件开发");
|
||||||
|
column.setBzr("示例:张三");
|
||||||
|
classList.add(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
List<String> campusNames=schDicCampusService.getSchDicCampusCacheList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> divisionNames=schDicDivisionService.getSchDicDivisionCacheList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> majorsNames=schDicMajorsService.getSchDicMajorsCacheList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
|
List<String> teaNames=schTeacherService.getSchTeacherList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<ImportRuleExcelColumn> ruleList = new ArrayList<>();
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule1 = new ImportRuleExcelColumn();
|
||||||
|
rule1.setRuleItem("校区");
|
||||||
|
rule1.setDescription("选填");
|
||||||
|
rule1.setContent(String.join("、",campusNames));
|
||||||
|
ruleList.add(rule1);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule2 = new ImportRuleExcelColumn();
|
||||||
|
rule2.setRuleItem("系部");
|
||||||
|
rule2.setDescription("必填");
|
||||||
|
rule2.setContent(String.join("、",divisionNames));
|
||||||
|
ruleList.add(rule2);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule3 = new ImportRuleExcelColumn();
|
||||||
|
rule3.setRuleItem("专业");
|
||||||
|
rule3.setDescription("必填");
|
||||||
|
rule3.setContent(String.join("、",majorsNames));
|
||||||
|
ruleList.add(rule3);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule4 = new ImportRuleExcelColumn();
|
||||||
|
rule4.setRuleItem("班主任");
|
||||||
|
rule4.setDescription("选填");
|
||||||
|
rule4.setContent(String.join("、",teaNames));
|
||||||
|
ruleList.add(rule4);
|
||||||
|
|
||||||
|
ExportParams params1 = new ExportParams("班级导入",comSchTreeService.getSchoolName(schId));
|
||||||
|
Map<String, Object> sheet1 = new HashMap<>();
|
||||||
|
sheet1.put("title",params1);
|
||||||
|
sheet1.put("entity", SchHeightClassExcelColumn.class);
|
||||||
|
sheet1.put("data", classList);
|
||||||
|
sheets.add(sheet1);
|
||||||
|
|
||||||
|
ExportParams params2 = new ExportParams("导入规则", "导入规则");
|
||||||
|
|
||||||
|
Map<String, Object> sheet2 = new HashMap<>();
|
||||||
|
sheet2.put("title", params2);
|
||||||
|
sheet2.put("entity", ImportRuleExcelColumn.class);
|
||||||
|
sheet2.put("data", ruleList);
|
||||||
|
sheets.add(sheet2);
|
||||||
|
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(sheets, ExcelType.HSSF);
|
||||||
|
EasyPoiUtils.downLoadExcel(fileName + ".xls", response, workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importHeightClasses")
|
||||||
|
public void importHeightClasses(@RequestPart("file") MultipartFile file) {
|
||||||
|
schClassService.importHeightClasses(UserContext.getCurrentUser(),file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("backupAllSnapshot")
|
||||||
|
public void backupAllSnapshot() {
|
||||||
|
schClassService.backupAllSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("upgradeAllClasses")
|
||||||
|
public void upgradeAllClasses() {
|
||||||
|
schClassService.upgradeAllClasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.enums.CustomGroupType;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.AddMemberDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SchCustomGroupDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SetLeaderDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.CustomGroupExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.ImportRuleExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchCustomGroupVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
|
import com.yunhai.bschclassmanage.utils.EasyPoiUtils;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
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 javax.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/group/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchCustomGroupController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchCustomGroupService schCustomGroupService; // 使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicSubjectService schDicSubjectService; //使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
|
||||||
|
@GetMapping("getSchCustomGroup")
|
||||||
|
public List<SchCustomGroupVO> getSchCustomGroup(@RequestParam Integer type) {
|
||||||
|
return schCustomGroupService.getSchCustomGroup(UserContext.getSchId(),type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("saveSchCustomGroup")
|
||||||
|
public void saveSchCustomGroup(@Valid @RequestBody SchCustomGroupDTO dto) {
|
||||||
|
schCustomGroupService.saveSchCustomGroup(UserContext.getCurrentUser(),dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("saveMembers")
|
||||||
|
public void saveMembers(@Valid @RequestBody AddMemberDTO dto) {
|
||||||
|
schCustomGroupService.saveMembers(UserContext.getCurrentUser(),dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setLeaders")
|
||||||
|
public void setLeaders(@Valid @RequestBody SetLeaderDTO dto) {
|
||||||
|
schCustomGroupService.setLeaders(UserContext.getCurrentUser(),dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("deleteSchCustomGroup")
|
||||||
|
public void deleteSchCustomGroup(@RequestParam Integer groupId) {
|
||||||
|
schCustomGroupService.deleteSchCustomGroup(UserContext.getCurrentUser(),groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("downloadTemplate")
|
||||||
|
public void downloadTemplate(HttpServletResponse response, Integer schId) {
|
||||||
|
String fileName = "教师分组导入模板";
|
||||||
|
List<Map<String, Object>> sheets = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
List<CustomGroupExcelColumn> list = new ArrayList<>();
|
||||||
|
{
|
||||||
|
CustomGroupExcelColumn column = new CustomGroupExcelColumn();
|
||||||
|
column.setGroupName("示例:语文组");
|
||||||
|
column.setGroupType("示例:年级组");
|
||||||
|
column.setGradeBin("示例:高一年级");
|
||||||
|
column.setGradeBin("示例:语文,数学");
|
||||||
|
column.setLeaderName("示例:张三");
|
||||||
|
column.setMemberName("示例:张三");
|
||||||
|
list.add(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> teaNames=schTeacherService.getSchTeacherList(schId).stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> gradeNames=baseSchsystemGradeService.getGradeSelect(schId,null,null)
|
||||||
|
.stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> subjectNames=schDicSubjectService.getSchSubList(schId,null)
|
||||||
|
.stream().map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> groupNames=CustomGroupType.list().stream()
|
||||||
|
.map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
ExportParams params1 = new ExportParams("自定义组导入",comSchTreeService.getSchoolName(schId));
|
||||||
|
Map<String, Object> sheet1 = new HashMap<>();
|
||||||
|
sheet1.put("title",params1);
|
||||||
|
sheet1.put("entity", CustomGroupExcelColumn.class);
|
||||||
|
sheet1.put("data", list);
|
||||||
|
sheets.add(sheet1);
|
||||||
|
|
||||||
|
List<ImportRuleExcelColumn> ruleList = new ArrayList<>();
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule1 = new ImportRuleExcelColumn();
|
||||||
|
rule1.setRuleItem("组长/组员");
|
||||||
|
rule1.setDescription("多选");
|
||||||
|
rule1.setContent(String.join(",",teaNames));
|
||||||
|
ruleList.add(rule1);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule2 = new ImportRuleExcelColumn();
|
||||||
|
rule2.setRuleItem("年级");
|
||||||
|
rule2.setDescription("多选");
|
||||||
|
rule2.setContent(String.join(",",gradeNames));
|
||||||
|
ruleList.add(rule2);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule3 = new ImportRuleExcelColumn();
|
||||||
|
rule3.setRuleItem("学科");
|
||||||
|
rule3.setDescription("多选");
|
||||||
|
rule3.setContent(String.join(",",subjectNames));
|
||||||
|
ruleList.add(rule3);
|
||||||
|
|
||||||
|
ImportRuleExcelColumn rule4 = new ImportRuleExcelColumn();
|
||||||
|
rule4.setRuleItem("组类型");
|
||||||
|
rule4.setDescription("单选");
|
||||||
|
rule4.setContent(String.join(",",groupNames));
|
||||||
|
ruleList.add(rule4);
|
||||||
|
|
||||||
|
ExportParams params2 = new ExportParams("导入规则", "导入规则");
|
||||||
|
|
||||||
|
Map<String, Object> sheet2 = new HashMap<>();
|
||||||
|
sheet2.put("title", params2);
|
||||||
|
sheet2.put("entity", ImportRuleExcelColumn.class);
|
||||||
|
sheet2.put("data", ruleList);
|
||||||
|
sheets.add(sheet2);
|
||||||
|
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(sheets, ExcelType.HSSF);
|
||||||
|
EasyPoiUtils.downLoadExcel(fileName + ".xls", response, workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("importCustomGroup")
|
||||||
|
public void importCustomGroup(@RequestPart("file") MultipartFile file) {
|
||||||
|
schCustomGroupService.importCustomGroup(UserContext.getCurrentUser(),file);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicCampus;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicCampusService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/campus/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchDicCampusController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicCampusService schDicCampusService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<SchDicCampus> getSchDicCampusCacheList() {
|
||||||
|
return schDicCampusService.getSchDicCampusCacheList(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveSchCampus(@Valid @RequestBody SchDicCampus model) {
|
||||||
|
schDicCampusService.saveSchCampus(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("sort")
|
||||||
|
public void sortSchCampus(@RequestBody List<Integer> ids) {
|
||||||
|
schDicCampusService.sortSchCampus(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delete(@PathVariable Integer id) {
|
||||||
|
schDicCampusService.delete(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> select() {
|
||||||
|
return schDicCampusService.select(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.enums.CourseType;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SchDicCourseDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchDicCourseVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicCourseService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/course/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchDicCourseController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicCourseService schDicCourseService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("search")
|
||||||
|
public PageVO<SchDicCourseVO> search(@RequestParam(required = false) Integer type,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
@RequestParam(required = false) Integer divisionId,
|
||||||
|
@RequestParam(required = false) Integer majorsId,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schDicCourseService.search(UserContext.getSchId(),type,keyword,divisionId,majorsId,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveSchMajors(@Valid @RequestBody SchDicCourseDTO dto) {
|
||||||
|
schDicCourseService.saveSchCourse(UserContext.getCurrentUser(),dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delete(@PathVariable Integer id) {
|
||||||
|
schDicCourseService.delete(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("typeSelect")
|
||||||
|
public List<SelectIntVO> typeSelect() {
|
||||||
|
return CourseType.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicDivision;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicDivisionService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/division/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchDicDivisionController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicDivisionService schDicDivisionService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<SchDicDivision> getSchDicDivisionCacheList() {
|
||||||
|
return schDicDivisionService.getSchDicDivisionCacheList(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveSchDivision(@Valid @RequestBody SchDicDivision model) {
|
||||||
|
schDicDivisionService.saveSchDivision(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("sort")
|
||||||
|
public void sortSchDivision(@RequestBody List<Integer> ids) {
|
||||||
|
schDicDivisionService.sortSchDivision(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delete(@PathVariable Integer id) {
|
||||||
|
schDicDivisionService.delete(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> select() {
|
||||||
|
return schDicDivisionService.select(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicMajors;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicMajorsService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/majors/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchDicMajorsController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicMajorsService schDicMajorsService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<SchDicMajors> getSchDicMajorsList(@RequestParam(required = false)String keyword) {
|
||||||
|
return schDicMajorsService.getSchDicMajorsList(UserContext.getSchId(),keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveSchMajors(@Valid @RequestBody SchDicMajors model) {
|
||||||
|
schDicMajorsService.saveSchMajors(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("sort")
|
||||||
|
public void sortSchMajors(@RequestBody List<Integer> ids) {
|
||||||
|
schDicMajorsService.sortSchMajors(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delete(@PathVariable Integer id) {
|
||||||
|
schDicMajorsService.delete(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> select() {
|
||||||
|
return schDicMajorsService.select(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/grade/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchGradeController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> getGradeSelect() {
|
||||||
|
return baseSchsystemGradeService.getGradeSelect(UserContext.getSchId(),null,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("selectBySchsystemId")
|
||||||
|
public List<SelectIntVO> getGradeSelectBySchsystemId(@RequestParam Integer schsystemId) {
|
||||||
|
return baseSchsystemGradeService.getGradeSelect(UserContext.getSchId(),schsystemId,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("selectBySchId")
|
||||||
|
public List<SelectIntVO> getGradeSelectBySchId(@RequestParam Integer schId) {
|
||||||
|
return baseSchsystemGradeService.getGradeSelect(schId,null,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("selectByMajorsId")
|
||||||
|
public List<SelectIntVO> getGradeByMajorsId(@RequestParam Integer majorsId) {
|
||||||
|
return baseSchsystemGradeService.getGradeByMajorsId(UserContext.getSchId(),majorsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.HistoryClassTeachVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.HistorySchClassVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.HistorySchStudentVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.IStudentClassHistoryService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.WebDataBinder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.beans.PropertyEditorSupport;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/history/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchHistoryController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IStudentClassHistoryService studentClassHistoryService; // 使用接口
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Integer 参数收到的 "null"/空串 统一当作 null,使方法内能进入并触发业务校验,
|
||||||
|
* 而不是在 Spring 类型转换阶段直接抛 MethodArgumentTypeMismatchException。
|
||||||
|
*/
|
||||||
|
@InitBinder
|
||||||
|
public void initBinder(WebDataBinder binder) {
|
||||||
|
binder.registerCustomEditor(Integer.class, new PropertyEditorSupport() {
|
||||||
|
@Override
|
||||||
|
public void setAsText(String text) {
|
||||||
|
String t = (text == null) ? null : text.trim();
|
||||||
|
if (t == null || t.isEmpty() || "null".equalsIgnoreCase(t)) {
|
||||||
|
setValue(null);
|
||||||
|
} else {
|
||||||
|
setValue(Integer.valueOf(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getClass")
|
||||||
|
public HistorySchClassVO GetClassFirst(Integer classId) {
|
||||||
|
if (classId == null || classId <= 0) {
|
||||||
|
throw new DException("班级ID不允许为空");
|
||||||
|
}
|
||||||
|
return studentClassHistoryService.GetClassFirst(UserContext.getSchId(),classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取历史学生信息(逐年倒序)
|
||||||
|
@GetMapping("getHistoryClassStudent")
|
||||||
|
public List<HistorySchStudentVO> getHistoryClassStudent(Integer classId) {
|
||||||
|
if (classId == null || classId <= 0) {
|
||||||
|
throw new DException("班级ID不允许为空");
|
||||||
|
}
|
||||||
|
return studentClassHistoryService.getHistoryClassStudent(UserContext.getSchId(),classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取历史任教信息
|
||||||
|
@GetMapping("getHistoryClassTeach")
|
||||||
|
public List<HistoryClassTeachVO> getHistoryClassTeach(Integer classId) {
|
||||||
|
if (classId == null || classId <= 0) {
|
||||||
|
throw new DException("班级ID不允许为空");
|
||||||
|
}
|
||||||
|
return studentClassHistoryService.getHistoryClassTeach(UserContext.getSchId(),classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过学生stuId获取历史任教信息
|
||||||
|
@GetMapping("getHistoryClassTeachByStuId")
|
||||||
|
public Map<String, Object> getHistoryClassTeachByStuId(Integer stuId) {
|
||||||
|
if (stuId == null || stuId <= 0) {
|
||||||
|
throw new DException("学生ID不允许为空");
|
||||||
|
}
|
||||||
|
return studentClassHistoryService.getHistoryClassTeachByStuId(UserContext.getSchId(),stuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.enums.StuAbnormalStatus;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SchStudentDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.StuAbnormalStatusDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.StuTransferClassDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.ImportRuleExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.StudentExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchStudentVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchClassService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchStudentService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.EasyPoiUtils;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/student/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchStudentController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchStudentService schStudentService; // 使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchClassService schClassService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("baseSchSearch")
|
||||||
|
public PageVO<SchStudentVO> searchBaseSchStudentVO(@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schStudentService.searchBaseSchStudentVO(UserContext.getSchId(),schsystemId,gradeId,classId,keyword,true,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("higherSchSearch")
|
||||||
|
public PageVO<SchStudentVO> searchHigherSchStudentVO(@RequestParam(required = false) Integer year,
|
||||||
|
@RequestParam(required = false) Integer classId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schStudentService.searchHigherSchStudentVO(UserContext.getSchId(),year,classId,keyword,true,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("baseSchAbnormalSearch")
|
||||||
|
public PageVO<SchStudentVO> baseSchAbnormalSearch(@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
if(gradeId==null)
|
||||||
|
{
|
||||||
|
throw new DException("年级ID不允许为空");
|
||||||
|
}
|
||||||
|
if(classId==null||classId<=0)
|
||||||
|
{
|
||||||
|
throw new DException("班级ID不允许为空");
|
||||||
|
}
|
||||||
|
return schStudentService.searchBaseSchStudentVO(UserContext.getSchId(),schsystemId,gradeId,classId,keyword,false,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("higherSchAbnormalSearch")
|
||||||
|
public PageVO<SchStudentVO> higherSchAbnormalSearch(@RequestParam(required = false) Integer year,
|
||||||
|
@RequestParam(required = false) Integer classId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schStudentService.searchHigherSchStudentVO(UserContext.getSchId(),year,classId,keyword,false,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("searchSchClassStudent")
|
||||||
|
public List<SchStudentVO> searchSchClassStudentVO(@RequestParam Integer gradeId,
|
||||||
|
@RequestParam Integer classId) {
|
||||||
|
return schStudentService.searchSchClassStudentVO(UserContext.getSchId(),gradeId,classId,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveStudent(@Valid @RequestBody SchStudentDTO model) {
|
||||||
|
schStudentService.saveStudent(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{ids}")
|
||||||
|
public void deleteStudent(@PathVariable String ids) {
|
||||||
|
schStudentService.deleteStudent(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("abnormal")
|
||||||
|
public List<SelectIntVO> abnormal() {
|
||||||
|
return StuAbnormalStatus.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("transferClass")
|
||||||
|
public void transferClass(@Valid @RequestBody StuTransferClassDTO model) {
|
||||||
|
schStudentService.transferClass(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setAbnormalStatus")
|
||||||
|
public void setAbnormalStatus(@Valid @RequestBody StuAbnormalStatusDTO model) {
|
||||||
|
schStudentService.setAbnormalStatus(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setTransferOut/{ids}")
|
||||||
|
public void setTransferOut(@PathVariable String ids){
|
||||||
|
schStudentService.setTransferOut(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setTransferIn")
|
||||||
|
public void setTransferIn(@Valid @RequestBody StuTransferClassDTO model) {
|
||||||
|
schStudentService.setTransferIn(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("transferOutSchSelect")
|
||||||
|
public List<SelectIntVO> transferOutSchSelect(){
|
||||||
|
return schStudentService.transferOutSchSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("searchTransferOut")
|
||||||
|
public PageVO<SchStudentVO> searchTransferOutStudent(@RequestParam(required = false) Integer schId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schStudentService.searchTransferOutStudent(schId,gradeId,classId,keyword,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("downloadTemplate")
|
||||||
|
public void downloadTemplate(HttpServletResponse response,Integer schId) {
|
||||||
|
String fileName="学生导入模板";
|
||||||
|
List<Map<String, Object>> sheets = new ArrayList<>();
|
||||||
|
|
||||||
|
List<StudentExcelColumn> stuList=new ArrayList<>();
|
||||||
|
{
|
||||||
|
StudentExcelColumn column=new StudentExcelColumn();
|
||||||
|
column.setGradeName("示例:初一");
|
||||||
|
column.setClazzName("示例:1班");
|
||||||
|
column.setStuName("示例:小明");
|
||||||
|
column.setAccount ("示例:430********4321");
|
||||||
|
column.setPassword ("示例:p123456@");
|
||||||
|
column.setIdCard("示例:430********4321");
|
||||||
|
column.setClazzNo("示例:01");
|
||||||
|
column.setGender("示例:男");
|
||||||
|
stuList.add(column);
|
||||||
|
}
|
||||||
|
List<SelectIntVO> gradeList=baseSchsystemGradeService.getGradeSelect(schId,null,null)
|
||||||
|
.stream().collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<SchClass> schClassList=schClassService.getSchClassCacheList(schId);
|
||||||
|
|
||||||
|
List<ImportRuleExcelColumn> ruleList = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
for(SelectIntVO grade:gradeList){
|
||||||
|
ImportRuleExcelColumn rule = new ImportRuleExcelColumn();
|
||||||
|
rule.setRuleItem(grade.getName());
|
||||||
|
rule.setDescription("选择班级:");
|
||||||
|
List<String> clazzNames=schClassList.stream()
|
||||||
|
.filter(s->s.getGradeId().equals(grade.getId()))
|
||||||
|
.map(s->s.getName())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
rule.setContent(clazzNames.isEmpty() ? "暂无班级":String.join("、",clazzNames));
|
||||||
|
ruleList.add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ImportRuleExcelColumn rule = new ImportRuleExcelColumn();
|
||||||
|
rule.setRuleItem("密码");
|
||||||
|
rule.setDescription("验证规则");
|
||||||
|
rule.setContent("长度 8-32;必须同时包含字母、数字、符号;不允许出现连续自然数序列(如 1234、6789)。");
|
||||||
|
ruleList.add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportParams params1 = new ExportParams("学生导入",comSchTreeService.getSchoolName(schId));
|
||||||
|
|
||||||
|
Map<String, Object> sheet1 = new HashMap<>();
|
||||||
|
sheet1.put("title",params1);
|
||||||
|
sheet1.put("entity", StudentExcelColumn.class);
|
||||||
|
sheet1.put("data", stuList);
|
||||||
|
sheets.add(sheet1);
|
||||||
|
|
||||||
|
ExportParams params2 = new ExportParams("导入规则", "导入规则");
|
||||||
|
|
||||||
|
Map<String, Object> sheet2 = new HashMap<>();
|
||||||
|
sheet2.put("title", params2);
|
||||||
|
sheet2.put("entity", ImportRuleExcelColumn.class);
|
||||||
|
sheet2.put("data", ruleList);
|
||||||
|
sheets.add(sheet2);
|
||||||
|
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(sheets, ExcelType.HSSF);
|
||||||
|
EasyPoiUtils.downLoadExcel(fileName + ".xls", response, workbook);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("studentClassNoTemplate")
|
||||||
|
public void studentClassNoTemplate(HttpServletResponse response,Integer schId,
|
||||||
|
@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId){
|
||||||
|
schStudentService.studentClassNoTemplate(response,schId,schsystemId,gradeId,classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importStudents")
|
||||||
|
public void importStudents(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId) {
|
||||||
|
schStudentService.importStudents(UserContext.getCurrentUser(),file,schsystemId,gradeId,classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importStudentClassNo")
|
||||||
|
public void importStudentClassNo(@RequestPart("file") MultipartFile file,
|
||||||
|
@RequestParam(required = false) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId,
|
||||||
|
@RequestParam(required = false) Integer classId) {
|
||||||
|
schStudentService.importStudentClassNo(UserContext.getCurrentUser(),file,schsystemId,gradeId,classId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchDicSubject;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectStrVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicSubjectService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/subject/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchSubjectController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicSubjectService schDicSubjectService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<SchDicSubject> getSchSubList(Integer schSystemId) {
|
||||||
|
return schDicSubjectService.getSchSubList(UserContext.getSchId(),schSystemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveSchSub(@Valid @RequestBody SchDicSubject model) {
|
||||||
|
schDicSubjectService.saveSchSub(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("sort")
|
||||||
|
public void schSubSort(Integer schSystemId, @RequestBody List<String> subIds) {
|
||||||
|
schDicSubjectService.schSubSort(UserContext.getCurrentUser(),subIds,schSystemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delSchSub(@PathVariable Integer id) {
|
||||||
|
schDicSubjectService.delSchSub(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectStrVO> select(@RequestParam(required = false) Integer schSystemId) {
|
||||||
|
return schDicSubjectService.select(UserContext.getSchId(),schSystemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClassTeach;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.*;
|
||||||
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
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 javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/teachs/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchTeachController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchClassTeachService schClassTeachService; //使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchDicSubjectService schDicSubjectService; //使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchClassService schClassService; //使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService; //使用接口
|
||||||
|
|
||||||
|
@GetMapping("search")
|
||||||
|
public SchTeachMapVO getSchTeachMapVO(@RequestParam(required = true) Integer schsystemId,
|
||||||
|
@RequestParam(required = false) Integer gradeId) {
|
||||||
|
return schClassTeachService.getSchTeachMapVO(UserContext.getSchId(),schsystemId,gradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getSchClassTeach")
|
||||||
|
public List<SchTeachMapIdVO> getSchClassTeachMapVO(@RequestParam Integer gradeId,@RequestParam Integer classId) {
|
||||||
|
return schClassTeachService.getSchClassTeachMapVO(UserContext.getSchId(),gradeId,classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveTeach(@Valid @RequestBody SchClassTeach model) {
|
||||||
|
schClassTeachService.saveTeach(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete/{id}")
|
||||||
|
public void delTeachById(@PathVariable Integer id) {
|
||||||
|
schClassTeachService.delTeachById(UserContext.getCurrentUser(),id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delClassTeach")
|
||||||
|
public void delClassTeach(@RequestParam Integer classId) {
|
||||||
|
schClassTeachService.delClassTeach(UserContext.getCurrentUser(),classId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delBatch")
|
||||||
|
public void delBatch(@RequestParam Integer schsystemId, @RequestParam(required = false) Integer gradeId) {
|
||||||
|
schClassTeachService.delBatch(UserContext.getCurrentUser(),schsystemId,gradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("downloadTemplate")
|
||||||
|
public void downloadTemplate(HttpServletResponse response,@RequestParam Integer schId,@RequestParam Integer schsystemId, @RequestParam(required = false) Integer gradeId) throws IOException {
|
||||||
|
|
||||||
|
// 2. 获取科目和班级
|
||||||
|
List<SelectStrVO> subList = schDicSubjectService.select(schId, schsystemId);
|
||||||
|
if (subList == null) subList = Collections.emptyList();
|
||||||
|
List<BaseSchClassVO> schClassList = schClassService.searcBaseSchClass(schId, schsystemId, gradeId,null);
|
||||||
|
if (schClassList == null) schClassList = Collections.emptyList();
|
||||||
|
|
||||||
|
// 3. 创建工作簿
|
||||||
|
Workbook workbook = new HSSFWorkbook(); // 或 XSSFWorkbook
|
||||||
|
Sheet sheet = workbook.createSheet("教师任教导入");
|
||||||
|
|
||||||
|
// 4. 构建表头
|
||||||
|
Row headerRow = sheet.createRow(0);
|
||||||
|
int colIdx = 0;
|
||||||
|
headerRow.createCell(colIdx++).setCellValue("年级");
|
||||||
|
headerRow.createCell(colIdx++).setCellValue("班级");
|
||||||
|
for (SelectStrVO sub : subList) {
|
||||||
|
headerRow.createCell(colIdx++).setCellValue(sub.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 填充数据行
|
||||||
|
int rowIdx = 1;
|
||||||
|
for (BaseSchClassVO clzz : schClassList) {
|
||||||
|
Row row = sheet.createRow(rowIdx++);
|
||||||
|
colIdx = 0;
|
||||||
|
row.createCell(colIdx++).setCellValue(clzz.getGradeName());
|
||||||
|
row.createCell(colIdx++).setCellValue(clzz.getName());
|
||||||
|
for (int i = 0; i < subList.size(); i++) {
|
||||||
|
row.createCell(colIdx++).setCellValue("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 自动调整列宽(可选)
|
||||||
|
for (int i = 0; i < 2 + subList.size(); i++) {
|
||||||
|
sheet.autoSizeColumn(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 下载
|
||||||
|
String fileName = "教师任教导入模板.xls";
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||||
|
workbook.write(response.getOutputStream());
|
||||||
|
workbook.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("export")
|
||||||
|
public void export(HttpServletResponse response,@RequestParam Integer schId,@RequestParam Integer schsystemId, @RequestParam(required = false) Integer gradeId) throws IOException {
|
||||||
|
|
||||||
|
// 2. 获取科目和班级
|
||||||
|
List<SelectStrVO> subList = schDicSubjectService.select(schId, schsystemId);
|
||||||
|
if (subList == null) subList = Collections.emptyList();
|
||||||
|
List<BaseSchClassVO> schClassList = schClassService.searcBaseSchClass(schId, schsystemId, gradeId,null);
|
||||||
|
if (schClassList == null) schClassList = Collections.emptyList();
|
||||||
|
Map<Integer,String> schTeacherMap=schTeacherService.toIdAndNameMap(schId);
|
||||||
|
List<SchClassTeach> schClassTeachList=schClassTeachService.getSchClassTeachCacheList(schId,gradeId,null);
|
||||||
|
|
||||||
|
// 3. 创建工作簿
|
||||||
|
Workbook workbook = new HSSFWorkbook(); // 或 XSSFWorkbook
|
||||||
|
Sheet sheet = workbook.createSheet("教师任教导出");
|
||||||
|
|
||||||
|
// 4. 构建表头
|
||||||
|
Row headerRow = sheet.createRow(0);
|
||||||
|
int colIdx = 0;
|
||||||
|
headerRow.createCell(colIdx++).setCellValue("年级");
|
||||||
|
headerRow.createCell(colIdx++).setCellValue("班级");
|
||||||
|
for (SelectStrVO sub : subList) {
|
||||||
|
headerRow.createCell(colIdx++).setCellValue(sub.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 填充数据行
|
||||||
|
int rowIdx = 1;
|
||||||
|
for (BaseSchClassVO clzz : schClassList) {
|
||||||
|
Row row = sheet.createRow(rowIdx++);
|
||||||
|
colIdx = 0;
|
||||||
|
row.createCell(colIdx++).setCellValue(clzz.getGradeName());
|
||||||
|
row.createCell(colIdx++).setCellValue(clzz.getName());
|
||||||
|
for (SelectStrVO sub:subList) {
|
||||||
|
Optional<SchClassTeach> classTeachOpt= schClassTeachList.stream().filter(s->s.getClassId().equals(clzz.getClassId())&&s.getSubId().equals(sub.getId())).findFirst();
|
||||||
|
row.createCell(colIdx++).setCellValue(classTeachOpt.isPresent()?schTeacherMap.get(classTeachOpt.get().getTeaId()):"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. 自动调整列宽(可选)
|
||||||
|
for (int i = 0; i < 2 + subList.size(); i++) {
|
||||||
|
sheet.autoSizeColumn(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. 下载
|
||||||
|
String fileName = "教师任教导出.xls";
|
||||||
|
response.setContentType("application/vnd.ms-excel");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
|
||||||
|
workbook.write(response.getOutputStream());
|
||||||
|
workbook.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importTeach")
|
||||||
|
public void importTeach(@RequestPart("file") MultipartFile file,@RequestParam Integer schsystemId, @RequestParam(required = false) Integer gradeId) {
|
||||||
|
schClassTeachService.importTeach(UserContext.getCurrentUser(),file,schsystemId,gradeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SchTeacherDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.TeaTransferGroupDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.TeaTransferInGroupDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.excel.TeacherExcelColumn;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchTeacherTOutVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchTeacherVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchTeacherService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.EasyPoiUtils;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/teacher/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchTeacherController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService; // 使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("search")
|
||||||
|
public PageVO<SchTeacherVO> searchSchTeacher(@RequestParam(required = false) Integer groupId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schTeacherService.searchSchTeacher(UserContext.getSchId(),groupId,keyword,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("searchTransferOut")
|
||||||
|
public PageVO<SchTeacherTOutVO> searchTransferOutTeacher(@RequestParam(required = false) Integer schId,
|
||||||
|
@RequestParam(required = false) Integer groupId,
|
||||||
|
@RequestParam(required = false) String keyword,
|
||||||
|
Pageable pageable) {
|
||||||
|
return schTeacherService.searchTransferOutTeacher(schId,groupId,keyword,pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("save")
|
||||||
|
public void saveTeacher(@Valid @RequestBody SchTeacherDTO model) {
|
||||||
|
schTeacherService.saveTeacher(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("moveGroup")
|
||||||
|
public void moveGroup(@Valid @RequestBody TeaTransferGroupDTO model) {
|
||||||
|
schTeacherService.moveGroup(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setStatus")
|
||||||
|
public void setTeacherStatus(String ids,Integer status){
|
||||||
|
schTeacherService.setTeacherStatus(UserContext.getCurrentUser(),ids,status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("delete")
|
||||||
|
public void deleteTeacher(String ids ,Integer groupId) {
|
||||||
|
schTeacherService.deleteTeacher(UserContext.getCurrentUser(),ids,groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("groupSelect") // 当前用户
|
||||||
|
public List<SelectIntVO> toTeacherGroupSelect() {
|
||||||
|
return schTeacherService.toTeacherGroupSelect(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("groupSelectBySchId")
|
||||||
|
public List<SelectIntVO> toTeacherGroupSelect(@RequestParam Integer schId) {
|
||||||
|
return schTeacherService.toTeacherGroupSelect(schId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> toIdAndNameSelect(@RequestParam(required = false) Integer groupId) {
|
||||||
|
return schTeacherService.toIdAndNameSelect(groupId,UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("transferOutSchSelect")
|
||||||
|
public List<SelectIntVO> transferOutSchSelect() {
|
||||||
|
return schTeacherService.transferOutSchSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("setTransferOut/{ids}")
|
||||||
|
public void setTransferOut(@PathVariable String ids){
|
||||||
|
schTeacherService.setTransferOut(UserContext.getCurrentUser(),ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("setTransferIn")
|
||||||
|
public void setTransferIn(@Valid @RequestBody TeaTransferInGroupDTO model) {
|
||||||
|
schTeacherService.setTransferIn(UserContext.getCurrentUser(),model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("downloadTemplate")
|
||||||
|
public void downloadTemplate(HttpServletResponse response) {
|
||||||
|
List<TeacherExcelColumn> list=new ArrayList<>();
|
||||||
|
String fileName="教师导入模板";
|
||||||
|
String titleName ="教师信息导入" ;
|
||||||
|
ExportParams exportParams = new ExportParams(titleName, "");
|
||||||
|
List<SelectIntVO> teaGroupNameList = comSchTreeService.getTeaGroupNameList(UserContext.getSchId(),null);
|
||||||
|
for (SelectIntVO group:teaGroupNameList)
|
||||||
|
{
|
||||||
|
TeacherExcelColumn column=new TeacherExcelColumn();
|
||||||
|
column.setGroupName(group.getName());
|
||||||
|
column.setAccount("");
|
||||||
|
column.setPassword("");
|
||||||
|
column.setTeaName("");
|
||||||
|
column.setIdCard("");
|
||||||
|
column.setTel("");
|
||||||
|
column.setGender("");
|
||||||
|
list.add(column);
|
||||||
|
}
|
||||||
|
Workbook workbook2 = ExcelExportUtil.exportExcel(exportParams, TeacherExcelColumn.class, list);
|
||||||
|
EasyPoiUtils.downLoadExcel(fileName + ".xls", response, workbook2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("importTeachers")
|
||||||
|
public void importTeachers(@RequestPart("file") MultipartFile file) {
|
||||||
|
schTeacherService.importTeachers(UserContext.getCurrentUser(),file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SchSystemTreeVO;
|
||||||
|
import com.yunhai.platform.utils.model.BoaGroup;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/tree/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchTreeController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("getGroupTree")
|
||||||
|
public List<BoaGroup> getGroupTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getGroupTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getTeacherTree")
|
||||||
|
public BoaGroup getTeacherTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getTeacherTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("getSchoolList")
|
||||||
|
public List<SelectIntVO> getSchoolList()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getSchoolList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getGradeTree")
|
||||||
|
public SchSystemTreeVO getGradeTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getGradeTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getClassTree")
|
||||||
|
public SchSystemTreeVO getClassTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getClassTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getClassHistoryTree")
|
||||||
|
public SchSystemTreeVO getClassHistoryTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getClassHistoryTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getHigherSchGradeTree")
|
||||||
|
public SchSystemTreeVO getHigherSchGradeTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getHigherSchGradeTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getHigherSchClassTree")
|
||||||
|
public SchSystemTreeVO getHigherSchClassTree()
|
||||||
|
{
|
||||||
|
return comSchTreeService.getHigherSchClassTree(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("getTeaTree")
|
||||||
|
public BoaGroup getTeaTree(@RequestParam(required = false, defaultValue = "true") Boolean withSub)
|
||||||
|
{
|
||||||
|
return comSchTreeService.getTeaTree(UserContext.getSchId(), withSub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.enums.NodeType;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SendMoveUserGroupDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SendUserGroupDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISendUserBaseService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/usergroup/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchUserGroupController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISendUserBaseService sendUserBaseService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("getNodeType")
|
||||||
|
public List<SelectIntVO> getNodeType() {
|
||||||
|
return NodeType.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("addGroup")
|
||||||
|
public void addGroup(@Valid @RequestBody SendUserGroupDTO groupdto) {
|
||||||
|
sendUserBaseService.addGroup(groupdto.getName(),groupdto.getParentId(),groupdto.getSort(),NodeType.NORMAL,UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("editGroup")
|
||||||
|
public void editGroup(@Valid @RequestBody SendUserGroupDTO groupdto) {
|
||||||
|
sendUserBaseService.editGroup(groupdto.getId(),groupdto.getName(),groupdto.getParentId(),groupdto.getSort(),NodeType.NORMAL,UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("moveGroup")
|
||||||
|
public void moveGroup(@Valid @RequestBody SendMoveUserGroupDTO groupdto) {
|
||||||
|
sendUserBaseService.moveGroup(groupdto.getMoveId(),groupdto.getPid(),UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("deleteGroup")
|
||||||
|
public void deleteGroup(@RequestParam Integer id) {
|
||||||
|
sendUserBaseService.deleteGroup(id,UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.annotation.OperationLog;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.constant.LogModule;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.SchInfoDto;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/school/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchoolController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchInfoService schInfoService;
|
||||||
|
|
||||||
|
@PostMapping("addSchool")
|
||||||
|
@OperationLog(module = LogModule.SCHOOL_SYSTEM, description = "添加学校(初始化)成功")
|
||||||
|
public void addSchool(@Valid @RequestBody SchInfoDto dto) {
|
||||||
|
schInfoService.addSchool(UserContext.getCurrentUser(), dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.annotation.OperationLog;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchBinSchsystem;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserRole;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.AcademicStageSchsystemVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.TreeSelectVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchBinSchsystemService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.LogContextHolder;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/schsystem/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchsystemController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchBinSchsystemService schBinSchsystemService; // 使用接口
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService; // 使用接口
|
||||||
|
/**
|
||||||
|
* 获取学段枚举 + 学制列表
|
||||||
|
* @return 学段分组后的学制列表
|
||||||
|
*/
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<AcademicStageSchsystemVO> getAcademicStageSchsystemList(@RequestParam(required = false) Integer schId) {
|
||||||
|
|
||||||
|
Integer roleId = UserContext.getRoleId();
|
||||||
|
boolean isSuperAdmin = UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType());
|
||||||
|
boolean isAreaAdmin = !isSuperAdmin && UserRole.AREAADMIN.getValue().equals(roleId);
|
||||||
|
|
||||||
|
if (!isSuperAdmin && !isAreaAdmin) {
|
||||||
|
throw new DException("无权操作,仅超级管理员或学校管理员可设置学制");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 确定最终操作的学校ID,并校验
|
||||||
|
Integer targetSchId;
|
||||||
|
if (isAreaAdmin) {
|
||||||
|
// 区域管理员:强制使用自己所属的学校,忽略前端传入的schId
|
||||||
|
targetSchId = UserContext.getSchId();
|
||||||
|
if (targetSchId == null || targetSchId <= 0) {
|
||||||
|
throw new DException("当前学校管理员未关联有效的学校");
|
||||||
|
}
|
||||||
|
} else { // 超管
|
||||||
|
if (schId == null || schId < 0) {
|
||||||
|
throw new DException("学校ID不能为空且必须为正整数");
|
||||||
|
}
|
||||||
|
targetSchId = schId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return schBinSchsystemService.getAcademicStageSchsystemList(targetSchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getType")
|
||||||
|
public Integer getSchType() {
|
||||||
|
return schBinSchsystemService.getSchType(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学校选择学制
|
||||||
|
* @return 学段分组后的学制列表
|
||||||
|
*/
|
||||||
|
@PostMapping("save")
|
||||||
|
@OperationLog(module = "绑定学制")
|
||||||
|
public void saveSchBinSchsystem(@RequestParam(required = false) Integer schId,
|
||||||
|
@RequestParam("schsystemIds") String schsystemIdsStr) {
|
||||||
|
|
||||||
|
UserContext.UserInfo user= UserContext.getCurrentUser();
|
||||||
|
// 2. 角色权限校验
|
||||||
|
Integer roleId = user.getRoleId();
|
||||||
|
boolean isSuperAdmin = UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType());
|
||||||
|
boolean isAreaAdmin =!isSuperAdmin && UserRole.AREAADMIN.getValue().equals(roleId);
|
||||||
|
|
||||||
|
if (!isSuperAdmin && !isAreaAdmin) {
|
||||||
|
throw new DException("无权操作,仅超级管理员或学校管理员可设置学制");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 确定最终操作的学校ID,并校验
|
||||||
|
Integer targetSchId;
|
||||||
|
if (isAreaAdmin) {
|
||||||
|
// 区域管理员:强制使用自己所属的学校,忽略前端传入的schId
|
||||||
|
targetSchId = UserContext.getSchId();
|
||||||
|
if (targetSchId == null || targetSchId <= 0) {
|
||||||
|
throw new DException("当前学校管理员未关联有效的学校");
|
||||||
|
}
|
||||||
|
} else { // 超管
|
||||||
|
if (schId == null || schId <= 0) {
|
||||||
|
throw new DException("学校ID不能为空且必须为正整数");
|
||||||
|
}
|
||||||
|
targetSchId = schId;
|
||||||
|
}
|
||||||
|
String schName= comSchTreeService.getSchoolName(targetSchId);
|
||||||
|
// 4. 转换学制ID数组
|
||||||
|
Integer[] schsystemIds = OtherUtil.convertToArray(schsystemIdsStr);
|
||||||
|
|
||||||
|
List<String> schsystemNames= schBinSchsystemService.selectSchBinSchsystem(targetSchId)
|
||||||
|
.stream().filter(s-> Arrays.asList(schsystemIds).contains(s.getId()))
|
||||||
|
.map(s->s.getName()).collect(Collectors.toList());
|
||||||
|
|
||||||
|
LogContextHolder.setDescription(String.format("为学校 %s 绑定学制:%s", schName,String.join(",",schsystemNames) ));
|
||||||
|
if (schsystemIds == null || schsystemIds.length == 0) {
|
||||||
|
throw new DException("学制ID列表无效");
|
||||||
|
}
|
||||||
|
SchBinSchsystem entity=new SchBinSchsystem();
|
||||||
|
OtherUtil.setBaseEntityValue(user, entity);
|
||||||
|
entity.setSchId(targetSchId);
|
||||||
|
// 5. 调用服务
|
||||||
|
schBinSchsystemService.saveSchBinSchsystem(entity, schsystemIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("select")
|
||||||
|
public List<SelectIntVO> selectSchBinSchsystem() {
|
||||||
|
return schBinSchsystemService.selectSchBinSchsystem(UserContext.getSchId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("selectTree")
|
||||||
|
public List<TreeSelectVO> selectSchsystemTree() {
|
||||||
|
return schBinSchsystemService.selectSchsystemTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SyncLog;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISyncLogService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH + "/synclog/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SyncLogController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISyncLogService syncLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超管校验:非超级管理员直接抛异常阻断(运维工作台仅超级管理员可访问)
|
||||||
|
*/
|
||||||
|
private void denyIfNotSuperAdmin() {
|
||||||
|
boolean isSuperAdmin = UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType());
|
||||||
|
if (!isSuperAdmin) {
|
||||||
|
throw new DException("无权限:仅超级管理员可访问同步日志");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 同步调用日志分页查询;schId 为"所选学校"筛选条件(非登录用户隔离),不传则查全部学校 */
|
||||||
|
@GetMapping("list")
|
||||||
|
public PageVO<SyncLog> list(
|
||||||
|
@RequestParam(required = false) Integer schId,
|
||||||
|
@RequestParam(required = false) String syncType,
|
||||||
|
@RequestParam(required = false) String syncTypeName,
|
||||||
|
@RequestParam(required = false) String classMethod,
|
||||||
|
@RequestParam(required = false) Integer status,
|
||||||
|
@RequestParam(required = false) String userName,
|
||||||
|
Pageable pageable) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
return syncLogService.pageQuery(schId, syncType, syncTypeName,
|
||||||
|
classMethod, status, userName, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 下载某条同步日志原文(优先 jsonData,回退 errorMsg) */
|
||||||
|
@GetMapping("download/{id}")
|
||||||
|
public ResponseEntity<InputStreamResource> download(@PathVariable Long id) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
String data = syncLogService.getDownloadData(id);
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
|
try {
|
||||||
|
headers.add(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=" + new String(("sync-" + id + ".txt").getBytes("gbk"), "iso8859-1"));
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok().headers(headers)
|
||||||
|
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||||
|
.body(new InputStreamResource(bis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重试某条同步/推送调用:按记录中的 classMethod + jsonData 反射重放原始操作 */
|
||||||
|
@PostMapping("retry/{id}")
|
||||||
|
public Map<String, Object> retry(@PathVariable Long id) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
Object result = syncLogService.retry(id);
|
||||||
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("success", true);
|
||||||
|
m.put("message", "重试成功");
|
||||||
|
if (result != null) m.put("data", result);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
+98
@@ -0,0 +1,98 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.controller.BaseController;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SysOperationLog;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.PageVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISysOperationLogService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import com.yunhai.platform.utils.exception.DException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.io.InputStreamResource;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH + "/syslog/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SysOperationLogController extends BaseController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysOperationLogService sysOperationLogService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 超管校验:非超级管理员直接抛异常阻断(运维工作台仅超级管理员可访问)
|
||||||
|
*/
|
||||||
|
private void denyIfNotSuperAdmin() {
|
||||||
|
boolean isSuperAdmin = UserType.SUPER_ADMINISTRATOR.getId().equals(UserContext.getType());
|
||||||
|
if (!isSuperAdmin) {
|
||||||
|
throw new DException("无权限:仅超级管理员可访问接口日志");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 审计日志分页查询;schId 为"所选学校"筛选条件(非登录用户隔离),不传则查全部学校 */
|
||||||
|
@GetMapping("list")
|
||||||
|
public PageVO<SysOperationLog> list(
|
||||||
|
@RequestParam(required = false) Integer schId,
|
||||||
|
@RequestParam(required = false) String uri,
|
||||||
|
@RequestParam(required = false) String method,
|
||||||
|
@RequestParam(required = false) Integer statusCode,
|
||||||
|
@RequestParam(required = false) Integer logLevel,
|
||||||
|
@RequestParam(required = false) String userName,
|
||||||
|
Pageable pageable) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
return sysOperationLogService.pageQuery(schId, uri, method,
|
||||||
|
statusCode, logLevel, userName, pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 下载某条响应原文(GZIP 解压) */
|
||||||
|
@GetMapping("download/{id}")
|
||||||
|
public ResponseEntity<InputStreamResource> download(@PathVariable Long id) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
String data = sysOperationLogService.getResponseData(id);
|
||||||
|
if (data == null) data = "该条审计日志未记录响应数据";
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
|
try {
|
||||||
|
headers.add(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
|
"attachment; filename=" + new String(("audit-" + id + ".txt").getBytes("gbk"), "iso8859-1"));
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok().headers(headers)
|
||||||
|
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||||
|
.body(new InputStreamResource(bis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 查询某条日志的响应原文(GZIP 解压),供详情页伸缩框展示 */
|
||||||
|
@GetMapping("response/{id}")
|
||||||
|
public Map<String, Object> response(@PathVariable Long id) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
String data = sysOperationLogService.getResponseData(id);
|
||||||
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("success", true);
|
||||||
|
m.put("data", data == null ? "该条审计日志未记录响应数据" : data);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重试某条失败的操作:按记录中的 classMethod + requestParams 反射重放原始操作 */
|
||||||
|
@PostMapping("retry/{id}")
|
||||||
|
public Map<String, Object> retry(@PathVariable Long id) {
|
||||||
|
denyIfNotSuperAdmin();
|
||||||
|
Object result = sysOperationLogService.retry(id);
|
||||||
|
Map<String, Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("success", true);
|
||||||
|
m.put("message", "重试成功");
|
||||||
|
if (result != null) m.put("data", result);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseYearTerm;
|
||||||
|
import com.yunhai.bschclassmanage.model.dto.BaseYearTermDTO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.BaseYearTermVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseYearTermService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH+"/yearterm/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SystemYearTermController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBaseYearTermService baseYearTermService; // 使用接口
|
||||||
|
|
||||||
|
@GetMapping("list")
|
||||||
|
public List<BaseYearTermVO> getAllYearTerm() {
|
||||||
|
return baseYearTermService.getAllYearTermVO();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("add")
|
||||||
|
public void createYearTerm(@Valid @RequestBody BaseYearTermDTO dto) {
|
||||||
|
BaseYearTerm entity = new BaseYearTerm();
|
||||||
|
entity.setCreateDate(new Date());
|
||||||
|
entity.setCreateUserId(UserContext.getUserId());
|
||||||
|
BeanUtils.copyProperties(dto, entity);
|
||||||
|
baseYearTermService.createNowYearTerm(UserContext.getCurrentUser(),entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("edit")
|
||||||
|
public void updateYearTerm(@Valid @RequestBody BaseYearTermDTO dto) {
|
||||||
|
BaseYearTerm entity = new BaseYearTerm();
|
||||||
|
entity.setUpdateDate(new Date());
|
||||||
|
entity.setUpdateUserId(UserContext.getUserId());
|
||||||
|
BeanUtils.copyProperties(dto, entity);
|
||||||
|
baseYearTermService.updateYearTerm(UserContext.getCurrentUser(),entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.api;
|
||||||
|
import com.yunhai.bschclassmanage.utils.UserContext;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.platform.openapi.base.YschBaseOpenApi;
|
||||||
|
import com.yunhai.platform.utils.model.BoaGroup;
|
||||||
|
import com.yunhai.platform.utils.model.BoaModule;
|
||||||
|
import com.yunhai.platform.utils.model.BoaUser;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.API_PATH +"/base/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@GetMapping("getUserMod")
|
||||||
|
public List<BoaModule> getUserMod(BoaUser authUserWithDept) {
|
||||||
|
Integer schoolId = Optional.ofNullable(authUserWithDept.getSchool())
|
||||||
|
.map(BoaGroup::getId)
|
||||||
|
.orElse(null);
|
||||||
|
return YschBaseOpenApi.getUserModule(authUserWithDept.getId(), schoolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getUserInfo")
|
||||||
|
public BoaUser getUserInfo(BoaUser authUserWithDept) {
|
||||||
|
return authUserWithDept;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("logout")
|
||||||
|
protected void logout(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
Enumeration<String> names = session.getAttributeNames();
|
||||||
|
while (names.hasMoreElements()) {
|
||||||
|
System.out.print(names.nextElement() + ",");
|
||||||
|
}
|
||||||
|
session.invalidate();
|
||||||
|
System.out.println("logout over");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherGroupRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchInfo;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/** Compatibility endpoints used by BestSchool.IBaseClass.BLL.DbClass consumers. */
|
||||||
|
|
||||||
|
@Tag(name = "DbClass", description = "School class data APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/DbClass/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class DbClassController {
|
||||||
|
@Autowired private ISchInfoService schInfoService;
|
||||||
|
@Autowired private SchTeacherGroupRepository schTeacherGroupRepository;
|
||||||
|
@Autowired private SchTeacherRepository schTeacherRepository;
|
||||||
|
@Autowired private SchInfoRepository schInfoRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetSchteaList")
|
||||||
|
@Operation(summary = "Get school teachers", description = "Returns one row for each active teacher-group membership. A teacher in multiple groups is returned multiple times.")
|
||||||
|
public ResponseEntity<List<Map<String, Object>>> getSchteaList(
|
||||||
|
@Parameter(description = "School ID", required = true, example = "3")
|
||||||
|
@RequestParam("Group") Integer group) {
|
||||||
|
if (group == null || group <= 0) return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
|
||||||
|
SchInfoVO school = schInfoService.GetSchFirst(group);
|
||||||
|
String schSerId = school == null
|
||||||
|
? schInfoRepository.findBySchId(group).map(SchInfo::getSchSerId).orElse(null)
|
||||||
|
: school.getSchSerId();
|
||||||
|
List<SchTeacherGroup> memberships = schTeacherGroupRepository.findBySchIdAndTransferStatus(group, 0);
|
||||||
|
if (memberships == null || memberships.isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
|
||||||
|
List<Integer> teaIds = memberships.stream().map(SchTeacherGroup::getTeaId)
|
||||||
|
.filter(java.util.Objects::nonNull).distinct().collect(Collectors.toList());
|
||||||
|
Map<Integer, SchTeacher> teachers = schTeacherRepository.findByTeaIdIn(teaIds).stream()
|
||||||
|
.collect(Collectors.toMap(SchTeacher::getTeaId, t -> t, (a, b) -> a, LinkedHashMap::new));
|
||||||
|
|
||||||
|
List<Map<String, Object>> result = memberships.stream()
|
||||||
|
.filter(membership -> teachers.get(membership.getTeaId()) != null)
|
||||||
|
.map(membership -> teacherRow(teachers.get(membership.getTeaId()), schSerId,membership.getGroupId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> teacherRow(SchTeacher teacher, String schSerId, Integer groupId) {
|
||||||
|
Map<String, Object> row = new LinkedHashMap<>();
|
||||||
|
row.put("SchSerID", schSerId);
|
||||||
|
row.put("TeaTel", teacher.getTel());
|
||||||
|
row.put("TeaName", teacher.getName());
|
||||||
|
row.put("TeaGender", teacher.getGender());
|
||||||
|
row.put("UserTeaSerID", teacher.getTeaId());
|
||||||
|
row.put("TeaIDCard", teacher.getIdCard());
|
||||||
|
row.put("TeaNo", teacher.getSort());
|
||||||
|
row.put("GroupID", groupId);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Tag(name = "FamilyCompat", description = "FamilyCompat related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/Common/FamCom/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class FamilyCompatController {
|
||||||
|
@PostMapping("GetStuUserFamIDList")
|
||||||
|
@Operation(summary = "getStuUserFamIdList")
|
||||||
|
public ResponseEntity<List<String>> getStuUserFamIdList(@RequestBody(required=false) String stuIds) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
@PostMapping("GetAllStuFamMem")
|
||||||
|
@Operation(summary = "getAllStuFamMem")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> getAllStuFamMem(@RequestBody(required=false) String stuIds) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
final class OaCompatSupport {
|
||||||
|
private OaCompatSupport() { }
|
||||||
|
static List<Integer> ints(String value) {
|
||||||
|
if (value == null || value.trim().isEmpty()) return Collections.emptyList();
|
||||||
|
List<Integer> out = new ArrayList<>();
|
||||||
|
for (String token : value.split(",")) try { out.add(Integer.valueOf(token.trim())); } catch (NumberFormatException ignored) { }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
static List<String> strings(String value) {
|
||||||
|
if (value == null || value.trim().isEmpty()) return Collections.emptyList();
|
||||||
|
List<String> out = new ArrayList<>();
|
||||||
|
for (String token : value.split(",")) if (!token.trim().isEmpty()) out.add(token.trim());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
static Map<String,Object> student(SchStudent s, String schSerId, String classId) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("Account", s.getAccount()); m.put("UserStuSerID", s.getStuId()); m.put("StuName", s.getName());
|
||||||
|
m.put("StuIDCard", s.getIdCard()); m.put("StuSex", s.getGender() == null ? null : String.valueOf(s.getGender()));
|
||||||
|
m.put("StuStatus", s.getStatus() == null ? null : String.valueOf(s.getStatus())); m.put("ClassID", classId);
|
||||||
|
m.put("ClassStuID", s.getStuClassNo()); m.put("GroupID", s.getGroupId()); m.put("StuPhoto", null);
|
||||||
|
m.put("CardID", null); m.put("StuCurrentTel", null); m.put("invitecode", s.getInvitationCode());
|
||||||
|
m.put("SchSerID", schSerId == null ? null : schSerId.toLowerCase(Locale.ROOT)); m.put("Graduated", false); m.put("isjiedu", 0);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
static Map<String,Object> electiveStudent(SchStudent s, String schSerId, String classId) {
|
||||||
|
Map<String,Object> m = student(s, schSerId, classId);
|
||||||
|
m.put("StuSex", s.getGender()); m.put("electiveId", 0); m.put("schoolId", s.getSchId());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
static Map<String,Object> classInfo(SchClass c, String schSerId) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>();
|
||||||
|
m.put("Id", c.getId()); m.put("Name", c.getName()); m.put("OwnerId", c.getSchId()); m.put("Levell", c.getGradeId());
|
||||||
|
m.put("sx", c.getSort()); m.put("SchSerID", schSerId); m.put("ClassID", c.getClassId()); m.put("UserClassID", c.getClassId());
|
||||||
|
m.put("Schooling", null); m.put("MajorCode", null); m.put("ClassCode", c.getCode()); m.put("ClassMotto", null);
|
||||||
|
m.put("ClassName", c.getCname() == null ? c.getName() : c.getCname()); m.put("StartDate", null);
|
||||||
|
m.put("FirstTeaUserID", c.getFirstTeacherId()); m.put("SecondTeaUserID", c.getSecondTeacherId());
|
||||||
|
m.put("UpgradeYear", null); m.put("CurrentIndex", c.getSort()); m.put("CreationTime", c.getCreateDate());
|
||||||
|
m.put("GradtionTime", c.getGraduateDate()); m.put("GreduatedYear", c.getEnrollYear()); m.put("Graduated", Boolean.TRUE.equals(c.getGraduate()));
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
static Map<String,Object> teaching(SchClassTeach t, String schSerId) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>(); m.put("SerID", t.getId()); m.put("SchSerID", schSerId);
|
||||||
|
m.put("UserTeaSerID", t.getTeaId()); m.put("SubID", t.getSubId()); m.put("ClassID", t.getClassId());
|
||||||
|
m.put("UserClassID", t.getClassId()); m.put("CreationTime", t.getCreateDate()); m.put("static", false); return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaTreeVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Tag(name = "SchGroup", description = "SchGroup related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/SchGroup/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchGroupController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchInfoService schInfoService;
|
||||||
|
|
||||||
|
@GetMapping("GetTeaTree")
|
||||||
|
@Operation(summary = "获取学校教师组树(toUser 默认 true 带教师,false 仅返回组骨架;SchSerID 与 schId 二选一)")
|
||||||
|
public ResponseEntity<List<TeaTreeVO>> getTeaTree(@RequestParam(value = "SchSerID", required = false) String SchSerID,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "toUser", required = false, defaultValue = "true") boolean toUser) {
|
||||||
|
Integer resolvedSchId = resolveSchId(schId, SchSerID);
|
||||||
|
if (resolvedSchId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(comSchTreeService.getSchTeaTree(resolvedSchId, toUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetStuTree")
|
||||||
|
@Operation(summary = "获取学校学生树:学校→学段→年级→班级→学生(toUser 默认 true 带学生,false 仅返回组织骨架;SchSerID 与 schId 二选一)")
|
||||||
|
public ResponseEntity<List<TeaTreeVO>> getStuTree(@RequestParam(value = "SchSerID", required = false) String SchSerID,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "toUser", required = false, defaultValue = "true") boolean toUser) {
|
||||||
|
Integer resolvedSchId = resolveSchId(schId, SchSerID);
|
||||||
|
if (resolvedSchId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(comSchTreeService.getSchStuTree(resolvedSchId, toUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析学校ID:支持直接传 schId,或传 SchSerID 反查 schId,二者至少提供一个。
|
||||||
|
*
|
||||||
|
* @param schId 学校内部ID(优先使用)
|
||||||
|
* @param schSerID 学校外部序列号
|
||||||
|
* @return 学校内部ID,参数非法或查不到时返回 null
|
||||||
|
*/
|
||||||
|
private Integer resolveSchId(Integer schId, String schSerID) {
|
||||||
|
if (schId != null) {
|
||||||
|
return schId;
|
||||||
|
}
|
||||||
|
if (schSerID == null || schSerID.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SchInfoVO schInfoVO = schInfoService.GetSchFirst(schSerID);
|
||||||
|
return schInfoVO == null ? null : schInfoVO.getUserSchSerId();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchInfo;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "SchInfo", description = "SchInfo related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/SchInfo/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchInfoController {
|
||||||
|
@Autowired private ISchInfoService schInfoService;
|
||||||
|
@Autowired private SchInfoRepository schInfoRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetSchlist")
|
||||||
|
@Operation(summary = "获取学校列表", description = "根据多个学校 ID 查询学校")
|
||||||
|
public ResponseEntity<List<SchInfoVO>> GetSchlist(@RequestParam(required = false) String SchIDArr) {
|
||||||
|
return ResponseEntity.ok(schInfoService.getSchVOList(SchIDArr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("AllList")
|
||||||
|
@Operation(summary = "获取全部学校列表", description = "查询全部学校")
|
||||||
|
public ResponseEntity<List<SchInfoVO>> AllList() { return ResponseEntity.ok(schInfoService.getSchVOList(null)); }
|
||||||
|
|
||||||
|
@GetMapping("GetSchFirst")
|
||||||
|
@Operation(summary = "获取单个学校校", description = "根据单个学校 ID 查询学校")
|
||||||
|
public ResponseEntity<SchInfoVO> GetSchFirst(@RequestParam(required = false) String SchID) {
|
||||||
|
return ResponseEntity.ok(SchID == null ? null : schInfoService.GetSchFirst(SchID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetUserSchFirst")
|
||||||
|
@Operation(summary = "获取学校", description = "根据用户中心 ID 查询学校")
|
||||||
|
public ResponseEntity<SchInfoVO> GetUserSchFirst(@RequestParam(required = false) Integer UserSchID) {
|
||||||
|
return ResponseEntity.ok(UserSchID == null ? null : schInfoService.GetSchFirst(UserSchID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetUserSchlist")
|
||||||
|
@Operation(summary = "获取学校列表", description = "根据用户中心多个 ID 查询学校")
|
||||||
|
public ResponseEntity<List<SchInfoVO>> GetUserSchlist(@RequestParam(required = false) String UserSchIds) {
|
||||||
|
if (UserSchIds == null || UserSchIds.trim().isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Set<Integer> ids = parseInts(UserSchIds);
|
||||||
|
return ResponseEntity.ok(schInfoRepository.findAll().stream()
|
||||||
|
.filter(s -> ids.contains(s.getId()) || ids.contains(s.getSchId()))
|
||||||
|
.map(this::toVo).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchoolByGroupId")
|
||||||
|
@Operation(summary = "获取学校列表", description = "根据用户中心组 ID 查询学校")
|
||||||
|
public ResponseEntity<List<SchInfoVO>> GetSchoolByGroupId(@RequestParam(required = false) Integer groupId) {
|
||||||
|
if (groupId == null || groupId == 0) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(schInfoRepository.findAll().stream()
|
||||||
|
.filter(s -> Objects.equals(s.getSchId(), groupId)).map(this::toVo).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchoolBySchoolenId")
|
||||||
|
@Operation(summary = "获取学校学制", description = "根据用户中心组 ID 查询学校学制")
|
||||||
|
public ResponseEntity<List<Map<String, Object>>> GetSchoolBySchoolenId(@RequestParam(required = false) Integer groupId) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private SchInfoVO toVo(SchInfo s) {
|
||||||
|
return SchInfoVO.builder().schSerId(s.getSchSerId()).userSchSerId(s.getId()).schName(s.getName()).build();
|
||||||
|
}
|
||||||
|
private Set<Integer> parseInts(String value) {
|
||||||
|
Set<Integer> result = new HashSet<>();
|
||||||
|
for (String token : value.split(",")) try { result.add(Integer.valueOf(token.trim())); } catch (NumberFormatException ignored) { }
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.*;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicSubjectService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "SchSub", description = "SchSub related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/SubInfo/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchSubController {
|
||||||
|
@Autowired private ISchDicSubjectService subjectService;
|
||||||
|
@Autowired private SchInfoRepository schInfoRepository;
|
||||||
|
@Autowired private SchClassTeachRepository teachRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetSchSublist")
|
||||||
|
@Operation(summary = "GetSchSublist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchSublist(@RequestParam(required=false) String SchID, @RequestParam(required=false) Integer schooling, @RequestParam(required=false) Integer gradeId) {
|
||||||
|
if (SchID == null || SchID.trim().isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Optional<SchInfo> school = schInfoRepository.findBySchSerId(SchID);
|
||||||
|
if (!school.isPresent()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(subjectService.getSchSubList(school.get().getSchId(), schooling).stream().filter(this::enabled).map(s -> subject(s, school.get().getSchSerId())).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchIdsSublist")
|
||||||
|
@Operation(summary = "GetSchIdsSublist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchIdsSublist(@RequestParam(required=false) String SchIds) {
|
||||||
|
if (SchIds == null || SchIds.trim().isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
List<String> ids = OaCompatSupport.strings(SchIds);
|
||||||
|
List<Map<String,Object>> out = new ArrayList<>();
|
||||||
|
for (String id : ids) schInfoRepository.findBySchSerId(id).ifPresent(s -> subjectService.getSchSubList(s.getSchId(), null).stream().filter(this::enabled).forEach(sub -> out.add(subject(sub, s.getSchSerId()))));
|
||||||
|
return ResponseEntity.ok(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchTeaSublist")
|
||||||
|
@Operation(summary = "GetSchTeaSublist")
|
||||||
|
public ResponseEntity<List<String>> GetSchTeaSublist(@RequestParam(required=false) String UserTeaSerID) {
|
||||||
|
if (UserTeaSerID == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
try {
|
||||||
|
Integer teaId = Integer.valueOf(UserTeaSerID);
|
||||||
|
List<SchClassTeach> teaches = teachRepository.findAll().stream().filter(t -> Objects.equals(t.getTeaId(), teaId)).collect(Collectors.toList());
|
||||||
|
Set<String> enabledCodes = new HashSet<>();
|
||||||
|
teaches.stream().map(SchClassTeach::getSchId).filter(Objects::nonNull).distinct().forEach(schId -> enabledCodes.addAll(enabledSubjectCodes(schId)));
|
||||||
|
return ResponseEntity.ok(teaches.stream().map(SchClassTeach::getSubId).filter(c -> c != null && enabledCodes.contains(c)).distinct().collect(Collectors.toList()));
|
||||||
|
} catch (NumberFormatException e) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchTeachSublist")
|
||||||
|
@Operation(summary = "GetSchTeachSublist")
|
||||||
|
public ResponseEntity<List<String>> GetSchTeachSublist(@RequestParam(required=false) String SchID) {
|
||||||
|
if (SchID == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Optional<SchInfo> school = schInfoRepository.findBySchSerId(SchID);
|
||||||
|
if (!school.isPresent()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Set<String> enabledCodes = enabledSubjectCodes(school.get().getSchId()).stream().map(c -> c.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());
|
||||||
|
return ResponseEntity.ok(teachRepository.findAll().stream().filter(t -> Objects.equals(t.getSchId(), school.get().getSchId())).map(SchClassTeach::getSubId).filter(Objects::nonNull).map(s -> s.toLowerCase(Locale.ROOT)).filter(enabledCodes::contains).distinct().collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean enabled(SchDicSubject s) { return Boolean.TRUE.equals(s.getEnable()); }
|
||||||
|
|
||||||
|
private Set<String> enabledSubjectCodes(Integer schId) { return subjectService.toEnableIdAndNameMap(schId, null).keySet(); }
|
||||||
|
|
||||||
|
private Map<String,Object> subject(SchDicSubject s, String schSerId) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>(); m.put("SchSerID", schSerId); m.put("SubID", s.getCode() == null ? String.valueOf(s.getId()) : s.getCode()); m.put("SubName", s.getName()); m.put("No", s.getSort()); return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.*;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "Schooling", description = "Schooling related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/Schoolen/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class SchoolingController {
|
||||||
|
@Autowired private ISchInfoService schInfoService;
|
||||||
|
@Autowired private IBaseSchsystemGradeService gradeService;
|
||||||
|
@Autowired private BaseSchsystemGradeRepository gradeRepository;
|
||||||
|
@Autowired private BaseSchsystemRepository schoolingRepository;
|
||||||
|
@Autowired private SchInfoRepository schInfoRepository;
|
||||||
|
@Autowired private SchClassRepository classRepository;
|
||||||
|
@Autowired private SchClassTeachRepository teachingRepository;
|
||||||
|
@Autowired private SchTeacherRepository teacherRepository;
|
||||||
|
@Autowired private SchDicSubjectRepository subjectRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetSchLenLevellist")
|
||||||
|
@Operation(summary = "获取学校学制列表", description = "根据用 SchSerID 查询学校学制")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchLenLevellist(@RequestParam(required=false) String SchSerID) {
|
||||||
|
if (SchSerID == null || SchSerID.trim().isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
SchInfoVOHolder school = findSchool(SchSerID);
|
||||||
|
if (school == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(gradeService.getSchGradeCacheList(school.id, null, null).stream().map(this::grade).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetLevelIdlist")
|
||||||
|
@Operation(summary = "获取学校学制列表", description = "根据用 Schooling 查询学校学制")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetLevelIdlist(@RequestParam(required=false) Integer Schooling) {
|
||||||
|
if (Schooling == null || Schooling == 0) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(gradeRepository.findBySchSystemId(Schooling).stream().map(this::grade).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchLenLevelFirst")
|
||||||
|
@Operation(summary = "获取学校学制列表", description = "根据用 年级id 查询学校学制")
|
||||||
|
public ResponseEntity<Map<String,Object>> GetSchLenLevelFirst(@RequestParam(required=false) String GradeId) {
|
||||||
|
if (GradeId == null) return ResponseEntity.ok(null);
|
||||||
|
try {
|
||||||
|
Integer id = Integer.valueOf(GradeId);
|
||||||
|
return ResponseEntity.ok(gradeRepository.findById(id).map(this::grade).orElse(null));
|
||||||
|
} catch (NumberFormatException e) { return ResponseEntity.ok(null); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchLenlist")
|
||||||
|
@Operation(summary = "获取学校学制长度", description = "根据用 SchSerID 查询学校学制长度")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchLenlist(@RequestParam(required=false) String SchSerID) {
|
||||||
|
if (SchSerID == null || SchSerID.trim().isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
SchInfoVOHolder school = findSchool(SchSerID);
|
||||||
|
if (school == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
List<Integer> ids = gradeService.getSchGradeCacheList(school.id, null, null).stream().map(BaseSchsystemGrade::getSchSystemId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(schoolingRepository.findAllById(ids).stream().map(this::schooling).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetAllClassSubject")
|
||||||
|
@Operation(summary = "获取全部", description = "根据用 SchSerID 查询学校学制长度")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetAllClassSubject(@RequestParam(required=false) Integer schId, @RequestParam(required=false) String schserid, @RequestParam(required=false) String startTime) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String schoolSer(Integer id) { return id == null ? null : schInfoRepository.findBySchId(id).map(SchInfo::getSchSerId).orElse(null); }
|
||||||
|
|
||||||
|
private Map<String,Object> grade(BaseSchsystemGrade g) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>(); m.put("Id", g.getGradeId()); m.put("Name", g.getGradeNickname());
|
||||||
|
m.put("OwnerId", g.getSchSystemId()); m.put("Levell", g.getGradeId()); m.put("code", g.getGradeId()); m.put("sx", g.getGradeId()); return m;
|
||||||
|
}
|
||||||
|
private Map<String,Object> schooling(BaseSchsystem s) {
|
||||||
|
Map<String,Object> m = new LinkedHashMap<>(); m.put("Id", s.getId()); m.put("Name", s.getName()); m.put("FormerName", null); m.put("Type", s.getType()); return m;
|
||||||
|
}
|
||||||
|
private SchInfoVOHolder findSchool(String serId) {
|
||||||
|
return schInfoRepository.findBySchSerId(serId).map(s -> new SchInfoVOHolder(s.getSchId())).orElse(null);
|
||||||
|
}
|
||||||
|
private static final class SchInfoVOHolder { final Integer id; SchInfoVOHolder(Integer id) { this.id=id; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.*;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "StuInfo", description = "StuInfo related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/OAStu/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class StuInfoController {
|
||||||
|
@Autowired private SchStudentRepository studentRepository;
|
||||||
|
@Autowired private SchInfoRepository schoolRepository;
|
||||||
|
@Autowired private SchStudentHistoryRepository historyRepository;
|
||||||
|
@Autowired private SchClassRepository classRepository;
|
||||||
|
@Autowired private BaseSchsystemGradeRepository baseSchsystemGradeRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetAllStulist")
|
||||||
|
@Operation(summary = "GetAllStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetAllStulist() { return ResponseEntity.ok(students(studentRepository.findAll(), null)); }
|
||||||
|
@GetMapping("GetEleAllStulist")
|
||||||
|
@Operation(summary = "GetEleAllStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleAllStulist() { return ResponseEntity.ok(studentRepository.findAll().stream().map(s -> OaCompatSupport.electiveStudent(s, schoolSer(s.getSchId()), String.valueOf(s.getClassId()))).collect(Collectors.toList())); }
|
||||||
|
|
||||||
|
@GetMapping("GetSchStulist")
|
||||||
|
@Operation(summary = "GetSchStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchStulist(@RequestParam(required=false) String schserid, @RequestParam(required=false) String schgroupid) {
|
||||||
|
return ResponseEntity.ok(filter(schserid, schgroupid, null, null));
|
||||||
|
}
|
||||||
|
@GetMapping("GetEleSchStulist")
|
||||||
|
@Operation(summary = "GetEleSchStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchStulist(@RequestParam(required=false) String schserid, @RequestParam(required=false) String schgroupid) {
|
||||||
|
return ResponseEntity.ok(filter(schserid, schgroupid, null, null).stream().map(m -> m).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("GetClaStulist")
|
||||||
|
@Operation(summary = "GetClaStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetClaStulist(@RequestParam(required=false) String ClassID, @RequestParam(required=false) String clagroupid) { return ResponseEntity.ok(filter(null, null, ClassID, clagroupid)); }
|
||||||
|
@GetMapping("GetEleClaStulist")
|
||||||
|
@Operation(summary = "GetEleClaStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleClaStulist(@RequestParam(required=false) String ClassID, @RequestParam(required=false) String clagroupid) { return ResponseEntity.ok(filter(null, null, ClassID, clagroupid)); }
|
||||||
|
|
||||||
|
@GetMapping("GetClaArrStulist")
|
||||||
|
@Operation(summary = "GetClaArrStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetClaArrStulist(@RequestParam(required=false) String ClassIDs, @RequestParam(required=false) String clagroupids) { return ResponseEntity.ok(filterArrays(ClassIDs, clagroupids)); }
|
||||||
|
@GetMapping("GetEleClaArrStulist")
|
||||||
|
@Operation(summary = "GetEleClaArrStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleClaArrStulist(@RequestParam(required=false) String ClassIDs, @RequestParam(required=false) String clagroupids) { return ResponseEntity.ok(filterArrays(ClassIDs, clagroupids)); }
|
||||||
|
|
||||||
|
@GetMapping("GetStuIdslist")
|
||||||
|
@Operation(summary = "GetStuIdslist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetStuIdslist(@RequestParam(required=false) String stuids) {
|
||||||
|
Set<Integer> ids = new HashSet<>(OaCompatSupport.ints(stuids));
|
||||||
|
return ResponseEntity.ok(students(studentRepository.findAll().stream().filter(s -> ids.contains(s.getStuId())).collect(Collectors.toList()), null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按学校+年级直查学生(CampusNotice 推送范围圈人:免逐班聚合) */
|
||||||
|
@GetMapping("GetGradeStulist")
|
||||||
|
@Operation(summary = "GetGradeStulist", description = "按学校+年级查询在校学生(不含已毕业班级)")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetGradeStulist(@RequestParam(required=false) String SchSerID, @RequestParam(required=false) Integer GradeId) {
|
||||||
|
Integer schId = SchSerID == null ? null : schoolRepository.findBySchSerId(SchSerID).map(SchInfo::getSchId).orElse(null);
|
||||||
|
if (schId == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Set<Integer> classIds = activeClassIds(schId, null, GradeId == null ? null : Collections.singleton(GradeId));
|
||||||
|
if (classIds.isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(students(studentRepository.findAll().stream().filter(s -> classIds.contains(s.getClassId())).collect(Collectors.toList()), SchSerID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按学校+学段(学制)直查学生(CampusNotice「学部」级范围一键展开) */
|
||||||
|
@GetMapping("GetSubStulist")
|
||||||
|
@Operation(summary = "GetSubStulist", description = "按学校+学段查询在校学生(不含已毕业班级)")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSubStulist(@RequestParam(required=false) String SchSerID, @RequestParam(required=false) Integer SchSystemId) {
|
||||||
|
Integer schId = SchSerID == null ? null : schoolRepository.findBySchSerId(SchSerID).map(SchInfo::getSchId).orElse(null);
|
||||||
|
if (schId == null || SchSystemId == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
Set<Integer> gradeIds = baseSchsystemGradeRepository.findBySchSystemId(SchSystemId).stream()
|
||||||
|
.map(BaseSchsystemGrade::getGradeId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
Set<Integer> classIds = activeClassIds(schId, gradeIds, null);
|
||||||
|
if (classIds.isEmpty()) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(students(studentRepository.findAll().stream().filter(s -> classIds.contains(s.getClassId())).collect(Collectors.toList()), SchSerID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 学校在读班级 class_id 集合:gradeIds 非空按年级集合过滤,单个 gradeId 传 singleton */
|
||||||
|
private Set<Integer> activeClassIds(Integer schId, Set<Integer> gradeIds, Set<Integer> singleGrade) {
|
||||||
|
return classRepository.findAll().stream()
|
||||||
|
.filter(c -> Objects.equals(c.getSchId(), schId) && !Boolean.TRUE.equals(c.getGraduate()))
|
||||||
|
.filter(c -> (gradeIds == null || gradeIds.contains(c.getGradeId())) && (singleGrade == null || singleGrade.contains(c.getGradeId())))
|
||||||
|
.map(SchClass::getClassId).filter(Objects::nonNull).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetEleStuIdslist")
|
||||||
|
@Operation(summary = "GetEleStuIdslist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleStuIdslist(@RequestParam(required=false) String stuids) { return GetStuIdslist(stuids); }
|
||||||
|
@GetMapping("GetStuUserFamIDList")
|
||||||
|
@Operation(summary = "GetStuUserFamIDList")
|
||||||
|
public ResponseEntity<List<String>> GetStuUserFamIDList(@RequestParam(required=false) String stuids) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
@GetMapping("GetFamStulist")
|
||||||
|
@Operation(summary = "GetFamStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetFamStulist(@RequestParam(required=false) String invitecodes) {
|
||||||
|
Set<String> codes = new HashSet<>(OaCompatSupport.strings(invitecodes));
|
||||||
|
return ResponseEntity.ok(students(studentRepository.findAll().stream().filter(s -> codes.contains(s.getInvitationCode())).collect(Collectors.toList()), null));
|
||||||
|
}
|
||||||
|
@GetMapping("GetStuFamMem")
|
||||||
|
@Operation(summary = "GetAllStuFamMem")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetAllStuFamMem(@RequestParam(required=false) String SchSerID) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
@GetMapping("GetSchBySchIds")
|
||||||
|
@Operation(summary = "GetSchIdsStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchIdsStulist(@RequestParam(required=false) String schserids) {
|
||||||
|
Set<Integer> ids = new HashSet<>(); for (String id : OaCompatSupport.strings(schserids)) schoolRepository.findBySchSerId(id).ifPresent(s -> ids.add(s.getSchId()));
|
||||||
|
return ResponseEntity.ok(students(studentRepository.findAll().stream().filter(s -> ids.contains(s.getSchId())).collect(Collectors.toList()), null));
|
||||||
|
}
|
||||||
|
@GetMapping("GetEleSchIdsStulist")
|
||||||
|
@Operation(summary = "GetEleSchIdsStulist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchIdsStulist(@RequestParam(required=false) String schserids) { return GetSchIdsStulist(schserids); }
|
||||||
|
@GetMapping("GetEleSchBySchIds")
|
||||||
|
@Operation(summary = "GetEleSchBySchIds")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchBySchIds(@RequestParam(required=false) String schserids) { return GetSchIdsStulist(schserids); }
|
||||||
|
@GetMapping("GetStudentsByElectiveId")
|
||||||
|
@Operation(summary = "GetStudentsByElectiveId")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetStudentsByElectiveId(@RequestParam(required=false) Integer electiveIds) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
@GetMapping("getHistoryStudentsBySchoolId")
|
||||||
|
@Operation(summary = "getHistoryStudentsBySchoolId")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> getHistoryStudentsBySchoolId(@RequestParam Integer schoolId, @RequestParam Integer year) {
|
||||||
|
return ResponseEntity.ok(historyRepository.findAll().stream().filter(h -> Objects.equals(h.getSchId(), schoolId) && Objects.equals(h.getYear(), year)).map(this::history).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("getHistoryClass")
|
||||||
|
@Operation(summary = "getHistoryClass")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> getHistoryClass(@RequestParam Integer schoolId, @RequestParam Integer year) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
|
||||||
|
private List<Map<String,Object>> filter(String schserid, String schgroupid, String classId, String classGroupId) {
|
||||||
|
Integer schId = schserid == null ? null : schoolRepository.findBySchSerId(schserid).map(SchInfo::getSchId).orElse(null);
|
||||||
|
Integer cls = firstInt(classId != null ? classId : classGroupId);
|
||||||
|
return students(studentRepository.findAll().stream().filter(s -> (schId == null || Objects.equals(s.getSchId(), schId)) && (cls == null || Objects.equals(s.getClassId(), cls) || Objects.equals(s.getGroupId(), cls))).collect(Collectors.toList()), schserid);
|
||||||
|
}
|
||||||
|
private List<Map<String,Object>> filterArrays(String classIds, String groupIds) {
|
||||||
|
Set<Integer> ids = new HashSet<>(OaCompatSupport.ints(classIds)); ids.addAll(OaCompatSupport.ints(groupIds));
|
||||||
|
return students(studentRepository.findAll().stream().filter(s -> ids.contains(s.getClassId()) || ids.contains(s.getGroupId())).collect(Collectors.toList()), null);
|
||||||
|
}
|
||||||
|
private List<Map<String,Object>> students(List<SchStudent> list, String schserid) { return list.stream().map(s -> OaCompatSupport.student(s, schserid == null ? schoolSer(s.getSchId()) : schserid, String.valueOf(s.getClassId()))).collect(Collectors.toList()); }
|
||||||
|
private String schoolSer(Integer id) { return id == null ? null : schoolRepository.findBySchId(id).map(SchInfo::getSchSerId).orElse(null); }
|
||||||
|
private Integer firstInt(String s) { try { return s == null ? null : Integer.valueOf(s); } catch (Exception e) { return null; } }
|
||||||
|
private Map<String,Object> history(SchStudentHistory h) { Map<String,Object> m = new LinkedHashMap<>(); m.put("stuId", h.getStuId()); m.put("stuName", h.getName()); m.put("classId", h.getClassId()); m.put("className", null); m.put("grade", h.getGradeId()); m.put("name", null); m.put("school_system_id", h.getSchId()); m.put("system_grade", h.getGradeId()); return m; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.*;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import com.yunhai.bschclassmanage.enums.TransferStatus;
|
||||||
|
import com.yunhai.bschclassmanage.service.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "TeaChes", description = "TeaChes related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/TeachInfo/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class TeaChesController {
|
||||||
|
@Autowired private SchClassTeachRepository teachingRepository;
|
||||||
|
@Autowired private SchInfoRepository schoolRepository;
|
||||||
|
@Autowired private SchTeacherGroupRepository teacherGroupRepository;
|
||||||
|
@Autowired private ISchClassService classService;
|
||||||
|
@Autowired private ISchDicSubjectService subjectService;
|
||||||
|
|
||||||
|
@GetMapping("GetSchTeachlist")
|
||||||
|
@Operation(summary = "GetSchTeach")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchTeach(@RequestParam(required=false) String SchID, @RequestParam(required=false) Integer UserTeaSerID) {
|
||||||
|
Integer schId = SchID == null ? null : schoolRepository.findBySchSerId(SchID).map(SchInfo::getSchId).orElse(null);
|
||||||
|
List<SchClassTeach> list = teachingRepository.findAll().stream().filter(t -> (schId == null || Objects.equals(t.getSchId(), schId)) && (UserTeaSerID == null || Objects.equals(t.getTeaId(), UserTeaSerID))).collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(normalFiltered(list).stream().map(t -> OaCompatSupport.teaching(t, schoolSer(t.getSchId()))).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("GetEleSchTeachlist")
|
||||||
|
@Operation(summary = "GetEleSchTeachlist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchTeachlist(@RequestParam(required=false) String SchID, @RequestParam(required=false) Integer UserTeaSerID) { return GetSchTeach(SchID, UserTeaSerID); }
|
||||||
|
@GetMapping("GetSchArrTeachlist")
|
||||||
|
@Operation(summary = "GetSchArrTeach")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchArrTeach(@RequestParam(required=false) String SchIDArr) { return bySchools(SchIDArr); }
|
||||||
|
@GetMapping("GetEleSchArrTeachList")
|
||||||
|
@Operation(summary = "GetEleSchArrTeachList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchArrTeachList(@RequestParam(required=false) String SchIDArr) { return bySchools(SchIDArr); }
|
||||||
|
@GetMapping("GetSchClaTeachlist")
|
||||||
|
@Operation(summary = "GetClassTeach")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetClassTeach(@RequestParam(required=false) String ClassID) {
|
||||||
|
Integer classId = intValue(ClassID);
|
||||||
|
List<SchClassTeach> list = teachingRepository.findAll().stream().filter(t -> classId != null && Objects.equals(t.getClassId(), classId)).collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(normalFiltered(list).stream().map(t -> OaCompatSupport.teaching(t, schoolSer(t.getSchId()))).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("GetEleSchClaTeachlist")
|
||||||
|
@Operation(summary = "GetEleSchClaTeachlist")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchClaTeachlist(@RequestParam(required=false) String ClassID) { return GetClassTeach(ClassID); }
|
||||||
|
@GetMapping("GetElectiveClassByGrade")
|
||||||
|
@Operation(summary = "GetElectiveClassByGrade")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetElectiveClassByGrade(@RequestParam(required=false) Integer schoolId, @RequestParam(required=false) Integer gradeId) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
@PostMapping("GetElectiveClassByTeachers")
|
||||||
|
@Operation(summary = "GetElectiveClassByTeachers")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetElectiveClassByTeachers(@RequestBody(required=false) String teacherIds) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
|
||||||
|
private ResponseEntity<List<Map<String,Object>>> bySchools(String value) {
|
||||||
|
Set<Integer> ids = new HashSet<>(); for (String ser : OaCompatSupport.strings(value)) schoolRepository.findBySchSerId(ser).ifPresent(s -> ids.add(s.getSchId()));
|
||||||
|
List<SchClassTeach> list = teachingRepository.findAll().stream().filter(t -> ids.contains(t.getSchId())).collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(normalFiltered(list).stream().map(t -> OaCompatSupport.teaching(t, schoolSer(t.getSchId()))).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
/** 只保留正常教师(sch_teacher_group 中 transfer_status=转入)、正常班级(未毕业)、启用学科(enable=true)的任教记录,按学校分别过滤 */
|
||||||
|
private List<SchClassTeach> normalFiltered(List<SchClassTeach> teaches) {
|
||||||
|
List<SchClassTeach> out = new ArrayList<>();
|
||||||
|
Map<Integer, List<SchClassTeach>> bySch = new HashMap<>();
|
||||||
|
for (SchClassTeach t : teaches) if (t.getSchId() != null) bySch.computeIfAbsent(t.getSchId(), k -> new ArrayList<>()).add(t);
|
||||||
|
for (Map.Entry<Integer, List<SchClassTeach>> e : bySch.entrySet()) {
|
||||||
|
Integer schId = e.getKey();
|
||||||
|
Set<Integer> teaIds = teacherGroupRepository.findBySchIdAndTransferStatus(schId, TransferStatus.IN.getId()).stream().map(SchTeacherGroup::getTeaId).collect(Collectors.toSet());
|
||||||
|
Set<Integer> classIds = classService.getSchAllClassCacheList(schId).stream().filter(c -> !Boolean.TRUE.equals(c.getGraduate()) && c.getClassId() != null).map(SchClass::getClassId).collect(Collectors.toSet());
|
||||||
|
Set<String> subCodes = subjectService.toEnableIdAndNameMap(schId, null).keySet();
|
||||||
|
for (SchClassTeach t : e.getValue()) if (teaIds.contains(t.getTeaId()) && classIds.contains(t.getClassId()) && t.getSubId() != null && subCodes.contains(t.getSubId())) out.add(t);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
private Integer intValue(String s) { try { return s == null ? null : Integer.valueOf(s); } catch (Exception e) { return null; } }
|
||||||
|
private String schoolSer(Integer id) { return id == null ? null : schoolRepository.findBySchId(id).map(SchInfo::getSchSerId).orElse(null); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherGroupRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserGender;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserRole;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchTeacherService;
|
||||||
|
import com.yunhai.bschclassmanage.utils.OtherUtil;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "Teainfo", description = "Teainfo related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/OATea/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class TeainfoController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherRepository schTeacherRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherGroupRepository schTeacherGroupRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchInfoService schInfoService;
|
||||||
|
|
||||||
|
@GetMapping("GetTeainfo")
|
||||||
|
@Operation(summary = "getTeainfo")
|
||||||
|
public ResponseEntity<TeaInfoVO> getTeainfo(@RequestParam Integer uid) {
|
||||||
|
// 1. 鍙傛暟鏍¢獙
|
||||||
|
if (uid == null) {
|
||||||
|
return ResponseEntity.ok(new TeaInfoVO());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 鐩存帴浣跨敤 uid 鏌ヨ
|
||||||
|
return schTeacherRepository.findByTeaId(uid).stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(teacher -> {
|
||||||
|
fillGroupList(Collections.singletonList(teacher), null);
|
||||||
|
return teacher;
|
||||||
|
})
|
||||||
|
.map(this::convertToTeaInfoVO)
|
||||||
|
.map(ResponseEntity::ok)
|
||||||
|
.orElse(ResponseEntity.ok(new TeaInfoVO()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TeaInfoVO convertToTeaInfoVO(SchTeacher teacher) {
|
||||||
|
if (teacher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TeaInfoVO vo = new TeaInfoVO();
|
||||||
|
|
||||||
|
// 鐩存帴鏄犲皠
|
||||||
|
vo.setAccount(teacher.getAccount());
|
||||||
|
vo.setName(teacher.getName());
|
||||||
|
vo.setTeaIDCard(teacher.getIdCard());
|
||||||
|
vo.setTel(teacher.getTel());
|
||||||
|
vo.setTeaNo(teacher.getSort());
|
||||||
|
vo.setRole(UserRole.TEACHER_USER.getValue());
|
||||||
|
|
||||||
|
if (teacher.getGender() != null) {
|
||||||
|
String sex = UserGender.nameById(teacher.getGender());
|
||||||
|
vo.setTeaSex(sex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TeaSerID 浣跨敤 teaId锛堣浆涓哄瓧绗︿覆锛夋垨 id
|
||||||
|
if (teacher.getTeaId() != null) {
|
||||||
|
vo.setTeaSerID(teacher.getTeaId().toString());
|
||||||
|
} else {
|
||||||
|
vo.setTeaSerID(teacher.getId().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SchTeacherGroup> groupList=teacher.getGroupList();
|
||||||
|
if(groupList==null||groupList.isEmpty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 鍏朵粬瀛楁榛樿 null锛堟垨鏍规嵁涓氬姟璁剧疆榛樿鍊硷級
|
||||||
|
SchInfoVO schInfoVO= schInfoService.GetSchFirst(groupList.stream().findFirst().get().getSchId());
|
||||||
|
|
||||||
|
vo.setSchSerID(schInfoVO==null?null:schInfoVO.getSchSerId());
|
||||||
|
vo.setGroupID(groupList.stream().findFirst().get().getGroupId());
|
||||||
|
vo.setSchSerIDs(schInfoVO==null?null:schInfoVO.getSchSerId());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量回填教师的分组列表(groupList 为 @Transient 字段,查询后需要单独填充)。
|
||||||
|
* schId 不为空时只查该校的组关系,保证取到的 GroupID/SchSerID 属于当前学校。
|
||||||
|
*/
|
||||||
|
private void fillGroupList(List<SchTeacher> teachers, Integer schId) {
|
||||||
|
if (teachers == null || teachers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<Integer> teaIds = teachers.stream()
|
||||||
|
.map(SchTeacher::getTeaId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (teaIds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<SchTeacherGroup> relations = (schId != null)
|
||||||
|
? schTeacherGroupRepository.findByTeaIdInAndSchId(teaIds, schId)
|
||||||
|
: schTeacherGroupRepository.findByTeaIdIn(teaIds);
|
||||||
|
Map<Integer, List<SchTeacherGroup>> groupMap = relations.stream()
|
||||||
|
.filter(g -> g.getTeaId() != null)
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherGroup::getTeaId));
|
||||||
|
teachers.forEach(t -> t.setGroupList(groupMap.getOrDefault(t.getTeaId(), Collections.emptyList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("GetArrTeainfo")
|
||||||
|
@Operation(summary = "根据教师id数组 获取教师列表")
|
||||||
|
public ResponseEntity<List<TeaInfoVO>> getArrTeainfo(@RequestBody String userIds) {
|
||||||
|
// 1. 鍙傛暟鏍¢獙
|
||||||
|
if (userIds == null) {
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> uids= Arrays.asList(OtherUtil.convertToArray(userIds));
|
||||||
|
|
||||||
|
List<SchTeacher> teachers = schTeacherRepository.findByTeaIdIn(uids);
|
||||||
|
fillGroupList(teachers, null);
|
||||||
|
List<TeaInfoVO> voList = teachers.stream()
|
||||||
|
.map(this::convertToTeaInfoVO)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(voList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析学校ID:支持直接传 schId,或传 SchSerID 反查 schId,二者至少提供一个。
|
||||||
|
*
|
||||||
|
* @param schId 学校内部ID(优先使用)
|
||||||
|
* @param schSerID 学校外部序列号
|
||||||
|
* @return 学校内部ID,参数非法或查不到时返回 null
|
||||||
|
*/
|
||||||
|
private Integer resolveSchId(Integer schId, String schSerID) {
|
||||||
|
if (schId != null) {
|
||||||
|
return schId;
|
||||||
|
}
|
||||||
|
if (schSerID == null || schSerID.trim().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SchInfoVO schInfoVO = schInfoService.GetSchFirst(schSerID);
|
||||||
|
return schInfoVO == null ? null : schInfoVO.getUserSchSerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchTeainfo")
|
||||||
|
@Operation(summary = "根据学校ID 获取教师列表(SchSerID 与 schId 二选一)")
|
||||||
|
public ResponseEntity<List<TeaInfoVO>> getSchTeainfo(@RequestParam(value = "SchSerID", required = false) String SchSerID,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
// 1. 参数校验:SchSerID 与 schId 至少传一个
|
||||||
|
Integer resolvedSchId = resolveSchId(schId, SchSerID);
|
||||||
|
if (resolvedSchId == null) {
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SchTeacher> teachers = schTeacherService.getSchTeacherList(resolvedSchId);
|
||||||
|
fillGroupList(teachers, resolvedSchId);
|
||||||
|
|
||||||
|
List<TeaInfoVO> voList = teachers.stream()
|
||||||
|
.map(this::convertToTeaInfoVO)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(voList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("GetSchTeaList")
|
||||||
|
@Operation(summary = "getSchTeaList(SchSerID 与 schId 二选一)")
|
||||||
|
public ResponseEntity<List<TeaInfoVO>> getSchTeaList(@RequestParam(value = "SchSerID", required = false) String SchSerID,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
return getSchTeainfo(SchSerID, schId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchStudentRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherGroup;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserRole;
|
||||||
|
import com.yunhai.bschclassmanage.enums.UserType;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.UserInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.oa.SchInfoVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchInfoService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchStudentService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchTeacherService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "UserInfo", description = "UserInfo related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/UserInfo/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class UserInfoController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchStudentService schStudentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherRepository schTeacherRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchStudentRepository schStudentRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISchInfoService schInfoService;
|
||||||
|
|
||||||
|
@GetMapping("GetUserList")
|
||||||
|
@Operation(summary = "getUserList")
|
||||||
|
public ResponseEntity<List<UserInfoVO>> getUserList(@RequestParam String SchSerID) {
|
||||||
|
// 1. 鍙傛暟鏍¢獙
|
||||||
|
if (SchSerID == null || SchSerID.trim().isEmpty()) {
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
SchInfoVO schInfoVO = schInfoService.GetSchFirst(SchSerID);
|
||||||
|
if (schInfoVO == null) {
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
Integer schId = schInfoVO.getUserSchSerId();
|
||||||
|
|
||||||
|
// 2. 鑾峰彇鏁欏笀鍜屽鐢熷垪琛紙鍒ょ┖锛?
|
||||||
|
List<SchTeacher> teachers = schTeacherService.getSchTeacherCacheList(schId);
|
||||||
|
List<SchStudent> students = schStudentService.getSchGradeClassStudentCacheList(schId, null, null, null);
|
||||||
|
|
||||||
|
// 3. 杞崲涓?UserInfoVO
|
||||||
|
List<UserInfoVO> voList = new ArrayList<>();
|
||||||
|
if (teachers != null) {
|
||||||
|
voList.addAll(teachers.stream()
|
||||||
|
.map(this::convertToUserInfoVO)
|
||||||
|
.filter(vo -> vo != null) // 杩囨护杞崲澶辫触鐨?
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
if (students != null) {
|
||||||
|
voList.addAll(students.stream()
|
||||||
|
.map(this::convertToUserInfoVO)
|
||||||
|
.filter(vo -> vo != null)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 杩斿洖缁撴灉
|
||||||
|
return ResponseEntity.ok(voList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 杞崲鏁欏笀 =====
|
||||||
|
private UserInfoVO convertToUserInfoVO(SchTeacher teacher) {
|
||||||
|
if (teacher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfoVO vo = new UserInfoVO();
|
||||||
|
// 鍩虹瀛楁
|
||||||
|
vo.setUids(teacher.getAccount());
|
||||||
|
vo.setName(teacher.getName());
|
||||||
|
vo.setIDCard(teacher.getIdCard());
|
||||||
|
vo.setTel(teacher.getTel());
|
||||||
|
vo.setNo(teacher.getSort());
|
||||||
|
vo.setSex(teacher.getGender());
|
||||||
|
vo.setUserID(teacher.getTeaId()); // 鏁欏笀鐢ㄦ埛ID
|
||||||
|
vo.setUsertype(1); // 鍋囪鏁欏笀绫诲瀷涓?
|
||||||
|
|
||||||
|
// 鑾峰彇瀛︽牎ID鍜岀粍ID
|
||||||
|
List<SchTeacherGroup> groupList = teacher.getGroupList();
|
||||||
|
if (groupList != null && !groupList.isEmpty()) {
|
||||||
|
SchTeacherGroup firstGroup = groupList.get(0);
|
||||||
|
vo.setGroupID(firstGroup.getGroupId());
|
||||||
|
// 閫氳繃缁勮幏鍙栧鏍′俊鎭?
|
||||||
|
SchInfoVO schInfo = schInfoService.GetSchFirst(firstGroup.getSchId());
|
||||||
|
// 鑻ユ病鏈夌洿鎺ユ寜缁勬煡瀛︽牎鐨勬柟娉曪紝鍙敼涓洪€氳繃缁勭殑schId鏌?
|
||||||
|
if (schInfo != null) {
|
||||||
|
vo.setSchSerID(schInfo.getSchSerId());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 鏃犲垎缁勶紝鍙兘鏄鐞嗗憳鎴栫壒娈婄敤鎴凤紝鍙缃粯璁ゆ垨 null
|
||||||
|
vo.setGroupID(null);
|
||||||
|
vo.setSchSerID(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鍏朵粬瀛楁锛堝 Photo, SerID 绛夛級濡傛灉 SchTeacher 娌℃湁锛屽彲缃?null 鎴栦粠鍒鑾峰彇
|
||||||
|
vo.setPhoto(null); // 鍙牴鎹?teacher 鐨勬煇瀛楁琛ュ厖
|
||||||
|
vo.setSerID(null);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 杞崲瀛︾敓 =====
|
||||||
|
private UserInfoVO convertToUserInfoVO(SchStudent student) {
|
||||||
|
if (student == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInfoVO vo = new UserInfoVO();
|
||||||
|
vo.setUids(student.getAccount());
|
||||||
|
vo.setName(student.getName());
|
||||||
|
vo.setIDCard(student.getIdCard());
|
||||||
|
vo.setTel(null); // 瀛︾敓琛ㄥ彲鑳芥棤鐢佃瘽锛屽鏈夊垯琛ュ厖
|
||||||
|
vo.setNo(null); // 瀛︾敓琛ㄦ病鏈?No 瀛楁锛屽彲缃?null 鎴栦粠 stuClassNo 杞崲
|
||||||
|
vo.setSex(student.getGender());
|
||||||
|
vo.setUserID(student.getStuId()); // 瀛︾敓鐢ㄦ埛ID
|
||||||
|
vo.setUsertype(UserRole.STU_USER.getValue()); // 鍋囪瀛︾敓绫诲瀷涓?
|
||||||
|
|
||||||
|
vo.setGroupID(student.getGroupId());
|
||||||
|
|
||||||
|
SchInfoVO schInfo = schInfoService.GetSchFirst(student.getSchId());
|
||||||
|
// 鑻ユ病鏈夌洿鎺ユ寜缁勬煡瀛︽牎鐨勬柟娉曪紝鍙敼涓洪€氳繃缁勭殑schId鏌?
|
||||||
|
if (schInfo != null) {
|
||||||
|
vo.setSchSerID(schInfo.getSchSerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
vo.setPhoto(null);
|
||||||
|
vo.setSerID(null);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getUserIdList")
|
||||||
|
@Operation(summary = "getUserIdList")
|
||||||
|
public ResponseEntity<List<UserInfoVO>> getUserIdList(@RequestParam Integer userid) {
|
||||||
|
if (userid == null) {
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同一 teaId/stuId 可能在多所学校各有记录,取第一条即可(不能按唯一查询)
|
||||||
|
Optional<SchTeacher> teacherOpt = schTeacherRepository.findByTeaId(userid).stream().findFirst();
|
||||||
|
if (teacherOpt.isPresent()) {
|
||||||
|
UserInfoVO vo = convertToUserInfoVO(teacherOpt.get());
|
||||||
|
if (vo != null) {
|
||||||
|
return ResponseEntity.ok(Collections.singletonList(vo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<SchStudent> studentOpt = schStudentRepository.findByStuId(userid).stream().findFirst();
|
||||||
|
if (studentOpt.isPresent()) {
|
||||||
|
UserInfoVO vo = convertToUserInfoVO(studentOpt.get());
|
||||||
|
if (vo != null) {
|
||||||
|
return ResponseEntity.ok(Collections.singletonList(vo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.oa;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.*;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "VClass", description = "VClass related APIs")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI+"/VSchClass/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class VClassController {
|
||||||
|
@Autowired private SchClassRepository classRepository;
|
||||||
|
@Autowired private SchInfoRepository schoolRepository;
|
||||||
|
@Autowired private SchClassTeachRepository teachingRepository;
|
||||||
|
|
||||||
|
@GetMapping("GetVClassList")
|
||||||
|
@Operation(summary = "GetVClassList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetVClassList(@RequestParam(required=false) String SchSerID) { return bySchool(SchSerID, false); }
|
||||||
|
@GetMapping("GetEleVClassList")
|
||||||
|
@Operation(summary = "GetEleVClassList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleVClassList(@RequestParam(required=false) String SchSerID) { return bySchool(SchSerID, true); }
|
||||||
|
@GetMapping("GetSchArrVClassList")
|
||||||
|
@Operation(summary = "GetSchArrVClassList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchArrVClassList(@RequestParam(required=false) String SchIDArr) { return bySchools(SchIDArr, false); }
|
||||||
|
@GetMapping("GetEleSchArrVClassList")
|
||||||
|
@Operation(summary = "GetEleSchArrVClassList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchArrVClassList(@RequestParam(required=false) String SchIDArr) { return bySchools(SchIDArr, true); }
|
||||||
|
@GetMapping("GetFunTimeSchClass")
|
||||||
|
@Operation(summary = "GetFunTimeSchClass")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetFunTimeSchClass(@RequestParam(required=false) String time, @RequestParam(required=false) String SchSerID) { return bySchool(SchSerID, false); }
|
||||||
|
@GetMapping("GetVClassFirst")
|
||||||
|
@Operation(summary = "GetVClassFirst")
|
||||||
|
public ResponseEntity<Map<String,Object>> GetVClassFirst(@RequestParam(required=false) String ClassID) { return one(ClassID); }
|
||||||
|
@GetMapping("GetEleVClassFirst")
|
||||||
|
@Operation(summary = "GetEleVClassFirst")
|
||||||
|
public ResponseEntity<Map<String,Object>> GetEleVClassFirst(@RequestParam(required=false) String ClassID) { return one(ClassID); }
|
||||||
|
@GetMapping("GetVClassIdsList")
|
||||||
|
@Operation(summary = "GetVClassIdsList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetVClassIdsList(@RequestParam(required=false) String ClassIds) { return byClassIds(ClassIds); }
|
||||||
|
@GetMapping("GetEleVClassIdsList")
|
||||||
|
@Operation(summary = "GetEleVClassIdsList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleVClassIdsList(@RequestParam(required=false) String ClassIds) { return byClassIds(ClassIds); }
|
||||||
|
@GetMapping("GetGradeClassList")
|
||||||
|
@Operation(summary = "GetGradeClassList")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetGradeClassList(@RequestParam(required=false) String SchSerID, @RequestParam(required=false) Integer Schooling, @RequestParam(required=false) Integer GradeId) {
|
||||||
|
Integer schId = schoolId(SchSerID); if (schId == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> Objects.equals(c.getSchId(), schId) && (GradeId == null || Objects.equals(c.getGradeId(), GradeId)) && (Schooling == null || Objects.equals(c.getGradeId(), Schooling)) && !Boolean.TRUE.equals(c.getGraduate())).map(c -> OaCompatSupport.classInfo(c, SchSerID)).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("GetTeachClassArr")
|
||||||
|
@Operation(summary = "GetTeachClassArr")
|
||||||
|
public ResponseEntity<List<String>> GetTeachClassArr(@RequestParam(required=false) Integer UserTeaSerID) {
|
||||||
|
if (UserTeaSerID == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(teachingRepository.findAll().stream().filter(t -> Objects.equals(t.getTeaId(), UserTeaSerID)).map(SchClassTeach::getClassId).filter(Objects::nonNull).map(String::valueOf).distinct().collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
@GetMapping("GetSchArrVClassListAll")
|
||||||
|
@Operation(summary = "GetSchArrVClassListAll")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchArrVClassListAll() { return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> !Boolean.TRUE.equals(c.getGraduate())).map(c -> OaCompatSupport.classInfo(c, schoolSer(c.getSchId()))).collect(Collectors.toList())); }
|
||||||
|
@GetMapping("GetEleSchArrVClassListAll")
|
||||||
|
@Operation(summary = "GetEleSchArrVClassListAll")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetEleSchArrVClassListAll() { return GetSchArrVClassListAll(); }
|
||||||
|
@PostMapping("GetSchArrVClassListPost")
|
||||||
|
@Operation(summary = "GetSchArrVClassListPost")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetSchArrVClassListPost(@RequestBody(required=false) String body) { return bySchools(body, false); }
|
||||||
|
@GetMapping("GetElectiveClassById")
|
||||||
|
@Operation(summary = "GetElectiveClassById")
|
||||||
|
public ResponseEntity<Map<String,Object>> GetElectiveClassById(@RequestParam(required=false) Integer electiveId) { return ResponseEntity.ok(null); }
|
||||||
|
@GetMapping("GetElectiveClassByGrade")
|
||||||
|
@Operation(summary = "GetElectiveClassByGrade")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetElectiveClassByGrade(@RequestParam(required=false) Integer schoolId, @RequestParam(required=false) Integer gradeId) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
@PostMapping("GetElectiveClassByTeachers")
|
||||||
|
@Operation(summary = "GetElectiveClassByTeachers")
|
||||||
|
public ResponseEntity<List<Map<String,Object>>> GetElectiveClassByTeachers(@RequestBody(required=false) String teacherIds) { return ResponseEntity.ok(Collections.emptyList()); }
|
||||||
|
|
||||||
|
private ResponseEntity<List<Map<String,Object>>> bySchool(String ser, boolean elective) {
|
||||||
|
Integer id = schoolId(ser); if (id == null) return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> Objects.equals(c.getSchId(), id) && (elective || !Boolean.TRUE.equals(c.getGraduate()))).map(c -> OaCompatSupport.classInfo(c, ser)).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
private ResponseEntity<List<Map<String,Object>>> bySchools(String value, boolean elective) {
|
||||||
|
Set<Integer> ids = new HashSet<>(); for (String ser : OaCompatSupport.strings(value)) { Integer id = schoolId(ser); if (id != null) ids.add(id); }
|
||||||
|
return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> ids.contains(c.getSchId()) && (elective || !Boolean.TRUE.equals(c.getGraduate()))).map(c -> OaCompatSupport.classInfo(c, schoolSer(c.getSchId()))).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
private ResponseEntity<List<Map<String,Object>>> byClassIds(String value) { Set<Integer> ids = new HashSet<>(OaCompatSupport.ints(value)); return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> ids.contains(c.getClassId()) || ids.contains(c.getId())).map(c -> OaCompatSupport.classInfo(c, schoolSer(c.getSchId()))).collect(Collectors.toList())); }
|
||||||
|
private ResponseEntity<Map<String,Object>> one(String value) { Integer id = parse(value); if (id == null) return ResponseEntity.ok(null); return ResponseEntity.ok(classRepository.findAll().stream().filter(c -> Objects.equals(c.getClassId(), id)).findFirst().map(c -> OaCompatSupport.classInfo(c, schoolSer(c.getSchId()))).orElse(null)); }
|
||||||
|
private Integer schoolId(String ser) { return ser == null ? null : schoolRepository.findBySchSerId(ser).map(SchInfo::getSchId).orElse(null); }
|
||||||
|
private String schoolSer(Integer id) { return id == null ? null : schoolRepository.findBySchId(id).map(SchInfo::getSchSerId).orElse(null); }
|
||||||
|
private Integer parse(String s) { try { return s == null ? null : Integer.valueOf(s); } catch (Exception e) { return null; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+182
@@ -0,0 +1,182 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.sch;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchClassRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.OapiClassVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.OapiGradeNameVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchBinSchsystemService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchClassService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchTeacherService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "OapiSchClass", description = "开放接口-班级(含班主任)")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/sch/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class OapiSchClassController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchClassRepository schClassRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchInfoRepository schInfoRepository;
|
||||||
|
@Autowired
|
||||||
|
private ISchClassService schClassService;
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
@Autowired
|
||||||
|
private ISchBinSchsystemService schBinSchsystemService;
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemService baseSchsystemService;
|
||||||
|
|
||||||
|
@GetMapping("getClassInfo")
|
||||||
|
@Operation(summary = "获取班级信息", description = "按班级ID(班级组ID)查询班级信息,含班主任/副班主任ID与姓名;可传 schId 精确到学校")
|
||||||
|
public ResponseEntity<OapiClassVO> getClassInfo(@RequestParam(value = "classId", required = false) Integer classId,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
if (classId == null) {
|
||||||
|
return ResponseEntity.ok(null);
|
||||||
|
}
|
||||||
|
Optional<SchClass> first = schId != null
|
||||||
|
? schClassRepository.findByClassIdAndSchId(classId, schId)
|
||||||
|
: schClassRepository.findAll().stream()
|
||||||
|
.filter(c -> classId.equals(c.getClassId()))
|
||||||
|
.findFirst();
|
||||||
|
return ResponseEntity.ok(first.map(c -> toVOList(Collections.singletonList(c)).get(0)).orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getGradeClassList")
|
||||||
|
@Operation(summary = "获取年级班级列表", description = "按年级编码查询班级列表;建议同时传 schId(走学校缓存),不传则跨校查询")
|
||||||
|
public ResponseEntity<List<OapiClassVO>> getGradeClassList(@RequestParam(value = "gradeId", required = false) Integer gradeId,
|
||||||
|
@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
if (gradeId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchClass> classes = schId != null
|
||||||
|
? schClassService.getSchClassCacheFilter(schId, gradeId, null)
|
||||||
|
: schClassRepository.findAll().stream()
|
||||||
|
.filter(c -> gradeId.equals(c.getGradeId()) && !Boolean.TRUE.equals(c.getGraduate()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(toVOList(classes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getSchClassList")
|
||||||
|
@Operation(summary = "获取全校班级列表", description = "按学校ID查询全部班级(含班主任);默认不含毕业班,includeGraduate=true 时含毕业班")
|
||||||
|
public ResponseEntity<List<OapiClassVO>> getSchClassList(@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "includeGraduate", required = false, defaultValue = "false") boolean includeGraduate) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchClass> classes = includeGraduate
|
||||||
|
? schClassService.getSchAllClassCacheList(schId)
|
||||||
|
: schClassService.getSchClassCacheList(schId);
|
||||||
|
return ResponseEntity.ok(toVOList(classes));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getGradeName")
|
||||||
|
@Operation(summary = "获取年级名称", description = "按学校ID+入学年份+学段(1小学/2初中/3高中)查询学校年级字典名称(gradeNickname);"
|
||||||
|
+ "年份按当前学年与年级序换算(与班级导入同口径),无匹配学制/年级返回 null,由调用方自行降级")
|
||||||
|
public ResponseEntity<OapiGradeNameVO> getGradeName(@RequestParam("schId") Integer schId,
|
||||||
|
@RequestParam("year") Integer year,
|
||||||
|
@RequestParam(value = "stage", required = false) Integer stage) {
|
||||||
|
if (schId == null || year == null) {
|
||||||
|
return ResponseEntity.ok(null);
|
||||||
|
}
|
||||||
|
// 学段 → 学制:按学校各学制记录的学段名(小学/初中/高中)匹配;不传 stage 时不限学段
|
||||||
|
String stageName = stage == null ? null
|
||||||
|
: stage == 1 ? "小学" : stage == 2 ? "初中" : stage == 3 ? "高中" : null;
|
||||||
|
List<Integer> targetSystems = new ArrayList<>();
|
||||||
|
if (stageName == null) {
|
||||||
|
targetSystems.addAll(schBinSchsystemService.getSchBinSchsystemIds(schId));
|
||||||
|
} else {
|
||||||
|
for (Integer schsystemId : schBinSchsystemService.getSchBinSchsystemIds(schId)) {
|
||||||
|
try {
|
||||||
|
String name = baseSchsystemService.getAcademicStageName(schsystemId);
|
||||||
|
if (name != null && name.contains(stageName)) {
|
||||||
|
targetSystems.add(schsystemId);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 单个学制学段名缺失(学制未找到等)跳过,不影响其余学制
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Integer schsystemId : targetSystems) {
|
||||||
|
// 年级→入学年份(当前学年-年级偏移,与班级导入 getNowYearGradeMap 同口径);再查字典别称
|
||||||
|
Map<Integer, Integer> yearMap = baseSchsystemGradeService.getNowYearGradeMap(schId, schsystemId);
|
||||||
|
if (yearMap == null || yearMap.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<Integer, String> nameMap = baseSchsystemGradeService.getGradeNameMap(schId, schsystemId, null);
|
||||||
|
for (Map.Entry<Integer, Integer> e : yearMap.entrySet()) {
|
||||||
|
if (year.equals(e.getValue()) && nameMap.get(e.getKey()) != null) {
|
||||||
|
OapiGradeNameVO vo = new OapiGradeNameVO();
|
||||||
|
vo.setGradeId(e.getKey());
|
||||||
|
vo.setGradeName(nameMap.get(e.getKey()));
|
||||||
|
vo.setYear(year);
|
||||||
|
return ResponseEntity.ok(vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 批量转 VO:按学校分组后统一回填学校名/年级名/班主任姓名 */
|
||||||
|
private List<OapiClassVO> toVOList(List<SchClass> classes) {
|
||||||
|
if (classes == null || classes.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Map<Integer, List<SchClass>> bySchool = classes.stream()
|
||||||
|
.filter(c -> c.getSchId() != null)
|
||||||
|
.collect(Collectors.groupingBy(SchClass::getSchId, LinkedHashMap::new, Collectors.toList()));
|
||||||
|
|
||||||
|
List<OapiClassVO> result = new ArrayList<>();
|
||||||
|
for (Map.Entry<Integer, List<SchClass>> entry : bySchool.entrySet()) {
|
||||||
|
Integer schId = entry.getKey();
|
||||||
|
String schName = schInfoRepository.findBySchId(schId).map(s -> s.getName()).orElse(null);
|
||||||
|
Map<Integer, String> gradeNameMap = baseSchsystemGradeService.getGradeNameMap(schId, null, null);
|
||||||
|
Map<Integer, String> teacherNameMap = schTeacherService.toIdAndNameMap(schId);
|
||||||
|
for (SchClass clazz : entry.getValue()) {
|
||||||
|
result.add(toVO(clazz, schName, gradeNameMap, teacherNameMap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 无学校ID的脏数据兜底转换
|
||||||
|
classes.stream()
|
||||||
|
.filter(c -> c.getSchId() == null)
|
||||||
|
.forEach(c -> result.add(toVO(c, null, Collections.emptyMap(), Collections.emptyMap())));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OapiClassVO toVO(SchClass clazz, String schName,
|
||||||
|
Map<Integer, String> gradeNameMap, Map<Integer, String> teacherNameMap) {
|
||||||
|
OapiClassVO vo = new OapiClassVO();
|
||||||
|
vo.setId(clazz.getId());
|
||||||
|
vo.setClassId(clazz.getClassId());
|
||||||
|
vo.setCode(clazz.getCode());
|
||||||
|
vo.setName(clazz.getName());
|
||||||
|
vo.setCname(clazz.getCname());
|
||||||
|
vo.setGradeId(clazz.getGradeId());
|
||||||
|
vo.setGradeName(clazz.getGradeId() == null ? null : gradeNameMap.get(clazz.getGradeId()));
|
||||||
|
vo.setSchId(clazz.getSchId());
|
||||||
|
vo.setSchName(schName);
|
||||||
|
vo.setFirstTeacherId(clazz.getFirstTeacherId());
|
||||||
|
vo.setFirstTeacherName(clazz.getFirstTeacherId() == null ? null : teacherNameMap.get(clazz.getFirstTeacherId()));
|
||||||
|
vo.setSecondTeacherId(clazz.getSecondTeacherId());
|
||||||
|
vo.setSecondTeacherName(clazz.getSecondTeacherId() == null ? null : teacherNameMap.get(clazz.getSecondTeacherId()));
|
||||||
|
vo.setCampusId(clazz.getCampusId());
|
||||||
|
vo.setEnrollYear(clazz.getEnrollYear());
|
||||||
|
vo.setGraduate(clazz.getGraduate());
|
||||||
|
vo.setSort(clazz.getSort());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
}
|
||||||
+309
@@ -0,0 +1,309 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.sch;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherCustomGroupInGradeRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherCustomGroupInSubjectRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherCustomGroupInTeacherRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchTeacherCustomGroupRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroup;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInGrade;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInSubject;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchTeacherCustomGroupInTeacher;
|
||||||
|
import com.yunhai.bschclassmanage.enums.CustomGroupType;
|
||||||
|
import com.yunhai.bschclassmanage.model.oa.TeaTreeVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectStrVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.OapiGroupVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.TeaCustomGroupTreeVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.IComSchTreeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchDicSubjectService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchTeacherService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "OapiSchGroup", description = "开放接口-学校组(教师组树/学生组树/年级组教研组等自定义组树)")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/sch/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class OapiSchGroupController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IComSchTreeService comSchTreeService;
|
||||||
|
@Autowired
|
||||||
|
private ISchTeacherService schTeacherService;
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
@Autowired
|
||||||
|
private ISchDicSubjectService schDicSubjectService;
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherCustomGroupRepository customGroupRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherCustomGroupInGradeRepository groupInGradeRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherCustomGroupInSubjectRepository groupInSubjectRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchTeacherCustomGroupInTeacherRepository groupInTeacherRepository;
|
||||||
|
|
||||||
|
@GetMapping("getTeaGroupTree")
|
||||||
|
@Operation(summary = "获取教师组树+教师", description = "学校→教师组(含子组)→教师;toUser=false 时仅返回组骨架。与 oa/SchGroup/GetTeaTree 同源同结构")
|
||||||
|
public ResponseEntity<List<TeaTreeVO>> getTeaGroupTree(@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "toUser", required = false, defaultValue = "true") boolean toUser) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(comSchTreeService.getSchTeaTree(schId, toUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getStuGroupTree")
|
||||||
|
@Operation(summary = "获取学生组树+学生", description = "学校→学段→年级→班级→学生;toUser=false 时仅返回组织骨架。与 oa/SchGroup/GetStuTree 同源同结构")
|
||||||
|
public ResponseEntity<List<TeaTreeVO>> getStuGroupTree(@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "toUser", required = false, defaultValue = "true") boolean toUser) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(comSchTreeService.getSchStuTree(schId, toUser));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getTeaCustomGroupTree")
|
||||||
|
@Operation(summary = "获取教师自定义组树+教师(年级组/教研组/备课组)",
|
||||||
|
description = "不传 groupType 时返回三层:类型根节点(id=-1年级组/-2教研组/-3备课组)→ 组节点 → 教师叶子;"
|
||||||
|
+ "传 groupType(1年级组 2教研组 3备课组,教研组即教师学科组)时直接返回该类型组节点列表(两层)。"
|
||||||
|
+ "组节点携带组长、关联年级、关联学科;教师叶子携带 isLeader")
|
||||||
|
public ResponseEntity<List<TeaCustomGroupTreeVO>> getTeaCustomGroupTree(@RequestParam(value = "schId") Integer schId,
|
||||||
|
@RequestParam(value = "groupType", required = false) Integer groupType) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchTeacherCustomGroup> groups = (groupType != null)
|
||||||
|
? customGroupRepository.findBySchIdAndGroupType(schId, groupType)
|
||||||
|
: customGroupRepository.findBySchId(schId);
|
||||||
|
if (groups == null || groups.isEmpty()) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
groups = groups.stream()
|
||||||
|
.sorted(Comparator.comparing(SchTeacherCustomGroup::getSort, Comparator.nullsLast(Integer::compareTo)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return ResponseEntity.ok(buildTree(schId, groups, groupType != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getTeaCustomGroupList")
|
||||||
|
@Operation(summary = "获取教师分组列表(组/组员/组长合一)",
|
||||||
|
description = "按学校查教师分组列表:组id、组名称、学科集合、年级集合、组员集合、组长集合;"
|
||||||
|
+ "groupType 可选(1年级组 2教研组 3备课组,不传返回全部类型)。"
|
||||||
|
+ "组长取关系表 group_type=1 的全部教师(取不到时兜底组记录 leader_id 字段),组员取 group_type=2 且排除组长")
|
||||||
|
public ResponseEntity<List<OapiGroupVO>> getTeaCustomGroupList(@RequestParam(value = "schId") Integer schId,
|
||||||
|
@RequestParam(value = "groupType", required = false) Integer groupType) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchTeacherCustomGroup> groups = (groupType != null)
|
||||||
|
? customGroupRepository.findBySchIdAndGroupType(schId, groupType)
|
||||||
|
: customGroupRepository.findBySchId(schId);
|
||||||
|
if (groups == null || groups.isEmpty()) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
groups = groups.stream()
|
||||||
|
.sorted(Comparator.comparing(SchTeacherCustomGroup::getSort, Comparator.nullsLast(Integer::compareTo)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<Integer> groupIds = groups.stream().map(SchTeacherCustomGroup::getId).collect(Collectors.toList());
|
||||||
|
Map<Integer, List<SchTeacherCustomGroupInGrade>> groupIdToGrades = groupInGradeRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInGrade::getCgGroupId));
|
||||||
|
Map<Integer, List<SchTeacherCustomGroupInSubject>> groupIdToSubjects = groupInSubjectRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInSubject::getCgGroupId));
|
||||||
|
// relationType:1组长 2组员
|
||||||
|
Map<Integer, List<SchTeacherCustomGroupInTeacher>> groupIdToTeachers = groupInTeacherRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.filter(r -> r.getTeaId() != null)
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInTeacher::getCgGroupId));
|
||||||
|
|
||||||
|
Map<Integer, SchTeacher> teacherMap = schTeacherService.getSchTeacherCacheList(schId).stream()
|
||||||
|
.filter(t -> t.getTeaId() != null)
|
||||||
|
.collect(Collectors.toMap(SchTeacher::getTeaId, t -> t, (a, b) -> a));
|
||||||
|
Map<Integer, String> gradeNameMap = baseSchsystemGradeService.getGradeNameMap(schId, null, null);
|
||||||
|
Map<String, String> subjectNameMap = schDicSubjectService.toIdAndNameMap(schId, null);
|
||||||
|
|
||||||
|
List<OapiGroupVO> result = new ArrayList<>(groups.size());
|
||||||
|
for (SchTeacherCustomGroup group : groups) {
|
||||||
|
List<SchTeacherCustomGroupInTeacher> relations = groupIdToTeachers.getOrDefault(group.getId(), Collections.emptyList());
|
||||||
|
List<Integer> leaderIds = resolveLeaders(group, relations);
|
||||||
|
|
||||||
|
OapiGroupVO vo = new OapiGroupVO();
|
||||||
|
vo.setGroupId(group.getId());
|
||||||
|
vo.setGroupName(group.getGroupName());
|
||||||
|
vo.setGroupType(group.getGroupType());
|
||||||
|
vo.setGroupTypeName(group.getGroupType() == null ? null : CustomGroupType.nameById(group.getGroupType()));
|
||||||
|
vo.setSubjects(groupIdToSubjects.getOrDefault(group.getId(), Collections.emptyList()).stream()
|
||||||
|
.map(SchTeacherCustomGroupInSubject::getSubId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.map(subId -> new SelectStrVO(subId, subjectNameMap.get(subId)))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
vo.setGrades(groupIdToGrades.getOrDefault(group.getId(), Collections.emptyList()).stream()
|
||||||
|
.map(SchTeacherCustomGroupInGrade::getGradeId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.map(gradeId -> new SelectIntVO(gradeId, gradeNameMap.get(gradeId)))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
vo.setLeaders(toIdNameList(leaderIds, teacherMap));
|
||||||
|
vo.setMembers(toIdNameList(relations.stream()
|
||||||
|
.filter(r -> Integer.valueOf(2).equals(r.getGroupType()))
|
||||||
|
.map(SchTeacherCustomGroupInTeacher::getTeaId)
|
||||||
|
.filter(id -> !leaderIds.contains(id))
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList()), teacherMap));
|
||||||
|
result.add(vo);
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 组长ID集合:关系表 group_type=1 的全部教师,取不到时兜底组记录 leader_id 字段(与 getSchCustomGroup 语义一致) */
|
||||||
|
private List<Integer> resolveLeaders(SchTeacherCustomGroup group, List<SchTeacherCustomGroupInTeacher> relations) {
|
||||||
|
List<Integer> leaderIds = relations.stream()
|
||||||
|
.filter(r -> Integer.valueOf(1).equals(r.getGroupType()))
|
||||||
|
.map(SchTeacherCustomGroupInTeacher::getTeaId)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (leaderIds.isEmpty() && group.getLeaderId() != null) {
|
||||||
|
leaderIds = Collections.singletonList(group.getLeaderId());
|
||||||
|
}
|
||||||
|
return leaderIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 教师ID集合 → [{id,姓名}],按入参顺序;姓名取不到时与 getSchCustomGroup 一致回退"未知教师" */
|
||||||
|
private List<SelectIntVO> toIdNameList(List<Integer> teaIds, Map<Integer, SchTeacher> teacherMap) {
|
||||||
|
return teaIds.stream()
|
||||||
|
.map(teaId -> new SelectIntVO(teaId,
|
||||||
|
Optional.ofNullable(teacherMap.get(teaId)).map(SchTeacher::getName).orElse("未知教师")))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 组装类型节点→组节点→教师叶子树(flatTypeRoot=true 时不建类型根,组节点直接作为顶层) */
|
||||||
|
private List<TeaCustomGroupTreeVO> buildTree(Integer schId, List<SchTeacherCustomGroup> groups, boolean flatTypeRoot) {
|
||||||
|
List<Integer> groupIds = groups.stream().map(SchTeacherCustomGroup::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<Integer, List<Integer>> groupIdToGradeIds = groupInGradeRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInGrade::getCgGroupId,
|
||||||
|
Collectors.mapping(SchTeacherCustomGroupInGrade::getGradeId, Collectors.toList())));
|
||||||
|
Map<Integer, List<String>> groupIdToSubIds = groupInSubjectRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInSubject::getCgGroupId,
|
||||||
|
Collectors.mapping(SchTeacherCustomGroupInSubject::getSubId, Collectors.toList())));
|
||||||
|
// relationType:1组长 2组员
|
||||||
|
Map<Integer, List<SchTeacherCustomGroupInTeacher>> groupIdToTeachers = groupInTeacherRepository.findByCgGroupIdIn(groupIds).stream()
|
||||||
|
.filter(r -> r.getTeaId() != null)
|
||||||
|
.collect(Collectors.groupingBy(SchTeacherCustomGroupInTeacher::getCgGroupId));
|
||||||
|
|
||||||
|
Map<Integer, SchTeacher> teacherMap = schTeacherService.getSchTeacherCacheList(schId).stream()
|
||||||
|
.filter(t -> t.getTeaId() != null)
|
||||||
|
.collect(Collectors.toMap(SchTeacher::getTeaId, t -> t, (a, b) -> a));
|
||||||
|
Map<Integer, String> gradeNameMap = baseSchsystemGradeService.getGradeNameMap(schId, null, null);
|
||||||
|
Map<String, String> subjectNameMap = schDicSubjectService.toIdAndNameMap(schId, null);
|
||||||
|
|
||||||
|
Map<Integer, List<TeaCustomGroupTreeVO>> groupNodesByType = new LinkedHashMap<>();
|
||||||
|
for (SchTeacherCustomGroup group : groups) {
|
||||||
|
TeaCustomGroupTreeVO groupNode = buildGroupNode(group, flatTypeRoot,
|
||||||
|
groupIdToGradeIds, groupIdToSubIds, groupIdToTeachers, teacherMap, gradeNameMap, subjectNameMap);
|
||||||
|
groupNodesByType.computeIfAbsent(group.getGroupType(), k -> new ArrayList<>()).add(groupNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flatTypeRoot) {
|
||||||
|
return groupNodesByType.values().stream().flatMap(List::stream).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
// 类型根节点(id = -groupType),只输出实际有组的类型,按 1年级组 2教研组 3备课组 顺序
|
||||||
|
List<TeaCustomGroupTreeVO> roots = new ArrayList<>();
|
||||||
|
for (CustomGroupType type : CustomGroupType.list()) {
|
||||||
|
List<TeaCustomGroupTreeVO> children = groupNodesByType.get(type.getId());
|
||||||
|
if (children == null || children.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
TeaCustomGroupTreeVO typeNode = new TeaCustomGroupTreeVO();
|
||||||
|
typeNode.setId(-type.getId());
|
||||||
|
typeNode.setName(type.getName());
|
||||||
|
typeNode.setPid(0);
|
||||||
|
typeNode.setNo(type.getId());
|
||||||
|
typeNode.setType(1);
|
||||||
|
typeNode.setIsParent(true);
|
||||||
|
typeNode.setGroupType(type.getId());
|
||||||
|
typeNode.setGroupTypeName(type.getName());
|
||||||
|
typeNode.setChildren(children);
|
||||||
|
roots.add(typeNode);
|
||||||
|
}
|
||||||
|
return roots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TeaCustomGroupTreeVO buildGroupNode(SchTeacherCustomGroup group, boolean flatTypeRoot,
|
||||||
|
Map<Integer, List<Integer>> groupIdToGradeIds,
|
||||||
|
Map<Integer, List<String>> groupIdToSubIds,
|
||||||
|
Map<Integer, List<SchTeacherCustomGroupInTeacher>> groupIdToTeachers,
|
||||||
|
Map<Integer, SchTeacher> teacherMap,
|
||||||
|
Map<Integer, String> gradeNameMap,
|
||||||
|
Map<String, String> subjectNameMap) {
|
||||||
|
TeaCustomGroupTreeVO node = new TeaCustomGroupTreeVO();
|
||||||
|
node.setId(group.getId());
|
||||||
|
node.setName(group.getGroupName());
|
||||||
|
node.setPid(flatTypeRoot ? 0 : (group.getGroupType() == null ? null : -group.getGroupType()));
|
||||||
|
node.setNo(group.getSort());
|
||||||
|
node.setType(1);
|
||||||
|
node.setIsParent(true);
|
||||||
|
node.setGroupType(group.getGroupType());
|
||||||
|
node.setGroupTypeName(group.getGroupType() == null ? null : CustomGroupType.nameById(group.getGroupType()));
|
||||||
|
node.setLeaderId(group.getLeaderId());
|
||||||
|
node.setLeaderName(group.getLeaderId() == null ? null
|
||||||
|
: Optional.ofNullable(teacherMap.get(group.getLeaderId())).map(SchTeacher::getName).orElse(null));
|
||||||
|
|
||||||
|
List<Integer> gradeIds = groupIdToGradeIds.getOrDefault(group.getId(), Collections.emptyList());
|
||||||
|
node.setGradeIds(gradeIds);
|
||||||
|
node.setGradeNames(gradeIds.stream()
|
||||||
|
.map(gradeNameMap::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
List<String> subIds = groupIdToSubIds.getOrDefault(group.getId(), Collections.emptyList());
|
||||||
|
node.setSubjectIds(subIds);
|
||||||
|
node.setSubjectNames(subIds.stream()
|
||||||
|
.map(subjectNameMap::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
|
// 教师叶子:组长(relationType=1)在前,组员在后;同组内按 teaId 去重
|
||||||
|
List<SchTeacherCustomGroupInTeacher> relations = groupIdToTeachers.getOrDefault(group.getId(), Collections.emptyList());
|
||||||
|
List<TeaCustomGroupTreeVO> teacherNodes = new ArrayList<>();
|
||||||
|
Set<Integer> seenTeaIds = new HashSet<>();
|
||||||
|
relations.stream().filter(r -> Integer.valueOf(1).equals(r.getGroupType()))
|
||||||
|
.forEach(r -> addTeacherNode(teacherNodes, seenTeaIds, r, group.getId(), teacherMap));
|
||||||
|
relations.stream().filter(r -> !Integer.valueOf(1).equals(r.getGroupType()))
|
||||||
|
.forEach(r -> addTeacherNode(teacherNodes, seenTeaIds, r, group.getId(), teacherMap));
|
||||||
|
node.setChildren(teacherNodes);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTeacherNode(List<TeaCustomGroupTreeVO> teacherNodes, Set<Integer> seenTeaIds,
|
||||||
|
SchTeacherCustomGroupInTeacher relation, Integer groupId,
|
||||||
|
Map<Integer, SchTeacher> teacherMap) {
|
||||||
|
if (!seenTeaIds.add(relation.getTeaId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SchTeacher teacher = teacherMap.get(relation.getTeaId());
|
||||||
|
if (teacher == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TeaCustomGroupTreeVO leaf = new TeaCustomGroupTreeVO();
|
||||||
|
leaf.setId(relation.getTeaId());
|
||||||
|
leaf.setName(teacher.getName());
|
||||||
|
leaf.setPid(groupId);
|
||||||
|
leaf.setNo(0);
|
||||||
|
leaf.setType(2);
|
||||||
|
leaf.setIsParent(false);
|
||||||
|
leaf.setIsLeader(Integer.valueOf(1).equals(relation.getGroupType()));
|
||||||
|
teacherNodes.add(leaf);
|
||||||
|
}
|
||||||
|
}
|
||||||
+127
@@ -0,0 +1,127 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.sch;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.BaseSchsystemRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseSchsystem;
|
||||||
|
import com.yunhai.bschclassmanage.entity.BaseSchsystemGrade;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchInfo;
|
||||||
|
import com.yunhai.bschclassmanage.enums.AcademicStage;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.SelectIntVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.GradeItemVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.SchInfoDetailVO;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.SchSystemDetailVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchBinSchsystemService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "OapiSchInfo", description = "开放接口-学校信息(含学段/学制)")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/sch/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class OapiSchInfoController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchInfoRepository schInfoRepository;
|
||||||
|
@Autowired
|
||||||
|
private BaseSchsystemRepository baseSchsystemRepository;
|
||||||
|
@Autowired
|
||||||
|
private ISchBinSchsystemService schBinSchsystemService;
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
|
||||||
|
@GetMapping("getSchInfo")
|
||||||
|
@Operation(summary = "获取学校信息", description = "按 schId(用户中心学校组ID)查询学校信息,含学段/学制信息")
|
||||||
|
public ResponseEntity<SchInfoDetailVO> getSchInfo(@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(null);
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(schInfoRepository.findBySchId(schId).map(this::toDetail).orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getSchInfoList")
|
||||||
|
@Operation(summary = "获取学校列表", description = "按 schIds(逗号分隔)查询学校列表,schIds 为空时返回全部学校,含学段/学制信息")
|
||||||
|
public ResponseEntity<List<SchInfoDetailVO>> getSchInfoList(@RequestParam(value = "schIds", required = false) String schIds) {
|
||||||
|
List<SchInfo> schools;
|
||||||
|
Set<Integer> idSet = parseInts(schIds);
|
||||||
|
if (idSet.isEmpty()) {
|
||||||
|
schools = schInfoRepository.findAll();
|
||||||
|
} else {
|
||||||
|
schools = schInfoRepository.findAll().stream()
|
||||||
|
.filter(s -> idSet.contains(s.getSchId()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(schools.stream().map(this::toDetail).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 学校实体 → 详情 VO(拼装学段/学制信息) */
|
||||||
|
private SchInfoDetailVO toDetail(SchInfo schInfo) {
|
||||||
|
SchInfoDetailVO vo = new SchInfoDetailVO();
|
||||||
|
vo.setSchId(schInfo.getSchId());
|
||||||
|
vo.setSchName(schInfo.getName());
|
||||||
|
vo.setSchSerId(schInfo.getSchSerId());
|
||||||
|
vo.setSort(schInfo.getSort());
|
||||||
|
|
||||||
|
List<SelectIntVO> systemList = schBinSchsystemService.selectSchBinSchsystem(schInfo.getSchId());
|
||||||
|
if (systemList == null || systemList.isEmpty()) {
|
||||||
|
vo.setSchSystemList(Collections.emptyList());
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> systemIds = systemList.stream().map(SelectIntVO::getId).collect(Collectors.toList());
|
||||||
|
Map<Integer, BaseSchsystem> systemMap = baseSchsystemRepository.findAllById(systemIds).stream()
|
||||||
|
.collect(Collectors.toMap(BaseSchsystem::getId, s -> s, (a, b) -> a));
|
||||||
|
|
||||||
|
vo.setSchSystemList(systemIds.stream()
|
||||||
|
.map(systemMap::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.map(system -> toSystemDetail(schInfo.getSchId(), system))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 学制实体 → 学制 VO(含学段名称与该学制年级) */
|
||||||
|
private SchSystemDetailVO toSystemDetail(Integer schId, BaseSchsystem system) {
|
||||||
|
SchSystemDetailVO vo = new SchSystemDetailVO();
|
||||||
|
vo.setId(system.getId());
|
||||||
|
vo.setName(system.getName());
|
||||||
|
vo.setAcademicStage(system.getAcademicStage());
|
||||||
|
vo.setAcademicStageName(system.getAcademicStage() == null ? null : AcademicStage.nameById(system.getAcademicStage()));
|
||||||
|
vo.setStartGradeCode(system.getStartGradeCode());
|
||||||
|
vo.setEndGradeCode(system.getEndGradeCode());
|
||||||
|
vo.setGraduationLeng(system.getGraduationLeng());
|
||||||
|
vo.setType(system.getType());
|
||||||
|
|
||||||
|
List<BaseSchsystemGrade> gradeList = baseSchsystemGradeService.getSchGradeCacheList(schId, system.getId(), null);
|
||||||
|
vo.setGradeList(gradeList == null ? Collections.emptyList() : gradeList.stream()
|
||||||
|
.map(g -> {
|
||||||
|
GradeItemVO item = new GradeItemVO();
|
||||||
|
item.setGradeId(g.getGradeId());
|
||||||
|
item.setGradeNickname(g.getGradeNickname());
|
||||||
|
return item;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Integer> parseInts(String value) {
|
||||||
|
Set<Integer> result = new LinkedHashSet<>();
|
||||||
|
if (value == null || value.trim().isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (String token : value.split(",")) {
|
||||||
|
try {
|
||||||
|
result.add(Integer.valueOf(token.trim()));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
package com.yunhai.bschclassmanage.controller.oapi.sch;
|
||||||
|
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchClassRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchInfoRepository;
|
||||||
|
import com.yunhai.bschclassmanage.Repository.SchStudentRepository;
|
||||||
|
import com.yunhai.bschclassmanage.config.Config;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchClass;
|
||||||
|
import com.yunhai.bschclassmanage.entity.SchStudent;
|
||||||
|
import com.yunhai.bschclassmanage.model.vo.sch.OapiStudentVO;
|
||||||
|
import com.yunhai.bschclassmanage.service.IBaseSchsystemGradeService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchClassService;
|
||||||
|
import com.yunhai.bschclassmanage.service.ISchStudentService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Tag(name = "OapiSchStudent", description = "开放接口-学生")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(Config.OAPI + "/sch/")
|
||||||
|
@CrossOrigin(originPatterns = {"*"}, allowCredentials = "true")
|
||||||
|
public class OapiSchStudentController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchStudentRepository schStudentRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchClassRepository schClassRepository;
|
||||||
|
@Autowired
|
||||||
|
private SchInfoRepository schInfoRepository;
|
||||||
|
@Autowired
|
||||||
|
private ISchStudentService schStudentService;
|
||||||
|
@Autowired
|
||||||
|
private ISchClassService schClassService;
|
||||||
|
@Autowired
|
||||||
|
private IBaseSchsystemGradeService baseSchsystemGradeService;
|
||||||
|
|
||||||
|
@GetMapping("getStudentInfo")
|
||||||
|
@Operation(summary = "获取学生信息", description = "按学生ID(用户中心用户ID)查询学生信息,含班级/年级/学校名称")
|
||||||
|
public ResponseEntity<OapiStudentVO> getStudentInfo(@RequestParam(value = "stuId", required = false) Integer stuId) {
|
||||||
|
if (stuId == null) {
|
||||||
|
return ResponseEntity.ok(null);
|
||||||
|
}
|
||||||
|
// 同一 stu_id 可能在多所学校各有记录,取第一条即可(不能按唯一查询)
|
||||||
|
return ResponseEntity.ok(schStudentRepository.findByStuId(stuId).stream()
|
||||||
|
.findFirst()
|
||||||
|
.map(stu -> toVOList(stu.getSchId(), Collections.singletonList(stu)).get(0))
|
||||||
|
.orElse(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getClassStudentList")
|
||||||
|
@Operation(summary = "获取班级学生列表", description = "按学校ID+班级ID(班级组ID)查询班级学生列表(在读正常)")
|
||||||
|
public ResponseEntity<List<OapiStudentVO>> getClassStudentList(@RequestParam(value = "schId", required = false) Integer schId,
|
||||||
|
@RequestParam(value = "classId", required = false) Integer classId) {
|
||||||
|
if (schId == null || classId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchStudent> students = schStudentService.getSchGradeClassStudentCacheList(schId, null, null, classId);
|
||||||
|
return ResponseEntity.ok(toVOList(schId, students));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("getSchStudentList")
|
||||||
|
@Operation(summary = "获取全校学生列表", description = "按学校ID查询全校学生列表(在读正常)")
|
||||||
|
public ResponseEntity<List<OapiStudentVO>> getSchStudentList(@RequestParam(value = "schId", required = false) Integer schId) {
|
||||||
|
if (schId == null) {
|
||||||
|
return ResponseEntity.ok(Collections.emptyList());
|
||||||
|
}
|
||||||
|
List<SchStudent> students = schStudentService.getSchGradeClassStudentCacheList(schId, null, null, null);
|
||||||
|
return ResponseEntity.ok(toVOList(schId, students));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 批量转 VO:统一回填学校/年级/班级名称 */
|
||||||
|
private List<OapiStudentVO> toVOList(Integer schId, List<SchStudent> students) {
|
||||||
|
if (students == null || students.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
String schName = schId == null ? null
|
||||||
|
: schInfoRepository.findBySchId(schId).map(s -> s.getName()).orElse(null);
|
||||||
|
Map<Integer, String> gradeNameMap = schId == null ? Collections.emptyMap()
|
||||||
|
: baseSchsystemGradeService.getGradeNameMap(schId, null, null);
|
||||||
|
Map<Integer, SchClass> classMap = schId == null ? Collections.emptyMap()
|
||||||
|
: schClassService.getSchAllClassCacheList(schId).stream()
|
||||||
|
.filter(c -> c.getClassId() != null)
|
||||||
|
.collect(Collectors.toMap(SchClass::getClassId, c -> c, (a, b) -> a));
|
||||||
|
|
||||||
|
return students.stream().map(stu -> {
|
||||||
|
OapiStudentVO vo = new OapiStudentVO();
|
||||||
|
vo.setId(stu.getId());
|
||||||
|
vo.setStuId(stu.getStuId());
|
||||||
|
vo.setAccount(stu.getAccount());
|
||||||
|
vo.setName(stu.getName());
|
||||||
|
vo.setGender(stu.getGender());
|
||||||
|
vo.setStuClassNo(stu.getStuClassNo());
|
||||||
|
vo.setClassId(stu.getClassId());
|
||||||
|
vo.setStatus(stu.getStatus());
|
||||||
|
vo.setSchId(schId);
|
||||||
|
vo.setSchName(schName);
|
||||||
|
SchClass clazz = stu.getClassId() == null ? null : classMap.get(stu.getClassId());
|
||||||
|
if (clazz != null) {
|
||||||
|
vo.setClassName(clazz.getCname() == null || clazz.getCname().trim().isEmpty()
|
||||||
|
? clazz.getName() : clazz.getCname());
|
||||||
|
vo.setGradeId(clazz.getGradeId());
|
||||||
|
}
|
||||||
|
vo.setGradeName(vo.getGradeId() == null ? null : gradeNameMap.get(vo.getGradeId()));
|
||||||
|
return vo;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user