- 移除多余的统计、预算、AI设置、用户偏好、数据同步及AI处理相关类型定义 - 删除大量未使用的API请求函数,简化导出接口 - 保留核心的用户认证、交易记录、聊天消息和账单提醒相关接口 - 优化App组件状态初始化,改为从localStorage加载持久化数据,避免重复请求 - VoiceInput组件重构,改用持续监听及更健壮的权限和错误处理逻辑 - 优化语音识别启动和停止机制,提升用户体验和错误恢复能力 - 更新依赖顺序,无功能性变更
341 lines
7.2 KiB
TypeScript
341 lines
7.2 KiB
TypeScript
import { Transaction, Message, BillReminder } from '../types';
|
|
|
|
// API基础配置
|
|
const getApiUrl = (): string => {
|
|
return process.env.API_URL || 'http://localhost:8000';
|
|
};
|
|
|
|
const getAuthToken = (): string | null => {
|
|
return localStorage.getItem('auth_token');
|
|
};
|
|
|
|
// 统一响应格式
|
|
interface ApiResponse<T = any> {
|
|
code: number;
|
|
msg?: string;
|
|
message?: string;
|
|
result?: T;
|
|
}
|
|
|
|
// 分页响应格式
|
|
interface PaginatedResponse<T> {
|
|
items: T[];
|
|
skip: number;
|
|
total: number;
|
|
}
|
|
|
|
// 通用请求函数
|
|
async function request<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const token = getAuthToken();
|
|
const apiUrl = getApiUrl();
|
|
const url = `${apiUrl}${endpoint}`;
|
|
|
|
console.log(`请求地址: ${url}`);
|
|
|
|
const defaultHeaders: HeadersInit = {
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
if (token) {
|
|
defaultHeaders['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
const config: RequestInit = {
|
|
...options,
|
|
headers: {
|
|
...defaultHeaders,
|
|
...options.headers,
|
|
},
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(url, config);
|
|
|
|
const data: ApiResponse<T> = await response.json();
|
|
|
|
if (!response.ok || (data.code && data.code !== 200)) {
|
|
const errorMsg = data.msg || data.message || `HTTP error! status: ${response.status}`;
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
return data.result as T;
|
|
} catch (error) {
|
|
console.error('API请求错误:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// ==================== 用户认证接口 ====================
|
|
|
|
/**
|
|
* 登录或注册
|
|
*/
|
|
export async function loginOrRegister(openid: string, mobile: string): Promise<{
|
|
token: string;
|
|
user: any;
|
|
}> {
|
|
const apiUrl = getApiUrl();
|
|
console.log(`请求地址: ${apiUrl}/wx/loginOrRegister`);
|
|
|
|
const response = await fetch(`${apiUrl}/wx/loginOrRegister`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ openid, mobile }),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.code === 200 && data.result?.token) {
|
|
// 保存token到localStorage
|
|
localStorage.setItem('auth_token', data.result.token);
|
|
}
|
|
|
|
return data.result;
|
|
}
|
|
|
|
/**
|
|
* 获取用户信息
|
|
*/
|
|
export async function getUserProfile(): Promise<any> {
|
|
return request<any>('/wx/profile', {
|
|
method: 'GET',
|
|
});
|
|
}
|
|
|
|
// ==================== 交易记录接口 ====================
|
|
|
|
/**
|
|
* 创建交易记录
|
|
*/
|
|
export async function createTransaction(data: {
|
|
item: string;
|
|
amount: number;
|
|
type: 'expense' | 'income';
|
|
category: string;
|
|
date: string;
|
|
timestamp: number;
|
|
}): Promise<Transaction> {
|
|
return request<Transaction>('/bill/transactions/', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 查询交易记录列表(分页)
|
|
*/
|
|
export async function getTransactions(params?: {
|
|
skip?: number;
|
|
limit?: number;
|
|
type?: 'expense' | 'income';
|
|
category?: string;
|
|
start_date?: string;
|
|
end_date?: string;
|
|
month?: string;
|
|
}): Promise<PaginatedResponse<Transaction>> {
|
|
const queryString = new URLSearchParams(
|
|
Object.entries(params || {}).reduce((acc, [key, value]) => {
|
|
if (value !== undefined) {
|
|
acc[key] = String(value);
|
|
}
|
|
return acc;
|
|
}, {} as Record<string, string>)
|
|
).toString();
|
|
|
|
return request<PaginatedResponse<Transaction>>(
|
|
`/bill/transactions/${queryString ? `?${queryString}` : ''}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 更新交易记录
|
|
*/
|
|
export async function updateTransaction(
|
|
id: string,
|
|
data: Partial<{
|
|
item: string;
|
|
amount: number;
|
|
type: 'expense' | 'income';
|
|
category: string;
|
|
date: string;
|
|
timestamp: number;
|
|
}>
|
|
): Promise<Transaction> {
|
|
return request<Transaction>(`/bill/transactions/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 删除交易记录
|
|
*/
|
|
export async function deleteTransaction(id: string): Promise<void> {
|
|
return request<void>(`/bill/transactions/${id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
}
|
|
|
|
// ==================== 聊天消息接口 ====================
|
|
|
|
/**
|
|
* 创建聊天消息
|
|
*/
|
|
export async function createMessage(data: {
|
|
role: 'user' | 'assistant';
|
|
content: string;
|
|
timestamp: number;
|
|
transaction_id?: string;
|
|
}): Promise<Message> {
|
|
return request<Message>('/bill/messages/', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 查询聊天消息列表
|
|
*/
|
|
export async function getMessages(params?: {
|
|
skip?: number;
|
|
limit?: number;
|
|
role?: 'user' | 'assistant';
|
|
start_timestamp?: number;
|
|
end_timestamp?: number;
|
|
}): Promise<PaginatedResponse<Message>> {
|
|
const queryString = new URLSearchParams(
|
|
Object.entries(params || {}).reduce((acc, [key, value]) => {
|
|
if (value !== undefined) {
|
|
acc[key] = String(value);
|
|
}
|
|
return acc;
|
|
}, {} as Record<string, string>)
|
|
).toString();
|
|
|
|
return request<PaginatedResponse<Message>>(
|
|
`/bill/messages/${queryString ? `?${queryString}` : ''}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 删除消息
|
|
*/
|
|
export async function deleteMessage(id: string): Promise<void> {
|
|
return request<void>(`/bill/messages/${id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
}
|
|
|
|
// ==================== 账单提醒接口 ====================
|
|
|
|
/**
|
|
* 创建账单提醒
|
|
*/
|
|
export async function createReminder(data: {
|
|
title: string;
|
|
amount?: number;
|
|
frequency: 'monthly' | 'once';
|
|
target_date: string;
|
|
}): Promise<BillReminder> {
|
|
return request<BillReminder>('/bill/reminders/', {
|
|
method: 'POST',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 查询账单提醒列表
|
|
*/
|
|
export async function getReminders(params?: {
|
|
skip?: number;
|
|
limit?: number;
|
|
frequency?: 'monthly' | 'once';
|
|
is_completed?: boolean;
|
|
month?: string;
|
|
}): Promise<PaginatedResponse<BillReminder>> {
|
|
const queryString = new URLSearchParams(
|
|
Object.entries(params || {}).reduce((acc, [key, value]) => {
|
|
if (value !== undefined) {
|
|
acc[key] = String(value);
|
|
}
|
|
return acc;
|
|
}, {} as Record<string, string>)
|
|
).toString();
|
|
|
|
return request<PaginatedResponse<BillReminder>>(
|
|
`/bill/reminders/${queryString ? `?${queryString}` : ''}`
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 更新账单提醒
|
|
*/
|
|
export async function updateReminder(
|
|
id: string,
|
|
data: Partial<{
|
|
title: string;
|
|
amount?: number;
|
|
frequency: 'monthly' | 'once';
|
|
target_date: string;
|
|
}>
|
|
): Promise<BillReminder> {
|
|
return request<BillReminder>(`/bill/reminders/${id}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(data),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 切换提醒完成状态
|
|
*/
|
|
export async function toggleReminder(
|
|
id: string
|
|
): Promise<{ id: string; is_completed: boolean }> {
|
|
return request<{ id: string; is_completed: boolean }>(
|
|
`/bill/reminders/${id}/toggle`,
|
|
{
|
|
method: 'PATCH',
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 删除账单提醒
|
|
*/
|
|
export async function deleteReminder(id: string): Promise<void> {
|
|
return request<void>(`/bill/reminders/${id}`, {
|
|
method: 'DELETE',
|
|
});
|
|
}
|
|
|
|
|
|
// ==================== 导出所有API ====================
|
|
export default {
|
|
// 用户认证
|
|
loginOrRegister,
|
|
getUserProfile,
|
|
|
|
// 交易记录
|
|
createTransaction,
|
|
getTransactions,
|
|
updateTransaction,
|
|
deleteTransaction,
|
|
|
|
// 聊天消息
|
|
createMessage,
|
|
getMessages,
|
|
deleteMessage,
|
|
|
|
// 账单提醒
|
|
createReminder,
|
|
getReminders,
|
|
updateReminder,
|
|
toggleReminder,
|
|
deleteReminder,
|
|
};
|