feat(projects): 工作台接口切换为真实数据
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import dayjs from 'dayjs';
|
||||
import { normalizeNullableStringId, normalizeStringId } from './shared';
|
||||
|
||||
type ProjectStatusCode = Api.Project.ProjectStatusCode;
|
||||
@@ -76,6 +77,60 @@ export type MyOwnedProjectResponse = Omit<Api.Project.MyOwnedProjectItem, 'id' |
|
||||
members?: MyOwnedProjectMemberResponse[] | null;
|
||||
};
|
||||
|
||||
export type MyTaskResponse = Omit<
|
||||
Api.Project.MyTaskItem,
|
||||
| 'id'
|
||||
| 'projectId'
|
||||
| 'executionId'
|
||||
| 'priority'
|
||||
| 'plannedEndDate'
|
||||
| 'progressRate'
|
||||
| 'createTime'
|
||||
| 'parentTaskId'
|
||||
| 'availableActions'
|
||||
> & {
|
||||
id: StringIdResponse;
|
||||
projectId: StringIdResponse;
|
||||
executionId?: StringIdResponse | null;
|
||||
priority?: string | number | null;
|
||||
plannedEndDate?: ProjectLocalDateValue;
|
||||
progressRate?: number | string | null;
|
||||
createTime?: string | number | null;
|
||||
parentTaskId?: StringIdResponse | null;
|
||||
availableActions?: LifecycleActionResponse<Api.Project.ProjectTaskActionCode>[] | null;
|
||||
};
|
||||
|
||||
export type TeamLoadDistributionItemResponse = Omit<Api.Project.TeamLoadDistributionItem, 'projectId'> & {
|
||||
projectId?: StringIdResponse | null;
|
||||
};
|
||||
|
||||
export type TeamLoadMemberResponse = Omit<Api.Project.TeamLoadMember, 'userId' | 'items'> & {
|
||||
userId: StringIdResponse;
|
||||
items?: TeamLoadDistributionItemResponse[] | null;
|
||||
};
|
||||
|
||||
export type TeamLoadResponse = {
|
||||
members?: TeamLoadMemberResponse[] | null;
|
||||
};
|
||||
|
||||
export type WorklogDistributionItemResponse = Omit<Api.Project.WorklogDistributionItem, 'projectId'> & {
|
||||
projectId?: StringIdResponse | null;
|
||||
};
|
||||
|
||||
export type MyWorklogWeekResponse = Omit<Api.Project.MyWorklogWeekResult, 'dailyHours' | 'distribution'> & {
|
||||
dailyHours?: number[] | null;
|
||||
distribution?: WorklogDistributionItemResponse[] | null;
|
||||
};
|
||||
|
||||
export type TeamWorklogWeekMemberResponse = Omit<Api.Project.TeamWorklogWeekMember, 'userId' | 'items'> & {
|
||||
userId: StringIdResponse;
|
||||
items?: WorklogDistributionItemResponse[] | null;
|
||||
};
|
||||
|
||||
export type TeamWorklogWeekResponse = Omit<Api.Project.TeamWorklogWeekResult, 'members'> & {
|
||||
members?: TeamWorklogWeekMemberResponse[] | null;
|
||||
};
|
||||
|
||||
export type ExecutionAssigneeResponse = Omit<Api.Project.ExecutionAssignee, 'id' | 'executionId' | 'userId'> & {
|
||||
id: StringIdResponse;
|
||||
executionId: StringIdResponse;
|
||||
@@ -263,6 +318,28 @@ export function normalizeProjectLocalDate(value: ProjectLocalDateValue | undefin
|
||||
return String(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 后端 LocalDateTime 统一序列化为毫秒时间戳(也可能是数字字符串/格式化字符串),
|
||||
* 归一为 'YYYY-MM-DD HH:mm:ss' 供展示与 dayjs 解析。
|
||||
*/
|
||||
export function normalizeProjectDateTime(value: string | number | null | undefined): string {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
let parsed: dayjs.Dayjs;
|
||||
if (typeof value === 'number') {
|
||||
parsed = dayjs(value);
|
||||
} else if (/^\d+$/.test(value)) {
|
||||
// 字符串形态的毫秒时间戳:dayjs 无法直接解析,先转数值(时间值非 ID,安全整数范围内)
|
||||
parsed = dayjs(Number(value));
|
||||
} else {
|
||||
parsed = dayjs(value);
|
||||
}
|
||||
|
||||
return parsed.isValid() ? parsed.format('YYYY-MM-DD HH:mm:ss') : '';
|
||||
}
|
||||
|
||||
export function normalizeLifecycleActions<ActionCode extends string>(
|
||||
actions: LifecycleActionResponse<ActionCode>[] | null | undefined
|
||||
): Api.Project.LifecycleAction<ActionCode>[] {
|
||||
@@ -296,6 +373,15 @@ function normalizePriority(value: string | number | null | undefined): string {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function normalizeProgressRate(value: number | string | null | undefined) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const numeric = typeof value === 'number' ? value : Number(value ?? 0);
|
||||
return Number.isFinite(numeric) ? numeric : null;
|
||||
}
|
||||
|
||||
export function normalizeProjectExecution(response: ProjectExecutionResponse): Api.Project.ProjectExecution {
|
||||
return {
|
||||
...response,
|
||||
@@ -366,6 +452,75 @@ export function normalizeMyOwnedProject(response: MyOwnedProjectResponse): Api.P
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeMyTask(response: MyTaskResponse): Api.Project.MyTaskItem {
|
||||
return {
|
||||
...response,
|
||||
id: normalizeStringId(response.id),
|
||||
projectId: normalizeStringId(response.projectId),
|
||||
executionId: normalizeNullableStringId(response.executionId),
|
||||
executionName: response.executionName ?? null,
|
||||
statusName: response.statusName ?? null,
|
||||
priority: normalizePriority(response.priority),
|
||||
plannedEndDate: normalizeProjectLocalDate(response.plannedEndDate),
|
||||
progressRate: normalizeProgressRate(response.progressRate) ?? 0,
|
||||
createTime: normalizeProjectDateTime(response.createTime),
|
||||
parentTaskId: normalizeNullableStringId(response.parentTaskId),
|
||||
terminal: Boolean(response.terminal),
|
||||
allowEdit: Boolean(response.allowEdit),
|
||||
availableActions: normalizeLifecycleActions(response.availableActions)
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeWorklogDistributionItem(
|
||||
response: WorklogDistributionItemResponse | TeamLoadDistributionItemResponse
|
||||
): { projectId: string | null; projectName: string | null; kind: 'project' | 'personal' | 'other' } {
|
||||
return {
|
||||
projectId: normalizeNullableStringId(response.projectId),
|
||||
projectName: response.projectName ?? null,
|
||||
kind: response.kind
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeTeamLoad(response: TeamLoadResponse): Api.Project.TeamLoadResult {
|
||||
return {
|
||||
members: (response.members ?? []).map(member => ({
|
||||
userId: normalizeStringId(member.userId),
|
||||
userNickname: member.userNickname ?? '',
|
||||
items: (member.items ?? []).map(item => ({
|
||||
...normalizeWorklogDistributionItem(item),
|
||||
count: typeof item.count === 'number' ? item.count : 0
|
||||
})),
|
||||
dueSoonCount: typeof member.dueSoonCount === 'number' ? member.dueSoonCount : 0,
|
||||
overdueCount: typeof member.overdueCount === 'number' ? member.overdueCount : 0
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeMyWorklogWeek(response: MyWorklogWeekResponse): Api.Project.MyWorklogWeekResult {
|
||||
return {
|
||||
weekStart: response.weekStart ?? '',
|
||||
dailyHours: response.dailyHours ?? [0, 0, 0, 0, 0],
|
||||
distribution: (response.distribution ?? []).map(item => ({
|
||||
...normalizeWorklogDistributionItem(item),
|
||||
hours: typeof item.hours === 'number' ? item.hours : 0
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeTeamWorklogWeek(response: TeamWorklogWeekResponse): Api.Project.TeamWorklogWeekResult {
|
||||
return {
|
||||
weekStart: response.weekStart ?? '',
|
||||
members: (response.members ?? []).map(member => ({
|
||||
userId: normalizeStringId(member.userId),
|
||||
userNickname: member.userNickname ?? '',
|
||||
items: (member.items ?? []).map(item => ({
|
||||
...normalizeWorklogDistributionItem(item),
|
||||
hours: typeof item.hours === 'number' ? item.hours : 0
|
||||
}))
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
export function normalizeExecutionAssignee(response: ExecutionAssigneeResponse): Api.Project.ExecutionAssignee {
|
||||
return {
|
||||
...response,
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
type MyExecutionResponse,
|
||||
type MyOwnedProjectResponse,
|
||||
type MyParticipatedProjectResponse,
|
||||
type MyTaskResponse,
|
||||
type MyWorklogWeekResponse,
|
||||
type ProjectExecutionResponse,
|
||||
type ProjectLocalDateValue,
|
||||
type ProjectMemberResponse,
|
||||
@@ -20,19 +22,25 @@ import {
|
||||
type TaskAssigneeFromApiResponse,
|
||||
type TaskAssigneeLogResponse,
|
||||
type TaskWorklogResponse,
|
||||
type TeamLoadResponse,
|
||||
type TeamWorklogWeekResponse,
|
||||
getProjectLifecycleActions,
|
||||
normalizeExecutionAssignee,
|
||||
normalizeExecutionAssigneeLog,
|
||||
normalizeMyExecution,
|
||||
normalizeMyOwnedProject,
|
||||
normalizeMyParticipatedProject,
|
||||
normalizeMyTask,
|
||||
normalizeMyWorklogWeek,
|
||||
normalizeProjectExecution,
|
||||
normalizeProjectLocalDate,
|
||||
normalizeProjectMember,
|
||||
normalizeProjectTask,
|
||||
normalizeTaskAssignee,
|
||||
normalizeTaskAssigneeLog,
|
||||
normalizeTaskWorklog
|
||||
normalizeTaskWorklog,
|
||||
normalizeTeamLoad,
|
||||
normalizeTeamWorklogWeek
|
||||
} from './project-shared';
|
||||
|
||||
const PROJECT_PREFIX = `${WEB_SERVICE_PREFIX}/project/project`;
|
||||
@@ -440,6 +448,57 @@ export async function fetchGetMyOwnedProjectPage(params?: Api.Project.MyProjectS
|
||||
}));
|
||||
}
|
||||
|
||||
/** 获取工作台「我的任务」(跨项目聚合,负责人/在岗协办人口径,只返回非终态;隐式取当前登录用户) */
|
||||
export async function fetchGetMyTaskPage(params?: Api.Project.MyTaskSearchParams) {
|
||||
type MyTaskPageResponse = Api.Project.PageResult<MyTaskResponse>;
|
||||
const result = await request<MyTaskPageResponse>({
|
||||
...safeJsonRequestConfig,
|
||||
url: `${PROJECT_PREFIX}/me/tasks/page`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
|
||||
return mapServiceResult(result as ServiceRequestResult<MyTaskPageResponse>, data => ({
|
||||
...data,
|
||||
list: data.list.map(normalizeMyTask)
|
||||
}));
|
||||
}
|
||||
|
||||
/** 获取工作台「团队负载」(团队 = 当前用户 + 管理链路直接下级,members[0] 恒为当前用户) */
|
||||
export async function fetchGetMyTeamLoad() {
|
||||
const result = await request<TeamLoadResponse>({
|
||||
...safeJsonRequestConfig,
|
||||
url: `${PROJECT_PREFIX}/me/team-load`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
return mapServiceResult(result as ServiceRequestResult<TeamLoadResponse>, normalizeTeamLoad);
|
||||
}
|
||||
|
||||
/** 获取工作台「我的工时周聚合」(weekStart 传任意日期,后端归一到所在周周一;逐日工时为均摊推算值) */
|
||||
export async function fetchGetMyWorklogWeek(params: Api.Project.WorklogWeekParams) {
|
||||
const result = await request<MyWorklogWeekResponse>({
|
||||
...safeJsonRequestConfig,
|
||||
url: `${PROJECT_PREFIX}/me/worklog-week`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
|
||||
return mapServiceResult(result as ServiceRequestResult<MyWorklogWeekResponse>, normalizeMyWorklogWeek);
|
||||
}
|
||||
|
||||
/** 获取工作台「团队工时周聚合」(成员集合与团队负载同口径;周标准工时后端不返回,前端落常量) */
|
||||
export async function fetchGetTeamWorklogWeek(params: Api.Project.WorklogWeekParams) {
|
||||
const result = await request<TeamWorklogWeekResponse>({
|
||||
...safeJsonRequestConfig,
|
||||
url: `${PROJECT_PREFIX}/me/team-worklog-week`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
|
||||
return mapServiceResult(result as ServiceRequestResult<TeamWorklogWeekResponse>, normalizeTeamWorklogWeek);
|
||||
}
|
||||
|
||||
/** 获取项目执行状态看板 */
|
||||
export function fetchGetProjectExecutionStatusBoard(
|
||||
projectId: string,
|
||||
|
||||
Reference in New Issue
Block a user