Codex Assistant
昨天 58d9f460b2f8c34430285115e2557d18333c5cab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// API配置文件 - 统一管理所有API相关配置
export const API_CONFIG = {
  // 基础URL配置
  BASE_URL: '/api',
  
  // GraphQL端点
  GRAPHQL_ENDPOINT: '/api/graphql',
  
  // 其他API端点
  ENDPOINTS: {
    MEDIA_UPLOAD: '/api/media/upload',
    MEDIA_DOWNLOAD: '/api/media/download',
    WECHAT_LOGIN: '/api/wechat/login',
    WECHAT_PHONE: '/api/wechat/phone'
  }
}
 
// GraphQL请求工具函数
export const graphqlRequest = async (query: string, variables: any = {}) => {
  // 获取JWT token与工具
  const { getToken, isTokenExpired, clearAuth } = await import('@/utils/auth');
  const token = getToken();
 
  // 若token过期,直接清理并跳登录
  if (!token || isTokenExpired(token)) {
    clearAuth();
    // 避免在登录页重复跳转造成白屏/循环
    const atLogin = typeof window !== 'undefined' && window.location && window.location.hash?.startsWith('#/login');
    if (!atLogin) {
      window.location.href = '/#/login';
    }
    throw new Error('Token expired or missing')
  }
 
  // 构建请求头
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
  };
 
  if (token) {
    headers['Authorization'] = `Bearer ${token}`;
  }
 
  // 构建请求体
  const requestBody = JSON.stringify({
    query,
    variables,
  });
 
  try {
    // 发送请求
    const response = await fetch(API_CONFIG.GRAPHQL_ENDPOINT, {
      method: 'POST',
      headers,
      body: requestBody,
    });
 
    if (!response.ok) {
      // 处理401未授权
      if (response.status === 401) {
        const { clearAuth } = await import('@/utils/auth');
        clearAuth();
        const atLogin = typeof window !== 'undefined' && window.location && window.location.hash?.startsWith('#/login');
        if (!atLogin) {
          window.location.href = '/#/login';
        }
      }
      throw new Error(`HTTP error! status: ${response.status}`);
    }
 
    const result = await response.json();
 
    if (result.errors) {
      const msg = JSON.stringify(result.errors) || ''
      // 识别认证类错误关键字
      const isAuthError =
        msg.includes('Unauthorized') ||
        msg.includes('认证') ||
        msg.includes('unauthorized') ||
        msg.includes('invalid token') ||
        msg.includes('expired')
 
      if (isAuthError) {
        const { clearAuth } = await import('@/utils/auth');
        clearAuth();
        const atLogin = typeof window !== 'undefined' && window.location && window.location.hash?.startsWith('#/login');
        if (!atLogin) {
          window.location.href = '/#/login';
        }
      }
      throw new Error(`GraphQL errors: ${msg}`);
    }
 
    return result;
  } catch (error) {
    console.error('=== GraphQL请求失败 ===');
    console.error('错误详情:', error);
    throw error;
  }
}
 
// 通用API请求工具函数
export const apiRequest = async (endpoint: string, options: RequestInit = {}) => {
  const url = endpoint.startsWith('http') ? endpoint : `${API_CONFIG.BASE_URL}${endpoint}`
  
  const response = await fetch(url, {
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
    ...options,
  })
 
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`)
  }
 
  return response.json()
}