v91 观影/任务卡加 4x4/6x4(滚动列表+新建+卡上完成任务);修任务卡无数据(解析器用错:看板嵌套需 parseTasks)

This commit is contained in:
2026-10-25 09:29:41 +08:00
parent 6711197a94
commit 7ae34e6e23
12 changed files with 1042 additions and 9 deletions
+54 -5
View File
@@ -19,7 +19,8 @@ import { FB_SERVER_STORE } from './FbServerStore';
import { FB_TOKEN_STORE } from './FbTokenStore';
import { fbApi, FbApiResult, FbApiOptions } from './FbHttp';
import { fbCardBuild, FbCardData } from './FbCardData';
import { parseTaskList } from './FbParse';
import { parseTasks } from './FbParse';
import { setTaskStatus } from './FbTaskRepo';
import { FbTaskItem } from '../model/Types';
const DOMAIN: number = 0x0000;
@@ -85,6 +86,8 @@ export class FbMovieCardData {
totalCount: number = 0;
/** 最近观影(按日期倒序,最多 4 条) */
recentJson: string = '[]';
/** 🔴 v91:4×4/6×4 的滚动列表(按日期倒序,最多 30 条)—— 4×2 的卡不吃这个字段 */
listJson: string = '[]';
/** 🔴 v89 教训:ForEach key 前缀源 */
version: string = '';
}
@@ -200,6 +203,15 @@ export async function fbMovieCardBuild(ctx: common.Context): Promise<FbMovieCard
rows.push(movieRowOf(arr[i], i));
}
out.recentJson = JSON.stringify(rows);
/* v91:4×4/6×4 的滚动列表 —— 全量倒序(最多 30 条,够滑一阵子;
200 条全塞会让 FormBindingData 序列化白白变大,卡片也展示不了那么多)。 */
const list: FbMovieCardRow[] = [];
for (let i = 0; i < arr.length && list.length < 30; i++) {
list.push(movieRowOf(arr[i], i));
}
out.listJson = JSON.stringify(list);
out.state = 'ok';
out.hint = '';
return out;
@@ -212,6 +224,8 @@ export async function fbMovieCardBuild(ctx: common.Context): Promise<FbMovieCard
/** 任务卡上的一行 */
export class FbTaskCardRow {
key: string = '';
/** 🔴 v91:任务 id —— 卡片上点「完成」要靠它告诉 FbFormAbility 改哪条 */
id: number = 0;
title: string = '';
/** 截止时间文案(服务端给的显示文本,空 = 没有期限) */
dueText: string = '';
@@ -231,8 +245,10 @@ export class FbTaskCardData {
openCount: number = 0;
/** 其中逾期数(标题行给红色提示) */
overdueCount: number = 0;
/** 优先展示的几条(逾期 > 进行中 > 普通,同组按截止时间升序),最多 4 条 */
/** 逾期优先展示的几条(逾期 > 进行中 > 普通,同组按截止时间升序),最多 4 条 */
rowsJson: string = '[]';
/** 🔴 v91:4×4/6×4 的滚动列表(同一排序,最多 30 条)—— 2×2/2×4 的卡不吃这个字段 */
allJson: string = '[]';
version: string = '';
}
@@ -247,6 +263,7 @@ function taskRank(t: FbTaskItem): number {
/** 一条任务 → 卡片行 */
function taskRowOf(t: FbTaskItem): FbTaskCardRow {
const r: FbTaskCardRow = new FbTaskCardRow();
r.id = t.id;
r.key = 't' + t.id.toString() + '_' + t.status;
r.title = t.title !== '' ? t.title : '未命名任务';
r.dueText = t.dueText;
@@ -259,8 +276,12 @@ function taskRowOf(t: FbTaskItem): FbTaskCardRow {
/**
* 组装任务卡数据(异步,**永远不抛错**)。
*
* ⚠️ `/api/v1/tasks` 默认视图就是"未完成任务"(已完成走 `?view=done`);
* 这里仍按 status 过滤一道,服务端口径将来变了也不会把 done 显示成待办。
* 🔴🔴 v91 修「任务卡片没有数据」:`/api/v1/tasks` 默认视图回的是
* **看板嵌套**结构 `{ok, data:{boards:[{name,color,tasks:[…]}]}}`,
* 原来用 `parseTaskList()`(只认扁平数组)⇒ 解析成 0 条,卡片永远空。
* 改用 `parseTasks()` —— 它就是任务页看板视图用的那个扁平化解析
* (顺带把**看板色**也填进每行,卡片色条不再全是兜底色)。
* 完成态仍按 status 过滤一道,服务端口径将来变了也不会把 done 显示成待办。
*/
export async function fbTaskCardBuild(ctx: common.Context): Promise<FbTaskCardData> {
const out: FbTaskCardData = new FbTaskCardData();
@@ -290,7 +311,7 @@ export async function fbTaskCardBuild(ctx: common.Context): Promise<FbTaskCardDa
let items: FbTaskItem[] = [];
try {
items = parseTaskList(r.data);
items = parseTasks(r.data);
} catch (err) {
hilog.warn(DOMAIN, TAG, '任务卡数据解析失败');
}
@@ -335,11 +356,39 @@ export async function fbTaskCardBuild(ctx: common.Context): Promise<FbTaskCardDa
rows.push(taskRowOf(open[i]));
}
out.rowsJson = JSON.stringify(rows);
/* v91:4×4/6×4 的滚动列表 —— 同一排序全量(最多 30 条) */
const all: FbTaskCardRow[] = [];
for (let i = 0; i < open.length && all.length < 30; i++) {
all.push(taskRowOf(open[i]));
}
out.allJson = JSON.stringify(all);
out.state = 'ok';
out.hint = '';
return out;
}
/**
* 🔴 v91:卡片上点「完成」—— 把任务标成 done,然后重算一份数据。
*
* ⚠️ 由 `FbFormAbility.onFormEvent` 调用(卡片自己不能发网络请求)。
* ⚠️ 标记失败(断网/401)**不抛错**:照旧重算返回旧数据,
* 用户顶多看到"没变化",不能让 FormExtensionAbility 死在半路。
* ⚠️ 401 也不踢登录(`authProbe: true`,与卡片取数同口径)。
*/
export async function fbTaskCardComplete(ctx: common.Context, id: number): Promise<FbTaskCardData> {
const token: string = await cardToken(ctx);
if (token !== '' && FB_SERVER_STORE.get() !== '') {
try {
await setTaskStatus(token, id, 'done');
} catch (err) {
hilog.warn(DOMAIN, TAG, '卡片完成任务 %{public}d 失败', id);
}
}
return fbTaskCardBuild(ctx);
}
/* ══════════════════════════════════════════════════════════════
按卡片类型分流
══════════════════════════════════════════════════════════════ */