@wwkit/freetoken 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/cli/helpers/args.js +48 -0
  4. package/cli/index.js +374 -0
  5. package/cli/pid-manager.js +87 -0
  6. package/client/index.html +25 -0
  7. package/client/public/favicon.svg +1 -0
  8. package/client/public/icons.svg +24 -0
  9. package/client/src/App.vue +136 -0
  10. package/client/src/assets/vite.svg +1 -0
  11. package/client/src/assets/vue.svg +1 -0
  12. package/client/src/components/ChatBox.vue +320 -0
  13. package/client/src/components/CheckList.vue +52 -0
  14. package/client/src/components/CodeBlock.vue +99 -0
  15. package/client/src/components/DetailBlock.vue +47 -0
  16. package/client/src/components/HelloWorld.vue +95 -0
  17. package/client/src/components/LangSwitch.vue +32 -0
  18. package/client/src/components/LinkList.vue +32 -0
  19. package/client/src/components/OsSwitch.vue +42 -0
  20. package/client/src/components/OsToggle.vue +15 -0
  21. package/client/src/components/PageHeader.vue +31 -0
  22. package/client/src/components/StepList.vue +92 -0
  23. package/client/src/composables/useClipboard.js +26 -0
  24. package/client/src/composables/useOs.js +22 -0
  25. package/client/src/data/docs/agent.js +1002 -0
  26. package/client/src/data/docs/auth.js +631 -0
  27. package/client/src/data/docs/builtin-tools.js +322 -0
  28. package/client/src/data/docs/chat.js +181 -0
  29. package/client/src/data/docs/index.js +9 -0
  30. package/client/src/data/docs/skills.js +396 -0
  31. package/client/src/data/docs/spec-conversion.js +1042 -0
  32. package/client/src/data/freeModels/bluesliu.js +97 -0
  33. package/client/src/data/freeModels/index.js +11 -0
  34. package/client/src/data/freeModels/nvidia.js +126 -0
  35. package/client/src/data/freeModels/openrouter.js +116 -0
  36. package/client/src/data/harness/claude.js +89 -0
  37. package/client/src/data/harness/codex.js +66 -0
  38. package/client/src/data/harness/dsh.js +86 -0
  39. package/client/src/data/harness/hermes.js +56 -0
  40. package/client/src/data/harness/index.js +22 -0
  41. package/client/src/data/harness/opencode.js +77 -0
  42. package/client/src/data/proxy/api-relay.js +53 -0
  43. package/client/src/data/proxy/builtin-proxy.js +54 -0
  44. package/client/src/data/proxy/cf-workers.js +67 -0
  45. package/client/src/data/proxy/ecs-forward.js +75 -0
  46. package/client/src/data/proxy/ecs-reverse.js +89 -0
  47. package/client/src/data/proxy/index.js +15 -0
  48. package/client/src/docs/claudecode.md +44 -0
  49. package/client/src/docs/codex.md +90 -0
  50. package/client/src/docs/hermesagent.md +42 -0
  51. package/client/src/docs/opencode.md +103 -0
  52. package/client/src/locales/en.js +436 -0
  53. package/client/src/locales/index.js +31 -0
  54. package/client/src/locales/zh-CN.js +461 -0
  55. package/client/src/main.js +16 -0
  56. package/client/src/router/index.js +76 -0
  57. package/client/src/style.css +15 -0
  58. package/client/src/views/AdminModelsView.vue +214 -0
  59. package/client/src/views/DocsView.vue +1604 -0
  60. package/client/src/views/FreeModelsView.vue +518 -0
  61. package/client/src/views/HarnessView.vue +314 -0
  62. package/client/src/views/HomeView.vue +147 -0
  63. package/client/src/views/ProxyView.vue +112 -0
  64. package/client/src/views/TokenMarketView.vue +26 -0
  65. package/client/vite.config.js +41 -0
  66. package/package.json +85 -0
  67. package/scripts/build-zip.sh +61 -0
  68. package/scripts/postinstall.js +7 -0
  69. package/server/src/config/targets.json +1 -0
  70. package/server/src/index.js +52 -0
  71. package/server/src/lib/coding-test.js +215 -0
  72. package/server/src/lib/database.js +353 -0
  73. package/server/src/lib/run-test.js +15 -0
  74. package/server/src/lib/scheduler.js +21 -0
  75. package/server/src/lib/tester.js +310 -0
  76. package/server/src/routes/admin.js +48 -0
  77. package/server/src/routes/proxy.js +64 -0
  78. package/server/src/routes/speed.js +87 -0
  79. package/src/config.js +45 -0
  80. package/src/config.json5 +27 -0
  81. package/src/index.js +10 -0
@@ -0,0 +1,314 @@
1
+ <script setup>
2
+ import { ref, computed } from 'vue'
3
+ import { useI18n } from 'vue-i18n'
4
+ import { harnessTools, npmMirrors } from '../data/harness/index.js'
5
+ import PageHeader from '../components/PageHeader.vue'
6
+ import CodeBlock from '../components/CodeBlock.vue'
7
+ import DetailBlock from '../components/DetailBlock.vue'
8
+ import LinkList from '../components/LinkList.vue'
9
+ import { useOs } from '../composables/useOs'
10
+
11
+ const { t } = useI18n()
12
+ const { os } = useOs()
13
+
14
+ const activeId = ref(harnessTools[0].id)
15
+ const activeTool = ref(harnessTools[0])
16
+ const activeSubTab = ref('install')
17
+ const npmRegistry = ref('')
18
+
19
+ const subTabs = computed(() => {
20
+ const tabs = [
21
+ { id: 'install', label: t('harness.install') },
22
+ { id: 'config', label: t('harness.config') },
23
+ ]
24
+ if (activeTool.value.startup) {
25
+ tabs.push({ id: 'startup', label: t('harness.startup') })
26
+ }
27
+ if (activeTool.value.sessionManagement) {
28
+ tabs.push({ id: 'session', label: t('harness.sessionManagement') })
29
+ }
30
+ if (activeTool.value.install.git) {
31
+ tabs.push({ id: 'develop', label: t('harness.develop') })
32
+ }
33
+ if (activeTool.value.requirements) {
34
+ tabs.push({ id: 'requirements', label: t('harness.requirements') })
35
+ }
36
+ return tabs
37
+ })
38
+
39
+ const curlCopyText = computed(() => {
40
+ if (!activeTool.value.install.curl) return ''
41
+ return activeTool.value.install.curl.copy[os.value]
42
+ })
43
+
44
+ const npmCopyText = computed(() => {
45
+ if (!activeTool.value.install.npm) return ''
46
+ const { pkg, verify } = activeTool.value.install.npm
47
+ if (!pkg || !verify) return ''
48
+ const sep = os.value === 'unix' ? ' && ' : '; '
49
+ const registry = npmRegistry.value
50
+ const flag = registry ? ` --registry=${registry}` : ''
51
+ return `npm install -g ${pkg}${flag}${sep}${verify}`
52
+ })
53
+
54
+ function selectTool(tool) {
55
+ activeId.value = tool.id
56
+ activeTool.value = tool
57
+ activeSubTab.value = 'install'
58
+ }
59
+ </script>
60
+
61
+ <template>
62
+ <div class="harness-page">
63
+ <PageHeader
64
+ :title="$t('harness.pageTitle')"
65
+ :description="$t('harness.pageDesc')"
66
+ />
67
+
68
+ <el-tabs v-model="activeId" @tab-change="selectTool(harnessTools.find(t => t.id === activeId))">
69
+ <el-tab-pane
70
+ v-for="tool in harnessTools"
71
+ :key="tool.id"
72
+ :name="tool.id"
73
+ >
74
+ <template #label>
75
+ <span>{{ $t(tool.nameKey) }}</span>
76
+ </template>
77
+ </el-tab-pane>
78
+ </el-tabs>
79
+
80
+ <div v-if="activeTool" class="tool-detail">
81
+ <div class="tool-header">
82
+ <h2 class="tool-name">{{ $t(activeTool.nameKey) }}</h2>
83
+ <el-tag>{{ $t(activeTool.badgeKey) }}</el-tag>
84
+ </div>
85
+ <p class="tool-tagline">{{ $t(activeTool.taglineKey) }}</p>
86
+ <p class="tool-description">{{ $t(activeTool.descriptionKey) }}</p>
87
+
88
+ <el-tabs v-model="activeSubTab" class="sub-tabs">
89
+ <el-tab-pane :label="subTabs[0].label" name="install">
90
+ <div class="install-section">
91
+ <DetailBlock v-if="activeTool.install.curl" :title="$t('harness.curlInstall')">
92
+ <CodeBlock
93
+ :code="activeTool.install.curl.display"
94
+ :copy-text="curlCopyText"
95
+ lang="bash"
96
+ filename="terminal"
97
+ />
98
+ </DetailBlock>
99
+
100
+ <DetailBlock v-if="activeTool.install.npm">
101
+ <template #header>
102
+ <div class="npm-header">
103
+ <span class="npm-title">{{ $t('harness.npmInstall') }}</span>
104
+ <el-select v-model="npmRegistry" size="small" :placeholder="$t('harness.npmMirrorPlaceholder')" class="registry-select">
105
+ <el-option
106
+ v-for="m in npmMirrors"
107
+ :key="m.value"
108
+ :label="$t(m.labelKey)"
109
+ :value="m.value"
110
+ />
111
+ </el-select>
112
+ </div>
113
+ </template>
114
+ <CodeBlock
115
+ :code="activeTool.install.npm.display"
116
+ :copy-text="npmCopyText"
117
+ lang="bash"
118
+ filename="terminal"
119
+ />
120
+ </DetailBlock>
121
+ </div>
122
+ </el-tab-pane>
123
+
124
+ <el-tab-pane :label="subTabs[1].label" name="config">
125
+ <DetailBlock :title="$t('harness.modelConfig')">
126
+ <CodeBlock :code="activeTool.config" :lang="activeTool.configFormat" :filename="activeTool.configFilename" />
127
+ </DetailBlock>
128
+ <DetailBlock v-if="activeTool.configTips" :title="$t('harness.configTips')">
129
+ <div v-for="(tip, index) in activeTool.configTips" :key="index" class="tip-item">
130
+ <span class="tip-text">{{ tip }}</span>
131
+ </div>
132
+ </DetailBlock>
133
+ <DetailBlock v-if="activeTool.modelSwitch" :title="$t('harness.modelSwitch')">
134
+ <template v-if="typeof activeTool.modelSwitch === 'string'">
135
+ <p class="model-switch-text">{{ activeTool.modelSwitch }}</p>
136
+ </template>
137
+ <template v-else>
138
+ <p class="model-switch-text">{{ activeTool.modelSwitch.description }}</p>
139
+ <div v-for="(method, index) in activeTool.modelSwitch.methods" :key="index" class="method-item">
140
+ <h4>{{ method.title }}</h4>
141
+ <p>{{ method.content }}</p>
142
+ <CodeBlock v-if="method.command" :code="method.command" lang="bash" filename="terminal" />
143
+ <CodeBlock v-if="method.example" :code="method.example" lang="json" filename="settings.json" />
144
+ </div>
145
+ </template>
146
+ </DetailBlock>
147
+ </el-tab-pane>
148
+
149
+ <el-tab-pane v-if="activeTool.startup" :label="subTabs[2].label" name="startup">
150
+ <DetailBlock :title="$t('harness.startupCommand')">
151
+ <CodeBlock
152
+ :code="activeTool.startup.command"
153
+ lang="bash"
154
+ filename="terminal"
155
+ />
156
+ </DetailBlock>
157
+ <DetailBlock v-if="activeTool.startup.tips" :title="$t('harness.sessionOperations')">
158
+ <div v-for="(tip, index) in activeTool.startup.tips" :key="index" class="tip-item">
159
+ <span class="tip-text">{{ tip }}</span>
160
+ </div>
161
+ </DetailBlock>
162
+ </el-tab-pane>
163
+
164
+ <el-tab-pane v-if="activeTool.sessionManagement" :label="subTabs[subTabs.findIndex(t => t.id === 'session')].label" name="session">
165
+ <DetailBlock :title="$t('harness.sessionExport')">
166
+ <CodeBlock
167
+ :code="activeTool.sessionManagement.export"
168
+ lang="bash"
169
+ filename="terminal"
170
+ />
171
+ </DetailBlock>
172
+ <DetailBlock :title="$t('harness.sessionImport')">
173
+ <CodeBlock
174
+ :code="activeTool.sessionManagement.import"
175
+ lang="bash"
176
+ filename="terminal"
177
+ />
178
+ </DetailBlock>
179
+ </el-tab-pane>
180
+
181
+ <el-tab-pane v-if="activeTool.install.git" :label="subTabs[subTabs.findIndex(t => t.id === 'develop')].label" name="develop">
182
+ <DetailBlock :title="$t('harness.gitInstall')">
183
+ <CodeBlock
184
+ :code="activeTool.install.git.display"
185
+ lang="bash"
186
+ filename="terminal"
187
+ />
188
+ </DetailBlock>
189
+ </el-tab-pane>
190
+
191
+ <el-tab-pane v-if="activeTool.requirements" :label="subTabs[subTabs.length - 1].label" name="requirements">
192
+ <div class="requirements-section">
193
+ <DetailBlock :title="$t('harness.nodeRequirement')">
194
+ <div class="requirement-item">
195
+ <span class="label">Node.js:</span>
196
+ <span class="value">{{ activeTool.requirements.node }}</span>
197
+ </div>
198
+ </DetailBlock>
199
+ <DetailBlock v-if="activeTool.requirements.envVars" :title="$t('harness.envRequirement')">
200
+ <div v-for="envVar in activeTool.requirements.envVars" :key="envVar" class="requirement-item">
201
+ <span class="label">{{ envVar }}:</span>
202
+ <span class="value">{{ $t('harness.envVarDesc') }}</span>
203
+ </div>
204
+ </DetailBlock>
205
+ </div>
206
+ </el-tab-pane>
207
+ </el-tabs>
208
+
209
+ <DetailBlock :title="$t('harness.relatedLinks')">
210
+ <LinkList :links="activeTool.links" />
211
+ </DetailBlock>
212
+ </div>
213
+ </div>
214
+ </template>
215
+
216
+ <style scoped>
217
+ .tool-detail {
218
+ margin-top: 16px;
219
+ }
220
+ .tool-header {
221
+ display: flex;
222
+ align-items: center;
223
+ gap: 12px;
224
+ margin-bottom: 8px;
225
+ }
226
+ .tool-name {
227
+ margin: 0;
228
+ font-size: 22px;
229
+ font-weight: 600;
230
+ }
231
+ .tool-tagline {
232
+ margin: 0 0 8px;
233
+ font-size: 14px;
234
+ color: var(--el-text-color-secondary);
235
+ }
236
+ .tool-description {
237
+ margin: 0 0 24px;
238
+ font-size: 14px;
239
+ line-height: 1.8;
240
+ color: var(--el-text-color-primary);
241
+ }
242
+ .sub-tabs {
243
+ margin-bottom: 24px;
244
+ }
245
+ .install-section {
246
+ display: flex;
247
+ flex-direction: column;
248
+ gap: 16px;
249
+ }
250
+ .npm-header {
251
+ display: flex;
252
+ align-items: center;
253
+ justify-content: space-between;
254
+ gap: 12px;
255
+ }
256
+ .npm-title {
257
+ font-size: 14px;
258
+ font-weight: 600;
259
+ color: var(--el-text-color-primary);
260
+ }
261
+ .registry-select {
262
+ width: 160px;
263
+ }
264
+ .requirements-section {
265
+ display: flex;
266
+ flex-direction: column;
267
+ gap: 16px;
268
+ }
269
+ .requirement-item {
270
+ display: flex;
271
+ align-items: center;
272
+ gap: 8px;
273
+ padding: 8px 0;
274
+ }
275
+ .requirement-item .label {
276
+ font-size: 13px;
277
+ font-weight: 600;
278
+ color: var(--el-text-color-primary);
279
+ }
280
+ .requirement-item .value {
281
+ font-size: 13px;
282
+ color: var(--el-text-color-regular);
283
+ }
284
+ .model-switch-text {
285
+ margin: 0;
286
+ font-size: 13px;
287
+ line-height: 1.6;
288
+ color: var(--el-text-color-regular);
289
+ }
290
+ .tip-item {
291
+ padding: 8px 0;
292
+ }
293
+ .tip-text {
294
+ font-size: 13px;
295
+ line-height: 1.6;
296
+ color: var(--el-text-color-regular);
297
+ }
298
+ .method-item {
299
+ margin-top: 16px;
300
+ padding: 12px;
301
+ background: var(--el-fill-color-light);
302
+ border-radius: 4px;
303
+ }
304
+ .method-item h4 {
305
+ margin: 0 0 8px;
306
+ font-size: 14px;
307
+ font-weight: 600;
308
+ }
309
+ .method-item p {
310
+ margin: 0 0 8px;
311
+ font-size: 13px;
312
+ color: var(--el-text-color-regular);
313
+ }
314
+ </style>
@@ -0,0 +1,147 @@
1
+ <script setup>
2
+ import { computed } from 'vue'
3
+ import { RouterLink } from 'vue-router'
4
+ import { useI18n } from 'vue-i18n'
5
+ import PageHeader from '../components/PageHeader.vue'
6
+
7
+ const { t, tm } = useI18n()
8
+
9
+ const sections = computed(() => [
10
+ {
11
+ to: '/harness',
12
+ title: t('home.sections.harness.title'),
13
+ desc: t('home.sections.harness.desc'),
14
+ icon: '🔧',
15
+ },
16
+ {
17
+ to: '/free-models',
18
+ title: t('home.sections.freeModels.title'),
19
+ desc: t('home.sections.freeModels.desc'),
20
+ icon: '🎁',
21
+ },
22
+ {
23
+ to: '/proxy',
24
+ title: t('home.sections.proxy.title'),
25
+ desc: t('home.sections.proxy.desc'),
26
+ icon: '🌐',
27
+ },
28
+ ])
29
+ </script>
30
+
31
+ <template>
32
+ <div class="home">
33
+ <section class="hero-section">
34
+ <h1>{{ $t('home.heroTitle') }}</h1>
35
+ <p class="hero-subtitle">{{ $t('home.heroSubtitle') }}</p>
36
+ <div class="hero-actions">
37
+ <el-button type="primary" size="large" tag="a" @click="$router.push('/harness')">
38
+ {{ $t('home.startLearning') }}
39
+ </el-button>
40
+ <el-button size="large" @click="$router.push('/free-models')">
41
+ {{ $t('home.freeModelsBtn') }}
42
+ </el-button>
43
+ </div>
44
+ </section>
45
+
46
+ <section class="cards-section">
47
+ <h2 class="section-title">{{ $t('home.sectionsTitle') }}</h2>
48
+ <el-row :gutter="20">
49
+ <el-col v-for="s in sections" :key="s.to" :xs="24" :sm="8">
50
+ <el-card shadow="hover" class="card">
51
+ <RouterLink :to="s.to" class="card-link">
52
+ <div class="card-icon">{{ s.icon }}</div>
53
+ <h3 class="card-title">{{ s.title }}</h3>
54
+ <p class="card-desc">{{ s.desc }}</p>
55
+ <span class="card-enter">{{ $t('home.cardEnter') }} &rarr;</span>
56
+ </RouterLink>
57
+ </el-card>
58
+ </el-col>
59
+ </el-row>
60
+ </section>
61
+
62
+ <section class="intro-section">
63
+ <h2 class="section-title">{{ $t('home.whatIsHarness') }}</h2>
64
+ <el-card shadow="never">
65
+ <div class="intro-content">
66
+ <p>{{ $t('home.introP1') }}</p>
67
+ <p>{{ $t('home.introP2') }}</p>
68
+ <p>{{ $t('home.introP3') }}</p>
69
+ </div>
70
+ </el-card>
71
+ </section>
72
+ </div>
73
+ </template>
74
+
75
+ <style scoped>
76
+ .hero-section {
77
+ text-align: center;
78
+ padding: 48px 0 32px;
79
+ }
80
+ .hero-section h1 {
81
+ margin: 0 0 12px;
82
+ font-size: 48px;
83
+ font-weight: 700;
84
+ color: var(--el-text-color-primary);
85
+ }
86
+ .hero-subtitle {
87
+ font-size: 16px;
88
+ color: var(--el-text-color-secondary);
89
+ margin: 0 0 24px;
90
+ }
91
+ .hero-actions {
92
+ display: flex;
93
+ justify-content: center;
94
+ gap: 16px;
95
+ }
96
+ .cards-section {
97
+ margin: 32px 0;
98
+ }
99
+ .section-title {
100
+ font-size: 22px;
101
+ font-weight: 600;
102
+ color: var(--el-text-color-primary);
103
+ margin: 0 0 16px;
104
+ }
105
+ .card {
106
+ height: 100%;
107
+ transition: transform 0.2s;
108
+ }
109
+ .card:hover {
110
+ transform: translateY(-4px);
111
+ }
112
+ .card-link {
113
+ text-decoration: none;
114
+ display: block;
115
+ }
116
+ .card-icon {
117
+ font-size: 36px;
118
+ margin-bottom: 12px;
119
+ }
120
+ .card-title {
121
+ margin: 0 0 8px;
122
+ font-size: 18px;
123
+ font-weight: 600;
124
+ color: var(--el-text-color-primary);
125
+ }
126
+ .card-desc {
127
+ margin: 0 0 12px;
128
+ font-size: 14px;
129
+ line-height: 1.6;
130
+ color: var(--el-text-color-secondary);
131
+ }
132
+ .card-enter {
133
+ color: var(--el-color-primary);
134
+ font-size: 14px;
135
+ }
136
+ .intro-section {
137
+ margin: 32px 0;
138
+ }
139
+ .intro-content p {
140
+ margin: 0 0 12px;
141
+ line-height: 1.8;
142
+ color: var(--el-text-color-primary);
143
+ }
144
+ .intro-content p:last-child {
145
+ margin-bottom: 0;
146
+ }
147
+ </style>
@@ -0,0 +1,112 @@
1
+ <script setup>
2
+ import { ref, computed } from 'vue'
3
+ import { useI18n } from 'vue-i18n'
4
+ import { proxySolutions } from '../data/proxy/index.js'
5
+ import PageHeader from '../components/PageHeader.vue'
6
+ import CodeBlock from '../components/CodeBlock.vue'
7
+ import DetailBlock from '../components/DetailBlock.vue'
8
+ import StepList from '../components/StepList.vue'
9
+ import CheckList from '../components/CheckList.vue'
10
+
11
+ const { t, tm } = useI18n()
12
+
13
+ const activeId = ref(proxySolutions[0].id)
14
+ const activeSolution = ref(proxySolutions[0])
15
+ const activeSubTab = ref('steps')
16
+
17
+ const subTabs = computed(() => [
18
+ { id: 'steps', label: t('proxy.steps') },
19
+ { id: 'config', label: t('proxy.configExample') },
20
+ { id: 'notes', label: t('proxy.notes') },
21
+ ])
22
+
23
+ const stepsItems = computed(() => activeSolution.value.steps || [])
24
+ const tipsItems = computed(() => activeSolution.value.tips || [])
25
+
26
+ function selectSolution(s) {
27
+ activeId.value = s.id
28
+ activeSolution.value = s
29
+ activeSubTab.value = 'steps'
30
+ }
31
+ </script>
32
+
33
+ <template>
34
+ <div class="proxy-page">
35
+ <PageHeader
36
+ :title="$t('proxy.pageTitle')"
37
+ :description="$t('proxy.pageDesc')"
38
+ />
39
+
40
+ <el-tabs v-model="activeId" @tab-change="selectSolution(proxySolutions.find(s => s.id === activeId))">
41
+ <el-tab-pane
42
+ v-for="s in proxySolutions"
43
+ :key="s.id"
44
+ :name="s.id"
45
+ >
46
+ <template #label>
47
+ <span>{{ s.name }}</span>
48
+ </template>
49
+ </el-tab-pane>
50
+ </el-tabs>
51
+
52
+ <div v-if="activeSolution" class="solution-detail">
53
+ <div class="solution-header">
54
+ <h2 class="solution-name">{{ activeSolution.name }}</h2>
55
+ <el-tag type="warning">{{ activeSolution.badge }}</el-tag>
56
+ </div>
57
+ <p class="solution-tagline">{{ activeSolution.tagline }}</p>
58
+ <p class="solution-description">{{ activeSolution.description }}</p>
59
+
60
+ <el-tabs v-model="activeSubTab" class="sub-tabs">
61
+ <el-tab-pane :label="subTabs[0].label" name="steps">
62
+ <DetailBlock :title="$t('proxy.steps')">
63
+ <StepList :steps="stepsItems" small />
64
+ </DetailBlock>
65
+ </el-tab-pane>
66
+
67
+ <el-tab-pane :label="subTabs[1].label" name="config">
68
+ <DetailBlock :title="$t('proxy.configExample')">
69
+ <CodeBlock :code="activeSolution.config" lang="bash" />
70
+ </DetailBlock>
71
+ </el-tab-pane>
72
+
73
+ <el-tab-pane :label="subTabs[2].label" name="notes">
74
+ <DetailBlock :title="$t('proxy.notes')">
75
+ <CheckList :items="tipsItems" small />
76
+ </DetailBlock>
77
+ </el-tab-pane>
78
+ </el-tabs>
79
+ </div>
80
+ </div>
81
+ </template>
82
+
83
+ <style scoped>
84
+ .solution-detail {
85
+ margin-top: 16px;
86
+ }
87
+ .solution-header {
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 12px;
91
+ margin-bottom: 8px;
92
+ }
93
+ .solution-name {
94
+ margin: 0;
95
+ font-size: 22px;
96
+ font-weight: 600;
97
+ }
98
+ .solution-tagline {
99
+ margin: 0 0 8px;
100
+ font-size: 14px;
101
+ color: var(--el-text-color-secondary);
102
+ }
103
+ .solution-description {
104
+ margin: 0 0 24px;
105
+ font-size: 14px;
106
+ line-height: 1.8;
107
+ color: var(--el-text-color-primary);
108
+ }
109
+ .sub-tabs {
110
+ margin-bottom: 24px;
111
+ }
112
+ </style>
@@ -0,0 +1,26 @@
1
+ <script setup>
2
+ import { useI18n } from 'vue-i18n'
3
+
4
+ const { t } = useI18n()
5
+ </script>
6
+
7
+ <template>
8
+ <div class="token-market-page">
9
+ <el-empty :description="t('common.underConstruction')">
10
+ <template #image>
11
+ <el-icon :size="80" color="var(--el-text-color-secondary)">
12
+ <Tools />
13
+ </el-icon>
14
+ </template>
15
+ </el-empty>
16
+ </div>
17
+ </template>
18
+
19
+ <style scoped>
20
+ .token-market-page {
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ min-height: 400px;
25
+ }
26
+ </style>
@@ -0,0 +1,41 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import AutoImport from 'unplugin-auto-import/vite'
4
+ import Components from 'unplugin-vue-components/vite'
5
+ import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
6
+ import JSON5 from 'json5'
7
+
8
+ export default defineConfig({
9
+ plugins: [
10
+ vue(),
11
+ AutoImport({
12
+ resolvers: [ElementPlusResolver()],
13
+ }),
14
+ Components({
15
+ resolvers: [ElementPlusResolver()],
16
+ }),
17
+ // 支持 .json5 文件导入
18
+ {
19
+ name: 'json5-plugin',
20
+ transform(code, id) {
21
+ if (id.endsWith('.json5')) {
22
+ const data = JSON5.parse(code)
23
+ return {
24
+ code: `export default ${JSON.stringify(data)}`,
25
+ map: null,
26
+ }
27
+ }
28
+ },
29
+ },
30
+ ],
31
+ server: {
32
+ port: 7905,
33
+ host: "0.0.0.0",
34
+ proxy: {
35
+ '/api': {
36
+ target: 'http://localhost:5905',
37
+ changeOrigin: true
38
+ }
39
+ }
40
+ },
41
+ })