# 查看/编辑状态分离设计

> DDS-Section: Frontend DDS - 3. 查看状态 vs 编辑状态
> DDS-Lines: L130-L217

## 状态定义

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

## 查看状态 (默认)

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

### 交互行为

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

### 组件列表

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

## 编辑状态

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

### 数据流

```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, 刷新数据
```

### 退出保护

```typescript
// 脏数据检测
const hasChanges = computed(() => {
  return JSON.stringify(editForm.value) !== JSON.stringify(masterData.value)
})

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

### 编辑状态指示器

编辑模式下，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>
```

## 编辑模式数据流示例

```typescript
// 进入编辑模式
const enterEditMode = () => {
  editForm.value = JSON.parse(JSON.stringify(masterData.value)) // 深拷贝
  isEditMode.value = true
}

// 保存修改
const handleSave = async () => {
  try {
    await updateProject(projectId.value, editForm.value)
    await loadProject() // 重新加载数据
    isEditMode.value = false
    snackbar.success('保存成功')
  } catch (error) {
    snackbar.error('保存失败')
  }
}

// 取消编辑
const handleCancel = () => {
  if (hasChanges.value) {
    confirmDialog.value = true
  } else {
    isEditMode.value = false
  }
}
```
