Compare commits

...

95 Commits

Author SHA1 Message Date
liweijie 60841e5bc8 连接字符串修改 2026-09-24 17:40:56 +08:00
liweijie 4137d61561 数据库连接修改,换国产数据库opengauss 2026-09-24 15:50:17 +08:00
liweijie f8e6466d24 1、课时统计功能调整新增;
2、教学楼序号改为自动填充,无需填写;
3、教学楼检索,教学楼代号下拉选择;
4、课表冲突检查修复
2026-09-24 15:07:26 +08:00
liweijie bd395a5504 课时统计功能提交 2026-09-24 14:08:44 +08:00
liweijie d9f8bf705d 从班次信息管理的排课按钮进排课窗口,刷新页面信息 2026-09-24 11:49:22 +08:00
liweijie 836995a794 班次学期管理,年度检索下拉框数据缺失问题修复 2026-09-24 11:32:26 +08:00
liweijie 094245231c 1、新增教学大纲,报专业名称重复,其实是code重复,修复;
2、已经限制教员排课的,教员仍然可以排课的问题修复
2026-09-24 11:13:23 +08:00
liweijie 4f5e219a6e 新增专业信息的时候设置下拉选项 2026-09-24 09:07:43 +08:00
liweijie 06c057e490 1、学员信息管理成绩查看,只显示课程编号改为显示课程名称和课程编号;
2、机关教学日志日期显示格式修改
2026-09-23 17:43:40 +08:00
liweijie 07ec44e9d4 学员查看成绩没有操作权限的问题修复 2026-09-23 16:41:55 +08:00
liweijie ad92f4afc9 学员信息列表,性别改为显示标签 2026-09-23 15:39:25 +08:00
liweijie 69a1a7d560 学员队表和学员队期表联动 2026-09-23 15:19:19 +08:00
liweijie fb3d20def6 1、学员队期下拉选择;
2、学员信息管理,操作列改为两行显示
2026-09-23 14:58:19 +08:00
liweijie 90fb852cf2 日期保存报错修复 2026-09-22 17:26:04 +08:00
liweijie 62fb137611 课程科目新建的时候部分字段改为下拉选择 2026-09-22 17:13:55 +08:00
liweijie f87e02b06b 选修课和课程科目,上传按钮样式调整,点击按钮选择文件导入 2026-09-22 16:46:56 +08:00
liweijie 1ac022757d 1、选修课保存调整,加上教材的保存;
2、课程可以下拉选择;
2026-09-22 16:25:55 +08:00
liweijie 97ae86f9c7 1、选修课选择教室、教员等用下拉选择,
2、绑定教材落库
2026-09-22 16:09:20 +08:00
liweijie cda0854ab1 教学场地工具条按两行显示 2026-09-22 15:24:06 +08:00
liweijie 3fcec5d756 把工具条横过来,占满一行,数据导入也放到工具条中,不要单独放 2026-09-22 11:56:08 +08:00
liweijie 69a32e31d0 属性信息填写及编号回填等梳理 2026-09-22 10:35:02 +08:00
liweijie c9a2098f3f 添加一个复职的功能,页面操作列按钮分成两行展示,添加根据离职过滤 2026-09-22 10:17:37 +08:00
liweijie 2c5823df09 教研室-教员管理,新建教员的时候,在职类型和导师类型改为下拉,在职类型默认在职 2026-09-22 09:51:15 +08:00
liweijie 738d5917f9 教研室管理,按照序号字段排序 2026-09-22 09:27:20 +08:00
liweijie ae3dbe66a5 人才培养方案,列表过滤,停用的不展示 2026-09-22 09:16:41 +08:00
liweijie 12eddac276 教学大纲,导出选中数据,有勾选导出勾选条目,无勾选导出所有 2026-09-21 17:48:38 +08:00
liweijie 450d664c33 教学大纲,模板下载,添加填写说明 2026-09-21 17:28:46 +08:00
liweijie 3fe66d770d 学员队新增的时候,教室改为下拉,默认在校 2026-09-21 17:20:16 +08:00
liweijie f5728c0827 操作列透明度设置为不透明,否则底层显示跟操作列冲突 2026-09-21 17:09:31 +08:00
liweijie 1482bfd31c 班次编号生成,改为XYD+年度+补零序号 2026-09-21 16:36:09 +08:00
liweijie 035c01e90b 教学任务管理界面完善,教员、教学场地改为下拉 2026-09-20 19:03:39 +08:00
zhaichao 7b84d499a9 排课窗口单元格单击双选问题修复 2026-09-20 17:22:55 +08:00
zhaichao f5a5c89ee3 联教编辑报错 2026-09-20 15:24:07 +08:00
zhaichao 5e3bee9c5f 学员学籍异动申请新增报错 2026-09-20 14:45:19 +08:00
zhaichao a566a26fec 选修课管理 2026-09-20 14:26:52 +08:00
zhaichao 9f0c0ac873 人才培养方案 2026-09-20 11:59:04 +08:00
liweijie e4f4720113 生成课表的时候死循环导致系统崩溃 2026-09-18 20:58:00 +08:00
liweijie 574d41aea8 课表模板新增的时候报错修复 2026-09-18 20:38:21 +08:00
liweijie 62ff4d48ab 学科专业新增报错修复 2026-09-18 20:31:29 +08:00
liweijie b87e910f9a 教学配当界面无法打开的问题修复 2026-09-18 20:11:59 +08:00
liweijie 7e0d96f627 教学任务 → 复制所选 → 粘贴到其它班次,目标班次选择弹窗会正常浮在最上层,不再被遮罩盖住 2026-09-18 19:58:39 +08:00
liweijie fdc7bb01fd 教学业务-班次学期信息管理-操作列点击教学任务-新增课程任务,课编号要求下拉选择,并能带出所选课程的对应信息 2026-09-18 19:51:41 +08:00
liweijie 7096873e2c 教研室账号校验改为用角色校验 2026-09-18 19:31:53 +08:00
liweijie 5a3d202599 添加页面必填信息校验 2026-09-18 19:00:08 +08:00
liweijie 04551fce73 教学公告删除报错 2026-09-18 18:20:36 +08:00
liweijie f36b1f4701 AI测试反馈的报错调整 2026-09-18 18:12:59 +08:00
liweijie 68b02ea58e 部分表名写成了英文名调整 2026-09-18 17:48:31 +08:00
liweijie cff7b039e3 DBVersion的读写修改 2026-09-18 16:56:26 +08:00
liweijie e27b61b5fe 工具条按钮样式统一 2026-09-18 11:50:09 +08:00
liweijie b529f0b523 人才培养方案工具条调整 2026-09-18 11:36:30 +08:00
liweijie a0d5a3b0fe 教学公告添加发布功能 2026-09-18 10:50:26 +08:00
liweijie f3ae9fb2fd 1、校历的78、晚上、夜间等直接落库,
2、配当、任务书完善、排课窗完善;
3、任务书批量发布、删除等;
4、班历同步校历
2026-09-18 10:38:39 +08:00
liweijie 911dfe911b 1课表模板管理;
2、课表生成;
3、课表的网格视图;
4、导出与打印
2026-09-18 09:02:41 +08:00
liweijie 971ea46da5 1、添加实施计划统计分析;
2、添加单课程实施计划列表;
3、恢复同步班历;
4、冲突项添加颜色分级;
5、校历补上正课;
6、添加教学场地总览;
2026-09-17 18:20:48 +08:00
liweijie 351df2cba2 排课功能优化 2026-09-17 17:14:31 +08:00
liweijie a958bcf059 添加排课功能 2026-09-17 15:58:33 +08:00
liweijie 80e91707e6 1、分页添加默认项,
2、登录名冲突无"复用/认领"机制,教员永久无法开通账号
3、两条对齐路径对"停用教研室"处理不一致
2026-09-17 15:18:13 +08:00
liweijie 8c346de4d8 1、停用教员的同时禁用该教员的账号;
2、教员导入的时候,如果有错误,跳过并返回具体报错行;
3、教研室接口权限添加控制
2026-09-17 14:35:06 +08:00
liweijie 95a3571c69 新增教研室和教员的时候,同步创建部门和教员账号 2026-09-17 12:00:44 +08:00
liweijie f7299c36e8 教学大纲新增导出模板和导入按钮 2026-09-17 10:03:29 +08:00
liweijie 9af6de6ff3 新增教学场地校验编号的重复性 2026-09-17 09:30:04 +08:00
liweijie abf616a8ee 班历功能添加 2026-09-16 17:13:57 +08:00
liweijie 2e151ea228 1、添加教学场地历;
2、很多表继承了基础类,但是没有添加对应字段导致报错,把继承去掉
2026-09-16 16:37:23 +08:00
liweijie 58499afe8e 教室编号生成调整 2026-09-16 12:02:33 +08:00
zhaichao 49b3232e79 人培新建 2026-09-16 11:22:11 +08:00
liweijie 62cf543760 专业代码改为下拉框,选择之后带出专业信息 2026-09-16 11:15:13 +08:00
zhaichao af51469121 Merge branch 'main' of https://gitea.fengyingkj.top/liweijie/education 2026-09-16 11:07:00 +08:00
zhaichao 490e1845f6 人才培养方案新增自动生成代号,代码 2026-09-16 11:04:18 +08:00
liweijie 4cb39ca1b0 Merge remote-tracking branch 'origin/main' into main 2026-09-16 09:30:37 +08:00
liweijie 25c1922f08 注释添加 2026-09-16 09:30:31 +08:00
zhaichao bbf54c26a3 人才培养方案新增下拉框 2026-09-16 09:28:16 +08:00
liweijie 9d70d4c25e Merge remote-tracking branch 'origin/main' into main 2026-09-16 09:27:34 +08:00
liweijie 8c992183e3 教学楼排序调整 2026-09-16 09:27:17 +08:00
zhaichao b05c4d33db 教学大纲新增显示排序问题 2026-09-16 09:24:10 +08:00
liweijie b30e39f91a 1、教学楼添加批量删除功能;
2、教学楼导入代号从excel获取,不要自己生成
2026-09-16 09:07:47 +08:00
liweijie d9b10a3f05 教学楼管理功能新增 2026-09-15 18:38:37 +08:00
liweijie 6e767947f7 专业添加导入模板下载和数据上传 2026-09-15 17:43:34 +08:00
liweijie c7397ad457 专业保存提示错误,前后端数据类型不一致导致的 2026-09-15 17:15:06 +08:00
zhaichao 5903f0c590 教学大纲下载功能 2026-09-15 16:13:06 +08:00
zhaichao 5d928bd303 教学大纲停用改删除 2026-09-15 16:06:16 +08:00
liweijie 9312327112 新增教员页面,下拉框乱码修复,保存报错修复 2026-09-15 15:54:06 +08:00
liweijie 3905e5cb54 教学任务书填报 2026-09-15 14:44:16 +08:00
liweijie e8a58b19fe 通过AI比对原操作文档,生成系统功能完善方案,根据方案进行增补,完善从学期新增到最终的排课功能 2026-09-15 14:42:43 +08:00
liweijie 5187435285 学期新增的时候校验校历功能点添加,否则会有大量的数据重复生成 2026-09-14 17:24:56 +08:00
liweijie 52a04dbf60 1、正课与学期关系关联;
2、天假删除保护;
3、教学任务计划增加了「结束发布」。已发布或库里的「已发布」都可以结束;结束后写入结束时间,任务书和班次课程任务只读
4、班次学期操作内容调整修改;
2026-09-14 16:30:52 +08:00
zhaichao 30f2182453 忽略配置 2026-09-10 17:56:11 +08:00
zhaichao afa561a7a4 仓库配置 2026-09-10 17:52:03 +08:00
zhaichao 345f425a1d 前端文件 2026-09-10 17:42:46 +08:00
liumengyu 255a0e56a5 bug修复 2026-09-10 17:31:19 +08:00
liumengyu 407f89a603 bug修复 2026-08-28 19:45:32 +08:00
liumengyu 770d32a625 bug修复 2026-08-28 17:34:56 +08:00
liumengyu a43561af8d bug修复 2026-08-26 09:56:12 +08:00
liumengyu a30b963dea 课表申请功能重写 bug修复 2026-08-25 18:47:22 +08:00
liumengyu aa4145fd33 后端代码 2026-08-24 17:48:55 +08:00
zhaichao e0485f7366 Merge pull request 'Main' (#2) from zhaichao/education:main into main
Reviewed-on: liweijie/education#2
2026-08-24 07:39:18 +00:00
608 changed files with 57840 additions and 7859 deletions
+52
View File
@@ -0,0 +1,52 @@
# OS
.DS_Store
Thumbs.db
Desktop.ini
# IDE / editor
.idea/
*.iml
.vscode/
*.swp
*.swo
*~
# Java / Maven
target/
*.class
*.jar
!backend/DmJdbcDriver8.jar
hs_err_pid*
replay_pid*
# Node / Vue
node_modules/
dist/
frontend/dist/
.cache/
.temp/
# Logs
*.log
logs/
# Env / local secrets
.env
.env.*
!.env.example
*.local
# Test / coverage
coverage/
.nyc_output/
htmlcov/
# Local deploy / agent state
deploy/
.reasonix/
reasonix.toml
.workbuddy/
# Agent scratch (screenshot/temp working dirs, local maven repo)
output/*/working/
m2repo/
-10
View File
@@ -1,10 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="DM" uuid="a3a7e92a-b8da-4229-8b83-5db11f9db9a9">
<driver-ref>9fcb59ee-b3c5-470d-89df-ad01e7cabb15</driver-ref>
<imported>true</imported>
<configured-by-url>true</configured-by-url>
<remarks>$PROJECT_DIR$/backend/roomroot-admin/src/main/resources/application-druid.yml</remarks>
<auto-commit>false</auto-commit>
<jdbc-driver>dm.jdbc.driver.DmDriver</jdbc-driver>
<jdbc-url>jdbc:dm://10.1.1.17:5236?schema=JIAOWU&amp;useUnicode=true&amp;characterEncoding=utf-8</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

@@ -1,8 +0,0 @@
{
"topic_20260818-025043_e469238a6cc39459": {
"stage": 3,
"userTurns": 3,
"basisHash": "ab28583a1084bba5",
"updatedAt": 1787024624634
}
}
-3
View File
@@ -1,3 +0,0 @@
{
"topic_20260818-025043_e469238a6cc39459": 1787021443129
}
@@ -1,3 +0,0 @@
{
"topic_20260818-025043_e469238a6cc39459": "auto"
}
-3
View File
@@ -1,3 +0,0 @@
{
"topic_20260818-025043_e469238a6cc39459": "在JYSController中,教研…"
}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T11:50:58.8315719+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-1","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T11:51:29.838828+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-1","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-1","job_id":"bash-1","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":8,"created_at":"2026-08-18T11:50:58.8315719+08:00","updated_at":"2026-08-18T11:51:29.838828+08:00"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T11:52:59.6491318+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-2","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T11:53:12.5470012+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-2","session_id":"20260818-025043.151598500-session","state":"failed","runtime_state":"exited","error_code":"job_failed"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-2","job_id":"bash-2","session_id":"20260818-025043.151598500-session","state":"failed","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":4,"created_at":"2026-08-18T11:52:59.6491318+08:00","updated_at":"2026-08-18T11:53:12.5470012+08:00","error_code":"job_failed"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T11:55:22.4260602+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-3","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T11:55:48.4568907+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-3","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-3","job_id":"bash-3","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":7,"created_at":"2026-08-18T11:55:22.4260602+08:00","updated_at":"2026-08-18T11:55:48.4568907+08:00"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T11:56:26.9971307+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-4","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T11:57:42.5597432+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-4","session_id":"20260818-025043.151598500-session","state":"cancelled","runtime_state":"exited","error_code":"job_failed"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-4","job_id":"bash-4","session_id":"20260818-025043.151598500-session","state":"cancelled","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":17,"created_at":"2026-08-18T11:56:26.9971307+08:00","updated_at":"2026-08-18T11:57:42.5597432+08:00","error_code":"job_failed"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T15:59:13.8456942+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-5","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T15:59:39.9995233+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-5","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-5","job_id":"bash-5","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":7,"created_at":"2026-08-18T15:59:13.8456942+08:00","updated_at":"2026-08-18T15:59:39.9995233+08:00"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-18T15:59:54.7700222+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-6","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-18T16:01:27.1609364+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-6","session_id":"20260818-025043.151598500-session","state":"cancelled","runtime_state":"exited","error_code":"job_failed"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-6","job_id":"bash-6","session_id":"20260818-025043.151598500-session","state":"cancelled","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":20,"created_at":"2026-08-18T15:59:54.7700222+08:00","updated_at":"2026-08-18T16:01:27.1609364+08:00","error_code":"job_failed"}
@@ -1,2 +0,0 @@
{"sequence":1,"timestamp":"2026-08-20T10:07:19.1030303+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-7","session_id":"20260818-025043.151598500-session","state":"running","runtime_state":"alive"}
{"sequence":2,"timestamp":"2026-08-20T10:08:07.4924999+08:00","event_type":"state_change","task_id":"20260818-025043.151598500-session--bash-7","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited"}
@@ -1 +0,0 @@
{"schema_version":1,"task_id":"20260818-025043.151598500-session--bash-7","job_id":"bash-7","session_id":"20260818-025043.151598500-session","state":"succeeded","runtime_state":"exited","runtime_lease_until":"0001-01-01T00:00:00Z","version":11,"created_at":"2026-08-20T10:07:19.1030303+08:00","updated_at":"2026-08-20T10:08:07.4924999+08:00"}
-4
View File
@@ -1,4 +0,0 @@
# Maven 编译产物
target/
**/target/
*.class
+1 -1
View File
@@ -9,7 +9,7 @@
<version>3.9.2</version>
<name>roomroot</name>
<description>风影随行管理系统</description>
<description>教务管理系统</description>
<properties>
<roomroot.version>3.9.2</roomroot.version>
+7
View File
@@ -37,6 +37,13 @@
<version>8.1.2.192</version>
</dependency>
<!-- openGauss 数据库驱动包 -->
<dependency>
<groupId>org.opengauss</groupId>
<artifactId>opengauss-jdbc</artifactId>
<version>6.0.3-og</version>
</dependency>
<!-- 核心模块-->
<dependency>
<groupId>com.roomroot</groupId>
@@ -5,6 +5,8 @@ import com.roomroot.jwgl.service.BuildService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.build.BuildDeleteResultVO;
import com.roomroot.jwgl.vo.build.BuildImportResultVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
@@ -40,6 +42,15 @@ public class BuildController {
return Result.success();
}
/**
* 批量删除教学楼(已绑定教学场地的跳过不删,暂定)
*/
@PostMapping("/batchDelete")
public Result<BuildDeleteResultVO> batchDelete(@RequestBody List<String> ids) {
BuildDeleteResultVO result = buildService.batchDelete(ids);
return Result.success(result.getMessage(), result);
}
/**
* 更新教学楼
*/
@@ -77,9 +88,9 @@ public class BuildController {
* 导入Excel文件
*/
@PostMapping("/import")
public Result<Integer> importExcel(@RequestParam("file") MultipartFile file) {
int count = buildService.importExcel(file);
return Result.success("导入成功", count);
public Result<BuildImportResultVO> importExcel(@RequestParam("file") MultipartFile file) {
BuildImportResultVO result = buildService.importExcel(file);
return Result.success(result.getMessage(), result);
}
/**
@@ -0,0 +1,65 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.calendar.ClassCalendarApplyDTO;
import com.roomroot.jwgl.dto.calendar.ClassCalendarBatchSaveDTO;
import com.roomroot.jwgl.dto.calendar.ClassCalendarEventDTO;
import com.roomroot.jwgl.service.ClassEventCalendarService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.calendar.ClassCalendarResyncVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 班历(假期表)。与课程任务接口 /classCalendar 分开。
*/
@RestController
@RequestMapping("/class-calendar")
public class ClassEventCalendarController {
@Resource
private ClassEventCalendarService classEventCalendarService;
@GetMapping("/list")
public Result<List<ClassCalendarEventDTO>> list(@RequestParam("xydxqbh") String xydxqbh) {
return Result.success(classEventCalendarService.listOrInherit(xydxqbh));
}
@PostMapping("/update")
public Result<Void> update(@RequestBody ClassCalendarEventDTO event) {
classEventCalendarService.update(event);
return Result.success();
}
/**
* 批量保存班历时间格(拖选区域一次提交,单事务 upsert;action=clear 恢复默认)
*/
@PostMapping("/batchSave")
public Result<Integer> batchSave(@RequestBody ClassCalendarBatchSaveDTO body) {
int saved = classEventCalendarService.batchSave(body);
return Result.success("已保存 " + saved + " 个时间格", saved);
}
/**
* 重新同步校历:confirm=false 返回差异预览,confirm=true 实际写入;
* force=true 时额外覆盖与校历不一致的已有格。
*/
@PostMapping("/resync")
public Result<ClassCalendarResyncVO> resync(@RequestParam("xydxqbh") String xydxqbh,
@RequestParam(value = "confirm", defaultValue = "false") boolean confirm,
@RequestParam(value = "force", defaultValue = "false") boolean force) {
return Result.success(classEventCalendarService.resync(xydxqbh, confirm, force));
}
@PostMapping("/apply")
public Result<Integer> apply(@RequestBody ClassCalendarApplyDTO body) {
return Result.success(classEventCalendarService.apply(
body.getSourceXydxqbh(), body.getTargetBhList(), body.getEventBhList()));
}
}
@@ -5,6 +5,8 @@ import com.roomroot.jwgl.service.ClassRoomCalendarService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.classroom.VenueLessonVO;
import com.roomroot.jwgl.vo.classroom.VenueScheduleItemVO;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@@ -86,4 +88,60 @@ public class ClassRoomCalendarController {
public Result<List<JXCDL>> listByRq(@RequestParam("rq") String rq) {
return Result.success(calendarService.listByRq(rq));
}
/**
* 批量保存场地历事件(拖选区域写入,按 教室编号+日期+节次 判重覆盖)
*/
@PostMapping("/batchSave")
public Result<Integer> batchSave(@RequestBody List<JXCDL> list) {
int saved = calendarService.batchSave(list);
return Result.success("已保存 " + saved + " 个时间格事件", saved);
}
/**
* 按 ID 批量删除场地历事件(恢复可排)
*/
@PostMapping("/batchDelete")
public Result<Integer> batchDelete(@RequestBody List<String> ids) {
int deleted = calendarService.batchDelete(ids);
return Result.success("已删除 " + deleted + " 个时间格事件", deleted);
}
/**
* 按教室编号 + 日期范围查询场地历
*/
@GetMapping("/listByJsbhAndRange")
public Result<List<JXCDL>> listByJsbhAndRange(@RequestParam("jsbh") String jsbh,
@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end) {
return Result.success(calendarService.listByJsbhAndRange(jsbh, start, end));
}
/**
* 查询场地在日期范围内已排课次(编辑器蓝格数据源)
*/
@GetMapping("/lessons")
public Result<List<VenueLessonVO>> listVenueLessons(@RequestParam("jsbh") String jsbh,
@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end,
@RequestParam(value = "nd", required = false) Integer nd) {
return Result.success(calendarService.listVenueLessons(jsbh, start, end, nd));
}
/**
* 查询指定本场地为专用教室的班次(编辑器顶部横幅数据源)
*/
@GetMapping("/designatedTeams")
public Result<List<String>> listDesignatedTeams(@RequestParam("jsbh") String jsbh) {
return Result.success(calendarService.listDesignatedTeams(jsbh));
}
/**
* 场地占用总览:某日期+节次全部场地的占用状态
*/
@GetMapping("/venueSchedule")
public Result<List<VenueScheduleItemVO>> venueSchedule(@RequestParam("rq") String rq,
@RequestParam("jc") Integer jc) {
return Result.success(calendarService.venueSchedule(rq, jc));
}
}
@@ -13,7 +13,7 @@ import java.util.Map;
* 学员队任务表控制器
*/
@RestController
@RequestMapping("/classCalendar")
@RequestMapping({"/classCalendar", "/course-task"})
public class ClassSemesterCalendarController {
@Resource
@@ -3,7 +3,6 @@ package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.courserunning.ClassesImportDTO;
import com.roomroot.jwgl.dto.courserunning.ImportRemoveDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustApplyDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustStrategyDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustAuditDTO;
import com.roomroot.jwgl.dto.courserunning.ScheduleAdjustQueryDTO;
import com.roomroot.jwgl.dto.courserunning.SemesterImportDTO;
@@ -290,24 +289,30 @@ public class CourseRunningController {
/**
* 分页查询调课申请列表。
* <p>
* 根据查询条件分页查询调课申请列表,支持按实施_课程表编号、申请教员、
* 年度、审批状态、查收状态、删除状态、申请日期范围筛选。
* </p>
*
* @param query 查询参数(包含分页信息和筛选条件)
* @return 分页调课申请列表
*/
@GetMapping("/adjust/list")
public Result<PageResult<ScheduleAdjustApplyVO>> queryScheduleAdjustList(ScheduleAdjustQueryDTO query) {
return Result.success(courseRunningImportService.queryScheduleAdjustList(query));
}
/**
* 查询当前教员可供调课的课次。
* <p>
* 返回值对齐 {@code /adjust/submit} 入参:除事由、备注等需用户填写的项外,
* 其余字段带出当前课次默认值。
* </p>
*/
@GetMapping("/adjust/lessons")
public Result<List<AdjustableLessonVO>> listAdjustableLessons(
@RequestParam(value = "nd", required = false) Integer nd) {
return Result.success(courseRunningImportService.listAdjustableLessons(nd));
}
/**
* 查询单个调课申请的完整详情。
* <p>
* 根据调课申请编号查询该申请的完整信息,包括申请信息、调整后的内容、
* 教研室审批状态、机关审批记录、关联的教室、辅助教员、学员队、保障明细等。
* 教研室审批与查收状态、关联的教室、辅助教员、学员队、保障明细等。
* </p>
*
* @param ssdksqbh 调课申请编号
@@ -336,148 +341,30 @@ public class CourseRunningController {
/**
* 教研室审批调课申请。
* <p>
* 教研室审批教员提交的调课申请,包含同意、发回、拒绝三种处理方式。
* 教研室审批调课申请。点审批即已查收,审批人同时记为查收人。
* 同意、发回、拒绝均为已查收;教员撤回后为未查收。
* </p>
*
* @param dto 教研室审批参数(auditRole 传 "jys")
* @param dto 教研室审批参数
* @return 操作结果
*/
@PostMapping("/adjust/audit/jys")
public Result<Void> auditByTeachingOffice(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为教研室
dto.setAuditRole("jys");
courseRunningImportService.auditByTeachingOffice(dto);
return Result.success();
}
/**
* 教研室查收调课申请。
* <p>
* 教研室查收调课申请,标记查收状态和查收时间。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param csrbh 查收人编号
* @return 操作结果
*/
@PostMapping("/adjust/receive/jys")
public Result<Void> receiveByTeachingOffice(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("csrbh") String csrbh) {
courseRunningImportService.receiveByTeachingOffice(ssdksqbh, csrbh);
return Result.success();
}
/**
* 教学系审批调课申请。
* <p>
* 教学系审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。
* 构成三级审批流程的中间环节(教研室→教学系→机关)。
* </p>
*
* @param dto 教学系审批参数(auditRole 传 "jxx")
* @return 操作结果
*/
@PostMapping("/adjust/audit/jxx")
public Result<Void> auditByTeachingDepartment(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为教学系
dto.setAuditRole("jxx");
courseRunningImportService.auditByTeachingDepartment(dto);
return Result.success();
}
/**
* 机关审批调课申请。
* <p>
* 机关审批教研室已同意的调课申请,包含同意、发回、拒绝三种处理方式。
* </p>
*
* @param dto 机关审批参数(auditRole 传 "jg",需传 jgbh)
* @return 操作结果
*/
@PostMapping("/adjust/audit/jg")
public Result<Void> auditByAuthority(@Valid @RequestBody ScheduleAdjustAuditDTO dto) {
// 自动设置审批角色为机关
dto.setAuditRole("jg");
courseRunningImportService.auditByAuthority(dto);
return Result.success();
}
/**
* 机关查收调课申请。
* <p>
* 机关查收调课申请,标记查收状态和查收时间。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param jgbh 机关编号
* @param csrbh 查收人编号
* @return 操作结果
*/
@PostMapping("/adjust/receive/jg")
public Result<Void> receiveByAuthority(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("jgbh") String jgbh,
@RequestParam("csrbh") String csrbh) {
courseRunningImportService.receiveByAuthority(ssdksqbh, jgbh, csrbh);
return Result.success();
}
/**
* 撤销调课申请。
* <p>
* 教员撤销自己提交的、未经过审批的调课申请。
* 教员撤销未经过审批的调课申请。列表已按登录教员过滤,只需传申请编号。
* </p>
*
* @param ssdksqbh 调课申请编号
* @param sqjybh 申请教员编号
* @return 操作结果
*/
@DeleteMapping("/adjust/cancel")
public Result<Void> cancelScheduleAdjust(@RequestParam("ssdksqbh") String ssdksqbh,
@RequestParam("sqjybh") String sqjybh) {
courseRunningImportService.cancelScheduleAdjust(ssdksqbh, sqjybh);
return Result.success();
}
// ==================== 调课策略管理 ====================
/**
* 查询调课策略列表。
* <p>
* 支持按策略类型筛选,返回所有策略(含停用)。
* </p>
*
* @param cllx 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批,为空时查询全部
* @return 调课策略列表
*/
@GetMapping("/adjust/strategy/list")
public Result<List<ScheduleAdjustStrategyVO>> listScheduleAdjustStrategies(
@RequestParam(required = false) String cllx) {
return Result.success(courseRunningImportService.listScheduleAdjustStrategies(cllx));
}
/**
* 保存调课策略(新增或修改)。
* <p>
* 策略编号为空时执行新增,非空时执行修改。
* </p>
*
* @param dto 策略参数
* @return 策略编号
*/
@PostMapping("/adjust/strategy/save")
public Result<String> saveScheduleAdjustStrategy(@Valid @RequestBody ScheduleAdjustStrategyDTO dto) {
return Result.success("保存成功", courseRunningImportService.saveScheduleAdjustStrategy(dto));
}
/**
* 删除调课策略。
*
* @param clbh 策略编号
* @return 操作结果
*/
@DeleteMapping("/adjust/strategy/delete")
public Result<Void> deleteScheduleAdjustStrategy(@RequestParam("clbh") String clbh) {
courseRunningImportService.deleteScheduleAdjustStrategy(clbh);
public Result<Void> cancelScheduleAdjust(@RequestParam("ssdksqbh") String ssdksqbh) {
courseRunningImportService.cancelScheduleAdjust(ssdksqbh);
return Result.success();
}
@@ -6,14 +6,19 @@ import com.roomroot.jwgl.service.DisciplineService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.discipline.MajorImportResultVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* 学科专业管理控制器
@@ -212,4 +217,36 @@ public class DisciplineManagementController {
cond.setTy(ty);
return Result.success(disciplineService.pageMajor(new PageQuery(pageNum, pageSize), cond));
}
/**
* 从 Excel 导入专业(.xls/.xlsx)。
* <p>
* 表头按专业导入模板的列名匹配(列顺序不限)。已存在的专业跳过、不覆盖库中已有数据;
* 校验不通过的行跳过并在结果明细中给出原因,合格行正常导入。
* </p>
*
* @param file 上传的 Excel 文件(form-data 字段名 file)
* @return 导入结果(新增/跳过/失败数量与明细)
*/
@PostMapping("/major/import")
public Result<MajorImportResultVO> importMajor(@RequestParam("file") MultipartFile file) throws Exception {
MajorImportResultVO result = disciplineService.importMajorExcel(file);
return Result.success(result.getMessage(), result);
}
/**
* 下载专业导入模板(xlsx),列头与导入解析保持一致。
*
* @param response 响应对象
*/
@GetMapping("/major/template")
public void downloadMajorTemplate(HttpServletResponse response) throws Exception {
byte[] bytes = disciplineService.buildMajorImportTemplate();
String fileName = "专业导入模板.xlsx";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename="
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
response.getOutputStream().write(bytes);
response.getOutputStream().flush();
}
}
@@ -2,6 +2,8 @@ package com.roomroot.web.controller.jwgl;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.common.utils.file.FileUtils;
import com.roomroot.jwgl.service.TeachingMaterialService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ClassPathResource;
@@ -23,6 +25,9 @@ public class DownloadController {
private static final String TEMPLATE_DIR = "file/";
@Resource
private TeachingMaterialService teachingMaterialService;
/**
* 人才培养方案课程数据文件模板
*/
@@ -56,11 +61,11 @@ public class DownloadController {
}
/**
* 教材管理模板
* 教材管理模板(动态生成,与 /teachingMaterial/template 一致)
*/
@GetMapping("/teaching-material")
public void downloadTeachingMaterial(HttpServletResponse response) throws IOException {
downloadTemplate(response, "教材管理.xls");
public void downloadTeachingMaterial(HttpServletResponse response) {
teachingMaterialService.downloadTemplate(response);
}
/**
@@ -72,11 +77,156 @@ public class DownloadController {
}
/**
* 联教连训管理模板
* 教员导入模板(动态生成:数据 sheet + 填写说明 sheet)。
* <p>列序与 /jys/teacher/import 解析一致:
* 教员编号、教员姓名、教研室代号、职称、专业技术职务等级、教员类别、
* 性别、手机号、身份证号、备注、序号、虚实类型。</p>
*/
@GetMapping("/jy")
public void downloadJy(HttpServletResponse response) throws IOException {
org.apache.poi.ss.usermodel.Workbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook();
try {
org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle();
org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerStyle.setFont(headerFont);
org.apache.poi.ss.usermodel.CellStyle requiredStyle = workbook.createCellStyle();
org.apache.poi.ss.usermodel.Font requiredFont = workbook.createFont();
requiredFont.setBold(true);
requiredFont.setColor(org.apache.poi.ss.usermodel.IndexedColors.RED.getIndex());
requiredStyle.setFont(requiredFont);
String[] headers = {"教员编号", "教员姓名*", "教研室代号*", "职称", "专业技术职务等级",
"教员类别", "性别", "手机号", "身份证号", "备注", "序号", "虚实类型"};
org.apache.poi.ss.usermodel.Sheet dataSheet = workbook.createSheet("教员");
org.apache.poi.ss.usermodel.Row headerRow = dataSheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
org.apache.poi.ss.usermodel.Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headers[i].endsWith("*") ? requiredStyle : headerStyle);
dataSheet.setColumnWidth(i, 16 * 256);
}
String[][] instructions = {
{"教员编号", "选填", "留空则系统自动生成(JY+流水号);手填须唯一"},
{"教员姓名", "必填", "文本"},
{"教研室代号", "必填", "教研室表中的教研室代号(非名称),必须已存在"},
{"职称", "选填", "文本,如:讲师、副教授"},
{"专业技术职务等级", "选填", "文本,如:初级、中级、高级"},
{"教员类别", "选填", "文本,如:专业技术军官"},
{"性别", "选填", "数字:1=男,0=女"},
{"手机号", "选填", "文本"},
{"身份证号", "选填", "文本"},
{"备注", "选填", "文本"},
{"序号", "选填", "数字"},
{"虚实类型", "选填", "数字:0=实员"}
};
org.apache.poi.ss.usermodel.Sheet helpSheet = workbook.createSheet("填写说明");
org.apache.poi.ss.usermodel.Row titleRow = helpSheet.createRow(0);
org.apache.poi.ss.usermodel.Cell titleCell = titleRow.createCell(0);
titleCell.setCellValue("教员导入填写说明(红色表头列为必填;导入只写教员档案不建账号,账号用列表【对齐到用户表】批量开通)");
titleCell.setCellStyle(headerStyle);
String[] helpHeaders = {"列名", "是否必填", "填写说明"};
org.apache.poi.ss.usermodel.Row helpHeaderRow = helpSheet.createRow(1);
for (int i = 0; i < helpHeaders.length; i++) {
org.apache.poi.ss.usermodel.Cell cell = helpHeaderRow.createCell(i);
cell.setCellValue(helpHeaders[i]);
cell.setCellStyle(headerStyle);
}
for (int i = 0; i < instructions.length; i++) {
org.apache.poi.ss.usermodel.Row row = helpSheet.createRow(i + 2);
for (int j = 0; j < 3; j++) {
row.createCell(j).setCellValue(instructions[i][j]);
}
if ("必填".equals(instructions[i][1])) {
row.getCell(1).setCellStyle(requiredStyle);
}
}
helpSheet.setColumnWidth(0, 18 * 256);
helpSheet.setColumnWidth(1, 10 * 256);
helpSheet.setColumnWidth(2, 60 * 256);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileUtils.setAttachmentResponseHeader(response, "教员导入模板.xlsx");
workbook.write(response.getOutputStream());
response.getOutputStream().flush();
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new ServiceException("生成教员导入模板失败:" + e.getMessage());
} finally {
try {
workbook.close();
} catch (IOException ignored) {
}
}
}
/**
* 联教联训导入模板(动态生成:宋体表头 + 测试样例)。
* 列序与 ExcelParseUtil.parseKSBZXMExcel 一致。
*/
@GetMapping("/joint-training")
public void downloadJointTraining(HttpServletResponse response) throws IOException {
downloadTemplate(response, "联教连训管理.xls");
org.apache.poi.ss.usermodel.Workbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook();
try {
org.apache.poi.ss.usermodel.Font headerFont = workbook.createFont();
headerFont.setFontName("宋体");
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 11);
org.apache.poi.ss.usermodel.CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setFont(headerFont);
org.apache.poi.ss.usermodel.Font dataFont = workbook.createFont();
dataFont.setFontName("宋体");
dataFont.setFontHeightInPoints((short) 11);
org.apache.poi.ss.usermodel.CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setFont(dataFont);
String[] headers = {
"序号", "补助项目名称", "性质", "依据", "开始日期", "结束日期",
"项目说明", "项目备注", "教研室名称", "补助教员姓名", "补助课时量", "课时量备注"
};
org.apache.poi.ss.usermodel.Sheet sheet = workbook.createSheet("联教联训");
org.apache.poi.ss.usermodel.Row headerRow = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
org.apache.poi.ss.usermodel.Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
sheet.setColumnWidth(i, 18 * 256);
}
String[][] samples = {
{"1", "联教联训测试项目甲", "集中", "训练计划〔2026〕1号", "2026-03-01", "2026-03-10",
"联合教学演练", "导入测试样例1", "战术教研室", "张三", "16", "含备课课时"},
{"2", "联教联训测试项目乙", "分散", "训练计划〔2026〕2号", "2026-05-08", "2026-05-20",
"跨校区联训", "导入测试样例2", "射击教研室", "李四", "24", ""},
{"3", "联教联训测试项目丙", "集中", "训练计划〔2026〕3号", "2026-09-01", "2026-09-15",
"联训考核", "导入测试样例3", "指挥教研室", "王五", "12", "按天数核算"}
};
for (int r = 0; r < samples.length; r++) {
org.apache.poi.ss.usermodel.Row row = sheet.createRow(r + 1);
for (int c = 0; c < samples[r].length; c++) {
org.apache.poi.ss.usermodel.Cell cell = row.createCell(c);
cell.setCellValue(samples[r][c]);
cell.setCellStyle(dataStyle);
}
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
FileUtils.setAttachmentResponseHeader(response, "联教联训数据文件模板.xlsx");
workbook.write(response.getOutputStream());
response.getOutputStream().flush();
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new ServiceException("生成联教联训导入模板失败:" + e.getMessage());
} finally {
try {
workbook.close();
} catch (IOException ignored) {
}
}
}
/**
@@ -344,8 +344,9 @@ public class ElectiveController {
public Result<SemesterInitVO> semesterInit(
@RequestParam("xydbh") String xydbh,
@RequestParam(required = false) String presetKxrq,
@RequestParam(required = false) String presetJsrq) {
return Result.success(electiveService.getSemesterInit(xydbh, presetKxrq, presetJsrq));
@RequestParam(required = false) String presetJsrq,
@RequestParam(required = false) Integer xqdc) {
return Result.success(electiveService.getSemesterInit(xydbh, presetKxrq, presetJsrq, xqdc));
}
/**
@@ -38,7 +38,7 @@ public class FacultyController {
*/
@PostMapping("/office/add")
public Result<Void> addOffice(@RequestBody JYSB entity) {
facultyService.addJYSB(entity);
facultyService.addJYSB(entity, null);
return Result.success();
}
@@ -49,7 +49,7 @@ public class FacultyController {
*/
@PostMapping("/office/disable")
public Result<Void> disableOffice(@RequestParam("jysdh") String jysdh) {
facultyService.disableJYSB(jysdh);
facultyService.disableJYSB(jysdh, null);
return Result.success();
}
@@ -58,7 +58,7 @@ public class FacultyController {
*/
@PostMapping("/office/update")
public Result<Void> updateOffice(@RequestBody JYSB entity) {
facultyService.updateJYSB(entity);
facultyService.updateJYSB(entity, null);
return Result.success();
}
@@ -1,20 +1,44 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.common.core.domain.entity.SysUser;
import com.roomroot.common.utils.StringUtils;
import com.roomroot.jwgl.dto.faculty.AddTeacherDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseBatchDTO;
import com.roomroot.jwgl.dto.jys.ElectiveCourseQuery;
import com.roomroot.jwgl.dto.jys.ElectiveCourseSaveDTO;
import com.roomroot.jwgl.dto.jys.TeachingTaskQuery;
import com.roomroot.jwgl.dto.jys.TeachingTaskSaveDTO;
import com.roomroot.jwgl.entity.JYB;
import com.roomroot.jwgl.entity.JYSB;
import com.roomroot.jwgl.entity.JYSX;
import com.roomroot.jwgl.entity.KB;
import com.roomroot.jwgl.service.ElectiveCourseService;
import com.roomroot.jwgl.service.FacultyService;
import com.roomroot.jwgl.service.KBService;
import com.roomroot.jwgl.service.TeachingTaskManageService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.faculty.TeacherListVO;
import com.roomroot.jwgl.vo.jys.ElectiveCourseVO;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookCourseVO;
import com.roomroot.jwgl.vo.jys.TeachingOfficeBookVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskDetailVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskSquadVO;
import com.roomroot.jwgl.vo.jys.TeachingTaskVO;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.faculty.TeacherListVO;
import com.roomroot.jwgl.vo.jys.ElectiveCourseVO;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 教研室管理(教研室管理
* 教员管理
@@ -32,14 +56,25 @@ public class JYSController {
@Resource
private KBService kbService;
@Resource
private ElectiveCourseService electiveCourseService;
@Resource
private TeachingTaskManageService teachingTaskManageService;
@Resource
private com.roomroot.jwgl.service.OrgSyncService orgSyncService;
// ======================== 教研室管理 ========================
/**
* 新增教研室
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/office/add")
public Result<Void> addOffice(@RequestBody JYSB entity) {
facultyService.addJYSB(entity);
public Result<Void> addOffice(@RequestBody JYSB entity,
@RequestParam(required = false) Boolean syncDept) {
facultyService.addJYSB(entity, syncDept);
return Result.success();
}
@@ -50,26 +85,56 @@ public class JYSController {
* 001 001 军事基础教研室 军基 基础部
* @param jysdh 教研室代号
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/office/disable")
public Result<Void> disableOffice(@RequestParam("jysdh") String jysdh) {
facultyService.disableJYSB(jysdh);
public Result<Void> disableOffice(@RequestParam("jysdh") String jysdh,
@RequestParam(required = false) Boolean syncDept) {
facultyService.disableJYSB(jysdh, syncDept);
return Result.success();
}
/**
* 更新教研室
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/office/update")
public Result<Void> updateOffice(@RequestBody JYSB entity) {
facultyService.updateJYSB(entity);
public Result<Void> updateOffice(@RequestBody JYSB entity,
@RequestParam(required = false) Boolean syncDeptName) {
facultyService.updateJYSB(entity, syncDeptName);
return Result.success();
}
/**
* 单个教研室补建/对齐组织部门(幂等:已关联则直接返回部门编号)。
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/office/sync-dept")
public Result<Long> syncOfficeDept(@RequestParam("jysdh") String jysdh) {
JYSB entity = facultyService.getJYSBById(jysdh);
if (entity == null) {
return Result.error("教研室不存在:" + jysdh);
}
return Result.success(orgSyncService.ensureOfficeDept(entity));
}
/**
* 对齐组织部门:为教研室批量创建/复用组织部门(直接执行,幂等)。
* body:{ "ids": ["JYS01", ...] };ids 不传 = 全部教研室。
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/org/align-dept")
public Result<com.roomroot.jwgl.vo.orgsync.OrgAlignResultVO> alignDepts(
@RequestBody(required = false) java.util.Map<String, List<String>> body) {
List<String> ids = body == null ? null : body.get("ids");
return Result.success(orgSyncService.alignDepts(ids));
}
/**
* 根据代号查询教研室详情
*
* @param jysdh 教研室代号
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@GetMapping("/office/get")
public Result<JYSB> getOffice(@RequestParam("jysdh") String jysdh) {
JYSB entity = facultyService.getJYSBById(jysdh);
@@ -86,13 +151,15 @@ public class JYSController {
* </ul>
* </p>
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@GetMapping("/office/list")
public Result<PageResult<JYSB>> listOffice(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jysdh,
@RequestParam(required = false) String jysmc,
@RequestParam(required = false) String bx) {
@RequestParam(required = false) String bx,
@RequestParam(required = false) String ty) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
@@ -100,6 +167,7 @@ public class JYSController {
cond.setJysdh(jysdh);
cond.setJysmc(jysmc);
cond.setBx(bx);
cond.setTy(StringUtils.hasText(ty) ? Integer.valueOf(ty) : null);
PageResult<JYSB> pageResult = facultyService.pageJYSB(query, cond);
return Result.success(pageResult);
}
@@ -113,9 +181,11 @@ public class JYSController {
* 未填写时返回"XX未填写";序号、停用、虚实类型等非空字段由后台自动填充。
* </p>
*/
@PreAuthorize("@ss.hasPermi('teach:office:list')")
@PostMapping("/office/import")
public Result<Integer> importOffice(@RequestParam("file") MultipartFile file) throws Exception {
int count = facultyService.importJYSBFromExcel(file);
public Result<Integer> importOffice(@RequestParam("file") MultipartFile file,
@RequestParam(required = false) Boolean syncDept) throws Exception {
int count = facultyService.importJYSBFromExcel(file, syncDept);
return Result.success("导入成功,共" + count + "条记录", count);
}
// ======================== 教员管理 ========================
@@ -124,6 +194,7 @@ public class JYSController {
* 新增教员(同时写入教员表和教员属性表)
* <p>教员属性中的非空字段由前端一并传入。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/add")
public Result<Void> addTeacher(@RequestBody AddTeacherDTO dto) {
facultyService.addJYB(dto);
@@ -135,16 +206,77 @@ public class JYSController {
*
* @param jybh 教员编号
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/disable")
public Result<Void> disableTeacher(@RequestParam("jybh") String jybh) {
facultyService.disableJYB(jybh);
return Result.success();
}
/**
* 复职(还原离职状态)教员
*
* @param jybh 教员编号
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/enable")
public Result<Void> enableTeacher(@RequestParam("jybh") String jybh) {
facultyService.enableJYB(jybh);
return Result.success();
}
/**
* 单个教员补建/对齐系统账号(幂等:已有账号直接返回用户编号)。
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/sync-user")
public Result<Long> syncTeacherUser(@RequestParam("jybh") String jybh,
@RequestParam(required = false) String loginName,
@RequestParam(required = false) String password,
@RequestParam(required = false) Long roleId) {
JYB entity = facultyService.getJYBById(jybh);
if (entity == null) {
return Result.error("教员不存在:" + jybh);
}
SysUser user = orgSyncService.ensureTeacherUser(entity, loginName, password, roleId);
String expected = StringUtils.hasText(loginName) ? loginName.trim() : jybh;
if (!expected.equals(user.getUserName())) {
return Result.success("登录名 " + expected + " 已被无关账号占用,已自动改用 "
+ user.getUserName(), user.getUserId());
}
return Result.success(user.getUserId());
}
/**
* 对齐到用户表:为无账号教员批量建账号(直接执行,幂等,逐条返回明细)。
* body:{ "ids": ["JY01", ...] };ids 不传 = 全部无账号教员。
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/align-user")
public Result<com.roomroot.jwgl.vo.orgsync.OrgAlignResultVO> alignUsers(
@RequestBody(required = false) java.util.Map<String, List<String>> body) {
List<String> ids = body == null ? null : body.get("ids");
return Result.success(orgSyncService.alignUsers(ids));
}
/**
* 一键对齐:先对齐组织部门、再对齐用户账号(同一事务,幂等)。
*/
@PreAuthorize("@ss.hasPermi('teach:office:list') and @ss.hasPermi('teach:teacher:list')")
@PostMapping("/org/align-apply")
public Result<java.util.Map<String, com.roomroot.jwgl.vo.orgsync.OrgAlignResultVO>> alignApply() {
java.util.Map<String, com.roomroot.jwgl.vo.orgsync.OrgAlignResultVO> result =
new java.util.LinkedHashMap<>();
result.put("dept", orgSyncService.alignDepts(null));
result.put("user", orgSyncService.alignUsers(null));
return Result.success(result);
}
/**
* 更新教员基本信息
* <p>支持教学单位调整(修改教研室代号)、职称调整(修改职称、专业技术职务等级)。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/update")
public Result<Void> updateTeacher(@RequestBody JYB entity) {
facultyService.updateJYB(entity);
@@ -156,6 +288,7 @@ public class JYSController {
*
* @param jybh 教员编号
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@GetMapping("/teacher/get")
public Result<JYB> getTeacher(@RequestParam("jybh") String jybh) {
JYB entity = facultyService.getJYBById(jybh);
@@ -174,6 +307,7 @@ public class JYSController {
* </ul>
* </p>
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@GetMapping("/teacher/list")
public Result<PageResult<TeacherListVO>> listTeacher(
@RequestParam(defaultValue = "1") Integer pageNum,
@@ -181,7 +315,8 @@ public class JYSController {
@RequestParam(required = false) String jyxm,
@RequestParam(required = false) String jysdh,
@RequestParam(required = false) String zc,
@RequestParam(required = false) String jylb) {
@RequestParam(required = false) String jylb,
@RequestParam(required = false) Integer lzzt) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
@@ -190,10 +325,41 @@ public class JYSController {
cond.setJysdh(jysdh);
cond.setZc(zc);
cond.setJylb(jylb);
cond.setLzzt(lzzt);
PageResult<TeacherListVO> pageResult = facultyService.pageJYBDetail(query, cond);
return Result.success(pageResult);
}
/**
* 去重职称列表(职称检索下拉数据源,职称无字典表)
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@GetMapping("/teacher/zc-options")
public Result<java.util.List<String>> teacherZcOptions() {
return Result.success(facultyService.listDistinctZc());
}
/**
* 教员数据文件导入(.xls/.xlsx)
* <p>表头顺序:教员编号, 教员姓名, 教研室代号, 职称, 专业技术职务等级, 教员类别,
* 性别, 手机号, 身份证号, 备注, 序号, 虚实类型。教员编号不填自动创建,离职状态默认 0。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/import")
public Result<Integer> importTeacher(@RequestParam("file") MultipartFile file) throws Exception {
int count = facultyService.importJYBFromExcel(file);
return Result.success("导入成功,共" + count + "条", count);
}
/**
* 导出全部在职教员到 Excel(.xlsx)。
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@GetMapping("/teacher/export")
public void exportTeacher(HttpServletResponse response) throws Exception {
facultyService.exportJYBExcel(response);
}
// ======================== 教员属性管理 ========================
/**
@@ -201,6 +367,7 @@ public class JYSController {
*
* @param jybh 教员编号
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@GetMapping("/teacher/attribute/get")
public Result<JYSX> getTeacherAttribute(@RequestParam("jybh") String jybh) {
JYSX entity = facultyService.getJYSXByJYBH(jybh);
@@ -211,6 +378,7 @@ public class JYSController {
* 更新教员属性
* <p>支持岗位调整(修改职务、职务时间)和技术等级调整(修改技术等级、技术等级时间)。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:teacher:list')")
@PostMapping("/teacher/attribute/update")
public Result<Void> updateTeacherAttribute(@RequestBody JYSX entity) {
facultyService.updateJYSX(entity);
@@ -226,6 +394,7 @@ public class JYSController {
* @param entity 课表实体
* @return 操作结果
*/
@PreAuthorize("@ss.hasPermi('teach:subject:list')")
@PostMapping("/kb/add")
public Result<Void> addKb(@RequestBody KB entity) {
kbService.add(entity);
@@ -239,6 +408,7 @@ public class JYSController {
* @param kbh 课编号
* @return 操作结果
*/
@PreAuthorize("@ss.hasPermi('teach:subject:list')")
@PostMapping("/kb/delete")
public Result<Void> deleteKb(@RequestParam("kbh") String kbh) {
kbService.delete(kbh);
@@ -251,6 +421,7 @@ public class JYSController {
* @param entity 课表实体(须含课编号)
* @return 操作结果
*/
@PreAuthorize("@ss.hasPermi('teach:subject:list')")
@PostMapping("/kb/update")
public Result<Void> updateKb(@RequestBody KB entity) {
kbService.update(entity);
@@ -263,6 +434,7 @@ public class JYSController {
* @param kbh 课编号
* @return 课表详情
*/
@PreAuthorize("@ss.hasPermi('teach:subject:list')")
@GetMapping("/kb/get")
public Result<KB> getKb(@RequestParam("kbh") String kbh) {
return Result.success(kbService.getByKbh(kbh));
@@ -282,6 +454,7 @@ public class JYSController {
* @param jc 简称(模糊,可选)
* @return 分页结果
*/
@PreAuthorize("@ss.hasPermi('teach:subject:list')")
@GetMapping("/kb/list")
public Result<PageResult<KB>> listKb(
@RequestParam(defaultValue = "1") Integer pageNum,
@@ -303,4 +476,263 @@ public class JYSController {
cond.setJc(jc);
return Result.success(kbService.pageList(new PageQuery(pageNum, pageSize), cond));
}
// ======================== 选修课管理 ========================
/**
* 分页查询选修课。
* <p>
* 联查学员队任务表、学员队表、课表,课类型含“选修”。
* 支持按授课教员、课程科目名称、可选班次年级、选修班名称、选择课状态、培训层次筛选。
* </p>
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@GetMapping("/elective/list")
public Result<PageResult<ElectiveCourseVO>> listElective(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String jyxm,
@RequestParam(required = false) String kmc,
@RequestParam(required = false) String kxbcnj,
@RequestParam(required = false) String xxbmc,
@RequestParam(required = false) String xkzt,
@RequestParam(required = false) String pxcc) {
ElectiveCourseQuery cond = new ElectiveCourseQuery();
cond.setJyxm(jyxm);
cond.setKmc(kmc);
cond.setKxbcnj(kxbcnj);
cond.setXxbmc(xxbmc);
cond.setXkzt(xkzt);
cond.setPxcc(pxcc);
return Result.success(electiveCourseService.pageList(new PageQuery(pageNum, pageSize), cond));
}
/**
* 新建选修课。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/add")
public Result<Void> addElective(@RequestBody ElectiveCourseSaveDTO dto) {
electiveCourseService.add(dto);
return Result.success();
}
/**
* 所选批量开放报名。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/batch-open")
public Result<Integer> batchOpenElective(@RequestBody ElectiveCourseBatchDTO dto) {
int count = electiveCourseService.batchOpenRegistration(dto == null ? null : dto.getBhList());
return Result.success("已开放报名 " + count + " 条", count);
}
/**
* 所选批量取消开放报名。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/batch-cancel-open")
public Result<Integer> batchCancelOpenElective(@RequestBody ElectiveCourseBatchDTO dto) {
int count = electiveCourseService.batchCancelOpenRegistration(dto == null ? null : dto.getBhList());
return Result.success("已取消开放报名 " + count + " 条", count);
}
/**
* 批量停止报名。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/batch-stop")
public Result<Integer> batchStopElective(@RequestBody ElectiveCourseBatchDTO dto) {
int count = electiveCourseService.batchStopRegistration(dto == null ? null : dto.getBhList());
return Result.success("已停止报名 " + count + " 条", count);
}
/**
* 所选批量根据学员反向确定班次范围。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/batch-reverse-range")
public Result<Integer> batchReverseRangeElective(@RequestBody ElectiveCourseBatchDTO dto) {
int count = electiveCourseService.batchReverseClassRange(dto == null ? null : dto.getBhList());
return Result.success("已根据学员反向确定班次范围 " + count + " 条", count);
}
/**
* 下载选修班列表。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@GetMapping("/elective/export")
public void exportElective(
@RequestParam(required = false) String jyxm,
@RequestParam(required = false) String kmc,
@RequestParam(required = false) String kxbcnj,
@RequestParam(required = false) String xxbmc,
@RequestParam(required = false) String xkzt,
@RequestParam(required = false) String pxcc,
HttpServletResponse response) {
ElectiveCourseQuery cond = new ElectiveCourseQuery();
cond.setJyxm(jyxm);
cond.setKmc(kmc);
cond.setKxbcnj(kxbcnj);
cond.setXxbmc(xxbmc);
cond.setXkzt(xkzt);
cond.setPxcc(pxcc);
electiveCourseService.exportClassList(cond, response);
}
/**
* 下载选修班学员名单 Excel。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@GetMapping("/elective/students/export-excel")
public void exportElectiveStudentExcel(@RequestParam("bhList") List<String> bhList,
HttpServletResponse response) {
electiveCourseService.exportStudentExcel(bhList, response);
}
/**
* 下载选修班学员名单 Word。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@GetMapping("/elective/students/export-word")
public void exportElectiveStudentWord(@RequestParam("bhList") List<String> bhList,
HttpServletResponse response) {
electiveCourseService.exportStudentWord(bhList, response);
}
/**
* 上传选修课数据。
*/
@PreAuthorize("@ss.hasPermi('teach:elective:list')")
@PostMapping("/elective/import")
public Result<Integer> importElective(@RequestParam("file") MultipartFile file) throws Exception {
int count = electiveCourseService.importData(file);
return Result.success("导入成功,共" + count + "条", count);
}
// ======================== 教学任务管理 ========================
/**
* 分页查询教学任务列表。
* <p>含教研室数、学员队数、合班前后课程任务数和学时。未传年度时按当前学期。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/list")
public Result<PageResult<TeachingTaskVO>> listTask(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String rwmc,
@RequestParam(required = false) Integer nd,
@RequestParam(required = false) Integer xqdc,
@RequestParam(required = false) String zt) {
TeachingTaskQuery cond = new TeachingTaskQuery();
cond.setRwmc(rwmc);
cond.setNd(nd);
cond.setXqdc(xqdc);
cond.setZt(zt);
return Result.success(teachingTaskManageService.pageList(new PageQuery(pageNum, pageSize), cond));
}
/**
* 教学任务详情(含教研室任务书、学员队两个页签)。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/get")
public Result<TeachingTaskDetailVO> getTask(@RequestParam("bh") String bh) {
return Result.success(teachingTaskManageService.getDetail(bh));
}
/**
* 新增教学任务。
* <p>机关发布;关联学员队后按专业教学计划和课表归属教研室生成教研室任务书。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@PostMapping("/task/add")
public Result<Void> addTask(@RequestBody TeachingTaskSaveDTO dto) {
teachingTaskManageService.add(dto);
return Result.success();
}
/**
* 编辑教学任务。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@PostMapping("/task/update")
public Result<Void> updateTask(@RequestBody TeachingTaskSaveDTO dto) {
teachingTaskManageService.update(dto);
return Result.success();
}
/**
* 删除教学任务(同时逻辑删除教研室任务书,并解除学员队关联)。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@PostMapping("/task/delete")
public Result<Void> deleteTask(@RequestParam("bh") String bh) {
teachingTaskManageService.delete(bh);
return Result.success();
}
/**
* 发布教学任务,并同步发布关联的教研室任务书。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@PostMapping("/task/publish")
public Result<Integer> publishTask(@RequestParam("bh") String bh) {
int count = teachingTaskManageService.publish(bh);
return Result.success("已发布,同步教研室任务书 " + count + " 份", count);
}
/**
* 结束发布。结束后任务书和课程任务只读。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@PostMapping("/task/endPublish")
public Result<Void> endPublishTask(@RequestParam("bh") String bh) {
teachingTaskManageService.endPublish(bh);
return Result.success();
}
/**
* 教研室任务书列表。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/office-book/list")
public Result<List<TeachingOfficeBookVO>> listTaskOfficeBooks(@RequestParam("jxrwbh") String jxrwbh) {
return Result.success(teachingTaskManageService.listOfficeBooks(jxrwbh));
}
/**
* 教研室任务书详细(该教研室在本任务下的课程任务)。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/office-book/courses")
public Result<List<TeachingOfficeBookCourseVO>> listTaskOfficeBookCourses(
@RequestParam("jxrwbh") String jxrwbh,
@RequestParam("jysdh") String jysdh) {
return Result.success(teachingTaskManageService.listOfficeBookCourses(jxrwbh, jysdh));
}
/**
* 教学任务已关联学员队。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/squad/list")
public Result<List<TeachingTaskSquadVO>> listTaskSquads(@RequestParam("jxrwbh") String jxrwbh) {
return Result.success(teachingTaskManageService.listBoundSquads(jxrwbh));
}
/**
* 某学期可选学员队(未占用或占用当前任务)。年度、学期第次为空时取当前学期。
*/
@PreAuthorize("@ss.hasPermi('teach:taskPlan:list')")
@GetMapping("/task/squad/available")
public Result<List<TeachingTaskSquadVO>> listAvailableTaskSquads(
@RequestParam(required = false) Integer nd,
@RequestParam(required = false) Integer xqdc,
@RequestParam(required = false) String jxrwbh) {
return Result.success(teachingTaskManageService.listAvailableSquads(nd, xqdc, jxrwbh));
}
}
@@ -1,11 +1,26 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.kcb.TimetableGridQuery;
import com.roomroot.jwgl.dto.kcb.TimetableQuery;
import com.roomroot.jwgl.entity.KCB;
import com.roomroot.jwgl.service.KCBService;
import com.roomroot.jwgl.service.TimetableGridService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.kcb.ClassTimetableVO;
import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableRangeVO;
import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO;
import com.roomroot.jwgl.vo.kcb.FreePeriodsVO;
import com.roomroot.jwgl.vo.kcb.TimetableGridVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
@@ -18,6 +33,9 @@ public class KCBController {
@Resource
private KCBService kcbService;
@Resource
private TimetableGridService timetableGridService;
/**
* 新增
*/
@@ -69,4 +87,105 @@ public class KCBController {
public Result<List<KCB>> list() {
return Result.success(kcbService.list());
}
/**
* 今日课表。可连续点上一天 / 下一天。
* <p>
* 首次不传参数查当天。之后把返回的 {@code rq} 回传,并传 offset:-1 上一天,1 下一天。
* </p>
*/
@GetMapping("/today/list")
public Result<DailyWeeklyTimetableRangeVO> listToday(
@RequestParam(value = "rq", required = false) String rq,
@RequestParam(value = "offset", required = false) Integer offset) {
return Result.success(kcbService.listToday(rq, offset));
}
/**
* 本周课表(周一至周日)。可连续点上一周 / 下一周。
* <p>
* 首次不传参数查本周。之后把返回的 {@code rq} 回传,并传 offset:-1 上一周,1 下一周。
* </p>
*/
@GetMapping("/week/list")
public Result<DailyWeeklyTimetableRangeVO> listWeek(
@RequestParam(value = "rq", required = false) String rq,
@RequestParam(value = "offset", required = false) Integer offset) {
return Result.success(kcbService.listWeek(rq, offset));
}
/**
* 班次课表。未传年度时按当前时间取本学期,可按队别班次筛选。
*/
@GetMapping("/class/list")
public Result<PageResult<ClassTimetableVO>> listClass(PageQuery query, TimetableQuery cond) {
return Result.success(kcbService.pageClassTimetable(query, cond));
}
/**
* 下载学期教学实施计划 Excel。
*/
@GetMapping("/class/export-plan")
public void exportSemesterPlan(TimetableQuery cond, HttpServletResponse response) {
kcbService.exportSemesterPlan(cond, response);
}
/**
* 下载学期成绩表 Excel。
*/
@GetMapping("/class/export-grades")
public void exportSemesterGrades(TimetableQuery cond, HttpServletResponse response) {
kcbService.exportSemesterGrades(cond, response);
}
/**
* 班次课程列表另存 Excel。
*/
@GetMapping("/class/export-courses")
public void exportClassCourses(TimetableQuery cond, HttpServletResponse response) {
kcbService.exportClassCourses(cond, response);
}
/**
* 周次横版课表网格(手册一第12章)。
* <p>dim=semester|team|teacher|room,id 为对应编号;可传 mbbh 套用课表模板。</p>
*/
@GetMapping("/grid")
public Result<TimetableGridVO> grid(TimetableGridQuery query) {
return Result.success(timetableGridService.grid(query));
}
/**
* 网格课表矩阵 Excel 导出(每周一个 sheet,节次 × 星期)。
*/
@GetMapping("/grid/export")
public ResponseEntity<byte[]> exportGrid(TimetableGridQuery query) {
byte[] bytes = timetableGridService.exportGrid(query);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
String name = "课表_" + query.getDim() + ".xlsx";
headers.setContentDispositionFormData("attachment",
new String(name.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
return ResponseEntity.ok().headers(headers).body(bytes);
}
/**
* 有课/无课时段查询:按日期给出 busy(有课节次)与 free(无课节次)。
* <p>dim=semester|team|teacher|room,id 为对应编号;start/end 缺省本周。</p>
*/
@GetMapping("/freeSlots")
public Result<FreePeriodsVO> freeSlots(TimetableGridQuery query) {
return Result.success(timetableGridService.freePeriods(query));
}
/**
* 课次综合查询:按 年度/学期/学员队/教员/教室/教研室/学员 组合过滤课次日历。
* <p>学员账号只看本队;教员只看本人;教研室只看本室课程。</p>
*/
@GetMapping("/lessons")
public Result<List<DailyWeeklyTimetableVO>> listLessons(TimetableQuery cond,
@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end) {
return Result.success(kcbService.listLessons(cond, start, end));
}
}
@@ -0,0 +1,63 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.KCBMBB;
import com.roomroot.jwgl.service.KCBMBService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 课表模版管理(手册一第12章;CRUD + 启停 + 下拉选项)
*/
@RestController
@RequestMapping("/kcbmb")
public class KCBMBController {
@Resource
private KCBMBService kcbmbService;
@GetMapping("/list")
public Result<PageResult<KCBMBB>> list(PageQuery query, @RequestParam(required = false) String mbmc) {
return Result.success(kcbmbService.page(query, mbmc));
}
@GetMapping("/get")
public Result<KCBMBB> get(@RequestParam("bh") String bh) {
return Result.success(kcbmbService.get(bh));
}
/** 可用模板下拉(课表生成页套用选择) */
@GetMapping("/options")
public Result<List<KCBMBB>> options() {
return Result.success(kcbmbService.options());
}
@PostMapping("/add")
public Result<Void> add(@RequestBody KCBMBB tpl) {
kcbmbService.add(tpl);
return Result.success();
}
@PostMapping("/update")
public Result<Void> update(@RequestBody KCBMBB tpl) {
kcbmbService.update(tpl);
return Result.success();
}
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
kcbmbService.delete(bh);
return Result.success();
}
/** 启用/停用模版 */
@PostMapping("/toggle")
public Result<Void> toggle(@RequestParam("bh") String bh, @RequestParam("enabled") boolean enabled) {
kcbmbService.toggle(bh, enabled);
return Result.success();
}
}
@@ -195,6 +195,17 @@ public class KSController {
return Result.success(ksService.pageHourStatistics(new PageQuery(pageNum, pageSize), cond));
}
/**
* 课时核算:按指定自然年的已排课次聚合生成课时统计表(覆盖该年数据)。
* 仅教务人员可执行。
*
* @param year 自然年(可选,默认当前年)
*/
@PostMapping("/hour-stat/recalculate")
public Result<Integer> recalcHourStatistics(@RequestParam(required = false) Integer year) {
return Result.success(ksService.recalcHourStatistics(year));
}
/**
* 导出课时统计 Excel。
*/
@@ -198,7 +198,7 @@ public class LogController {
@GetMapping("/teaching-log/download-template")
public void downloadTemplate(HttpServletResponse response) {
try {
java.io.InputStream is = getClass().getClassLoader().getResourceAsStream("template/导入教学日志模板.xls");
java.io.InputStream is = getClass().getClassLoader().getResourceAsStream("file/导入教学日志模板.xls");
if (is == null) {
response.setStatus(404);
return;
@@ -0,0 +1,109 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.service.MyBusinessService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.kcb.ClassTimetableVO;
import com.roomroot.jwgl.vo.kcb.DailyWeeklyTimetableVO;
import com.roomroot.jwgl.vo.kcb.TimetableGridVO;
import com.roomroot.jwgl.vo.mybusiness.MyCourseTaskVO;
import org.springframework.beans.factory.annotation.Autowired;
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.List;
import java.util.Map;
/**
* 「我的教学」角色视图接口(阶段 C)。
*
* <p>教员/教研室/学员维度全部由服务端按登录身份解析,
* 不接受调用方传入他人编号。</p>
*/
@RestController
@RequestMapping("/my")
public class MyBusinessController {
@Autowired
private MyBusinessService myBusinessService;
// ==================== 教员 ====================
/** 本教员课程任务 */
@GetMapping("/teacher/courses")
public Result<List<MyCourseTaskVO>> teacherCourses(@RequestParam(value = "nd", required = false) Integer nd,
@RequestParam(value = "xqdc", required = false) Integer xqdc) {
return Result.success(myBusinessService.teacherCourses(nd, xqdc));
}
/** 本教员实施计划(默认本周) */
@GetMapping("/teacher/lessons")
public Result<List<DailyWeeklyTimetableVO>> teacherLessons(@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end,
@RequestParam(value = "nd", required = false) Integer nd) {
return Result.success(myBusinessService.teacherLessons(start, end, nd));
}
/** 本教员课表网格 */
@GetMapping("/teacher/grid")
public Result<TimetableGridVO> teacherGrid(@RequestParam(value = "mbbh", required = false) String mbbh,
@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end,
@RequestParam(value = "nd", required = false) Integer nd) {
return Result.success(myBusinessService.teacherGrid(mbbh, start, end, nd));
}
// ==================== 教研室 ====================
/** 今日本室计划 */
@GetMapping("/office/today")
public Result<List<DailyWeeklyTimetableVO>> officeToday(@RequestParam(value = "rq", required = false) String rq,
@RequestParam(value = "offset", required = false) Integer offset) {
return Result.success(myBusinessService.officeToday(rq, offset));
}
/** 本室课程 */
@GetMapping("/office/courses")
public Result<List<ClassTimetableVO>> officeCourses(@RequestParam(value = "nd", required = false) Integer nd,
@RequestParam(value = "xqdc", required = false) Integer xqdc) {
return Result.success(myBusinessService.officeCourses(nd, xqdc));
}
/** 本室教员清单 */
@GetMapping("/office/teachers")
public Result<List<Map<String, Object>>> officeTeachers() {
return Result.success(myBusinessService.officeTeachers());
}
// ==================== 学员 ====================
/** 本学员队课程列表 */
@GetMapping("/student/courses")
public Result<List<ClassTimetableVO>> studentCourses(@RequestParam(value = "nd", required = false) Integer nd,
@RequestParam(value = "xqdc", required = false) Integer xqdc) {
return Result.success(myBusinessService.studentCourses(nd, xqdc));
}
/** 本学员队课次(默认本周) */
@GetMapping("/student/lessons")
public Result<List<DailyWeeklyTimetableVO>> studentLessons(@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end) {
return Result.success(myBusinessService.studentLessons(start, end));
}
/** 本学员队课表网格 */
@GetMapping("/student/grid")
public Result<TimetableGridVO> studentGrid(@RequestParam(value = "mbbh", required = false) String mbbh,
@RequestParam(value = "start", required = false) String start,
@RequestParam(value = "end", required = false) String end,
@RequestParam(value = "nd", required = false) Integer nd) {
return Result.success(myBusinessService.studentGrid(mbbh, start, end, nd));
}
/** 本学员队干部清单 */
@GetMapping("/team/cadres")
public Result<List<Map<String, Object>>> teamCadres() {
return Result.success(myBusinessService.teamCadres());
}
}
@@ -0,0 +1,211 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.common.exception.ServiceException;
import com.roomroot.jwgl.dto.scheduling.SchedulingArrangeRequest;
import com.roomroot.jwgl.dto.scheduling.SchedulingCellOpRequest;
import com.roomroot.jwgl.dto.scheduling.SchedulingCourseEditRequest;
import com.roomroot.jwgl.dto.scheduling.SchedulingMoveRequest;
import com.roomroot.jwgl.service.RunningCoursePublishService;
import com.roomroot.jwgl.service.SchedulingWindowService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.scheduling.SchedulingViewVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 实施排课窗口 Controller(阶段 5.3)。
*
* <p>组合查询 + 写操作:安排所选节次 / 删除所选节次 / 删除课程全部节次 / 彻底删除运行课程。
* 硬冲突格忽略(双占、校历/班历/场地历/教员历不可排);软提示(配当周次不符、非正课)随返回值给出。</p>
*/
@RestController
@RequestMapping("/schedulingWindow")
public class SchedulingWindowController {
@Autowired
private SchedulingWindowService schedulingWindowService;
@Autowired
private RunningCoursePublishService runningCoursePublishService;
/**
* 导出排课窗视图 Excel:每周一个 sheet(节次×星期网格,阶段 E4)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:list')")
@GetMapping("/export")
public ResponseEntity<byte[]> export(@RequestParam("xydxqbh") String xydxqbh) {
byte[] bytes = schedulingWindowService.exportView(xydxqbh);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment",
new String("排课窗口.xlsx".getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
return ResponseEntity.ok().headers(headers).body(bytes);
}
/**
* 排课窗组合视图:班次头 + 课程列表(排满标绿)+ 周次×星期×节次格子。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:list')")
@GetMapping("/view")
public Result<SchedulingViewVO> view(@RequestParam("xydxqbh") String xydxqbh) {
return Result.success(schedulingWindowService.view(xydxqbh));
}
/**
* 安排所选节次。硬冲突格忽略并列出,软提示格照常安排并给出提示。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/arrange")
public Result<Map<String, Object>> arrange(@RequestBody SchedulingArrangeRequest request) {
return Result.success(schedulingWindowService.arrange(request));
}
/**
* 拖拽移动课次:把 from 格的课次平移到 to 格(阶段 E4)。
* 目标格走与 arrange 相同的硬冲突校验;软提示照常移动并返回 warning。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/move")
public Result<Map<String, Object>> move(@RequestBody SchedulingMoveRequest request) {
return Result.success(schedulingWindowService.moveLesson(request));
}
/**
* 删除所选节次:仅删除该课程在这些格上的课次;已提交实施计划的课次拒绝。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/deleteCells")
public Result<Integer> deleteCells(@RequestBody SchedulingCellOpRequest request) {
return Result.success(schedulingWindowService.deleteCells(request));
}
/**
* 删除课程全部节次(课程仍留在列表)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/clearCourse")
public Result<Integer> clearCourse(@RequestParam("sskcbh") String sskcbh) {
return Result.success(schedulingWindowService.clearCourse(sskcbh));
}
/**
* 彻底删除运行课程:课次与列表项一起删,编制侧任务保留(教员不可用)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/deleteCourse")
public Result<Integer> deleteCourse(@RequestParam("sskcbh") String sskcbh) {
return Result.success(schedulingWindowService.deleteCourse(sskcbh));
}
/**
* 排课日志查询:按课程(可叠加操作类型)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:list')")
@GetMapping("/logs")
public Result<List<Map<String, Object>>> logs(@RequestParam("sskcbh") String sskcbh,
@RequestParam(value = "czlx", required = false) String czlx) {
return Result.success(schedulingWindowService.logs(sskcbh, czlx));
}
/**
* 编辑课程教学任务信息(手册 12.3.1):学时/周课时/课程简称/责任教员/默认场地。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/course/update")
public Result<Map<String, Object>> updateCourse(@RequestBody SchedulingCourseEditRequest request) {
return Result.success(schedulingWindowService.updateCourse(request));
}
/**
* 教学班次(合班)当前列表 + 候选班次(手册 12.3.2.2)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:list')")
@GetMapping("/course/teams")
public Result<Map<String, Object>> courseTeams(@RequestParam("sskcbh") String sskcbh) {
return Result.success(schedulingWindowService.courseTeams(sskcbh));
}
/**
* 教学保障选项:保障类别 + 保障资源(含总量与计量单位,手册 12.3.2.5)。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:list')")
@GetMapping("/support/options")
public Result<Map<String, Object>> supportOptions() {
return Result.success(schedulingWindowService.supportOptions());
}
/**
* 批量发布【运行课表】(手册 12.1):把班次学期的课程任务发布为运行课程。
*
* <p>发布前要求教学任务已发布未结束、责任教员与默认场地齐备;逐个班次独立事务,
* 单个失败不影响其它班次,失败原因逐条返回。</p>
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/publish")
public Result<List<Map<String, Object>>> publish(@RequestBody PublishRequest request) {
return Result.success(batchPublish(request, true));
}
/**
* 批量删除【运行课表】(手册 12.2):撤回该班次学期的运行课程,已排课次一并删除。
*/
@PreAuthorize("@ss.hasPermi('teach:schedulingWindow:edit')")
@PostMapping("/withdraw")
public Result<List<Map<String, Object>>> withdraw(@RequestBody PublishRequest request) {
return Result.success(batchPublish(request, false));
}
/** 批量发布/撤回公共实现 */
private List<Map<String, Object>> batchPublish(PublishRequest request, boolean publish) {
if (request == null || request.getXydxqbhs() == null || request.getXydxqbhs().isEmpty()) {
throw new ServiceException("请选择要操作的班次学期", 400);
}
List<Map<String, Object>> results = new ArrayList<>();
for (String xydxqbh : request.getXydxqbhs()) {
Map<String, Object> item = new HashMap<>();
item.put("xydxqbh", xydxqbh);
try {
int count = publish
? runningCoursePublishService.publish(xydxqbh)
: runningCoursePublishService.withdraw(xydxqbh);
item.put("success", true);
item.put("count", count);
item.put("message", publish ? ("已发布 " + count + " 条运行课程") : ("已删除 " + count + " 条运行课程"));
} catch (Exception e) {
item.put("success", false);
item.put("count", 0);
item.put("message", e.getMessage() == null ? "操作失败" : e.getMessage());
}
results.add(item);
}
return results;
}
/** 批量发布/删除请求体 */
public static class PublishRequest {
private List<String> xydxqbhs;
public List<String> getXydxqbhs() {
return xydxqbhs;
}
public void setXydxqbhs(List<String> xydxqbhs) {
this.xydxqbhs = xydxqbhs;
}
}
}
@@ -20,11 +20,13 @@ public class SemesterCalendarController {
private SemesterCalendarService semesterCalendarService;
/**
* 新增学期校历
* 预生成学期校历(幂等)。nd 为 6 位学期代号,为空时后端按日期在「学期」表反查。
*/
@PostMapping("/add")
public Result<Void> add(@RequestParam("startDate") String startDate,@RequestParam("endDate") String endDate) {
semesterCalendarService.add(startDate,endDate);
public Result<Void> add(@RequestParam("startDate") String startDate,
@RequestParam("endDate") String endDate,
@RequestParam(value = "nd", required = false) Integer nd) {
semesterCalendarService.add(startDate, endDate, nd);
return Result.success();
}
@@ -42,6 +44,11 @@ public class SemesterCalendarController {
*/
@PostMapping("/update")
public Result<Void> update(@RequestBody XQXLB xqxlb) {
if(xqxlb.getBh() == null || xqxlb.getBh().trim().isEmpty()){
return Result.error(200,"编号不得为空");
}
semesterCalendarService.update(xqxlb);
return Result.success();
}
@@ -25,6 +25,10 @@ public class SemesterController {
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XQ xq) {
if (semesterService.getById(xq.getNd()) != null) {
return Result.error(400, "该年度已存在,不能重复添加");
}
semesterService.add(xq);
return Result.success();
}
@@ -3,6 +3,9 @@ package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.XYXX;
import com.roomroot.jwgl.entity.XYDNDXQJBXXB;
import com.roomroot.jwgl.entity.XYDB;
import com.roomroot.jwgl.entity.XYDQB;
import com.roomroot.jwgl.entity.KB;
import com.roomroot.jwgl.entity.PXRW;
import com.roomroot.jwgl.entity.XYXJYDSQB;
import com.roomroot.jwgl.entity.XYXJYJJGB;
import com.roomroot.jwgl.entity.XYXJYJTJB;
@@ -44,8 +47,22 @@ public class StudentRecordsController {
@Resource
private ClassSemesterService classSemesterService;
/**
* 校验培训:按主体培训任务 0/1 查询培训任务。
*
* @param ztpxrw 主体培训任务,0-否,1-是
*/
@GetMapping("/training-tasks")
public Result<List<PXRW>> listTrainingTasks(@RequestParam("ztpxrw") Integer ztpxrw) {
return Result.success(studentRecordsService.listTrainingTasks(ztpxrw));
}
// ======================== 学员信息维护 ========================
/**
* 新增学员。
* <p>编号由后台生成 UUID;学号按当前班次编号查学员队期表的学号前缀、学号位数顺序生成,保证不重复。</p>
*/
@PostMapping("/add")
public Result<Void> add(@RequestBody XYXX xyxx) {
studentRecordsService.add(xyxx);
@@ -69,11 +86,33 @@ public class StudentRecordsController {
return Result.success(studentRecordsService.getById(bh));
}
/**
* 分页查询学员信息。
* <p>回显年级、专业、班次、考试情况、不及格门数、管理机构。
* 当前班次编号关联学员队表、专业表、学员课程成绩。</p>
*/
@GetMapping("/list")
public Result<PageResult<XYXX>> list(PageQuery query, XYXX xyxx) {
return Result.success(studentRecordsService.pageList(query, xyxx));
}
/**
* 学员队期下拉选项(编号+名称),供学员信息表单选择学员队期编号。
*/
@GetMapping("/period-options")
public Result<List<XYDQB>> periodOptions() {
return Result.success(studentRecordsService.listPeriodOptions());
}
/**
* 课程科目下拉选项(课编号+课名称),供学员成绩查询等页面使用。
* 与 /jys/kb/list 不同,本接口不带教研室权限要求。
*/
@GetMapping("/kb-options")
public Result<List<KB>> kbOptions() {
return Result.success(studentRecordsService.listKbOptions());
}
// ======================== 学员信息批量导入 ========================
/**
@@ -381,25 +420,110 @@ public class StudentRecordsController {
return Result.success(count);
}
/**
* 未毕业、且该年度学期尚未建立班次学期信息的班次。
*/
@GetMapping("/semester/creatableClasses")
public Result<List<XYDB>> creatableClasses(@RequestParam("nd") Integer nd,
@RequestParam("xqdc") Integer xqdc) {
return Result.success(classSemesterService.listCreatableClasses(nd, xqdc));
}
/**
* 按学校学期带出开学/结束日期。
*/
@GetMapping("/semester/presetDates")
public Result<Map<String, String>> presetDates(@RequestParam("nd") Integer nd,
@RequestParam("xqdc") Integer xqdc) {
return Result.success(classSemesterService.presetDates(nd, xqdc));
}
/**
* 为符合条件的全部班次创建班次学期,返回实际创建数。
*/
@PostMapping("/semester/batchCreate")
public Result<Integer> batchCreate(@RequestBody Map<String, Object> params) {
Integer nd = asInt(params.get("nd"));
Integer xqdc = asInt(params.get("xqdc"));
String kxrq = asText(params.get("kxrq"));
String jsrq = asText(params.get("jsrq"));
int count = classSemesterService.batchCreateEligible(
nd,
xqdc,
kxrq == null ? null : java.time.LocalDate.parse(kxrq),
jsrq == null ? null : java.time.LocalDate.parse(jsrq));
return Result.success(count);
}
/**
* 学期级预设合班,只改预设编班号。
*/
@PostMapping("/semester/batchWaveMerge")
public Result<Integer> batchWaveMerge(@RequestBody Map<String, Object> params) {
return Result.success(classSemesterService.batchWaveMerge(asBhList(params)));
}
/**
* 学期级预设拆班,所选班次各自独立成波。
*/
@PostMapping("/semester/batchWaveSplit")
public Result<Integer> batchWaveSplit(@RequestBody Map<String, Object> params) {
return Result.success(classSemesterService.batchWaveSplit(asBhList(params)));
}
private Integer asInt(Object value) {
if (value == null || "".equals(value)) {
return null;
}
if (value instanceof Number) {
return ((Number) value).intValue();
}
return Integer.valueOf(String.valueOf(value));
}
private String asText(Object value) {
if (value == null) {
return null;
}
String text = String.valueOf(value).trim();
return text.isEmpty() ? null : text;
}
@SuppressWarnings("unchecked")
private List<String> asBhList(Map<String, Object> params) {
Object raw = params.get("bhList");
if (!(raw instanceof List)) {
return List.of();
}
return (List<String>) raw;
}
// ======================== 课程成绩查询 ========================
/**
* 分页查询学员的课程成绩列表。
* <p>默认不传参数则全部分页展示;可按学员编号、年度筛选;年度不传时默认展示最新年度(最大年度)的数据。</p>
* <p>
* 按课程编号、学员队编号、学号、年度筛选。学号通过学员编号关联学员信息表匹配。
* </p>
*
* @param pageNum 页码(默认1)
* @param pageSize 每页条数(默认20)
* @param xybh 学员编号(可选)
* @param kcbh 课程编号(对应成绩表科目编号,可选)
* @param xydbh 学员队编号(可选)
* @param xh 学号(可选,关联学员信息表)
* @param nd 年度(可选)
*/
@GetMapping("/grades")
public Result<PageResult<XYKCCJ>> getGrades(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String kcbh,
@RequestParam(required = false) String xydbh,
@RequestParam(required = false) String xh,
@RequestParam(required = false) String xybh,
@RequestParam(required = false) Integer nd) {
return Result.success(studentRecordsService.pageCourseGrades(
new PageQuery(pageNum, pageSize), xybh, nd));
new PageQuery(pageNum, pageSize), kcbh, xydbh, xh, xybh, nd));
}
/**
@@ -124,21 +124,19 @@ public class StudentTeamTaskController {
/**
* 自动生成必修课程
* <p>
* 根据学员队编号从学员队表获取专业代号,
* 再根据专业代号和学期第次查询专业教学计划表,
* 为当前班次自动生成必修课程,插入到学员队任务表。
* 按学员队学期编号定位目标班次学期,由它反查学员队编号、学期第次与年度,
* 再按专业代号 + 学期第次查专业教学计划表补齐必修课程。
* 已存在的课程(按课编号判断)不会重复添加。
* </p>
*
* @param xydbh 学员队编号
* @param xqdc 学期第次
* @param xydxqbh 学员队学期编号
* @return 新增数量
*/
@PostMapping("/autoGenerateRequiredCourses")
public Result<Integer> autoGenerateRequiredCourses(
@RequestParam("xydbh") String xydbh,
@RequestParam("xqdc") Integer xqdc) {
int count = studentTeamTaskService.autoGenerateRequiredCourses(xydbh, xqdc);
public Result<Integer> autoGenerateRequiredCourses(@RequestParam("xydxqbh") String xydxqbh) {
// 必须按「班次学期编号」定位:同一学员队在多个年度可能有学期第次相同的班次学期,
// 只传 (学员队编号, 学期第次) 无法区分学年,会把课程任务写进别的年度。
int count = studentTeamTaskService.autoGenerateRequiredCourses(xydxqbh);
return Result.success(count);
}
@@ -159,4 +157,47 @@ public class StudentTeamTaskController {
List<String> newBhList = studentTeamTaskService.copy(bhList, newXydbh);
return Result.success(newBhList);
}
@PostMapping("/batchAutoGenerate")
public Result<Integer> batchAutoGenerate(@RequestBody List<String> xydxqbhList) {
return Result.success(studentTeamTaskService.batchAutoGenerate(xydxqbhList));
}
@GetMapping("/planCourses")
public Result<List<com.roomroot.jwgl.vo.PlanCourseVO>> planCourses(
@RequestParam("xydxqbh") String xydxqbh,
@RequestParam(value = "otherOnly", defaultValue = "true") boolean otherOnly) {
return Result.success(studentTeamTaskService.listPlanCourses(xydxqbh, otherOnly));
}
@PostMapping("/addFromLibrary")
public Result<Void> addFromLibrary(@RequestParam("xydxqbh") String xydxqbh,
@RequestParam("kbh") String kbh) {
studentTeamTaskService.addFromLibrary(xydxqbh, kbh);
return Result.success();
}
@PostMapping("/addFromPlan")
public Result<Void> addFromPlan(@RequestParam("xydxqbh") String xydxqbh,
@RequestParam("planBh") String planBh) {
studentTeamTaskService.addFromPlan(xydxqbh, planBh);
return Result.success();
}
@PostMapping("/syncFromPlan")
public Result<Integer> syncFromPlan(@RequestBody List<String> bhList) {
return Result.success(studentTeamTaskService.syncFromPlan(bhList));
}
@PostMapping("/batchDelete")
public Result<Integer> batchDelete(@RequestBody List<String> bhList) {
return Result.success(studentTeamTaskService.batchDeleteGuarded(bhList));
}
@PostMapping("/paste")
public Result<Integer> paste(@RequestBody Map<String, Object> params) {
List<String> bhList = (List<String>) params.get("bhList");
String targetXydxqbh = (String) params.get("targetXydxqbh");
return Result.success(studentTeamTaskService.pasteToSemester(bhList, targetXydxqbh));
}
}
@@ -0,0 +1,50 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.DBVersion;
import com.roomroot.jwgl.entity.JCSJB;
import com.roomroot.jwgl.service.ClassPeriodService;
import com.roomroot.jwgl.service.SystemSettingsService;
import com.roomroot.jwgl.unit.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 教务系统参数(DBVersion 单行,阶段 E1)。
*
* <p>当前开放字段:显示78节(xs78j)、显示晚上(xsws)、显示夜间(xsyj)、
* 教学要点名称(jxydmc)。更新只写非空字段。</p>
*/
@RestController
@RequestMapping("/systemSettings")
public class SystemSettingsController {
@Autowired
private SystemSettingsService systemSettingsService;
@Autowired
private ClassPeriodService classPeriodService;
/** 读取系统参数 */
@GetMapping("/get")
public Result<DBVersion> get() {
return Result.success(systemSettingsService.get());
}
/** 节次段字典:节次时间表的双节次行,供日历编辑器渲染节次列 */
@GetMapping("/periodSlots")
public Result<List<JCSJB>> periodSlots() {
return Result.success(classPeriodService.slotRows());
}
/** 更新系统参数(只写非空字段) */
@PostMapping("/update")
public Result<DBVersion> update(@RequestBody DBVersion settings) {
return Result.success(systemSettingsService.update(settings));
}
}
@@ -0,0 +1,133 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.dto.taskbook.TaskBookBatchFillRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookBatchRoomRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookBatchTeacherRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookBhListRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookFillRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookRoomRequest;
import com.roomroot.jwgl.dto.taskbook.TaskBookTeacherRequest;
import com.roomroot.jwgl.service.TaskBookFillService;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.taskbook.TaskBookRowVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 教研室任务书填报 Controller(阶段 4)。
*
* <p>把已生成的课程任务确认成「可以排课的运行对象」:合班、责任教员、默认场地。</p>
*/
@RestController
@RequestMapping("/taskBookFill")
public class TaskBookFillController {
@Autowired
private TaskBookFillService taskBookFillService;
/**
* 填报列表:某教学任务下全部课程任务行(排序 课程→责任教员→课次,含合班分组号)。
*/
@GetMapping("/list")
public Result<List<TaskBookRowVO>> list(@RequestParam("jxrwbh") String jxrwbh,
@RequestParam(value = "jybh", required = false) String jybh) {
return Result.success(taskBookFillService.list(jxrwbh, jybh));
}
/**
* 手动合班:所选行写入同一编组;科目/学时/课类型/成绩分制不同则拒绝并说明。
*/
@PostMapping("/merge")
public Result<Integer> merge(@RequestBody TaskBookBhListRequest request) {
return Result.success(taskBookFillService.merge(request));
}
/**
* 按预设合班:按课程科目分组,组内按预设编班号写入同一编组。
*/
@PostMapping("/mergeByPreset")
public Result<List<Map<String, Object>>> mergeByPreset(@RequestBody TaskBookBhListRequest request) {
return Result.success(taskBookFillService.mergeByPreset(request));
}
/**
* 拆班:所选行编组置 0。
*/
@PostMapping("/split")
public Result<Integer> split(@RequestBody TaskBookBhListRequest request) {
return Result.success(taskBookFillService.split(request));
}
/**
* 责任教员指定:mode = unit(责任单位教员)/ academy(全院教员)/ plan(应用教研室计划教员)。
* 同合班组其它行同步。
*/
@PostMapping("/setTeacher")
public Result<Integer> setTeacher(@RequestBody TaskBookTeacherRequest request) {
return Result.success(taskBookFillService.setTeacher(request));
}
/**
* 场地指定:useSpecial=true 使用班次专用教室;否则按 jsbh 指定其它教室。同合班组同步。
*/
@PostMapping("/setRoom")
public Result<Integer> setRoom(@RequestBody TaskBookRoomRequest request) {
return Result.success(taskBookFillService.setRoom(request));
}
/**
* 填报字段:计划教员 / 场地(同合班同步)/ 排课建议 / 课次序号。
*/
@PostMapping("/fill")
public Result<Integer> fill(@RequestBody TaskBookFillRequest request) {
return Result.success(taskBookFillService.fill(request));
}
/**
* 批量指定责任教员:对每行执行与 setTeacher 相同的校验与合班组同步。
*/
@PostMapping("/batchSetTeacher")
public Result<Integer> batchSetTeacher(@RequestBody TaskBookBatchTeacherRequest request) {
return Result.success(taskBookFillService.batchSetTeacher(request));
}
/**
* 批量指定场地:对每行执行与 setRoom 相同的校验与合班组同步。
*/
@PostMapping("/batchSetRoom")
public Result<Integer> batchSetRoom(@RequestBody TaskBookBatchRoomRequest request) {
return Result.success(taskBookFillService.batchSetRoom(request));
}
/**
* 批量填报:对所选行统一应用填报字段(仅写非空),单事务。
*/
@PostMapping("/batchFill")
public Result<Integer> batchFill(@RequestBody TaskBookBatchFillRequest request) {
return Result.success(taskBookFillService.batchFill(request));
}
/**
* 行级删除:所选课程任务行逻辑删除;已发布到运行课表的班次须先撤回。
*/
@PostMapping("/deleteRows")
public Result<Integer> deleteRows(@RequestBody TaskBookBhListRequest request) {
return Result.success(taskBookFillService.deleteRows(request));
}
/**
* 教研室跨任务汇总:该教研室全部任务书(附教学任务名称/年度/状态)。
*/
@GetMapping("/officeSummary")
public Result<List<Map<String, Object>>> officeSummary(@RequestParam("jysdh") String jysdh) {
return Result.success(taskBookFillService.officeSummary(jysdh));
}
}
@@ -0,0 +1,85 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JYL;
import com.roomroot.jwgl.service.JYLService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 教员历控制器(阶段 5.1)。排课冲突同时读取场地历与教员历。
*/
@RestController
@RequestMapping("/teacherCalendar/jyl")
public class TeacherCalendarController {
@Resource
private JYLService jylService;
/** 新增教员历 */
@PostMapping("/add")
public Result<Void> add(@RequestBody JYL jyl) {
jylService.add(jyl);
return Result.success();
}
/** 删除教员历(软删) */
@PostMapping("/delete")
public Result<Void> delete(@RequestParam("bh") String bh) {
jylService.delete(bh);
return Result.success();
}
/** 更新教员历 */
@PostMapping("/update")
public Result<Void> update(@RequestBody JYL jyl) {
jylService.update(jyl);
return Result.success();
}
/** 根据编号查询 */
@GetMapping("/get")
public Result<JYL> getById(@RequestParam("bh") String bh) {
return Result.success(jylService.getById(bh));
}
/** 分页查询 */
@GetMapping("/list")
public Result<PageResult<JYL>> list(PageQuery query, JYL jyl) {
return Result.success(jylService.pageList(query, jyl));
}
/** 查询全部 */
@GetMapping("/all")
public Result<List<JYL>> all(JYL jyl) {
return Result.success(jylService.list(jyl));
}
/** 按教员编号查询 */
@GetMapping("/listByJybh")
public Result<List<JYL>> listByJybh(@RequestParam("jybh") String jybh) {
return Result.success(jylService.listByJybh(jybh));
}
/** 按日期查询 */
@GetMapping("/listByRq")
public Result<List<JYL>> listByRq(@RequestParam("rq") String rq) {
return Result.success(jylService.listByRq(rq));
}
/** 批量保存教员历(教员历编辑器整片提交,按 教员+日期+节次 幂等覆盖) */
@PostMapping("/batchSave")
public Result<Integer> batchSave(@RequestBody List<JYL> list) {
return Result.success(jylService.batchSave(list));
}
/** 批量删除教员历(本表无 del_flag,物理删除) */
@PostMapping("/batchDelete")
public Result<Integer> batchDelete(@RequestBody List<String> bhs) {
return Result.success(jylService.batchDelete(bhs));
}
}
@@ -0,0 +1,93 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.dto.allocation.AllocationGroupRequest;
import com.roomroot.jwgl.dto.allocation.AllocationSaveItem;
import com.roomroot.jwgl.service.TeachingAllocationService;
import com.roomroot.jwgl.vo.allocation.AllocationViewVO;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* 教学配当 Controller(阶段 3)。
*
* <p>配当只做排课粗约束(周学时分布、同开同结),不直接写实施课程表。</p>
*/
@RestController
@RequestMapping("/teachingAllocation")
public class TeachingAllocationController {
@Autowired
private TeachingAllocationService teachingAllocationService;
/**
* 配当编辑器视图:周轴(每周可排正课)+ 任务行(含铺学时建议)。
*/
@GetMapping("/view")
public Result<AllocationViewVO> view(@RequestParam("xydxqbh") String xydxqbh) {
return Result.success(teachingAllocationService.view(xydxqbh));
}
/**
* 保存配当:单条(列表 1 个元素)或多选批量;元素 saveGroup=true 时整编组同开同结。
*/
@PostMapping("/save")
public Result<Integer> save(@RequestBody List<AllocationSaveItem> items) {
return Result.success(teachingAllocationService.save(items));
}
/**
* 优选序数上移/下移(direction: up/down),返回归一化后的任务编号顺序。
*/
@PostMapping("/move")
public Result<List<String>> move(@RequestParam("xydxqbh") String xydxqbh,
@RequestParam("bh") String bh,
@RequestParam("direction") String direction) {
return Result.success(teachingAllocationService.move(xydxqbh, bh, direction));
}
/**
* 编组管理面板:同科目全部开课班次。
*/
@GetMapping("/groups")
public Result<List<Map<String, Object>>> groups(@RequestParam("kbh") String kbh) {
return Result.success(teachingAllocationService.groups(kbh));
}
/**
* 编组管理:把所选任务统一改编组号。
*/
@PostMapping("/setGroup")
public Result<Integer> setGroup(@RequestBody AllocationGroupRequest request) {
return Result.success(teachingAllocationService.setGroup(request));
}
/**
* 自动排布:按铺学时建议把计算起始周回填到 pdqsz。
* onlyMissing=true(辅助排布)只补未设起始周的任务;body 可选传任务编号列表限定范围。
*/
@PostMapping("/autoArrange")
public Result<Integer> autoArrange(@RequestParam("xydxqbh") String xydxqbh,
@RequestParam(value = "onlyMissing", defaultValue = "false") boolean onlyMissing,
@RequestBody(required = false) List<String> bhList) {
return Result.success(teachingAllocationService.autoArrange(xydxqbh, bhList, onlyMissing));
}
/**
* 导出配当 Excel(支持批量:xydxqbh 逗号分隔)。
*/
@GetMapping("/export")
public void export(@RequestParam("xydxqbh") String xydxqbh, HttpServletResponse response) throws Exception {
teachingAllocationService.exportExcel(Arrays.asList(xydxqbh.split(",")), response);
}
}
@@ -92,11 +92,8 @@ public class TeachingPlanController {
* 下载教学实施计划导入模板
*/
@GetMapping("/template")
public ResponseEntity<org.springframework.core.io.Resource> downloadTemplate() throws IOException {
ClassPathResource resource = new ClassPathResource("template/教学实施计划导入模板.xlsx");
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
public ResponseEntity<byte[]> downloadTemplate() throws Exception {
byte[] bytes = teachingPlanService.buildImportTemplate();
String fileName = URLEncoder.encode("教学实施计划导入模板.xlsx", "UTF-8");
HttpHeaders headers = new HttpHeaders();
@@ -105,6 +102,6 @@ public class TeachingPlanController {
return ResponseEntity.ok()
.headers(headers)
.body(resource);
.body(bytes);
}
}
@@ -81,15 +81,33 @@ public class TeachingTaskController {
}
/**
* 发布教学任务及教研室任务书
* 根据教学任务编号修改状态为"发布",并批量更新所有关联的教研室任务书状态为"发布"
* 批量发布教学任务及教研室任务书
* 逐个任务置"发布"并同步教研室任务书;任一校验失败(已结束/任务书未生成)整批回滚。
*
* @param bh 教学任务编号
* @return 更新数量
* @param bhList 教学任务编号列表
* @return 更新的教研室任务书行数合计
*/
@PostMapping("/batchPublish")
public Result<Integer> batchPublish(@RequestParam("bh") String bh) {
int count = teachingTaskService.batchPublish(bh);
public Result<Integer> batchPublish(@RequestBody List<String> bhList) {
int count = teachingTaskService.batchPublish(bhList);
return Result.success(count);
}
/**
* 结束发布。结束后教研室不能再改任务书和课程任务。
*/
@PostMapping("/endPublish")
public Result<Void> endPublish(@RequestParam("bh") String bh) {
teachingTaskService.endPublish(bh);
return Result.success();
}
/**
* 导出教学任务书 Excel(该教学任务下全部教研室任务书课程明细)。
*/
@GetMapping("/exportTaskBook")
public void exportTaskBook(jakarta.servlet.http.HttpServletResponse response,
@RequestParam("bh") String bh) throws Exception {
teachingTaskService.exportTaskBook(response, bh);
}
}
@@ -1,13 +1,17 @@
package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.JXGLJG;
import com.roomroot.jwgl.entity.ZYB;
import com.roomroot.jwgl.service.TrainingProgramService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.util.List;
/**
* 培养方案管理控制器
@@ -85,6 +89,7 @@ public class TrainingProgramController {
* <li>zydm — 专业代码(模糊匹配)</li>
* <li>pxlx — 培训类型(精确匹配,用于版本筛选)</li>
* <li>pxcc — 培训层次(精确匹配)</li>
* <li>ty — 停用(精确匹配)</li>
* </ul>
* </p>
*
@@ -103,7 +108,8 @@ public class TrainingProgramController {
@RequestParam(required = false) String zymc,
@RequestParam(required = false) String zydm,
@RequestParam(required = false) String pxlx,
@RequestParam(required = false) String pxcc) {
@RequestParam(required = false) String pxcc,
@RequestParam(required = false) Boolean ty) {
PageQuery query = new PageQuery();
query.setPageNum(pageNum);
query.setPageSize(pageSize);
@@ -112,7 +118,43 @@ public class TrainingProgramController {
cond.setZydm(zydm);
cond.setPxlx(pxlx);
cond.setPxcc(pxcc);
cond.setTy(ty);
PageResult<ZYB> pageResult = trainingProgramService.pageList(query, cond);
return Result.success(pageResult);
}
/**
* 培养方案目录导入模板(仅表头,含学年制、学期数等必填列)。
*/
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) throws Exception {
trainingProgramService.exportZYBTemplate(response);
}
/**
* 培养方案(专业)数据文件导入(.xls/.xlsx)。
* <p>按列名匹配:专业代号, 专业名称, 专业代码, 专业版本, 培训类型, 培训层次, 学年制,
* 学期数, 专业方向, 专业备注, 学员类别, 简称, 培训类型2。专业代号不填自动生成;学年制、学期数必填。</p>
*/
@PostMapping("/import")
public Result<Integer> importData(@RequestParam("file") MultipartFile file) throws Exception {
int count = trainingProgramService.importZYBFromExcel(file);
return Result.success("导入成功,共" + count + "条", count);
}
/**
* 导出培养方案(专业)到 Excel(.xlsx)。
*/
@GetMapping("/export")
public void exportData(HttpServletResponse response) throws Exception {
trainingProgramService.exportZYBExcel(response);
}
/**
* 教学管理机构下拉选项(来自教学管理机构表,提交编号、展示名称)。
*/
@GetMapping("/teaching-organizations")
public Result<List<JXGLJG>> listTeachingOrganizations() {
return Result.success(trainingProgramService.listTeachingOrganizations());
}
}
@@ -2,8 +2,12 @@ package com.roomroot.web.controller.jwgl;
import com.roomroot.jwgl.entity.ZYJXJHB;
import com.roomroot.jwgl.service.ZYJXJHBService;
import com.roomroot.jwgl.unit.PageQuery;
import com.roomroot.jwgl.unit.PageResult;
import com.roomroot.jwgl.unit.Result;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import java.util.List;
@@ -77,8 +81,46 @@ public class ZYJXJHBController {
* @param ty 停用标识(0-正常,1-停用)
*/
@GetMapping("/listByZydhAndTy")
public Result<List<ZYJXJHB>> listByZydhAndTy(@RequestParam("zydh") String zydh,
@RequestParam("ty") Integer ty) {
return Result.success(zyjxjhbService.listByZydhAndTy(zydh, ty));
public Result<PageResult<ZYJXJHB>> listByZydhAndTy(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "20") Integer pageSize,
@RequestParam(required = false) String zydh,
@RequestParam(required = false) Integer ty) {
return Result.success(zyjxjhbService.pageByZydhAndTy(
new PageQuery(pageNum, pageSize), zydh, ty));
}
/**
* 专业教学计划表数据文件导入(.xls/.xlsx)。
* <p>按表头名匹配列(列位置不限),推荐使用 /template 下载的模板填写。
* 必填列:专业代号、课编号、学期第次、课类型、学时;
* "专业代号+课编号+学期第次"已存在的行跳过,校验失败行返回行级明细。</p>
*/
@PostMapping("/import")
public Result<com.roomroot.jwgl.vo.syllabus.SyllabusImportResultVO> importData(
@RequestParam("file") MultipartFile file) throws Exception {
com.roomroot.jwgl.vo.syllabus.SyllabusImportResultVO result = zyjxjhbService.importExcel(file);
return Result.success(result.getMessage(), result);
}
/**
* 下载教学大纲导入模板(数据 sheet + 填写说明 sheet)。
*/
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) throws Exception {
zyjxjhbService.downloadTemplate(response);
}
/**
* 导出专业教学计划到 Excel(.xlsx)。
* <p>专业代号、停用标识可选,与列表筛选条件一致。</p>
*/
@GetMapping("/export")
public void exportData(
HttpServletResponse response,
@RequestParam(required = false) String zydh,
@RequestParam(required = false) Integer ty,
@RequestParam(required = false) List<String> bhList) throws Exception {
zyjxjhbService.exportZYJXJHBExcel(response, zydh, ty, bhList);
}
}
@@ -0,0 +1,90 @@
package com.roomroot.web.controller.jwtest;
import com.roomroot.jwgl.mapper.TestPkMapper;
import com.roomroot.jwgl.unit.Result;
import com.roomroot.jwgl.vo.jwtest.PkConflictCheckVO;
import com.roomroot.jwgl.vo.jwtest.PkConflictVO;
import com.roomroot.jwgl.vo.jwtest.PkLessonVO;
import jakarta.annotation.Resource;
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.List;
/**
* 排课测试接口。
*/
@RestController
@RequestMapping("/jwtest/pk")
public class TestPkController {
@Resource
private TestPkMapper testPkMapper;
/**
* 全查排课记录,无筛选条件。
* <p>
* 回显:课堂名称、课程名称、教师名称、班级名称、教室名称、
* 上课日期、开始时间、结束时间、学年学期、周次、应到人数。
* </p>
*/
@GetMapping("/all")
public Result<List<PkLessonVO>> all() {
return Result.success(testPkMapper.selectAll());
}
/**
* 教学班时间冲突:同一个班在同一日期同一节次被安排多门课程。
*/
@GetMapping("/conflict/class")
public Result<PkConflictCheckVO> classTimeConflict(@RequestParam(required = false) Integer nd) {
return Result.success(wrap(
"教学班时间冲突",
"同一班次在同一天同一节次被安排了多门课程",
testPkMapper.selectClassTimeConflict(nd)));
}
/**
* 必修课与选修课时间冲突:同一班次同一时间既有必修又有选修。
*/
@GetMapping("/conflict/elective-required")
public Result<PkConflictCheckVO> electiveRequiredConflict(@RequestParam(required = false) Integer nd) {
return Result.success(wrap(
"必修选修时间冲突",
"同一班次在同一天同一节次同时安排了必修课和选修课",
testPkMapper.selectElectiveRequiredConflict(nd)));
}
/**
* 教员时间冲突:同一教员在同一时间段被安排多门课程。
*/
@GetMapping("/conflict/teacher")
public Result<PkConflictCheckVO> teacherTimeConflict(@RequestParam(required = false) Integer nd) {
return Result.success(wrap(
"教员时间冲突",
"同一教员在同一天同一节次被安排了多门课程",
testPkMapper.selectTeacherTimeConflict(nd)));
}
/**
* 教室时间冲突:同一教室在同一时间段被多门课程占用。
*/
@GetMapping("/conflict/classroom")
public Result<PkConflictCheckVO> classroomTimeConflict(@RequestParam(required = false) Integer nd) {
return Result.success(wrap(
"教室时间冲突",
"同一教室在同一天同一节次被多门课程占用",
testPkMapper.selectClassroomTimeConflict(nd)));
}
private PkConflictCheckVO wrap(String ctlx, String jcsm, List<PkConflictVO> mx) {
PkConflictCheckVO vo = new PkConflictCheckVO();
vo.setCtlx(ctlx);
vo.setJcsm(jcsm);
vo.setMx(mx);
vo.setTs(mx == null ? 0 : mx.size());
return vo;
}
}
@@ -3,10 +3,10 @@ spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
# 达梦连接串:ip:端口,schema指定默认模式
url: jdbc:dm://10.1.1.17:5236?schema=JIAOWU&useUnicode=true&characterEncoding=utf-8
username: JIAOWU
url: jdbc:opengauss://10.1.1.17:5436/jwgl?currentSchema=jwgl&batchMode=off&stringtype=unspecified
username: jwgl
password: Jiaowu123
driver-class-name: dm.jdbc.driver.DmDriver
driver-class-name: org.opengauss.Driver
# Druid 基础参数
druid:
@@ -29,7 +29,7 @@ spring:
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
validationQuery: SELECT 1
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
@@ -107,6 +107,7 @@ mybatis-plus:
typeAliasesPackage: com.roomroot.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:com/roomroot/**/mapper/*.xml
typeHandlersPackage: com.roomroot.jwgl.handler
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
@@ -13,7 +13,7 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 指定 MyBatis 所用日志的具体实现 -->
<setting name="logImpl" value="SLF4J" />
<!-- 使用驼峰命名法转换字段 -->
<!-- 使用驼峰命名法转换字段 -->
<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
</settings>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
</component>
</module>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
</component>
</module>
@@ -0,0 +1,40 @@
package com.roomroot.framework.config;
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tools.jackson.databind.ext.javatime.deser.LocalDateTimeDeserializer;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.module.SimpleModule;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
/**
* 兼容前端常用的 {@code yyyy-MM-dd HH:mm:ss} 与 ISO {@code yyyy-MM-ddTHH:mm:ss}。
*/
@Configuration
public class JacksonConfig {
@Bean
public JsonMapperBuilderCustomizer flexibleLocalDateTimeCustomizer() {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.optionalStart()
.optionalStart().appendLiteral('T').optionalEnd()
.optionalStart().appendLiteral(' ').optionalEnd()
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.optionalEnd()
.parseDefaulting(java.time.temporal.ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(java.time.temporal.ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(java.time.temporal.ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter();
return (JsonMapper.Builder builder) -> {
SimpleModule module = new SimpleModule("FlexibleLocalDateTime");
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter));
builder.addModule(module);
};
}
}
@@ -100,7 +100,7 @@ public class SecurityConfig
.authorizeHttpRequests((requests) -> {
permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll());
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
requests.requestMatchers("/login", "/register", "/captchaImage","/jys/teacher/list").permitAll()
requests.requestMatchers("/login", "/register", "/captchaImage", "/jwtest/pk/all").permitAll()
// 静态资源,可匿名访问
.requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll()
.requestMatchers("/swagger-ui.html", "/v3/api-docs/**", "/swagger-ui/**", "/druid/**").permitAll()
@@ -73,6 +73,10 @@ public class TokenService
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
if (user == null)
{
log.warn("令牌签名有效,但登录缓存已失效,请重新登录");
}
return user;
}
catch (Exception e)
@@ -218,14 +222,42 @@ public class TokenService
*/
private String getToken(HttpServletRequest request)
{
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
String token = firstHeader(request, header, "Authorization", "token");
if (StringUtils.isNotEmpty(token))
{
token = token.replace(Constants.TOKEN_PREFIX, "");
token = token.trim();
if (StringUtils.startsWithIgnoreCase(token, Constants.TOKEN_PREFIX))
{
token = token.substring(Constants.TOKEN_PREFIX.length()).trim();
}
}
return token;
}
/**
* 按顺序读取请求头,兼容 Authorization / token。
*/
private String firstHeader(HttpServletRequest request, String... names)
{
if (names == null)
{
return null;
}
for (String name : names)
{
if (StringUtils.isEmpty(name))
{
continue;
}
String value = request.getHeader(name);
if (StringUtils.isNotEmpty(value))
{
return value;
}
}
return null;
}
private String getTokenKey(String uuid)
{
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="AdditionalModuleElements">
<content url="file://$MODULE_DIR$" dumb="true">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
</component>
</module>
@@ -1,88 +1,25 @@
package com.roomroot.jwgl.config;
import com.roomroot.jwgl.interceptor.AccountManagementAuthorizationInterceptor;
import com.roomroot.jwgl.interceptor.JwglApiAccessInterceptor;
import com.roomroot.jwgl.interceptor.OperationLogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 在线账户状态和账户管理权限 Web MVC 配置。
*
* <p>该配置对已有在线会话执行账户状态校验,同时保持普通匿名请求的原有访问规则;
* 账户管理路径继续执行超级管理员权限校验,并在校验通过后采集操作日志上下文。</p>
* 操作日志采集 Web MVC 配置。
* <p>页面菜单权限由前端控制;后台只校验登录态,查询时再按角色和用户ID过滤数据。</p>
*/
@Configuration
public class AccountManagementWebMvcConfig implements WebMvcConfigurer {
/**
* 账户管理身份和权限拦截器。
*/
private final AccountManagementAuthorizationInterceptor
authorizationInterceptor;
/**
* 操作日志统一请求采集拦截器。
*/
private final OperationLogInterceptor operationLogInterceptor;
private final JwglApiAccessInterceptor jwglApiAccessInterceptor;
/**
* 构造账户管理和操作日志统一 Web MVC 配置。
*
* @param authorizationInterceptor 账户管理身份和权限拦截器
* @param operationLogInterceptor 操作日志统一请求采集拦截器
* @param jwglApiAccessInterceptor 教务角色接口访问拦截器
*/
public AccountManagementWebMvcConfig(
AccountManagementAuthorizationInterceptor
authorizationInterceptor,
OperationLogInterceptor operationLogInterceptor,
JwglApiAccessInterceptor jwglApiAccessInterceptor) {
// 第一步:保存账户管理专用拦截器,供 MVC 注册阶段使用。
this.authorizationInterceptor = authorizationInterceptor;
// 第二步:保存操作日志采集拦截器,供 MVC 注册阶段使用。
public AccountManagementWebMvcConfig(OperationLogInterceptor operationLogInterceptor) {
this.operationLogInterceptor = operationLogInterceptor;
this.jwglApiAccessInterceptor = jwglApiAccessInterceptor;
}
/**
* 注册账户状态校验、账户管理权限和操作日志采集规则。
*
* @param registry Spring MVC 拦截器注册器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*
* 第一步:注册账户管理鉴权拦截器。
* 第二步:覆盖全部 Controller 请求,使停用或已合并账户不能绕过
* 账户管理路径继续访问其他业务接口。
* 第三步:拦截器内部会放行没有 Servlet 会话的普通匿名请求,
* 因此不会改变项目现有公开接口的访问方式。
*/
// registry.addInterceptor(authorizationInterceptor)
// .addPathPatterns("/**");
/*
* 第四步:在账户状态和账户管理权限校验通过后采集日志上下文。
* 第五步:覆盖全部 Controller 请求,由采集拦截器自行跳过
* 非 Controller 处理器和没有有效登录记录的请求。
*/
registry.addInterceptor(jwglApiAccessInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(
"/login",
"/register",
"/captchaImage",
"/jys/teacher/list",
"/swagger-ui/**",
"/v3/api-docs/**",
"/druid/**");
registry.addInterceptor(operationLogInterceptor)
.addPathPatterns("/**");
}
@@ -0,0 +1,18 @@
package com.roomroot.jwgl.dto.allocation;
import lombok.Data;
import java.util.List;
/**
* 教学配当 - 编组管理改编组号请求。
*/
@Data
public class AllocationGroupRequest {
/** 任务编号列表(必填) */
private List<String> bhList;
/** 目标配档编组号(必填,&gt;=0) */
private Integer pdbz;
}
@@ -0,0 +1,34 @@
package com.roomroot.jwgl.dto.allocation;
import lombok.Data;
/**
* 教学配当 - 单条保存项。
*
* <p>字段为 null 表示不修改。{@code saveGroup=true} 时按「同科目 + 同配档编组 + 同学期代号」
* 把同组各班次任务一起改(同开同结),限定在同一学期代号内防止跨学期串改。</p>
*/
@Data
public class AllocationSaveItem {
/** 任务编号(必填) */
private String bh;
/** 配档序号(优选序数) */
private Integer pdxh;
/** 配档起始周 */
private Integer pdqsz;
/** 配档按周:0=连排 1=按周 */
private Integer pdaz;
/** 配档占正课时间 */
private Integer pdzzksj;
/** 配档编组 */
private Integer pdbz;
/** 是否保存整个编组 */
private Boolean saveGroup;
}
@@ -0,0 +1,16 @@
package com.roomroot.jwgl.dto.calendar;
import lombok.Data;
import java.util.List;
/**
* 把班历事件应用到其它班次。eventBhList 为空时复制整个班历。
*/
@Data
public class ClassCalendarApplyDTO {
private String sourceXydxqbh;
private List<String> targetBhList;
private List<String> eventBhList;
}
@@ -0,0 +1,22 @@
package com.roomroot.jwgl.dto.calendar;
import lombok.Data;
import java.util.List;
/**
* 班历批量保存入参。一次拖选产生的所有时间格在单事务内 upsert。
*/
@Data
public class ClassCalendarBatchSaveDTO {
/**
* 学员队学期编号(班次学期)
*/
private String xydxqbh;
/**
* 时间格列表。cell.action = "clear" 表示恢复默认(清名称、可排课)。
*/
private List<ClassCalendarEventDTO> cells;
}
@@ -0,0 +1,29 @@
package com.roomroot.jwgl.dto.calendar;
import lombok.Data;
/**
* 班历时间格。日期用 yyyy-MM-dd,便于复用校历编辑器。
*/
@Data
public class ClassCalendarEventDTO {
private String bh;
private Integer nd;
private String xydbh;
private String xydxqbh;
private String jqsj;
private String jqmc;
private Boolean jc;
private String bz;
private Boolean kpk;
private Boolean bzxs;
private Boolean zdpk;
private Boolean zk;
private String courseClass;
/**
* 批量保存动作:"clear" 表示恢复默认(清名称、可排课);空或其它值按事件内容写入。
*/
private String action;
}
@@ -17,17 +17,17 @@ import java.util.List;
public class ScheduleAdjustApplyDTO {
/**
* 实施_课程表编号,必填,标识需要调整的课次。
* 实施_课程表编号,必填,对应实施_调课申请.实施_课程表编号。
*/
@NotBlank(message = "课次编号不能为空")
@Size(max = 50, message = "课次编号不能超过50个字符")
private String sskcbbh;
/**
* 调课事由,必填,描述本次调课的原因和依据。
* 调课事由,对应 实施_调课申请.事由 VARCHAR(200)。
*/
@NotBlank(message = "调课事由不能为空")
@Size(max = 500, message = "调课事由不能超过500个字符")
@Size(max = 200, message = "调课事由不能超过200个字符")
private String sy;
/**
@@ -49,16 +49,39 @@ public class ScheduleAdjustApplyDTO {
private Integer nd;
/**
* 申请教员编号,必填,标识提交申请的教员。
* 申请教员编号,教员提交时由服务端按登录人写入,前端可不传。
*/
@NotBlank(message = "申请教员编号不能为空")
@Size(max = 50, message = "申请教员编号不能超过50个字符")
private String sqjybh;
/**
* 调课后教学内容,调整后的本节课教学主题或知识点。
* 学员队任务表编号,由服务端根据实施课次反查,前端可不传。
*/
@Size(max = 2000, message = "教学内容不能超过2000个字符")
@Size(max = 50, message = "学员队任务编号不能超过50个字符")
private String xydrwbh;
/**
* 课表.课编号。
*/
@Size(max = 50, message = "课编号不能超过50个字符")
private String kbh;
/**
* 课程表编号。
*/
@Size(max = 50, message = "课程表编号不能超过50个字符")
private String kcbbh;
/**
* 拟调整教室编号。
*/
@Size(max = 50, message = "教室编号不能超过50个字符")
private String xjsbh;
/**
* 调课后教学内容,对应 实施_调课申请.教学内容 VARCHAR(500)。
*/
@Size(max = 500, message = "教学内容不能超过500个字符")
private String jxnr;
/**
@@ -68,9 +91,9 @@ public class ScheduleAdjustApplyDTO {
private String jxyd;
/**
* 调课后教学方法,调整后的教学方法。
* 调课后教学方法,对应 实施_调课申请.教学方法 VARCHAR(50)。
*/
@Size(max = 200, message = "教学方法不能超过200个字符")
@Size(max = 50, message = "教学方法不能超过50个字符")
private String jxff;
/**
@@ -86,9 +109,9 @@ public class ScheduleAdjustApplyDTO {
private String ycxx;
/**
* 备注,补充说明信息。
* 备注,对应 实施_调课申请.备注 VARCHAR(50)。
*/
@Size(max = 500, message = "备注不能超过500个字符")
@Size(max = 50, message = "备注不能超过50个字符")
private String bz;
/**
@@ -2,54 +2,42 @@ package com.roomroot.jwgl.dto.courserunning;
import lombok.Data;
import jakarta.validation.constraints.*;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
/**
* 调课申请审批参数。
* <p>
* 用于教研室或机关审批调课申请,包含审批结果、审批意见和审批人编号。
* </p>
* 教研室审批调课申请参数。
*/
@Data
public class ScheduleAdjustAuditDTO {
/**
* 调课申请编号,必填,标识需要审批的调课申请。
* 调课申请编号。
*/
@NotBlank(message = "调课申请编号不能为空")
@Size(max = 50, message = "调课申请编号不能超过50个字符")
private String ssdksqbh;
/**
* 审批角色,必填:jys(教研室审批)、jg(机关审批)。
*/
@NotBlank(message = "审批角色不能为空")
@Size(max = 20, message = "审批角色不能超过20个字符")
private String auditRole;
/**
* 审批结果,必填:1-同意,2-发回修改,3-拒绝。
* 审批结果:1-同意,2-发回,3-拒绝。点审批即已查收。
*/
@NotNull(message = "审批结果不能为空")
@Min(value = 1, message = "审批结果不正确")
@Max(value = 3, message = "审批结果不正确")
private Integer spzt;
/**
* 审批意见,可选,记录审批的具体意见或发回原因。
* 审批意见,发回时填写原因。
*/
@Size(max = 500, message = "审批意见不能超过500个字符")
private String fhyj;
/**
* 审批人编号,必填,标识审批人身份。
* 审批人编号,不传时取当前登录人;同时记为查收人。
*/
@NotBlank(message = "审批人编号不能为空")
@Size(max = 50, message = "审批人编号不能超过50个字符")
private String sprbh;
/**
* 机关编号,机关审批时必填,标识审批机关。
*/
@Size(max = 50, message = "机关编号不能超过50个字符")
private String jgbh;
}
@@ -38,20 +38,30 @@ public class ScheduleAdjustQueryDTO extends PageQuery {
private Integer jyspzzt;
/**
* 教研室查收状态:0-未查收,1-已查收。
* 教研室查收状态:0-未查收,1-已查收。点了审批即为已查收。
*/
private Integer jyscszt;
/**
* 机关审批状态:0-未审批,1-已同意,2-已发回,3-已拒绝。
*/
private Integer jgspzt;
/**
* 删除状态:0-正常,1-已删除。
*/
private Integer sczt;
/**
* 教研室代号,教研室角色由服务端强制写入,前端不必传。
*/
private String jysdh;
/**
* 学员队任务表编号。
*/
private String xydrwbh;
/**
* 课编号。
*/
private String kbh;
/**
* 申请日期范围开始。
*/
@@ -1,52 +0,0 @@
package com.roomroot.jwgl.dto.courserunning;
import lombok.Data;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* 调课策略新增/修改参数。
* <p>
* 统一处理新增和修改:策略编号为空时执行新增,非空时执行修改。
* 策略类型为 TIME_LIMIT 时需填写截止星期和截止节次;
* 策略类型为 AUTO_APPROVE 时截止星期和截止节次不生效。
* </p>
*/
@Data
public class ScheduleAdjustStrategyDTO {
/** 策略编号(修改时必填,新增时为空) */
@Size(max = 50, message = "策略编号不能超过50个字符")
private String clbh;
/** 策略名称 */
@NotBlank(message = "策略名称不能为空")
@Size(max = 100, message = "策略名称不能超过100个字符")
private String clmc;
/** 策略类型:TIME_LIMIT=时间段限制,AUTO_APPROVE=免审批 */
@NotBlank(message = "策略类型不能为空")
@Size(max = 20, message = "策略类型不能超过20个字符")
private String cllx;
/** 是否启用:0=停用,1=启用(为空时默认1) */
private Integer sfqy;
/** 截止星期:0-6(仅 TIME_LIMIT 类型使用) */
private Integer jzxq;
/** 截止节次(仅 TIME_LIMIT 类型使用) */
private Integer jzjc;
/** 生效开始时间 */
private LocalDateTime sxkssj;
/** 生效结束时间 */
private LocalDateTime sxjssj;
/** 备注 */
@Size(max = 500, message = "备注不能超过500个字符")
private String bz;
}
@@ -0,0 +1,32 @@
package com.roomroot.jwgl.dto.discipline;
import com.roomroot.jwgl.entity.ZYB;
import lombok.Data;
/**
* 专业(专业表)导入行解析结果。
* <p>
* 保留 Excel 中的原始行号,便于把校验失败原因定位到具体行。
* </p>
*/
@Data
public class MajorImportRowDTO {
/**
* Excel 行号(1 起始,含表头行)。
*/
private int rowNum;
/**
* 该行解析出的专业实体。
*/
private ZYB entity;
public MajorImportRowDTO() {
}
public MajorImportRowDTO(int rowNum, ZYB entity) {
this.rowNum = rowNum;
this.entity = entity;
}
}
@@ -16,4 +16,16 @@ public class AddTeacherDTO {
/** 教员属性信息(含职务、技术等级、学历学位等非空字段) */
private JYSX attributes;
/** 是否同时创建系统账号 */
private Boolean createUser;
/** 登录名(空则取教员编号) */
private String loginName;
/** 初始密码明文(空则取统一初始值) */
private String password;
/** 角色ID(空则取默认教员角色 101) */
private Long roleId;
}
@@ -0,0 +1,32 @@
package com.roomroot.jwgl.dto.faculty;
import com.roomroot.jwgl.entity.JYB;
import lombok.Data;
/**
* 教员(教员表)导入行解析结果。
* <p>
* 保留 Excel 中的原始行号,便于把校验失败原因定位到具体行。
* </p>
*/
@Data
public class TeacherImportRowDTO {
/**
* Excel 行号(1 起始,含表头行)。
*/
private int rowNum;
/**
* 该行解析出的教员实体。
*/
private JYB entity;
public TeacherImportRowDTO() {
}
public TeacherImportRowDTO(int rowNum, JYB entity) {
this.rowNum = rowNum;
this.entity = entity;
}
}
@@ -0,0 +1,15 @@
package com.roomroot.jwgl.dto.jys;
import lombok.Data;
import java.util.List;
/**
* 选修课批量操作参数。
*/
@Data
public class ElectiveCourseBatchDTO {
/** 学员队任务编号列表 */
private List<String> bhList;
}
@@ -0,0 +1,62 @@
package com.roomroot.jwgl.dto.jys;
import com.roomroot.common.annotation.Excel;
import lombok.Data;
/**
* 选修课数据文件导入行。
*/
@Data
public class ElectiveCourseImportDTO {
@Excel(name = "授课教员")
private String jyxm;
@Excel(name = "课程科目名称")
private String kmc;
@Excel(name = "可选班次年级")
private String kxbcnj;
@Excel(name = "选修班名称")
private String xxbmc;
@Excel(name = "选择课状态")
private String xkzt;
@Excel(name = "培训层次")
private String pxcc;
@Excel(name = "教材")
private String jcmc;
@Excel(name = "教学场地")
private String jsmc;
@Excel(name = "计划学时")
private Integer jhxs;
@Excel(name = "运行学时")
private Integer yxxs;
@Excel(name = "学分")
private Float xf;
@Excel(name = "开课日期")
private String kkrq;
@Excel(name = "结课日期")
private String jkrq;
@Excel(name = "报名开始日期")
private String bmkssj;
@Excel(name = "报名结束日期")
private String bmjssj;
@Excel(name = "计划人数")
private Integer jhrs;
@Excel(name = "要求说明")
private String yqsm;
}
@@ -0,0 +1,33 @@
package com.roomroot.jwgl.dto.jys;
import lombok.Data;
import java.util.List;
/**
* 选修课管理查询条件。
*/
@Data
public class ElectiveCourseQuery {
/** 授课教员姓名(模糊) */
private String jyxm;
/** 课程科目名称(模糊) */
private String kmc;
/** 可选班次年级(模糊,匹配年级或可选队列班次) */
private String kxbcnj;
/** 选修班名称(模糊) */
private String xxbmc;
/** 选择课状态:拟制 / 开放报名 / 停止报名 */
private String xkzt;
/** 培训层次 */
private String pxcc;
/** 任务编号列表(学员名单导出时使用) */
private List<String> bhList;
}
@@ -0,0 +1,73 @@
package com.roomroot.jwgl.dto.jys;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 新建选修课。
* <p>写入学员队任务表(课类型含“选修”),并同步拼班信息中的报名日期与要求说明。</p>
*/
@Data
public class ElectiveCourseSaveDTO {
/** 年度,空则取当前年 */
private Integer nd;
/** 学员队编号(选修班),与选修班名称二选一 */
private String xydbh;
/** 选修班名称。学员队编号为空时按名称查找或新建选修班 */
private String xxbmc;
/** 年级(新建选修班时使用) */
private String nj;
/** 课编号 */
private String kbh;
/** 学期第次 */
private Integer xqdc;
/** 授课教员编号 */
private String jybh;
/** 教室编号 */
private String jsbh;
/** 教材名称(按名称匹配教材信息,写入课程教材关联) */
private String jcmc;
/** 计划人数 */
private Integer rs;
/** 计划学时 */
private Integer xs;
/** 学分 */
private Float xf;
/** 教研室代号 */
private String jysdh;
/** 备注 */
private String bz;
/** 要求说明 */
private String yqsm;
/** 显示可选队列班次 */
private String kxdlbc;
/** 开课日期 */
private LocalDateTime kkrq;
/** 结课日期 */
private LocalDateTime jkrq;
/** 报名开始日期 */
private LocalDateTime bmkssj;
/** 报名结束日期 */
private LocalDateTime bmjssj;
}
@@ -0,0 +1,22 @@
package com.roomroot.jwgl.dto.jys;
import lombok.Data;
/**
* 教学任务列表查询条件。
*/
@Data
public class TeachingTaskQuery {
/** 任务名称(模糊) */
private String rwmc;
/** 年度,空则本学期年度 */
private Integer nd;
/** 学期第次 */
private Integer xqdc;
/** 状态:上报 / 发布 */
private String zt;
}
@@ -0,0 +1,32 @@
package com.roomroot.jwgl.dto.jys;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
/**
* 新增 / 编辑教学任务。
* <p>机关发布教学任务,并关联学员队(班次);教研室任务书按课程归属教研室自动生成。</p>
*/
@Data
public class TeachingTaskSaveDTO {
/** 编号,编辑时必填 */
private String bh;
/** 年度,空则取当前学期 */
private Integer nd;
/** 学期第次,空则取当前学期 */
private Integer xqdc;
/** 任务名称 */
private String rwmc;
/** 结束时间 */
private LocalDateTime jssj;
/** 关联的学员队年度学期基本信息编号 */
private List<String> xydxqbhList;
}
@@ -0,0 +1,30 @@
package com.roomroot.jwgl.dto.kcb;
import lombok.Data;
/**
* 课表网格查询参数(手册一第12章 课表生成)。
* <p>dim 维度:semester 班次学期 / team 学员队 / teacher 教员 / room 教室。
* id 为对应维度主键(xydxqbh / xydbh / jybh / jsbh)。</p>
*/
@Data
public class TimetableGridQuery {
/** 维度:semester | team | teacher | room */
private String dim;
/** 维度目标编号 */
private String id;
/** 年度(校历/备注取数用;semester 维度自动从班次学期带出) */
private Integer nd;
/** 起始日期 yyyy-MM-dd;空时 semester 取学期范围,其它维度取本周 */
private String start;
/** 结束日期 yyyy-MM-dd */
private String end;
/** 课表模板编号(可选;套用模板显示开关:78节/晚上/夜间/选修/天数) */
private String mbbh;
}
@@ -0,0 +1,40 @@
package com.roomroot.jwgl.dto.kcb;
import lombok.Data;
import java.util.List;
/**
* 班次课表查询条件。
* <p>未传年度、学期时按当前时间取本学期。</p>
*/
@Data
public class TimetableQuery {
/** 年度,空则本学期年度 */
private Integer nd;
/** 学期第次,空则本学期序号 */
private Integer xqdc;
/** 学员队编号(队别班次) */
private String xydbh;
/** 学员队名称(队别班次模糊) */
private String xydmc;
/** 教员编号(主讲/辅讲/责任教员任一命中) */
private String jybh;
/** 教室编号(课次场地或课程默认场地任一命中) */
private String jsbh;
/** 教研室代号(按课程归属教研室过滤) */
private String jysdh;
/** 学员编号(服务端解析为其所在学员队后按队过滤) */
private String xybh;
/** 教员编号集合(教研室等批量范围过滤用) */
private List<String> jybhs;
}

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