工作成果里摆着别单的资料:「这一单产出的」认本单碰过的行

放行存档(archiveAssetFiles)与在办列单(assetFilesOf)取行都用 taskView(where:{}) ——
那是「正式版全表 + 本单草稿」的合并视图,而资料常落在主数据上,整表里躺着别单放行过的行。
抽 assetRowsOf 两处同用,touched 为必填入参;e2e 补份数断言。
顺手清两笔:wake.test.ts 的 as unknown as(lint 红)、wake 契约的 api-report 快照(api:check 红)。
This commit is contained in:
xcs
2026-08-25 15:38:10 +08:00
parent 094386f02c
commit d788140548
9 changed files with 260 additions and 57 deletions
+13 -19
View File
@@ -28,7 +28,7 @@ import {
} from '@contracts';
import { ReplyRejectedError } from '@modules/human-tool';
import { advanceOrder } from '@modules/process';
import { keyText, listArchived, readArchived } from '../asset-archive.ts';
import { assetRowsOf, keyText, listArchived, readArchived } from '../asset-archive.ts';
import { composeFile, isFileFormat, MIME_OF, safeFileName, type FileFormat } from '../file-compose.ts';
import { toFileDoc } from '../file-doc.ts';
import { displayLog } from './log-lines.ts';
@@ -510,6 +510,9 @@ async function landingOf(
* 两个来源,**存档优先**:放行之后那一份已经冻住(归档件点开的必须是他签字那一刻
* 的那一份);在办期间还没有存档,就照台账现列 —— 人在审的那几份也该看得见。
* 认行一律 `address + key`,与件上 `data-file` 那一串同一形状:点开走同一条路。
*
* 在办这一路挑哪几行与存档同一段(`assetRowsOf`):认**本单碰过的行**,
* 不是这张表里现有的所有行 —— 两处各写一份的下场见那段的病根记档。
*/
async function assetFilesOf(
container: Container,
@@ -529,12 +532,11 @@ async function assetFilesOf(
}
const declarations = await declarationsOf(container, taskId);
// 本单碰过的行 —— 「这一单产出的」只有这一个答案(整表里还躺着别单放行过的资产)
const touched = await container.ledger.taskDrafts(taskId).catch(() => []);
const out: Array<{ address: string; key: string; title: string; format: string; name: string; archived: boolean }> = [];
for (const declared of declarations ?? []) {
const spec = declared.file;
if (spec === undefined) continue;
const keys = declared.fields.filter((f) => f.primaryKey).map((f) => f.name);
if (keys.length === 0) continue;
if (declared.file === undefined) continue;
const page = await container.ledger
.taskView(taskId, {
address: { domain: declared.domain, object: declared.object },
@@ -544,21 +546,13 @@ async function assetFilesOf(
offset: 0,
})
.catch(() => ({ rows: [] as Array<Record<string, unknown>> }));
for (const row of page.rows) {
// 没正文的行不是资料 —— 摆出来点开只会落一句「还没产出」
if (String(row[spec.bodyColumn] ?? '').trim() === '') continue;
const key: Record<string, string> = {};
for (const k of keys) key[k] = String(row[k] ?? '');
if (Object.values(key).some((v) => v === '')) continue;
const rawFormat = String(row[spec.formatColumn] ?? '').trim().toLowerCase();
const format = isFileFormat(rawFormat) ? rawFormat : 'md';
const title = String(row[spec.titleColumn] ?? '').trim() || Object.values(key).join('-');
for (const asset of assetRowsOf(declared, page.rows as Array<Record<string, unknown>>, touched)) {
out.push({
address: `${declared.domain}.${declared.object}`,
key: keyText(key),
title,
format,
name: safeFileName(title, format),
address: asset.address,
key: keyText(asset.key),
title: asset.title,
format: asset.format,
name: safeFileName(asset.title, asset.format),
archived: false,
});
}