Просмотр исходного кода

chore: auto bump version and changelog [skip ci]

iwt 2 недель назад
Родитель
Сommit
cb80facd83

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-9c4965741a4c3735f3add974cf476f69c2e31bd1
+4dd215e397c363357dfdad620dad639aadd150e5

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1798",
+  "version": "1.0.1799",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.1798",
+      "version": "1.0.1799",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.1799",
+  "version": "1.0.1800",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 268 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,274 @@
 
 ---
 
+## v1.0.1800 (2026-10-26)
+
+### 样式
+- U3 小程序圆角收敛为 4 档(8/16/24/999rpx)
+- U4 30rpx 间距令牌归并(安全边距→$uni-space-page / 内部间距→$uni-space-lg/xl)
+- U5 收敛五维色映射到 colorTokens.js 单一出口,去除 #1677FF 硬编码
+- U6 后台间距令牌归并——teacher 全目录 + OrderManage + Dashboard 裸写 px → var(--spacing-*)
+
+### 其他
+- - 任务书字面映射:4/6/10rpx→8rpx、12rpx→16rpx、16rpx 保留、20rpx→24rpx、24rpx 保留、40/44rpx→24rpx;9999rpx→999rpx(全圆角哨兵值规范化)
+- - 主理人批准的就近档扩展:1-11rpx→8rpx、12-18rpx→16rpx、>=20rpx→24rpx
+- - 改动 1564 处 / 334 文件;rpx 数值种类 37 种 → 4 种(8/16/24/999)
+- - 保留:50%/circle/999rpx/0/px 值、var(--radius-*) 回退与 $uni-radius-* 令牌引用
+- - uni.scss 已有 $uni-radius-* 令牌,按任务书「不得改动令牌值」未改;common/uni.css 全局基线未改
+- - 仅样式变更,无逻辑/接口/数据结构改动;无 DB 迁移
+- 
+- 三表数据回填成非空 List,触发 updateReportFromPayload 三个「先删后插」块;而这三处
+- insert 从不 set collectionDate / description / relatedBacteria → 老报告(无 payload_json)
+- 只想改个日期,却把三列存量数据永久清掉。
+- 修复:发送日期专用最小 payload {type, summary:{reportDate}},刻意不带那三个键。
+- 后端对缺键已有 instanceof List 保护,缺键即整块跳过「先删后插」→ 三张明细表零 SQL。
+- summary 复制一份再覆盖 reportDate:payload.summary 与编辑态日期输入框 v-model 双向
+- 绑定,直接改会把未保存/已失败的日期写进组件状态。
+- updateReportFromPayload 缺键审计(payload 只含 {type, summary} 时逐处取值):
+- | 位置      | 取值                              | 行为                                                | 结论 |
+- | L1817     | payload.get("summary")            | 是 Map → scoreSource = summary                       | 安全 |
+- | L1822-39  | scoreSource.get(10 个分数键)      | 缺失→null→toInteger→null→setter 有 !=null 守卫      | 不写空值 |
+- | L1840     | scoreSource.get("shannonIndex")   | null → 跳过                                          | 安全 |
+- | L1847     | scoreSource.get("reportDate")     | 有值→严格解析;非法/未来抛 IllegalArgumentException  | 正常 |
+- | L1869     | payload.get("indicators")         | null → 非 List → 跳过 delete+insert                  | 零 SQL |
+- | L1893     | payload.get("gutFlora")           | null → 跳过                                          | 零 SQL |
+- | L1919     | payload.get("diseaseRisks")       | null → 跳过                                          | 零 SQL |
+- | L1990     | writeValueAsString(payload)       | payload_json 快照覆写为最小 payload(health_report 单行 UPDATE) | 观察项* |
+- | L2010/20  | reportBlockAssembler.fromMap()    | 只读 summary+diseaseRisks,toInt/str 均 null 安全    | 不 NPE |
+- | L2022     | normalizeIndicatorPipeline        | indicators/gutFlora 为 null → 循环不执行(只 upsert,从不 delete) | 零 SQL |
+- scoreSource 结论:summary 存在时从 summary 取分数;最小 payload 的 summary 只覆盖
+- reportDate、沿用原有分数键 → 分数保留,缺失键返回 null 且全部有守卫,不会 NPE、
+- 不会误删、不会误写空值。
+- 实测(临时单测 TempDateOnlyPayloadAuditTest,跑完即删不提交,2 项 PASS):
+- 1) 最小 payload → healthIndicator/GutFlora/DiseaseRisk 三个 mapper 的 delete 与 insert
+-    均 never 被调用(一条 SQL 都不执行),overallScore=88 保留,reportDate 正确更新;
+- 2) 反向对照 → payload 带上那三个键(哪怕空 List)时 delete 必然被调用,
+-    证明零风险来自「缺键即跳过」而非其它巧合。
+- 观察项*:step6 会把 health_report.payload_json 覆写为只含 summary 的最小快照;
+- step7 从 fromMap 结果重装 report_blocks(fromMap 本就不读 indicators/gutFlora,属 edit
+- 流既有行为;最小 payload 无分数时 blocks 为空 → reportBlockService.save 空列表早退,
+- 老报告 report_blocks 保持不变)。二者均为 updateReportFromPayload 对「提交了什么
+- payload」的既有处理,本次不改后端,对三张明细表无任何 SQL。
+- 附:lastDetail 仍由 loadData 缓存,本次不再用于回填,未删除以免扩大改动面。
+- 
+- 根因:api.js 的 request() 封装在 res.data.code !== 200 时,已先
+- uni.showToast(res.data.message) 再 reject(res.data)。随后 catch 又弹「保存失败」/
+- 「保存异常」——uni-app 的 showToast 不排队,后者替换前者,用户永远看不到
+- 「报告日期格式应为 yyyy-MM-dd,当前值:xxx」「报告日期不能晚于今天,当前值:xxx」
+- 这类后端原因(P1-1 原实现声称的非 200 直出 res.message 实际是死代码:
+- /report/edit 不返回 5001,封装层对非 200 一律 reject,.then 只会拿到 200)。
+- 修复:
+- 1) submitDateChange 删除 .then() 内不可达的 else 分支。
+- 2) 两个 catch 统一改为以 err.message 为准:先 hideLoading,再重放同一条后端原文;
+-    仅当 reject 的对象没有 message(网络异常等非业务错误)时才兜底弹一次通用提示。
+-    关键:微信小程序 showToast 与 showLoading 共用同一组件(官方文档:二者同时只能
+-    显示一个),hideLoading 会把封装层刚弹的那条提示一并隐藏。所以不能写成「只
+-    hideLoading、不再弹」——那样微信端会一条提示都不剩,反而吞错;重放同一文案在
+-    小程序与 H5 上表现一致,且不改变接口契约与数据结构。
+- 影响面:仅 report-detail.vue 的 saveEdit / submitDateChange 两处失败提示。
+- 
+- 规则执行:
+- - 页面安全边距(四向 padding:30rpx / padding 简写左右对称 / 同规则内 padding-left+right 对称)→ $uni-space-page(值不变,仅补令牌语义)
+- - 内部间距(margin/gap、padding 非对称 slot)→ $uni-space-lg (24rpx)
+- - 明显区块大间距(页面级 section/group/timeline/list 容器的纵向 margin)→ $uni-space-xl (32rpx)
+- - 本批只处理 spacing 上下文 30rpx,不扩散到 font-size/border-radius 等其他裸值;不改动 admin-tokens.css / uni.scss 既有令牌值
+- 跳过清单(5 文件):style 块未标 lang=scss,无法引用 uni.scss 令牌,保留原样待人工复核:
+-   pages/mind-detail/innate-trajectory.vue / training.vue / member-mind-detail.vue
+-   components/BaseEmpty.vue / PageBanner.vue
+-   (其中 BaseEmpty.vue 无 spacing 命中,PageBanner.vue 命中 1 处 padding:24rpx 30rpx)
+- 补充:pages/energy/index.vue 的 .picker-item.active 单行内同时出现 margin:0 -30rpx(溢出负边距)
+- 与 padding-left/right: 30rpx 对称声明,脚本按非配对规则落到 $uni-space-lg;已人工修正为
+- $uni-space-page,保证负边距与对称内边距继续对齐(值均 30rpx,未改数值)。
+- 基线 → 改后(grep 实测):
+-   总字面 30rpx occurrences: 1380 → 461(-66.6%;剩余全部为 font-size/border-radius 等非 spacing
+-   裸值,属字号/圆角后续批次的处理范围,本批按纪律不扩散)
+-   任务书口径“padding/margin: 30rpx 前导值”(492 处): 492 → 2(2 处在跳过文件)
+-   $uni-space-page 替换: 463 次
+-   $uni-space-lg 替换: 451 次
+-   $uni-space-xl 替换: 5 次
+-   变动文件数: 256(仅 cfc-frontend/pages/ + cfc-frontend/components/)
+- 编译验证:
+-   mvn -pl cfc-backend -am compile: BUILD SUCCESS(本批未改后端,仅走纪律门禁)
+-   cfc-web vue-cli-service build: DONE(本批未改 cfc-web,仅走纪律门禁)
+-   cfc-frontend node scripts/verify-vue-compile.js: 模板 386 / 样式 386,与 baseline 一致
+-   cfc-frontend node scripts/audit-mp-antipatterns.js: ERROR 0(未引入新反模式)
+-   git diff 行对语义对齐检查: 891 对行全部为 spacing-only 变更,无逻辑/非间距改动
+- 
+-   adminColor()(getComputedStyle 读 --adm-primary,供 canvas/echarts 使用)+ dimensionColor()
+- - DimensionWeightPicker / EnergyBehaviorConfig / ProfileManagement 的重复五维映射改引单一出口
+- - admin/Dashboard、admin/org/Dashboard 的 echarts itemStyle.color 与 color 数组改走 adminColor()/DIMENSION_COLORS
+- - EnergySandbox el-tag color prop 改 class 绑定 .tag-score-primary 走 var(--adm-primary)
+- - TeacherTeam 等级头像色、MbtiProfiles 页头图标色改走令牌
+- - 注释里的色值与 admin-tokens.css 令牌定义均未改动
+- 
+- 范围:cfc-web/src/views/teacher/(10 个 .vue)+ src/views/admin/OrderManage.vue + src/views/admin/Dashboard.vue
+- 改动:
+- - padding/margin 裸写 px 归并到既有令牌 var(--spacing-*):
+-   8→sm / 12→md / 16→base / 20→lg / 24→lg / 32→xxl(刻度 8/12/16/20/24/32 就近匹配,20px 优先对齐 24px 规范方向)
+- - 65 处声明、69 个 px 值替换为令牌引用
+- - 本批 padding/margin 裸写 px:87 → 29(-66.7%)
+- - 全库 var(-- 引用率(.vue 口径,审计基线 21.9%):22.02% → 24.10%
+- 未动:admin-tokens.css 与 uni.scss 令牌定义/值;border-radius / font-size / width / height / line-height /
+- top / left;非候选刻度(2/4/6/10/14/15/48px)按 U6 范围外保留(逐条清单见回报报告)。
+- 验证:
+- - cfc-backend mvn clean compile → BUILD SUCCESS(1948 源文件)
+- - cfc-web npm run build → DONE Build complete(85s;dist CSS 中 85 处 var(--spacing-*) 生效)
+- - lint 不可用:package.json 无 lint script、未安装 @vue/cli-plugin-eslint(vue-cli-service lint: command does not exist)
+- 
+-   DAN 报告走 /api/dan-report 独立存储与接口,不在 /report/edit 编辑范围)
+- - 新增内联日期编辑行(text input + 取消/保存,格式 yyyy-MM-dd)
+- - submitDateChange:复用 editHealthReport(reportId, payload, subjectId) 提交,
+-   仅覆盖 payload.summary.reportDate;保存前用 detail 接口返回的 indicators/gutFlora/diseaseRisks
+-   回填空 payload,避免老报告无 payload_json 快照时只改日期却清空指标
+- - 非 200 直接展示后端 res.message(不吞错误,不弹「已保存」);成功后 toast「已保存」+ loadData() 重载
+- - headInfo.reportDateText 改用 formatDate(原 parseDate 把 Date 对象直接渲染进模板,
+-   违反项目时间显示规范 yyyy-MM-dd),新增 headInfo.reportDate 供编辑回填
+- - 未做 gut-flora-detail.vue / report-result.vue 的日期入口(设计文档 §5 P1-2 范围外)
+- 校验:vue-template-compiler 模板 PASS / dart-sass 样式 PASS / node --check 脚本 PASS
+-       audit-mp-antipatterns ERROR 0 / audit-duplicate-api-calls 0 error
+- 
+-   解析失败抛 IllegalArgumentException(GlobalExceptionHandler 转 400 + 明确提示),不再静默吞错
+- - 未来日期拦截:parsedDate.after(now) 拒绝,当天允许
+- - 记录 reportDateChanged 标记,改日期后补调 refreshMemberIndicatorCurrent(subjectId, reportId)
+-   刷新 member_indicator_current 快照(改日期改变 report_date 排序,需重定位上一期)
+- - date_source 标记:columnExists(indicator_values, date_source) 兜底判断,列存在则 UPDATE report 时序行为 real,
+-   列不存在(T01 迁移未落地)整段跳过并 log.info 说明原因,不崩不报错
+- - 幂等性未破:oldReport.reportDate 先改再走 normalizeIndicatorPipeline.processReport,
+-   upsert SQL 含 report_date = VALUES(report_date),时序日期自动同步
+- - 新增私有 columnExists 辅助(参照 DatabaseInitializer 实现)
+- 设计文档:docs/superpowers/specs/2026-10-26-report-date-editable-design.md §3.2
+- mvn -o compile EXIT_CODE=0
+- 
+- - 出参含 eligible / dateFixable / skippedNoSubject / skippedNoPayload / written / details
+- - admin 角色校验,默认 dryRun=true
+- 
+- - parseRefRange/judgeInRange:参考范围解析与 in_range_is_better 四分支
+- - computeChange:Δ/Δ%、微小基数护栏(refHigh×1%)、2% 持平阈值、五值 trendCode
+- - 单测 23 例覆盖解析/判定/护栏/单位/非数值/无上一期两档
+- 
+- - HealthReportController.confirmDraft: createReport 后补写统一指标层时序
+- - 两处均 try/catch,失败不阻断主流程;底层 upsert 幂等
+- 
+- - upsertMapping 的 INSERT 与 ON DUPLICATE 子句同步 2 列
+- - NormalizeIndicatorPipeline 写入日期来源标记与参考范围快照
+- - HealthIndicator.collectionDate 移除 @TableField(exist=false)(前置列存在性兜底已在迁移422)
+- 
+- - 迁移422 前置: health_indicators.collection_date 存在性兜底(放开实体映射前必须先行)
+- - 迁移423: 新建 body_fat_scale_records 表
+- - schema.sql 同步以上 DDL
+- 
+- - mini-app .vue (pages+components): 家长->本人/家庭成员, 孩子->家庭成员/儿童,
+-   age-context 成人/儿童/长者; comments included. Excluded (whitelist, A2):
+-   pages/activity/create.vue + activity-detail.vue (activity pricing UI).
+- - backend user-visible strings: toast/Result messages, @Operation/@Tag,
+-   message templates, AI prompts (application.yml, cognitive-recommendations.yml),
+-   seed copy (seed-test-data.sql, mbti_seed_data.sql, schema_service_guide.sql),
+-   comment/log wording swept for grep cleanliness.
+- - no DB column comments, no API paths, no page dirs, no Java identifiers changed.
+- - skipped (A2 parallel): Activity.java, ActivityDTO.java, ActivityOrderService.java,
+-   DatabaseInitializer.java (66 lines), schema.sql (45 lines).
+- verify: mvn compile EXIT=0; node scripts/verify-vue-compile.js PASS (385/385/385).
+- 
+- 后端
+- - 迁移421: activities 新增 audience_scope(all/member_only) / audience_type
+-   (adult/include_child/include_elder/include_child_elder) 两列,
+-   information_schema 存在性检查 + AFTER visible_to 列定位,幂等;schema.sql 同步。
+- - Activity/ActivityDTO 新增 audienceScope/audienceType 字段与映射。
+- - ActivityDTO 新增 basePrice(原始普通价):price 已被 resolveMemberPrice
+-   替换成会员价,编辑表单回填必须用原始值,否则会员编辑会把会员价写成普通价。
+- - ActivityOrderService 结算按参与者身份分类:
+-   self(未关联成员)/child(age<18)/elder(age>=60)/adult(其他成年家庭成员),
+-   废弃「memberId 非空即孩子」旧语义;批量预取年龄避免 N+1。
+- - 成人档 price>0 ? price : parentFee;会员档区分 memberPrice NULL(存量别名)
+-   vs 0(新模型同普通价),parentMemberFee=0 的存量免费语义原样保留。
+- - audience_scope=member_only 后端硬门禁:非登录引导登录、非会员拒绝,
+-   范式对齐 TaskController.checkMemberOnly。
+- 前端(create.vue 仅【费用与适用人群区块】)
+- - 参加范围单选 + 参与人群多选(成人恒选,含儿童/含长者)
+- - 价格/会员价恒显输入;儿童两档仅在勾选「含儿童」时显示
+- - 不再提交 parentFee/parentMemberFee(历史别名);存量收费不误清零
+- - 保留 A1 已提交的 multiSelector 时间选择器代码,未改动
+- 测试:ActivityOrderServiceTest(15) + ActivityDTOTest(3),18 例全绿
+- 
+- - 新增 cfc-frontend/utils/activity-fee.js:统一 audienceScope/audienceType 归一化与成人/儿童/长者档位取价
+-   (长者复用成人价,D1 不新增长者价格列;parentFee/parentMemberFee 作为成人非会员价历史别名回落,A2 §2.4)
+- - activity-detail.vue:费用区按 audienceType 条件渲染「成人/儿童/长者」(成人恒显;儿童/长者需含该人群且对应价格 > 0);
+-   海报价格文案按 audienceType 选「(成人)/(儿童)/(长者)」,不再出现「家长」「孩子」;
+-   hasFee / hasMemberPrice 纳入 price / memberPrice(修复只填成人价的付费活动误显「免费」的真实 bug);
+-   minFeeText 改为当前用户可用档位的最小值(会员用会员价列、非会员用非会员价列);
+-   报名弹窗为每个报名人展示身份标签(成人/儿童/长者)与对应单价,合计同步按身份口径估算
+- - index.vue:normalizeRegistration 不再用 4 个 child/parent 费用的最小值覆盖 price,仅 price 为空时回落 parentFee;
+-   列表卡片的 hasFee / minFee 同步纳入成人档
+- - cfc-web ActivityEdit.vue:价格区之后追加适用人群(单选)与参与人群(多选),勾选「含儿童」时条件显示儿童两档费用;
+-   读写字段名对齐 A2 的 DTO(audienceScope / audienceType + childFee / childMemberFee),与小程序保存口径一致
+- 范围说明:A2 的数据层(audience_scope / audience_type 列、实体与 DTO)与结算逻辑不在本任务范围;
+- audienceScope / audienceType 需 A2 合入后才能落库与回显,本分支前端已按 A2 契约对齐并对字段缺失做了降级。
+- 
+- - 3 处 <picker mode=time> 改为原生 multiSelector 双列:时 24 项 00..23,分 12 项 00/05/.../55,
+-   5 分钟粒度在选择过程中即生效,用户无法选中非 5 倍数分钟,不再出现选了 07 分却变 05 分
+- - 删除 3 处 picker-hint 提示文案「以 5 分钟为一个单元(如 14:00、14:05)」及对应 CSS 注释/样式
+- - data 新增 hourOptions/minuteOptions 与 3 组时/分索引;新增 applyTimeParts 统一做索引↔字符串双向同步
+- - 新增 onStartTimeColChange/onEndTimeColChange/onRegTimeColChange;日期逻辑与 syncXxx 组装逻辑不变
+- - 回填路径 fmtTime/loadDetail 归一化后反算分钟索引,picker 显示与提交值一致(14:07 → 显示与提交均为 14:05)
+- - normalizeTimeTo5Min 保留为兜底(历史脏数据/后台写入非 5 倍数仍收敛),提交串恒为 YYYY-MM-DDTHH:mm:00
+- 
+-   ArticleEdit/ActivityEdit/ProductEdit/HomeBannerManage/ProductSkuEditor/
+-   GuidePackages/KnowledgeDialog 的接入方式,以及 Activities/ArticleManage/
+-   SupplierProductManage/RecommendationRules/IndicatorMappings 等无上传控件页面、
+-   ProxyReportUpload 等报告解析专用端点页面的跳过原因
+- - 标注旧端点 /api/admin/articles/upload/image|video 保留兼容
+- - PROJECT-OVERVIEW.md 同步(版本号口径、接入页面清单含 GuidePackages 与拖拽上传)
+- 
+- - editorAssetUpload.js:getEditorCustomAlert 改为具名导出,修复 3 个 wangEditor 页面 import 告警
+- 
+-   抽出 uploadAndSelect 统一点击与拖拽两条路径的上传入库+自动选中逻辑,
+-   增加拖拽态高亮与「点击或拖拽文件到此处」提示
+- - GuidePackages: 封面图上传端点由失效的 /api/upload(无鉴权、后端无此路由)
+-   改为 /api/admin/file-record/upload(Bearer + category=guide-packages),
+-   修正 handleUploadSuccess 取 res.data.url,并接入「从素材库选择」AssetPicker
+- - 回填脚本: file_type 回填的 WHERE 条件与注释声明的意图对齐
+-   (排除与目标值相同的行,避免无意义行更新)
+- 
+- - 新增 components/AssetPicker.vue(图片/视频/文档三类筛选 + 上传入库 + 标签筛选 + 单选/多选)
+- - 新增 views/admin/AssetLibrary.vue(网格卡片 + 类型/分类/标签/关键词/日期筛选 + 批量打标签/删除 + 改描述 + 预览 + 标签管理 + 统计);router 注册 admin/asset-library,Layout 加菜单与缓存页
+- - ArticleEdit / ActivityEdit / ProductEdit / ProductSkuEditor / HomeBannerManage / KnowledgeDialog 接入「从素材库选择」与 /api/admin/file-record/upload
+- - HomeBannerManage 修复重复 beforeUpload 导致封面图永远无法上传的缺陷;FileManage 类型口径 pdf → document
+- 
+- - JdCloudStorageService 存量写入回填 file_type;LocalDiskStorageService 本地模式实现 storeFileRecord
+- - 新增 FileRecordService 业务层(分页/标签/描述/统计),Controller 不直接触碰 Mapper
+- - FileRecordController 重写:/upload(微信图片内容安全校验 fail-open + 标签关联 + 去重命中补标签)、/list(tagIds 前置过滤保证 total)、/update、/delete、/tags、/tag/create|update|delete、/stats,统一 admin 角色守卫
+- - schema.sql file_type 注释口径统一;新增 docs/migrations/20261025_asset_library_file_type_backfill.sql(存量回填,严格按 content_type,不占迁移编号)
+- - API_REFERENCE.md §4.56 + PROJECT-OVERVIEW.md v2.22 同步文档
+- 
+
+### Bug 修复
+- P1-1 报告日期可修改·前端修复2 - 日期改用最小 payload,杜绝三表存量列被清
+- P1-1 报告日期可修改·前端修复1 - 保存失败不再覆盖后端明确原因
+- 修复 G3 事后绑定成员不补时序 + confirm 链路补写
+
+### 新功能
+- P1-1 报告日期可修改·前端 - report-detail 查看态日期修改入口
+- P1-1 报告日期可修改·后端 - 严格解析+未来日期拦截,日期变更联动快照刷新与 date_source 兜底
+- 新增 /api/admin/indicator/backfill 回填端点(dryRun 优先)
+- 新增 IndicatorChangeService 变化计算底座 + 单测
+- 指标值落库补日期来源/参考范围快照,放开 collection_date 映射
+- 迁移422/423 指标多期展示数据地基
+- A2 活动适用人群 + 费用模型重构
+- A3 活动费用展示层口径统一(成人/儿童/长者 × 会员/非会员 + 适用人群)
+- A1 创建活动页时间选择器改为 5 分钟粒度双列 picker
+- F-8 清理收尾-三套旧账本写接口410Gone+补CF值单一事实源文档
+- 成长规划师任务模板封面接入素材库 + 补 getEditorCustomAlert 具名导出
+- 素材库补齐拖拽上传与任务模板封面入库
+- 后台素材库前端 — AssetLibrary 页 + AssetPicker 组件 + 上传点改造
+- 后台素材库后端 — file-record 上传/检索/标签CRUD/统计
+
+### 重构
+- neutralize parent/child wording in user-visible copy
+
+### 文档
+- 素材库补充上传点接入范围与跳过说明
+
+
 ## v1.0.1799 (2026-10-26)
 
 ### Bug 修复

+ 269 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.1799
+> 当前版本: v1.0.1800
 
 ## 历史版本
 
@@ -8,6 +8,274 @@
 
 ---
 
+## v1.0.1800 (2026-10-26)
+
+### 样式
+- U3 小程序圆角收敛为 4 档(8/16/24/999rpx)
+- U4 30rpx 间距令牌归并(安全边距→$uni-space-page / 内部间距→$uni-space-lg/xl)
+- U5 收敛五维色映射到 colorTokens.js 单一出口,去除 #1677FF 硬编码
+- U6 后台间距令牌归并——teacher 全目录 + OrderManage + Dashboard 裸写 px → var(--spacing-*)
+
+### 其他
+- - 任务书字面映射:4/6/10rpx→8rpx、12rpx→16rpx、16rpx 保留、20rpx→24rpx、24rpx 保留、40/44rpx→24rpx;9999rpx→999rpx(全圆角哨兵值规范化)
+- - 主理人批准的就近档扩展:1-11rpx→8rpx、12-18rpx→16rpx、>=20rpx→24rpx
+- - 改动 1564 处 / 334 文件;rpx 数值种类 37 种 → 4 种(8/16/24/999)
+- - 保留:50%/circle/999rpx/0/px 值、var(--radius-*) 回退与 $uni-radius-* 令牌引用
+- - uni.scss 已有 $uni-radius-* 令牌,按任务书「不得改动令牌值」未改;common/uni.css 全局基线未改
+- - 仅样式变更,无逻辑/接口/数据结构改动;无 DB 迁移
+- 
+- 三表数据回填成非空 List,触发 updateReportFromPayload 三个「先删后插」块;而这三处
+- insert 从不 set collectionDate / description / relatedBacteria → 老报告(无 payload_json)
+- 只想改个日期,却把三列存量数据永久清掉。
+- 修复:发送日期专用最小 payload {type, summary:{reportDate}},刻意不带那三个键。
+- 后端对缺键已有 instanceof List 保护,缺键即整块跳过「先删后插」→ 三张明细表零 SQL。
+- summary 复制一份再覆盖 reportDate:payload.summary 与编辑态日期输入框 v-model 双向
+- 绑定,直接改会把未保存/已失败的日期写进组件状态。
+- updateReportFromPayload 缺键审计(payload 只含 {type, summary} 时逐处取值):
+- | 位置      | 取值                              | 行为                                                | 结论 |
+- | L1817     | payload.get("summary")            | 是 Map → scoreSource = summary                       | 安全 |
+- | L1822-39  | scoreSource.get(10 个分数键)      | 缺失→null→toInteger→null→setter 有 !=null 守卫      | 不写空值 |
+- | L1840     | scoreSource.get("shannonIndex")   | null → 跳过                                          | 安全 |
+- | L1847     | scoreSource.get("reportDate")     | 有值→严格解析;非法/未来抛 IllegalArgumentException  | 正常 |
+- | L1869     | payload.get("indicators")         | null → 非 List → 跳过 delete+insert                  | 零 SQL |
+- | L1893     | payload.get("gutFlora")           | null → 跳过                                          | 零 SQL |
+- | L1919     | payload.get("diseaseRisks")       | null → 跳过                                          | 零 SQL |
+- | L1990     | writeValueAsString(payload)       | payload_json 快照覆写为最小 payload(health_report 单行 UPDATE) | 观察项* |
+- | L2010/20  | reportBlockAssembler.fromMap()    | 只读 summary+diseaseRisks,toInt/str 均 null 安全    | 不 NPE |
+- | L2022     | normalizeIndicatorPipeline        | indicators/gutFlora 为 null → 循环不执行(只 upsert,从不 delete) | 零 SQL |
+- scoreSource 结论:summary 存在时从 summary 取分数;最小 payload 的 summary 只覆盖
+- reportDate、沿用原有分数键 → 分数保留,缺失键返回 null 且全部有守卫,不会 NPE、
+- 不会误删、不会误写空值。
+- 实测(临时单测 TempDateOnlyPayloadAuditTest,跑完即删不提交,2 项 PASS):
+- 1) 最小 payload → healthIndicator/GutFlora/DiseaseRisk 三个 mapper 的 delete 与 insert
+-    均 never 被调用(一条 SQL 都不执行),overallScore=88 保留,reportDate 正确更新;
+- 2) 反向对照 → payload 带上那三个键(哪怕空 List)时 delete 必然被调用,
+-    证明零风险来自「缺键即跳过」而非其它巧合。
+- 观察项*:step6 会把 health_report.payload_json 覆写为只含 summary 的最小快照;
+- step7 从 fromMap 结果重装 report_blocks(fromMap 本就不读 indicators/gutFlora,属 edit
+- 流既有行为;最小 payload 无分数时 blocks 为空 → reportBlockService.save 空列表早退,
+- 老报告 report_blocks 保持不变)。二者均为 updateReportFromPayload 对「提交了什么
+- payload」的既有处理,本次不改后端,对三张明细表无任何 SQL。
+- 附:lastDetail 仍由 loadData 缓存,本次不再用于回填,未删除以免扩大改动面。
+- 
+- 根因:api.js 的 request() 封装在 res.data.code !== 200 时,已先
+- uni.showToast(res.data.message) 再 reject(res.data)。随后 catch 又弹「保存失败」/
+- 「保存异常」——uni-app 的 showToast 不排队,后者替换前者,用户永远看不到
+- 「报告日期格式应为 yyyy-MM-dd,当前值:xxx」「报告日期不能晚于今天,当前值:xxx」
+- 这类后端原因(P1-1 原实现声称的非 200 直出 res.message 实际是死代码:
+- /report/edit 不返回 5001,封装层对非 200 一律 reject,.then 只会拿到 200)。
+- 修复:
+- 1) submitDateChange 删除 .then() 内不可达的 else 分支。
+- 2) 两个 catch 统一改为以 err.message 为准:先 hideLoading,再重放同一条后端原文;
+-    仅当 reject 的对象没有 message(网络异常等非业务错误)时才兜底弹一次通用提示。
+-    关键:微信小程序 showToast 与 showLoading 共用同一组件(官方文档:二者同时只能
+-    显示一个),hideLoading 会把封装层刚弹的那条提示一并隐藏。所以不能写成「只
+-    hideLoading、不再弹」——那样微信端会一条提示都不剩,反而吞错;重放同一文案在
+-    小程序与 H5 上表现一致,且不改变接口契约与数据结构。
+- 影响面:仅 report-detail.vue 的 saveEdit / submitDateChange 两处失败提示。
+- 
+- 规则执行:
+- - 页面安全边距(四向 padding:30rpx / padding 简写左右对称 / 同规则内 padding-left+right 对称)→ $uni-space-page(值不变,仅补令牌语义)
+- - 内部间距(margin/gap、padding 非对称 slot)→ $uni-space-lg (24rpx)
+- - 明显区块大间距(页面级 section/group/timeline/list 容器的纵向 margin)→ $uni-space-xl (32rpx)
+- - 本批只处理 spacing 上下文 30rpx,不扩散到 font-size/border-radius 等其他裸值;不改动 admin-tokens.css / uni.scss 既有令牌值
+- 跳过清单(5 文件):style 块未标 lang=scss,无法引用 uni.scss 令牌,保留原样待人工复核:
+-   pages/mind-detail/innate-trajectory.vue / training.vue / member-mind-detail.vue
+-   components/BaseEmpty.vue / PageBanner.vue
+-   (其中 BaseEmpty.vue 无 spacing 命中,PageBanner.vue 命中 1 处 padding:24rpx 30rpx)
+- 补充:pages/energy/index.vue 的 .picker-item.active 单行内同时出现 margin:0 -30rpx(溢出负边距)
+- 与 padding-left/right: 30rpx 对称声明,脚本按非配对规则落到 $uni-space-lg;已人工修正为
+- $uni-space-page,保证负边距与对称内边距继续对齐(值均 30rpx,未改数值)。
+- 基线 → 改后(grep 实测):
+-   总字面 30rpx occurrences: 1380 → 461(-66.6%;剩余全部为 font-size/border-radius 等非 spacing
+-   裸值,属字号/圆角后续批次的处理范围,本批按纪律不扩散)
+-   任务书口径“padding/margin: 30rpx 前导值”(492 处): 492 → 2(2 处在跳过文件)
+-   $uni-space-page 替换: 463 次
+-   $uni-space-lg 替换: 451 次
+-   $uni-space-xl 替换: 5 次
+-   变动文件数: 256(仅 cfc-frontend/pages/ + cfc-frontend/components/)
+- 编译验证:
+-   mvn -pl cfc-backend -am compile: BUILD SUCCESS(本批未改后端,仅走纪律门禁)
+-   cfc-web vue-cli-service build: DONE(本批未改 cfc-web,仅走纪律门禁)
+-   cfc-frontend node scripts/verify-vue-compile.js: 模板 386 / 样式 386,与 baseline 一致
+-   cfc-frontend node scripts/audit-mp-antipatterns.js: ERROR 0(未引入新反模式)
+-   git diff 行对语义对齐检查: 891 对行全部为 spacing-only 变更,无逻辑/非间距改动
+- 
+-   adminColor()(getComputedStyle 读 --adm-primary,供 canvas/echarts 使用)+ dimensionColor()
+- - DimensionWeightPicker / EnergyBehaviorConfig / ProfileManagement 的重复五维映射改引单一出口
+- - admin/Dashboard、admin/org/Dashboard 的 echarts itemStyle.color 与 color 数组改走 adminColor()/DIMENSION_COLORS
+- - EnergySandbox el-tag color prop 改 class 绑定 .tag-score-primary 走 var(--adm-primary)
+- - TeacherTeam 等级头像色、MbtiProfiles 页头图标色改走令牌
+- - 注释里的色值与 admin-tokens.css 令牌定义均未改动
+- 
+- 范围:cfc-web/src/views/teacher/(10 个 .vue)+ src/views/admin/OrderManage.vue + src/views/admin/Dashboard.vue
+- 改动:
+- - padding/margin 裸写 px 归并到既有令牌 var(--spacing-*):
+-   8→sm / 12→md / 16→base / 20→lg / 24→lg / 32→xxl(刻度 8/12/16/20/24/32 就近匹配,20px 优先对齐 24px 规范方向)
+- - 65 处声明、69 个 px 值替换为令牌引用
+- - 本批 padding/margin 裸写 px:87 → 29(-66.7%)
+- - 全库 var(-- 引用率(.vue 口径,审计基线 21.9%):22.02% → 24.10%
+- 未动:admin-tokens.css 与 uni.scss 令牌定义/值;border-radius / font-size / width / height / line-height /
+- top / left;非候选刻度(2/4/6/10/14/15/48px)按 U6 范围外保留(逐条清单见回报报告)。
+- 验证:
+- - cfc-backend mvn clean compile → BUILD SUCCESS(1948 源文件)
+- - cfc-web npm run build → DONE Build complete(85s;dist CSS 中 85 处 var(--spacing-*) 生效)
+- - lint 不可用:package.json 无 lint script、未安装 @vue/cli-plugin-eslint(vue-cli-service lint: command does not exist)
+- 
+-   DAN 报告走 /api/dan-report 独立存储与接口,不在 /report/edit 编辑范围)
+- - 新增内联日期编辑行(text input + 取消/保存,格式 yyyy-MM-dd)
+- - submitDateChange:复用 editHealthReport(reportId, payload, subjectId) 提交,
+-   仅覆盖 payload.summary.reportDate;保存前用 detail 接口返回的 indicators/gutFlora/diseaseRisks
+-   回填空 payload,避免老报告无 payload_json 快照时只改日期却清空指标
+- - 非 200 直接展示后端 res.message(不吞错误,不弹「已保存」);成功后 toast「已保存」+ loadData() 重载
+- - headInfo.reportDateText 改用 formatDate(原 parseDate 把 Date 对象直接渲染进模板,
+-   违反项目时间显示规范 yyyy-MM-dd),新增 headInfo.reportDate 供编辑回填
+- - 未做 gut-flora-detail.vue / report-result.vue 的日期入口(设计文档 §5 P1-2 范围外)
+- 校验:vue-template-compiler 模板 PASS / dart-sass 样式 PASS / node --check 脚本 PASS
+-       audit-mp-antipatterns ERROR 0 / audit-duplicate-api-calls 0 error
+- 
+-   解析失败抛 IllegalArgumentException(GlobalExceptionHandler 转 400 + 明确提示),不再静默吞错
+- - 未来日期拦截:parsedDate.after(now) 拒绝,当天允许
+- - 记录 reportDateChanged 标记,改日期后补调 refreshMemberIndicatorCurrent(subjectId, reportId)
+-   刷新 member_indicator_current 快照(改日期改变 report_date 排序,需重定位上一期)
+- - date_source 标记:columnExists(indicator_values, date_source) 兜底判断,列存在则 UPDATE report 时序行为 real,
+-   列不存在(T01 迁移未落地)整段跳过并 log.info 说明原因,不崩不报错
+- - 幂等性未破:oldReport.reportDate 先改再走 normalizeIndicatorPipeline.processReport,
+-   upsert SQL 含 report_date = VALUES(report_date),时序日期自动同步
+- - 新增私有 columnExists 辅助(参照 DatabaseInitializer 实现)
+- 设计文档:docs/superpowers/specs/2026-10-26-report-date-editable-design.md §3.2
+- mvn -o compile EXIT_CODE=0
+- 
+- - 出参含 eligible / dateFixable / skippedNoSubject / skippedNoPayload / written / details
+- - admin 角色校验,默认 dryRun=true
+- 
+- - parseRefRange/judgeInRange:参考范围解析与 in_range_is_better 四分支
+- - computeChange:Δ/Δ%、微小基数护栏(refHigh×1%)、2% 持平阈值、五值 trendCode
+- - 单测 23 例覆盖解析/判定/护栏/单位/非数值/无上一期两档
+- 
+- - HealthReportController.confirmDraft: createReport 后补写统一指标层时序
+- - 两处均 try/catch,失败不阻断主流程;底层 upsert 幂等
+- 
+- - upsertMapping 的 INSERT 与 ON DUPLICATE 子句同步 2 列
+- - NormalizeIndicatorPipeline 写入日期来源标记与参考范围快照
+- - HealthIndicator.collectionDate 移除 @TableField(exist=false)(前置列存在性兜底已在迁移422)
+- 
+- - 迁移422 前置: health_indicators.collection_date 存在性兜底(放开实体映射前必须先行)
+- - 迁移423: 新建 body_fat_scale_records 表
+- - schema.sql 同步以上 DDL
+- 
+- - mini-app .vue (pages+components): 家长->本人/家庭成员, 孩子->家庭成员/儿童,
+-   age-context 成人/儿童/长者; comments included. Excluded (whitelist, A2):
+-   pages/activity/create.vue + activity-detail.vue (activity pricing UI).
+- - backend user-visible strings: toast/Result messages, @Operation/@Tag,
+-   message templates, AI prompts (application.yml, cognitive-recommendations.yml),
+-   seed copy (seed-test-data.sql, mbti_seed_data.sql, schema_service_guide.sql),
+-   comment/log wording swept for grep cleanliness.
+- - no DB column comments, no API paths, no page dirs, no Java identifiers changed.
+- - skipped (A2 parallel): Activity.java, ActivityDTO.java, ActivityOrderService.java,
+-   DatabaseInitializer.java (66 lines), schema.sql (45 lines).
+- verify: mvn compile EXIT=0; node scripts/verify-vue-compile.js PASS (385/385/385).
+- 
+- 后端
+- - 迁移421: activities 新增 audience_scope(all/member_only) / audience_type
+-   (adult/include_child/include_elder/include_child_elder) 两列,
+-   information_schema 存在性检查 + AFTER visible_to 列定位,幂等;schema.sql 同步。
+- - Activity/ActivityDTO 新增 audienceScope/audienceType 字段与映射。
+- - ActivityDTO 新增 basePrice(原始普通价):price 已被 resolveMemberPrice
+-   替换成会员价,编辑表单回填必须用原始值,否则会员编辑会把会员价写成普通价。
+- - ActivityOrderService 结算按参与者身份分类:
+-   self(未关联成员)/child(age<18)/elder(age>=60)/adult(其他成年家庭成员),
+-   废弃「memberId 非空即孩子」旧语义;批量预取年龄避免 N+1。
+- - 成人档 price>0 ? price : parentFee;会员档区分 memberPrice NULL(存量别名)
+-   vs 0(新模型同普通价),parentMemberFee=0 的存量免费语义原样保留。
+- - audience_scope=member_only 后端硬门禁:非登录引导登录、非会员拒绝,
+-   范式对齐 TaskController.checkMemberOnly。
+- 前端(create.vue 仅【费用与适用人群区块】)
+- - 参加范围单选 + 参与人群多选(成人恒选,含儿童/含长者)
+- - 价格/会员价恒显输入;儿童两档仅在勾选「含儿童」时显示
+- - 不再提交 parentFee/parentMemberFee(历史别名);存量收费不误清零
+- - 保留 A1 已提交的 multiSelector 时间选择器代码,未改动
+- 测试:ActivityOrderServiceTest(15) + ActivityDTOTest(3),18 例全绿
+- 
+- - 新增 cfc-frontend/utils/activity-fee.js:统一 audienceScope/audienceType 归一化与成人/儿童/长者档位取价
+-   (长者复用成人价,D1 不新增长者价格列;parentFee/parentMemberFee 作为成人非会员价历史别名回落,A2 §2.4)
+- - activity-detail.vue:费用区按 audienceType 条件渲染「成人/儿童/长者」(成人恒显;儿童/长者需含该人群且对应价格 > 0);
+-   海报价格文案按 audienceType 选「(成人)/(儿童)/(长者)」,不再出现「家长」「孩子」;
+-   hasFee / hasMemberPrice 纳入 price / memberPrice(修复只填成人价的付费活动误显「免费」的真实 bug);
+-   minFeeText 改为当前用户可用档位的最小值(会员用会员价列、非会员用非会员价列);
+-   报名弹窗为每个报名人展示身份标签(成人/儿童/长者)与对应单价,合计同步按身份口径估算
+- - index.vue:normalizeRegistration 不再用 4 个 child/parent 费用的最小值覆盖 price,仅 price 为空时回落 parentFee;
+-   列表卡片的 hasFee / minFee 同步纳入成人档
+- - cfc-web ActivityEdit.vue:价格区之后追加适用人群(单选)与参与人群(多选),勾选「含儿童」时条件显示儿童两档费用;
+-   读写字段名对齐 A2 的 DTO(audienceScope / audienceType + childFee / childMemberFee),与小程序保存口径一致
+- 范围说明:A2 的数据层(audience_scope / audience_type 列、实体与 DTO)与结算逻辑不在本任务范围;
+- audienceScope / audienceType 需 A2 合入后才能落库与回显,本分支前端已按 A2 契约对齐并对字段缺失做了降级。
+- 
+- - 3 处 <picker mode=time> 改为原生 multiSelector 双列:时 24 项 00..23,分 12 项 00/05/.../55,
+-   5 分钟粒度在选择过程中即生效,用户无法选中非 5 倍数分钟,不再出现选了 07 分却变 05 分
+- - 删除 3 处 picker-hint 提示文案「以 5 分钟为一个单元(如 14:00、14:05)」及对应 CSS 注释/样式
+- - data 新增 hourOptions/minuteOptions 与 3 组时/分索引;新增 applyTimeParts 统一做索引↔字符串双向同步
+- - 新增 onStartTimeColChange/onEndTimeColChange/onRegTimeColChange;日期逻辑与 syncXxx 组装逻辑不变
+- - 回填路径 fmtTime/loadDetail 归一化后反算分钟索引,picker 显示与提交值一致(14:07 → 显示与提交均为 14:05)
+- - normalizeTimeTo5Min 保留为兜底(历史脏数据/后台写入非 5 倍数仍收敛),提交串恒为 YYYY-MM-DDTHH:mm:00
+- 
+-   ArticleEdit/ActivityEdit/ProductEdit/HomeBannerManage/ProductSkuEditor/
+-   GuidePackages/KnowledgeDialog 的接入方式,以及 Activities/ArticleManage/
+-   SupplierProductManage/RecommendationRules/IndicatorMappings 等无上传控件页面、
+-   ProxyReportUpload 等报告解析专用端点页面的跳过原因
+- - 标注旧端点 /api/admin/articles/upload/image|video 保留兼容
+- - PROJECT-OVERVIEW.md 同步(版本号口径、接入页面清单含 GuidePackages 与拖拽上传)
+- 
+- - editorAssetUpload.js:getEditorCustomAlert 改为具名导出,修复 3 个 wangEditor 页面 import 告警
+- 
+-   抽出 uploadAndSelect 统一点击与拖拽两条路径的上传入库+自动选中逻辑,
+-   增加拖拽态高亮与「点击或拖拽文件到此处」提示
+- - GuidePackages: 封面图上传端点由失效的 /api/upload(无鉴权、后端无此路由)
+-   改为 /api/admin/file-record/upload(Bearer + category=guide-packages),
+-   修正 handleUploadSuccess 取 res.data.url,并接入「从素材库选择」AssetPicker
+- - 回填脚本: file_type 回填的 WHERE 条件与注释声明的意图对齐
+-   (排除与目标值相同的行,避免无意义行更新)
+- 
+- - 新增 components/AssetPicker.vue(图片/视频/文档三类筛选 + 上传入库 + 标签筛选 + 单选/多选)
+- - 新增 views/admin/AssetLibrary.vue(网格卡片 + 类型/分类/标签/关键词/日期筛选 + 批量打标签/删除 + 改描述 + 预览 + 标签管理 + 统计);router 注册 admin/asset-library,Layout 加菜单与缓存页
+- - ArticleEdit / ActivityEdit / ProductEdit / ProductSkuEditor / HomeBannerManage / KnowledgeDialog 接入「从素材库选择」与 /api/admin/file-record/upload
+- - HomeBannerManage 修复重复 beforeUpload 导致封面图永远无法上传的缺陷;FileManage 类型口径 pdf → document
+- 
+- - JdCloudStorageService 存量写入回填 file_type;LocalDiskStorageService 本地模式实现 storeFileRecord
+- - 新增 FileRecordService 业务层(分页/标签/描述/统计),Controller 不直接触碰 Mapper
+- - FileRecordController 重写:/upload(微信图片内容安全校验 fail-open + 标签关联 + 去重命中补标签)、/list(tagIds 前置过滤保证 total)、/update、/delete、/tags、/tag/create|update|delete、/stats,统一 admin 角色守卫
+- - schema.sql file_type 注释口径统一;新增 docs/migrations/20261025_asset_library_file_type_backfill.sql(存量回填,严格按 content_type,不占迁移编号)
+- - API_REFERENCE.md §4.56 + PROJECT-OVERVIEW.md v2.22 同步文档
+- 
+
+### Bug 修复
+- P1-1 报告日期可修改·前端修复2 - 日期改用最小 payload,杜绝三表存量列被清
+- P1-1 报告日期可修改·前端修复1 - 保存失败不再覆盖后端明确原因
+- 修复 G3 事后绑定成员不补时序 + confirm 链路补写
+
+### 新功能
+- P1-1 报告日期可修改·前端 - report-detail 查看态日期修改入口
+- P1-1 报告日期可修改·后端 - 严格解析+未来日期拦截,日期变更联动快照刷新与 date_source 兜底
+- 新增 /api/admin/indicator/backfill 回填端点(dryRun 优先)
+- 新增 IndicatorChangeService 变化计算底座 + 单测
+- 指标值落库补日期来源/参考范围快照,放开 collection_date 映射
+- 迁移422/423 指标多期展示数据地基
+- A2 活动适用人群 + 费用模型重构
+- A3 活动费用展示层口径统一(成人/儿童/长者 × 会员/非会员 + 适用人群)
+- A1 创建活动页时间选择器改为 5 分钟粒度双列 picker
+- F-8 清理收尾-三套旧账本写接口410Gone+补CF值单一事实源文档
+- 成长规划师任务模板封面接入素材库 + 补 getEditorCustomAlert 具名导出
+- 素材库补齐拖拽上传与任务模板封面入库
+- 后台素材库前端 — AssetLibrary 页 + AssetPicker 组件 + 上传点改造
+- 后台素材库后端 — file-record 上传/检索/标签CRUD/统计
+
+### 重构
+- neutralize parent/child wording in user-visible copy
+
+### 文档
+- 素材库补充上传点接入范围与跳过说明
+
+
 ## v1.0.1799 (2026-10-26)
 
 ### Bug 修复