# API 接口文档

本目录包含了小说阅读平台的所有API接口封装，基于后端Swagger API文档自动生成。

## 📐 架构设计

### 🎯 设计原则
本项目采用 **纯净API + 状态管理分离** 的架构设计：

- **API层**：只负责HTTP请求，不包含任何业务逻辑
- **Store层**：负责状态管理和业务逻辑处理
- **组件层**：调用API获取数据，通过Store管理状态

### 🏗️ 分层架构

```
┌─────────────────┐
│   Component     │  ← 调用API，处理响应，更新Store
├─────────────────┤
│     Store       │  ← 状态管理 + 业务逻辑
├─────────────────┤
│      API        │  ← 纯净HTTP请求
├─────────────────┤
│   Axios/HTTP    │  ← 网络请求
└─────────────────┘
```

## 文件结构

```
src/api/
├── index.js           # Axios实例配置和拦截器（纯净）
├── auth.js            # 授权登录相关接口（纯净）
├── home.js            # 首页相关接口（纯净）
├── bookshelf.js       # 书架相关接口（纯净）
├── user.js            # 用户相关接口（纯净）
├── sms.js             # 短信验证码接口（纯净）
├── modules.js         # 模块统一导出
├── types.ts           # TypeScript类型定义
├── usage-example.js   # 使用示例
├── api.json           # Swagger API文档
└── README.md          # 说明文档

src/store/
└── index.js           # 状态管理 + 业务逻辑
```

## 🚀 快速开始

### 基础使用模式

```javascript
// 1. 导入API和Store
import { authApi } from '@/api/modules';
import { useMainStore } from '@/store';

// 2. 在组件中使用
export default {
  setup() {
    const store = useMainStore();
    
    const handleLogin = async (formData) => {
      try {
        // 调用纯净API
        const response = await authApi.phoneLogin(formData);
        
        // 处理响应，更新状态
        if (response.success) {
          store.handleLoginSuccess(response.result);
          // 登录成功后的其他操作...
        }
      } catch (error) {
        // 错误处理...
      }
    };
    
    return { handleLogin };
  }
};
```

## 🔧 核心功能

### 1. 纯净API接口

所有API方法都是纯函数，只返回HTTP响应数据：

```javascript
// ✅ 正确：纯净的API调用
const response = await authApi.phoneLogin({ phone, code });
// response 是原始的API响应数据

// ❌ 错误：API不再自动处理状态
// API方法不会自动保存token或更新用户状态
```

### 2. Store状态管理

所有状态变更都通过Store方法处理：

```javascript
const store = useMainStore();

// 处理登录成功
store.handleLoginSuccess(result);

// 处理用户信息更新  
store.handleUserInfoUpdate(userInfo);

// 处理401错误（通常由axios拦截器自动调用）
store.handle401Error();

// 手动清除认证状态
store.clearAuthStatus();

// 手动登出
store.logout();
```

### 3. 自动错误处理

401错误由axios拦截器自动处理：

```javascript
// axios拦截器自动处理401错误
api.interceptors.response.use(
  response => response,
  error => {
    if (error.response.status === 401) {
      // 自动调用store的错误处理方法
      store.handle401Error();
    }
    return Promise.reject(error);
  }
);
```

## 📚 使用示例

### 登录流程

```javascript
import { authApi } from '@/api/modules';
import { useMainStore } from '@/store';

export async function login(phoneData) {
  const store = useMainStore();
  
  try {
    // 1. 调用API
    const response = await authApi.phoneLogin(phoneData);
    
    // 2. 检查响应
    if (response.success && response.result) {
      // 3. 更新状态
      store.handleLoginSuccess(response.result);
      return response.result;
    } else {
      throw new Error(response.message || '登录失败');
    }
  } catch (error) {
    console.error('登录失败:', error.message);
    throw error;
  }
}
```

### 获取数据流程

```javascript
import { homeApi } from '@/api/modules';

export async function getBooks(params) {
  try {
    // 纯净的数据获取，不涉及状态管理
    const response = await homeApi.getNewList(params);
    
    if (response.success) {
      return response.result;
    } else {
      throw new Error(response.message || '获取失败');
    }
  } catch (error) {
    console.error('获取书籍失败:', error.message);
    throw error;
  }
}
```

### 用户信息更新

```javascript
import { authApi } from '@/api/modules';
import { useMainStore } from '@/store';

export async function updateProfile(userInfo) {
  const store = useMainStore();
  
  try {
    // 1. 更新用户信息
    const updateResponse = await authApi.updateUserInfo(userInfo);
    
    if (updateResponse.success) {
      // 2. 重新获取最新信息
      const userResponse = await authApi.getUserByToken();
      
      if (userResponse.success) {
        // 3. 更新store状态
        store.handleUserInfoUpdate(userResponse.result);
        return userResponse.result;
      }
    }
    
    throw new Error(updateResponse.message || '更新失败');
  } catch (error) {
    console.error('更新用户信息失败:', error.message);
    throw error;
  }
}
```

## 🎨 在Vue组件中使用

```vue
<template>
  <div>
    <el-button @click="handleLogin" :loading="loading">
      登录
    </el-button>
    <div v-if="isLoggedIn">
      欢迎，{{ store.user.name }}
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import { authApi } from '@/api/modules';
import { useMainStore } from '@/store';
import { ElMessage } from 'element-plus';

const store = useMainStore();
const loading = ref(false);

// 响应式计算属性
const isLoggedIn = computed(() => store.isAuthenticated);

// 登录处理
const handleLogin = async () => {
  loading.value = true;
  
  try {
    const response = await authApi.phoneLogin({
      phone: '13800138000',
      code: '1234'
    });
    
    if (response.success) {
      store.handleLoginSuccess(response.result);
      ElMessage.success('登录成功');
    } else {
      throw new Error(response.message);
    }
  } catch (error) {
    ElMessage.error(error.message);
  } finally {
    loading.value = false;
  }
};

// 登出处理
const handleLogout = () => {
  store.logout();
  ElMessage.success('已登出');
};
</script>
```

## 📝 最佳实践

### ✅ 推荐做法

1. **分离关注点**：API只做请求，Store管理状态
2. **统一错误处理**：在组件层统一处理API错误
3. **响应式状态**：使用computed属性获取store状态
4. **类型安全**：使用TypeScript类型定义

```javascript
// ✅ 好的做法
const response = await authApi.phoneLogin(params);
if (response.success) {
  store.handleLoginSuccess(response.result);
}

// ✅ 使用响应式状态
const isLoggedIn = computed(() => store.isAuthenticated);
```

### ❌ 避免的做法

1. **在API中处理状态**：不要在API方法中操作localStorage或store
2. **直接操作状态**：不要绕过store方法直接修改状态
3. **混合关注点**：不要在同一个方法中既请求数据又处理UI逻辑

```javascript
// ❌ 不好的做法
const response = await authApi.phoneLogin(params);
// 不要直接操作localStorage
localStorage.setItem('token', response.result.token);

// ❌ 不要直接修改store状态
store.user = response.result.userInfo;
```

## 🛠️ 开发规范

### API层规范
- 所有方法都是纯函数，不包含副作用
- 只返回HTTP响应数据，不处理业务逻辑
- 不操作localStorage或其他全局状态
- 保持接口签名简洁明确

### Store层规范
- 所有状态变更都通过action方法
- 处理登录成功、用户信息更新等业务逻辑
- 管理localStorage的读写
- 处理错误状态和用户反馈

### 组件层规范
- 调用API获取数据
- 根据API响应调用相应的store方法
- 处理用户交互和UI状态
- 使用computed属性获取响应式状态

## 🔍 调试和排错

### 常见问题

1. **401错误处理**：由axios拦截器自动处理，会调用`store.handle401Error()`
2. **状态不同步**：确保所有状态变更都通过store方法
3. **重复登录**：检查是否正确调用了`store.handleLoginSuccess()`

### 调试技巧

```javascript
// 开启详细日志
console.log('[Debug] API Response:', response);
console.log('[Debug] Store State:', store.$state);

// 检查登录状态
console.log('[Debug] Auth Status:', store.checkAuthStatus());
```

## 🔗 相关链接

- [Pinia 官方文档](https://pinia.vuejs.org/)
- [Axios 官方文档](https://axios-http.com/)
- [Vue 3 Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)

这种架构设计确保了代码的可维护性、可测试性和扩展性，同时保持了各层职责的清晰分离。 