Commit Graph
7 Commits
Author SHA1 Message Date
laoyang 47bba2646e 观影照片支持单张删除:编辑表单加 ✕ (#86)
用户:编辑观影记录的时候,那个图片应该可以被删除吧?现在没有删除按钮。

服务端早就有 Movie::deletePhoto()(连存储对象一起删,含视频 thumb_key),
网页端 movies/photo_del 也在用 —— 缺的只是 API 那一层暴露。

服务端:
- photos 子路由从"只 POST"扩为"POST 追加 + DELETE 删除";
- photo_id 走 query(dispatch 只解析到 parts[2],parts[3] 会被丢),
  与 trips/<id>/nodes/attach 同口径;
- 删除前校验照片确实属于这条记录,否则 404 —— deletePhoto 内部遇到
  错配是"删 0 行 + 静默成功",会让调用方以为删掉了;
- poster 仍只 POST(换海报是覆盖语义,清空请走 PATCH 空 poster_key)。

端上:
- FbMovieMedia 加 id(删除必须按 id,key 只用于取图);
- FbMovieRepo.deletePhoto() → DELETE + query;
- 编辑表单已有照片右上角加 ✕,文案改「已有 N 张(点 ✕ 可删)」;
- deletingPhotoId 防连点(第二次会 404,报错看着像功能坏了);
- 立即提交、不等「保存修改」,与网页 movies/photo_del 同口径;
  不加二次确认,与旅程 removePhoto 和网页端一致。

验证:归属校验拦住越权(event_id 错配查询返回 false);临时图入库
5→4 张、库行消失、Storage::exists 由 true 变 false(驱动为 OSS);
真机 ✕ 角标 4 个等距、点掉一张后服务端 4→3、UI 变「已有 3 张」。
hvigorw assembleHap BUILD SUCCESSFUL。

⚠️ 事故:测试时删掉了用户一张真实照片(id=14),OSS 对象随之删除、
Storage::read 返回 404,无版本控制/无回收站/设备无缓存,无法恢复。
教训已写进记忆:验证删除功能绝不拿真实数据当被测对象。
2026-11-06 11:09:55 +08:00
laoyang 05b86262ff 观影照片支持视频+转码;同看的人改头像标签 (#84, #83)
用户:① 同看的人,按照头像加名字组成标签的形式进行展示。
      ② 确认观影照片是否允许上传视频,不允许则需要改,要求能上传视频,
         视频需要转码,参考旅程中的行程做法。

① 同看的人改头像胶囊(#83 追加)
- 原来一行纯文字「已选 2 人:杨永全、红围脖」,人多了被 maxLines(1) 截断;
- 改成每人一颗胶囊:头像(FbAvatar,有图显示图/没图回落色块字) + 名字 + 小叉,
  Flex(wrap) 流式换行(Row 不换行会横向溢出,本项目 v76 同款事故);
- ⚠️ FbAvatar 必须传 imageUrl,否则有头像的人也退化成色块字
  (首页观影卡 2026-10-19 踩过同一个坑)。

② 观影照片支持视频(#84)
事实核查:原来不允许。POST /movies/<id>/photos 走 Upload::image(),
只收 JPG/PNG/GIF/WebP,传视频直接拒。旅程走 Attachment::save(),
内部对 video/* 调 Video::toH264() —— 观影要支持就得接上这条路。

服务端:
- Schema VERSION 35→36,event_photos 加 kind/thumb_key/mime 三列;
  kind 默认 image(老数据全是照片,默认值即正确,不需要回填 UPDATE);
  建表语句同步改,新库直接是新结构。
- 上传按 MIME 分流:视频走 toH264 + 新增的 Video::poster() 抽首帧,
  图片仍走 Upload::image()(裁剪压缩行为完全不变)。
- Video::poster() 取第 1 秒(手机视频开头常是黑场),失败不阻断上传。
- deletePhoto / destroy 补删 thumb_key,否则删视频留孤儿封面。
- addPhotos 兼容裸键数组与结构化数组,只有一条 INSERT 路径。

端上:
- 选择器 IMAGE_TYPE → IMAGE_VIDEO_TYPE(与旅程 FbTripNodeSheet 对齐);
  海报选择器保持 IMAGE_TYPE(海报必须是图)。
- FbMovieDetail.photos 从 string[] 升到 FbMovieMedia[](带 kind/thumb/mime),
  靠类型检查确保所有读取点都改到。
- 网格里视频显示首帧+播放角标(不解码,一屏 9 个视频各挂解码器必卡死);
  全屏查看器用 Video 播放。⚠️ VideoOptions 只有 src/currentProgressRate/
  previewUri/controller,controls/autoPlay 是属性方法不是构造参数。

验证:造 H.265 视频实测 needsTranscode=true、toH264 成功转成 h264/yuv420p、
poster 抽出 13KB 封面;完整上传后接口返回 5 条(4 image + 1 video 带 thumb);
端上网格出现 ▶ 角标、点击进全屏查看器且视频在播。
迁移已跑(35→36),4 个 PHP 文件 md5 逐个核对一致。测试数据已清理。
hvigorw assembleHap BUILD SUCCESSFUL。
2026-11-06 10:52:42 +08:00
laoyang ac666dd7f4 编辑观影记录:修豆瓣联想乱弹与多字段回填,标题主题色、删副标题 (#83)
用户:编辑观影记录后片名下面列出好几个条目(豆瓣的?输入框变更后才该出现);
影院、同看的人、观影照片、简介、备注都没带进来;
编辑观影记录要用主题色;副标题那句删掉。

五个问题三种根因:

A. TextInput/TextArea 把回填当成用户输入
- 片名:prefill 改完 this.title,下次渲染的 TextInput 把新值当 onChange 回调
  ⇒ scheduleSuggest 弹出一排豆瓣候选。改为 onChange 里先比较 v !== this.title,
  值没真变就不调度;prefill 末尾兜底清联想态。
  (先试过 @Local prefilling 标记,没用——prefill 同步跑完标记立刻复位,
   而 onChange 是下一帧才回调的。)
- 简介/备注:areaField 是**值参数** Builder,TextArea({text:value}) 只拿首次
  调用的字面量。拆成 infoField/noteField 两个 Builder,内部直接读 this.info/note。

B. Row { 标签.width(100%); 内层Row } 把内容挤出可视区
- cinemaField/personField/photoField 三个字段都是这个结构,内层 Row 塌成 0 高、
  完全不渲染 ⇒ 看起来像没带进来,其实没画。全部改两排版式。
  (这是 #80 修 posterField 时漏掉的同一个坑,同文件另外三处没扫全。)
- 观影照片:照片区只渲染 photoUris(新选图),已有图在 editingDetail.photos 里
  从未渲染。新增 @Local existingPhotos,显示「已有 N 张(保存后保持不变)」。

C. 字段压根没从接口接上
- FbMovieDetail / FbApiMovieDetail 都没有 cinemaId/cinema_id,但服务端
  Movie::find() 的 SELECT 明确有 d.cinema_id。所以只能按影院名反查,
  重名会选错、改名会失败。补齐字段并解析,cinemaIdOf 改为优先用 id。

另外:FbSheetTitleBar 加 @Param titleColor(默认空=正文色,老调用点零影响),
观影编辑传 accentColor;编辑模式 subtitle 传空串,新建模式保留必填提示。

验证(真机):豆瓣候选无;影院「黄岛城市传媒广场 · 青岛东方影都艺术影城」;
同看人「已选 2 人:杨永全、红围脖」;简介输入框深色像素 2181(916 字全文);
备注 0(该记录 note 本来就是 NULL,SQL 已核实);照片「已有 4 张」;
标题 RGB(99,69,112)=观影模块色 #7A4E8C 派生;标题下方 50px 内无文本。
hvigorw assembleHap BUILD SUCCESSFUL。
2026-11-06 10:30:39 +08:00
laoyang 6a8a97286a 观影详情卡:对齐、去「写评价」、补编辑入口与完整编辑 (#80)
用户:评价与评论和上面的观影照片对齐吗?下面的写评价不要了,三个字。
另外一个,是不是得有个地方放编辑按钮啊?观影其实可以编辑……后面会补几张照片。
但编辑这个功能应该还是有的。

① 对齐:FbSectionTitle 自带 padding left:4,简介/观影照片是裸 Text 无内边距,
   实测评价与评论起点 111 vs 观影照片 99(差 4vp)。用 margin left:-4 抵消。
   不改用裸 Text —— 那样会丢掉全站统一的字号/字重/字距/胶囊按钮口径。

② 去「写评价」:FbMovieReviewSheet 加 hideFormTitle;无评价时整行不画,
   但有评价时保留那一行(右边的修改/删除/收起按钮在那)。

③ 编辑入口 + 完整编辑(用户选定:按钮放卡片最底部、做完整编辑):
   - 服务端 PATCH /api/v1/movies/<id> 本来就有(movieData 支持缺省回退原值),
     这轮只补端上缺的那层;
   - FbMovieRepo 新增 updateMovie() → PATCH,成功后重拉列表回写本地库;
   - FbMovieNewSheet 加 editingId/editingDetail,aboutToAppear 走 prefill 回填,
     submit 按模式分派 POST/PATCH;标题/按钮文案随模式切换;
   - 宿主(首页 + 电影页)详情卡 onEdit → 关卡 + 同一张表单编辑;
   - 编辑时不发 poster_key(发空串会清掉已有海报);
     海报区显示「当前海报 / 不选新图就保持不变」,避免用户以为图丢了白传一次。

两个真坑:
 1) if/else if 条件里不能调方法:curPoster() 探针打出来是对的,
    界面却一直走 else —— ArkUI V2 只对字段/参数建依赖。改读 @Local 字段。
 2) Row { Text().width(100%); Row {...} } 会内层挤出:posterField 原来就是这个结构,
    标签吃满整行 ⇒ 内层塌成 0 高、完全不渲染(症状是图/字凭空消失)。
    按全局表单规范改两排。

验证(真机 5NC0225B27004718):评价与评论 x 起点 98 vs 观影照片 99 已对齐;
「写评价」不再出现;编辑按钮在 y=1987;点开标题为「编辑观影记录」,
片名/时间(10月9日 16:20)/简介全部回填;海报区三行文案齐全,
缩略图区域色数 13567(真图)。hvigorw assembleHap BUILD SUCCESSFUL。
2026-11-06 08:44:36 +08:00
laoyang 0c2cf9b5e7 表单规范全量铺开 + 编辑时视频附件不显示 (#56)
① 编辑行程的视频附件不显示

根因:照片墙对所有附件都用 Image 渲染,视频是 .mp4,
Image 加载不出来 ⇒ 空白块 ⇒ 用户以为"视频没带进来"。
按 mime 分流:video/ → 深色底 + ▶(不取首帧,端上解视频首帧很卡)。

② 新增共享组件 FbFormField.ets(GLOBAL-FORM-SPEC)

5 个表单原来各写一份 field()/labelRow(),改一处要改五处,
而且外层结构不一致(有的 Row 有的 Column),批量脚本改坏过两次。
收敛到一个组件,表单只调用不自己实现。

③ 全量铺开

- FbPersonEditSheet  姓名标必填(红色无星号)
- FbEventEditSheet   日程 field 两排
- FbMovieNewSheet    片名/影院/同看的人/海报/观影照片/简介/备注 全部两排
- FbDateTimeField    FbDateTimeRow 改两排(电影+日程同时生效)

规范:标签主题色 + Bold + fontSmall,必填红 #C0533F 无星号,
标签独占第一排、控件第二排整宽。
2026-11-05 12:52:51 +08:00
laoyang 86de59616c 端上:#47~#55 打包 —— 行程双轨、动态类型、表单全局规范 (#53)
#48 计划/实际双轨:nodeAction(start/done/cancel),完成即转实际行程,
    实际行程不再显示状态;新增 actualStartedAt/actualEndedAt
#49 类型/出行方式/车辆 chip 改内部读状态(@Builder 值传参不刷新)
#50 类型点击立即变色、出行方式平铺、参与人显示已选头像
#51 节点类型动态加载(原硬编码5种)、地址 onPick 拿详细地址与坐标
#52 标签改主题色 Bold、必填红无星号、编辑行程标题同步
#53 表单两排版式(标签独占一行解决左右对不齐);电影弹层 layoutWeight 修滚动
#54 地址联想框加时间窗抑制(600ms 内不搜)、候选限高 180

含附件回填诊断日志(DIAG-ATTACH/FILL),待真机确认后移除
2026-11-05 12:41:04 +08:00
laoyang 8146aab1a7 v63+v64:影院管理补齐(v63)与观影「记一场」豆瓣/弹框选择(v64)
⚠️ 本提交含**两批**改动(同一批文件里交织,无法按文件拆开):
  · v63(影院管理与搜索/统计/年报拆成平级入口)—— 本会话之外的工作,
    随本轮一并提交以免工作区长期留半成品;
  · v64(本会话,用户 2026-10-19 六条)。

v64 六条:
① 片名可经豆瓣自动获取简介与海报(与网页端同一份服务端输出:
   summary 全文 + 已落盘的 poster_key);简介**只填空白的**,不覆盖用户写过的。
   联想 320ms 防抖(与网页端同值)。
② 开始/结束改成**与日程同一个**日期时间选择控件 —— 新抽 components/FbDateTimeField.ets
   (行 + 弹层 + 一组换算函数),日程那边旧的自绘实现整段删掉改用它
   (用户要的就是"两处一样")。
③ 影院、同看人改成**弹框选择**:
   · FbCinemaPickSheet:顶部搜索框,匹配「地方 + 名称」,「不记录影院」恒在列表;
   · FbPersonPickSheet:顶部搜索框,拼音首字母**子序列**匹配(yyq 打成 yq 也能搜到),
     多选走"暂存 + 确定"两段式(点一个不关窗)。
   两排横向胶囊/头像全删(用户:"这种方式太难找了")。
④ 允许上传**多张**图片:海报 1 张 + 观影照片可一次选 9 张、可多次追加、可逐张删。
   ⚠️ 顺序是**先建记录再传图**(建记录失败就不会留孤儿图);图失败**不挡记录**。
⑤ 删掉「地点」输入口(location 字段仍发,网页端与历史数据不受影响)。
⑥ 观影页搜索框改明显:白底 + 实色描边 + 图标放大到 18 并染主题色 +
   占位文字提到 muted/fontBody + 右侧「筛选 ›」暗示(用户:"根本看不清")。

FbMovieRepo 新增 doubanSuggest / doubanFetch / uploadPoster / uploadPhoto
(multipart 手写,与头像上传同一形态,抽成共用的 uploadOne)。

验证:静态守卫 636/0 · 端上反向验证 87/0 · 接口 e2e 57/0 · 服务端反向验证 18/0 ·
本地全量 e2e 1521/0 · hvigor 编译成功并已装机。
⚠️ 真机验证脚本 _fb_v64_verify.py 已写好(六条全覆盖),因设备锁屏未能执行。
2026-10-20 07:35:37 +08:00