import { WEB_SERVICE_PREFIX } from '@/constants/service'; import { request } from '../request'; import { type ServiceRequestResult, mapServiceResult, normalizeNullableStringId, normalizeStringId, safeJsonRequestConfig } from './shared'; import { type ExecutionAssigneeLogResponse, type ExecutionAssigneeResponse, type ProjectExecutionResponse, type ProjectLocalDateValue, type ProjectMemberResponse, type ProjectTaskResponse, type TaskAssigneeFromApiResponse, type TaskAssigneeLogResponse, type TaskWorklogResponse, getProjectLifecycleActions, normalizeExecutionAssignee, normalizeExecutionAssigneeLog, normalizeProjectExecution, normalizeProjectLocalDate, normalizeProjectMember, normalizeProjectTask, normalizeTaskAssignee, normalizeTaskAssigneeLog, normalizeTaskWorklog } from './project-shared'; const PROJECT_PREFIX = `${WEB_SERVICE_PREFIX}/project/project`; type ProjectResponse = Omit< Api.Project.Project, 'id' | 'managerUserId' | 'productId' | 'plannedStartDate' | 'plannedEndDate' | 'actualStartDate' | 'actualEndDate' > & { id: string | number; managerUserId?: string | number | null; productId?: string | number | null; plannedStartDate?: ProjectLocalDateValue; plannedEndDate?: ProjectLocalDateValue; actualStartDate?: ProjectLocalDateValue; actualEndDate?: ProjectLocalDateValue; }; type ProjectPageResponse = Api.Project.PageResult; type ProjectExecutionPageResponse = Api.Project.PageResult; type ProjectTaskPageResponse = Api.Project.PageResult; type StatusBoardResponse = Api.Project.StatusBoard; type ProjectTaskBoardPageResponse = { items: Array<{ statusCode: string; statusName: string; sort: number; terminal?: boolean; list: ProjectTaskResponse[]; total: number; }>; }; type ProjectContextResponse = Omit & { currentProject: Omit & { id: string | number }; navs: Array & { id: string | number }>; }; function getExecutionPrefix(projectId: string) { return `${PROJECT_PREFIX}/${projectId}/executions`; } function getTaskPrefix(projectId: string, executionId: string) { return `${getExecutionPrefix(projectId)}/${executionId}/tasks`; } /** 归一化项目数据 */ function normalizeProject(project: ProjectResponse): Api.Project.Project { return { ...project, id: normalizeStringId(project.id), managerUserId: normalizeNullableStringId(project.managerUserId) ?? '', productId: normalizeNullableStringId(project.productId), plannedStartDate: normalizeProjectLocalDate(project.plannedStartDate), plannedEndDate: normalizeProjectLocalDate(project.plannedEndDate), actualStartDate: normalizeProjectLocalDate(project.actualStartDate), actualEndDate: normalizeProjectLocalDate(project.actualEndDate) }; } /** 将项目详情组装为设置页数据 */ function createProjectSettings(project: Api.Project.Project): Api.Project.ProjectSettings { return { baseInfo: { id: project.id, projectCode: project.projectCode, projectName: project.projectName, directionCode: project.directionCode, projectType: project.projectType, productId: project.productId, productName: project.productName ?? null, managerUserId: project.managerUserId, managerUserNickname: project.managerUserNickname ?? null, statusCode: project.statusCode, plannedStartDate: project.plannedStartDate, plannedEndDate: project.plannedEndDate, actualStartDate: project.actualStartDate, actualEndDate: project.actualEndDate, projectDesc: project.projectDesc, lastStatusReason: project.lastStatusReason }, lifecycle: { statusCode: project.statusCode, lastStatusReason: project.lastStatusReason, availableActions: getProjectLifecycleActions(project.statusCode) } }; } /** 获取项目分页 */ export async function fetchGetProjectPage(params?: Api.Project.ProjectSearchParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProject) })); } /** 获取项目入口页概览统计 */ export function fetchGetProjectOverviewSummary() { return request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/overview-summary`, method: 'get' }); } /** 获取项目详情 */ export async function fetchGetProject(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/get`, method: 'get', params: { id } }); return mapServiceResult(result as ServiceRequestResult, normalizeProject); } /** 根据产品ID获取产品下的所有项目 */ export async function fetchGetProjectListByProductId(productId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/list-by-product`, method: 'get', params: { productId } }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeProject)); } /** 创建项目 */ export async function fetchCreateProject(data: Api.Project.SaveProjectParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/create`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 创建项目(含初始团队,原子接口) */ export async function fetchCreateProjectWithTeam(data: Api.Project.CreateProjectWithTeamParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/create-with-team`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目 */ export function fetchUpdateProject(data: Api.Project.UpdateProjectParams) { return request({ url: `${PROJECT_PREFIX}/update`, method: 'put', data }); } /** 变更项目状态 */ export function fetchChangeProjectStatus(data: Api.Project.ChangeProjectStatusParams) { return request({ url: `${PROJECT_PREFIX}/change-status`, method: 'post', data }); } /** 删除项目 */ export function fetchDeleteProject(data: Api.Project.DeleteProjectParams) { return request({ url: `${PROJECT_PREFIX}/delete`, method: 'post', data }); } /** 获取项目上下文 */ export async function fetchGetProjectContext(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/context`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, currentProject: { ...data.currentProject, id: normalizeStringId(data.currentProject.id) }, navs: data.navs.map(nav => ({ ...nav, id: normalizeStringId(nav.id) })) })); } /** 获取项目成员列表 */ export async function fetchGetProjectMembers(id: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeProjectMember) ); } /** 创建项目成员 */ export async function fetchCreateProjectMember(id: string, data: Api.Project.CreateProjectMemberParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目成员 */ export function fetchUpdateProjectMember(id: string, memberId: string, data: Api.Project.UpdateProjectMemberParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members/${memberId}`, method: 'put', data }); } /** 移出项目成员 */ export function fetchInactiveProjectMember( id: string, memberId: string, data: Api.Project.InactiveProjectMemberParams ) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members/${memberId}/inactive`, method: 'post', data }); } export async function fetchBatchCreateProjectMembers(id: string, data: Api.Project.BatchCreateProjectMembersParams) { const result = await request>({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members/batch`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult>, list => Array.isArray(list) ? list.map(normalizeStringId) : [] ); } export function fetchBatchInactiveProjectMembers(id: string, data: Api.Project.BatchInactiveProjectMembersParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_PREFIX}/${id}/members/batch/inactive`, method: 'post', data }); } /** 获取项目设置 */ export async function fetchGetProjectSettings(id: string) { const result = await fetchGetProject(id); if (result.error || !result.data) { return result as ServiceRequestResult; } return { ...result, data: createProjectSettings(result.data) }; } /** 更新项目设置基础信息 */ export async function fetchUpdateProjectSettingBaseInfo( id: string, data: Api.Project.UpdateProjectSettingBaseInfoParams ) { const detailResult = await fetchGetProject(id); if (detailResult.error || !detailResult.data) { return detailResult as ServiceRequestResult; } return fetchUpdateProject({ id, projectCode: detailResult.data.projectCode, projectName: data.projectName, directionCode: data.directionCode, projectType: data.projectType, productId: detailResult.data.productId, managerUserId: detailResult.data.managerUserId, plannedStartDate: data.plannedStartDate, plannedEndDate: data.plannedEndDate, actualStartDate: detailResult.data.actualStartDate, actualEndDate: detailResult.data.actualEndDate, projectDesc: data.projectDesc }); } /** 获取项目执行分页 */ export async function fetchGetProjectExecutionPage( projectId: string, params?: Api.Project.ProjectExecutionSearchParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProjectExecution) })); } /** 获取项目执行状态看板 */ export function fetchGetProjectExecutionStatusBoard( projectId: string, params?: Api.Project.ProjectExecutionStatusBoardParams ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/status-board`, method: 'get', params }); } /** 获取项目执行详情 */ export async function fetchGetProjectExecution(projectId: string, executionId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, normalizeProjectExecution); } /** 创建项目执行 */ export async function fetchCreateProjectExecution(projectId: string, data: Api.Project.CreateProjectExecutionParams) { const result = await request({ ...safeJsonRequestConfig, url: getExecutionPrefix(projectId), method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目执行 */ export function fetchUpdateProjectExecution( projectId: string, executionId: string, data: Api.Project.UpdateProjectExecutionParams ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}`, method: 'put', data }); } /** 变更项目执行负责人 */ export function fetchChangeProjectExecutionOwner( projectId: string, executionId: string, data: Api.Project.ChangeExecutionOwnerParams ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/change-owner`, method: 'post', data }); } /** 删除项目执行 */ export function fetchDeleteProjectExecution( projectId: string, executionId: string, data: Api.Project.DeleteProjectExecutionParams ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}`, method: 'delete', data }); } /** 执行删除预检(spec §2.1:返回是否含下挂数据,用于前端弹层分流) */ export function fetchPrecheckDeleteProjectExecution(projectId: string, executionId: string) { return request({ url: `${getExecutionPrefix(projectId)}/${executionId}/delete-precheck`, method: 'get' }); } /** 变更项目执行状态 */ export function fetchChangeProjectExecutionStatus( projectId: string, executionId: string, data: Api.Project.ChangeExecutionStatusParams ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/change-status`, method: 'post', data }); } /** 获取项目执行协办人 */ export async function fetchGetProjectExecutionAssignees(projectId: string, executionId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/assignees`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeExecutionAssignee) ); } /** 创建项目执行协办人 */ export async function fetchCreateProjectExecutionAssignee( projectId: string, executionId: string, data: Api.Project.CreateExecutionAssigneeParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/assignees`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 移除项目执行协办人 */ export function fetchInactiveProjectExecutionAssignee( projectId: string, executionId: string, payload: { assigneeId: string; data: Api.Project.InactiveExecutionAssigneeParams } ) { return request({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/assignees/${payload.assigneeId}/inactive`, method: 'post', data: payload.data }); } /** 获取项目执行协办人变更历史分页 */ export async function fetchGetProjectExecutionAssigneeLogPage( projectId: string, executionId: string, params?: Api.Project.ExecutionAssigneeLogSearchParams ) { const result = await request>({ ...safeJsonRequestConfig, url: `${getExecutionPrefix(projectId)}/${executionId}/assignee-logs`, method: 'get', params }); return mapServiceResult( result as ServiceRequestResult>, data => ({ ...data, list: data.list.map(normalizeExecutionAssigneeLog) }) ); } /** 获取项目任务分页 */ export async function fetchGetProjectTaskPage( projectId: string, executionId: string, params?: Api.Project.ProjectTaskSearchParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProjectTask) })); } /** 获取项目任务状态看板 */ export function fetchGetProjectTaskStatusBoard( projectId: string, executionId: string, params?: Api.Project.ProjectTaskStatusBoardParams ) { return request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/status-board`, method: 'get', params }); } /** * 任务看板按状态分组的分页接口。 * * 看板模式专用:一次请求拿到所有列(或指定列)的首屏 + 总数,替代"5 列 5 次 page"的旧方式。 * 列内向下滚续页时再传 `statusCode=[X]&pageNo=N+1` 单列查询。 */ export async function fetchGetProjectTaskBoardPage( projectId: string, executionId: string, params?: Api.Project.ProjectTaskBoardPageParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/board-page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ items: data.items.map(item => ({ ...item, list: item.list.map(normalizeProjectTask) })) })); } /** 获取项目任务详情 */ export async function fetchGetProjectTask(projectId: string, executionId: string, taskId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, normalizeProjectTask); } /** 创建项目任务 */ export async function fetchCreateProjectTask( projectId: string, executionId: string, data: Api.Project.SaveProjectTaskParams ) { const result = await request({ ...safeJsonRequestConfig, url: getTaskPrefix(projectId, executionId), method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目任务 */ export function fetchUpdateProjectTask( projectId: string, executionId: string, payload: { taskId: string; data: Api.Project.SaveProjectTaskParams } ) { return request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${payload.taskId}`, method: 'put', data: payload.data }); } /** 删除项目任务 */ // eslint-disable-next-line max-params export function fetchDeleteProjectTask( projectId: string, executionId: string, taskId: string, data: Api.Project.DeleteProjectTaskParams ) { return request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}`, method: 'delete', data }); } /** 任务删除预检(spec §2.1) */ export function fetchPrecheckDeleteProjectTask(projectId: string, executionId: string, taskId: string) { return request({ url: `${getTaskPrefix(projectId, executionId)}/${taskId}/delete-precheck`, method: 'get' }); } /** 变更项目任务状态 */ export function fetchChangeProjectTaskStatus( projectId: string, executionId: string, payload: { taskId: string; data: Api.Project.ChangeTaskStatusParams } ) { return request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${payload.taskId}/change-status`, method: 'post', data: payload.data }); } // ============= 项目级跨执行任务(不带 executionId 路径段) ============= // 调试文档:所有接口挂在 /project/project/{projectId}/tasks/* 下;通过 involveUserId / ownerId / executionIds 等 // 入参组合表达"我的任务 / 项目全部 / 指定执行"等视角。原有执行级 {eid}/tasks/page 等保留不动。 function getProjectTasksPrefix(projectId: string) { return `${PROJECT_PREFIX}/${projectId}/tasks`; } /** 项目级跨执行任务分页 */ export async function fetchGetProjectTaskPageCross( projectId: string, params?: Api.Project.ProjectTaskCrossSearchParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getProjectTasksPrefix(projectId)}/page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProjectTask) })); } /** 项目级跨执行任务状态看板 */ export function fetchGetProjectTaskStatusBoardCross( projectId: string, params?: Api.Project.ProjectTaskCrossStatusBoardParams ) { return request({ ...safeJsonRequestConfig, url: `${getProjectTasksPrefix(projectId)}/status-board`, method: 'get', params }); } /** 项目级跨执行任务看板分页(每列共用同一组 pageNo / pageSize;列内固定 plannedEndDate ASC, id DESC) */ export async function fetchGetProjectTaskBoardPageCross( projectId: string, params?: Api.Project.ProjectTaskCrossBoardPageParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getProjectTasksPrefix(projectId)}/board-page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ items: data.items.map(item => ({ ...item, list: item.list.map(normalizeProjectTask) })) })); } /** * 项目级"今日小条"汇总(4 个数字 + 服务器日期边界)。 * * scope=all 必须有 project:task:list-all 权限,否则 403(PROJECT_OBJECT_PERMISSION_DENIED)。 * 前端切到"项目全部"视角前应已基于权限码隐藏入口;如真被 403,UI 应自动切回"我的"。 */ export function fetchGetProjectTaskSummary(projectId: string, params?: Api.Project.ProjectTaskSummaryParams) { return request({ ...safeJsonRequestConfig, url: `${getProjectTasksPrefix(projectId)}/summary`, method: 'get', params }); } type TaskWorklogPageResponse = Api.Project.PageResult; function getWorklogPrefix(projectId: string, executionId: string, taskId: string) { return `${getTaskPrefix(projectId, executionId)}/${taskId}/worklogs`; } /** 获取任务工时分页 */ // eslint-disable-next-line max-params export async function fetchGetProjectTaskWorklogPage( projectId: string, executionId: string, taskId: string, params?: Api.Project.TaskWorklogSearchParams ) { const result = await request({ ...safeJsonRequestConfig, url: getWorklogPrefix(projectId, executionId, taskId), method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeTaskWorklog) })); } /** 新增任务工时 */ // eslint-disable-next-line max-params export async function fetchCreateProjectTaskWorklog( projectId: string, executionId: string, taskId: string, data: Api.Project.SaveTaskWorklogParams ) { const result = await request({ ...safeJsonRequestConfig, url: getWorklogPrefix(projectId, executionId, taskId), method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 修改任务工时 */ // eslint-disable-next-line max-params export function fetchUpdateProjectTaskWorklog( projectId: string, executionId: string, taskId: string, payload: { worklogId: string; data: Api.Project.SaveTaskWorklogParams } ) { return request({ ...safeJsonRequestConfig, url: `${getWorklogPrefix(projectId, executionId, taskId)}/${payload.worklogId}`, method: 'put', data: payload.data }); } /** 删除任务工时 */ // eslint-disable-next-line max-params export function fetchDeleteProjectTaskWorklog( projectId: string, executionId: string, taskId: string, worklogId: string ) { return request({ ...safeJsonRequestConfig, url: `${getWorklogPrefix(projectId, executionId, taskId)}/${worklogId}`, method: 'delete' }); } /** 5.6 获取任务协办人列表(仅当前活跃) */ export async function fetchGetProjectTaskAssignees(projectId: string, executionId: string, taskId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}/assignees`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeTaskAssignee) ); } /** 5.7 加入任务协办人 */ // eslint-disable-next-line max-params export async function fetchCreateProjectTaskAssignee( projectId: string, executionId: string, taskId: string, data: Api.Project.CreateTaskAssigneeParams ) { const result = await request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}/assignees`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 5.8 退出任务协办人 */ // eslint-disable-next-line max-params export function fetchInactiveProjectTaskAssignee( projectId: string, executionId: string, taskId: string, assigneeId: string, data: Api.Project.InactiveTaskAssigneeParams ) { return request({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}/assignees/${assigneeId}/inactive`, method: 'post', data }); } /** 5.9 任务协办人变更历史分页 */ // eslint-disable-next-line max-params export async function fetchGetProjectTaskAssigneeLogPage( projectId: string, executionId: string, taskId: string, params?: Api.Project.TaskAssigneeLogSearchParams ) { const result = await request>({ ...safeJsonRequestConfig, url: `${getTaskPrefix(projectId, executionId)}/${taskId}/assignee-logs`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult>, data => ({ ...data, list: data.list.map(normalizeTaskAssigneeLog) })); } // ========== 项目需求 API ========== const PROJECT_REQUIREMENT_PREFIX = `${WEB_SERVICE_PREFIX}/project/project/requirement`; type ProjectRequirementResponse = Omit< Api.Project.ProjectRequirement, 'id' | 'projectId' | 'parentId' | 'moduleId' | 'proposerId' | 'currentHandlerUserId' | 'sourceBizId' | 'attachments' > & { id: string | number; projectId: string | number; parentId: string | number; moduleId: string | number; proposerId: string | number; currentHandlerUserId?: string | number | null; sourceBizId?: string | number | null; attachments?: AttachmentItemResponse[] | null; children?: ProjectRequirementResponse[]; }; type ProjectRequirementPageResponse = Api.Project.PageResult; type ProjectRequirementReviewResponse = Omit< Api.Project.ProjectRequirementReview, 'id' | 'requirementId' | 'operatorId' | 'attendees' | 'attachments' > & { id: string | number; requirementId: string | number; operatorId: string | number; attendees?: Array<{ userId: string | number; nickname: string; }>; attachments?: AttachmentItemResponse[] | null; }; type ProjectRequirementModuleResponse = Omit & { id: string | number; parentId: string | number; projectId: string | number; children?: ProjectRequirementModuleResponse[]; }; type AttachmentItemResponse = Omit & { fileId?: string | number; id?: string | number; }; function normalizeAttachments(list?: AttachmentItemResponse[] | null): Api.Project.AttachmentItem[] | null { if (!list) { return null; } return list.map(item => { const rawId = item.fileId ?? item.id; return { ...item, fileId: rawId === null || rawId === undefined ? '' : String(rawId) }; }); } function normalizeProjectRequirement(requirement: ProjectRequirementResponse): Api.Project.ProjectRequirement { return { ...requirement, id: normalizeStringId(requirement.id), projectId: normalizeStringId(requirement.projectId), parentId: normalizeStringId(requirement.parentId), moduleId: normalizeStringId(requirement.moduleId), proposerId: normalizeStringId(requirement.proposerId), currentHandlerUserId: normalizeNullableStringId(requirement.currentHandlerUserId), sourceBizId: normalizeNullableStringId(requirement.sourceBizId), attachments: normalizeAttachments(requirement.attachments), progressRate: typeof requirement.progressRate === 'number' ? requirement.progressRate : 0, children: requirement.children?.map(normalizeProjectRequirement) }; } function normalizeProjectRequirementReview( review: ProjectRequirementReviewResponse ): Api.Project.ProjectRequirementReview { return { ...review, id: normalizeStringId(review.id), requirementId: normalizeStringId(review.requirementId), operatorId: normalizeStringId(review.operatorId), attendees: review.attendees?.map(item => ({ ...item, userId: normalizeStringId(item.userId) })), attachments: normalizeAttachments(review.attachments) }; } function normalizeProjectRequirementModule( module: ProjectRequirementModuleResponse ): Api.Project.ProjectRequirementModule { return { ...module, id: normalizeStringId(module.id), parentId: normalizeStringId(module.parentId), projectId: normalizeStringId(module.projectId), children: module.children?.map(normalizeProjectRequirementModule) }; } /** 获取项目需求分页列表 */ export async function fetchGetProjectRequirementPage(params?: Api.Project.ProjectRequirementSearchParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/page`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProjectRequirement) })); } /** 获取项目需求树形列表 */ export async function fetchGetProjectRequirementTree(params?: Api.Project.ProjectRequirementSearchParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/tree`, method: 'get', params }); return mapServiceResult(result as ServiceRequestResult, data => ({ ...data, list: data.list.map(normalizeProjectRequirement) })); } /** 获取项目需求详情 */ export async function fetchGetProjectRequirement(id: string, projectId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/get`, method: 'get', params: { id, projectId } }); return mapServiceResult(result as ServiceRequestResult, normalizeProjectRequirement); } /** 创建项目需求 */ export async function fetchCreateProjectRequirement(data: Api.Project.SaveProjectRequirementParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/create`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目需求 */ export function fetchUpdateProjectRequirement(data: Api.Project.UpdateProjectRequirementParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/update`, method: 'put', data }); } /** 变更项目需求状态 */ export function fetchChangeProjectRequirementStatus(data: Api.Project.ChangeProjectRequirementStatusParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/change-status`, method: 'post', data }); } /** 删除项目需求 */ export function fetchDeleteProjectRequirement(data: Api.Project.DeleteProjectRequirementParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/delete`, method: 'post', data }); } /** 拆分项目需求 */ export async function fetchSplitProjectRequirement(data: Api.Project.SplitProjectRequirementParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/split`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 关闭项目需求 */ export function fetchCloseProjectRequirement(data: Api.Project.CloseProjectRequirementParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/close`, method: 'post', data }); } /** 获取项目需求可执行状态动作列表 */ export async function fetchGetProjectRequirementAllowedTransitions(requirementId: string, projectId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/allowed-transitions`, method: 'get', params: { requirementId, projectId } }); return mapServiceResult( result as ServiceRequestResult, data => data ); } /** 批量获取项目需求可执行状态动作列表 */ export async function fetchGetProjectRequirementAllowedTransitionsBatch( data: Api.Project.ProjectRequirementBatchReqVO ) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/allowed-transitions/batch`, method: 'post', data }); return mapServiceResult( result as ServiceRequestResult, data1 => data1.map(item => ({ requirementId: normalizeStringId(item.requirementId), transitions: item.transitions })) ); } /** 提交项目需求评审 */ export async function fetchSubmitProjectRequirementReview(data: Api.Project.ProjectRequirementReviewSubmitParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/review/submit`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 获取项目需求评审记录 */ export async function fetchGetProjectRequirementReview(projectId: string, requirementId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/review/get`, method: 'get', params: { projectId, requirementId } }); return mapServiceResult( result as ServiceRequestResult, normalizeProjectRequirementReview ); } /** 获取项目需求状态字典 */ export async function fetchGetProjectRequirementStatusDict() { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/status/dict`, method: 'get' }); return mapServiceResult(result as ServiceRequestResult, data => data); } /** 获取项目需求模块树 */ export async function fetchGetProjectRequirementModuleTree(projectId: string) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/module/tree`, method: 'get', params: { projectId } }); return mapServiceResult(result as ServiceRequestResult, data => data.map(normalizeProjectRequirementModule) ); } /** 创建项目需求模块 */ export async function fetchCreateProjectRequirementModule(data: Api.Project.SaveProjectRequirementModuleParams) { const result = await request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/module/create`, method: 'post', data }); return mapServiceResult(result as ServiceRequestResult, normalizeStringId); } /** 更新项目需求模块 */ export function fetchUpdateProjectRequirementModule(data: Api.Project.SaveProjectRequirementModuleParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/module/update`, method: 'put', data }); } /** 删除项目需求模块 */ export function fetchDeleteProjectRequirementModule(data: Api.Project.DeleteProjectRequirementModuleParams) { return request({ ...safeJsonRequestConfig, url: `${PROJECT_REQUIREMENT_PREFIX}/module/delete`, method: 'post', data }); }