weicw
|
a57a824004
|
fix(sql): 注册表种子 tenant_id 对齐本环境租户(10049)
|
2026-11-04 00:08:47 +08:00 |
|
weicw
|
3c2e8b082c
|
fix(sql): 回填脚本 LIKE 显式 COLLATE(MySQL 8 上业务表 general_ci 与组织表 0900_ai_ci 混用会报错)
|
2026-11-04 00:04:26 +08:00 |
|
weicw
|
7696a56740
|
fix(sql): 注册表不登记 gxmu_tygl(只是前端别名,无业务表,会让启动期一致性校验失败)
|
2026-11-04 00:01:24 +08:00 |
|
weicw
|
9b6c9fb90c
|
merge: 审查修复(college 写入、逐级解析、文件默认收紧、注册表 all/has_college、层级校验下沉)
|
2026-11-03 23:16:21 +08:00 |
|
weicw
|
70213ab783
|
refactor(gxmu): 审批链层级校验下沉到 Service,删除路径也校验剩余链
- ReviewFlowController 里约 115 行的 validateLevels / validateUpdate /
validateBatchUpdate / validateRemaining / merge 下沉为
ReviewFlowService.validateLevelsOnSave / OnUpdate / OnBatchUpdate / OnRemove,
controller 只在写操作前调用一次
- remove / removeBatch 新增删除后剩余链连续性校验;删除前就已不连续的链跳过校验,
避免存量脏数据变成「永远删不掉」
- 顺手修掉一个真缺陷:merge 会就地改 existing,导致「改名后原链剩余校验」永远不触发
(批量路径同样先取旧标题再合并)
- 模块标题回退三份收敛成 ModuleRegistryService.titleOf(Map, module) 一处,
ReviewFlowConfigServiceImpl / ReviewListServiceImpl 直接调用
- ReviewFlowLevelValidator 的手写 join 换成 Collectors.joining(", ")
- 回填脚本头部补「表名 → 学院文本列」对照表,注明新增表按此表同步 4 处
refs #58
|
2026-11-03 23:14:24 +08:00 |
|
weicw
|
6bfdae5787
|
fix(security): 文件内联预览默认需登录,公开目录改为显式白名单
- file.public-preview 默认值由 true 改为 false(application.yml 与 @Value 同步),
上传一律落在 /yyyyMMdd/ 日期目录,默认公开等于把所有上传文件(含盖章证明材料)
变成匿名可读;公开页面引用的文件必须把所在目录列进 file.public-dirs
- 注释写清「公开页面引用的文件必须列进白名单,否则匿名访问会被拒」,同步更新
FileAccessRules 类注释
- 删掉只被测试调用的 FileAccessRules.isPublicFileRequest(测试钉住的是没上线的
平行判定);测试改为断言 downloadPatterns / permitAllPatterns /
authenticatedPatterns 的内容与顺序
- 顺带把 gxmu.module-registry.strict 改成 ${GXMU_MODULE_REGISTRY_STRICT:true},
与相邻配置一致
refs #58
|
2026-11-03 23:14:13 +08:00 |
|
weicw
|
43f0119b25
|
fix(gxmu): 审批人解析覆盖第 2..N 级,已处理节点再提交直接拒绝
- ReviewFlowStarterService 新增 advanceReview(module, pk, currentSortNumber):
通过后推进下一级也走 ReviewerResolver,不再 setUserId(nextOne.getReviewUserId());
解析为空抛可读 BusinessException 且不写节点,最后一级则不生成节点
- ReviewListController 的推进改为调用 advanceReview;ManuscriptController 的首级
改为 startReview("cms_manuscript", id),cms 稿件不再复制 review_user_id
- 推进前校验当前节点 status == 0(ReviewStatus.PENDING),已处理节点再 PUT 直接拒绝,
避免重复通过造出第二组活跃节点;批量审批同样逐行校验
- 新增 ReviewStatus 常量(gxmu_review_list.status:0待审 1通过 2驳回),
把 controller / starter / DeclareGuard / TzbcyFormServiceImpl 里的裸 1、2 换成常量
- 解析失败的兜底消息补上学院与层级,与 ReviewerResolver 口径一致
- 审批动作注释里的「撤销」改成实际语义(通过 / 驳回)
refs #58
|
2026-11-03 23:14:00 +08:00 |
|
weicw
|
be011dd4f1
|
fix(gxmu): 新申报按学籍补齐 college_id,不再只有存量回填
4 张在跑表(gxmu_sjqn / gxmu_tzbcy_form / gxmu_qmgc_form / gxmu_wxxzx_project)
的实体补 collegeId,save 路径在为空时按「登录用户 → gxmu_student.college_id」
补齐;解析不到(无学籍、名册未同步、学院不唯一)一律留空不报错。
更新路径不调用解析器,collegeId 为 null 时 MyBatis-Plus 忽略该字段,库里已有值不变。
解析逻辑收在一个共享组件 CollegeResolver 里,4 个 controller 只各调一行;
口径与一次性回填脚本一致(优先在校那条学籍,学院不唯一就留空)。
单测:有学籍时写入、无学籍时留空、学院多义时留空、更新不覆盖已有值。
refs #58
|
2026-11-03 23:13:41 +08:00 |
|
weicw
|
37cc8ee0d5
|
fix(gxmu): 注册表补 has_college 与团员管理种子,接口返回 DTO 并支持 all=true
- gxmu_module_registry 增加 has_college(4 张在跑表置 1,含已有库补列与补数据语句)
- 种子补 gxmu_tygl_form / gxmu_tygl(enabled=0,团员管理,sort 11/12),
同步修正末尾「执行后校验」:12 行未删除、5 行启用、has_college 4 行
- GET /api/gxmu/module-registry/list 支持 all=true(默认只返回启用),
改为返回 ModuleRegistryDTO,不再外泄 tenantId / userId / 时间戳
- ModuleRegistryService:删掉无生产调用的 titleOf(String)/allModules,
标题回退收敛成唯一的静态 titleOf(Map, module);getByModule 改由 hasCollege 使用
- listAll 只保留 SQL 排序(sort_number 升序,NULL 排最前,与 MySQL ASC 口径一致),
删掉内存二次排序
- ModuleRegistryIntegrityChecker 增加反向告警:review_flow_config 里有、注册表里没有的
module 打 warn,不阻断启动
refs #58
|
2026-11-03 23:13:29 +08:00 |
|
weicw
|
9c4476a395
|
fix(sql): 注册表种子启用稿件模块(cms_manuscript 有在跑的审核链)
|
2026-11-03 22:36:52 +08:00 |
|
weicw
|
4c2cf5542e
|
merge: #60 模块注册表后端与启动期一致性校验
|
2026-11-03 22:31:28 +08:00 |
|
weicw
|
2838bc0d9e
|
merge: #61 审批人规则解析并接入发起与重提
|
2026-11-03 22:31:19 +08:00 |
|
weicw
|
5c998f39d0
|
merge: #62 驳回清理旧节点与审批链层级校验
冲突解决:ReviewFlowStarterServiceImpl 保留 #62 的驳回清理与事务注解,
发起/重提仍由 ReviewerResolver 解析取人;合并两份 ReviewFlowStarterServiceImplTest,
置于同一文件(驳回清理 4 个用例 + 审批人解析 4 个用例)。
|
2026-11-03 22:30:39 +08:00 |
|
weicw
|
51b8dddd22
|
merge: #64 学院标识一次性回填脚本
|
2026-11-03 22:29:48 +08:00 |
|
weicw
|
02b2e4b56b
|
merge: spec58/integration(带进 #59 schema 与已合并的集成顶部)
|
2026-11-03 22:29:27 +08:00 |
|
weicw
|
11f0f90f7a
|
feat(spec58): 模块注册表后端与模块硬编码收敛(#60)
- 新增 gxmu/module 包:ModuleRegistry 实体/Mapper/Service,listEnabled 按 sort_number 升序,titleOf 未注册回退 module 原串
- 新增 GET /api/gxmu/module-registry/list(需登录),返回启用模块元数据
- ReviewFlowConfigServiceImpl / ReviewListServiceImpl 的模块名映射改读注册表,查不到回退原串
- DeclareGuardServiceImpl 的模块集合改为注册表驱动,含 enabled=0(停用模块存量仍可撤回/作废)
- 启动期一致性校验:table_name≠module 或业务表缺失即启动失败,gxmu.module-registry.strict=false 可关闭
- 单测 13 例:注册表加载与排序、titleOf 回退、启动校验、module 名回退
|
2026-11-03 22:29:27 +08:00 |
|
weicw
|
446a56db72
|
Merge branch 'spec58/integration' into spec58/t6
|
2026-11-03 22:28:55 +08:00 |
|
weicw
|
5b7ddd48c7
|
feat(spec58): 4 张业务表 college_id 一次性回填脚本
以学生档案 gxmu_student.college_id 为准,按 user_id 回填 sjqn / tzbcy_form /
qmgc_form / wxxzx_project 的 college_id;仍为空的行再用表单里的学院文本
按组织名 LIKE 兜底,只有唯一命中才写入,无法匹配留空。
- A 段学生档案主路径,优先取在校记录的学院,档案学院不唯一时留空不猜
- B 段文本兜底,候选学院 = 有平台单位号的节点 ∪ 学生档案引用过的节点
- 只填空不覆盖,可重复执行;不接定时任务
- 附回填率、空值清单、未匹配文本一览与一致性抽查(3a-3d),供人工核对
|
2026-11-03 22:28:49 +08:00 |
|
weicw
|
58b09b029a
|
merge: #63 审批动作鉴权与文件访问白名单
|
2026-11-03 22:28:29 +08:00 |
|
weicw
|
f96613a0ee
|
feat(spec58): 审批人解析组件 ReviewerResolver 与发起接线
- 新增 ReviewerResolver:USER:<userId> / COLLEGE_ROLE:<roleCode>,; 分隔多段取并集升序
- reviewer_rule 为空回退 review_user_id;按学院解析空集合抛 BusinessException,消息含学院名/层级/缺什么
- ReviewFlowStarterService 发起与驳回重提改由解析取人,解析为空不写任何节点
- ReviewFlow 增加 reviewerRule 字段;DeclareRecordMapper 增加 selectReviewContext(仅 4 张在跑表)
|
2026-11-03 22:28:02 +08:00 |
|
weicw
|
c732cdb037
|
Merge branch 'spec58/integration' into spec58/t5
|
2026-11-03 22:26:58 +08:00 |
|
Codex
|
d65e8453f5
|
fix(file): 下载需登录,内联预览与缩略图默认公开
- /api/file/download/** 恒需登录,注册顺序排在公开模式之前
- 新增 file.public-preview(默认 true):内联预览 /api/file/*/* 与缩略图默认匿名
- file.public-dirs 保留为额外公开目录,语义限定在原图与缩略图
- 测试补三条:下载无白名单也需登录、内联默认公开、public-preview=false 时内联需登录
|
2026-11-03 22:26:52 +08:00 |
|
weicw
|
4b50891fd4
|
merge: #62 驳回清理旧节点与审批链层级校验
|
2026-11-03 22:25:44 +08:00 |
|
weicw
|
91b3007939
|
Merge branch 'spec58/integration' into spec58/t4
|
2026-11-03 22:25:01 +08:00 |
|
weicw
|
17499cb526
|
fix(review): 驳回重走时清理旧节点,审批链层级连续性保存校验
- restartReviewWhenLastRejected 先删同一申报记录下旧节点再建第一级,同一事务
- 新增 ReviewFlowLevelValidator,按 title 校验层级从 1 连续升序
- ReviewFlowController 的 save/update/saveBatch/updateBatch 接入校验
- 单测覆盖驳回清理、层级缺级/重复/多链独立校验
|
2026-11-03 22:24:56 +08:00 |
|
weicw
|
b8c9c6c853
|
Merge branch 'spec58/integration' into spec58/t5
|
2026-11-03 22:23:42 +08:00 |
|
Codex
|
94071092e3
|
fix(review): 审批动作校验归属、驳回必须写意见、文件下载需登录
- PUT /api/gxmu/review-list 与 /batch:操作者必须是待办行 user_id,否则 code 403
- status=2 且意见为空时拒绝并提示「驳回必须填写审核意见」
- GET /api/file/** 由匿名改为需登录,公开目录走 file.public-dirs 白名单
- 新增 FileAccessRules 纯规则组件,SecurityConfig 按其产出注册 antMatchers
- 新增 ReviewListControllerAuthTest(8 例)与 FileAccessRulesTest(7 例)
|
2026-11-03 22:23:35 +08:00 |
|
weicw
|
1f2a837609
|
merge: #59 schema 脚本(审批人规则列、学院标识列、模块注册表)
|
2026-11-03 22:21:56 +08:00 |
|
weicw
|
fa7633b35e
|
feat(spec58): 审批人规则列、学院标识列与模块注册表
- gxmu_review_flow 增加 reviewer_rule(为空回退 review_user_id)
- 4 张在跑业务表增加可空 college_id,供按学院解析审批人
- 新建 gxmu_module_registry 并写入 10 个模块,仅 4 个在跑模块启用
- information_schema 判存 + INSERT IGNORE,脚本可重复执行
|
2026-11-03 22:21:22 +08:00 |
|
weicw
|
0e4986330a
|
feat(declare): 同一申报项目进行中只允许一条申报
- 新增 DeclareGuardService:按已通过/未处理驳回/待审核数判重,申报项目行加锁防连点
- 9 张申报表补 declare_id / declare_status / declare_remark,提交时写入并随审核结果回写
- 新增撤回、作废(强制放行)接口;挑战杯团队成员按手机号判重
- 申报项目支持配置允许重复提交与最多同时条数
- 迁移脚本 sql/20261102_add_declare_uniqueness.sql(含存量回填与重复清单)
|
2026-11-02 19:28:56 +08:00 |
|
weicw
|
76c9edd4be
|
feat(file): 上传准入白名单 + 素材媒体大类筛选
素材库要从「只传图片」放开到文档与音视频,后端必须先有一道类型防线:
/api/file/upload 此前对文件类型零校验,任意文件都能落到公开可读目录。
- UploadRules:image/* 按探测 MIME 放行(历史头像/图标格式多,不做后缀白名单);
其余按后缀白名单(pdf/doc/docx/xls/xlsx/ppt/pptx/txt/md/csv、
mp3/wav/m4a/aac、mp4/mov/webm),再用危险 MIME 黑名单兜住 exe 改名。
不用「扩展名必须等于探测类型」的严格比对:docx/xlsx/pptx 经 Tika 常得到
application/zip,md/csv 得到 text/plain,严格比对会误杀正常办公文档。
- FileStorageService.store 落盘后校验,本地分支失败删除刚写的文件,不留孤儿。
- FileController 单独捕获 UploadRejectedException,把原因原样回给前端。
- FileRecordParam.mediaCategory + Mapper 展开成 image/video/audio/doc 四类条件:
「文档」在 MIME 里没有统一前缀,只能落到 application/% | text/%。
设计取舍见 docs/adr/0004(本仓库外,tuanwei-home)。
|
2026-11-01 21:03:56 +08:00 |
|
weicw
|
9e88c53052
|
fix: 数据源会话时区强制 +08:00,修复创建时间早 8 小时
生产数据库容器(1Panel-mariadb-ZOpD)的 system_time_zone 是 UTC,而数据源 URL 写着
serverTimezone=Asia/Shanghai:JDBC 会话时区是 UTC、驱动却按 +08 解析服务端返回的字面量,
于是 timestamp 列(分类管理、文章、系统日志、审核流、AI 对话等)读出来整体早 8 小时。
数据源 URL 增加 connectionTimeZone=%2B08:00&forceConnectionTimeZoneToSession=true,
连接建立时把会话时区设为 +08:00,与 JVM 默认时区、spring.jackson.time-zone 保持一致。
用偏移量而非命名时区,避免 MariaDB 容器未加载时区表时报 Unknown or incorrect time zone。
附 sql/20261026_timezone_8h_check.sql:部署后的时区自检、分类管理核对,
以及 datetime 列历史 UTC 字面量与教师建号行的时间回填模板(默认注释未执行)。
|
2026-10-26 11:09:15 +08:00 |
|
weicw
|
0252672997
|
fix(ai): 短视频/图片产物归一并转存为对外地址(禅道 #1)
- 归一按内容识别 video_result(此前只认图片):地址字符串、markdown 链接、
文件对象都统一成 {url,name,type:video},端上四个页面才取得到播放地址,
修复「上游接口已通、我方未输出视频、复制链接为空」;
- answer 不再残留裸地址:媒体地址命中时改写成「文件名 + 链接」,
生成记录也补上媒体直链,纯视频分支不再因正文为空而整条不入库;
- 新增 CreativeMediaRelay:上游产物在内网,端上打不开,由后端下载、
存入本项目文件存储,下发 /api/file 对外地址(Range 续传现成);
失败只降级保留原地址,不影响本次生成;
- FileStorageService.storeFile 支持把磁盘文件落入本地/对象存储;
- 开发环境关闭转存(公网 demo 地址本就可直接访问),生产默认开启。
|
2026-10-25 15:55:49 +08:00 |
|
b2894lxlx
|
5626cdd679
|
fix: 申报可用时间按东八区判断,写入时显式使用北京时间
避免容器 JVM/库会话仍为 UTC 时 createTime 偏 8 小时,以及 usable 查询把刚开放的申报滤掉。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-10-25 12:20:04 +08:00 |
|
weicw
|
0a2801850d
|
fix(sync): 班级人数与辅导员不再被空值覆盖,人数按名册兜底
开放平台对 2025 级起的班级不返回 BJRS,对 2026 级连 FDYH 都不返回,
而 batchUpsert 用 VALUES() 直写这两列,每晚同步都会把人工补录的辅导员和
学生人数刷成 NULL;新生班级的人数因此一直空着,班级管理页首屏(2026 级)
两列全空。
- ClassInfoMapper.xml: counselor_name / student_count 改为
COALESCE(VALUES(x), x),平台有值仍以平台为准,给空时保留存量
- 新增 refreshStudentCountFromRoster:学生同步结束时按 gxmu_student
全量在册统计(不过滤 status,与平台 BJRS 口径一致)回填人数,
只补「为空或 0」的班级,名册里没学生的班级不动
- StudentSyncHandler: 学生段写完后调用兜底
开发库已用同一语句回填 728 个班级。
|
2026-10-24 20:41:35 +08:00 |
|
weicw
|
4c2a787d81
|
feat(ai): 写作/生图/创意/活动策划也保存历史记录
- ai_chat_list 新增 chat_type / params,旧数据默认 chat
- 新增 AiGenerationRecorder:成功后同事务写 list + history,末帧回传 chatId
- 聊天改为成功收尾才建行,失败/中止不再留下空记录
- 写作(含自由创作)、生图、创意助手、活动策划四处接入,软失败与断流不入库
- 历史列表只取最近 30 条(SQL LIMIT),并强制按登录用户过滤
- 修复历史排序用了不存在的 sort_number 列(多行会 NPE)
- 新增 4 个测试类:记录器规则、排序回归、创意成功/软失败、30 条上限
|
2026-10-24 17:37:39 +08:00 |
|
b2894lxlx
|
d54f559d34
|
fix: 审核列表与申报可见性,并统一 Docker 北京时区
修复团支部等角色待审漏数、PageParam 对 Collection 的 IN 条件失效,以及容器默认 UTC 导致时间偏移 8 小时的问题。
Co-authored-by: Cursor <cursoragent@cursor.com>
|
2026-10-24 14:55:11 +08:00 |
|
weicw-dshsa
|
da5c5c1e09
|
fix(ai): SSE 帧优先投给在途流式请求,修「生成后按钮永久不可点」
WebSocketServer.send 原本 WS 优先:只要同一账号还有 WS 会话(问答助手页会建
连接),文稿工作台那条 /stream 的帧就全被投到 WS 上,SSE 一帧收不到——正文只能
等末帧,收尾的 __END__ 永远不来,前端 loading 不复位,生成按钮卡死。
改为 SSE 优先:ChatStreamRegistry 是按请求登记的,登记期间发出的帧都属于那条
请求;没有在途请求时 emit 返回 false,照旧走 WS。握手回执「连接成功」改由
register() 直接写给该会话,避免被派发到别的请求。
测试:补两条回归(有在途 SSE 时即使 WS 在线也投 SSE;没有在途 SSE 时仍走 WS),
ai 包 158 条全绿。
|
2026-10-23 12:57:03 +08:00 |
|
weicw-dshsa
|
206adbff6c
|
chore(build): 项目 JDK 固定为 17,修正 .sdkmanrc 的过期结论
原先钉的是 JDK 8,注释里写「lombok 1.18.20 不支持 JDK 17」。实测不成立:
JDK 17 下 `mvn -o clean compile` 与 158 条 ai 测试全绿;真正炸的是 JDK 21
(NoSuchFieldError: JCTree$JCImport does not have member field 'qualid')。
本机 sdkman 全局默认已切到 21,所以按项目固定 17,不动 sdk default。
|
2026-10-23 12:57:03 +08:00 |
|
weicw-dshsa
|
1ae2ab580d
|
feat(manuscript): 稿件正文增加 content_format 格式标记
- cms_manuscript 新增 content_format(html/markdown/text),默认 html
- Manuscript 实体加 contentFormat;保存与修改时缺省按 html 落库,下游不再靠猜
- 迁移脚本幂等,并把明显是 markdown 的历史行标出来
|
2026-10-22 14:37:34 +08:00 |
|
weicw-dshsa
|
f5a89634c4
|
feat(file): 文件存储接入 RustFS(S3),修正文件外链域名与路径
文件上传从本地磁盘改为可切换的对象存储(默认 s3,type 改回 local 即退回原行为):
- 新增 common.core.storage 包:ObjectStorage 接口 + S3ObjectStorage(minio 8.5.17)
+ NoopObjectStorage + FileStorageService + StorageConfig + StoredFile;
key 规则沿用 file/yyyyMMdd/uuid.ext、缩略图 file/thumbnail/...,桶内结构对齐旧磁盘目录
- 读取仍走后端代理 GET /api/file/**:s3 模式下首次读取物化到本地 cache-path 再返回,
对外 URL 不变;历史本地文件一律作废,不做回退兼容
- ConfigProperties 增加 storage 配置块,endpoint/access-key/secret-key 支持环境变量覆盖
(RUSTFS_ENDPOINT / RUSTFS_ACCESS_KEY / RUSTFS_SECRET_KEY),配置非法时启动即失败
- FileRecordService.deleteFileAsync 改为按 path 删除,本地与对象存储同时清理
- pom 固定 okhttp3.version=4.12.0、kotlin.version=1.9.25:Spring Boot 2.5.4 默认的
okhttp 3.14.9 与 minio 所需的 okhttp 4.12.0 冲突,会导致启动即
NoClassDefFoundError: okhttp3/ConnectionPool
同时修正文件外链拼接(以下均为改造前就存在的问题):
- application-prod.yml:server-url / file-server 由失效的 tuanwei-api.gxwebsoft.com
改为生产实际域名 https://twai-api.gxmu.edu.cn(与 admin .env.production、
uniapp request.js 一致),此前上传返回的 url 指向旧域名导致访问不到
- FileController 抽出 fileBaseUrl(),分页/列表原来漏了 /api/file 前缀
- OpenFileController 同样补 /api/open/file 前缀
- TzbcyMaterialServiceImpl 下载链接补 /api/file/download
|
2026-10-21 23:11:45 +08:00 |
|
weicw-dshsa
|
bf6813e71d
|
feat(ai): 聊天 WebSocket 加 /api 端点与心跳,WS 不可用时退到 HTTP SSE
生产网关在 /api 前丢掉 Upgrade 头,wss://…/chat/{userId} 到不了后端,
端上一直卡在「正在建立 WebSocket 连接…」。
- 新增 ApiChatWebSocketServer(/api/chat/{userId}),与老端点共用会话表;
会话表改存 Session 而不是端点实例,两条路径都能收到推送
- 登记会话时关闭空闲超时(Tomcat 默认 20s,AI 首字慢时会被掐断),
并补 @OnMessage 丢弃心跳(缺了它容器会因不支持的文本帧直接断连)
- send() 找不到 WS 会话时改投 ChatStreamRegistry,把帧送到 HTTP SSE 连接,
推送侧仍只有 sendMessage 一个入口,三千多次调用点不用改
- prod 放开 com.gxwebsoft.ai.config 到 INFO:只保留连接/断开,推送路径仍静默
- 补 ChatStreamRegistryTest / WebSocketEndpointPathTest / AiControllerSseFrameTest
顺带补上 31eb75c 漏加的 ChatStreamRegistry.java:AiController 已经 import 它,
缺文件时 HEAD 编译不过。
|
2026-10-21 19:18:02 +08:00 |
|
weicw-dshsa
|
31eb75cdad
|
fix(ai): 创意助手繁忙归类补 503/50508 与流式中断,失败日志保留尾部
线上日志(2026-10-21 18:10/18:50)显示失败节点已从出图节点移到最前面的
「问题分类器」(SiliconFlow):503 code 50508 System is too busy,以及
requests/urllib3 read_chunked 流式读取中断。旧归类只认 50500,用户看到的是
「生成失败」而不是「生成服务繁忙」;且 briefUpstreamError 只留头部,
Python traceback 的异常类型在尾部被截掉。
- isUpstreamCapacityFailure 增补 50508 / 503 / 流式中断等模式
- briefUpstreamError 改为头 2/3 + 标记 + 尾 1/3(仍单行、仍 <900 字符)
- buildCreativeAssistantResult 在成功但无可展示内容时记 WARN(含 outputKeys
与 photo_files 条数),让解析兜底路径下一次可诊断
- 新增 AiCreativeBusyClassificationTest(6 条)
issue 19;不恢复自动重试。
|
2026-10-21 19:09:03 +08:00 |
|
weicw-dshsa
|
f4590001d8
|
feat(ai): 创意助手出图链路收口——去重试、图片模式包装提示词、输出形状兼容(issue 19)
- 删除 CREATIVE_ASSISTANT_MAX_RETRY / executeCreativeAssistantWithRetry /
isRetryableCreativeFailure,失败即失败;日志仍带 failedNode 与上游 error。
- 图片模式(mode=image)把 user_content 包装成「【任务类型】生成图片…」意图声明,
避免上游「问题分类器」把画面描述判成文案/脚本分支;不带 mode 的入口保持原话直送。
- outputs 形状兼容:image7 这类数组里的 markdown 图片按内容归一到 photo_files
({url,name,type}),findTextValue 支持 List 中的图片字符串;raw 保持上游原样。
- 测试:新增 AiCreativeNoRetryIntegrationTest(2)、AiCreativeImagePromptTest(4)、
AiCreativeImageOutputTest(5),删除两个重试用例;全量 148 跑 0 failures。
|
2026-10-21 15:42:54 +08:00 |
|
weicw-dshsa
|
42655ecd83
|
chore(build): 用 .sdkmanrc 固定 JDK 8 与 Maven 3.9.16
父 POM 管的 lombok 1.18.20 不支持 JDK 17,而本机 sdkman 全局默认是 java 17.0.20-tem,编译必然失败。按项目固定工具链,不改 sdk default。
|
2026-10-21 12:40:13 +08:00 |
|
weicw-dshsa
|
aed2870b27
|
chore(dev): 开发环境 Dify 指向公网演示实例
只覆盖 dify.base-url,dify.apps / dataset / workflows 仍取 application.yml 默认值,避免两份配置漂移。base-url 必须带 /v1(/v1/parameters 返回缺 Bearer 的 401 JSON,/parameters 返回控制台 404)。演示实例与内网实例共用同一批应用 Key 与知识库。
|
2026-10-21 12:40:13 +08:00 |
|
weicw-dshsa
|
1b61fe5586
|
feat(ai): 自由模式转创意助手,失败日志补失败节点与上游 error(issue 17 / 18)
自由模式(issue 18):
- docType 为空时不调「内容创作与宣传助手」——它开始节点的 doc_type 是必填 select,
空值直接被上游判 failed(error="doc_type is required in input form")。改为转
「AI 创意助手」,只发它唯一的必填入参 user_content。
- ManuscriptGenInputs 增加 userContent;doc_type / Number 仍无条件带键(空串能过
Dify 的必填校验,缺键不行)。
- 用例:AiManuscriptFreeModeRouteTest、AiManuscriptInputsContractTest。
失败日志(issue 17):
- 稿件流程、大纲流程、executeWorkflowForResult 三处失败日志补 status + failedNode +
upstreamError + elapsed。失败信息拆在 node_finished 与 workflow_finished 两类事件,
入参校验类失败只有后者,只取节点事件等于没取。
- 补 event=error 与「静默断流」(没有 workflow_finished / message_end)的日志,
两者都带 taskId,可与请求对上。
- 日志级用 error 而非 warn:生产 com.gxwebsoft 只开 ERROR。
- 用例:AiWorkflowFailureDetailTest。
|
2026-10-21 12:40:05 +08:00 |
|
weicw-dshsa
|
9e20014cd6
|
fix(cms): 分类写入前校验上级分类,拦截自引用与成环
分类是自关联结构,一旦出现「自己指向自己」或「祖先指向后代」的环,前端构建分类树时
会直接抛错,导致整个页面无法渲染(报 data error: {categoryId: x, parentId: x})。
- ArticleCategoryService 新增 checkParentValid:顶级分类放行;修改时沿父级链向上回溯,
父级链中不允许出现自己;带回溯深度上限兜底,避免历史脏数据造成死循环。
- Controller 的保存与更新入口都调用该校验,不通过时抛 BusinessException(中文提示)。
注:本提交同时包含这三个文件的整体重新格式化(忽略空白后实际逻辑改动为 52 行插入)。
|
2026-10-13 20:00:25 +08:00 |
|
weicw-dshsa
|
21e49c6a1a
|
fix(ai): WebSocket 推送静默化,并补重试与静默推送用例(issue 11 / 12)
- WebSocketServer.sendMessage 里两行 System.out.println 删除。该方法被**每个 SSE
事件**调用一次(大纲单次生成实测 3062 个事件,即一次请求刷 6000+ 行),而且绕过
日志框架——既不受 logging.level 控制(生产把 com.gxwebsoft 压到 ERROR 也拦不住),
也不进日志文件,真故障时需要的几行会被顶掉。日志改到低频的 onOpen / onClose;
同时把 onOpen 里静默吞掉的握手回应异常改成 WARN(那是「连上了却收不到内容」的
第一现场)。
- 新增用例:AiCreativeRetryTest、AiCreativeRetryIntegrationTest(issue 11,
后者用本地 HTTP server 扮演 Dify,断言瞬时故障确实重跑一次、凭证失效只请求一次)、
WebSocketServerSilentPushTest(issue 12,捕获 System.out 断言推送路径零输出)。
|
2026-10-13 20:00:01 +08:00 |
|
weicw-dshsa
|
8406c90cf3
|
fix(ai): 文件上传按应用选择凭证;并入创意助手重试与失败日志(issue 11 / 14)
同一文件内包含两块内容,无法拆分提交:
一、文件上传按应用选择凭证(issue 14,本次)
Dify 的 /files/upload 是按应用鉴权的:实测同一张图、同一个 end user 下,chat Key
上传得到的 file id 喂给创意助手工作流的 file-list 变量,0.2 秒即报
Invalid upload file;用 creativeAssistant Key 上传的同一文件则 succeeded。
而原实现只有两个分支(type 为空/0 用 chat,否则用 manuscript),从不使用创意助手
的 Key,因此任何喂给创意助手的附件都必然失败 —— views/gxmu/creativeAssistant 表单页
用的是同一个接口,它的附件功能同样是坏的(既有缺陷)。
新增 app 参数按应用代号取凭证(复用 DifyProperties.AppKeys#byCode),不传时保持既有
行为;未知代号回退旧逻辑并打 WARN。新增 resolveUploadToken。
二、创意助手出图失败的重试与可观测(issue 11,前次会话已完成验收、此前未提交)
executeCreativeAssistantWithRetry / runCreativeAssistantOnce / CreativeRun /
CreativeApiFailureException / creativeFailureReason / creativeFailureAnswer /
isUpstreamCapacityFailure / isRetryableCreativeFailure / briefUpstreamError:
上游 50500 算力不足时自动重跑一次,凭证失效、模型停用等不重试;每次失败按 ERROR
打结构化日志(含失败节点名与上游原文截断)。
|
2026-10-13 19:57:41 +08:00 |
|