Files
tuanwei-admin/docs/phase2-P0-delivery.md
T
gxwebsoft d8e7e2a2a8 feat(volunteer): 新增志愿服务证明材料识别及年度证明功能
- 新增志愿证明材料识别功能,支持自动识别材料并回填关键信息
- 在志愿时长编辑页面添加材料识别按钮及识别结果展示
- 新增志愿服务证明模块,支持查询、生成及下载年度志愿服务证明PDF
- 志愿时长列表及审核详情中新增“服务地点”字段显示
- 志愿时长导入功能支持“服务地点”字段,完善导入表头与数据映射
- 志愿时长详情、审核流程等界面优化,增加识别材料公章状态及流程节点提示
- 志愿时长待审核项支持用户撤回操作,撤回后记录被删除需重新录入
- 社团年度报告相关接口新增,实现社团年度报告生成及分页查询
- 调整相关样式与界面布局,提升用户体验与信息展示完整性
2026-11-06 12:04:32 +08:00

19 KiB
Raw Blame History

二期 P0 交付说明

一、本次交付范围

按《副本二期功能--定稿0802.docx》规划,P0 阶段交付以下 8 个功能模块,全部已完成前后端联调验证。

# 功能 状态 后端接口前缀 前端页面
1 站内消息中心 已完成 /api/oa/notice、/api/oa/notice-template 复用既有顶栏铃铛 + /user/notice;新增模板与推送记录页
2 第二课堂学分 已完成 /api/gxmu/credit /growth/credit
3 学生成长主页 已完成 /api/gxmu/growth/my /growth/myHome
4 志愿服务时长 已完成 /api/gxmu/volunteer /club/volunteerHour、/club/volunteerReview、/club/volunteerCertificate
5 社团管理 已完成 /api/gxmu/club /club/club、/club/activity、/club/activityReview
6 场地预约 已完成 /api/gxmu/venue /club/venue、/club/venueReview
7 青马培养档案 已完成 /api/gxmu/qmgc-student /gxmu/qmgcStudent、/gxmu/qmgcTask、/gxmu/qmgcScore
8 主题团课库 已完成 /api/gxmu/thematic-course /gxmu/thematicCourse

P1/P2 的 10 个功能已建菜单与占位页(写明实施依赖),不会出现菜单 404:

社会实践学分、学分预警、学生画像、推荐内容、社团年审、社团评优、AI 辅助教学设计、AI 主题团日设计、专家评审、专家库。

二、数据库部署

在 tuanwei-java/sql/ 下按顺序执行(全部可重复执行):

mysql -h <host> -P <port> -u <user> -p tuanwei < sql/20261105_phase2_01_growth_credit.sql
mysql ... < sql/20261105_phase2_02_volunteer.sql
mysql ... < sql/20261105_phase2_03_club_venue.sql
mysql ... < sql/20261105_phase2_04_qmgc.sql
mysql ... < sql/20261105_phase2_05_thematic_course.sql
mysql ... < sql/20261105_phase2_06_notice.sql
mysql ... < sql/20261105_phase2_07_review_parallel.sql
mysql ... < sql/20261105_phase2_08_menu_permission.sql
mysql ... < sql/20261105_phase2_09_dict.sql
脚本 内容 是否含初始数据
01 学分规则/记录/社会实践/毕业要求/预警/画像/推荐(8 张表) 6 条毕业学分要求
02 志愿时长/证明模板/已生成证明(3 张表) 无
03 社团/成员/活动/年审/评优/年报/场地/预约(8 张表) 无
04 青马学员/材料/任务/任务分配/评分/考试(7 张表) 无
05 主题团课库(1 张表) 无
06 站内消息 + 消息模板(2 张表) 10 条消息模板
07 审核流并行节点改造(ALTER 4 处) 回填存量 parallel_group
08 菜单 + 按钮权限 + 角色授权(62 条菜单/按钮) 超管全量、学生部分
09 字典(学分类别、社团类别) 11 条字典项

注意:脚本 07 会修改 gxmu_review_flow / gxmu_review_list / gxmu_review_flow_config 三张生产表,只是新增列并回填,不影响存量串行审核逻辑。

三、后端改动清单

新增包

com.gxwebsoft.notice           消息中心(Notice / NoticeTemplate / 2 个 Controller / 2 个 Mapper)
com.gxwebsoft.gxmu.credit      学分域(规则、记录、汇总、导入)
com.gxwebsoft.gxmu.volunteer   志愿服务(录入、导入、审核、汇总)
com.gxwebsoft.gxmu.club        社团(主档、成员、活动)
com.gxwebsoft.gxmu.venue       场地与预约(含时间段冲突校验)
com.gxwebsoft.gxmu.qmgcpro     青马培养档案(学员、材料、任务、评分)
com.gxwebsoft.gxmu.thematic    主题团课库(含 jsoup 爬虫)
com.gxwebsoft.gxmu.growth      成长主页聚合

关键实现说明

  1. 消息中心:路径与前端既有约定完全一致(/api/oa/notice),顶栏铃铛和 /user/notice 无需改代码即可生效。查询默认按当前登录用户收口,学生只能看自己的消息。
  2. 学分汇总:应修学分来自 gxmu_graduate_requirement(学院专属优先于「不限」),已修来自 gxmu_credit_record;按类别输出已修/应修/差额/完成率。
  3. 场地冲突校验:同场地 + 同日期 + 状态非驳回,时间段半开区间重叠即拒绝;审核通过前会二次校验,避免并发下重复通过。
  4. 成长主页聚合:串起 sys_user + gxmu_student + gxmu_tygl_form + 学分 + 志愿 + 社团 + 青马;任一未建表时静默跳过,不影响其他区块。
  5. 消息推送:志愿提交/审核、场地预约/审核已接入模板推送,失败不阻塞主业务。
  6. 团课爬虫:站点通过 gxmu.thematic-course.sites 配置(名称|列表页|条目选择器|标题选择器|链接选择器,多个站点换行分隔),未配置时只支持手工维护。

新增配置项

gxmu:
  thematic-course:
    max-per-site: 50          # 单站点单轮抓取上限
    sites: |                  # 可选,格式见上

四、前端改动清单

新增目录

src/api/growth/{credit,volunteer,home,club,qmgc,thematic}/
src/api/system/notice/
src/components/MultiFileUpload/          统一多附件上传(JSON 数组与后端契约)
src/views/growth/{myHome,credit,practiceCredit,creditWarning,portrait,recommend}/
src/views/club/{volunteerHour,volunteerReview,volunteerCertificate,club,activity,activityReview,venue,venueReview,annualReview,award}/
src/views/gxmu/{qmgcStudent,qmgcTask,qmgcScore,thematicCourse,teachingDesign,themeDayDesign,expertReview,expertPool}/
src/views/system/{messageTemplate,messageLog}/

复用而非重写

  • 列表页统一 ele-pro-table + .page/.ele-body/a-card,与 studentRoster 一致。
  • 导入复用 views/gxmu/components/common-import.vue(模板下载、逐行校验、失败清单)。
  • 附件展示复用 attachmentList,审核状态复用 reviewStatusTag。
  • 权限判断用 hasPermission / hasAnyRole(注意 hasRole 是「全部满足」语义)。

五、验证记录

已执行

项 结果
后端 mvn -o compile(JDK 17) 通过
前端 vite build 通过
前端 vue-tsc(仅新增文件) 0 错误
9 个 SQL 脚本在开发库执行 全部成功
18 个 GET 接口 全部 200 / code=0
社团 → 成员 → 详情(人数联动) 通过
场地 → 预约 → 冲突拒绝 → 当日排期 通过
志愿录入(缺附件拒绝)→ 审核 → 汇总 4 小时 通过
学分导入 → 重复导入跳过 → 汇总 0.5/9.0 通过
成长主页聚合(真实学院/班级/团支书数据) 通过
志愿审核触发站内消息落库 通过

验证后已清理

测试期间创建的社团、成员、场地、预约、志愿记录、学分记录、站内消息已全部删除,保留毕业要求与消息模板等基础配置。

六、上线前必做

  1. 执行 9 个 SQL 脚本(生产库先备份,尤其脚本 07 改动审核表)。
  2. 给角色授权:脚本 08 只授了 superAdmin 和 student,其余角色(校团委、二级学院团委、指导老师)需在「角色管理」里按需勾选二期菜单。
  3. 配置团课抓取站点(如需自动同步),否则该页只能手工录入。
  4. 确认 Redis 可用:消息与登录依赖 Redis,本地验证时需先启动。
  5. 学生账号:需要 gxmu_student.user_id 已认领,成长主页才能带出学籍信息;否则只显示账号基础信息。

七、已知边界

项 说明
志愿证明 PDF 已实现:按年度汇总已通过审核的志愿时长,生成含志愿者姓名、学院、专业、班级、学号、活动名称、活动时间、活动地点、时长、数据来源、总时长的 PDF,自动加水印,不设电子章(正文留公章位)。接口 /api/gxmu/volunteer/certificate/*
社团年度数据报告 已实现:按年度汇总活动、成员、场地数据,生成含核心指标、类别分布、月度趋势、成员构成图表与文字小结的 PDF。入口「社团与志愿 → 年度数据报告」(/club/report),接口 /api/gxmu/club/report/*。文字小结可按需编辑后再生成
志愿记录服务地点 新增 gxmu_volunteer_record.service_place,录入表单与导入模板均支持;证明材料「活动地点」列取此值
OCR 公章识别 字段已预留(ocr_status / ocr_org / ocr_raw),未接 OCR 服务;活动审批暂由人工核验材料
审核流并行 已实现,见下方「补充交付」
学分自动获取 第二课堂/桂志愿暂无 API,先走 Excel 导入,source + external_id 已为后续对接预留
移动端 本期只交付 PC,接口均支持 /api/open 对外复用,移动端工程后续独立建设

八、补充交付(P0 收尾追加)

8.1 审核流并行审批

青马选拔要求「二级学院团委 + 二级学院党委」同时审核,原审核引擎用 sortNumber + 1 推进,隐含「一个节点一个人」。

改动:

文件 改动
entity/ReviewFlow 新增 parallelGroup
entity/ReviewList 新增 parallelGroup、attachments
entity/ReviewFlowConfig 新增 rejectMode
service/ReviewProgressService(新增) 按并行组推进、幂等创建、组内待审判断
service/impl/ReviewProgressServiceImpl(新增) 上述实现
service/impl/ReviewFlowStarterServiceImpl 发起时创建首个并行组的全部节点(原来只建一个)
controller/ReviewListController 用 progressService.advance() 替换原串行推进
service/impl/DeclareGuardServiceImpl syncReviewStatus 改为「任一组驳回过即驳回」,不再只看最后一条

语义:

  • parallelGroup 相同的节点属同一组,全部通过才进入下一组;
  • 组内任一驳回按 reject_mode 处理,默认 any(任一驳回即终止);
  • parallelGroup 为空的存量数据退化为「sortNumber 即组号」,保持原串行行为;
  • 推进逻辑幂等:重复点击通过不会重复创建下一组节点。

验证结果(开发库实测):

场景 结果
同组两人,第一人通过 不创建下一组(仍有待审)✓
第二人通过 创建第 2 组节点 ✓
第 2 组驳回 不再创建新节点,流程终止 ✓
末组驳回后申报记录状态 回写为「驳回」(原逻辑会误判为通过)✓

8.2 修复:9 张申报表缺 declare_id 列

开发库未执行过 sql/20261102_add_declare_uniqueness.sql,导致青马申报页报 Unknown column 'declare_id'。已执行该迁移,9 张申报表接口全部恢复 200。

上线提醒:若生产库也未执行此迁移,请一并补上,否则青马工程、五四评优等申报页会直接报错。

8.3 修复:个人资料保存 403

views/user/profile 原来调用 PUT /system/user(需 sys:user:update),学生账号没有该权限会保存失败。已改为后端已有的 PUT /system/user/self,并新增前端封装 updateSelfUser。

8.4 统一最新审核记录排序

reviewStatusTag 原按 id 取最新,utils/review.ts 按 createTime + id,并行审核下两处可能给出矛盾结论。现已抽出 getLatestReview() 统一为「sortNumber → createTime → id」,两个调用方共用。

九、P1 首批交付:社会实践学分 + 学分预警

9.1 社会实践学分

后端(com.gxwebsoft.gxmu.credit)

文件 说明
PracticeCreditController 提交/撤回/作废/删除/汇总/导出
PracticeCreditService + Impl 校验、状态回写、通过后自动发放学分
PracticeCreditApplyParam 查询参数

审核接入:模块名 gxmu_practice_credit,走既有 gxmu_review_list 引擎,四级审核(个人 → 班级 → 二级学院团委 → 校团委)在「审核流配置」里绑定即可。ReviewListController 审核完成后回调:

  1. syncReviewStatus 回写申报状态;
  2. grantCreditWhenApproved 在通过时写一条 gxmu_credit_record(source=practice、external_id=practice-{id},幂等)。

教务处模板导出:POST /api/gxmu/practice-credit/export,输出 14 列 xls(序号/学号/姓名/学院/班级/学年/活动名称/活动类型/起止日期/实践内容/担任角色/核定学分/审核状态),走既有「生成文件 → FileRecord 入库 → 返回下载地址」模式。

前端:/growth/practiceCredit,替换原占位页。

9.2 学分预警

文件 说明
CreditWarningService + Impl 缺口计算、级别判定、月度去重推送
CreditWarningController 列表/汇总/重算/推送
CreditWarningTask(新增) 每天 02:30 全量重算,gxmu.credit-warning.enabled 可关

级别规则:gap/required ≥ 0.6 且 gap ≥ 2 → danger;≥ 0.3 → warn;其余 normal。 叠加绝对门槛是因为只看比例会把「应修 1 分、缺 1 分」也判成严重。

去重:同一学生同一类别每个自然月只推一条站内消息(notify_month 记录)。

闭环:补分后重算会自动清理已达成类别的预警(逻辑删除),不会永远挂着。

前端:/growth/creditWarning,替换原占位页。

9.3 验证记录

场景 结果
社会实践缺附件提交 拒绝「请上传社会实践证明材料」✓
正常提交 → 生成审核节点 ✓
审核通过 → 申报状态置 2 ✓
审核通过 → 学分自动入账(2.00,source=practice) ✓
重复审核同一条 → 学分不重复发 ✓(仍 1 条 2.00)
学分类别缺口识别 6 类全部识别 ✓
补分后重算 → 该类别预警清除 ✓(有效预警 6→5)
级别判定 缺 2 分 danger、缺 1 分 warn ✓
预警推送 → 第一次 5 条、第二次 0 条 月度去重生效 ✓

9.4 修复记录

初版曾把 gxmu_practice_credit 加进 DeclareGuardServiceImpl 的模块列表,导致审核回写时按「模块名=表名」去更新不存在的表。已移除——社会实践用独立表 gxmu_practice_credit_apply,状态回写由自己的 service 负责。

十、部署排查:部署后看不到新功能

症状

前端已是最新版本,侧栏没有「成长中心」「社团与志愿」;访问新接口报错:

Table 'tuanwei.gxmu_credit_record' doesn't exist

原因

三个部分必须同时到位,缺一项都会表现为「没有新功能」:

部分 状态判断 缺失表现
前端 dist 已确认包含新页面(index.0475cb90.js 内有 21 个新路由) 页面 404
后端 jar 已确认新接口可达(返回业务错误而非 404) 接口 404
数据库 未执行二期 SQL 接口报表不存在、侧栏无菜单

菜单是动态从 sys_menu 读取的(GET /auth/user → formatMenus → addRoute), 库里没有菜单记录,前端代码再全也不会显示。

部署步骤

在服务器的 tuanwei-java 目录执行:

# 方式一:一键脚本(自动备份 + 执行 9 个脚本 + 验证)
sh sql/deploy_phase2.sh ./sql

# 方式二:合并脚本(单文件,等价于依次执行 01~09)
docker exec -i 1Panel-mariadb-ZOpD \
  mysql -utuanwei -p'TytQZsSW5m4wGh38' tuanwei < sql/phase2_all_in_one.sql

# 方式三:逐个执行(便于定位问题)
for f in sql/20261105_phase2_0*.sql; do
  docker exec -i 1Panel-mariadb-ZOpD \
    mysql -utuanwei -p'TytQZsSW5m4wGh38' tuanwei < "$f"
done

执行完重启后端(Docker 里通常已配置 restart: unless-stopped,只需 docker restart tuanwei-api),然后浏览器强制刷新并重新登录。

脚本安全性

  • 全部可重复执行,实测连续执行两遍:146 条语句零报错,菜单/授权/模板/字典数量完全不变
  • 07 会 ALTER 三张审核表,只新增列并回填存量数据,不改原有字段
  • 脚本建议先备份;deploy_phase2.sh 已内置自动备份并校验备份非空

执行后的验证

SELECT COUNT(*) FROM sys_menu WHERE menu_id BETWEEN 14500 AND 14663;   -- 应为 62
SELECT COUNT(*) FROM oa_notice_template;                                -- 应为 10
SELECT COUNT(*) FROM gxmu_graduate_requirement;                         -- 应为 6

接口验证:

curl -H "Authorization: <token>" https://twai-api.gxmu.edu.cn/api/gxmu/credit/page
# 应返回 {"code":0,...} 而不是 Table doesn't exist

若菜单仍未出现

脚本 08 只给 superAdmin 和 student 授了权。若你当前账号是其他角色 (校团委、二级学院团委、指导老师等),需在「系统设置 → 角色管理」里 手动勾选二期菜单。

十一、导入报错 ERROR 1273 Unknown collation

症状

导入 SQL 时在第 271 行报:

ERROR 1273 (HY000): Unknown collation: 'utf8mb4_0900_ai_ci'

出错语句是 CREATE TABLE gxmu_certificate_template,结尾带 COLLATE=utf8mb4_0900_ai_ci。

原因

导错了文件:这条语句来自从开发库导出的整库 dump,不是二期的迁移脚本。

  • 开发库是 MySQL 8.0.44,建表时 DEFAULT CHARSET=utf8mb4 会隐式采用 MySQL 8 专有的 utf8mb4_0900_ai_ci
  • 生产是 MariaDB,不识别这个 collation,直接报错

经核查,sql/20261105_phase2_*.sql 里 COLLATE= 出现 0 次, 不是迁移脚本的问题。mysqldump 导出时会把隐式默认值显式写出来,于是把 MySQL 8 的特性带进了 dump。

解决方案

方案 A(推荐):用迁移脚本,不要导整库 dump

docker exec -i 1Panel-mariadb-ZOpD \
  mysql -utuanwei -p'密码' tuanwei < sql/phase2_all_in_one.sql

迁移脚本的建表语句现在已显式锁定 COLLATE=utf8mb4_general_ci (30 处建表全部处理),在 MySQL 8 / MariaDB 上都能安全执行。

方案 B:确实要导整库 dump 时,先做兼容转换

python3 sql/fix_mysql8_dump_for_mariadb.py dev_dump.sql
# 生成 dev_dump.mariadb.sql,再导入
docker exec -i 1Panel-mariadb-ZOpD \
  mysql -utuanwei -p'密码' tuanwei < dev_dump.mariadb.sql

转换器会处理:

转换项 说明
utf8mb4_0900_* → utf8mb4_general_ci / utf8mb4_bin 核心问题
utf8mb3_* → utf8mb4_* MySQL 8 的新叫法,MariaDB 不认
CHARACTER SET utf8mb3 / CHARSET=utf8mb3 裸写声明
删除 SET @@GLOBAL.GTID_PURGED 等 MariaDB 不支持或会报错
处理 /*!80000 ... */ 版本条件注释 仅 MySQL 8 执行的内容

当前开发库情况

开发库 88 张表中有 61 张是 utf8mb4_0900_ai_ci(sys_user、gxmu_club 等),如果整库同步到生产,这 61 张都会失败。建议只同步二期新增的数据, 或先跑转换器。

防呆

deploy_phase2.sh 新增了预检:执行前扫描脚本中是否含 utf8mb4_0900_ai_ci,命中则直接中止并提示「不要导入 MySQL 8 的整库 dump」。