Files
cn-rdms-web/src/typings/api/project.d.ts

1376 lines
48 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

declare namespace Api {
/**
* namespace Project
*
* backend api module: "project/project"
*/
namespace Project {
/** 项目状态编码 */
type ProjectStatusCode = 'pending' | 'active' | 'paused' | 'completed' | 'cancelled' | 'archived';
/** 项目状态动作编码 */
type ProjectStatusActionCode = 'auto_start' | 'pause' | 'resume' | 'complete' | 'cancel' | 'reopen' | 'archive';
/** 项目设置基础信息 */
interface ProjectSettingBaseInfo {
/** 项目 ID */
id: string;
/** 项目编码 */
projectCode: string;
/** 项目名称 */
projectName: string;
/** 项目方向字典值 */
directionCode: string;
/** 项目类型字典值 */
projectType: string;
/** 所属产品 ID */
productId: string | null;
/** 所属产品名称 */
productName: string | null;
/** 项目负责人用户昵称 */
managerUserNickname: string | null;
/** 项目负责人用户 ID */
managerUserId: string | null;
/** 项目状态编码 */
statusCode: ProjectStatusCode;
/** 计划开始日期 */
plannedStartDate: string | null;
/** 计划结束日期 */
plannedEndDate: string | null;
/** 实际开始日期 */
actualStartDate: string | null;
/** 实际结束日期 */
actualEndDate: string | null;
/** 项目说明 */
projectDesc: string | null;
/** 最近一次状态动作原因 */
lastStatusReason: string | null;
}
/** 项目生命周期动作 */
interface ProjectLifecycleAction {
actionCode: Exclude<ProjectStatusActionCode, 'auto_start'>;
actionName: string;
needReason: boolean;
}
/** 项目生命周期信息 */
interface ProjectLifecycleInfo {
statusCode: ProjectStatusCode;
lastStatusReason: string | null;
availableActions: ProjectLifecycleAction[];
}
/** 执行状态编码 */
type ProjectExecutionStatusCode = 'pending' | 'active' | 'paused' | 'completed' | 'cancelled';
/** 执行动作编码 */
type ProjectExecutionActionCode = 'start' | 'pause' | 'resume' | 'cancel' | 'complete';
/** 任务状态编码 */
type ProjectTaskStatusCode = 'pending' | 'active' | 'paused' | 'completed' | 'cancelled';
/** 任务动作编码 */
type ProjectTaskActionCode = 'auto_start' | 'pause' | 'resume' | 'complete' | 'cancel';
interface LifecycleAction<ActionCode extends string = string> {
actionCode: ActionCode;
actionName: string;
needReason: boolean;
}
interface StatusBoardItem {
statusCode: string;
statusName: string;
count: number;
sort: number;
terminal?: boolean;
}
interface StatusBoard {
total: number;
items: StatusBoardItem[];
}
interface ProjectExecution {
id: string;
projectId: string;
projectRequirementId: string | null;
/** 关联项目需求名称service 层批量回填;未关联 = null */
projectRequirementName: string | null;
/** 关联项目需求状态编码pending_confirm/pending_review/implementing/accepted/closed/rejected/cancelled */
projectRequirementStatusCode: string | null;
executionName: string;
executionType: string | null;
ownerId: string;
ownerNickname?: string | null;
statusCode: ProjectExecutionStatusCode;
statusName: string | null;
terminal: boolean;
allowEdit: boolean;
availableActions: LifecycleAction<ProjectExecutionActionCode>[];
plannedStartDate: string | null;
plannedEndDate: string | null;
actualStartDate: string | null;
actualEndDate: string | null;
progressRate: number;
/** 优先级字典 valuerdms_req_priority"0" P0 / "1" P1默认/ "2" P2 / "3" P3数字越小越高 */
priority: string;
/** 优先级标签预留字段;当前后端不填、永远为 null前端按 priority 自译 */
priorityName: string | null;
executionDesc: string | null;
lastStatusReason: string | null;
createTime: string;
updateTime: string;
}
interface ExecutionAssignee {
id: string;
executionId: string;
userId: string;
userNickname?: string | null;
joinedAt: string | null;
removedAt: string | null;
removedReason: string | null;
}
/** 执行协办人变更事件类型 */
type ExecutionAssigneeActionType = 'join' | 'inactive' | 'owner_transfer_in' | 'owner_transfer_out';
/** 执行协办人变更历史 */
interface ExecutionAssigneeLog {
id: string;
executionId: string;
actionType: ExecutionAssigneeActionType;
userId: string;
userNicknameSnapshot: string | null;
operatorUserId: string;
operatorNicknameSnapshot: string | null;
actionTime: string;
reason: string | null;
}
type ExecutionAssigneeLogSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
actionTypes: ExecutionAssigneeActionType[];
userId: string;
startTime: string;
endTime: string;
}
>;
/** 通用附件元数据(任务 / 工时等域共用,规则见 AttachmentValidator */
interface AttachmentItem {
/**
* 文件 IDinfra_file.id 字符串形式)。
* 用于会话级清理时调用 DELETE /system/file/delete?id=xxx 删除孤儿文件。
*/
fileId: string;
url: string;
name: string;
size?: number;
contentType?: string;
}
/** 任务详情 / 分页响应里嵌入的活跃协办人引用(按加入时间正序) */
interface TaskAssigneeRef {
id: string;
userId: string;
nickname: string;
/** 加入时间5.6 路径返5.3 嵌入路径不返,留 undefined */
joinedAt?: string | null;
}
/** 协办人变更事件类型5.9 actionType */
type TaskAssigneeActionType = 'join' | 'inactive';
/** 协办人变更日志 */
interface TaskAssigneeLog {
id: string;
taskId: string;
actionType: TaskAssigneeActionType;
userId: string;
userNicknameSnapshot: string | null;
operatorUserId: string;
operatorNicknameSnapshot: string | null;
actionTime: string;
reason: string | null;
}
type TaskAssigneeLogSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
actionTypes: TaskAssigneeActionType[];
userId: string;
startTime: string;
endTime: string;
}
>;
/** 5.7 加入协办人入参 */
interface CreateTaskAssigneeParams {
userId: string;
}
/** 5.8 退出协办人入参 */
interface InactiveTaskAssigneeParams {
reason: string;
}
interface ProjectTask {
id: string;
projectId: string;
executionId: string;
/** 所属执行名称;跨执行查询必有,单执行查询可缺省 */
executionName?: string | null;
/** 所属执行状态编码;跨执行查询必有,单执行查询可缺省(用于灰显已完成执行的任务行) */
executionStatusCode?: ProjectExecutionStatusCode | null;
parentTaskId: string | null;
/** 所属执行关联的项目需求 ID透传未关联 = null */
projectRequirementId: string | null;
/** 所属执行关联的项目需求名称(透传,未关联 = null跨执行查询永远为 null前端不在跨执行视角展示 */
projectRequirementName: string | null;
/** 所属执行关联的项目需求状态编码(同上) */
projectRequirementStatusCode: string | null;
taskTitle: string;
type: string;
ownerId: string;
ownerNickname?: string | null;
/** 所属执行的负责人 userId按钮可见度公式用跨执行查询永远为 null按钮判定退化为只看权限码 */
executionOwnerId: string | null;
/** 父任务负责人 userId一级任务为 null */
parentTaskOwnerId: string | null;
statusCode: ProjectTaskStatusCode;
statusName: string | null;
terminal: boolean;
allowEdit: boolean;
availableActions: LifecycleAction<ProjectTaskActionCode>[];
progressRate: number;
plannedStartDate: string | null;
plannedEndDate: string | null;
actualStartDate: string | null;
actualEndDate: string | null;
/** 优先级字典 valuerdms_req_priority"0" P0 / "1" P1默认/ "2" P2 / "3" P3数字越小越高 */
priority: string;
/** 优先级标签预留字段;当前后端不填、永远为 null前端按 priority 自译 */
priorityName: string | null;
taskDesc: string | null;
lastStatusReason: string | null;
assignees?: TaskAssigneeRef[] | null;
attachments?: AttachmentItem[] | null;
/** 已填报工时合计单位小时0.5 颗粒BigDecimal。逻辑删除的工时不计入。 */
totalSpentHours?: number | null;
createTime: string;
updateTime: string;
}
/**
* 执行截止时间范围(基于 plannedEndDateoverdue 逾期 / today 今天到期 / thisWeek 本周到期。
* 与任务侧 dueRange 同口径,后端三档均排除终态执行(已完成 / 已取消);未知值 = 不过滤。
*/
type ProjectExecutionDueRange = 'overdue' | 'today' | 'thisWeek';
/**
* 项目执行分页入参(`GET /project/project/{projectId}/executions/page`)。
*
* - `involveUserId` / `ownerId` 互斥:同传后端不报错但语义变 AND前端切视角时务必清另一字段。
* - 不传 `involveUserId` 且不传 `ownerId` = 项目下全部执行。
* - `dueRange` 按计划结束日期过滤,与其它参数 AND详见 ProjectExecutionDueRange。
*/
type ProjectExecutionSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
keyword: string;
executionType: string;
/** "我参与"语义:当前用户作为 owner 或活跃协办;与 ownerId 二选一 */
involveUserId: string;
/** 仅作为 owner 匹配;与 involveUserId 二选一 */
ownerId: string;
statusCode: string;
/** 优先级筛选(字典 valueString "0"~"3"),不传 = 全部档位 */
priority: string;
dueRange: ProjectExecutionDueRange;
updateTime: string[];
}
>;
type ProjectExecutionStatusBoardParams = CommonType.RecordNullable<{
keyword: string;
executionType: string;
/** "我参与"语义:当前用户作为 owner 或活跃协办;与 ownerId 二选一 */
involveUserId: string;
/** 仅作为 owner 匹配;与 involveUserId 二选一 */
ownerId: string;
/** 截止时间范围过滤,传入后各状态分组计数均在该范围内统计(口径同 page */
dueRange: ProjectExecutionDueRange;
updateTime: string[];
}>;
/** 工作台「我负责的执行」(跨项目)查询入参 */
type MyExecutionSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
/** 预留:单状态精确过滤,不传走后端默认口径 */
statusCode: string;
/** 预留:执行名称模糊匹配 */
keyword: string;
}
>;
/** 工作台「我负责的执行」单项跨项目聚合owner 恒为当前登录用户) */
interface MyExecutionItem {
/** 执行 ID雪花 ID字符串 */
id: string;
executionName: string;
/** 所属项目 */
projectId: string;
projectName: string;
/** 执行状态编码pending / active / paused */
statusCode: string;
/** 执行状态名称 */
statusName: string | null;
/** 优先级字典 valuerdms_req_priority"0"~"3" */
priority: string;
/** 计划起止YYYY-MM-DD */
plannedStartDate: string | null;
plannedEndDate: string | null;
/** 实际起止YYYY-MM-DD */
actualStartDate: string | null;
actualEndDate: string | null;
/** 进度0-100 整数) */
progressRate: number;
/** 关联项目需求 */
projectRequirementId: string | null;
projectRequirementName: string | null;
}
/** 工作台「我的项目」查询入参(我参与的 / 我负责的 共用) */
type MyProjectSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
/** 预留:项目名称/编码模糊关键字,后端本期不过滤 */
keyword: string;
}
>;
/** 工作台「我参与的项目」单项(成员视角,附带我的角色与任务量) */
interface MyParticipatedProjectItem {
/** 项目 ID字符串 */
id: string;
name: string;
/** 项目编码,可空 */
code: string | null;
/** 项目状态编码(如 active */
statusCode: string;
/** 项目状态名称,可空 */
statusName: string | null;
/** 项目整体进度 0-100 */
progress: number;
/** 我在该项目中的角色名(多角色拼接),可空 */
myRole: string | null;
/** 我负责的任务总数(按负责人,含已完成) */
myTaskCount: number;
/** 我负责的未完成任务数 */
myPendingTaskCount: number;
}
/** 工作台「我负责的项目」成员负载子项 */
interface MyOwnedProjectMember {
/** 成员用户 ID字符串 */
userId: string;
/** 成员姓名/昵称,可空 */
userName: string | null;
/** 该成员在本项目下进行中任务数(按负责人) */
activeTaskCount: number;
}
/** 工作台「我负责的项目」单项(项目负责人视角,附聚合统计与成员负载) */
interface MyOwnedProjectItem {
/** 项目 ID字符串 */
id: string;
name: string;
/** 项目编码,可空 */
code: string | null;
/** 项目整体进度 0-100 */
progress: number;
/** 我在该项目中的角色名,可空 */
myRole: string | null;
/** 项目计划结束日期 YYYY-MM-DD可空 */
plannedEndDate: string | null;
/** 项目下进行中执行数 */
executionCount: number;
/** 项目下进行中任务数 */
taskCount: number;
/** 项目下逾期任务数 */
overdueCount: number;
/** 项目当前有效成员数(多角色去重) */
memberCount: number;
/** 成员负载列表(无成员为 [] */
members: MyOwnedProjectMember[];
}
/** 工作台「我的任务」(跨项目)查询入参 */
type MyTaskSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
/** 身份过滤owner 我负责 / collaborator 我协办;缺省 = 两者并集 */
involveType: 'owner' | 'collaborator';
}
>;
/** 工作台「我的任务」单项(跨项目;当前用户为负责人或在岗协办人,接口只返回非终态任务) */
interface MyTaskItem {
/** 任务 ID雪花 ID字符串 */
id: string;
taskTitle: string;
/** 所属项目 */
projectId: string;
projectName: string;
/** 所属执行,未挂执行为 null */
executionId: string | null;
executionName: string | null;
/** 任务状态pending / active / paused非终态 */
statusCode: ProjectTaskStatusCode;
statusName: string | null;
/** 优先级字典 valuerdms_req_priority"0"~"3",数字越小越高) */
priority: string;
/** 计划结束日期YYYY-MM-DD可空 */
plannedEndDate: string | null;
/** 任务进度0-100后端定稿直接返回无进度明确返 0 */
progressRate: number;
/** 创建时间YYYY-MM-DD HH:mm:ss后端返毫秒时间戳适配层归一 */
createTime: string;
/** 我的角色owner 负责人 / collaborator 协办人;双重身份只返 owner */
myRole: 'owner' | 'collaborator';
/** 父任务 ID字符串一级任务为 null */
parentTaskId: string | null;
/** 是否终态;本接口只返非终态任务,正常恒为 false */
terminal: boolean;
/** 当前状态是否允许编辑任务 */
allowEdit: boolean;
/** 当前登录用户可执行的生命周期动作与任务详情同口径auto_start 不返回),无动作为 [] */
availableActions: LifecycleAction<ProjectTaskActionCode>[];
}
/** 工作台「团队负载」分布子项kind != project 时 projectId / projectName 为 null */
interface TeamLoadDistributionItem {
projectId: string | null;
projectName: string | null;
/** project 项目任务 / personal 个人事项 / other 无法归类的残留 */
kind: 'project' | 'personal' | 'other';
/** 未完成任务数(含待开始/已暂停) */
count: number;
}
/** 工作台「团队负载」成员members[0] 恒为当前用户) */
interface TeamLoadMember {
/** 用户 ID字符串 */
userId: string;
userNickname: string;
/** 未完成任务按归属分布,无任务为 [] */
items: TeamLoadDistributionItem[];
/** 临期:今天 ≤ 计划结束 ≤ 今天+3 天,且未完成(与逾期互斥) */
dueSoonCount: number;
/** 逾期:计划结束 < 今天,且未完成 */
overdueCount: number;
}
/** 工作台「团队负载」响应GET /project/project/me/team-load团队 = 自己 + 管理链路直接下级) */
interface TeamLoadResult {
members: TeamLoadMember[];
}
/** 工作台工时分布子项kind != project 时 projectId / projectName 为 nullhours=0 的行后端不输出) */
interface WorklogDistributionItem {
projectId: string | null;
projectName: string | null;
kind: 'project' | 'personal' | 'other';
hours: number;
}
/** 工作台「我的工时周聚合」响应GET /project/project/me/worklog-week */
interface MyWorklogWeekResult {
/** 归一后的周一日期 YYYY-MM-DD */
weekStart: string;
/** 周一~周五逐日工时(固定 5 元素;均摊推算值,周末份额归周五) */
dailyHours: number[];
/** 本周工时按归属分布hours 降序 */
distribution: WorklogDistributionItem[];
}
/** 工作台「团队工时周聚合」成员members[0] 恒为当前用户;该周未填报成员 items 为 [] */
interface TeamWorklogWeekMember {
userId: string;
userNickname: string;
items: WorklogDistributionItem[];
}
/** 工作台「团队工时周聚合」响应GET /project/project/me/team-worklog-week周标准工时后端不返回前端落常量 35 */
interface TeamWorklogWeekResult {
weekStart: string;
members: TeamWorklogWeekMember[];
}
/** 工作台工时周聚合查询入参weekStart 传任意日期,后端归一到所在周周一) */
interface WorklogWeekParams {
weekStart: string;
}
/** 创建执行入参(含 ownerId + assigneeUserIds */
interface CreateProjectExecutionParams {
executionName: string;
executionType: string;
ownerId: string;
projectRequirementId: string | null;
plannedStartDate: string | null;
plannedEndDate: string | null;
/** 优先级字典 value必填String "0"~"3" */
priority: string;
executionDesc: string | null;
assigneeUserIds?: string[];
}
/** 执行创建/编辑弹层 emit 的统一 payload创建时含 ownerId + assigneeUserIds编辑时不含 */
type SaveProjectExecutionParams = CreateProjectExecutionParams;
/** 编辑执行入参(不含 ownerId / assigneeUserIds */
interface UpdateProjectExecutionParams {
executionName: string;
executionType: string;
projectRequirementId: string | null;
plannedStartDate: string | null;
plannedEndDate: string | null;
/** 优先级字典 value必填String "0"~"3" */
priority: string;
executionDesc: string | null;
}
interface ChangeExecutionOwnerParams {
newOwnerId: string;
reason: string | null;
}
interface ChangeExecutionStatusParams {
actionCode: ProjectExecutionActionCode;
reason: string | null;
}
interface CreateExecutionAssigneeParams {
userId: string;
}
interface InactiveExecutionAssigneeParams {
reason: string;
}
type ProjectTaskSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
keyword: string;
parentTaskId: string;
ownerId: string;
statusCode: string;
/** 优先级筛选(字典 valueString "0"~"3"),不传 = 全部档位 */
priority: string;
updateTime: string[];
}
>;
type ProjectTaskStatusBoardParams = CommonType.RecordNullable<{
keyword: string;
parentTaskId: string;
ownerId: string;
updateTime: string[];
}>;
/**
* 任务看板按状态分组的分页入参。
*
* - `statusCode` 缺省 → 返回该执行下任务状态字典中的全部状态(即使该状态下当前没有任务,也要回该列、`total=0`、`list=[]`)。
* - 传入数组 → 只返回这些状态的列。
* - `pageNo` / `pageSize` 应用到所有返回的状态(同一页码下各状态各自分页),前端不需要"每列独立 pageNo"。
*/
type ProjectTaskBoardPageParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
statusCode: string[];
keyword: string;
parentTaskId: string;
ownerId: string;
/** 优先级筛选(字典 valueString "0"~"3"),不传 = 全部档位 */
priority: string;
updateTime: string[];
}
>;
interface ProjectTaskBoardColumn {
statusCode: string;
statusName: string;
sort: number;
terminal?: boolean;
list: ProjectTask[];
total: number;
}
interface ProjectTaskBoardPage {
items: ProjectTaskBoardColumn[];
}
/** 截止时间快速选项(跨执行接口专属) */
type ProjectTaskDueRange = 'overdue' | 'today' | 'thisWeek';
/** 跨执行任务排序字段 */
type ProjectTaskCrossSortBy = 'plannedEndDate' | 'priority' | 'updateTime' | 'createTime';
type ProjectTaskCrossSortOrder = 'asc' | 'desc';
/**
* 项目级跨执行任务分页入参(`GET /project/project/{projectId}/tasks/page`)。
*
* - `involveUserId` / `ownerId` 互斥:同传只 `ownerId` 生效(后端 SQL 双重过滤)。
* - `executionIds` 不传 = 项目内全部执行;空数组 `[]` = 明确返空。
* - `executionInvolveUserId` = 限定到"该用户参与的执行"owner 或活跃执行协办);未参与任何执行时返空;
* 与 `executionIds` 同传为 AND。用它表达"我参与的执行"范围,无需前端先查执行 id 再回传。
* - `executionStatusCodes` 在任务可见性之上叠加"任务所属执行状态 ∈ 白名单"过滤;多值 OR
* 与 `executionIds` 同传时为 AND。详见 `docs/debt/跨执行任务接口-按执行状态过滤-契约调整.html`。
* - 不传 `involveUserId / ownerId` 且无 `project:task:query` 权限时,后端静默降级为"自己有身份的范围",不抛 403。
*/
type ProjectTaskCrossSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
keyword: string;
executionIds: string[];
/**
* 执行成员过滤:该用户作为执行 owner 或活跃执行协办人的执行 → 其下任务;未参与任何执行时返空。
* 与 `involveUserId`(任务成员)正交,可同传取交集。
*/
executionInvolveUserId: string;
/** 任务所属执行的状态白名单(用于左侧执行池按状态 chip 切换时的任务范围过滤) */
executionStatusCodes: ProjectExecutionStatusCode[];
/** "我参与"语义:当前用户作为 owner 或活跃协办;与 ownerId 二选一 */
involveUserId: string;
/** 仅作为 owner 匹配;与 involveUserId 二选一 */
ownerId: string;
statusCodes: ProjectTaskStatusCode[];
/** 优先级字典 value"0"~"3" */
priority: string;
parentTaskId: string;
dueRange: ProjectTaskDueRange;
/** 更新时间范围 [start, end],格式 yyyy-MM-dd HH:mm:ss */
updateTime: string[];
sortBy: ProjectTaskCrossSortBy;
sortOrder: ProjectTaskCrossSortOrder;
}
>;
/** 项目级跨执行任务状态看板入参(与 page 同口径但不含 pageNo/pageSize/statusCodes/sortBy/sortOrder */
type ProjectTaskCrossStatusBoardParams = Omit<
ProjectTaskCrossSearchParams,
'pageNo' | 'pageSize' | 'statusCodes' | 'sortBy' | 'sortOrder'
>;
/** 项目级跨执行任务看板分页入参 */
type ProjectTaskCrossBoardPageParams = Omit<ProjectTaskCrossSearchParams, 'sortBy' | 'sortOrder'>;
/** 项目级"今日小条"汇总入参 */
interface ProjectTaskSummaryParams {
/** 默认 mine不传也走 mineall 必须有 project:task:query 权限,否则 403 */
scope?: 'mine' | 'all';
}
/**
* 项目级"今日小条"汇总响应(`GET /project/project/{projectId}/tasks/summary`)。
*
* 数字一致性dueThisWeek 的范围与 page?dueRange=thisWeek 完全一致(本周一~本周日)。
* today / weekStart / weekEnd 直接展示,不要前端再算"今天/本周一"(服务器时区为 Asia/Shanghai
*/
interface ProjectTaskSummary {
overdue: number;
dueToday: number;
dueThisWeek: number;
doneThisWeek: number;
today: string;
weekStart: string;
weekEnd: string;
}
interface SaveProjectTaskParams {
parentTaskId: string | null;
taskTitle: string;
type: string;
ownerId: string | null;
progressRate?: number;
plannedStartDate: string | null;
plannedEndDate: string | null;
/** 优先级字典 value必填String "0"~"3" */
priority: string;
taskDesc: string | null;
/** 仅创建任务时生效编辑接口静默忽略userId 必须是当前有效执行协办人且不能等于 ownerId */
assigneeUserIds?: string[];
/** 编辑语义null 保留原值 / [] 清空 / [...] 整体替换 */
attachments?: AttachmentItem[] | null;
}
interface ChangeTaskStatusParams {
actionCode: ProjectTaskActionCode;
reason: string | null;
}
/** 任务工时记录 */
interface TaskWorklog {
id: string;
taskId: string;
userId: string;
userNickname: string | null;
/** 段起始日期YYYY-MM-DD单天=与 endDate 相等 */
startDate: string;
/** 段结束日期YYYY-MM-DD单天=与 startDate 相等 */
endDate: string;
/** 本次填报小时数BigDecimal0.5 颗粒,> 0 */
durationHours: number;
/** 本次填报进度0~100scale=2 */
progressRate: number;
/** 难度,来自字典 rdms_task_item_worklog_difficulty */
difficulty: string;
/** 后端预留字段,目前始终为 null前端按 difficulty + 字典 cache 自译 */
difficultyName?: string | null;
workContent: string | null;
attachments?: AttachmentItem[] | null;
createTime: string;
updateTime: string;
}
type TaskWorklogSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
userId: string;
startDate: string;
endDate: string;
/** 完成难度筛选,等值匹配;不传 = 全部 */
difficulty: string;
}
>;
interface SaveTaskWorklogParams {
/** 段起始日期YYYY-MM-DD */
startDate: string;
/** 段结束日期YYYY-MM-DD不得早于 startDate */
endDate: string;
/** 本次填报小时数,> 0 且 0.5 整数倍 */
durationHours: number;
/** 本次填报进度0~100scale=2必填 */
progressRate: number;
/** 难度,来自字典 rdms_task_item_worklog_difficulty */
difficulty: string;
workContent?: string | null;
/** 编辑语义null 保留原值 / [] 清空 / [...] 替换 */
attachments?: AttachmentItem[] | null;
}
/** 项目设置参数 */
interface ProjectSettings {
baseInfo: ProjectSettingBaseInfo;
lifecycle: ProjectLifecycleInfo;
}
/** 项目设置基础信息参数 */
interface UpdateProjectSettingBaseInfoParams {
projectName: string;
directionCode: string;
projectType: string;
plannedStartDate: string | null;
plannedEndDate: string | null;
projectDesc: string | null;
}
/** 项目成员状态 */
type ProjectMemberStatus = 0 | 1;
interface PageParams {
pageNo: number;
pageSize: number;
}
interface PageResult<T = any> {
total: number;
list: T[];
}
/** 入口页概览统计状态看板项(状态机全部启用状态,按 sort 升序,计数为 0 也返回) */
interface OverviewStatusItem {
statusCode: string;
/** 状态展示名(状态机配置中文名,前端直接渲染,不做本地名称映射) */
statusName: string;
count: number;
sort: number;
/** 是否终态(状态机 terminal_flag不能用于"全部"排除或左栏分区completed 也可能是终态) */
terminal: boolean;
/** 是否计入"全部";当前口径无排除项恒为 true将来恢复排除项由该字段表达 */
includeInAll: boolean;
}
/** 项目入口页概览统计 */
interface ProjectOverviewSummary {
/** 项目状态数量映射key 为后端状态编码(过渡兼容字段,前端迁移完成后由后端删除) */
statusCounts: Record<string, number>;
/** "全部"口径总数 = items 各状态 count 之和(作废/归档计入) */
total: number;
/** 状态看板项,覆盖状态机全部启用状态,按 sort 升序 */
items: OverviewStatusItem[];
/** 游离项目计数 = 所有未挂产品的项目(不按状态过滤),左栏游离入口据此显隐 */
orphanCount?: number;
}
interface Project {
/** 项目 ID */
id: string;
/** 项目编码 */
projectCode: string;
/** 项目名称 */
projectName: string;
/** 项目方向字典值 */
directionCode: string;
/** 项目类型字典值 */
projectType: string;
/** 所属产品 ID */
productId: string | null;
/** 所属产品名称 */
productName?: string | null;
/** 项目负责人用户 ID */
managerUserId: string;
/** 项目负责人用户昵称 */
managerUserNickname?: string | null;
/** 项目状态编码 */
statusCode: ProjectStatusCode;
/** 计划开始日期 */
plannedStartDate: string | null;
/** 计划结束日期 */
plannedEndDate: string | null;
/** 实际开始日期 */
actualStartDate: string | null;
/** 实际结束日期 */
actualEndDate: string | null;
/** 进度百分比 */
progressRate: number;
/** 项目说明 */
projectDesc: string | null;
/** 最近一次状态动作原因 */
lastStatusReason: string | null;
/** 创建时间 */
createTime: string;
/** 更新时间 */
updateTime: string;
}
interface ProjectContext {
currentProject: {
id: string;
projectCode: string;
projectName: string;
projectType: string;
productId: string | null;
managerUserId: string;
statusCode: ProjectStatusCode;
};
currentRole: {
roleId: string | null;
roleCode: string | null;
roleName: string | null;
guestFlag: boolean;
};
navs: Array<{
id: string;
name: string;
path: string;
icon: string;
sort: number;
}>;
buttons: string[];
}
interface ProjectMember {
/** 成员关系 ID */
id: string;
/** 用户 ID */
userId: string;
/** 用户昵称 */
userNickname: string;
/** 角色 ID */
roleId: string;
/** 角色名称 */
roleName: string;
/** 角色编码 */
roleCode: string;
/** 是否项目负责人 */
managerFlag: boolean;
/** 成员状态 */
status: ProjectMemberStatus;
/** 加入时间 */
joinedTime: string;
/** 退出时间 */
leftTime: string | null;
/** 备注 */
remark: string | null;
}
/** 项目搜索参数 */
type ProjectSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
keyword: string;
directionCode: string;
projectType: string;
productId: string;
managerUserId: string;
/** 状态编码来自状态机overview-summary items 动态下发),不再用前端字面量联合约束 */
statusCode: string;
/** 多值状态筛选(存在时后端优先于单值 statusCode分组页"展开剩余"按"全部"口径传 items 派生的全量编码 */
statusCodes: string[];
/** 仅查游离项目productId 为空);与 productId 互斥,分组页展开游离组剩余时用 */
orphanOnly: boolean;
updateTime: string[];
}
>;
/**
* 项目列表"按产品分组"查询入参GET /project/project/group-page
*
* - pageNo / pageSize 为**产品组维度**分页(一页 M 个产品组),不是项目行分页。
* - statusCode 不传 = "全部"视图后端从状态机推导2026-06-11 口径变更后无排除项,作废/归档计入)。
* - orphanOnly = true 仅返回游离组productId 为空的项目);不可与 productId 同传。
* - topN每组返回项目条数上限后端默认 5范围 1~50超出由页面展开拉取。
*/
type ProjectGroupSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> & {
keyword: string;
productId: string;
projectType: string;
/** 状态编码来自状态机overview-summary items 动态下发),不再用前端字面量联合约束 */
statusCode: string;
orphanOnly: boolean;
topN: number;
}
>;
/** 按产品聚合的项目分组 */
interface ProjectGroup {
/** 产品 ID游离组为 null */
productId: string | null;
/** 产品名称;游离组固定为"游离项目" */
productName: string;
/** 产品编码;游离组为 null */
productCode: string | null;
/** 产品方向字典值;游离组为空串 */
directionCode: string;
/** 产品经理用户 ID */
managerUserId: string | null;
/** 产品经理昵称(后端回填;游离组为 null前端 managerLabelMap 兜底) */
managerUserNickname: string | null;
/** 当前筛选口径下组内项目总数 */
projectTotal: number;
/** 组内项目前 topN 条,按最近更新倒序;剩余由页面按 productId/orphanOnly + statusCodes 走 page 接口展开拉取 */
projects: Project[];
/** 组内按项目类型字典 value 的计数(现状按"全部口径"统计;已提需求改为跟随 statusCode 与 projectTotal 同口径,后端落地后更新本注释) */
typeCounts: Record<string, number>;
/** 是否已有主线项目(口径=存在非已取消 cancelled 的主线,已归档/完成也算占坑);前端直接消费、不用 typeCounts 推导 */
hasBaseline: boolean;
/** 是否游离组(未挂产品) */
orphan: boolean;
}
/** 产品分组分页结果 */
interface ProjectGroupPageResult {
/** 当前筛选口径下产品组总数(分页 total含游离组 */
total: number;
/** 当前筛选口径下项目总数(标题 meta 用) */
projectTotal: number;
/** 当前筛选口径下可见产品跨方向数≥2 时前端渲染方向层) */
directionCount: number;
/** 当前筛选口径下游离项目数(标题/分页用);左栏常驻游离计数改用 overview-summary 的 orphanCount 全口径 */
orphanTotal: number;
list: ProjectGroup[];
}
/** 创建/保存项目参数 */
type SaveProjectParams = Pick<Project, 'projectName' | 'directionCode' | 'projectType' | 'projectDesc'> & {
projectCode: string | null;
productId: string | null;
managerUserId: string;
plannedStartDate: string | null;
plannedEndDate: string | null;
actualStartDate?: string | null;
actualEndDate?: string | null;
};
/** 更新项目参数 */
type UpdateProjectParams = { id: string } & SaveProjectParams;
/** 变更项目状态参数 */
interface ChangeProjectStatusParams {
id: string;
actionCode: ProjectStatusActionCode;
reason: string | null;
}
/** 删除项目参数 */
interface DeleteProjectParams {
id: string;
projectName: string;
confirmText: string;
reason: string;
}
/** 删除执行入参 */
interface DeleteProjectExecutionParams {
/** 二次确认:必须与当前执行名称完全一致 */
executionName: string;
/** 删除确认口令:接受 "删除" 或 "DELETE" */
confirmText: string;
/** 删除原因,写入审计日志 */
reason: string;
}
/** 删除任务入参 */
interface DeleteProjectTaskParams {
/** 二次确认:必须与当前任务名称完全一致 */
taskName: string;
/** 删除确认口令:接受 "删除" 或 "DELETE" */
confirmText: string;
/** 删除原因,写入审计日志 */
reason: string;
}
/** 执行删除预检spec §2.1:判断是否需要走重型确认弹层) */
interface ProjectExecutionDeletePrecheck {
/** 该执行下任务总数(含子孙,含 completed展示用 */
taskCount: number;
/** taskCount > 0 视为 true */
hasDependentData: boolean;
}
/** 任务删除预检spec §2.1 */
interface ProjectTaskDeletePrecheck {
/** 直接子任务数 */
childTaskCount: number;
/** 工作日志条数 */
worklogCount: number;
/** childTaskCount + worklogCount > 0 视为 true */
hasDependentData: boolean;
}
/** 创建项目成员参数 */
interface CreateProjectMemberParams {
userId: string;
roleId: string;
remark: string | null;
previousManagerUserId?: string | null;
previousManagerRoleId?: string | null;
}
/** 更新项目成员参数 */
interface UpdateProjectMemberParams {
roleId: string;
reason: string | null;
remark: string | null;
previousManagerUserId?: string | null;
previousManagerRoleId?: string | null;
}
/** 移出项目成员参数 */
interface InactiveProjectMemberParams {
reason: string | null;
}
/**
* 批量新增项目成员参数
*
* 刻意不复用 CreateProjectMemberParams批量接口不承担"项目负责人交接"语义,
* 后端兜底拒绝 roleId 为项目负责人角色的项。
*/
interface BatchCreateProjectMembersParams {
members: Array<{
userId: string;
roleId: string;
remark?: string | null;
}>;
}
/** 批量移出项目成员参数 */
interface BatchInactiveProjectMembersParams {
memberIds: string[];
reason?: string | null;
}
/**
* 项目创建(含初始团队)原子接口参数
*
* 新增项目两步向导提交的载荷。经理成员也由前端聚合到 members 数组中。
*/
interface CreateProjectWithTeamParams {
project: SaveProjectParams;
members: CreateProjectMemberParams[];
/** 关注人 user_id 数组(选填);后端按 (user, object, role) 三元组幂等写入 project_watcher 角色 */
watcherUserIds?: string[];
}
// ========== 项目需求相关类型定义 ==========
/** 项目需求状态编码 */
type ProjectRequirementStatusCode =
| 'pending_claim'
| 'pending_review'
| 'reviewed'
| 'review_rejected'
| 'implementing'
| 'accepted'
| 'closed'
| 'rejected'
| 'cancelled';
/** 项目需求状态动作编码 */
type ProjectRequirementStatusActionCode =
| 'claim_to_review'
| 'claim_to_implement'
| 'pass_review'
| 'reject_review'
| 'start_implement'
| 'accept'
| 'cancel'
| 'close'
| 'reject';
/** 项目需求来源类型 */
type ProjectRequirementSourceType = 'manual' | 'work_order' | 'product_requirement';
/** 项目需求优先级 */
type ProjectRequirementPriority = 0 | 1 | 2 | 3;
/** 是否需要评审 */
type ProjectRequirementReviewRequired = 0 | 1;
interface ProjectRequirement {
/** 需求 ID */
id: string;
/** 所属项目 ID */
projectId: string;
/** 父需求 ID0 表示顶级需求 */
parentId: string;
/** 所属模块 ID */
moduleId: string;
/** 是否需要评审 */
reviewRequired: ProjectRequirementReviewRequired;
/** 需求标题 */
title: string;
/** 需求描述 */
description?: string | null;
/** 附件列表 */
attachments?: AttachmentItem[] | null;
/** 需求分类字典值 */
category: string;
/** 需求分类名称 */
categoryName?: string | null;
/** 需求来源类型 */
sourceType: ProjectRequirementSourceType;
/** 来源业务 ID */
sourceBizId?: string | null;
/** 优先级 */
priority: ProjectRequirementPriority;
/** 优先级名称 */
priorityName?: string | null;
/** 当前状态编码 */
statusCode: ProjectRequirementStatusCode;
/** 当前状态名称 */
statusName?: string | null;
/** 最近一次状态动作原因 */
lastStatusReason?: string | null;
/** 提出人用户 ID */
proposerId: string;
/** 提出人昵称 */
proposerNickname?: string | null;
/** 当前处理人用户 ID */
currentHandlerUserId?: string | null;
/** 当前处理人昵称 */
currentHandlerUserNickname?: string | null;
/** 预期完成日期 */
expectedTime?: string | null;
/** 排序值 */
sort: number;
/** 项目需求进度BigDecimal0.00 ~ 1.00HALF_UP 两位小数)。读时聚合,后端不接受写入。 */
progressRate: number;
/** 创建时间 */
createTime: string;
/** 更新时间 */
updateTime: string;
/** 子需求列表 */
children?: ProjectRequirement[];
}
interface ProjectRequirementModule {
/** 模块 ID */
id: string;
/** 父模块 ID0 表示顶级 */
parentId: string;
/** 所属项目 ID */
projectId: string;
/** 模块名称 */
moduleName: string;
/** 模块说明 */
remark?: string | null;
/** 图标 */
icon?: string | null;
/** 排序值 */
sort: number;
/** 子模块列表 */
children?: ProjectRequirementModule[];
}
interface ProjectRequirementStatusDict {
/** 状态编码 */
statusCode: string;
/** 状态名称 */
statusName: string;
/** 排序值 */
sort: number;
/** 是否初始状态 */
initialFlag: boolean;
/** 是否终态 */
terminalFlag: boolean;
/** 是否允许编辑 */
allowEdit: boolean;
}
interface ProjectRequirementLifecycleAction {
actionCode: ProjectRequirementStatusActionCode;
actionName: string;
toStatusCode: string;
toStatusName: string;
needReason: boolean;
}
interface ProjectRequirementBatchReqVO {
projectId: string;
requirementIds: string[];
}
interface ProjectRequirementAllowedTransitionBatchRespVO {
requirementId: string;
transitions: ProjectRequirementLifecycleAction[];
}
type ProjectRequirementReviewConclusion = 0 | 1;
interface ProjectRequirementReviewAttendeeItem {
userId: string;
nickname: string;
}
interface ProjectRequirementReview {
id: string;
objectType: 'project_requirement';
requirementId: string;
operatorId: string;
conclusion: ProjectRequirementReviewConclusion;
reviewContent?: string | null;
requirementEstimatedHours?: number | string | null;
attendees?: ProjectRequirementReviewAttendeeItem[];
attachments?: AttachmentItem[] | null;
reviewTime?: string | null;
createTime?: string;
updateTime?: string;
}
interface ProjectRequirementReviewSubmitParams {
projectId: string;
requirementId: string;
operatorId: string;
conclusion: ProjectRequirementReviewConclusion;
reviewContent?: string | null;
requirementEstimatedHours?: number | string | null;
attendees?: ProjectRequirementReviewAttendeeItem[];
attachments?: AttachmentItem[] | null;
reviewTime?: string | null;
}
/** 项目需求分页查询参数 */
type ProjectRequirementSearchParams = CommonType.RecordNullable<
Pick<PageParams, 'pageNo' | 'pageSize'> &
Pick<
ProjectRequirement,
'moduleId' | 'parentId' | 'category' | 'priority' | 'statusCode' | 'currentHandlerUserId' | 'sourceType'
> & {
projectId: string;
title: string;
}
>;
/** 创建项目需求参数 */
type SaveProjectRequirementParams = Pick<
ProjectRequirement,
| 'projectId'
| 'moduleId'
| 'reviewRequired'
| 'title'
| 'description'
| 'attachments'
| 'category'
| 'priority'
| 'proposerId'
| 'proposerNickname'
| 'currentHandlerUserId'
| 'currentHandlerUserNickname'
| 'expectedTime'
| 'sort'
>;
/** 更新项目需求参数 */
type UpdateProjectRequirementParams = { id: string } & SaveProjectRequirementParams;
/** 变更项目需求状态参数 */
interface ChangeProjectRequirementStatusParams {
id: string;
projectId: string;
actionCode: string;
reason?: string | null;
}
/** 关闭项目需求参数 */
interface CloseProjectRequirementParams {
id: string;
projectId: string;
reason: string;
}
/** 拆分项目需求参数 */
type SplitProjectRequirementParams = Pick<
ProjectRequirement,
| 'parentId'
| 'projectId'
| 'moduleId'
| 'reviewRequired'
| 'title'
| 'description'
| 'attachments'
| 'category'
| 'priority'
| 'proposerId'
| 'proposerNickname'
| 'currentHandlerUserId'
| 'currentHandlerUserNickname'
| 'expectedTime'
| 'sort'
>;
/** 删除项目需求参数 */
interface DeleteProjectRequirementParams {
id: string;
projectId: string;
}
/** 保存项目需求模块参数 */
interface SaveProjectRequirementModuleParams {
id?: string;
projectId: string;
parentId?: string | null;
moduleName: string;
remark?: string | null;
icon?: string | null;
sort?: number;
}
/** 删除项目需求模块参数 */
interface DeleteProjectRequirementModuleParams {
id?: string;
projectId: string;
}
}
}