# 统一错误处理规范

> 跨框架通用的错误处理与用户通知统一标准
> 版本: v1.0.0 | 更新: 2026-03-31

---

## 🎯 核心原则

1. **单一入口** — 全项目使用统一的通知/错误提示服务，禁止直接调用底层 API
2. **错误分级** — 区分 success / warning / error 级别，统一视觉表现
3. **可维护性** — 修改通知样式/行为只需改一处，而非搜索全项目

---

## ⚡ Flutter 统一错误处理

### 推荐架构

```
lib/core/utils/app_toast.dart     ← 统一通知入口
lib/core/services/notification/   ← 底层实现（可选）
```

### 统一入口示例

```dart
/// 全局通知入口 — 禁止在业务代码中直接调用 Get.snackbar / ScaffoldMessenger
class AppToast {
  static void success(String message) {
    Get.snackbar('', message,
      backgroundColor: AppColors.successBg,
      colorText: AppColors.successText,
      snackPosition: SnackPosition.TOP,
    );
  }

  static void error(String message) {
    Get.snackbar('', message,
      backgroundColor: AppColors.errorBg,
      colorText: AppColors.errorText,
      snackPosition: SnackPosition.TOP,
    );
  }

  static void warning(String message) {
    Get.snackbar('', message,
      backgroundColor: AppColors.warningBg,
      colorText: AppColors.warningText,
      snackPosition: SnackPosition.TOP,
    );
  }
}
```

### 禁止模式

```dart
// ❌ 禁止 — 直接调用底层 API
Get.snackbar('Error', '网络请求失败');
Get.snackbar('Success', '保存成功', backgroundColor: Colors.green);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('错误')));

// ✅ 正确 — 走统一入口
AppToast.error(S.current.networkError);
AppToast.success(S.current.saveSuccess);
```

### API 错误处理中间层

```dart
/// 在 Repository 或 DataSource 层统一处理
Future<T> safeApiCall<T>(Future<T> Function() apiCall) async {
  try {
    return await apiCall();
  } on DioException catch (e) {
    final message = _mapDioError(e);
    AppToast.error(message);
    rethrow;
  } catch (e) {
    AppToast.error(S.current.unknownError);
    rethrow;
  }
}
```

---

## ⚡ Vue 统一错误处理

### 推荐架构

```
src/utils/toast.ts           ← 统一通知入口
src/utils/request.ts         ← Axios 拦截器统一错误处理
```

### 统一入口示例

```typescript
// src/utils/toast.ts
import { ElMessage } from 'element-plus'

export const toast = {
  success(msg: string) {
    ElMessage.success(msg)
  },
  error(msg: string) {
    ElMessage.error(msg)
  },
  warning(msg: string) {
    ElMessage.warning(msg)
  },
}
```

### 禁止模式

```typescript
// ❌ 禁止 — 散落调用
ElMessage.error('保存失败')
ElMessage({ type: 'success', message: '保存成功' })
alert('操作完成')

// ✅ 正确
toast.error($t('保存失败'))
toast.success($t('保存成功'))
```

### Axios 拦截器

```typescript
// src/utils/request.ts
service.interceptors.response.use(
  (response) => response.data,
  (error) => {
    const message = error.response?.data?.message || $t('网络错误')
    toast.error(message)
    return Promise.reject(error)
  }
)
```

---

## 📊 真实案例

> 来自 my_flutter 项目 P1-4 优化

**优化前**: 8 个文件中散落 `Get.snackbar` 调用，每处的样式参数（背景色、位置、时长）不统一。

**问题**:
- 修改通知样式需要找到并修改 8 处
- 部分页面用红色背景，部分用默认
- 无法统一控制通知位置和时长

**优化后**: 统一收拢到 `AppToast.success/error/warning`，修改样式只需改 1 处。

---

## ✅ 检查清单

- [ ] 搜索项目中是否存在直接调用底层通知 API
  - Flutter: `grep -rn "Get.snackbar\|ScaffoldMessenger" lib/ | grep -v app_toast`
  - Vue: `grep -rn "ElMessage\.\|ElNotification\." src/ | grep -v utils/toast`
- [ ] 所有 API 错误通过拦截器/中间层统一处理
- [ ] 通知文本已国际化
- [ ] 错误分级正确（不要把 warning 当 error 展示）
