client.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { demoCards } from './demoFixtures';
  2. import { buildAuthHeaders } from './hmac';
  3. import type { CardInstance } from './types';
  4. const API_BASE = import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:6040/api/v1';
  5. const DEMO_MODE = import.meta.env.VITE_DEMO_MODE === 'true';
  6. function isSuccess(body: { code: unknown }): boolean {
  7. return body.code === 0 || body.code === 200;
  8. }
  9. export async function fetchCard(cardInstanceId: string): Promise<CardInstance> {
  10. if (DEMO_MODE) {
  11. const card = demoCards[cardInstanceId];
  12. if (!card) throw new Error(`演示卡片不存在: ${cardInstanceId}`);
  13. return card;
  14. }
  15. const path = `/api/v1/cards/${cardInstanceId}`;
  16. const headers = await buildAuthHeaders('GET', path, '');
  17. const response = await fetch(`${API_BASE}/cards/${cardInstanceId}`, { headers });
  18. const body = await response.json();
  19. if (!response.ok || !isSuccess(body)) throw new Error(body.msg ?? '查询卡片失败');
  20. return body.data;
  21. }
  22. export interface CardActionResult {
  23. status: string;
  24. actionId: string;
  25. nextCard?: CardInstance;
  26. }
  27. export async function submitCardAction(
  28. cardInstanceId: string,
  29. actionName: string,
  30. payload: Record<string, unknown>,
  31. idempotencyKey?: string,
  32. ): Promise<CardActionResult> {
  33. const key = idempotencyKey ?? `${cardInstanceId}-${actionName}-${Date.now()}`;
  34. const body = JSON.stringify({
  35. idempotencyKey: key,
  36. confirm: true,
  37. payload,
  38. });
  39. if (DEMO_MODE) {
  40. return { status: 'completed', actionId: `action_${Date.now()}` };
  41. }
  42. const path = `/api/v1/cards/${cardInstanceId}/actions/${actionName}`;
  43. const headers = await buildAuthHeaders('POST', path, body);
  44. const response = await fetch(`${API_BASE}/cards/${cardInstanceId}/actions/${actionName}`, {
  45. method: 'POST',
  46. headers: { ...headers, 'Content-Type': 'application/json' },
  47. body,
  48. });
  49. const data = await response.json();
  50. if (!response.ok || !isSuccess(data)) throw new Error(data.msg ?? '提交卡片动作失败');
  51. return data.data;
  52. }