项目中心

This commit is contained in:
wangzzpeng
2026-09-28 17:47:07 +08:00
parent 43c2dc0d8d
commit b014fffacf
23 changed files with 1630 additions and 1577 deletions

View File

@@ -130,34 +130,92 @@ export interface ProjectBill {
projectName: string
}
/** 售后工单 */
/**
* 售后工单(详情页组件契约)。
*
* <p>两态:`处理中` = 售后工单存在且未撤回/未作废(含后端 REQUESTED / IN_PROGRESS);
* `无` = 没有工单,或最近一条已 WITHDRAWN(撤回后回到可再次申请的状态)。</p>
*/
export interface AfterSales {
status: '无' | '处理中'
/**
* 售后类型 —— 申请页下拉的固定 8 项:软件 BUG 修复 / 软件 / 固件功能迭代 /
* 硬件 PCB & 电路改版调整 / 硬件故障排查维修 / 成品不良品返修 / 元器件物料替换变更 /
* 物联网整机联调与版本升级 / 交付资料补齐与技术答疑。
* 库内暂无对应字典,值域先写在前端(`views/project/after-sales.vue#TYPE_OPTIONS`)。
*/
type: string
/** 问题描述(后端 `reason`) */
description: string
/** 用户补充备注(后端 `remark`) */
remark: string
/** 售后工单附件(后端 `afterSaleAttachments`,phase = AFTER_SALE) */
attachments: FileInfo[]
/** 申请时间(后端 `requestTime`) */
createTime: string
}
/** 售后提交入参 */
export interface AfterSalesPayload {
type: string
description: string
remark: string
attachments: FileInfo[]
/**
* 售后附件(已上传到 OSS,携带 ossId 以便提交时由后端转存)。
*
* <p>上传走需求提报的同一个 OSS 上传口(`POST /web/workOrderDraft/upload`),
* 提交时只传 `ossId` 列表,后端按 `phase = AFTER_SALE`、`target_id = 售后工单 id`
* 写进 `vm_project_requirement_attachment`,OSS 文件不重复上传。</p>
*/
export interface AfterSalesAttachment extends FileInfo {
/** OSS 主键(提交时进 `attachmentOssIds`) */
ossId: string | number
}
/**
* 项目详情(**详情页仍是前端 mock 形态**,尚未接后端)。
* OSS 上传返回(后端 `SysOssVo` 的子集)—— 与需求提报共用同一个上传口。
*
* <p>列表已改走真实接口(见 {@link RdProjectVo}),本类型只服务详情页那几个组件。</p>
* <p>⚠️ `fileSuffix` 带前导点(`.pdf`);响应里**没有**文件大小,大小要取本地 `File.size`。</p>
*/
export interface AfterSalesUploadVo {
ossId: string | number
url: string
originalName: string
fileSuffix?: string
}
/**
* 售后申请入参 —— **对齐后端 `ProjectRequirementActionBo`**。
*
* <p>字段名与页面语义的对应:页面「问题描述」→ {@link reason}、「补充备注」→ {@link note}。</p>
*/
export interface AfterSalesPayload {
/** 售后类型(下拉 8 项之一),最长 50 */
type: string
/** 问题描述 → 后端 `reason`,最长 500 */
reason: string
/** 补充备注 → 后端 `note`(页面限 500,后端 BO 上限 2000) */
note: string
/** 附件 OSS 主键集合(空数组安全,后端 null 会走空判断) */
attachmentOssIds: Array<string | number>
}
/**
* 项目详情页数据模型 —— **详情页组件契约**,不是后端原样字段。
*
* <p>后端详情已拆成 4 个页签接口(见 {@link RequirementDetailBundle}),由
* `utils/projectVo.ts#toProjectDetail` 合并映射成本类型;详情页 6 个子组件
* (InfoCard/Team/Milestones/Files/Finance/AfterSales)只认这套字段,因此换数据来源
* 不需要动组件。</p>
*/
export interface Project {
id: string
projectNo: string
projectName: string
/** 归一化后的枚举(未知类型会落到 'other',仅供图标/配色等视觉用途) */
businessType: BusinessType
/**
* 后端**原样下发**的业务类型名称(如「互联网软件」,来自提报表)。
*
* <p>⚠️ 展示一律用它:`businessType` 只有 5 个固定枚举,后台新增业务类型时会全部落成
* 「其他」——那是枚举的兜底,不是接口的值。</p>
*/
businessTypeName: string
progress: number
status: ProjectStatus
submitTime: string
@@ -185,16 +243,16 @@ export interface ProjectTypeCount {
/**
* 项目列表查询条件(**已是后端口径**)。
*
* <p>与 `RdProjectBo` 的字段对应关系:`keyword → key`、`businessType → businessType`(提报表 id)、
* <p>与 `RdProjectBo` 的字段对应关系:`keyword → key`、`businessTypes → businessTypes`(提报表 id,多选 IN)、
* `status → status`(码值)、`startDate/endDate 或 timeShortcut → beginTime/endTime`(两者都落在
* `create_time` 上)、`pageNum/pageSize → PageQuery`。</p>
*
* <p>用空串表示「不限」而不是 'all'——空串直接不出现在 querystring 里,与后端 `eqIfText` 的语义一致。</p>
* <p>用空串 / 空数组表示「不限」而不是 'all'——空值直接不出现在 querystring 里,与后端 `eqIfText` 的语义一致。</p>
*/
export interface ProjectQuery {
keyword: string
/** '' = 全部;否则为后端统计下发的 businessTypeId */
businessType: string
/** 空数组 = 全部;元素为后端统计下发的 businessTypeId(**多选**,后端走 IN) */
businessTypes: string[]
/** '' = 全部;否则为 {@link RdProjectStatus} 码值 */
status: string
/** 提交时间快捷区间;与 startDate/endDate 互斥(选其一会把另一组清空) */
@@ -208,12 +266,22 @@ export interface ProjectQuery {
}
// ─────────────────────────────────────────────────────────────────────────────
// 详情契约:后端 `ProjectRequirementUserVo`(GET /web/requirementPool/get/{id})
// 详情契约:后端 4 个页签接口(都继承 ProjectRequirementBaseVo)
// GET /web/requirementPool/get/progress/{id} → ProjectRequirementProgressVo
// GET /web/requirementPool/get/files/{id} → ProjectRequirementFilesVo
// GET /web/requirementPool/get/finance/{id} → ProjectRequirementFinanceVo
// GET /web/requirementPool/get/afterSales/{id} → ProjectRequirementAfterSalesVo
//
// 与列表不同,详情是「需求表为主 + 各子表按需填充」:需求未立项时 `vm_rd_project`
// 没有对应行,项目侧字段(projectStage / projectMilestones / members / billPlans /
// invoices / contracts)一律为空,需求侧字段(基本信息 / requirementAttachments /
// afterSale)照常返回。
// 为什么拆 4 个:详情页本就是 4 个页签,单接口要一次查全 8 张表;拆开后可「按页签取数」。
// 4 个 VO 都带基础信息(继承 `ProjectRequirementBaseVo`)⇒ 任一页签的响应里都有项目名 /
// 编号 / 业务类型 / 状态 / 提交时间,所以前端可以只用 `progress` 那一支渲染顶部信息卡,
// 并保证切页签后信息卡不缺数据(合并逻辑见 utils/projectVo.ts#toProjectDetail)。
//
// 与列表一致:需求未立项时 `vm_rd_project` 没有对应行,项目侧字段(projectStage /
// projectMilestones / members / billPlans / invoices / contracts)为空数组 / null,
// 需求侧字段(基础信息 / requirementAttachments / afterSale)照常返回。
// ⚠️ id 传的是**需求 id**(vm_project_requirement.id)= 列表行的 RdProjectVo.id;
// 不存在 / 非本人 → 后端 `data` 为 null(详情页整页空态)。
// ─────────────────────────────────────────────────────────────────────────────
/** 开发进度(后端 `ProjectStage`,表 `vm_project_stage`) */
@@ -275,7 +343,8 @@ export interface RequirementBillPlan {
projectId: string | null
projectNo: string | null
projectName: string | null
totalAmount: number | null
/** ⚠️ BigDecimal ⇒ 后端以**字符串**下发("120000.00"),用前必须 `Number()` 归一 */
totalAmount: string | number | null
periods: number | null
currentPeriod: number | null
periodRule: string | null
@@ -290,7 +359,8 @@ export interface RequirementInvoice {
invoiceTitle: string | null
taxNo: string | null
invoiceType: string | null
amount: number | null
/** ⚠️ BigDecimal ⇒ 字符串下发,用前 `Number()` 归一 */
amount: string | number | null
status: string | null
invoiceNo: string | null
/** 电子发票文件地址 */
@@ -307,7 +377,8 @@ export interface RequirementContract {
contractNo: string | null
projectId: string | null
title: string | null
amount: number | null
/** ⚠️ BigDecimal ⇒ 字符串下发,用前 `Number()` 归一 */
amount: string | number | null
signStatus: string | null
status: string | null
signDate: string | null
@@ -321,8 +392,21 @@ export interface RequirementContract {
export interface RequirementAfterSale {
id: string
requirementId: string | null
/** 售后原因 */
/**
* 售后类型 —— 申请页下拉的固定 8 项:软件 BUG 修复 / 软件 / 固件功能迭代 /
* 硬件 PCB & 电路改版调整 / 硬件故障排查维修 / 成品不良品返修 / 元器件物料替换变更 /
* 物联网整机联调与版本升级 / 交付资料补齐与技术答疑。
* 库内暂无对应字典,值域先写在前端(`views/project/after-sales.vue#TYPE_OPTIONS`)。
*/
type: string | null
/** 售后原因(用户在申请页填的「问题描述」) */
reason: string | null
/** 用户补充备注(申请页的「补充备注」) */
remark: string | null
/**
* REQUESTED(待受理)/ IN_PROGRESS(处理中)/ WITHDRAWN(已撤回)/ COMPLETED(已完成)
* —— 见 `ProjectRequirementConstants`。
*/
status: string | null
requestUserName: string | null
requestTime: string | null
@@ -333,40 +417,74 @@ export interface RequirementAfterSale {
}
/**
* 需求详情响应(后端 `ProjectRequirementUserVo`)。
* 4 个页签接口的公共基础信息(后端 `ProjectRequirementBaseVo`)。
*
* <p>注意两个「名字骗人」的字段:`attachments` / `afterSales`(复数)后端**从未赋值**,
* 真正有数据的是 `requirementAttachments` 与 `afterSale`(单数)。前端只取后者。</p>
* <p>字段全部来自需求表 `vm_project_requirement`,**与是否立项无关**,任意页签都填充。</p>
*/
export interface RequirementDetailVo {
export interface RequirementBaseVo {
/** 需求 id(= 详情接口路径参数 = 列表行 RdProjectVo.id) */
id: string
projectNo: string | null
submitUserId: string | null
submitUserName: string | null
submitPhone: string | null
projectName: string | null
/** 业务类型**中文名**(如「硬件电路」),非英文 code */
businessType: string | null
projectName: string | null
requirementDesc: string | null
priority: string | null
/** 状态码值:需求侧 INITIATING/CANCELLED,项目侧 IN_PROGRESS/… */
status: string | null
customerServiceName: string | null
customerServicePhone: string | null
technicalOwnerName: string | null
internalRemark: string | null
attachmentCount: number | null
/** 提交时间 */
createTime: string | null
updateTime: string | null
launchNote: string | null
cancelReason: string | null
/** 未立项时为 null */
/** 提交人名称 */
submitUserName: string | null
}
/** 「项目进度」页签(后端 `ProjectRequirementProgressVo`):基础信息 + 开发进度 + 里程碑 + 团队 */
export interface RequirementProgressVo extends RequirementBaseVo {
/** 开发进度;未立项为 null */
projectStage: RequirementProjectStage | null
/**
* 总体进度百分比(= 列表 `RdProjectVo.progress`,同源 `vm_rd_project.progress`)。
* 后端在项目行没有 progress 时回落到 `projectStage.developmentProgress`;未立项为 null。
*/
developmentProgress?: number | null
projectMilestones: RequirementMilestone[]
requirementAttachments: RequirementAttachment[]
/** 项目团队;未立项为空数组 */
members: RequirementMember[]
}
/** 「项目文件」页签(后端 `ProjectRequirementFilesVo`):基础信息 + 需求附件 */
export interface RequirementFilesVo extends RequirementBaseVo {
/** 需求附件;与是否立项无关,始终填充 */
requirementAttachments: RequirementAttachment[]
}
/** 「合同财务」页签(后端 `ProjectRequirementFinanceVo`):基础信息 + 付款计划 + 发票 + 合同 */
export interface RequirementFinanceVo extends RequirementBaseVo {
billPlans: RequirementBillPlan[]
invoices: RequirementInvoice[]
contracts: RequirementContract[]
afterSale: RequirementAfterSale | null
}
/** 「售后信息」页签(后端 `ProjectRequirementAfterSalesVo`):基础信息 + 售后工单 + 工单附件 */
export interface RequirementAfterSalesVo extends RequirementBaseVo {
/** 售后工单;无则 null */
afterSale: RequirementAfterSale | null
/**
* 售后工单附件 —— 与需求附件同表 `vm_project_requirement_attachment`,
* 靠 `phase = AFTER_SALE` + `target_id = 售后工单 id` 区分。
* 后端无条件下发(无工单时为空数组),前端直接渲染即可。
*/
afterSaleAttachments: RequirementAttachment[]
}
/**
* 详情页四接口聚合结果。
*
* <p>`api/project.ts#getProjectDetail` 同帧并行取回 4 个页签后交给
* `utils/projectVo.ts#toProjectDetail` 合并成组件契约 {@link Project};
* 任一接口返回 null(需求不存在 / 非本人)即整页空态。</p>
*/
export interface RequirementDetailBundle {
progress: RequirementProgressVo
files: RequirementFilesVo
finance: RequirementFinanceVo
afterSales: RequirementAfterSalesVo
}

View File

@@ -1,65 +0,0 @@
// 后端「用户web端首页」接口真实返回类型
// 对应 vermis-maker: com.ruoyi.vermins.controller.pc.web.UserSideWebHomePageController
// 统一前缀: /web/home-page (公开接口,无需登录)
// 字段与后端 VO 严格对齐(驼峰、可空用 | null)。
/** GET /web/home-page/project-status-count —— 项目状态统计 */
export interface ProjectStatusCount {
/** 项目数量 */
projectCount: number
/** 进行中的项目数目 */
ongoingProjectCount: number
/** 待处理数目 */
pendingProjectCount: number
}
/** 服务类型子项(service-type-list / service-type-detail 内含) */
export interface ProjectServiceTypeVo {
id: number | null
projectId: number | null
serviceName: string | null
iconUrl: string | null
sortOrder: number | null
}
/** 项目背景(富文本) */
export interface ProjectBackgroundVo {
id: number | null
projectId: number | null
content: string | null
sortOrder: number | null
}
/** 项目提报视图对象:service-type-list / service-type-detail/{id} 的返回 */
export interface ProjectSubmissionVo {
id: number
businessType: string | null
title: string | null
subtitle: string | null
/** 是否启用:1 启用,0 停用 */
enabled: number | null
coverUrl: string | null
logoUrl: string | null
serviceTypes: ProjectServiceTypeVo[]
backgrounds: ProjectBackgroundVo[]
/** yyyy-MM-dd HH:mm:ss */
updateTime: string | null
}
/** GET /web/home-page/carousel-list —— 轮播图 */
export interface BannerVo {
id: number | null
imageUrl: string | null
sort: number | null
/** 是否启用(true 启用,false 停用) */
enabled: boolean | null
}
/** GET /web/home-page/platform-intro、contact-info —— 协议/静态文章富文本 */
export interface AgreementFormVo {
id: number | null
/** 协议类型(目前只有「关于我们」一条) */
type: string | null
/** 文章内容(富文本 HTML) */
content: string | null
}