File size: 7,413 Bytes
d0dd276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useBackendStore = defineStore('backend', () => {
  // 后端实例列表
  const backends = ref([
    {
      id: 'local',
      name: '本地实例',
      baseUrl: window.location.origin,
      password: '',
      isActive: true,
      isConnected: false,
      lastConnected: null,
      description: '当前页面的后端实例'
    }
  ])

  // 当前活跃的后端实例
  const activeBackendId = ref('local')

  // 获取当前活跃的后端实例
  const activeBackend = computed(() => {
    return backends.value.find(backend => backend.id === activeBackendId.value)
  })

  // 获取连接的后端数量
  const connectedBackendsCount = computed(() => {
    return backends.value.filter(backend => backend.isConnected).length
  })

  // 添加后端实例
  function addBackend(backend) {
    const newBackend = {
      id: `backend_${Date.now()}`,
      name: backend.name || '未命名实例',
      baseUrl: backend.baseUrl,
      password: backend.password || '',
      isActive: false,
      isConnected: false,
      lastConnected: null,
      description: backend.description || ''
    }
    
    backends.value.push(newBackend)
    return newBackend
  }

  // 删除后端实例
  function removeBackend(backendId) {
    if (backendId === 'local') {
      throw new Error('不能删除本地实例')
    }
    
    const index = backends.value.findIndex(backend => backend.id === backendId)
    if (index > -1) {
      backends.value.splice(index, 1)
      
      // 如果删除的是当前活跃实例,切换到本地实例
      if (activeBackendId.value === backendId) {
        activeBackendId.value = 'local'
      }
    }
  }

  // 更新后端实例
  function updateBackend(backendId, updates) {
    const backend = backends.value.find(b => b.id === backendId)
    if (backend) {
      Object.assign(backend, updates)
    }
  }

  // 切换活跃的后端实例
  function switchBackend(backendId) {
    const backend = backends.value.find(b => b.id === backendId)
    if (backend) {
      // 取消其他实例的活跃状态
      backends.value.forEach(b => { b.isActive = false })
      
      // 设置新的活跃实例
      backend.isActive = true
      activeBackendId.value = backendId
      
      console.log(`已切换到后端实例: ${backend.name}`)
      return true
    }
    return false
  }

  // 测试后端连接
  async function testBackendConnection(backendId) {
    const backend = backends.value.find(b => b.id === backendId)
    if (!backend) {
      throw new Error('后端实例不存在')
    }

    try {
      const response = await fetch(`${backend.baseUrl}/api/dashboard-data`, {
        method: 'GET',
        headers: {
          'Authorization': backend.password ? `Bearer ${backend.password}` : '',
          'Content-Type': 'application/json'
        }
      })

      if (response.ok) {
        backend.isConnected = true
        backend.lastConnected = new Date().toISOString()
        return { success: true, message: '连接成功' }
      } else {
        backend.isConnected = false
        return { success: false, message: `连接失败: ${response.status}` }
      }
    } catch (error) {
      backend.isConnected = false
      return { success: false, message: `连接错误: ${error.message}` }
    }
  }

  // 批量测试所有后端连接
  async function testAllConnections() {
    const results = await Promise.allSettled(
      backends.value.map(backend => testBackendConnection(backend.id))
    )
    
    return results.map((result, index) => ({
      backendId: backends.value[index].id,
      ...result.value
    }))
  }

  // 构造 API 请求 URL
  function buildApiUrl(endpoint) {
    const backend = activeBackend.value
    if (!backend) {
      throw new Error('没有活跃的后端实例')
    }
    
    const baseUrl = backend.baseUrl.replace(/\/$/, '') // 移除末尾斜杠
    const cleanEndpoint = endpoint.replace(/^\//, '') // 移除开头斜杠
    
    return `${baseUrl}/${cleanEndpoint}`
  }

  // 获取当前后端的认证头
  function getAuthHeaders() {
    const backend = activeBackend.value
    const headers = {
      'Content-Type': 'application/json'
    }
    
    if (backend && backend.password) {
      headers['Authorization'] = `Bearer ${backend.password}`
    }
    
    return headers
  }

  // 发起 API 请求(带自动重试)
  async function apiRequest(endpoint, options = {}) {
    const url = buildApiUrl(endpoint)
    const headers = { ...getAuthHeaders(), ...options.headers }
    
    try {
      const response = await fetch(url, {
        ...options,
        headers
      })
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }
      
      // 更新连接状态
      if (activeBackend.value) {
        activeBackend.value.isConnected = true
        activeBackend.value.lastConnected = new Date().toISOString()
      }
      
      return response
    } catch (error) {
      // 更新连接状态
      if (activeBackend.value) {
        activeBackend.value.isConnected = false
      }
      
      console.error(`API请求失败 [${activeBackend.value?.name}]:`, error)
      throw error
    }
  }

  // 保存配置到 localStorage
  function saveToStorage() {
    const data = {
      backends: backends.value,
      activeBackendId: activeBackendId.value
    }
    localStorage.setItem('hajimi_backends', JSON.stringify(data))
  }

  // 从 localStorage 加载配置
  function loadFromStorage() {
    try {
      const stored = localStorage.getItem('hajimi_backends')
      if (stored) {
        const data = JSON.parse(stored)
        
        if (data.backends && Array.isArray(data.backends)) {
          // 确保本地实例始终存在
          const hasLocal = data.backends.some(b => b.id === 'local')
          if (!hasLocal) {
            data.backends.unshift({
              id: 'local',
              name: '本地实例',
              baseUrl: window.location.origin,
              password: '',
              isActive: false,
              isConnected: false,
              lastConnected: null,
              description: '当前页面的后端实例'
            })
          }
          
          backends.value = data.backends
        }
        
        if (data.activeBackendId) {
          activeBackendId.value = data.activeBackendId
          switchBackend(data.activeBackendId)
        }
      }
    } catch (error) {
      console.error('加载后端配置失败:', error)
    }
  }

  // 重置为默认配置
  function resetToDefault() {
    backends.value = [
      {
        id: 'local',
        name: '本地实例',
        baseUrl: window.location.origin,
        password: '',
        isActive: true,
        isConnected: false,
        lastConnected: null,
        description: '当前页面的后端实例'
      }
    ]
    activeBackendId.value = 'local'
    saveToStorage()
  }

  // 初始化时加载配置
  loadFromStorage()

  return {
    backends,
    activeBackendId,
    activeBackend,
    connectedBackendsCount,
    addBackend,
    removeBackend,
    updateBackend,
    switchBackend,
    testBackendConnection,
    testAllConnections,
    buildApiUrl,
    getAuthHeaders,
    apiRequest,
    saveToStorage,
    loadFromStorage,
    resetToDefault
  }
})