2026-10-28 22:29:55 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 家书 FamilyBook · 观影影评 + 评论浮层(鸿蒙端,工单 #27)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 对应网页版 `templates/movies/show.php` 的「评价与评论」区块。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 用户 2026-10-28 原话:「鸿蒙端对齐网页端」。观影详情浮层原来只能看
|
|
|
|
|
|
* 一个平均分(`listRating`),不能写影评、不能评论。这个浮层把
|
|
|
|
|
|
* 影评(打分 + 观后感受 + 正文)与评论/回复补上。
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 每人对每部电影**只有一条影评**(再次提交即修改,服务端 `MovieReview::save`
|
|
|
|
|
|
* 的 isUpdate 语义);评论是**不限条数**的,可在任一条影评下回复。
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 只有「能写的人」(访客/只读账号)隐藏发表入口 —— 与 Web 端同口径。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import { FbColors, FbMetric, FB_MASK, fbAlpha } from '../common/Theme';
|
|
|
|
|
|
import { FbSheetRing } from './FbSheetRing';
|
|
|
|
|
|
import { FbSheetClose } from './FbSheetClose';
|
|
|
|
|
|
import { FbAvatar } from './Widgets';
|
|
|
|
|
|
import { FB_TOKEN_STORE } from '../data/FbTokenStore';
|
|
|
|
|
|
import { FbApiResult } from '../data/FbHttp';
|
|
|
|
|
|
import {
|
|
|
|
|
|
FbMovieComment, FbMovieReview, FbMovieReviews,
|
|
|
|
|
|
FbMovieRepo,
|
|
|
|
|
|
} from '../data/FbMovieRepo';
|
|
|
|
|
|
import { FbAppState, fbAppState } from '../common/Store';
|
|
|
|
|
|
|
|
|
|
|
|
/** 打分的一颗星 */
|
|
|
|
|
|
function starOn(i: number, cur: number): boolean {
|
|
|
|
|
|
return i <= cur;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ComponentV2
|
|
|
|
|
|
export struct FbMovieReviewSheet {
|
|
|
|
|
|
/** 观影记录 id */
|
|
|
|
|
|
@Param movieId: number = 0;
|
|
|
|
|
|
/** 电影名(显示在标题旁) */
|
|
|
|
|
|
@Param movieTitle: string = '';
|
|
|
|
|
|
/** 观影模块色 */
|
|
|
|
|
|
@Param accent: string = '#7A4E8C';
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 内嵌模式(2026-11-06)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 🔴 用户原话:「电影弹出框,评价与评论放在最下面,直接显示出来,
|
|
|
|
|
|
* 可以直接评论,不用再打开了。」
|
|
|
|
|
|
* ⇒ 本组件现在有两种形态:
|
|
|
|
|
|
* · `embedded = false`(默认,老形态):自带遮罩 + 圆角卡 + 标题栏,
|
|
|
|
|
|
* 作为独立浮层弹出(`bindSheet` 之类);
|
|
|
|
|
|
* · `embedded = true`:**只出内容**(我的评价 + 全部影评 + 评论),
|
|
|
|
|
|
* 不画遮罩、不画圆角卡、不画标题栏 —— 由 `FbMovieDetailSheet`
|
|
|
|
|
|
* 在它自己的 Scroll 里直接渲染。
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 为什么不另写一份「内嵌版」:影评/评论的表单、打分、感受多选、
|
|
|
|
|
|
* 回复树有 300+ 行,抄一份必然出现"改一处漏一处"(本项目已多次踩过)。
|
|
|
|
|
|
* 加一个开关,两条路径共用同一套逻辑与 DOM。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Param embedded: boolean = false;
|
2026-11-06 08:44:36 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 隐藏表单顶部的「写评价 / 我的评价」标题行(2026-11-06)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 🔴 用户:「下面的写评价不要了,三个字。」
|
|
|
|
|
|
* ⇒ 内嵌到详情卡后,上面已经有「评价与评论」这个区块标题,
|
|
|
|
|
|
* 再出现一行「写评价」是重复的。
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 只隐藏**标题文字那一段**,右边「修改 / 删除 / 收起」三颗动作按钮
|
|
|
|
|
|
* 仍然保留 —— 有评价时用户就是靠它们改和删,删掉整行会失去功能。
|
|
|
|
|
|
* 没有评价时那一行本来就只剩标题,于是整行自然消失。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Param hideFormTitle: boolean = false;
|
2026-10-28 22:29:55 +08:00
|
|
|
|
/** 保存/删除后通知宿主(列表的平均分可能要刷新) */
|
|
|
|
|
|
@Event onChanged: () => void = (): void => {};
|
|
|
|
|
|
|
|
|
|
|
|
@Event onClose: () => void = (): void => {};
|
|
|
|
|
|
|
|
|
|
|
|
/** 我的影评(null = 还没写) */
|
|
|
|
|
|
@Local mine: FbMovieReview | null = null;
|
|
|
|
|
|
/** 全影评 + 评论 */
|
|
|
|
|
|
@Local reviews: FbMovieReview[] = [];
|
|
|
|
|
|
@Local count: number = 0;
|
|
|
|
|
|
@Local avg: number = 0;
|
|
|
|
|
|
/** 感受目录:key -> emoji + ' ' + label */
|
|
|
|
|
|
@Local catalog: Record<string, string> = {};
|
|
|
|
|
|
|
|
|
|
|
|
/** 写影评表单态 */
|
|
|
|
|
|
@Local rating: number = 0;
|
|
|
|
|
|
@Local pickedFeelings: string[] = [];
|
|
|
|
|
|
@Local draft: string = '';
|
|
|
|
|
|
@Local ratingPickOpen: boolean = false;
|
|
|
|
|
|
@Local saving: boolean = false;
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 我的评价表单是否展开(2026-11-06)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 🔴 用户选择:「已评过=收起,没评过=展开」。
|
|
|
|
|
|
* · 已经写过的人:只看到评分摘要,想改再点「修改」展开 ——
|
|
|
|
|
|
* 否则每次打开详情卡都被一大块表单占住,评论被挤到很下面;
|
|
|
|
|
|
* · 还没写的人:直接看到表单,进来就能评。
|
|
|
|
|
|
*
|
|
|
|
|
|
* ⚠️ 初始值给 `false`,由 `load()` 拿到 `mine` 之后再定
|
|
|
|
|
|
* (数据还没回来时不知道写没写过,不能提前猜)。
|
|
|
|
|
|
* ⚠️ 是 `@Local` 而不是从这里反推 `this.mine !== null`:
|
|
|
|
|
|
* 用户点「修改」要能把它展开,而 `mine` 在**保存成功后**才会变,
|
|
|
|
|
|
* 两者不是同一个状态。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Local myFormOpen: boolean = false;
|
2026-10-28 22:29:55 +08:00
|
|
|
|
|
|
|
|
|
|
/** 评论输入(针对某条影评) */
|
|
|
|
|
|
@Local commentTarget: number = 0;
|
|
|
|
|
|
@Local commentDraft: string = '';
|
|
|
|
|
|
@Local replyingTo: number = 0; // 回复某条评论的 id;0 = 直接评论影评
|
|
|
|
|
|
@Local busy: boolean = false;
|
|
|
|
|
|
|
|
|
|
|
|
@Local note: string = '';
|
|
|
|
|
|
@Local loading: boolean = true;
|
|
|
|
|
|
|
|
|
|
|
|
/** 我是不是访客(只读)—— 拿 AppState 判断 */
|
|
|
|
|
|
private app: FbAppState = fbAppState();
|
|
|
|
|
|
|
|
|
|
|
|
aboutToAppear(): void {
|
|
|
|
|
|
this.load();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private canWrite(): boolean {
|
|
|
|
|
|
return this.app.session.me.canWrite;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async load(): Promise<void> {
|
|
|
|
|
|
this.loading = true;
|
|
|
|
|
|
const r: FbMovieReviews = await FbMovieRepo.inst().reviews(this.movieId, FB_TOKEN_STORE.get());
|
|
|
|
|
|
this.loading = false;
|
|
|
|
|
|
this.reviews = r.reviews;
|
|
|
|
|
|
this.mine = r.mine;
|
|
|
|
|
|
this.count = r.count;
|
|
|
|
|
|
this.avg = r.avg;
|
|
|
|
|
|
this.catalog = r.catalog;
|
|
|
|
|
|
if (this.mine !== null) {
|
|
|
|
|
|
this.rating = this.mine.rating;
|
|
|
|
|
|
this.pickedFeelings = this.mine.feelings.slice();
|
|
|
|
|
|
this.draft = this.mine.content;
|
|
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/* 「已评过=收起,没评过=展开」(用户 2026-11-06 选定)。
|
|
|
|
|
|
⚠️ 只在**首次加载**时决定,不能每次 load 都重置:
|
|
|
|
|
|
保存成功后 `load()` 会再跑一遍,若无条件按 `mine !== null` 赋 false,
|
|
|
|
|
|
用户刚写完评价、表单立刻收起来 —— 看着像"没保存成功"。
|
|
|
|
|
|
⇒ 用 `loading` 之前那个「首轮」标记控制(见 myFormTouched)。 */
|
|
|
|
|
|
if (!this.myFormTouched) {
|
|
|
|
|
|
this.myFormOpen = this.mine === null;
|
|
|
|
|
|
this.myFormTouched = true;
|
|
|
|
|
|
}
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 表单开合是否已被"用户意图"或"首轮加载"定过。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 为什么要这个标记:`load()` 在保存/删除后都会重跑,
|
|
|
|
|
|
* 若无条件按 `mine` 重置 `myFormOpen`,刚写完评价表单就自己收起,
|
|
|
|
|
|
* 用户会以为没保存成功。⇒ 只有第一轮才按"写没写过"决定。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Local myFormTouched: boolean = false;
|
|
|
|
|
|
|
2026-10-28 22:29:55 +08:00
|
|
|
|
private catalogKeys(): string[] {
|
|
|
|
|
|
return Object.keys(this.catalog);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private featText(key: string): string {
|
|
|
|
|
|
const v: string | undefined = this.catalog[key];
|
|
|
|
|
|
return v !== undefined ? v : key;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 打星(1-10,点第 n 颗 = 选 n 分) */
|
|
|
|
|
|
private pickRating(n: number): void {
|
|
|
|
|
|
if (this.rating === n) {
|
|
|
|
|
|
this.rating = 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.rating = n;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 点一个感受 chip(多选,最多 6 个,服务端 FEELING_MAX) */
|
|
|
|
|
|
private toggleFeeling(key: string): void {
|
|
|
|
|
|
const i: number = this.pickedFeelings.indexOf(key);
|
|
|
|
|
|
if (i >= 0) {
|
|
|
|
|
|
const next: string[] = [];
|
|
|
|
|
|
for (const f of this.pickedFeelings) {
|
|
|
|
|
|
if (f !== key) {
|
|
|
|
|
|
next.push(f);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
this.pickedFeelings = next;
|
|
|
|
|
|
} else if (this.pickedFeelings.length < 6) {
|
|
|
|
|
|
this.pickedFeelings = this.pickedFeelings.concat([key]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async saveReview(): Promise<void> {
|
|
|
|
|
|
if (this.saving) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.rating < 1 || this.rating > 10) {
|
|
|
|
|
|
this.note = '请先打一个 1-10 的评分。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.draft.trim() === '') {
|
|
|
|
|
|
this.note = '评价内容不能为空。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.saving = true;
|
|
|
|
|
|
this.note = '';
|
|
|
|
|
|
const res: FbApiResult = await FbMovieRepo.inst().saveReview(
|
|
|
|
|
|
this.movieId, FB_TOKEN_STORE.get(), this.rating, this.draft.trim(), this.pickedFeelings);
|
|
|
|
|
|
this.saving = false;
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
this.note = res.error !== '' ? res.error : '没发出去,请稍后再试。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/* 保存成功 ⇒ 收起表单(用户刚写完,接着就是想看结果/评论,
|
|
|
|
|
|
而不是继续盯着输入框)。⚠️ 必须在 `load()` 之后置,否则会被
|
|
|
|
|
|
load 里"首轮"判断覆盖。 */
|
|
|
|
|
|
this.myFormOpen = false;
|
2026-10-28 22:29:55 +08:00
|
|
|
|
await this.load();
|
|
|
|
|
|
this.onChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async deleteReview(): Promise<void> {
|
|
|
|
|
|
if (this.busy) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.busy = true;
|
|
|
|
|
|
this.note = '';
|
|
|
|
|
|
const res: FbApiResult = await FbMovieRepo.inst().deleteReview(this.movieId, FB_TOKEN_STORE.get());
|
|
|
|
|
|
this.busy = false;
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
this.note = res.error !== '' ? res.error : '没删掉,请稍后再试。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/* 删掉之后「我的评价」不存在了 ⇒ 表单重新展开,让用户能再写一个
|
|
|
|
|
|
(否则会停在一个空的摘要块上)。清空草稿与打分,别把旧内容带回来。 */
|
|
|
|
|
|
this.rating = 0;
|
|
|
|
|
|
this.pickedFeelings = [];
|
|
|
|
|
|
this.draft = '';
|
|
|
|
|
|
this.myFormOpen = true;
|
2026-10-28 22:29:55 +08:00
|
|
|
|
await this.load();
|
|
|
|
|
|
this.onChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 发一条评论(或回复) */
|
|
|
|
|
|
private async submitComment(): Promise<void> {
|
|
|
|
|
|
if (this.busy) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const txt: string = this.commentDraft.trim();
|
|
|
|
|
|
if (txt === '') {
|
|
|
|
|
|
this.note = '评论内容不能为空。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.busy = true;
|
|
|
|
|
|
this.note = '';
|
|
|
|
|
|
const res: FbApiResult = await FbMovieRepo.inst().addReviewComment(
|
|
|
|
|
|
this.movieId, FB_TOKEN_STORE.get(), this.commentTarget, txt, this.replyingTo);
|
|
|
|
|
|
this.busy = false;
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
this.note = res.error !== '' ? res.error : '没发出去,请稍后再试。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.commentTarget = 0;
|
|
|
|
|
|
this.commentDraft = '';
|
|
|
|
|
|
this.replyingTo = 0;
|
|
|
|
|
|
await this.load();
|
|
|
|
|
|
this.onChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 删评论 */
|
|
|
|
|
|
private async deleteComment(cid: number): Promise<void> {
|
|
|
|
|
|
if (this.busy) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.busy = true;
|
|
|
|
|
|
const res: FbApiResult = await FbMovieRepo.inst().deleteReviewComment(
|
|
|
|
|
|
this.movieId, FB_TOKEN_STORE.get(), cid);
|
|
|
|
|
|
this.busy = false;
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
this.note = res.error !== '' ? res.error : '没删掉,请稍后再试。';
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
await this.load();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 打开「写影评」表单(已有影评时就是编辑) */
|
|
|
|
|
|
private openReviewForm(): void {
|
|
|
|
|
|
this.note = '';
|
|
|
|
|
|
// 已有影评 → 回填;没有 → 空表单
|
|
|
|
|
|
if (this.mine !== null) {
|
|
|
|
|
|
this.rating = this.mine.rating;
|
|
|
|
|
|
this.pickedFeelings = this.mine.feelings.slice();
|
|
|
|
|
|
this.draft = this.mine.content;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.rating = 0;
|
|
|
|
|
|
this.pickedFeelings = [];
|
|
|
|
|
|
this.draft = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
build() {
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/* 🔴 用户 2026-11-06:「评价与评论放在最下面,直接显示出来,可以直接评论,
|
|
|
|
|
|
不用再打开了。」
|
|
|
|
|
|
⇒ 内嵌模式只出内容(发表遮罩/圆角卡/标题栏),由详情卡在自己的
|
|
|
|
|
|
Scroll 里直接渲染。内容与独立模式**同一份** `reviewContent()`,
|
|
|
|
|
|
不抄第二份 —— 影评/评论那 300 行抄一份必然改一处漏一处。 */
|
|
|
|
|
|
if (this.embedded) {
|
|
|
|
|
|
this.reviewContent(true)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Stack({ alignContent: Alignment.Center }) {
|
|
|
|
|
|
Column()
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.height('100%')
|
|
|
|
|
|
.backgroundColor(FB_MASK)
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.onClose();
|
|
|
|
|
|
})
|
2026-10-28 22:29:55 +08:00
|
|
|
|
|
2026-11-06 07:58:45 +08:00
|
|
|
|
Column() {
|
|
|
|
|
|
FbSheetRing({ radius: FbMetric.radius, ringColor: this.accent }) {
|
|
|
|
|
|
Column({ space: 0 }) {
|
|
|
|
|
|
// ---- 标题栏 ----
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Column({ space: 2 }) {
|
|
|
|
|
|
Text('评价与评论' + (this.movieTitle !== '' ? ' · ' + this.movieTitle : ''))
|
|
|
|
|
|
.fontSize(FbMetric.fontTitle)
|
|
|
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.maxLines(1)
|
|
|
|
|
|
Text(this.summaryText())
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.maxLines(1)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
.layoutWeight(1)
|
|
|
|
|
|
.flexShrink(1)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
|
2026-11-06 07:58:45 +08:00
|
|
|
|
FbSheetClose({
|
|
|
|
|
|
onClose: (): void => {
|
|
|
|
|
|
this.onClose();
|
|
|
|
|
|
},
|
|
|
|
|
|
color: this.accent
|
|
|
|
|
|
})
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
2026-11-06 07:58:45 +08:00
|
|
|
|
.padding({ bottom: 8 })
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
|
|
|
|
|
|
if (this.note !== '') {
|
|
|
|
|
|
Text(this.note)
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.red)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ top: 6, bottom: 6 })
|
|
|
|
|
|
.maxLines(3)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Scroll() {
|
|
|
|
|
|
this.reviewContent(false)
|
|
|
|
|
|
}
|
|
|
|
|
|
.constraintSize({ maxHeight: 520 })
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.scrollBar(BarState.Off)
|
|
|
|
|
|
.align(Alignment.TopStart)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
2026-11-06 07:58:45 +08:00
|
|
|
|
.padding({ left: 18, right: 18, top: 18, bottom: 18 })
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
.width('92%')
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
2026-11-06 07:58:45 +08:00
|
|
|
|
.width('100%')
|
|
|
|
|
|
.height('100%')
|
|
|
|
|
|
.hitTestBehavior(HitTestMode.Transparent)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-11-06 07:58:45 +08:00
|
|
|
|
/** 标题下方那句统计(独立模式用;内嵌模式由详情卡的区块标题承担) */
|
|
|
|
|
|
private summaryText(): string {
|
|
|
|
|
|
if (this.loading) {
|
|
|
|
|
|
return '正在加载…';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.count > 0) {
|
|
|
|
|
|
return this.count.toString() + ' 条评价 · 均分 ' + this.avg.toFixed(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
return '还没有评价,等你来评一个';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 评价与评论的正文(两种形态共用)。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param inner 是否为内嵌模式 —— 内嵌时不加额外上下留白
|
|
|
|
|
|
* (宿主已经在卡片里排好了间距,再补会多一截空)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Builder
|
|
|
|
|
|
reviewContent(inner: boolean) {
|
|
|
|
|
|
Column({ space: 12 }) {
|
|
|
|
|
|
// ---- 我的影评(写 / 改 / 删)----
|
|
|
|
|
|
if (this.canWrite()) {
|
|
|
|
|
|
this.myReviewBlock()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ---- 全部影评 + 评论 ----
|
|
|
|
|
|
if (this.reviews.length === 0 && !this.loading) {
|
|
|
|
|
|
Text('还没有评价')
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
} else {
|
|
|
|
|
|
ForEach(this.reviews, (rv: FbMovieReview) => {
|
|
|
|
|
|
this.reviewBlock(rv)
|
|
|
|
|
|
}, (rv: FbMovieReview): string => 'mvr_' + rv.id.toString())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ top: inner ? 0 : 4, bottom: inner ? 0 : 20 })
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 我的影评区块。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 两个态(用户 2026-11-06 选定「已评过=收起,没评过=展开」):
|
|
|
|
|
|
* · `myFormOpen === false` 且已写过 → **摘要态**:评分 + 感受 + 正文摘要
|
|
|
|
|
|
* +「修改 / 删除」,只占几行,把空间让给下面的评论;
|
|
|
|
|
|
* · `myFormOpen === true` 或无评价 → **表单态**:打分 + 感受 + 正文 + 发表。
|
|
|
|
|
|
*/
|
2026-10-28 22:29:55 +08:00
|
|
|
|
@Builder
|
|
|
|
|
|
myReviewBlock() {
|
2026-11-06 07:58:45 +08:00
|
|
|
|
if (this.mine !== null && !this.myFormOpen) {
|
|
|
|
|
|
this.myReviewSummary()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.myReviewForm()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 收起态:我写过的评价摘要 + 改/删 */
|
|
|
|
|
|
@Builder
|
|
|
|
|
|
myReviewSummary() {
|
|
|
|
|
|
Column({ space: 6 }) {
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Text('我的评价')
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontWeight(FontWeight.Bold)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.letterSpacing(0.6)
|
|
|
|
|
|
Blank()
|
|
|
|
|
|
Text('修改')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.myFormOpen = true;
|
|
|
|
|
|
})
|
|
|
|
|
|
Text('删除')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.red)
|
|
|
|
|
|
.padding({ left: 6, right: 2, top: 4, bottom: 4 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.deleteReview();
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
|
|
|
|
|
|
if (this.mine !== null) {
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Text('★ ' + this.mine.rating.toFixed(0))
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor('#C08A2E')
|
|
|
|
|
|
if (this.mine.feelings.length > 0) {
|
|
|
|
|
|
Text(this.mine.feelings.map((k: string): string => this.featText(k)).join(' · '))
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.muted)
|
|
|
|
|
|
.maxLines(1)
|
|
|
|
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
|
.layoutWeight(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
|
|
|
|
|
|
if (this.mine.content !== '') {
|
|
|
|
|
|
Text(this.mine.content)
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.maxLines(3)
|
|
|
|
|
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding(12)
|
|
|
|
|
|
.backgroundColor(fbAlpha(this.accent, 0.06))
|
|
|
|
|
|
.borderRadius(FbMetric.radiusS)
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 展开态:写 / 改评价的表单 */
|
|
|
|
|
|
@Builder
|
|
|
|
|
|
myReviewForm() {
|
2026-10-28 22:29:55 +08:00
|
|
|
|
Column({ space: 8 }) {
|
2026-11-06 08:44:36 +08:00
|
|
|
|
/* 🔴 用户 2026-11-06:「下面的写评价不要了,三个字。」
|
|
|
|
|
|
⇒ 整行只在「有评价(要显示改/删/收起)」或「没要求隐藏标题」时才画。
|
|
|
|
|
|
内嵌 + 未评过 = 整行不存在,直接从「评分」开始,不浪费一行高度。
|
|
|
|
|
|
⚠️ 有评价时**不能**整行删掉:修改/删除/收起三颗按钮就在这行右边。 */
|
|
|
|
|
|
if (this.mine !== null || !this.hideFormTitle) {
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
if (!this.hideFormTitle) {
|
|
|
|
|
|
Text(this.mine !== null ? '我的评价' : '写评价')
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontWeight(FontWeight.Bold)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.letterSpacing(0.6)
|
|
|
|
|
|
}
|
|
|
|
|
|
Blank()
|
|
|
|
|
|
if (this.mine !== null) {
|
|
|
|
|
|
Text('收起')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.muted)
|
|
|
|
|
|
.padding({ left: 6, right: 4, top: 4, bottom: 4 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.myFormOpen = false;
|
|
|
|
|
|
})
|
|
|
|
|
|
Text('删除')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.red)
|
|
|
|
|
|
.padding({ left: 8, right: 2, top: 4, bottom: 4 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.deleteReview();
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
2026-11-06 08:44:36 +08:00
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
2026-10-28 22:29:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打分(1-10 颗星)
|
|
|
|
|
|
Column({ space: 6 }) {
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Text('评分')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
Row({ space: 2 }) {
|
|
|
|
|
|
ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (i: number) => {
|
|
|
|
|
|
Text(starOn(i, this.rating) ? '★' : '☆')
|
|
|
|
|
|
.fontSize(18)
|
|
|
|
|
|
.fontColor(starOn(i, this.rating) ? '#C08A2E' : FbColors.line2)
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.pickRating(i);
|
|
|
|
|
|
})
|
|
|
|
|
|
}, (i: number): string => 'star_' + i.toString())
|
|
|
|
|
|
}
|
|
|
|
|
|
Text(this.rating > 0 ? this.rating.toString() + ' 分' : '未评分')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
}
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
|
|
|
|
|
|
// 感受多选
|
|
|
|
|
|
if (this.catalogKeys().length > 0) {
|
|
|
|
|
|
Column({ space: 6 }) {
|
|
|
|
|
|
Text('观后感受(可多选)')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
Flex({ wrap: FlexWrap.Wrap }) {
|
|
|
|
|
|
ForEach(this.catalogKeys(), (k: string) => {
|
|
|
|
|
|
Text(this.featText(k))
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(this.pickedFeelings.indexOf(k) >= 0 ? '#FFFFFF' : FbColors.ink)
|
|
|
|
|
|
.padding({ left: 10, right: 10, top: 5, bottom: 5 })
|
|
|
|
|
|
.backgroundColor(this.pickedFeelings.indexOf(k) >= 0
|
|
|
|
|
|
? this.accent : FbColors.inputBg)
|
|
|
|
|
|
.borderRadius(FbMetric.radiusPill)
|
|
|
|
|
|
.margin({ right: 6, bottom: 6 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.toggleFeeling(k);
|
|
|
|
|
|
})
|
|
|
|
|
|
}, (k: string): string => 'feel_' + k)
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 正文
|
|
|
|
|
|
TextArea({ text: this.draft, placeholder: '写下你对这部电影的评价…' })
|
|
|
|
|
|
.placeholderColor(FbColors.faint)
|
|
|
|
|
|
.placeholderFont({ size: FbMetric.fontTiny })
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.backgroundColor(FbColors.inputBg)
|
|
|
|
|
|
.borderRadius(FbMetric.radiusS)
|
|
|
|
|
|
.height(90)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ left: 10, right: 10, top: 8, bottom: 8 })
|
|
|
|
|
|
.onChange((v: string): void => {
|
|
|
|
|
|
this.draft = v;
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
Text(this.mine !== null ? '保存修改' : '发表评价')
|
|
|
|
|
|
.fontSize(FbMetric.fontBody)
|
|
|
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
|
|
|
.fontColor(this.saving ? FbColors.faint : '#FFFFFF')
|
|
|
|
|
|
.textAlign(TextAlign.Center)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.height(42)
|
|
|
|
|
|
.borderRadius(FbMetric.radiusS)
|
|
|
|
|
|
.backgroundColor(fbAlpha(this.accent, this.saving ? 0.4 : 0.96))
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.saveReview();
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ bottom: 10 })
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 一条影评(含评论树) */
|
|
|
|
|
|
@Builder
|
|
|
|
|
|
reviewBlock(rv: FbMovieReview) {
|
|
|
|
|
|
Column({ space: 8 }) {
|
|
|
|
|
|
// 影评头
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
FbAvatar({ name: rv.name, color: rv.color, dia: 30 })
|
|
|
|
|
|
Column({ space: 2 }) {
|
|
|
|
|
|
Text(rv.name)
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
Row({ space: 6 }) {
|
|
|
|
|
|
Text('★ ' + rv.rating.toFixed(0))
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor('#C08A2E')
|
|
|
|
|
|
if (rv.feelings.length > 0) {
|
|
|
|
|
|
Text(rv.feelings.map((k: string): string => this.featText(k).split(' ')[0]).join(''))
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.muted)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
}
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
.layoutWeight(1)
|
|
|
|
|
|
if (rv.mine) {
|
|
|
|
|
|
Text('我写的')
|
|
|
|
|
|
.fontSize(10)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Top)
|
|
|
|
|
|
|
|
|
|
|
|
Text(rv.content)
|
|
|
|
|
|
.fontSize(FbMetric.fontSmall)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
|
|
|
|
|
|
// 评论列表
|
|
|
|
|
|
if (rv.comments.length > 0) {
|
|
|
|
|
|
Column({ space: 6 }) {
|
|
|
|
|
|
ForEach(rv.comments, (c: FbMovieComment) => {
|
|
|
|
|
|
this.commentRow(rv.id, c)
|
|
|
|
|
|
}, (c: FbMovieComment): string => 'c_' + c.id.toString())
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ left: 8 })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 评论入口
|
|
|
|
|
|
if (this.canWrite()) {
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Text('发表评论')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.padding({ left: 8, right: 8, top: 5, bottom: 5 })
|
|
|
|
|
|
.borderRadius(FbMetric.radiusPill)
|
|
|
|
|
|
.backgroundColor(fbAlpha(this.accent, 0.08))
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.commentTarget = rv.id;
|
|
|
|
|
|
this.replyingTo = 0;
|
|
|
|
|
|
this.commentDraft = '';
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 评论输入框(针对这条影评展开时)
|
|
|
|
|
|
if (this.commentTarget === rv.id) {
|
|
|
|
|
|
Column({ space: 6 }) {
|
|
|
|
|
|
TextArea({ text: this.commentDraft, placeholder: this.replyingTo > 0 ? '写下回复…' : '写下评论…' })
|
|
|
|
|
|
.placeholderColor(FbColors.faint)
|
|
|
|
|
|
.placeholderFont({ size: FbMetric.fontTiny })
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.backgroundColor(FbColors.inputBg)
|
|
|
|
|
|
.borderRadius(FbMetric.radiusS)
|
|
|
|
|
|
.height(60)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ left: 8, right: 8, top: 6, bottom: 6 })
|
|
|
|
|
|
.onChange((v: string): void => {
|
|
|
|
|
|
this.commentDraft = v;
|
|
|
|
|
|
})
|
|
|
|
|
|
Row({ space: 8 }) {
|
|
|
|
|
|
Text('取消')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.muted)
|
|
|
|
|
|
.padding({ left: 8, right: 8, top: 5, bottom: 5 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.commentTarget = 0;
|
|
|
|
|
|
this.commentDraft = '';
|
|
|
|
|
|
this.replyingTo = 0;
|
|
|
|
|
|
})
|
|
|
|
|
|
Blank()
|
|
|
|
|
|
Text(this.busy ? '发不出…' : '发送')
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor('#FFFFFF')
|
|
|
|
|
|
.padding({ left: 14, right: 14, top: 6, bottom: 6 })
|
|
|
|
|
|
.borderRadius(FbMetric.radiusPill)
|
|
|
|
|
|
.backgroundColor(this.accent)
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.submitComment();
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ left: 8 })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Divider()
|
|
|
|
|
|
.color(FbColors.line)
|
|
|
|
|
|
.margin({ top: 4 })
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(HorizontalAlign.Start)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 一条评论(含回复) */
|
|
|
|
|
|
@Builder
|
|
|
|
|
|
commentRow(reviewId: number, c: FbMovieComment) {
|
|
|
|
|
|
Column({ space: 4 }) {
|
|
|
|
|
|
Row({ space: 6 }) {
|
|
|
|
|
|
Text(c.name)
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontWeight(FontWeight.Medium)
|
|
|
|
|
|
.fontColor(FbColors.muted)
|
|
|
|
|
|
if (c.replyTo !== '') {
|
|
|
|
|
|
Text('回复 ' + c.replyTo)
|
|
|
|
|
|
.fontSize(10)
|
|
|
|
|
|
.fontColor(FbColors.faint)
|
|
|
|
|
|
}
|
|
|
|
|
|
Blank()
|
|
|
|
|
|
if (c.mine) {
|
|
|
|
|
|
Text('删')
|
|
|
|
|
|
.fontSize(10)
|
|
|
|
|
|
.fontColor(FbColors.red)
|
|
|
|
|
|
.padding({ left: 4, right: 2 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.deleteComment(c.id);
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.canWrite()) {
|
|
|
|
|
|
Text('回复')
|
|
|
|
|
|
.fontSize(10)
|
|
|
|
|
|
.fontColor(this.accent)
|
|
|
|
|
|
.padding({ left: 4, right: 2 })
|
|
|
|
|
|
.onClick((): void => {
|
|
|
|
|
|
this.commentTarget = reviewId;
|
|
|
|
|
|
this.replyingTo = c.id;
|
|
|
|
|
|
this.commentDraft = '';
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.alignItems(VerticalAlign.Center)
|
|
|
|
|
|
|
|
|
|
|
|
Text(c.content)
|
|
|
|
|
|
.fontSize(FbMetric.fontTiny)
|
|
|
|
|
|
.fontColor(FbColors.ink)
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
|
|
|
|
|
|
// 回复
|
|
|
|
|
|
if (c.replies.length > 0) {
|
|
|
|
|
|
Column({ space: 4 }) {
|
|
|
|
|
|
ForEach(c.replies, (r: FbMovieComment) => {
|
|
|
|
|
|
this.commentRow(reviewId, r)
|
|
|
|
|
|
}, (r: FbMovieComment): string => 'cr_' + r.id.toString())
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
.padding({ left: 10 })
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
.width('100%')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|