feat(产品方案): 优化计划卡片展示和排序
This commit is contained in:
37
apps/web/lib/version-plan.test.ts
Normal file
37
apps/web/lib/version-plan.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import * as versionPlan from './version-plan';
|
||||
import type { VersionPlan } from './version-plan';
|
||||
|
||||
function plan(patch: Partial<VersionPlan>): VersionPlan {
|
||||
return {
|
||||
id: 'plan-1',
|
||||
versionId: 'version-1',
|
||||
type: 'product',
|
||||
title: '产品方案',
|
||||
owner: 'PM',
|
||||
startTime: '2026-06-25T09:00',
|
||||
endTime: '2026-06-25T18:00',
|
||||
status: 'pending',
|
||||
createdAt: '2026-06-25',
|
||||
addedBy: 'PM',
|
||||
...patch,
|
||||
};
|
||||
}
|
||||
|
||||
test('sortPlansNewestFirst places newly created plans before older plans', () => {
|
||||
const sortPlansNewestFirst = (versionPlan as any).sortPlansNewestFirst as undefined | ((plans: VersionPlan[]) => VersionPlan[]);
|
||||
assert.equal(typeof sortPlansNewestFirst, 'function');
|
||||
|
||||
const plans = [
|
||||
plan({ id: 'plan-100', createdAt: '2026-06-26' }),
|
||||
plan({ id: 'manual-old', createdAt: '2026-06-25' }),
|
||||
plan({ id: 'plan-300', createdAt: '2026-06-26' }),
|
||||
];
|
||||
|
||||
const sorted = (sortPlansNewestFirst as (items: VersionPlan[]) => VersionPlan[])(plans);
|
||||
|
||||
assert.deepEqual(sorted.map((item) => item.id), ['plan-300', 'plan-100', 'manual-old']);
|
||||
assert.deepEqual(plans.map((item) => item.id), ['plan-100', 'manual-old', 'plan-300']);
|
||||
});
|
||||
@@ -78,6 +78,26 @@ export interface VersionPlan {
|
||||
|
||||
export type PlanType = VersionPlan['type'];
|
||||
|
||||
function getPlanCreatedAtTime(plan: VersionPlan): number {
|
||||
const time = new Date(plan.createdAt).getTime();
|
||||
return Number.isFinite(time) ? time : 0;
|
||||
}
|
||||
|
||||
function getPlanIdTime(plan: VersionPlan): number {
|
||||
const match = /^plan-(\d+)$/.exec(plan.id);
|
||||
if (!match) return 0;
|
||||
const time = Number(match[1]);
|
||||
return Number.isFinite(time) ? time : 0;
|
||||
}
|
||||
|
||||
export function sortPlansNewestFirst(plans: VersionPlan[]): VersionPlan[] {
|
||||
return [...plans].sort((a, b) => {
|
||||
const createdDiff = getPlanCreatedAtTime(b) - getPlanCreatedAtTime(a);
|
||||
if (createdDiff !== 0) return createdDiff;
|
||||
return getPlanIdTime(b) - getPlanIdTime(a);
|
||||
});
|
||||
}
|
||||
|
||||
export function calcPlanProgress(tasks?: PlanTask[]): number {
|
||||
if (!tasks || tasks.length === 0) return 0;
|
||||
const completed = tasks.filter((t) => t.status === 'completed').length;
|
||||
|
||||
Reference in New Issue
Block a user