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 已写好(六条全覆盖),因设备锁屏未能执行。
This commit is contained in:
@@ -31,6 +31,8 @@ import { FbDb } from '../../data/FbDb';
|
||||
import { FbMovieDetail, FbMovieListItem, FbMovieRepo, FbSyncResult } from '../../data/FbMovieRepo';
|
||||
import { FbMovieDetailSheet } from '../../components/FbMovieDetailSheet';
|
||||
import { FbCinemaSheet } from '../../components/FbCinemaSheet';
|
||||
import { FbMovieNewSheet } from '../../components/FbMovieNewSheet';
|
||||
import { FbMovieInsightSheet } from '../../components/FbMovieInsightSheet';
|
||||
import { FbModuleSettingsSheet } from '../../components/FbModuleSettingsSheet';
|
||||
import { FB_BACK } from '../../common/FbBack';
|
||||
import { FB_SET_MOVIES } from '../../model/FbSettingsMenus';
|
||||
@@ -131,6 +133,25 @@ export struct FbMoviesPage {
|
||||
@Local settingsOpen: boolean = false;
|
||||
/** 影院浮层是否打开 */
|
||||
@Local cinemaSheetOpen: boolean = false;
|
||||
/**
|
||||
* 「记一场」新建浮层是否打开。
|
||||
*
|
||||
* 🔴 v63(用户 2026-10-19):「电影新增一场、新增一个电影,也就是说
|
||||
* "记一场"这个功能现在可以开始做了。」
|
||||
* ⇒ 那颗按钮原来**没有回调**(纯摆设),点了什么都不发生。
|
||||
*/
|
||||
@Local newOpen: boolean = false;
|
||||
/**
|
||||
* 高级搜索 / 统计 / 年度报告浮层是否打开。
|
||||
*
|
||||
* 🔴 v63:这三项**从「影院管理」里搬出来**,成为设置菜单里的独立入口
|
||||
* (用户:「影院管理就是管理影院,不要把统计搜索和年报放在这里面」)。
|
||||
* ⚠️ 用**一个** open 位 + 一个 mode 串(三者共用一个组件,
|
||||
* 见 `FbMovieInsightSheet` 的说明),不开三个 boolean。
|
||||
*/
|
||||
@Local insightOpen: boolean = false;
|
||||
/** `search` / `stats` / `report`(配合 `insightOpen`) */
|
||||
@Local insightMode: string = 'stats';
|
||||
|
||||
/**
|
||||
* 🔴 浮层开合时**让底部悬浮栏让位**(与名册页同一处 bug,见 `FbPeoplePage` 的说明)。
|
||||
@@ -139,10 +160,11 @@ export struct FbMoviesPage {
|
||||
* ⇒ 悬浮栏层级更高 ⇒ 浮层底部的按钮会与它重叠、点击被抢走。
|
||||
* ⇒ 用 `@Monitor` 一处声明、自动跟随派生(避免在多个赋值点手写、漏一处就出事)。
|
||||
*/
|
||||
@Monitor('sheetOpen', 'cinemaSheetOpen', 'settingsOpen')
|
||||
@Monitor('sheetOpen', 'cinemaSheetOpen', 'settingsOpen', 'newOpen', 'insightOpen')
|
||||
onSheetChanged(): void {
|
||||
const app: FbAppState = fbAppState();
|
||||
app.sheetCount = (this.sheetOpen || this.cinemaSheetOpen || this.settingsOpen) ? 1 : 0;
|
||||
app.sheetCount = (this.sheetOpen || this.cinemaSheetOpen || this.settingsOpen
|
||||
|| this.newOpen || this.insightOpen) ? 1 : 0;
|
||||
}
|
||||
/** 模块主题色(观影 = 紫) */
|
||||
private accent: string = '#7A4E8C';
|
||||
@@ -165,6 +187,12 @@ export struct FbMoviesPage {
|
||||
}
|
||||
|
||||
private backOnce(): boolean {
|
||||
if (this.newOpen) {
|
||||
this.newOpen = false;
|
||||
}
|
||||
if (this.insightOpen) {
|
||||
this.insightOpen = false;
|
||||
}
|
||||
if (this.settingsOpen) {
|
||||
this.settingsOpen = false;
|
||||
return true;
|
||||
@@ -426,6 +454,58 @@ export struct FbMoviesPage {
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 「记一场」新建浮层(用户 v63:「记一场这个功能现在可以开始做了」)----
|
||||
if (this.newOpen) {
|
||||
Column()
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(FB_MASK)
|
||||
.transition(fbMaskTransition())
|
||||
.onClick((): void => {
|
||||
this.newOpen = false;
|
||||
})
|
||||
|
||||
FbMovieNewSheet({
|
||||
cinemas: this.cinemas,
|
||||
accent: this.accent,
|
||||
/* 🔴 v64:「同看的人」默认要带上**我**(与网页端 v38 同口径:
|
||||
「自己不用选择就应该已经选上了」)。登录者 id 从全局会话取,
|
||||
取不到(0)时浮层就不预置任何人 —— 不会硬塞一个错的 id 进 attendees。 */
|
||||
meId: this.app.session.me.id,
|
||||
onClose: (): void => {
|
||||
this.newOpen = false;
|
||||
},
|
||||
/* 新建成功 ⇒ 重读本地库(`createMovie` 里已经重拉过接口并落库,
|
||||
这里只是把页面的列表刷出来)。 */
|
||||
onCreated: (): void => {
|
||||
this.reloadFromLocal();
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 高级搜索 / 统计 / 年度报告(三个入口共用这一个浮层)----
|
||||
if (this.insightOpen) {
|
||||
Column()
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(FB_MASK)
|
||||
.transition(fbMaskTransition())
|
||||
.onClick((): void => {
|
||||
this.insightOpen = false;
|
||||
})
|
||||
|
||||
FbMovieInsightSheet({
|
||||
mode: this.insightMode,
|
||||
cinemas: this.cinemas,
|
||||
accent: this.accent,
|
||||
onClose: (): void => {
|
||||
this.insightOpen = false;
|
||||
}
|
||||
})
|
||||
.transition(fbSheetTransition())
|
||||
}
|
||||
|
||||
// ---- 模块设置浮层(三条横线点开的那个)----
|
||||
if (this.settingsOpen) {
|
||||
Column()
|
||||
@@ -446,10 +526,22 @@ export struct FbMoviesPage {
|
||||
this.settingsOpen = false;
|
||||
},
|
||||
onPick: (action: string): void => {
|
||||
// 目前只有「影院管理」是已实现的;其余在菜单里显示「暂未开放」
|
||||
/* 🔴 v63:四条**全部接上**。
|
||||
⚠️ 三条"洞察类"(搜索/统计/年报)走**同一个浮层 + 不同 mode**,
|
||||
不是三个浮层(见 `FbMovieInsightSheet` 的说明)。
|
||||
⚠️ 先关设置再开目标浮层 —— 两者不叠(叠起来会看到两层遮罩)。 */
|
||||
this.settingsOpen = false;
|
||||
if (action === 'cinema') {
|
||||
this.settingsOpen = false;
|
||||
this.cinemaSheetOpen = true;
|
||||
} else if (action === 'moviesearch') {
|
||||
this.insightMode = 'search';
|
||||
this.insightOpen = true;
|
||||
} else if (action === 'moviestats') {
|
||||
this.insightMode = 'stats';
|
||||
this.insightOpen = true;
|
||||
} else if (action === 'moviereport') {
|
||||
this.insightMode = 'report';
|
||||
this.insightOpen = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -481,7 +573,12 @@ export struct FbMoviesPage {
|
||||
FbPrimaryButton({
|
||||
label: '记一场',
|
||||
bg: this.accent,
|
||||
icon: $r('app.media.fb_ic_plus')
|
||||
icon: $r('app.media.fb_ic_plus'),
|
||||
/* 🔴 v63:**接上回调**(原来这颗按钮没有 `onTap`,
|
||||
点了什么都不发生 —— 用户:「记一场这个功能现在可以开始做了」)。 */
|
||||
onTap: (): void => {
|
||||
this.newOpen = true;
|
||||
}
|
||||
})
|
||||
// 🔴 设置按钮 = 网页版那种**三条横线**(☰);「影院」也不单独占抽屉位置,
|
||||
// 它是观影模块的一部分,从设置菜单里进(与网页版一致)。
|
||||
@@ -499,42 +596,61 @@ export struct FbMoviesPage {
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// ---- 搜索条 ----
|
||||
Row({ space: 6 }) {
|
||||
//
|
||||
// 🔴 v64(用户 2026-10-19):「**电影的这个搜索框,非常不明显,根本看不清。**」
|
||||
//
|
||||
// 原来那版的三个毛病(改前):
|
||||
// · 底色是 `FbColors.inputBg`(`#F2EDE2`)—— 与页面底色 `paper` 几乎同色,
|
||||
// 整条**看不出是个框**,像一行普通文字飘在那儿;
|
||||
// · 图标 15vp + `faint`(`#A8988A`)—— 对比度太低,真机上几乎看不见;
|
||||
// · 文字也是 `faint` 且只有 `fontSmall`,与背景糊成一片。
|
||||
//
|
||||
// 现在的做法(四件事一起做才"看得清",只做一件仍然发飘):
|
||||
// ① 底色给**白**(`surface`)—— 与 paper 底形成面与面的区分;
|
||||
// ② 加一圈**实色描边**(`line`)—— 边界是硬边,不依赖光照假设;
|
||||
// ③ 图标放大到 18 且改用主题色 —— 它同时也是"可点"的视觉暗示;
|
||||
// ④ 占位文字从 `faint` 提到 `muted`、字号从 `small` 提到 `body`。
|
||||
Row({ space: 8 }) {
|
||||
Image($r('app.media.fb_ic_search'))
|
||||
.width(15)
|
||||
.height(15)
|
||||
.width(18)
|
||||
.height(18)
|
||||
.renderMode(ImageRenderMode.Template)
|
||||
.colorFilter(fbTint(FbTint.faint))
|
||||
.colorFilter(fbTint(this.accent))
|
||||
Text('搜索片名、影院、观影人…')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.faint)
|
||||
.fontSize(FbMetric.fontBody)
|
||||
.fontColor(FbColors.muted)
|
||||
.layoutWeight(1)
|
||||
.maxLines(1)
|
||||
}
|
||||
.height(36)
|
||||
.padding({ left: 12, right: 12 })
|
||||
.backgroundColor(FbColors.inputBg)
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
.margin({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 4 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
|
||||
// ---- 影院数(可点:看影院列表)----
|
||||
// 🔴 之前这是个**纯文字**(只能看数字);现在点它能看到名单 ——
|
||||
// Web 端「影院管理」就在观影模块里,这里给它一个入口。
|
||||
Row({ space: 6 }) {
|
||||
Blank()
|
||||
Text('影院 ' + this.cinemas.length.toString() + ' 家')
|
||||
// 右侧一枚"进入"提示 —— 让这一条**看着就是可以点的**(原来完全没有暗示)
|
||||
Text('筛选 ›')
|
||||
.fontSize(FbMetric.fontTiny)
|
||||
.fontColor(FbColors.faint)
|
||||
Text('›')
|
||||
.fontSize(FbMetric.fontSmall)
|
||||
.fontColor(FbColors.faint)
|
||||
.fontColor(this.accent)
|
||||
}
|
||||
.width('100%')
|
||||
.height(42)
|
||||
.padding({ left: 12, right: 12 })
|
||||
.backgroundColor(FbColors.surface)
|
||||
.borderRadius(FbMetric.radiusS)
|
||||
.border({ width: 1, color: FbColors.line })
|
||||
.margin({ left: FbMetric.pagePad, right: FbMetric.pagePad, bottom: 8 })
|
||||
.alignItems(VerticalAlign.Center)
|
||||
/* 🔴 v63(用户 2026-10-19):「"搜索"这个功能也可以开始做了,
|
||||
**现在点搜索还没有反应**。」
|
||||
⇒ 这原来是个**纯展示的假输入框**(一个 Row + 一行占位文字,
|
||||
连点击回调都没有 —— 所以点了没有任何反应)。
|
||||
现改成**点它打开「高级搜索」** —— 与设置菜单里那一条是同一个浮层,
|
||||
这样"看到搜索框 → 点它 → 就能搜"符合直觉。
|
||||
⚠️ 不在这里做"就地输入过滤":观影搜索是**组合条件 + 要跨影院/日期**,
|
||||
就地过滤只能按片名,做出来会让用户以为"搜不到就是没有"。 */
|
||||
.onClick((): void => {
|
||||
this.cinemaSheetOpen = true;
|
||||
this.insightMode = 'search';
|
||||
this.insightOpen = true;
|
||||
})
|
||||
.padding({ left: FbMetric.pagePad + 4, right: FbMetric.pagePad + 4, top: 6, bottom: 6 })
|
||||
|
||||
/* 🔴 v63(用户 2026-10-19):「**观影列表里面也有个"影院26家",
|
||||
也不知道是什么意思,没有用,要把它删掉。**都在影院管理、都在设置里面
|
||||
就可以了。」
|
||||
⇒ 整行删除。影院列表现在只从**设置 ☰ → 影院管理**进
|
||||
(以前这一行也是"影院管理"的入口,与设置里的那条重复)。 */
|
||||
|
||||
|
||||
// ---- 同步状态提示(只在有话说时显示,不占位)----
|
||||
|
||||
Reference in New Issue
Block a user