Compare commits

..

146 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: #2
2026-08-24 07:39:18 +00:00
zhaichao d0d7669b8f Merge remote-tracking branch 'upstream/main' 2026-08-24 15:30:42 +08:00
zhaichao 48aa410130 页面接口对接,以及样式调整 2026-08-24 15:28:13 +08:00
zhaichao 1a1b1ce66b 样式统一 2026-08-24 14:48:08 +08:00
zhaichao ad83f6b581 Merge pull request 'Main' (#1) from zhaichao/education:main into main
Reviewed-on: #1
2026-08-24 03:07:44 +00:00
zhaichao 215a48446d 表格横向滚动优化 2026-08-24 11:02:04 +08:00
zhaichao 3ac8c9496e 首页 2026-08-24 10:51:17 +08:00
zhaichao a5cd5eab44 样式 2026-08-24 10:49:27 +08:00
zhaichao 5e3217dc8f 课表接口修改 2026-08-24 10:07:50 +08:00
zhaichao ee25e06680 学期管理页面样式优化 2026-08-24 10:07:36 +08:00
zhaichao 137528beb2 校历 2026-08-24 10:04:59 +08:00
zhaichao a29c357ed2 选修课页面恢复 2026-08-24 09:30:26 +08:00
zhaichao c2098878b1 课程科目 2026-08-24 09:20:20 +08:00
zhaichao 08b1ea4606 样式调整 2026-08-24 09:15:34 +08:00
zhaichao 43f1aab297 样式调整 2026-08-23 21:43:03 +08:00
zhaichao 71257bdce0 多余组件删除 2026-08-23 21:02:32 +08:00
zhaichao 526b9082df 班次学期信息管理 2026-08-23 21:02:15 +08:00
zhaichao 499518a2a6 分组教学任务和教学任务计划管理 2026-08-23 20:43:24 +08:00
zhaichao 18bbfd71ba 人才培养方案 2026-08-23 20:34:08 +08:00
zhaichao ec448a1977 教学大纲 2026-08-23 20:33:20 +08:00
zhaichao 0a25dac2c1 教学场地 2026-08-23 20:31:48 +08:00
zhaichao a8aba532e2 分组教学任务 2026-08-23 20:31:14 +08:00
zhaichao 8bf726a745 课表调整申请 2026-08-23 20:24:04 +08:00
zhaichao 26fe8ea334 冲突检查 2026-08-23 20:23:37 +08:00
zhaichao 5fb95ae476 课表调整 2026-08-23 20:13:46 +08:00
zhaichao 2d3150c566 课表 2026-08-23 19:54:30 +08:00
zhaichao 0c3de2809e 教员管理 2026-08-23 18:42:33 +08:00
zhaichao 24ca73ffa5 教材管理 2026-08-23 18:39:34 +08:00
zhaichao 24907a7621 班次学员队 2026-08-23 17:51:51 +08:00
zhaichao 4b952280b3 学员预警结果 2026-08-23 17:51:20 +08:00
zhaichao 12214a326f 学员学籍异动申请 2026-08-23 17:23:17 +08:00
zhaichao c7f334ed53 防抖优化 2026-08-23 17:15:24 +08:00
zhaichao 088a35c9e8 缩放优化 2026-08-23 16:58:51 +08:00
zhaichao 18f1faba5f 自适应优化 2026-08-23 16:48:29 +08:00
zhaichao 0ea410ffec 移除班次课程表占位页面 2026-08-23 16:33:31 +08:00
zhaichao 29387b3193 课时补助核算 2026-08-23 16:33:10 +08:00
zhaichao 001a264f16 方案管理 2026-08-23 16:32:47 +08:00
zhaichao 1abadfb3ff 居中 2026-08-23 16:32:25 +08:00
zhaichao cc623d5fdb 全局表格字段居中显示 2026-08-23 16:31:38 +08:00
zhaichao 370cb615d0 课时补助核算两个tab页 2026-08-23 16:20:07 +08:00
zhaichao 97562579dc 联教联训管理接口文件 2026-08-23 16:17:51 +08:00
zhaichao 7a453e4ac3 联教联训管理 2026-08-23 16:17:28 +08:00
zhaichao a4b3c241a2 点击标题关闭所有tab 2026-08-23 16:12:57 +08:00
zhaichao fe008ce383 班次课程表二级菜单加图标以及添加占位页面 2026-08-23 16:09:46 +08:00
zhaichao 657774e1b1 禁止修改全局布局,以及菜单栏变动 2026-08-23 16:08:48 +08:00
zhaichao 4efb84e5d2 教学实施计划导入 2026-08-23 16:03:02 +08:00
zhaichao 776ffaac4f 教学日志管理 2026-08-23 15:57:09 +08:00
zhaichao 8a8aa0c7ca 学科专业 2026-08-23 15:47:43 +08:00
zhaichao 61ef0c1214 全局自适应以及表格横向拖动优化 2026-08-23 15:36:11 +08:00
zhaichao 14d4fa7c7c 恢复丢失的API集成模块(教学日志/学员成绩/预警条件/专业管理)
从git对象库找回此前未提交即丢失的文件: api/log.js, api/studentRecords/*, api/subjectMajor/major.js, teachingLog/organLog/components/*
2026-08-23 15:20:55 +08:00
zhaichao d20c490c74 1. 机关教学日志2.新增全局表格横向拖拽滚动指令3.学员模块 2026-08-23 15:10:56 +08:00
zhaichao df7800f001 chore: untrack Maven build artifacts under target/ and add gitignore 2026-08-21 18:52:49 +08:00
1837 changed files with 70734 additions and 38474 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"}
+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
@@ -1 +0,0 @@
restart.include.json=/com.alibaba.fastjson2.*.jar
@@ -1,56 +0,0 @@
# 数据源配置
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
password: Jiaowu123
driver-class-name: dm.jdbc.driver.DmDriver
# Druid 基础参数
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: roomroot
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
db-type: dm
@@ -1,149 +0,0 @@
# 项目相关配置
roomroot:
# 名称
name: roomroot
# 版本
version: 3.9.2
# 版权年份
copyrightYear: 2026
# 文件路径 示例( Windows配置D:/roomroot/uploadPath,Linux配置 /home/roomroot/uploadPath)
profile: D:/roomroot/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8080
servlet:
# 应用的访问路径
context-path: /api
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 1000
threads:
# tomcat最大线程数,默认为200
max: 800
# Tomcat启动初始化的线程数,默认值10
min-spare: 100
# 日志配置
logging:
level:
com.roomroot: debug
#org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间(默认10分钟)
lockTime: 10
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
data:
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟)
expireTime: 30
# MyBatis-Plus配置
mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.roomroot.**.domain
# 配置mapper的扫描,找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:com/roomroot/**/mapper/*.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# Springdoc配置
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui.html
tags-sorter: alpha
group-configs:
- group: 'default'
display-name: '测试模块'
paths-to-match: '/**'
packages-to-scan: com.roomroot.web.controller.tool
# 防盗链配置
referer:
# 防盗链开关
enabled: false
# 允许的域名列表
allowed-domains: localhost,127.0.0.1,roomroot.vip,www.roomroot.vip
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 自定义内嵌Redis开关
custom:
embedded-redis:
# dev环境true自动启动内嵌Redis;prod改为false使用外部Redis
enable: false
port: 6379
max-memory: 128M
@@ -1,5 +0,0 @@
Application Version: ${roomroot.version}
Spring Boot Version: ${spring-boot.version}
////////////////////////////////////////////////////////////////////
// 启动开始 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////

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