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;
      /** 优先级字典 value（rdms_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 {
      /**
       * 文件 ID（infra_file.id 字符串形式）。
       * 用于会话级清理时调用 DELETE /system/file/delete?id=xxx 删除孤儿文件。
       */
      fileId: string;
      url: string;
      name: string;
      size?: number;
      contentType?: string;
      /** 对象存储配置编号（上传返回），与 path 一起拼永久代理 URL */
      configId?: string;
      /** 文件相对路径（上传返回），与 configId 一起拼永久代理 URL */
      path?: 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（按钮可见度公式用）；跨执行查询为空时，前端无法识别执行负责人身份 */
      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;
      /** 优先级字典 value（rdms_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;
    }

    /**
     * 执行截止时间范围（基于 plannedEndDate）：overdue 逾期 / 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;
        /** 优先级筛选（字典 value：String "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;
      /** 优先级字典 value（rdms_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;
      /** 优先级字典 value（rdms_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 为 null；hours=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;
      /** 周一～周日逐日工时（固定 7 元素；按周填报时仅均摊到工作日，周末单天工时保留在周末当天） */
      dailyHours: number[];
      /** 本周工时按归属分布，hours 降序 */
      distribution: WorklogDistributionItem[];
    }

    /** 工作台「团队工时周聚合」成员（members[0] 恒为当前用户；该周未填报成员 items 为 []） */
    interface TeamWorklogWeekMember {
      userId: string;
      userNickname: string;
      items: WorklogDistributionItem[];
      overtimeHours: number;
    }

    /** 工作台「团队工时周聚合」响应（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;
        /** 优先级筛选（字典 value：String "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;
        /** 优先级筛选（字典 value：String "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（不传也走 mine）；all 必须有 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;
      /** 本次填报小时数（BigDecimal，0.5 颗粒，> 0） */
      durationHours: number;
      /** 本次填报进度（0~100，scale=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~100，scale=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;
      /** 当前登录用户在该项目的角色（后端只读计算字段，随登录身份变化；无角色为 []） */
      currentUserRoles: Api.Common.CurrentUserRole[];
    }

    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;
      /** 父需求 ID，0 表示顶级需求 */
      parentId: string;
      /** 所属模块 ID */
      moduleId: string;
      /** 是否需要评审 */
      reviewRequired: ProjectRequirementReviewRequired;
      /** 需求标题 */
      title: string;
      /** 需求描述 */
      description?: string | null;
      /** 附件列表 */
      attachments?: AttachmentItem[] | null;
      /** 需求分类字典值 */
      category: string;
      /** 需求分类名称 */
      categoryName?: string | null;
      /** 需求来源类型 */
      sourceType: ProjectRequirementSourceType;
      /** 来源业务编号 */
      sourceBizCode?: 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;
      /** 项目需求进度（BigDecimal，0.00 ~ 1.00；HALF_UP 两位小数）。读时聚合，后端不接受写入。 */
      progressRate: number;
      /** 创建时间 */
      createTime: string;
      /** 更新时间 */
      updateTime: string;
      /** 子需求列表 */
      children?: ProjectRequirement[];
    }

    interface ProjectRequirementModule {
      /** 模块 ID */
      id: string;
      /** 父模块 ID，0 表示顶级 */
      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' | 'sourceBizCode'
        > & {
          projectId: string;
          title: string;
        }
    >;

    /** 创建项目需求参数 */
    type SaveProjectRequirementParams = Pick<
      ProjectRequirement,
      | 'projectId'
      | 'moduleId'
      | 'reviewRequired'
      | 'title'
      | 'description'
      | 'attachments'
      | 'category'
      | 'priority'
      | 'sourceBizCode'
      | '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;
    }
  }
}
