This repository has been archived on 2026-09-13. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BPOS-TMP-REPO/apps/api/src/app/__tests__/activity-ops-summaries.test.ts
T
xcsandClaude Fable 5 0923fbfe4d feat(ops): 运营中心 · 活动模块接口落地 —— L1/L2/L3 十一条(全 ops)+ 设计端活动库两条改名让位
`apps/api/src/app/activity-ops/*`(service / store / instance-state / instance-steps / launch-params /
summaries / view-html / view-scope)+ `routes/activities.ts`;契约 `activity-ops.ts` / `api/activity-ops.ts`
(与队友按文档补的那版 43 个导出同名,多 INSTANCE_REASON_KINDS / STEP_RESULTS / launchOptionSchema);
迁移 0035_activity_ops;《API文档-活动模块》按契约回写。
设计端活动库 GET/POST `/api/gov/activities` 改名 `/api/gov/activity-packages`,`/api/gov/activities/*`
整个让给运营端(前端 import 路由对象,零改动);activity-registry CONTRACT.md 与路由总表同步。
2026-08-27 另一会话做的,一直留在工作树没入库;与同批另两条提交互相依赖,以合并提交为验证单位。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167qWjeyBwvfdGovd7FWbCu
2026-08-27 23:20:15 +08:00

77 lines
4.1 KiB
TypeScript

/** 清单一句话与检索 */
import { describe, expect, it } from 'vitest';
import type { InstanceSummary } from '@contracts';
import { staffIdSchema } from '@contracts';
import { fieldSpecsOf } from '../activity-ops/launch-params.ts';
import { applyInstanceFilters, clip, inputFilesOf, inputSummaryOf, outputSummaryOf, pageOf, statsOf } from '../activity-ops/summaries.ts';
const specs = fieldSpecsOf({
properties: {
customerCode: { type: 'string' },
requestDescription: { type: 'string', 'x-control': 'textarea' },
datasheets: { type: 'array', format: 'file' },
},
});
describe('inputSummaryOf / inputFilesOf / outputSummaryOf', () => {
it('textarea 那格优先;没有就最长的字符串;再没有退回来件主题;文件字段不算', () => {
expect(inputSummaryOf({ customerCode: 'CU-0142', requestDescription: ' 工业电源项目\n在用 LM2596S-5.0 ' }, specs)).toBe('工业电源项目 在用 LM2596S-5.0');
expect(inputSummaryOf({ customerCode: 'CU-0142', datasheets: [{ ref: 'r', name: 'a-very-long-file-name.pdf' }] }, specs)).toBe('CU-0142');
expect(inputSummaryOf({}, specs, 'RE: 询价')).toBe('RE: 询价');
expect(inputSummaryOf({}, specs)).toBe('');
expect(clip('x'.repeat(100))).toHaveLength(80);
expect(clip('x'.repeat(100)).endsWith('…')).toBe(true);
});
it('文件只认带 ref 的;index 跨字段连续', () => {
const files = inputFilesOf({ datasheets: [{ name: 'a.pdf', contentType: 'application/pdf', size: 10, ref: 'u-1' }, { name: 'no-ref' }, 'junk'] }, specs);
expect(files).toEqual([{ index: 0, name: 'a.pdf', contentType: 'application/pdf', size: 10, ref: 'u-1' }]);
});
it('产出:有文件摆文件名;没有摆发口;都没有 null', () => {
expect(outputSummaryOf(['报告.docx', '对照表.xlsx'], ['x'])).toBe('报告.docx、对照表.xlsx');
expect(outputSummaryOf([], ['assessment-released'])).toBe('已发口:assessment-released');
expect(outputSummaryOf([], [])).toBeNull();
});
});
const owner = { id: 's-1', name: '柴浩' };
const mk = (id: string, no: string, state: InstanceSummary['state'], startedAt: string, ownerId = 's-1'): InstanceSummary => ({
id,
no,
state,
owner: { id: staffIdSchema.parse(ownerId), name: owner.name },
input: 'x',
output: null,
startedAt,
});
const items = [
mk('t-aaa', 'INS-24', 'running', '2026-08-25T02:12:00.000Z'),
mk('t-bbb', 'INS-17', 'completed', '2026-08-24T09:03:00.000Z', 's-2'),
mk('t-ccc', 'INS-9', 'failed', '2026-08-20T01:00:00.000Z'),
];
describe('applyInstanceFilters / statsOf / pageOf', () => {
it('实例号模糊、负责人精确、状态精确、日期段含两端整日(本地时区)', () => {
expect(applyInstanceFilters(items, { id: 'ins-2' }).map((i) => i.no)).toEqual(['INS-24']);
expect(applyInstanceFilters(items, { id: 'bbb' }).map((i) => i.no)).toEqual(['INS-17']);
expect(applyInstanceFilters(items, { ownerId: 's-2' }).map((i) => i.no)).toEqual(['INS-17']);
expect(applyInstanceFilters(items, { state: 'failed' }).map((i) => i.no)).toEqual(['INS-9']);
const day = (iso: string) => {
const d = new Date(iso);
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
};
expect(applyInstanceFilters(items, { startedFrom: day('2026-08-24T09:03:00.000Z'), startedTo: day('2026-08-24T09:03:00.000Z') }).map((i) => i.no)).toEqual(['INS-17']);
expect(applyInstanceFilters(items, { startedFrom: day('2026-08-24T09:03:00.000Z') }).map((i) => i.no)).toEqual(['INS-24', 'INS-17']);
expect(applyInstanceFilters(items, { startedTo: day('2026-08-20T01:00:00.000Z') }).map((i) => i.no)).toEqual(['INS-9']);
expect(applyInstanceFilters(items, {})).toHaveLength(3);
});
it('统计五键齐;分页越界给空', () => {
expect(statsOf(items)).toEqual({ total: 3, byState: { pending: 0, running: 1, completed: 1, rejected: 0, failed: 1 } });
expect(pageOf(items, 1, 2).map((i) => i.no)).toEqual(['INS-24', 'INS-17']);
expect(pageOf(items, 2, 2).map((i) => i.no)).toEqual(['INS-9']);
expect(pageOf(items, 3, 2)).toEqual([]);
});
});