Files
Toolbox/apps/app_order_box/kits/motion_reminder/api.ts
T
yangxiangyuan 212dbc4e1d refactor: 重构禅音工具路径与配置,新增私人剪贴板技能
这是一次大型重构和功能新增:
1. 将原 zen_box 工具重命名为 web_zen_box,调整所有相关路径与配置
2. 新增 web_order_box 原生Web应用的完整资源与部署脚本
3. 新增私人剪贴板后端技能与配套测试脚本
4. 修复订单盒子APP的API地址配置,避免路径重复拼接
5. 新增本地开发跨域白名单支持localhost
6. 清理旧版zen_box的冗余文件
2026-07-26 21:03:28 +08:00

99 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios from 'axios';
import { ApiEnvelope, MotionCard, MotionSession } from './types';
const API_BASE_URL = process.env.EXPO_PUBLIC_API_BASE_URL || '/api/app_order_box';
// 注意:MOTION_BASE 是相对于 axios baseURL 的路径,不要包含 API_BASE_URL 前缀
// 否则 axios 会双重拼接导致 404(如 /api/app_order_box/api/app_order_box/kits/...)
const MOTION_BASE = '/kits/motion_reminder';
const api = axios.create({
baseURL: API_BASE_URL,
timeout: 15000,
headers: {
'Content-Type': 'application/json',
},
});
const formatError = (error: any): string => {
if (error?.response) {
return `服务器响应 ${error.response.status}: ${error.response.statusText}\n${JSON.stringify(error.response.data)}`;
}
if (error?.request) {
return `服务器无响应: 无法连接到 ${API_BASE_URL}`;
}
if (error?.message) {
return `请求错误: ${error.message}`;
}
return '未知错误';
};
export const motionReminderApi = {
async listCards(): Promise<MotionCard[]> {
try {
const response = await api.get<ApiEnvelope<MotionCard[]>>(`${MOTION_BASE}/cards`);
return response.data.data || [];
} catch (error) {
throw new Error(formatError(error));
}
},
async saveCard(card: Partial<MotionCard>): Promise<MotionCard> {
try {
const response = card.id
? await api.put<ApiEnvelope<MotionCard>>(`${MOTION_BASE}/cards`, card)
: await api.post<ApiEnvelope<MotionCard>>(`${MOTION_BASE}/cards`, card);
if (!response.data.ok || !response.data.data) {
throw new Error(response.data.error || '保存失败');
}
return response.data.data;
} catch (error) {
throw new Error(formatError(error));
}
},
async deleteCard(id: string): Promise<void> {
try {
await api.delete(`${MOTION_BASE}/cards`, { params: { id } });
} catch (error) {
throw new Error(formatError(error));
}
},
async listHistory(): Promise<MotionSession[]> {
try {
const response = await api.get<ApiEnvelope<MotionSession[]>>(`${MOTION_BASE}/history`);
return response.data.data || [];
} catch (error) {
throw new Error(formatError(error));
}
},
async startSession(card: MotionCard): Promise<MotionSession> {
try {
const response = await api.post<ApiEnvelope<MotionSession>>(`${MOTION_BASE}/sessions/start`, { card });
if (!response.data.ok || !response.data.data) {
throw new Error(response.data.error || '启动失败');
}
return response.data.data;
} catch (error) {
throw new Error(formatError(error));
}
},
async syncSession(payload: Partial<MotionSession> & { id: string }): Promise<void> {
try {
await api.post(`${MOTION_BASE}/sessions/sync`, payload);
} catch (error) {
throw new Error(formatError(error));
}
},
async finishSession(payload: Partial<MotionSession> & { id: string; status: 'completed' | 'stopped' }): Promise<void> {
try {
await api.post(`${MOTION_BASE}/sessions/finish`, payload);
} catch (error) {
throw new Error(formatError(error));
}
},
};