|
|
1 month ago | |
|---|---|---|
| .. | ||
| README.md | 4 months ago | |
| auth.js | 4 months ago | |
| bookshelf.js | 4 months ago | |
| home.js | 2 months ago | |
| index.js | 1 month ago | |
| modules.js | 4 months ago | |
| sms.js | 4 months ago | |
| types.ts | 4 months ago | |
| user.js | 4 months ago | |
本目录包含了小说阅读平台的所有API接口封装,基于后端Swagger API文档自动生成。
本项目采用 纯净API + 状态管理分离 的架构设计:
┌─────────────────┐
│ 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 # 状态管理 + 业务逻辑
// 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 };
}
};
所有API方法都是纯函数,只返回HTTP响应数据:
// ✅ 正确:纯净的API调用
const response = await authApi.phoneLogin({ phone, code });
// response 是原始的API响应数据
// ❌ 错误:API不再自动处理状态
// API方法不会自动保存token或更新用户状态
所有状态变更都通过Store方法处理:
const store = useMainStore();
// 处理登录成功
store.handleLoginSuccess(result);
// 处理用户信息更新
store.handleUserInfoUpdate(userInfo);
// 处理401错误(通常由axios拦截器自动调用)
store.handle401Error();
// 手动清除认证状态
store.clearAuthStatus();
// 手动登出
store.logout();
401错误由axios拦截器自动处理:
// axios拦截器自动处理401错误
api.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
// 自动调用store的错误处理方法
store.handle401Error();
}
return Promise.reject(error);
}
);
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;
}
}
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;
}
}
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;
}
}
<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>
// ✅ 好的做法
const response = await authApi.phoneLogin(params);
if (response.success) {
store.handleLoginSuccess(response.result);
}
// ✅ 使用响应式状态
const isLoggedIn = computed(() => store.isAuthenticated);
// ❌ 不好的做法
const response = await authApi.phoneLogin(params);
// 不要直接操作localStorage
localStorage.setItem('token', response.result.token);
// ❌ 不要直接修改store状态
store.user = response.result.userInfo;
store.handle401Error()store.handleLoginSuccess()// 开启详细日志
console.log('[Debug] API Response:', response);
console.log('[Debug] Store State:', store.$state);
// 检查登录状态
console.log('[Debug] Auth Status:', store.checkAuthStatus());
这种架构设计确保了代码的可维护性、可测试性和扩展性,同时保持了各层职责的清晰分离。