@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.
- package/LICENSE +21 -0
- package/README.md +96 -0
- package/cli/helpers/args.js +48 -0
- package/cli/index.js +374 -0
- package/cli/pid-manager.js +87 -0
- package/client/index.html +25 -0
- package/client/public/favicon.svg +1 -0
- package/client/public/icons.svg +24 -0
- package/client/src/App.vue +136 -0
- package/client/src/assets/vite.svg +1 -0
- package/client/src/assets/vue.svg +1 -0
- package/client/src/components/ChatBox.vue +320 -0
- package/client/src/components/CheckList.vue +52 -0
- package/client/src/components/CodeBlock.vue +99 -0
- package/client/src/components/DetailBlock.vue +47 -0
- package/client/src/components/HelloWorld.vue +95 -0
- package/client/src/components/LangSwitch.vue +32 -0
- package/client/src/components/LinkList.vue +32 -0
- package/client/src/components/OsSwitch.vue +42 -0
- package/client/src/components/OsToggle.vue +15 -0
- package/client/src/components/PageHeader.vue +31 -0
- package/client/src/components/StepList.vue +92 -0
- package/client/src/composables/useClipboard.js +26 -0
- package/client/src/composables/useOs.js +22 -0
- package/client/src/data/docs/agent.js +1002 -0
- package/client/src/data/docs/auth.js +631 -0
- package/client/src/data/docs/builtin-tools.js +322 -0
- package/client/src/data/docs/chat.js +181 -0
- package/client/src/data/docs/index.js +9 -0
- package/client/src/data/docs/skills.js +396 -0
- package/client/src/data/docs/spec-conversion.js +1042 -0
- package/client/src/data/freeModels/bluesliu.js +97 -0
- package/client/src/data/freeModels/index.js +11 -0
- package/client/src/data/freeModels/nvidia.js +126 -0
- package/client/src/data/freeModels/openrouter.js +116 -0
- package/client/src/data/harness/claude.js +89 -0
- package/client/src/data/harness/codex.js +66 -0
- package/client/src/data/harness/dsh.js +86 -0
- package/client/src/data/harness/hermes.js +56 -0
- package/client/src/data/harness/index.js +22 -0
- package/client/src/data/harness/opencode.js +77 -0
- package/client/src/data/proxy/api-relay.js +53 -0
- package/client/src/data/proxy/builtin-proxy.js +54 -0
- package/client/src/data/proxy/cf-workers.js +67 -0
- package/client/src/data/proxy/ecs-forward.js +75 -0
- package/client/src/data/proxy/ecs-reverse.js +89 -0
- package/client/src/data/proxy/index.js +15 -0
- package/client/src/docs/claudecode.md +44 -0
- package/client/src/docs/codex.md +90 -0
- package/client/src/docs/hermesagent.md +42 -0
- package/client/src/docs/opencode.md +103 -0
- package/client/src/locales/en.js +436 -0
- package/client/src/locales/index.js +31 -0
- package/client/src/locales/zh-CN.js +461 -0
- package/client/src/main.js +16 -0
- package/client/src/router/index.js +76 -0
- package/client/src/style.css +15 -0
- package/client/src/views/AdminModelsView.vue +214 -0
- package/client/src/views/DocsView.vue +1604 -0
- package/client/src/views/FreeModelsView.vue +518 -0
- package/client/src/views/HarnessView.vue +314 -0
- package/client/src/views/HomeView.vue +147 -0
- package/client/src/views/ProxyView.vue +112 -0
- package/client/src/views/TokenMarketView.vue +26 -0
- package/client/vite.config.js +41 -0
- package/package.json +85 -0
- package/scripts/build-zip.sh +61 -0
- package/scripts/postinstall.js +7 -0
- package/server/src/config/targets.json +1 -0
- package/server/src/index.js +52 -0
- package/server/src/lib/coding-test.js +215 -0
- package/server/src/lib/database.js +353 -0
- package/server/src/lib/run-test.js +15 -0
- package/server/src/lib/scheduler.js +21 -0
- package/server/src/lib/tester.js +310 -0
- package/server/src/routes/admin.js +48 -0
- package/server/src/routes/proxy.js +64 -0
- package/server/src/routes/speed.js +87 -0
- package/src/config.js +45 -0
- package/src/config.json5 +27 -0
- 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') }} →</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
|
+
})
|