# RMDC 项目详情页面前端详细设计说明书 (Frontend DDS)

**文档名称**: RMDC 项目详情页面前端设计文档  
**对应页面**:
- `frontend/src/modules/admin/pages/admin/ProjectDetail.vue` (管理员端)
- `frontend/src/modules/admin/pages/user/UserProjectDetail.vue` (用户端)

**版本**: v2.0  
**编制日期**: 2026-01-15

---

## 文档修订历史

| 版本 | 日期 | 修订内容 |
|:---|:---|:---|
| v1.0 | 2026-01-12 | 初始版本，基础页面架构设计 |
| v1.2 | 2026-01-14 | 完善模块设计规范、中间件卡片设计 |
| v2.0 | 2026-01-15 | **新增**：查看/编辑状态分离、用户侧/管理侧差异化设计、工单关联与跳转机制、多工单场景处理、页面美化规范 |

---

## 1. 设计概述

### 1.1 设计背景

项目详情页面是 RMDC 系统的核心交互界面，需要支持复杂的生命周期管理流程，并满足不同角色用户的差异化需求。本设计文档详细定义了页面的功能逻辑、交互行为、组件结构和美化规范。

### 1.2 核心设计目标

| 目标 | 说明 |
|:---|:---|
| **状态分离** | 明确区分「只读查看模式」与「编辑修改模式」，防止误操作 |
| **角色差异化** | 超级管理员与普通用户看到的内容、操作权限不同，但尽量复用组件 |
| **生命周期可视化** | 清晰展示项目当前状态（INIT/DRAFTING/REVIEWING/RELEASED/MODIFYING/ARCHIVED） |
| **工单关联** | 支持项目详情页与工单详情页的双向跳转，处理多工单场景 |
| **美观专业** | 采用现代 Material Design 风格，注重留白、排版与微动效 |
| **高复用性** | 最大化组件复用，用户侧与管理侧共用核心表单组件 |

### 1.3 页面文件结构

```
frontend/src/modules/admin/
├── pages/
│   ├── admin/
│   │   └── ProjectDetail.vue         # 超级管理员端项目详情
│   └── user/
│       └── UserProjectDetail.vue     # 普通用户端项目详情（填写人视角）
├── components/
│   ├── BasicInfoForm.vue             # 基本信息编辑表单
│   ├── BasicInfoReadonly.vue         # 基本信息只读展示
│   ├── BusinessInfoReadonly.vue      # 业务信息只读展示
│   ├── DeploymentBusinessForm.vue    # 部署业务编辑表单
│   ├── DeploymentEnvironmentForm.vue # 部署环境编辑表单
│   ├── EnvironmentInfoReadonly.vue   # 环境信息只读展示
│   ├── HostsInfoReadonly.vue         # 主机信息只读展示
│   ├── HostsManagement.vue           # 主机管理组件
│   ├── MiddlewareCardsGrid.vue       # 中间件卡片网格
│   ├── MiddlewareInfoReadonly.vue    # 中间件只读展示
│   ├── AuthorizationManagement.vue   # 授权管理 (SuperAdmin Only)
│   ├── VersionHistory.vue            # 版本历史 (SuperAdmin Only)
│   ├── SaveConfirmDialog.vue         # 保存确认对话框
│   ├── ProjectBasicInfoCard.vue      # 项目基本信息卡片
│   ├── CopyableField.vue             # 可复制字段组件
│   └── index.ts                      # 组件统一导出
```

---

## 2. 页面架构设计

### 2.1 整体布局结构

页面采用 **「固定头部 + 固定 Tab 导航 + 可滚动内容区域」** 的三段式布局。

```
┌─────────────────────────────────────────────────────────────────────────┐
│  [固定区域] 生命周期状态提示横幅 (Alert Banner)                           │
├─────────────────────────────────────────────────────────────────────────┤
│  [固定区域] 页面头部 Header                                               │
│  ┌─────────────────────────────────────┬─────────────────────────────┐  │
│  │  ← 返回  项目名称                     │  [查看工单] [打回] [通过]   │  │
│  │          Namespace | 省份 城市        │  [下载配置] [编辑/保存]     │  │
│  │          状态标签组                    │                            │  │
│  └─────────────────────────────────────┴─────────────────────────────┘  │
├─────────────────────────────────────────────────────────────────────────┤
│  [固定区域] Tab 导航栏                                                    │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │  基本信息 | 部署业务 | 部署环境 | 主机管理 | 中间件 | 授权 | 版本历史 ││
│  └─────────────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────────────┤
│  [滚动区域] Tab 内容区域                                                  │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │                                                                      ││
│  │                    当前 Tab 对应的表单/只读内容                        ││
│  │                                                                      ││
│  │                                                                      ││
│  └─────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────┘
```

### 2.2 CSS 布局实现

```css
.project-detail-page {
  height: 100%;
  max-height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.header-section {
  flex-shrink: 0;
  background: rgb(var(--v-theme-surface));
  z-index: 1;
}

.content-area {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  min-height: 0;  /* 关键：防止 Flex 子元素撑破父容器 */
  padding-bottom: 24px;
}
```

---

## 3. 查看状态 vs 编辑状态

### 3.1 状态定义

| 状态 | 变量名 | 说明 |
|:---|:---|:---|
| **查看状态** | `isEditMode = false` | 默认状态，展示只读组件 |
| **编辑状态** | `isEditMode = true` | 编辑模式，展示表单组件 |

### 3.2 查看状态 (默认)

#### 3.2.1 展示形式
- 使用 `*Readonly.vue` 系列组件展示数据
- 采用 `v-row/v-col` 布局，键值对形式展示
- 关键字段（IP、URL、密码）支持一键复制
- 敏感字段（密码）默认脱敏显示 `******`

#### 3.2.2 交互行为
| 交互 | 说明 |
|:---|:---|
| **一键复制** | 使用 `CopyableField` 组件，点击复制图标复制到剪贴板 |
| **密码查看** | 点击"小眼睛"图标切换明文/密文 |
| **链接跳转** | URL 字段支持点击新窗口打开 |

#### 3.2.3 组件列表
| 组件名称 | 对应模块 | 说明 |
|:---|:---|:---|
| `BasicInfoReadonly.vue` | 基本信息 | 项目名、NS、省市、性质 |
| `BusinessInfoReadonly.vue` | 部署业务 | 部署人、系统版本、入口URL |
| `EnvironmentInfoReadonly.vue` | 部署环境 | 网络、IP、域名、主机统计 |
| `HostsInfoReadonly.vue` | 主机管理 | 主机列表只读表格 |
| `MiddlewareInfoReadonly.vue` | 中间件 | 中间件卡片只读展示 |

### 3.3 编辑状态

#### 3.3.1 进入条件
- 点击 Header 的「编辑」按钮
- 用户必须具备编辑权限（基于角色和生命周期状态）

#### 3.3.2 数据流

```mermaid
sequenceDiagram
    participant User as 用户
    participant View as 查看模式
    participant Edit as 编辑模式
    participant API as 后端API

    User->>View: 点击[编辑]按钮
    View->>Edit: isEditMode = true
    Edit->>Edit: 深拷贝 masterData → editForm
    Edit-->>User: 显示表单组件

    User->>Edit: 修改字段
    Edit->>Edit: computed hasChanges = true

    User->>Edit: 点击[保存]
    Edit->>Edit: 弹出 SaveConfirmDialog
    User->>Edit: 确认保存
    Edit->>API: 调用更新接口
    API-->>Edit: 返回成功
    Edit->>View: isEditMode = false, 刷新数据
```

#### 3.3.3 退出保护
- **脏数据检测**：通过 `computed hasChanges` 检测是否有未保存的修改
- **退出确认**：如有未保存修改，点击「取消」或切换页面时弹出确认对话框

```typescript
const exitEditMode = () => {
  if (hasChanges.value) {
    exitConfirmDialog.value = true  // 弹出确认对话框
  } else {
    isEditMode.value = false
  }
}
```

#### 3.3.4 编辑状态指示器
编辑模式下，Header 区域显示明显的「编辑模式」标签：

```html
<v-chip v-if="isEditMode" color="info" variant="tonal" class="ml-2">
  <v-icon start size="small">mdi-pencil</v-icon>
  编辑模式
</v-chip>
```

---

## 4. 用户侧 vs 管理侧差异化设计

### 4.1 页面对照表

| 特性 | 管理员端 (ProjectDetail.vue) | 用户端 (UserProjectDetail.vue) |
|:---|:---|:---|
| **默认模式** | 查看模式 | 根据工单状态决定 |
| **查看权限** | 所有模块 | ACL 授权模块 |
| **授权信息 Tab** | ✅ 可见 | ❌ 不可见 |
| **版本历史 Tab** | ✅ 可见 | ❌ 不可见 |
| **主机管理 Tab** | ✅ 可见 | ❌ 不可见 |
| **基本信息** | 可编辑 | 只读（由管理员填写） |
| **编辑操作** | 直接保存（上帝模式） | 草稿 → 提交审核（工单流程） |
| **审批操作** | ✅ 通过/打回按钮 | ❌ 无 |
| **保存按钮** | 「保存修改」 | 「保存草稿」 |
| **提交按钮** | 无 | 「提交审核」 |

### 4.2 Tab 导航差异

#### 管理员端 Tabs
```html
<v-tabs v-model="activeTab">
  <v-tab value="basic">基本信息</v-tab>
  <v-tab value="business">部署业务</v-tab>
  <v-tab value="environment">部署环境</v-tab>
  <v-tab value="hosts">主机管理</v-tab>
  <v-tab value="middlewares">中间件</v-tab>
  <v-tab value="authorization" v-if="isSuperAdmin">授权信息</v-tab>
  <v-tab value="version-history" v-if="isSuperAdmin">版本历史</v-tab>
</v-tabs>
```

#### 用户端 Tabs
```html
<v-tabs v-model="activeTab">
  <v-tab value="basic">基本信息</v-tab>
  <v-tab value="business">部署业务</v-tab>
  <v-tab value="environment">部署环境</v-tab>
  <v-tab value="middlewares">中间件</v-tab>
</v-tabs>
```

### 4.3 组件复用策略

```mermaid
graph TB
    subgraph 共用组件
        A[BasicInfoForm]
        B[DeploymentBusinessForm]
        C[DeploymentEnvironmentForm]
        D[MiddlewareCardsGrid]
        E[BasicInfoReadonly]
        F[BusinessInfoReadonly]
        G[EnvironmentInfoReadonly]
        H[MiddlewareInfoReadonly]
    end

    subgraph 管理端专用
        I[AuthorizationManagement]
        J[VersionHistory]
        K[HostsManagement]
        L[SaveConfirmDialog]
    end

    subgraph 用户端专用
        M[ProjectBasicInfoCard]
    end

    Admin[ProjectDetail.vue] --> A
    Admin --> B
    Admin --> C
    Admin --> D
    Admin --> E
    Admin --> F
    Admin --> G
    Admin --> H
    Admin --> I
    Admin --> J
    Admin --> K
    Admin --> L

    User[UserProjectDetail.vue] --> B
    User --> C
    User --> D
    User --> M
```

### 4.4 权限控制逻辑

```typescript
// 管理员端 - 编辑权限判断
const canEdit = computed(() => {
  if (!masterData.value) return false
  const status = masterData.value.lifecycle_status

  // 超级管理员在已发布、变更中状态可以编辑
  if (isSuperAdmin.value) {
    return status === 'released' || status === 'modifying'
  }
  return false
})

// 用户端 - 编辑权限判断
const canEdit = computed(() => {
  if (!workflowInfo.value) return true  // 没有工单信息时默认可编辑
  const status = workflowInfo.value.status

  // 已分配、处理中、已打回状态可编辑
  return ['assigned', 'in_progress', 'returned', 'draft_saved'].includes(status)
})
```

---

## 5. 项目生命周期状态展示

### 5.1 状态标签设计

项目详情页 Header 区域展示三类状态标签：

```html
<div class="d-flex align-center gap-2">
  <h1 class="text-h4 font-weight-bold">{{ masterData.project_name }}</h1>
  
  <!-- 1. 连接状态 -->
  <v-chip :color="getStatusColor(masterData.status)" size="small" variant="tonal">
    {{ PROJECT_STATUS[masterData.status] }}
  </v-chip>
  
  <!-- 2. 生命周期状态 -->
  <v-chip :color="getLifecycleStatusColor(masterData.lifecycle_status)" 
          size="small" variant="tonal">
    <v-icon start size="small">{{ getLifecycleStatusIcon(masterData.lifecycle_status) }}</v-icon>
    {{ LIFECYCLE_STATUS[masterData.lifecycle_status] }}
  </v-chip>
  
  <!-- 3. 认证状态 -->
  <v-chip :color="masterData.project_certification === 'official' ? 'success' : 'warning'"
          size="small" variant="tonal">
    {{ PROJECT_CERTIFICATION[masterData.project_certification] }}
  </v-chip>
  
  <!-- 4. 编辑模式指示器 -->
  <v-chip v-if="isEditMode" color="info" variant="tonal">
    <v-icon start size="small">mdi-pencil</v-icon>
    编辑模式
  </v-chip>
</div>
```

### 5.2 生命周期状态配置

```typescript
// 生命周期状态枚举
export const LIFECYCLE_STATUS = {
  init: '初始化',
  drafting: '填写中',
  reviewing: '审核中',
  released: '已发布',
  modifying: '变更中',
  archived: '已归档'
}

// 状态颜色映射
export const LIFECYCLE_STATUS_COLORS: Record<string, string> = {
  init: 'grey',
  drafting: 'info',
  reviewing: 'warning',
  released: 'success',
  modifying: 'primary',
  archived: 'grey-darken-1'
}

// 状态图标
const getLifecycleStatusIcon = (status: string): string => {
  const icons: Record<string, string> = {
    init: 'mdi-clock-outline',
    drafting: 'mdi-pencil',
    reviewing: 'mdi-eye',
    released: 'mdi-check-circle',
    modifying: 'mdi-sync',
    archived: 'mdi-archive'
  }
  return icons[status] || 'mdi-help-circle'
}
```

### 5.3 生命周期提示横幅 (Alert Banner)

根据当前生命周期状态，在 Header 下方显示上下文提示：

```typescript
interface LifecycleAlert {
  type: 'info' | 'warning' | 'success' | 'error'
  message: string
  action?: {
    text: string
    handler: () => void
  }
}

const lifecycleStatusAlert = computed((): LifecycleAlert | null => {
  if (!masterData.value) return null
  const status = masterData.value.lifecycle_status

  switch (status) {
    case 'init':
      return {
        type: 'info',
        message: '项目已创建，等待指定填写人录入详细信息'
      }
    case 'drafting':
      return {
        type: 'info',
        message: `项目详情正在由 ${masterData.value.detail_filler_name || '填写人'} 填写中`,
        action: masterData.value.workflow_id ? {
          text: '查看工单',
          handler: () => router.push(`/admin/workflows/${masterData.value?.workflow_id}`)
        } : undefined
      }
    case 'reviewing':
      return {
        type: 'warning',
        message: '项目详情已提交，等待审核',
        action: masterData.value.workflow_id ? {
          text: '查看工单',
          handler: () => router.push(`/admin/workflows/${masterData.value?.workflow_id}`)
        } : undefined
      }
    case 'modifying':
      return {
        type: 'info',
        message: '项目存在活跃的变更工单，主线数据不受影响',
        action: masterData.value.workflow_id ? {
          text: '查看工单',
          handler: () => router.push(`/admin/workflows/${masterData.value?.workflow_id}`)
        } : undefined
      }
    case 'archived':
      return {
        type: 'warning',
        message: '项目已归档，仅保留历史数据'
      }
    default:
      return null
  }
})
```

---

## 6. 工单关联与跳转机制

### 6.1 工单与项目的关系

| 工单类型 | 生命周期状态 | 数量关系 | 说明 |
|:---|:---|:---|:---|
| 填写工单 (project_detail) | INIT → DRAFTING | 1:1 | 项目创建时只能有一个 |
| 修改工单 (project_modify) | RELEASED → MODIFYING | 1:N | 已发布项目可有多个 |

### 6.2 工单按钮显示逻辑

```typescript
// 是否显示工单按钮
const showWorkflowButton = computed(() => {
  if (!masterData.value?.workflow_id) return false
  const status = masterData.value.lifecycle_status
  // 在填写中、审核中、变更中状态显示工单按钮
  return ['drafting', 'reviewing', 'modifying'].includes(status)
})

// 工单按钮文本
const workflowButtonText = computed(() => {
  if (!masterData.value) return '查看工单'
  const status = masterData.value.lifecycle_status
  switch (status) {
    case 'drafting':
      return '查看填写工单'
    case 'reviewing':
      return '查看审核工单'
    case 'modifying':
      return '查看修改工单'
    default:
      return '查看工单'
  }
})
```

### 6.3 多工单场景处理

当项目处于 `MODIFYING` 状态时，可能同时存在多个修改工单。需要设计专门的工单列表展示。

#### 6.3.1 设计方案

**方案一：下拉菜单选择**

```html
<v-menu v-if="multipleWorkflows">
  <template v-slot:activator="{ props }">
    <v-btn v-bind="props" color="info" variant="tonal" prepend-icon="mdi-sitemap">
      查看工单 ({{ workflowCount }})
      <v-icon end>mdi-chevron-down</v-icon>
    </v-btn>
  </template>
  <v-list>
    <v-list-item 
      v-for="wf in relatedWorkflows" 
      :key="wf.workflow_id"
      @click="navigateToWorkflow(wf.workflow_id)"
    >
      <v-list-item-title>{{ wf.workflow_id }}</v-list-item-title>
      <v-list-item-subtitle>
        {{ wf.creator_name }} | {{ formatDate(wf.created_at) }}
      </v-list-item-subtitle>
    </v-list-item>
  </v-list>
</v-menu>
```

**方案二：工单列表对话框**（推荐用于工单较多的场景）

```html
<v-dialog v-model="workflowListDialog" max-width="600">
  <v-card>
    <v-card-title>
      <v-icon start>mdi-sitemap</v-icon>
      关联工单列表
    </v-card-title>
    <v-card-text>
      <v-data-table
        :headers="workflowHeaders"
        :items="relatedWorkflows"
        density="compact"
        hover
      >
        <template v-slot:item.workflow_id="{ item }">
          <a @click="navigateToWorkflow(item.workflow_id)">
            {{ item.workflow_id }}
          </a>
        </template>
        <template v-slot:item.status="{ item }">
          <v-chip :color="getWorkflowStatusColor(item.status)" size="small">
            {{ item.status_name }}
          </v-chip>
        </template>
      </v-data-table>
    </v-card-text>
  </v-card>
</v-dialog>
```

### 6.4 从工单页面跳转回项目详情

工单详情页应提供「查看项目」按钮：

```typescript
// 工单详情页
const navigateToProject = () => {
  if (workflowDetail.value?.business_context?.project_id) {
    router.push(`/admin/projects/${workflowDetail.value.business_context.project_id}`)
  }
}
```

---

## 7. 模块详细设计规范

### 7.1 基本信息模块 (Basic Info)

| 字段 | 类型 | 只读模式 | 编辑模式 |
|:---|:---|:---|:---|
| 项目名称 | String | 文本展示 + 复制 | `v-text-field` |
| 命名空间 | String | 文本展示 + 复制 | `disabled` 不可编辑 |
| 省份 | Enum | 文本展示 | 级联选择器 |
| 城市 | Enum | 文本展示 | 级联选择器（依赖省份） |
| 项目性质 | Enum | 文本展示 | `v-select` |
| 行业组人员 | String | 文本展示 | `v-text-field` |
| 行业组电话 | String | 文本展示 | `v-text-field` |
| 项目描述 | String | 多行文本 | `v-textarea` |

### 7.2 部署业务模块 (Deployment Business)

| 字段 | 类型 | 只读模式 | 编辑模式 |
|:---|:---|:---|:---|
| 部署人姓名 | String | 文本展示 | `v-text-field` 或用户搜索 |
| 部署人电话 | String | 文本展示 | `v-text-field` |
| 部署系统 | Enum | 文本展示 | `v-select` |
| 系统版本 | String | 文本展示 | `v-text-field` |
| 业务入口 URL | String | 可点击链接 | `v-text-field` |
| 超管账号 | String | 文本展示 + 复制 | `v-text-field` |
| 超管密码 | Password | 脱敏 + 查看按钮 | `v-text-field` 密码输入 |

### 7.3 部署环境模块 (Deployment Environment)

| 字段 | 类型 | 只读模式 | 编辑模式 |
|:---|:---|:---|:---|
| 网络环境 | Enum | 文本展示 | `v-select` |
| 主公网 IP | String | 文本展示 + 复制 | `v-text-field` IP 校验 |
| 域名 URL | String | 可点击链接 | `v-text-field` |
| 启用 SSL | Boolean | 图标显示 | `v-switch` |
| 主机管理方式 | Enum | 文本展示 | `v-select` |
| 管理控制台 URL | String | 可点击链接 | `v-text-field` |
| 主机数量 | Number | 文本展示 | `v-text-field type=number` |
| CPU 总核数 | Number | 统计卡片 | `v-text-field type=number` |
| 内存总量 | Number | 统计卡片 | `v-text-field type=number` |
| 存储总量 | Number | 统计卡片 | `v-text-field type=number` |

### 7.4 中间件模块 (Middleware)

采用 **卡片网格 (Card Grid)** 设计：

#### 7.4.1 数据结构
```typescript
interface MiddlewareFormItem {
  middleware_type: string
  public_ip: string
  public_port: number
  internal_ip: string
  internal_port: number
  admin_user: string
  admin_password?: string
}
```

#### 7.4.2 只读模式
- 每个中间件一张卡片，响应式网格布局
- 卡片包含：类型图标 + 标题 + IP/Port 信息
- 图标映射逻辑：

```typescript
const MIDDLEWARE_ICONS: Record<string, string> = {
  'mysql': 'mdi-database',
  'redis': 'mdi-database-clock',
  'emqx': 'mdi-broadcast',
  'minio': 'mdi-bucket',
  'influxdb': 'mdi-chart-timeline-variant',
  'nacos': 'mdi-cog-outline',
  'k8s-dashboard': 'mdi-kubernetes'
}
```

#### 7.4.3 编辑模式
- 现有卡片右上角显示「编辑」「删除」按钮
- 列表末尾显示「添加中间件」虚线框卡片
- 点击添加/编辑弹出对话框：
  - 类型选择：`v-combobox` 支持预设 + 自定义
  - 选择预设类型时自动填充默认端口

### 7.5 主机管理模块 (Hosts Management)

- 复用 `HostsManagement.vue` 组件
- 支持表格展示所有主机信息
- 编辑模式支持添加/删除主机

### 7.6 授权信息模块 (Authorization) - SuperAdmin Only

| 功能 | 说明 |
|:---|:---|
| TOTP 密钥展示 | 二维码 + 文本形式 |
| 授权类型切换 | 永久/限时 |
| 授权天数设置 | 数字输入 |
| 下发授权 | 调用 Exchange-Hub 接口 |
| 撤销授权 | 调用 Exchange-Hub 接口 |

### 7.7 版本历史模块 (Version History) - SuperAdmin Only

| 功能 | 说明 |
|:---|:---|
| 版本列表 | 时间轴形式展示 |
| 版本详情 | 点击查看完整快照 |
| 版本对比 | 选择两个版本进行 Diff |
| 工单关联 | 点击跳转关联工单 |

---

## 8. 组件设计规范

### 8.1 CopyableField 组件

用于展示可复制的字段值：

```html
<template>
  <div class="copyable-field d-flex align-center gap-2">
    <span class="field-value">{{ displayValue }}</span>
    <v-btn 
      icon="mdi-content-copy" 
      size="x-small" 
      variant="text"
      @click="copyToClipboard"
    >
      <v-tooltip activator="parent" location="top">复制</v-tooltip>
    </v-btn>
  </div>
</template>
```

### 8.2 SaveConfirmDialog 组件

保存前的确认对话框，展示变更差异：

```html
<v-dialog v-model="visible" max-width="600">
  <v-card>
    <v-card-title class="bg-primary text-white">
      <v-icon start>mdi-check-circle</v-icon>
      确认保存修改
    </v-card-title>
    <v-card-text>
      <v-alert type="info" variant="tonal" class="mb-4">
        以下字段将被修改：
      </v-alert>
      <v-table density="compact">
        <thead>
          <tr>
            <th>字段</th>
            <th>修改前</th>
            <th>修改后</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="item in diffItems" :key="item.field">
            <td>{{ item.label }}</td>
            <td class="text-error">{{ item.oldValue || '空' }}</td>
            <td class="text-success">{{ item.newValue || '空' }}</td>
          </tr>
        </tbody>
      </v-table>
    </v-card-text>
    <v-card-actions>
      <v-spacer />
      <v-btn variant="text" @click="cancel">取消</v-btn>
      <v-btn color="primary" :loading="loading" @click="confirm">确认保存</v-btn>
    </v-card-actions>
  </v-card>
</v-dialog>
```

### 8.3 DiffTextField 组件

编辑模式下显示与主线数据差异的输入框：

```html
<template>
  <v-text-field
    v-model="inputValue"
    :label="label"
    :class="{ 'diff-highlight': hasDiff }"
    :hint="hasDiff ? `主线值: ${masterValue}` : ''"
    persistent-hint
  >
    <template v-slot:prepend-inner v-if="hasDiff">
      <v-icon color="warning" size="small">mdi-alert-circle</v-icon>
    </template>
  </v-text-field>
</template>

<style scoped>
.diff-highlight :deep(.v-field__outline) {
  --v-field-border-color: rgb(var(--v-theme-warning));
}
</style>
```

---

## 9. 交互时序图

### 9.1 管理员编辑保存流程

```mermaid
sequenceDiagram
    participant Admin as 超级管理员
    participant Page as ProjectDetail.vue
    participant Dialog as SaveConfirmDialog
    participant API as 后端API

    Admin->>Page: 点击[编辑]按钮
    Page->>Page: isEditMode = true
    Page->>Page: editForm = deepClone(masterData)

    Admin->>Page: 修改字段
    Page->>Page: hasChanges = true

    Admin->>Page: 点击[保存修改]
    Page->>Page: 计算 diffItems
    Page->>Dialog: 显示确认对话框

    Admin->>Dialog: 确认保存
    Dialog->>API: updateProject()
    API-->>Dialog: 成功
    Dialog->>Page: emit('confirm')
    Page->>API: loadProject()
    Page->>Page: isEditMode = false
    Page-->>Admin: Snackbar: 保存成功
```

### 9.2 用户草稿提交流程

```mermaid
sequenceDiagram
    participant User as 普通用户
    participant Page as UserProjectDetail.vue
    participant Dialog as SubmitDialog
    participant API as 后端API
    participant WF as 工单模块

    User->>Page: 填写表单
    User->>Page: 点击[保存草稿]
    Page->>API: saveDraft()
    API-->>Page: 草稿保存成功

    User->>Page: 点击[提交审核]
    Page->>Dialog: 显示确认对话框
    User->>Dialog: 填写备注并确认
    Dialog->>API: saveDraft() (最终版本)
    Dialog->>API: submitProjectDetail()
    API->>WF: 触发工单状态转换
    WF-->>API: 成功
    API-->>Dialog: 提交成功
    Page-->>User: 跳转至工单详情页
```

### 9.3 管理员审批流程

```mermaid
sequenceDiagram
    participant Admin as 超级管理员
    participant Page as ProjectDetail.vue
    participant Dialog as ApproveDialog/RejectDialog
    participant API as 后端API
    participant WF as 工单模块

    Note over Page: lifecycle_status = reviewing

    Admin->>Page: 查看待审核内容
    
    alt 通过审批
        Admin->>Page: 点击[通过]
        Page->>Dialog: 显示审批对话框
        Admin->>Dialog: 填写备注并确认
        Dialog->>API: transitionWorkflow(approve)
        API->>WF: 工单状态 → approved
        WF-->>API: 回调更新项目状态
        API-->>Dialog: 成功
        Page->>API: updateProjectCertification('official')
        Page-->>Admin: Snackbar: 审批通过
    else 打回修改
        Admin->>Page: 点击[打回]
        Page->>Dialog: 显示打回对话框
        Admin->>Dialog: 填写打回原因并确认
        Dialog->>API: transitionWorkflow(return)
        API->>WF: 工单状态 → returned
        WF-->>API: 回调更新项目状态
        API-->>Dialog: 成功
        Page-->>Admin: Snackbar: 已打回
    end
```

---

## 10. 视觉设计规范

### 10.1 色彩系统

| 用途 | 颜色 | Vuetify 类 |
|:---|:---|:---|
| 主色调 | Deep Purple | `color="primary"` |
| 成功状态 | Green | `color="success"` |
| 警告状态 | Orange | `color="warning"` |
| 错误状态 | Red | `color="error"` |
| 信息状态 | Blue | `color="info"` |
| 页面背景 | Light Grey | `bg-grey-lighten-4` |
| 卡片背景 | White | `bg-white` |

### 10.2 卡片设计

```html
<v-card elevation="2" rounded="lg" class="pa-4">
  <!-- 卡片内容 -->
</v-card>
```

- 圆角：`rounded-lg` (8px)
- 阴影：`elevation-2`
- 内边距：`pa-4` (16px)
- Hover 效果：轻微上浮 + 阴影加深

### 10.3 排版规范

| 元素 | 字体样式 |
|:---|:---|
| 页面标题 | `text-h4 font-weight-bold` |
| 卡片标题 | `text-h6` |
| 字段标签 | `text-medium-emphasis text-body-2` |
| 字段值 | `text-high-emphasis` |
| 辅助文字 | `text-caption text-grey` |

### 10.4 间距规范

遵循 8px 网格系统：

| 间距 | Vuetify 类 | 值 |
|:---|:---|:---|
| 紧凑 | `pa-2` / `ma-2` | 8px |
| 标准 | `pa-4` / `ma-4` | 16px |
| 宽松 | `pa-6` / `ma-6` | 24px |
| 组件间距 | `gap-2` | 8px |
| 卡片间距 | `gap-4` | 16px |

### 10.5 动画与过渡

| 场景 | 效果 |
|:---|:---|
| Tab 切换 | `v-window` 默认滑动过渡 |
| 模式切换 | `v-expand-transition` |
| 按钮 Hover | 0.2s 缓动 |
| 卡片 Hover | `transform: translateY(-2px)` |
| 加载状态 | `v-skeleton-loader` 骨架屏 |

---

## 11. 响应式设计

### 11.1 断点配置

遵循 Vuetify 默认断点：

| 断点 | 宽度范围 |
|:---|:---|
| xs | < 600px |
| sm | 600px - 960px |
| md | 960px - 1280px |
| lg | 1280px - 1920px |
| xl | > 1920px |

### 11.2 布局适配

```html
<!-- 中间件卡片网格 -->
<v-row>
  <v-col 
    v-for="mw in middlewares" 
    :key="mw.type"
    cols="12" 
    sm="6" 
    md="4" 
    lg="3"
  >
    <MiddlewareCard :data="mw" />
  </v-col>
</v-row>
```

### 11.3 移动端适配要点

1. **Tab 导航**：使用 `show-arrows` 支持左右滑动
2. **操作按钮**：使用 `v-bottom-sheet` 或收起到菜单
3. **表单布局**：单列堆叠
4. **表格**：使用 `mobile-breakpoint` 切换卡片视图

---

## 12. 数据类型定义

### 12.1 核心类型

```typescript
// 项目详情
interface ProjectDetail {
  id: number
  project_id: string
  project_name: string
  namespace: string
  province: string
  city: string
  project_nature: string
  industry_group_member: string
  industry_group_phone: string
  description: string
  status: string
  lifecycle_status: string
  project_certification: string
  workflow_id: string
  detail_filler_id: number
  detail_filler_name: string
  deployment_business: DeploymentBusiness | null
  deployment_environment: DeploymentEnvironment | null
  middlewares: Middleware[]
  hosts: Host[]
  draft_data: Record<string, unknown> | null
  created_at: string
  updated_at: string
}

// 表单数据类型
interface BasicFormData {
  project_name: string
  province: string
  city: string
  industry_group_member: string
  industry_group_phone: string
  project_nature: string
  description: string
}

interface BusinessFormData {
  deployer_name: string
  deployer_phone: string
  deploy_system: string
  system_version: string
  business_entry_url: string
  super_admin_user: string
  super_admin_password: string
}

interface EnvironmentFormData {
  network_environment: string
  main_public_ip: string
  domain_url: string
  enable_ssl: boolean
  host_management_method: string
  management_console_url: string
  host_count: number
  total_cpu: number
  total_memory_gb: number
  total_storage_gb: number
}

interface MiddlewareFormItem {
  middleware_type: string
  public_ip: string
  public_port: number
  internal_ip: string
  internal_port: number
  admin_user: string
  admin_password?: string
}

// Diff 项
interface DiffItem {
  field: string
  label: string
  oldValue: string | number | boolean
  newValue: string | number | boolean
}
```

---

## 13. API 调用规范

### 13.1 项目管理 API

| 方法 | 路径 | 说明 |
|:---|:---|:---|
| POST | `/api/project/detail` | 获取项目详情 |
| POST | `/api/project/update` | 更新项目信息 (Admin) |
| POST | `/api/project/draft/save` | 保存草稿 |
| POST | `/api/project/draft/submit` | 提交审核 |
| POST | `/api/project/draft/discard` | 放弃草稿 |
| POST | `/api/project/export` | 导出配置 |

### 13.2 调用示例

```typescript
// 获取项目详情
const loadProject = async () => {
  const res = await getProjectDetail(projectId.value)
  if (res.code === 0) {
    masterData.value = res.data
  }
}

// 管理员保存修改
const confirmSave = async () => {
  await updateProject(projectId.value, {
    project_name: editForm.basic.project_name,
    province: editForm.basic.province,
    // ...
  })
}

// 用户保存草稿
const handleSaveDraft = async () => {
  const draftData = {
    formData: { ...businessFormData.value, ...environmentFormData.value },
    middlewareList: getMiddlewareList()
  }
  await saveDraft(projectId.value, draftData)
}
```

---

## 14. 附录

### 14.1 相关文档

| 文档 | 说明 |
|:---|:---|
| [项目管理 PRD](1-rmdc-project-management-PRD.md) | 产品需求文档 |
| [项目管理后端 DDS](2-rmdc-project-management-DDS.md) | 后端详细设计 |
| [Vue3 TypeScript 规范](../1-rmdc-system/prompts/vue3-typescript-stye.md) | 前端开发规范 |
| [API 开发规范](../../../ProjectAGiPrompt/1-Golang项目/3-api-development-prompt.md) | 接口设计规范 |

### 14.2 组件清单

| 组件 | 文件路径 | 说明 |
|:---|:---|:---|
| BasicInfoForm | `components/BasicInfoForm.vue` | 基本信息编辑表单 |
| BasicInfoReadonly | `components/BasicInfoReadonly.vue` | 基本信息只读 |
| BusinessInfoReadonly | `components/BusinessInfoReadonly.vue` | 业务信息只读 |
| DeploymentBusinessForm | `components/DeploymentBusinessForm.vue` | 业务信息表单 |
| DeploymentEnvironmentForm | `components/DeploymentEnvironmentForm.vue` | 环境信息表单 |
| EnvironmentInfoReadonly | `components/EnvironmentInfoReadonly.vue` | 环境信息只读 |
| HostsInfoReadonly | `components/HostsInfoReadonly.vue` | 主机信息只读 |
| HostsManagement | `components/HostsManagement.vue` | 主机管理 |
| MiddlewareCardsGrid | `components/MiddlewareCardsGrid.vue` | 中间件卡片网格 |
| MiddlewareInfoReadonly | `components/MiddlewareInfoReadonly.vue` | 中间件只读 |
| AuthorizationManagement | `components/AuthorizationManagement.vue` | 授权管理 |
| VersionHistory | `components/VersionHistory.vue` | 版本历史 |
| SaveConfirmDialog | `components/SaveConfirmDialog.vue` | 保存确认对话框 |
| CopyableField | `components/CopyableField.vue` | 可复制字段 |
| ProjectBasicInfoCard | `components/ProjectBasicInfoCard.vue` | 项目基本信息卡片 |
