feat(projects): 工作台部分组件调成真实数据
This commit is contained in:
@@ -10,8 +10,6 @@ export type WorkbenchTodoDeadlineFilter = 'overdue' | 'today' | 'week' | null;
|
||||
|
||||
export type WorkbenchTodoPriority = 'high' | 'mid' | 'low';
|
||||
|
||||
export type WorkbenchProjectStatus = 'active' | 'preview' | 'paused';
|
||||
|
||||
export interface WorkbenchKpiSource {
|
||||
/** 待办 */
|
||||
todo: {
|
||||
@@ -96,28 +94,17 @@ export interface WorkbenchActivityItem extends Omit<WorkbenchActivityItemSource,
|
||||
tone: 'sky' | 'emerald' | 'amber' | 'rose' | 'violet';
|
||||
}
|
||||
|
||||
export interface WorkbenchProjectItemSource {
|
||||
/** 「我参与的项目」展示项(由 Api.Project.MyParticipatedProjectItem 衍生) */
|
||||
export interface WorkbenchParticipatedProjectView {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
status: WorkbenchProjectStatus;
|
||||
/** 我的角色 */
|
||||
myRole: string;
|
||||
/** 进度百分比 0-100 */
|
||||
progress: number;
|
||||
/** 我负责的任务数 */
|
||||
myTaskCount: number;
|
||||
/** 我负责的待处理任务数 */
|
||||
myPendingTaskCount: number;
|
||||
/** 最近活动时间,ISO */
|
||||
lastActiveTime: string;
|
||||
}
|
||||
|
||||
export interface WorkbenchProjectItem extends Omit<WorkbenchProjectItemSource, 'lastActiveTime'> {
|
||||
statusLabel: string;
|
||||
code: string | null;
|
||||
statusName: string | null;
|
||||
statusTone: 'sky' | 'emerald' | 'amber';
|
||||
myRole: string | null;
|
||||
progress: number;
|
||||
lastActiveLabel: string;
|
||||
myTaskCount: number;
|
||||
myPendingTaskCount: number;
|
||||
}
|
||||
|
||||
const todoCategoryMeta: Record<
|
||||
@@ -144,11 +131,12 @@ const activityToneMap: Record<WorkbenchActivityItemSource['targetKind'], Workben
|
||||
product: 'rose'
|
||||
};
|
||||
|
||||
const projectStatusMeta: Record<WorkbenchProjectStatus, { label: string; tone: WorkbenchProjectItem['statusTone'] }> = {
|
||||
active: { label: '进行中', tone: 'emerald' },
|
||||
preview: { label: '试运行', tone: 'sky' },
|
||||
paused: { label: '已暂停', tone: 'amber' }
|
||||
};
|
||||
/** 列表只含进行中项目;按已知状态编码上色,未知回退 sky */
|
||||
function resolveParticipatedProjectTone(statusCode: string): 'sky' | 'emerald' | 'amber' {
|
||||
if (statusCode === 'active') return 'emerald';
|
||||
if (statusCode === 'paused') return 'amber';
|
||||
return 'sky';
|
||||
}
|
||||
|
||||
function clampPercent(value: number) {
|
||||
if (!Number.isFinite(value)) return 0;
|
||||
@@ -325,61 +313,68 @@ export function buildWorkbenchActivityItems(source: readonly WorkbenchActivityIt
|
||||
}));
|
||||
}
|
||||
|
||||
export function buildWorkbenchProjectItems(source: readonly WorkbenchProjectItemSource[]): WorkbenchProjectItem[] {
|
||||
return source.map(item => {
|
||||
const meta = projectStatusMeta[item.status];
|
||||
return {
|
||||
...item,
|
||||
statusLabel: meta.label,
|
||||
statusTone: meta.tone,
|
||||
progress: clampPercent(item.progress),
|
||||
lastActiveLabel: formatRelative(item.lastActiveTime)
|
||||
} satisfies WorkbenchProjectItem;
|
||||
});
|
||||
export function buildWorkbenchParticipatedProjects(
|
||||
source: readonly Api.Project.MyParticipatedProjectItem[]
|
||||
): WorkbenchParticipatedProjectView[] {
|
||||
return source.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
code: item.code,
|
||||
statusName: item.statusName,
|
||||
statusTone: resolveParticipatedProjectTone(item.statusCode),
|
||||
myRole: item.myRole,
|
||||
progress: clampPercent(item.progress),
|
||||
myTaskCount: item.myTaskCount,
|
||||
myPendingTaskCount: item.myPendingTaskCount
|
||||
}));
|
||||
}
|
||||
|
||||
export interface WorkbenchOwnedProjectMilestone {
|
||||
id: string;
|
||||
title: string;
|
||||
timeLabel: string;
|
||||
tone: 'amber' | 'slate';
|
||||
/** 「我负责的项目」成员负载展示项 */
|
||||
export interface WorkbenchOwnedProjectMemberView {
|
||||
userId: string;
|
||||
userName: string | null;
|
||||
/** 该成员在本项目下进行中任务数 */
|
||||
activeTaskCount: number;
|
||||
}
|
||||
|
||||
export interface WorkbenchOwnedProjectMember {
|
||||
name: string;
|
||||
/** 负载 0-100(百分比) */
|
||||
load: number;
|
||||
level: 'ok' | 'warn' | 'over';
|
||||
}
|
||||
|
||||
export interface WorkbenchOwnedProjectItemSource {
|
||||
/** 「我负责的项目」展示项(由 Api.Project.MyOwnedProjectItem 衍生) */
|
||||
export interface WorkbenchOwnedProjectView {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
/** 进度 0-100 */
|
||||
code: string | null;
|
||||
progress: number;
|
||||
myRole: string | null;
|
||||
executionCount: number;
|
||||
taskCount: number;
|
||||
memberCount: number;
|
||||
overdueCount: number;
|
||||
/** 距离计划结束剩余天数(负数表示已逾期) */
|
||||
remainingDays: number;
|
||||
/** 我在该项目中的角色 */
|
||||
myRole: string;
|
||||
milestones: WorkbenchOwnedProjectMilestone[];
|
||||
members: WorkbenchOwnedProjectMember[];
|
||||
memberCount: number;
|
||||
/** 计划结束日期 YYYY-MM-DD,可空 */
|
||||
plannedEndDate: string | null;
|
||||
/** 距计划结束剩余天数(负=已逾期);plannedEndDate 为空时 null */
|
||||
remainingDays: number | null;
|
||||
members: WorkbenchOwnedProjectMemberView[];
|
||||
}
|
||||
|
||||
export interface WorkbenchOwnedProjectItem extends WorkbenchOwnedProjectItemSource {
|
||||
progress: number;
|
||||
}
|
||||
|
||||
export function buildWorkbenchOwnedProjectItems(
|
||||
source: readonly WorkbenchOwnedProjectItemSource[]
|
||||
): WorkbenchOwnedProjectItem[] {
|
||||
export function buildWorkbenchOwnedProjects(
|
||||
source: readonly Api.Project.MyOwnedProjectItem[]
|
||||
): WorkbenchOwnedProjectView[] {
|
||||
return source.map(item => ({
|
||||
...item,
|
||||
progress: clampPercent(item.progress)
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
code: item.code,
|
||||
progress: clampPercent(item.progress),
|
||||
myRole: item.myRole,
|
||||
executionCount: item.executionCount,
|
||||
taskCount: item.taskCount,
|
||||
overdueCount: item.overdueCount,
|
||||
memberCount: item.memberCount,
|
||||
plannedEndDate: item.plannedEndDate,
|
||||
remainingDays: getRemainingDays(item.plannedEndDate),
|
||||
members: item.members.map(member => ({
|
||||
userId: member.userId,
|
||||
userName: member.userName,
|
||||
activeTaskCount: member.activeTaskCount
|
||||
}))
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -759,38 +754,13 @@ export function buildWorkbenchProgressBars(source: readonly WorkbenchProgressBar
|
||||
return source.map(s => ({ ...s, weekCompletionRate: Math.min(100, Math.max(0, Math.round(s.weekCompletionRate))) }));
|
||||
}
|
||||
|
||||
export interface WorkbenchMyExecutionItemSource {
|
||||
id: string;
|
||||
executionName: string;
|
||||
/** 关联项目 */
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
/** 执行状态编码(projectExecution 域:pending / active / paused / completed / cancelled) */
|
||||
statusCode: string;
|
||||
/** 状态名(后端字典返回) */
|
||||
statusName: string;
|
||||
/** 优先级编码(取 RDMS_REQ_PRIORITY_DICT_CODE 字典) */
|
||||
priority: string;
|
||||
/** 计划起止 */
|
||||
plannedStartDate: string | null;
|
||||
plannedEndDate: string | null;
|
||||
/** 实际起止 */
|
||||
actualStartDate: string | null;
|
||||
actualEndDate: string | null;
|
||||
/** 进度(0-100 整数) */
|
||||
progressRate: number;
|
||||
/** 关联项目需求 ID(可选) */
|
||||
projectRequirementId?: string;
|
||||
/** 关联项目需求名称(可选) */
|
||||
projectRequirementName?: string;
|
||||
}
|
||||
|
||||
export type WorkbenchMyExecutionItem = WorkbenchMyExecutionItemSource;
|
||||
|
||||
/** 过滤掉已完成 / 已取消 / 进度满 100 的执行(默认不在工作台呈现) */
|
||||
export function buildWorkbenchMyExecutionItems(
|
||||
source: readonly WorkbenchMyExecutionItemSource[]
|
||||
): WorkbenchMyExecutionItem[] {
|
||||
/**
|
||||
* 前端兜底过滤:剔除已完成 / 已取消 / 进度满 100 的执行(默认不在工作台呈现)。
|
||||
* 后端接口已按此口径过滤,此处为双保险;泛型保证接口返回类型可复用。
|
||||
*/
|
||||
export function buildWorkbenchMyExecutionItems<T extends { statusCode: string; progressRate: number }>(
|
||||
source: readonly T[]
|
||||
): T[] {
|
||||
return source.filter(item => {
|
||||
if (item.statusCode === 'completed' || item.statusCode === 'cancelled') return false;
|
||||
if (item.progressRate >= 100) return false;
|
||||
|
||||
Reference in New Issue
Block a user