﻿# PRD-001 产品工时计算

## 文档信息

| 字段 | 内容 |
|------|------|
| 文档编号 | PRD-001 |
| 文档类型 | 产品需求文档 |
| 功能名称 | product-work-hours-estimation |
| 对应流程 | 路径 F: 临时快速任务（Demo→产品，≤7天） |
| 关联用户故事 | US-001 |
| 关联用例 | UC-001 |
| 状态 | 草稿 |
| 仓库定位 | 原型仓库 |
| 说明 | 真实编码工作在外部开发仓库推进，本仓库保留原型与需求文档。 |

## 背景

当前产品报价基于"功能模块工时"进行计算。

不同产品（如 3D 大楼）具有不同的功能模块结构，其中包括：

*   基础产品功能

*   项目导入支援费

*   素材制作

*   定制开发功能


现阶段需要将原有基于表格管理的工时结构，转化为系统内可计算的工时模型。

## 目标

建立一个：

产品工时计算功能

实现以下能力：

1.  使用者选择某个特定产品

2.  系统加载该产品的工时模板

3.  使用者选择可选模块

4.  使用者输入必要数据（如建模工时）

5.  系统自动计算：

    *   各模块费用

    *   分类小计

    *   总报价金额


## 使用场景

当使用者创建一个项目或报价时：

1.  选择产品（例如：3D 大楼）

2.  系统自动加载该产品的标准工时结构

3.  系统默认包含：

    *   必选模块（如项目导入支援费）

    *   默认选中的功能

4.  使用者可：

    *   勾选可选模块

    *   输入可变工时数据（例如建模工时）

5.  系统实时计算并更新：

    *   各模块工时

    *   分类小计

    *   总工时

    *   总金额


```mermaid
flowchart TD
    A([开始]) --> B[选择产品]
    B --> C[加载工时模板]
    C --> D[必选模块自动纳入]
    C --> E{可选模块}
    E --> F{用户勾选?}
    F -->|是| G[纳入计算]
    F -->|否| H[排除计算]
    D --> I[输入可变数据\n如建模工时]
    G --> I
    I --> J[实时计算各模块费用]
    J --> K[分类小计]
    K --> L([总报价金额])
```

## 报价数据说明

报价模板：[请至钉钉文档查看附件《产品模块报价估算模板》](https://alidocs.dingtalk.com/i/nodes/Obva6QBXJw44Knv2cQKe24q48n4qY5Pr?iframeQuery=anchorId%3DX02mm46wdm7cgi279lb5vq)

报价以「模块」为最小计算单元

表格结构包含以下字段含义

数据层级关系如下：

```mermaid
graph TD
    P[产品\nProduct] --> C1[产品功能费]
    P --> C2[项目导入支援费]
    P --> C3[素材制作费]
    P --> C4[定制开发费用]

    C1 --> M1[模块 A]
    C1 --> M2[模块 B]
    C2 --> M3[项目导入]
    C3 --> M4[CG 制作]
    C4 --> M5[定制功能]

    M1 --> F1[功能 1]
    M1 --> F2[功能 2]
    M2 --> F3[功能 3]
    M4 --> F4[建模]
    M4 --> F5[材质制作]
    M4 --> F6[渲染]

    style P fill:#1e3a5f,color:#fff
    style C1 fill:#3b5ea6,color:#fff
    style C2 fill:#3b5ea6,color:#fff
    style C3 fill:#3b5ea6,color:#fff
    style C4 fill:#3b5ea6,color:#fff
```

### 类型

不同的类型，其最终的收费方式不同

*   产品功能费

    *   产品功能费用属于沉默成本，会不断被项目摊销，因此可以减免。采用预先录入的默认数据

*   项目导入支援费

    *   每个项目都会产生的实施成本，因此必须收取。采用预先录入的默认数据

*   素材制作费

    *   每个项目都会产生的制作成本，因此必须收取，需要单独估算。采用输入的数据。

*   定制开发费用

    *   根据客户需求产生的开发成本，根据是否选择动态变化。采用预先录入的默认数据


### 模块

报价的最小单元，从属于类型，用于表明该收费项的具体来源

在产品功能类型下，模块对应实际的 B/C 端产品可见模块

在素材制作费类型下，模块仅指 CG 制作

在项目导入支援费下，模块仅指项目导入(实施)

在定制开发费用下，模块仅指定制功能

每个模块需要包含

*   工时

*   定价

*   是否可选


### 功能

功能属于模块下的子项，功能仅用于展示费用的构成，不单独参与计算。

在产品功能类型下，功能对应实际的 B/C 端产品中的具体功能

在素材制作费类型下，功能指 CG 制作的各个工序任务

在项目导入支援费下，功能仅指项目导入(实施)的具体任务

在定制开发费用下，功能指客户指定的具体定制功能点

### 是否可选配

是否选配说明该模块是否可以选配，「是」代表可选配，「否」代表是固化费用

最终可以根据实际选配情况来决定是否加入计算

### 选配

选配代表对可选配模块的选配状态，如果选配，则模块纳入计算。非可选配的模块无法进行选配设置

### 工时

工时代表该模块的成本工时，仅用作展现，不参与计算。工时可进行更新设置。

### 定价

模块的具体价格，与工时无关联

## 系统架构

<div style="width: 100%; box-sizing: border-box; position: relative;">
  <style scoped>
    .arch-wrapper { display: flex; gap: 12px; }.arch-sidebar { width: 155px; flex-shrink: 0; }.arch-main { flex: 1; min-width: 0; }.arch-title { text-align: center; font-size: 20px; font-weight: bold; color: #1e293b; margin-bottom: 16px; }
    .arch-layer { margin: 8px 0; padding: 12px; border-radius: 10px; box-shadow: 0 2px 8px rgba(15, 23, 42, 0.1); }.arch-layer-title { font-size: 13px; font-weight: bold; color: #1e293b; margin-bottom: 10px; text-align: center; }
    .arch-grid { display: grid; gap: 8px; }.arch-grid-2 { grid-template-columns: repeat(2, 1fr); }.arch-grid-3 { grid-template-columns: repeat(3, 1fr); }.arch-grid-4 { grid-template-columns: repeat(4, 1fr); }
    .arch-box { border-radius: 6px; padding: 8px; text-align: center; font-size: 11px; font-weight: 600; line-height: 1.35; color: #0f172a; background: rgba(255, 255, 255, 0.9); border: 1px solid rgba(15, 23, 42, 0.1); }.arch-box.highlight { background: linear-gradient(135deg, #fef08a 0%, #fde047 100%); border: 2px solid #eab308; }.arch-box.tech { font-size: 10px; background: rgba(255, 255, 255, 0.7); }
    .arch-layer.user { background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); border: 2px solid #3b82f6; }.arch-layer.application { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); border: 2px solid #f59e0b; }.arch-layer.ai { background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); border: 2px solid #22c55e; }.arch-layer.data { background: linear-gradient(135deg, #fce7f3 0%, #fbcfe8 100%); border: 2px solid #ec4899; }.arch-layer.infra { background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%); border: 2px solid #6366f1; }
    .arch-sidebar-panel { border-radius: 8px; padding: 10px; background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%); border: 2px solid #9ca3af; margin-bottom: 10px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); }.arch-sidebar-title { font-size: 12px; font-weight: bold; text-align: center; color: #374151; margin-bottom: 6px; }.arch-sidebar-item { font-size: 10px; text-align: center; color: #1f2937; background: rgba(255, 255, 255, 0.8); padding: 5px; border-radius: 4px; margin: 3px 0; border: 1px solid rgba(0, 0, 0, 0.05); }.arch-sidebar-item.metric { background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); border: 1px solid #86efac; font-weight: 600; }
    .arch-subgroup { display: flex; gap: 8px; margin-top: 8px; }.arch-subgroup-box { flex: 1; border-radius: 6px; padding: 8px; background: rgba(255, 255, 255, 0.5); border: 1px solid rgba(0, 0, 0, 0.08); }.arch-subgroup-title { font-size: 10px; font-weight: bold; color: #374151; text-align: center; margin-bottom: 6px; }
  </style>
  <div class="arch-title">报价估算系统架构图</div>
  <div class="arch-wrapper">
    <div class="arch-sidebar">
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">👤 用户角色</div>
        <div class="arch-sidebar-item">销售人员</div>
        <div class="arch-sidebar-item">项目经理</div>
        <div class="arch-sidebar-item">数据管理员</div>
      </div>
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">📦 产品类型</div>
        <div class="arch-sidebar-item">3D 大楼</div>
        <div class="arch-sidebar-item">其他产品</div>
        <div class="arch-sidebar-item metric">可扩展</div>
      </div>
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">🔑 认证</div>
        <div class="arch-sidebar-item">LoginPage</div>
        <div class="arch-sidebar-item">auth.ts</div>
        <div class="arch-sidebar-item">路由守卫</div>
      </div>
    </div>
    <div class="arch-main">
      <div class="arch-layer user">
        <div class="arch-layer-title">页面层 · Vue 3 SPA</div>
        <div class="arch-grid arch-grid-3">
          <div class="arch-box highlight">ProductQuotePage<br><small>产品报价</small></div>
          <div class="arch-box">CGWorkPage<br><small>CG 工时</small></div>
          <div class="arch-box">DataManagerPage<br><small>数据管理</small></div>
        </div>
      </div>
      <div class="arch-layer application">
        <div class="arch-layer-title">业务逻辑层 · 报价流程</div>
        <div class="arch-subgroup">
          <div class="arch-subgroup-box">
            <div class="arch-subgroup-title">模块管理</div>
            <div class="arch-grid arch-grid-2">
              <div class="arch-box">产品功能费<br><small>默认数据</small></div>
              <div class="arch-box">项目导入费<br><small>固化费用</small></div>
              <div class="arch-box">素材制作费<br><small>输入数据</small></div>
              <div class="arch-box">定制开发费<br><small>可选模块</small></div>
            </div>
          </div>
          <div class="arch-subgroup-box">
            <div class="arch-subgroup-title">选配控制</div>
            <div class="arch-grid arch-grid-1" style="grid-template-columns: 1fr;">
              <div class="arch-box">必选模块<br><small>自动纳入计算</small></div>
              <div class="arch-box highlight">可选模块<br><small>用户勾选后计算</small></div>
              <div class="arch-box">可变工时<br><small>用户输入（如建模）</small></div>
            </div>
          </div>
        </div>
      </div>
      <div class="arch-layer ai">
        <div class="arch-layer-title">计算层 · 实时报价引擎</div>
        <div class="arch-grid arch-grid-3">
          <div class="arch-box">模块费用<br><small>hours × HOURLY_RATE<br>或 customPrice</small></div>
          <div class="arch-box">分类小计<br><small>Σ 参与计算模块</small></div>
          <div class="arch-box highlight">总报价金额<br><small>Σ 所有分类小计</small></div>
        </div>
      </div>
      <div class="arch-layer data">
        <div class="arch-layer-title">数据层 · 静态配置</div>
        <div class="arch-grid arch-grid-2">
          <div class="arch-box tech">products.ts<br><small>产品报价模板<br>模块 / 功能 / 定价</small></div>
          <div class="arch-box tech">cgwork.ts<br><small>CG 工时树<br>工序 / 工时结构</small></div>
        </div>
      </div>
      <div class="arch-layer infra">
        <div class="arch-layer-title">运行环境</div>
        <div class="arch-grid arch-grid-4">
          <div class="arch-box tech">Vue 3<br><small>前端框架</small></div>
          <div class="arch-box tech">Vue Router<br><small>路由管理</small></div>
          <div class="arch-box tech">TypeScript<br><small>类型安全</small></div>
          <div class="arch-box tech">浏览器<br><small>纯前端 SPA</small></div>
        </div>
      </div>
    </div>
    <div class="arch-sidebar">
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">💴 费用类型</div>
        <div class="arch-sidebar-item">产品功能费</div>
        <div class="arch-sidebar-item">项目导入费</div>
        <div class="arch-sidebar-item">素材制作费</div>
        <div class="arch-sidebar-item">定制开发费</div>
      </div>
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">📊 计算指标</div>
        <div class="arch-sidebar-item metric">实时更新</div>
        <div class="arch-sidebar-item">模块工时</div>
        <div class="arch-sidebar-item">分类小计</div>
        <div class="arch-sidebar-item metric">总报价金额</div>
      </div>
      <div class="arch-sidebar-panel">
        <div class="arch-sidebar-title">🛤️ 路由</div>
        <div class="arch-sidebar-item">/product-quote</div>
        <div class="arch-sidebar-item">/cg-work</div>
        <div class="arch-sidebar-item">/data-manager</div>
      </div>
    </div>
  </div>
</div>

### Mermaid 版本（文字流程）

```mermaid
graph TB
    subgraph Client["前端应用 (Vue 3 SPA)"]
        direction TB

        subgraph AuthLayer["认证层"]
            Login["LoginPage\n登录页"]
            Auth["auth.ts\n会话管理"]
        end

        subgraph RouterLayer["路由层 (Vue Router)"]
            R1["/product-quote"]
            R2["/cg-work"]
            R3["/data-manager"]
        end

        subgraph Pages["页面层"]
            PQ["ProductQuotePage\n产品报价"]
            CG["CGWorkPage\nCG 工时"]
            DM["DataManagerPage\n数据管理"]
        end

        subgraph DataLayer["数据层"]
            PD["products.ts\n产品报价模板"]
            CGD["cgwork.ts\nCG 工时树"]
        end

        subgraph Calc["计算层"]
            FC["模块费用\nhours × HOURLY_RATE\n或 customPrice"]
            SC["分类小计\nΣ 参与计算模块"]
            TC["总报价\nΣ 所有分类小计"]
        end
    end

    Login -->|验证通过| Auth
    Auth -->|守卫跳转| RouterLayer
    R1 --> PQ
    R2 --> CG
    R3 --> DM
    PQ --> PD
    DM -->|读写| PD
    CG --> CGD
    PQ --> Calc
    FC --> SC --> TC

    style Client fill:#f5f0e8,stroke:#c8b89a
    style AuthLayer fill:#e8edf5,stroke:#8fa3c8
    style RouterLayer fill:#eef5e8,stroke:#8fc8a3
    style Pages fill:#f5ece8,stroke:#c8a38f
    style DataLayer fill:#f0e8f5,stroke:#b08fc8
    style Calc fill:#e8f5f0,stroke:#8fc8b0
```

## 计算规则

### 模块参与计算条件

模块参与计算当且仅当：

*   是否可选配 = 否

    或

*   是否可选配 = 是 且 选配 = 是


```mermaid
flowchart LR
    A([模块]) --> B{是否可选配?}
    B -->|否 — 固化费用| C([✅ 参与计算])
    B -->|是 — 可选模块| D{选配 = 是?}
    D -->|是| C
    D -->|否| E([❌ 不参与计算])
```

### 分类小计

同一类型下所有参与计算模块金额之和。

例如：

产品功能费小计

素材制作费小计

项目导入支援费小计

定制开发费用小计

### 总计

总计 = 所有参与计算模块金额之和

## 案例

以一个3D大楼项目为例

### 全量

1.  选择所有模块

2.  素材制作费按照 600000 计算


产品功能费 = 2038500

素材制作费 = 600000

项目导入支援费 = 1275750

定制开发费用 = 405000

总计 = 4319250

```mermaid
pie title 3D大楼全量报价构成（JPY）
    "产品功能费 2,038,500" : 2038500
    "项目导入支援费 1,275,750" : 1275750
    "素材制作费 600,000" : 600000
    "定制开发费用 405,000" : 405000
```

### 部分模块

1.  不选飞行导航模块

2.  素材制作费按照 600000 计算


产品功能费 = 1984500

素材制作费 = 600000

项目导入支援费 = 1275750

定制开发费用 = 405000

总计 = 4265250

```mermaid
pie title 3D大楼（不含飞行导航）报价构成（JPY）
    "产品功能费 1,984,500" : 1984500
    "项目导入支援费 1,275,750" : 1275750
    "素材制作费 600,000" : 600000
    "定制开发费用 405,000" : 405000
```
