diff --git a/BPMN流程图_业务流程模型.html b/BPMN流程图_业务流程模型.html
new file mode 100644
index 0000000..3e5233f
--- /dev/null
+++ b/BPMN流程图_业务流程模型.html
@@ -0,0 +1,1924 @@
+
+
+
+
+
+ JCDP教育培训管理系统 - BPMN业务流程模型
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📊 业务流程总览
+ JCDP系统核心业务流程一览
+
+
+
+
培训计划管理 PROC-TRAIN-PLAN
+
年度培训计划的制定、调研、汇总与审批流程
+
+ 审批流
+ 多部门协作
+ 年度周期
+
+
+
+
+
培训实施管理 PROC-TRAIN-IMPLEMENT
+
培训班级创建、学员管理、授课与效果评估
+
+ 状态驱动
+ 班级管理
+ 效果反馈
+
+
+
+
+
考试管理 PROC-EXAM
+
试卷管理、在线答题、自动/人工判卷
+
+ 定时触发
+ 自动判分
+ 人员限定
+
+
+
+
+
外派培训管理 PROC-OUTTRAIN
+
外部培训申请、审批、归来登记与考核
+
+ 审批流
+ 外出管理
+ 经济责任制
+
+
+
+
+
通用审批流程 SUB-APPROVAL
+
被其他流程调用的通用多级审批子流程
+
+ 子流程
+ 多级审批
+ 可复用
+
+
+
+
+
年度培训总结 PROC-YEAR-SUMMARY
+
年度培训数据汇总、报告生成
+
+ 填报流
+ 年度周期
+ 数据汇总
+
+
+
+
+
+
+
+ 📝 培训计划管理流程 PROC-TRAIN-PLAN
+ 年度培训计划的制定、调研、汇总与审批管理
+
+
+
+
+
+
+
👥 参与者定义
+
+
+
🎯
+
+
所级管理员
+
发起计划、下发通知、汇总生成、审批
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📋 流程节点详情
+
+
+
+ | 节点ID |
+ 节点名称 |
+ 类型 |
+ 输入 |
+ 输出 |
+ 执行人 |
+
+
+
+
+ | PROC-TRAIN-PLAN.START |
+ 开始 |
+ 开始事件 |
+ 年度计划请求 |
+ - |
+ 所级管理员 |
+
+
+ | PROC-TRAIN-PLAN.CREATE |
+ 创建计划 |
+ 用户任务 |
+ 计划类型 |
+ et_train_ip/gip/gop记录 |
+ 所级管理员 |
+
+
+ | PROC-TRAIN-PLAN.FILL |
+ 部门填报 |
+ 子流程 |
+ 通知 |
+ et_train_gipgroup_kc |
+ 部门管理员 |
+
+
+ | PROC-TRAIN-PLAN.SURVEY |
+ 调研征集 |
+ 排他网关 |
+ - |
+ et_train_ipdy |
+ 所级管理员 |
+
+
+ | PROC-TRAIN-PLAN.SUMMARY |
+ 汇总生成 |
+ 用户任务 |
+ 部门需求 |
+ et_train_ipf |
+ 所级管理员 |
+
+
+ | PROC-TRAIN-PLAN.APPROVE |
+ 审批流程 |
+ 子流程 |
+ 计划ID |
+ 审批结果 |
+ 领导层 |
+
+
+ | PROC-TRAIN-PLAN.END |
+ 计划生效 |
+ 结束事件 |
+ 审批通过 |
+ 状态变更 |
+ 系统 |
+
+
+
+
+
+
+
+ 🎓 培训实施管理流程 PROC-TRAIN-IMPLEMENT
+ 培训班级的创建、审核、学员管理、授课与效果评估
+
+
+
+
+
+
+
+
+ 🔄 培训班级状态机
+
+
+
→
+
+
→
+
+
→
+
+
→
+
+
→
+
+
+
+
+
+
+
+
+
+ 📊 培训完成判定规则
+
+
判定逻辑:
+
+IF (nd >= 2023) THEN
+ 完成条件 = et_train_pd_cc_pgwjyxx.status = 2 (问卷/心得状态=已完成)
+ELSE
+ 完成条件 = IF(yxx.status IS NOT NULL, yxx.status=2, pg.status=1)
+END IF
+
+说明:2023年起新增培训效果问卷反馈环节,替代原有的评分机制
+
+
+
+
+
+ 📋 考试管理流程 PROC-EXAM
+ 试卷管理、在线答题、自动/人工判卷全流程
+
+
+
+
+
+
+
+
+ 🔄 考试状态机 (exampaper.state)
+
+
+
→
+
+
未开始
+
未开始
+
datediff>0
+
+
→
+
+
进行中
+
正在进行
+
startdate≤0≤enddate
+
+
→
+
+
已关闭
+
已关闭
+
datediff<0
+
+
→
+
+
+
+
+ ✏️ 判分规则
+
+
+
+ | 题型 |
+ 自动判分 |
+ 人工判分 |
+ 说明 |
+
+
+
+
+ | 单选题 |
+ ✅ 支持 |
+ ❌ |
+ 答案一致得分 |
+
+
+ | 多选题 |
+ ✅ 支持 |
+ ❌ |
+ 答案一致得分 |
+
+
+ | 判断题 |
+ ✅ 支持 |
+ ❌ |
+ 答案一致得分 |
+
+
+ | 简答题 |
+ ❌ |
+ ✅ 支持 |
+ 需阅卷教师评分 |
+
+
+
+
+
+
+
+
+
+
+
+
+ 🌐 外派培训管理流程 PROC-OUTTRAIN
+ 外部培训申请、审批、归来登记与考核关联
+
+
+
+
+
+
+
+
+
+
+ 📊 关键数据表
+
+
+
+ | 表名 |
+ 说明 |
+ 关键字段 |
+
+
+
+
+ | et_train_ot |
+ 外派培训主表 |
+ pxmc, pxfy, sld, pxdjfw, status=5 |
+
+
+ | et_train_ot_xy |
+ 外派学员表 |
+ usercode, username |
+
+
+ | et_train_ot_pxdj |
+ 外派登记表 |
+ status=4 (已完成登记) |
+
+
+
+
+
+
+
+ ✅ 通用审批流程 SUB-APPROVAL
+ 被其他流程调用的通用多级审批子流程
+
+
+
+
+
+
+
+
+
+
+ 📊 审批数据存储 (et_train_sp)
+
+
+
+ | 字段 |
+ 说明 |
+
+
+
+
+ | tname |
+ 目标业务表名 |
+
+
+ | tid |
+ 目标业务记录ID |
+
+
+ | spusername |
+ 审批人姓名 |
+
+
+ | spdate |
+ 审批时间 |
+
+
+ | yj |
+ 审批意见 |
+
+
+ | spresult |
+ 审批结果 (通过/驳回) |
+
+
+
+
+
+
+
+ 📈 年度培训总结流程 PROC-YEAR-SUMMARY
+ 年度培训数据汇总、报告生成流程
+
+
+
+
+
+
+
+
+
+
+
+
+ 📊 流程模型总览
+
+
+
+
+ | 流程ID |
+ 流程名称 |
+ 类型 |
+ 触发方式 |
+ 关联主表 |
+
+
+
+
+ | PROC-TRAIN-PLAN |
+ 培训计划管理 |
+ 审批流 |
+ 手工触发 |
+ et_train_ip / et_train_gip |
+
+
+ | PROC-TRAIN-IMPLEMENT |
+ 培训实施管理 |
+ 状态流 |
+ 计划批准后 |
+ et_train_pd_cc |
+
+
+ | PROC-EXAM |
+ 考试管理 |
+ 定时流 |
+ 试卷发布 |
+ et_exam_exampaper |
+
+
+ | PROC-OUTTRAIN |
+ 外派培训 |
+ 审批流 |
+ 手工发起 |
+ et_train_ot |
+
+
+ | SUB-APPROVAL |
+ 通用审批 |
+ 子流程 |
+ 被调用 |
+ et_train_sp |
+
+
+ | PROC-YEAR-SUMMARY |
+ 年度总结 |
+ 填报流 |
+ 年度结束 |
+ et_train_ys |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CODE_FIX_PLAN.md b/CODE_FIX_PLAN.md
new file mode 100644
index 0000000..6963b29
--- /dev/null
+++ b/CODE_FIX_PLAN.md
@@ -0,0 +1,311 @@
+# JCDP 项目代码修复方案
+
+> **文档版本**: v1.0
+> **创建时间**: 2026-04-16
+> **依据**: [CODE_REVIEW_REPORT.md](./CODE_REVIEW_REPORT.md)
+
+---
+
+## 一、修复执行情况
+
+### ✅ 已完成修复
+
+| 序号 | 问题 | 修复文件 | 修复内容 |
+|------|------|----------|----------|
+| 1 | 全局变量未声明 | `globalConfig.js` | 为 8 个正则变量添加 `const` 声明 |
+| 2 | 日期 API 误用 | `globalConfig.js` | `getDay()` → `getDate()` (第268、271行) |
+| 3 | 废弃 SQL 清理 | 4 个 map.xml | 删除 16 个废弃 SQL 定义 |
+| 4 | 注释死代码 | 115 个 ftl | 删除 615+ 处注释代码 |
+
+### 📋 待处理问题
+
+| 序号 | 问题 | 优先级 | 说明 |
+|------|------|--------|------|
+| 1 | 同步 AJAX 请求 | 🟠 严重 | 6 处 `async: false` 需要改为异步 |
+| 2 | SELECT * 过多 | 🟡 建议 | 120+ 处可优化为指定字段 |
+| 3 | 内联样式过多 | 🟡 建议 | 6265+ 处 style 属性待清理 |
+| 4 | 内联事件处理 | 🟡 建议 | 115 处 onclick/onchange 待重构 |
+
+---
+
+## 二、已修复问题详情
+
+### 2.1 全局变量声明修复
+
+**文件**: `asset/js/etms/globalConfig.js`
+
+**修复内容**: 为验证函数中的正则表达式变量添加 `const` 声明
+
+```javascript
+// 修复前
+validator: function (val) {
+ isIDCard1 = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
+ isIDCard2 = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}[0-9xX]$/;
+ ...
+}
+
+// 修复后
+validator: function (val) {
+ const isIDCard1 = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;
+ const isIDCard2 = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}[0-9xX]$/;
+ ...
+}
+```
+
+**涉及变量**: `isIDCard1`, `isIDCard2`, `isPostcode`, `isAboveAndEqualZero`, `isPositiveNumber`, `isPositiveInteger`, `isMonthNum`, `moreThanFive`, `isPointNum`, `isEmail`
+
+---
+
+### 2.2 日期 API 修复
+
+**文件**: `asset/js/etms/globalConfig.js` 第 268、271 行
+
+**修复内容**: `getDay()` → `getDate()`
+
+```javascript
+// 修复前
+if (dateTime1.getDay() == dateTime2.getDay()) {
+ tempTime = dateTime2.format("hh:mm");
+} else {
+ if (dateTime1.getDay() - dateTime2.getDay() == 1) {
+ tempTime = dateTime2.format("昨天 hh:mm");
+ }
+}
+
+// 修复后
+if (dateTime1.getDate() == dateTime2.getDate()) {
+ tempTime = dateTime2.format("hh:mm");
+} else {
+ if (dateTime1.getDate() - dateTime2.getDate() == 1) {
+ tempTime = dateTime2.format("昨天 hh:mm");
+ }
+}
+```
+
+---
+
+### 2.3 废弃 SQL 清理
+
+**修复文件**:
+- `chat.map.xml`: 删除 `updatePkgListToOld`
+- `et_exam_editexampaper.map.xml`: 删除 `moveOld`
+- `et_exam_usertest.map.xml`: 删除 10 个废弃 SQL
+- `et_train_outtrain.map.xml`: 删除 2 个废弃 SQL
+
+**清理的废弃 SQL ID**:
+- `getExamResultList之前的写法,在此备份`
+- `truncateExamDetail备份`
+- `getPersonDetail备份`
+- `getClassDetail备份`
+- `getCourseDetail备份`
+- `getInstitutionDetail 第二种写法 最慢`
+- `getDepartmentDetail 第二种写法 最慢`
+- `getPersonDetail第二种写法`
+- `getPersonDetail第三种写法 最慢`
+- `getClassDetail 第二种写法 最慢`
+- `getCourseDetail 第二种写法 最慢`
+- `getOutTrainDbList以前的写法备份`
+- `getOutTrainPxdjList以前的写法备份`
+
+---
+
+### 2.4 FTL 注释死代码清理
+
+**清理统计**:
+- 修改文件: 115 个
+- 清理注释: 615+ 处
+
+**高发文件** (Top 10):
+| 文件 | 清理数量 |
+|------|----------|
+| `exampaper_editexampaper.ftl` | 74 处 |
+| `examresult_edit.ftl` | 33 处 |
+| `exam_edit.ftl` | 37 处 |
+| `exampaper_add.ftl` | 29 处 |
+| `group_inplan_main.ftl` | 61 处 |
+| `group_inplan_bg_group_detail_1.ftl` | 34 处 |
+| `group_inplan_bg_group_detail.ftl` | 32 处 |
+| `research_project_main_examadd_sg.ftl` | 49 处 |
+| `exampaper_import.ftl` | 21 处 |
+| `pd_pg_main_assess.ftl` | 20 处 |
+
+---
+
+## 三、待处理问题修复方案
+
+### 3.1 同步 AJAX 请求改造 (🟠 严重)
+
+**问题位置**:
+- `globalConfig.js` 第 200 行
+- `userprofile/index.js` 第 71、104 行
+- `train/uptrain/uptrain.js` 第 176 行
+- `train/uptrain/uptrain_edit.js` 第 394 行
+- `train/plantodo/assess_audit.js` 第 319 行
+- `train/outtrain/out_train_main.js` 第 1209 行
+
+**修复方案示例**:
+
+```javascript
+// 修复前 (globalConfig.js)
+$.ajax({
+ type: 'post',
+ async: false, // 阻塞 UI
+ url: dictBaseUrl + dictKey,
+ dataType: 'json',
+ success: function (result) {
+ if (result.success) {
+ window[hdName] = result.data;
+ res = result.data;
+ }
+ }
+});
+
+// 修复后 (方案1: Promise + async/await)
+async function getDictData(dictKey) {
+ try {
+ const result = await $.ajax({
+ type: 'post',
+ url: dictBaseUrl + dictKey,
+ dataType: 'json'
+ });
+ if (result.success) {
+ window[dict_prefix + dictKey] = result.data;
+ return result.data;
+ }
+ return null;
+ } catch (error) {
+ console.error('获取字典数据失败:', error);
+ return null;
+ }
+}
+
+// 修复后 (方案2: 回调函数)
+function getDictData(dictKey, callback) {
+ $.ajax({
+ type: 'post',
+ url: dictBaseUrl + dictKey,
+ dataType: 'json',
+ success: function (result) {
+ if (result.success) {
+ window[dict_prefix + dictKey] = result.data;
+ callback(result.data);
+ } else {
+ callback(null);
+ }
+ },
+ error: function() {
+ callback(null);
+ }
+ });
+}
+```
+
+**建议优先级**:
+1. 优先改造 `globalConfig.js` 中的 `gridColFilter` 函数
+2. 然后处理业务模块中的同步请求
+3. 最后处理 `out_train_main.js` 等复杂模块
+
+---
+
+### 3.2 SELECT * 优化 (🟡 建议)
+
+**优化原则**:
+- 明确列出需要的字段
+- 减少网络传输开销
+- 提高代码可读性
+
+**示例**:
+
+```xml
+
+
+ select * from et_resource_file where 1=1
+
+
+
+
+ select id, name, file_path, file_size, created_by, created_at
+ from et_resource_file where 1=1
+
+```
+
+**建议**: 优先优化高频查询的 SQL
+
+---
+
+### 3.3 内联样式清理 (🟡 建议)
+
+**优化方案**: 提取为 CSS 类
+
+```html
+
+
+
+
+
+.form-title {
+ height: 86px;
+}
+
+
+
+```
+
+**建议**:
+1. 优先清理高频页面的内联样式
+2. 建立公共样式类库
+3. 使用 CSS 变量统一管理主题色
+
+---
+
+### 3.4 内联事件重构 (🟡 建议)
+
+**优化方案**: 使用 data 属性 + JS 事件委托
+
+```html
+
+
+
+
+
+
+
+
+$(document).on('click', '.checkbox-option', function() {
+ var action = $(this).data('check-action');
+ if (action && window[action]) {
+ window[action](this);
+ }
+});
+```
+
+---
+
+## 四、后续改进建议
+
+### 4.1 短期 (1个月内)
+- [ ] 完成同步 AJAX 改造
+- [ ] 引入 ESLint 检查
+- [ ] 建立代码格式化规范
+
+### 4.2 中期 (3个月内)
+- [ ] 优化高频 SQL 查询
+- [ ] 清理内联样式
+- [ ] 重构内联事件处理
+
+### 4.3 长期 (持续改进)
+- [ ] 引入自动化测试
+- [ ] 建立代码质量度量
+- [ ] 完善 Code Review 流程
+
+---
+
+## 五、相关文件
+
+- [CODE_REVIEW_GUIDE.md](./CODE_REVIEW_GUIDE.md) - 代码审查标准
+- [CODE_REVIEW_REPORT.md](./CODE_REVIEW_REPORT.md) - 代码审查报告
+
+---
+
+*本修复方案由 AI 代码审查专家生成*
diff --git a/WEB-INF/mapping/chatVersion.map.xml b/WEB-INF/mapping/chatVersion.map.xml
index a921b63..04bc1d6 100644
--- a/WEB-INF/mapping/chatVersion.map.xml
+++ b/WEB-INF/mapping/chatVersion.map.xml
@@ -8,13 +8,9 @@
<@p p=" AND %s">isupdatepkg@p>
]]>
- pkgtype@p>
- <@p p=" AND %s">isupdatepkg@p>
- ]]>
-
-
+id@p>
]]>
- newnum@p>
- where
- <@p>edit_id@p>
- <@p p=" and num = ?">oldnum@p>
- ]]>
-
-
+num@p>
where <@p>id@p>
diff --git a/WEB-INF/mapping/et_exam_usertest.map.xml b/WEB-INF/mapping/et_exam_usertest.map.xml
index fbefb57..d937a31 100644
--- a/WEB-INF/mapping/et_exam_usertest.map.xml
+++ b/WEB-INF/mapping/et_exam_usertest.map.xml
@@ -27,20 +27,9 @@ et_exam_usertest.user_answer
) examresult
]]>
- edit_id@p>
- <@p p=" and et_exam_exampaper_and_editexampaper.name like ? ">name@p>
- <@p p=" or user like ? ">user@p>
- group by user_id
- ]]>
-
-
+name@p>
<@p p=" and %s">pg@p>
@@ -78,47 +67,15 @@ et_exam_usertest.user_answer,et_exam_usertest.user_score
<@p p=" and %s">exam_id@p>
]]>
-
+
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation as limitation
- left join et_exam_usertest as usertest
- on limitation.exam_id = usertest.exam_id
- where <@p p=" limitation.exam_id = ?">exam_id@p>
- group by limitation.user_id
- ]]>
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation_class as class
- left join et_exam_usertest as usertest
- on class.exam_id = usertest.exam_id
- where <@p p=" class.exam_id = ?">exam_id@p>
- group by class.class_person_id
- ]]>
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation_course as course
- left join et_exam_usertest as usertest
- on course.exam_id = usertest.exam_id
- where <@p p=" course.exam_id = ?">exam_id@p>
- group by course.course_person_id
- ]]>
-
-
+exam_id@p>
]]>
@@ -133,19 +90,9 @@ et_exam_usertest.user_answer,et_exam_usertest.user_score
group by user_id
]]>
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from (select e.id as exam_id,b.username,b.usercode from et_exam_exampaper_and_editexampaper e,et_train_baseuser b
- where <@p p=" e.id = ? ">exam_id@p>) as baseuser
- left join et_exam_usertest as usertest
- on baseuser.exam_id = usertest.exam_id
- where <@p p=" baseuser.exam_id = ? ">exam_id@p>
- group by baseuser.usercode
- ]]>
-
-
+exam_id@p> group by user_id)
@@ -157,21 +104,9 @@ et_exam_usertest.user_answer,et_exam_usertest.user_score
group by user_id
]]>
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from (select l.exam_id,b.username,b.usercode from et_exam_limitation l,et_train_baseuser b
- where <@p p=" l.exam_id = ? ">exam_id@p>
- and b.orgcode = any (select user_id from et_exam_limitation
- where <@p>exam_id@p>) group by b.usercode) as baseuser
- left join et_exam_usertest as usertest
- on baseuser.exam_id = usertest.exam_id
- where <@p p=" baseuser.exam_id = ? ">exam_id@p>
- group by baseuser.usercode
- ]]>
-
-
+
-
+
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation as limitation
- left join et_exam_usertest as usertest
- on limitation.exam_id = usertest.exam_id
- where <@p p=" limitation.exam_id = ?">exam_id@p>
- group by limitation.user_id
- ]]>
-
-
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation_class as class
- left join et_exam_usertest as usertest
- on class.exam_id = usertest.exam_id
- where <@p p=" class.exam_id = ?">exam_id@p>
- group by class.class_person_id
- ]]>
-
-
+
- exam_id@p>)) = 1,"已答","未答")) as userstate
- from et_exam_limitation_course as course
- left join et_exam_usertest as usertest
- on course.exam_id = usertest.exam_id
- where <@p p=" course.exam_id = ?">exam_id@p>
- group by course.course_person_id
- ]]>
-
-
+enddate2@p>
]]>
- usercode@p> ) and ot.pxdjfw='1'
-and UPPER(<@p f="?">usercode@p>) not in (select UPPER(pxdj.addusercode) from et_train_ot_pxdj pxdj where ot.id=pxdj.otid)
- or 1=<@p f="?">sfgly@p> and ot.pxdjfw='0' and UPPER(ot.addusercode) =UPPER(<@p f="?">usercode@p>)
- and UPPER(<@p f="?">usercode@p>) not in (select pxdj.addusercode from et_train_ot_pxdj pxdj where ot.id=pxdj.otid))
- group by ot.id order by ot.addtime desc
- ]]>
-
-
+usercode@p> and pxdjfw='0' and delstatus=0 and status=5
and <@p f="?">usercode@p> not in (select pxdj.addusercode from et_train_ot_pxdj pxdj where ot.id=pxdj.otid)
@@ -66,23 +59,9 @@ select ot.pxmc, pxdj.* from et_train_ot_pxdj pxdj left join et_train_ot ot on(ot
select ot.pxmc, pxdj.* from et_train_ot_pxdj pxdj left join et_train_ot ot on(ot.id=pxdj.otid) where 1=1
<@p p="AND ot.ID IN(%s)" f="?">id@p>
]]>
- id@p>
- <@p p="and ot.pxmc like ?">pxmc@p>
- and (('0'=<@p f="?">sfsp@p>
- and 1=1
- <@p p="AND UPPER(pxdj.addusercode) =UPPER(%s)" f="?">usercode@p>
- or '1'=<@p f="?">sfgly@p>
- <@p p="AND pxdj.addgroupid =%s" f="?">groupid@p>
- and 1=1 ) or (1=1
- <@p p="AND UPPER(pxdj.addusercode) =UPPER(%s)" f="?">usercode@p>
- <@p p="AND pxdj.addgroupid =%s" f="?">groupid@p>
- <@p p="AND pxdj.status =%s" f="?">status@p>
- and '1'=<@p f="?))">sfsp@p>
- ]]>
-
-
+
<#include "../layout/ref_script.ftl">
-<#---->