File size: 3,834 Bytes
69b897d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { apiClient } from '@/config/api'

export const useSettingsStore = defineStore('settings', () => {
  // 状态
  const oemSettings = ref({
    siteName: 'Claude Relay Service',
    siteIcon: '',
    siteIconData: '',
    showAdminButton: true, // 控制管理后台按钮的显示
    updatedAt: null
  })

  const loading = ref(false)
  const saving = ref(false)

  // 移除自定义API请求方法,使用统一的apiClient

  // Actions
  const loadOemSettings = async () => {
    loading.value = true
    try {
      const result = await apiClient.get('/admin/oem-settings')

      if (result && result.success) {
        oemSettings.value = { ...oemSettings.value, ...result.data }

        // 应用设置到页面
        applyOemSettings()
      }

      return result
    } catch (error) {
      console.error('Failed to load OEM settings:', error)
      throw error
    } finally {
      loading.value = false
    }
  }

  const saveOemSettings = async (settings) => {
    saving.value = true
    try {
      const result = await apiClient.put('/admin/oem-settings', settings)

      if (result && result.success) {
        oemSettings.value = { ...oemSettings.value, ...result.data }

        // 应用设置到页面
        applyOemSettings()
      }

      return result
    } catch (error) {
      console.error('Failed to save OEM settings:', error)
      throw error
    } finally {
      saving.value = false
    }
  }

  const resetOemSettings = async () => {
    const defaultSettings = {
      siteName: 'Claude Relay Service',
      siteIcon: '',
      siteIconData: '',
      showAdminButton: true,
      updatedAt: null
    }

    oemSettings.value = { ...defaultSettings }
    return await saveOemSettings(defaultSettings)
  }

  // 应用OEM设置到页面
  const applyOemSettings = () => {
    // 更新页面标题
    if (oemSettings.value.siteName) {
      document.title = `${oemSettings.value.siteName} - 管理后台`
    }

    // 更新favicon
    if (oemSettings.value.siteIconData || oemSettings.value.siteIcon) {
      const favicon = document.querySelector('link[rel="icon"]') || document.createElement('link')
      favicon.rel = 'icon'
      favicon.href = oemSettings.value.siteIconData || oemSettings.value.siteIcon
      if (!document.querySelector('link[rel="icon"]')) {
        document.head.appendChild(favicon)
      }
    }
  }

  // 格式化日期时间
  const formatDateTime = (dateString) => {
    if (!dateString) return ''
    return new Date(dateString).toLocaleString('zh-CN', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit'
    })
  }

  // 验证文件上传
  const validateIconFile = (file) => {
    const errors = []

    // 检查文件大小 (350KB)
    if (file.size > 350 * 1024) {
      errors.push('图标文件大小不能超过 350KB')
    }

    // 检查文件类型
    const allowedTypes = ['image/x-icon', 'image/png', 'image/jpeg', 'image/jpg', 'image/svg+xml']
    if (!allowedTypes.includes(file.type)) {
      errors.push('不支持的文件类型,请选择 .ico, .png, .jpg 或 .svg 文件')
    }

    return {
      isValid: errors.length === 0,
      errors
    }
  }

  // 将文件转换为Base64
  const fileToBase64 = (file) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader()
      reader.onload = (e) => resolve(e.target.result)
      reader.onerror = reject
      reader.readAsDataURL(file)
    })
  }

  return {
    // State
    oemSettings,
    loading,
    saving,

    // Actions
    loadOemSettings,
    saveOemSettings,
    resetOemSettings,
    applyOemSettings,
    formatDateTime,
    validateIconFile,
    fileToBase64
  }
})