mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
feat: 大规模性能优化 - Redis Pipeline 批量操作、索引系统、连接池优化
This commit is contained in:
495
web/admin-spa/src/components/tutorial/ClaudeCodeTutorial.vue
Normal file
495
web/admin-spa/src/components/tutorial/ClaudeCodeTutorial.vue
Normal file
@@ -0,0 +1,495 @@
|
||||
<template>
|
||||
<div class="tutorial-content">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<NodeInstallTutorial :platform="platform" :step-number="1" tool-name="Claude Code" />
|
||||
|
||||
<!-- 第二步:安装 Claude Code -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-green-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
>
|
||||
安装 Claude Code
|
||||
</h4>
|
||||
|
||||
<div
|
||||
class="mb-4 rounded-xl border border-green-100 bg-gradient-to-r from-green-50 to-emerald-50 p-4 dark:border-green-500/40 dark:from-green-950/30 dark:to-emerald-950/30 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-200 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-download mr-2 text-green-600" />
|
||||
安装 Claude Code
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
{{ platform === 'windows' ? '打开 PowerShell 或 CMD' : '打开终端' }},运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="mb-4 overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 sm:p-4 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 全局安装 Claude Code</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
{{
|
||||
platform === 'windows'
|
||||
? 'npm install -g @anthropic-ai/claude-code'
|
||||
: 'sudo npm install -g @anthropic-ai/claude-code'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
这个命令会从 npm 官方仓库下载并安装最新版本的 Claude Code。
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-500/40 dark:bg-blue-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-blue-800 dark:text-blue-300 sm:text-base">
|
||||
提示
|
||||
</h6>
|
||||
<ul class="space-y-1 text-xs text-blue-700 dark:text-blue-300 sm:text-sm">
|
||||
<template v-if="platform === 'windows'">
|
||||
<li>• 建议使用 PowerShell 而不是 CMD,功能更强大</li>
|
||||
<li>• 如果遇到权限问题,以管理员身份运行 PowerShell</li>
|
||||
</template>
|
||||
<template v-else-if="platform === 'macos'">
|
||||
<li>• 如果遇到权限问题,可以使用 sudo</li>
|
||||
<li>• 或者使用 nvm 安装的 Node.js 避免权限问题</li>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li>• 使用 nvm 安装的 Node.js 可以避免 sudo</li>
|
||||
<li>• WSL2 用户确保在 Linux 子系统中运行</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 验证安装 -->
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-green-50 p-3 dark:border-green-500/40 dark:bg-green-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">验证 Claude Code 安装</h6>
|
||||
<p class="mb-3 text-sm text-green-700 dark:text-green-300">
|
||||
安装完成后,输入以下命令检查是否安装成功:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">claude --version</div>
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-green-700 dark:text-green-300">
|
||||
如果显示版本号,恭喜你!Claude Code 已经成功安装了。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第三步:设置环境变量 -->
|
||||
<div class="mb-6 sm:mb-10">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-purple-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>3</span
|
||||
>
|
||||
设置环境变量
|
||||
</h4>
|
||||
|
||||
<div
|
||||
class="mb-4 rounded-xl border border-purple-100 bg-gradient-to-r from-purple-50 to-pink-50 p-4 dark:border-purple-500/40 dark:from-purple-950/30 dark:to-pink-950/30 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-200 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fas fa-cog mr-2 text-purple-600" />
|
||||
配置 Claude Code 环境变量
|
||||
</h5>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
为了让 Claude Code 连接到你的中转服务,需要设置两个环境变量:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Windows 环境变量设置 -->
|
||||
<template v-if="platform === 'windows'">
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
方法一:PowerShell 临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
在 PowerShell 中运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
$env:ANTHROPIC_BASE_URL = "{{ currentBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
$env:ANTHROPIC_AUTH_TOKEN = "你的API密钥"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-yellow-700 dark:text-yellow-400">
|
||||
💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
方法二:PowerShell 永久设置(用户级)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
在 PowerShell 中运行以下命令设置用户级环境变量:
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 设置用户级环境变量(永久生效)</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "{{
|
||||
currentBaseUrl
|
||||
}}", [System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_AUTH_TOKEN",
|
||||
"你的API密钥", [System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-blue-700 dark:text-blue-300">
|
||||
💡 设置后需要重新打开 PowerShell 窗口才能生效。
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- macOS / Linux 环境变量设置 -->
|
||||
<template v-else>
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
方法一:临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">在终端中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export ANTHROPIC_BASE_URL="{{ currentBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export ANTHROPIC_AUTH_TOKEN="你的API密钥"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-yellow-700 dark:text-yellow-400">
|
||||
💡 记得将 "你的API密钥" 替换为在上方 "API Keys" 标签页中创建的实际密钥。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-white p-3 dark:border-purple-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
方法二:永久设置(Shell 配置文件)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
将以下内容添加到你的 shell 配置文件中({{
|
||||
platform === 'macos' ? '~/.zshrc' : '~/.bashrc'
|
||||
}}):
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export ANTHROPIC_BASE_URL="{{ currentBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export ANTHROPIC_AUTH_TOKEN="你的API密钥"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">然后执行:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
source {{ platform === 'macos' ? '~/.zshrc' : '~/.bashrc' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VSCode 插件配置 -->
|
||||
<div
|
||||
class="mt-6 rounded-lg border border-indigo-200 bg-indigo-50 p-3 dark:border-indigo-500/40 dark:bg-indigo-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-indigo-800 dark:text-indigo-300">
|
||||
VSCode Claude 插件配置
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-indigo-700 dark:text-indigo-300">
|
||||
如果使用 VSCode 的 Claude 插件,需要在配置文件中进行设置:
|
||||
</p>
|
||||
<div class="mb-3 space-y-2">
|
||||
<p class="text-sm text-indigo-700 dark:text-indigo-300">
|
||||
<strong>配置文件位置:</strong>
|
||||
<code class="rounded bg-indigo-100 px-1 dark:bg-indigo-900">{{
|
||||
platform === 'windows'
|
||||
? 'C:\\Users\\你的用户名\\.claude\\config.json'
|
||||
: '~/.claude/config.json'
|
||||
}}</code>
|
||||
</p>
|
||||
<p class="text-xs text-indigo-600 dark:text-indigo-400">
|
||||
💡 如果该文件不存在,请手动创建。
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">{</div>
|
||||
<div class="whitespace-nowrap text-gray-300">"primaryApiKey": "crs"</div>
|
||||
<div class="whitespace-nowrap text-gray-300">}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 验证环境变量设置 -->
|
||||
<div
|
||||
class="mt-6 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-500/40 dark:bg-blue-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-blue-800 dark:text-blue-300">验证环境变量设置</h6>
|
||||
<p class="mb-3 text-sm text-blue-700 dark:text-blue-300">
|
||||
设置完环境变量后,可以通过以下命令验证是否设置成功:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
{{ platform === 'windows' ? '在 PowerShell 中验证:' : '在终端中验证:' }}
|
||||
</h6>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<template v-if="platform === 'windows'">
|
||||
<div class="whitespace-nowrap text-gray-300">echo $env:ANTHROPIC_BASE_URL</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $env:ANTHROPIC_AUTH_TOKEN</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $ANTHROPIC_BASE_URL</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $ANTHROPIC_AUTH_TOKEN</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 space-y-2">
|
||||
<p class="text-sm text-blue-700 dark:text-blue-300">
|
||||
<strong>预期输出示例:</strong>
|
||||
</p>
|
||||
<div class="rounded bg-gray-100 p-2 font-mono text-sm dark:bg-gray-700">
|
||||
<div>{{ currentBaseUrl }}</div>
|
||||
<div>cr_xxxxxxxxxxxxxxxxxx</div>
|
||||
</div>
|
||||
<p class="text-xs text-blue-700 dark:text-blue-300">
|
||||
💡 如果输出为空或显示变量名本身,说明环境变量设置失败,请重新设置。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 第四步:开始使用 -->
|
||||
<div class="mb-6 sm:mb-8">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-orange-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>4</span
|
||||
>
|
||||
开始使用 Claude Code
|
||||
</h4>
|
||||
<div
|
||||
class="rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-yellow-50 p-4 dark:border-orange-500/40 dark:from-orange-950/30 dark:to-yellow-950/30 sm:p-6"
|
||||
>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
现在你可以开始使用 Claude Code 了!
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
启动 Claude Code
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">claude</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
在特定项目中使用
|
||||
</h6>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 进入你的项目目录</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
cd
|
||||
{{
|
||||
platform === 'windows' ? 'C:\\path\\to\\your\\project' : '/path/to/your/project'
|
||||
}}
|
||||
</div>
|
||||
<div class="mb-2 mt-2"># 启动 Claude Code</div>
|
||||
<div class="whitespace-nowrap text-gray-300">claude</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 故障排除 -->
|
||||
<div class="mb-8">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<i class="fas fa-wrench mr-2 text-red-600 sm:mr-3" />
|
||||
{{ platformName }} 常见问题解决
|
||||
</h4>
|
||||
<div class="space-y-4">
|
||||
<details
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<summary
|
||||
class="cursor-pointer p-3 text-sm font-medium text-gray-800 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4 sm:text-base"
|
||||
>
|
||||
安装时提示 "permission denied" 错误
|
||||
</summary>
|
||||
<div class="px-3 pb-3 text-gray-600 dark:text-gray-400 sm:px-4 sm:pb-4">
|
||||
<p class="mb-2">这通常是权限问题,尝试以下解决方法:</p>
|
||||
<ul class="list-inside list-disc space-y-1 text-sm">
|
||||
<template v-if="platform === 'windows'">
|
||||
<li>以管理员身份运行 PowerShell</li>
|
||||
<li>
|
||||
或者配置 npm 使用用户目录:<code
|
||||
class="rounded bg-gray-200 px-1 text-xs dark:bg-gray-700 sm:text-sm"
|
||||
>npm config set prefix %APPDATA%\npm</code
|
||||
>
|
||||
</li>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li>使用 sudo 运行安装命令</li>
|
||||
<li>或者使用 nvm 安装 Node.js 避免权限问题</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details
|
||||
v-if="platform === 'windows'"
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<summary
|
||||
class="cursor-pointer p-3 text-sm font-medium text-gray-800 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4 sm:text-base"
|
||||
>
|
||||
PowerShell 执行策略错误
|
||||
</summary>
|
||||
<div class="px-3 pb-3 text-gray-600 dark:text-gray-400 sm:px-4 sm:pb-4">
|
||||
<p class="mb-2">如果遇到执行策略限制,运行:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<summary
|
||||
class="cursor-pointer p-3 text-sm font-medium text-gray-800 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4 sm:text-base"
|
||||
>
|
||||
环境变量设置后不生效
|
||||
</summary>
|
||||
<div class="px-3 pb-3 text-gray-600 dark:text-gray-400 sm:px-4 sm:pb-4">
|
||||
<p class="mb-2">设置永久环境变量后需要:</p>
|
||||
<ul class="list-inside list-disc space-y-1 text-sm">
|
||||
<template v-if="platform === 'windows'">
|
||||
<li>重新启动 PowerShell 或 CMD</li>
|
||||
<li>或者注销并重新登录 Windows</li>
|
||||
<li>
|
||||
验证设置:<code
|
||||
class="rounded bg-gray-200 px-1 text-xs dark:bg-gray-700 sm:text-sm"
|
||||
>echo $env:ANTHROPIC_BASE_URL</code
|
||||
>
|
||||
</li>
|
||||
</template>
|
||||
<template v-else>
|
||||
<li>重新打开终端窗口</li>
|
||||
<li>
|
||||
或者执行
|
||||
<code class="rounded bg-gray-200 px-1 text-xs dark:bg-gray-700 sm:text-sm"
|
||||
>source {{ platform === 'macos' ? '~/.zshrc' : '~/.bashrc' }}</code
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
验证设置:<code
|
||||
class="rounded bg-gray-200 px-1 text-xs dark:bg-gray-700 sm:text-sm"
|
||||
>echo $ANTHROPIC_BASE_URL</code
|
||||
>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details
|
||||
v-if="platform === 'linux'"
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<summary
|
||||
class="cursor-pointer p-3 text-sm font-medium text-gray-800 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700 sm:p-4 sm:text-base"
|
||||
>
|
||||
WSL2 中无法访问 Windows 文件
|
||||
</summary>
|
||||
<div class="px-3 pb-3 text-gray-600 dark:text-gray-400 sm:px-4 sm:pb-4">
|
||||
<p class="mb-2">WSL2 可以通过 /mnt/ 路径访问 Windows 文件:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">cd /mnt/c/Users/你的用户名/项目目录</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useTutorialUrls } from '@/composables/useTutorialUrls'
|
||||
import NodeInstallTutorial from './NodeInstallTutorial.vue'
|
||||
|
||||
const props = defineProps({
|
||||
platform: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['windows', 'macos', 'linux'].includes(value)
|
||||
}
|
||||
})
|
||||
|
||||
const { currentBaseUrl } = useTutorialUrls()
|
||||
|
||||
const platformName = computed(() => {
|
||||
const names = { windows: 'Windows', macos: 'macOS', linux: 'Linux / WSL2' }
|
||||
return names[props.platform]
|
||||
})
|
||||
</script>
|
||||
354
web/admin-spa/src/components/tutorial/CodexTutorial.vue
Normal file
354
web/admin-spa/src/components/tutorial/CodexTutorial.vue
Normal file
@@ -0,0 +1,354 @@
|
||||
<template>
|
||||
<div class="tutorial-section">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<NodeInstallTutorial :platform="platform" :step-number="1" tool-name="Codex" />
|
||||
|
||||
<!-- 第二步:配置 Codex -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-indigo-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
>
|
||||
配置 Codex
|
||||
</h4>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
配置 Codex 以连接到中转服务:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- config.toml 配置 -->
|
||||
<div
|
||||
class="rounded-lg border border-yellow-200 bg-yellow-50 p-3 dark:border-yellow-500/40 dark:bg-yellow-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-yellow-800 dark:text-yellow-300">
|
||||
1. 配置文件 config.toml
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-yellow-700 dark:text-yellow-300">
|
||||
在
|
||||
<code class="rounded bg-yellow-100 px-1 dark:bg-yellow-900">{{ configPath }}</code>
|
||||
文件开头添加以下配置:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div
|
||||
v-for="line in configTomlLines"
|
||||
:key="line"
|
||||
class="whitespace-nowrap text-gray-300"
|
||||
:class="{ 'mt-2': line === '' }"
|
||||
>
|
||||
{{ line || ' ' }}
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 text-sm text-yellow-600 dark:text-yellow-400">一键写入命令:</p>
|
||||
<div
|
||||
class="mt-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">{{ configTomlWriteCmd }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- auth.json 配置 -->
|
||||
<div
|
||||
class="rounded-lg border border-orange-200 bg-orange-50 p-3 dark:border-orange-500/40 dark:bg-orange-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-orange-800 dark:text-orange-300">
|
||||
2. 认证文件 auth.json
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-orange-700 dark:text-orange-300">
|
||||
在
|
||||
<code class="rounded bg-orange-100 px-1 dark:bg-orange-900">{{ authPath }}</code>
|
||||
文件中配置:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">{</div>
|
||||
<div class="whitespace-nowrap text-gray-300"> "OPENAI_API_KEY": null</div>
|
||||
<div class="whitespace-nowrap text-gray-300">}</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-3 rounded border border-red-200 bg-red-50 p-2 dark:border-red-500/40 dark:bg-red-950/30"
|
||||
>
|
||||
<p class="text-sm font-semibold text-red-700 dark:text-red-300">
|
||||
⚠️ 必须将 OPENAI_API_KEY 设置为 null,否则 Codex 会优先使用它而忽略环境变量!
|
||||
</p>
|
||||
</div>
|
||||
<p class="mt-3 text-sm text-orange-600 dark:text-orange-400">一键写入命令:</p>
|
||||
<div
|
||||
class="mt-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">{{ authJsonWriteCmd }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 环境变量配置 -->
|
||||
<div
|
||||
class="rounded-lg border border-purple-200 bg-purple-50 p-3 dark:border-purple-500/40 dark:bg-purple-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-purple-800 dark:text-purple-300">
|
||||
3. 设置环境变量 CRS_OAI_KEY
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-purple-700 dark:text-purple-300">
|
||||
设置环境变量 CRS_OAI_KEY 为您的 API 密钥(格式如 cr_xxxxxxxxxx):
|
||||
</p>
|
||||
|
||||
<!-- Windows -->
|
||||
<template v-if="platform === 'windows'">
|
||||
<p class="mb-1 text-sm text-purple-600 dark:text-purple-400">
|
||||
系统级环境变量(推荐):
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("CRS_OAI_KEY", "cr_xxxxxxxxxx",
|
||||
[System.EnvironmentVariableTarget]::Machine)
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-1 text-sm text-purple-600 line-through opacity-60 dark:text-purple-400">
|
||||
用户级环境变量
|
||||
<span class="text-xs text-red-500">(不推荐)</span>
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 opacity-60 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300 line-through">
|
||||
[System.Environment]::SetEnvironmentVariable("CRS_OAI_KEY", "cr_xxxxxxxxxx",
|
||||
[System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-purple-600 dark:text-purple-400">
|
||||
💡 设置后需要重新打开终端窗口才能生效
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!-- macOS / Linux -->
|
||||
<template v-else>
|
||||
<p class="mb-1 text-sm text-purple-600 dark:text-purple-400">
|
||||
检查当前 shell:<code class="rounded bg-purple-100 px-1 dark:bg-purple-900"
|
||||
>echo $SHELL</code
|
||||
>
|
||||
</p>
|
||||
|
||||
<!-- 检查旧配置 -->
|
||||
<details
|
||||
class="my-3 rounded-lg border border-blue-200 bg-blue-50 dark:border-blue-500/40 dark:bg-blue-950/30"
|
||||
>
|
||||
<summary
|
||||
class="cursor-pointer p-2 text-sm font-medium text-blue-800 dark:text-blue-300"
|
||||
>
|
||||
检查是否已有旧配置
|
||||
</summary>
|
||||
<div class="px-3 pb-3">
|
||||
<p class="mb-2 text-sm text-blue-700 dark:text-blue-300">
|
||||
如果之前配置过,建议先检查并清理旧配置:
|
||||
</p>
|
||||
<div
|
||||
class="mb-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="text-gray-500"># zsh</div>
|
||||
<div class="whitespace-nowrap text-gray-300">grep 'CRS_OAI_KEY' ~/.zshrc</div>
|
||||
<div class="mt-1 text-gray-500"># bash</div>
|
||||
<div class="whitespace-nowrap text-gray-300">grep 'CRS_OAI_KEY' ~/.bashrc</div>
|
||||
</div>
|
||||
<p class="text-sm text-blue-600 dark:text-blue-400">
|
||||
如果有输出,说明已配置过,可以手动编辑文件修改或删除旧配置
|
||||
</p>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<p class="mb-1 mt-2 text-sm text-purple-600 dark:text-purple-400">
|
||||
{{ platform === 'macos' ? 'zsh (macOS 默认)' : 'bash (Linux 默认)' }}:
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
echo 'export CRS_OAI_KEY="cr_xxxxxxxxxx"' >>
|
||||
{{
|
||||
platform === 'macos'
|
||||
? '~/.zshrc && source ~/.zshrc'
|
||||
: '~/.bashrc && source ~/.bashrc'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mb-1 text-sm text-purple-600 dark:text-purple-400">
|
||||
{{ platform === 'macos' ? 'bash' : 'zsh' }}:
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
echo 'export CRS_OAI_KEY="cr_xxxxxxxxxx"' >>
|
||||
{{
|
||||
platform === 'macos'
|
||||
? '~/.bashrc && source ~/.bashrc'
|
||||
: '~/.zshrc && source ~/.zshrc'
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-purple-600 dark:text-purple-400">
|
||||
💡 设置后需要重新打开终端窗口或执行 source 命令才能生效
|
||||
</p>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 验证环境变量 -->
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-green-50 p-3 dark:border-green-500/40 dark:bg-green-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">4. 验证环境变量</h6>
|
||||
<p class="mb-2 text-sm text-green-700 dark:text-green-300">
|
||||
重新打开终端后,验证环境变量是否设置成功:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div v-if="platform === 'windows'" class="whitespace-nowrap text-gray-300">
|
||||
Get-ChildItem Env:CRS_OAI_KEY
|
||||
</div>
|
||||
<div v-else class="whitespace-nowrap text-gray-300">
|
||||
echo "CRS_OAI_KEY: $CRS_OAI_KEY"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除环境变量 -->
|
||||
<details
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800"
|
||||
>
|
||||
<summary class="cursor-pointer p-3 text-sm font-medium text-gray-800 dark:text-gray-300">
|
||||
如何删除环境变量
|
||||
</summary>
|
||||
<div class="px-3 pb-3">
|
||||
<template v-if="platform === 'windows'">
|
||||
<p class="mb-1 text-sm text-gray-600 dark:text-gray-400">删除用户级环境变量:</p>
|
||||
<div
|
||||
class="mb-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("CRS_OAI_KEY", $null,
|
||||
[System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-1 text-sm text-gray-600 dark:text-gray-400">删除系统级环境变量:</p>
|
||||
<div
|
||||
class="mb-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("CRS_OAI_KEY", $null,
|
||||
[System.EnvironmentVariableTarget]::Machine)
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="mb-1 text-sm text-gray-600 dark:text-gray-400">从 zsh 配置中删除:</p>
|
||||
<div
|
||||
class="mb-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="text-gray-500"># 删除包含 CRS_OAI_KEY 的行</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
sed -i '' '/CRS_OAI_KEY/d' ~/.zshrc && source ~/.zshrc
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-1 text-sm text-gray-600 dark:text-gray-400">从 bash 配置中删除:</p>
|
||||
<div
|
||||
class="mb-2 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="text-gray-500"># 删除包含 CRS_OAI_KEY 的行</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
sed -i '' '/CRS_OAI_KEY/d' ~/.bashrc && source ~/.bashrc
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<p class="mb-1 text-sm text-gray-600 dark:text-gray-400">验证是否删除成功:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div v-if="platform === 'windows'" class="whitespace-nowrap text-gray-300">
|
||||
Get-ChildItem Env:CRS_OAI_KEY
|
||||
</div>
|
||||
<div v-else class="whitespace-nowrap text-gray-300">
|
||||
echo "CRS_OAI_KEY: $CRS_OAI_KEY"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- 提示 -->
|
||||
<div
|
||||
class="rounded-lg border border-yellow-200 bg-yellow-50 p-3 dark:border-yellow-500/40 dark:bg-yellow-950/30 sm:p-4"
|
||||
>
|
||||
<p class="text-sm text-yellow-700 dark:text-yellow-300">
|
||||
💡 请将示例中的
|
||||
<code class="rounded bg-yellow-100 px-1 dark:bg-yellow-900">cr_xxxxxxxxxx</code>
|
||||
替换为您的实际 API 密钥
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useTutorialUrls } from '@/composables/useTutorialUrls'
|
||||
import NodeInstallTutorial from './NodeInstallTutorial.vue'
|
||||
|
||||
const props = defineProps({
|
||||
platform: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['windows', 'macos', 'linux'].includes(value)
|
||||
}
|
||||
})
|
||||
|
||||
const { openaiBaseUrl } = useTutorialUrls()
|
||||
|
||||
const configPath = computed(() =>
|
||||
props.platform === 'windows' ? '%USERPROFILE%\\.codex\\config.toml' : '~/.codex/config.toml'
|
||||
)
|
||||
|
||||
const authPath = computed(() =>
|
||||
props.platform === 'windows' ? '%USERPROFILE%\\.codex\\auth.json' : '~/.codex/auth.json'
|
||||
)
|
||||
|
||||
const configTomlLines = computed(() => [
|
||||
'model_provider = "crs"',
|
||||
'model = "gpt-5-codex"',
|
||||
'model_reasoning_effort = "high"',
|
||||
'disable_response_storage = true',
|
||||
'preferred_auth_method = "apikey"',
|
||||
'',
|
||||
'[model_providers.crs]',
|
||||
'name = "crs"',
|
||||
`base_url = "${openaiBaseUrl.value}"`,
|
||||
'wire_api = "responses"',
|
||||
'requires_openai_auth = true',
|
||||
'env_key = "CRS_OAI_KEY"'
|
||||
])
|
||||
|
||||
const configTomlContent = computed(() => configTomlLines.value.join('\n'))
|
||||
|
||||
const configTomlWriteCmd = computed(() => {
|
||||
if (props.platform === 'windows') {
|
||||
const escaped = configTomlContent.value.replace(/"/g, '`"').replace(/\n/g, '`n')
|
||||
return `New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.codex" | Out-Null; "${escaped}" | Set-Content -Path "$env:USERPROFILE\\.codex\\config.toml" -Force`
|
||||
}
|
||||
const escaped = configTomlContent.value.replace(/\n/g, '\\n')
|
||||
return `mkdir -p ~/.codex && printf '${escaped}\\n' > ~/.codex/config.toml`
|
||||
})
|
||||
|
||||
const authJsonWriteCmd = computed(() => {
|
||||
if (props.platform === 'windows') {
|
||||
return `New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.codex" | Out-Null; '{"OPENAI_API_KEY": null}' | Set-Content -Path "$env:USERPROFILE\\.codex\\auth.json" -Force`
|
||||
}
|
||||
return `mkdir -p ~/.codex && echo '{"OPENAI_API_KEY": null}' > ~/.codex/auth.json`
|
||||
})
|
||||
</script>
|
||||
98
web/admin-spa/src/components/tutorial/DroidCliTutorial.vue
Normal file
98
web/admin-spa/src/components/tutorial/DroidCliTutorial.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="tutorial-section">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<NodeInstallTutorial :platform="platform" :step-number="1" tool-name="Droid CLI" />
|
||||
|
||||
<!-- 第二步:配置 Droid CLI -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
>
|
||||
配置 Droid CLI
|
||||
</h4>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
Droid CLI 使用
|
||||
<code class="rounded bg-gray-100 px-1 dark:bg-gray-800">~/.factory/config.json</code>
|
||||
保存自定义模型;
|
||||
<template v-if="platform === 'windows'">
|
||||
在 Windows 中可直接编辑
|
||||
<code class="rounded bg-gray-100 px-1 dark:bg-gray-800"
|
||||
>C:\Users\你的用户名\.factory\config.json</code
|
||||
>。
|
||||
</template>
|
||||
<template v-else>
|
||||
在终端中可使用
|
||||
<code class="rounded bg-gray-100 px-1 dark:bg-gray-800">vim ~/.factory/config.json</code>
|
||||
编辑。
|
||||
</template>
|
||||
</p>
|
||||
<div
|
||||
class="rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-500/40 dark:bg-blue-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-blue-800 dark:text-blue-200 sm:text-base">
|
||||
配置文件示例
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-blue-700 dark:text-blue-200">
|
||||
将以下内容追加到配置文件中,并替换示例中的域名和 API 密钥:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div
|
||||
v-for="(line, index) in droidCliConfigLines"
|
||||
:key="line + index"
|
||||
class="whitespace-pre text-gray-300"
|
||||
>
|
||||
{{ line }}
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-3 text-xs text-blue-700 dark:text-blue-200 sm:text-sm">
|
||||
💡 在 Droid CLI 中选择自定义模型即可使用新的 Droid 账号池;确保服务地址可被本地访问。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useTutorialUrls } from '@/composables/useTutorialUrls'
|
||||
import NodeInstallTutorial from './NodeInstallTutorial.vue'
|
||||
|
||||
defineProps({
|
||||
platform: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['windows', 'macos', 'linux'].includes(value)
|
||||
}
|
||||
})
|
||||
|
||||
const { droidClaudeBaseUrl, droidOpenaiBaseUrl } = useTutorialUrls()
|
||||
|
||||
const droidCliConfigLines = computed(() => [
|
||||
'{',
|
||||
' "custom_models": [',
|
||||
' {',
|
||||
' "model_display_name": "Sonnet 4.5 [crs]",',
|
||||
' "model": "claude-sonnet-4-5-20250929",',
|
||||
` "base_url": "${droidClaudeBaseUrl.value}",`,
|
||||
' "api_key": "你的API密钥",',
|
||||
' "provider": "anthropic",',
|
||||
' "max_tokens": 8192',
|
||||
' },',
|
||||
' {',
|
||||
' "model_display_name": "GPT5-Codex [crs]",',
|
||||
' "model": "gpt-5-codex",',
|
||||
` "base_url": "${droidOpenaiBaseUrl.value}",`,
|
||||
' "api_key": "你的API密钥",',
|
||||
' "provider": "openai",',
|
||||
' "max_tokens": 16384',
|
||||
' }',
|
||||
' ]',
|
||||
'}'
|
||||
])
|
||||
</script>
|
||||
183
web/admin-spa/src/components/tutorial/GeminiCliTutorial.vue
Normal file
183
web/admin-spa/src/components/tutorial/GeminiCliTutorial.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="tutorial-section">
|
||||
<!-- 第一步:安装 Node.js -->
|
||||
<NodeInstallTutorial :platform="platform" :step-number="1" tool-name="Gemini CLI" />
|
||||
|
||||
<!-- 第二步:配置环境变量 -->
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-green-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>2</span
|
||||
>
|
||||
配置 Gemini CLI 环境变量
|
||||
</h4>
|
||||
<p class="mb-3 text-sm text-gray-700 dark:text-gray-300 sm:mb-4 sm:text-base">
|
||||
设置以下环境变量以连接到中转服务:
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Windows -->
|
||||
<template v-if="platform === 'windows'">
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-white p-3 dark:border-green-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
PowerShell 设置方法
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
在 PowerShell 中运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
$env:GOOGLE_GEMINI_BASE_URL = "{{ geminiBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">$env:GEMINI_API_KEY = "你的API密钥"</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
$env:GEMINI_MODEL = "gemini-2.5-pro"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-yellow-700 dark:text-yellow-400">
|
||||
💡 使用与 Claude Code 相同的 API 密钥即可。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-white p-3 dark:border-green-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
PowerShell 永久设置(用户级)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
在 PowerShell 中运行以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 设置用户级环境变量(永久生效)</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("GOOGLE_GEMINI_BASE_URL", "{{
|
||||
geminiBaseUrl
|
||||
}}", [System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("GEMINI_API_KEY", "你的API密钥",
|
||||
[System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
[System.Environment]::SetEnvironmentVariable("GEMINI_MODEL", "gemini-2.5-pro",
|
||||
[System.EnvironmentVariableTarget]::User)
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-blue-700 dark:text-blue-300">
|
||||
💡 设置后需要重新打开 PowerShell 窗口才能生效。
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- macOS / Linux -->
|
||||
<template v-else>
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-white p-3 dark:border-green-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
临时设置(当前会话)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">在终端中运行以下命令:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export GOOGLE_GEMINI_BASE_URL="{{ geminiBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">export GEMINI_API_KEY="你的API密钥"</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export GEMINI_MODEL="gemini-2.5-pro"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-yellow-700 dark:text-yellow-400">
|
||||
💡 使用与 Claude Code 相同的 API 密钥即可。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-white p-3 dark:border-green-700 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
永久设置(Shell 配置文件)
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">
|
||||
将以下内容添加到你的 shell 配置文件中({{
|
||||
platform === 'macos' ? '~/.zshrc' : '~/.bashrc'
|
||||
}}):
|
||||
</p>
|
||||
<div
|
||||
class="mb-3 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export GOOGLE_GEMINI_BASE_URL="{{ geminiBaseUrl }}"
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">export GEMINI_API_KEY="你的API密钥"</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
export GEMINI_MODEL="gemini-2.5-pro"
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-3 text-sm text-gray-600 dark:text-gray-400">然后执行:</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
source {{ platform === 'macos' ? '~/.zshrc' : '~/.bashrc' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 验证 -->
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-green-50 p-3 dark:border-green-500/40 dark:bg-green-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 font-medium text-green-800 dark:text-green-300">
|
||||
验证 Gemini CLI 环境变量
|
||||
</h6>
|
||||
<p class="mb-3 text-sm text-green-700 dark:text-green-300">
|
||||
{{ platform === 'windows' ? '在 PowerShell 中验证:' : '在终端中验证:' }}
|
||||
</p>
|
||||
<div
|
||||
class="space-y-1 overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<template v-if="platform === 'windows'">
|
||||
<div class="whitespace-nowrap text-gray-300">echo $env:GOOGLE_GEMINI_BASE_URL</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $env:GEMINI_API_KEY</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $env:GEMINI_MODEL</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $GOOGLE_GEMINI_BASE_URL</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $GEMINI_API_KEY</div>
|
||||
<div class="whitespace-nowrap text-gray-300">echo $GEMINI_MODEL</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useTutorialUrls } from '@/composables/useTutorialUrls'
|
||||
import NodeInstallTutorial from './NodeInstallTutorial.vue'
|
||||
|
||||
defineProps({
|
||||
platform: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['windows', 'macos', 'linux'].includes(value)
|
||||
}
|
||||
})
|
||||
|
||||
const { geminiBaseUrl } = useTutorialUrls()
|
||||
</script>
|
||||
234
web/admin-spa/src/components/tutorial/NodeInstallTutorial.vue
Normal file
234
web/admin-spa/src/components/tutorial/NodeInstallTutorial.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div class="mb-4 sm:mb-10 sm:mb-6">
|
||||
<h4
|
||||
class="mb-3 flex items-center text-lg font-semibold text-gray-800 dark:text-gray-300 sm:mb-4 sm:text-xl"
|
||||
>
|
||||
<span
|
||||
class="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-500 text-xs font-bold text-white sm:mr-3 sm:h-8 sm:w-8 sm:text-sm"
|
||||
>{{ stepNumber }}</span
|
||||
>
|
||||
安装 Node.js 环境
|
||||
</h4>
|
||||
<p class="mb-4 text-sm text-gray-600 dark:text-gray-400 sm:mb-4 sm:mb-6 sm:text-base">
|
||||
{{ toolName }} 需要 Node.js 环境才能运行。
|
||||
</p>
|
||||
|
||||
<!-- Windows -->
|
||||
<div v-if="platform === 'windows'" class="node-install-section">
|
||||
<div
|
||||
class="mb-4 rounded-xl border border-blue-100 bg-gradient-to-r from-blue-50 to-indigo-50 p-4 dark:border-blue-500/40 dark:from-blue-950/30 dark:to-indigo-950/30 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-200 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-windows mr-2 text-blue-600" />
|
||||
Windows 安装方法
|
||||
</h5>
|
||||
<div class="mb-3 sm:mb-4">
|
||||
<p class="mb-2 text-sm text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-base">
|
||||
方法一:官网下载(推荐)
|
||||
</p>
|
||||
<ol
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 dark:text-gray-400 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
>
|
||||
<li>
|
||||
打开浏览器访问
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-800 dark:text-yellow-400 sm:px-2 sm:text-sm"
|
||||
>https://nodejs.org/</code
|
||||
>
|
||||
</li>
|
||||
<li>点击 "LTS" 版本进行下载(推荐长期支持版本)</li>
|
||||
<li>
|
||||
下载完成后双击
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-800 dark:text-yellow-400 sm:px-2 sm:text-sm"
|
||||
>.msi</code
|
||||
>
|
||||
文件
|
||||
</li>
|
||||
<li>按照安装向导完成安装,保持默认设置即可</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="mb-3 sm:mb-4">
|
||||
<p class="mb-2 text-sm text-gray-700 dark:text-gray-300 sm:mb-3 sm:text-base">
|
||||
方法二:使用包管理器
|
||||
</p>
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
如果你安装了 Chocolatey 或 Scoop,可以使用命令行安装:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 dark:border dark:border-slate-700 dark:bg-slate-900 sm:p-4 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 使用 Chocolatey</div>
|
||||
<div class="whitespace-nowrap text-gray-300">choco install nodejs</div>
|
||||
<div class="mb-2 mt-3"># 或使用 Scoop</div>
|
||||
<div class="whitespace-nowrap text-gray-300">scoop install nodejs</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-500/40 dark:bg-blue-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-blue-800 dark:text-blue-300 sm:text-base">
|
||||
Windows 注意事项
|
||||
</h6>
|
||||
<ul class="space-y-1 text-xs text-blue-700 dark:text-blue-300 sm:text-sm">
|
||||
<li>• 建议使用 PowerShell 而不是 CMD</li>
|
||||
<li>• 如果遇到权限问题,尝试以管理员身份运行</li>
|
||||
<li>• 某些杀毒软件可能会误报,需要添加白名单</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<VerifyInstall terminal="PowerShell 或 CMD" />
|
||||
</div>
|
||||
|
||||
<!-- macOS -->
|
||||
<div v-else-if="platform === 'macos'" class="node-install-section">
|
||||
<div
|
||||
class="mb-4 rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4 dark:border-gray-700 dark:from-gray-800 dark:to-slate-800 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-200 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-apple mr-2 text-gray-700 dark:text-gray-400" />
|
||||
macOS 安装方法
|
||||
</h5>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700 dark:text-gray-300">方法一:使用 Homebrew(推荐)</p>
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
如果你已经安装了 Homebrew,使用它安装 Node.js 会更方便:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 dark:border dark:border-slate-700 dark:bg-slate-900 sm:p-4 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 更新 Homebrew</div>
|
||||
<div class="whitespace-nowrap text-gray-300">brew update</div>
|
||||
<div class="mb-2 mt-3"># 安装 Node.js</div>
|
||||
<div class="whitespace-nowrap text-gray-300">brew install node</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700 dark:text-gray-300">方法二:官网下载</p>
|
||||
<ol
|
||||
class="ml-2 list-inside list-decimal space-y-1 text-xs text-gray-600 dark:text-gray-400 sm:ml-4 sm:space-y-2 sm:text-sm"
|
||||
>
|
||||
<li>
|
||||
访问
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>https://nodejs.org/</code
|
||||
>
|
||||
</li>
|
||||
<li>下载适合 macOS 的 LTS 版本</li>
|
||||
<li>
|
||||
打开下载的
|
||||
<code
|
||||
class="rounded bg-gray-100 px-1 py-1 text-xs dark:bg-gray-700 sm:px-2 sm:text-sm"
|
||||
>.pkg</code
|
||||
>
|
||||
文件
|
||||
</li>
|
||||
<li>按照安装程序指引完成安装</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-lg border border-gray-200 bg-gray-50 p-3 dark:border-gray-600 dark:bg-gray-800 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-gray-800 dark:text-gray-300 sm:text-base">
|
||||
macOS 注意事项
|
||||
</h6>
|
||||
<ul class="space-y-1 text-xs text-gray-700 dark:text-gray-300 sm:text-sm">
|
||||
<li>
|
||||
• 如果遇到权限问题,可能需要使用
|
||||
<code class="rounded bg-gray-200 px-1 text-xs dark:bg-gray-700 sm:text-sm">sudo</code>
|
||||
</li>
|
||||
<li>• 首次运行可能需要在系统偏好设置中允许</li>
|
||||
<li>• 建议使用 Terminal 或 iTerm2</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<VerifyInstall terminal="Terminal" />
|
||||
</div>
|
||||
|
||||
<!-- Linux -->
|
||||
<div v-else class="node-install-section">
|
||||
<div
|
||||
class="mb-4 rounded-xl border border-orange-100 bg-gradient-to-r from-orange-50 to-amber-50 p-4 dark:border-orange-500/40 dark:from-orange-950/30 dark:to-amber-950/30 sm:mb-6 sm:p-6"
|
||||
>
|
||||
<h5
|
||||
class="mb-2 flex items-center text-base font-semibold text-gray-800 dark:text-gray-200 sm:mb-3 sm:text-lg"
|
||||
>
|
||||
<i class="fab fa-linux mr-2 text-orange-600" />
|
||||
Linux / WSL2 安装方法
|
||||
</h5>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700 dark:text-gray-300">方法一:使用 nvm(推荐)</p>
|
||||
<p class="mb-2 text-xs text-gray-600 dark:text-gray-400 sm:text-sm">
|
||||
nvm 可以方便地管理多个 Node.js 版本:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 dark:border dark:border-slate-700 dark:bg-slate-900 sm:p-4 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># 安装 nvm</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||||
</div>
|
||||
<div class="mb-2 mt-3"># 重新加载 shell 配置</div>
|
||||
<div class="whitespace-nowrap text-gray-300">source ~/.bashrc</div>
|
||||
<div class="mb-2 mt-3"># 安装最新 LTS 版本</div>
|
||||
<div class="whitespace-nowrap text-gray-300">nvm install --lts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<p class="mb-3 text-gray-700 dark:text-gray-300">方法二:使用包管理器</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded-lg bg-gray-900 p-3 font-mono text-xs text-green-400 dark:border dark:border-slate-700 dark:bg-slate-900 sm:p-4 sm:text-sm"
|
||||
>
|
||||
<div class="mb-2"># Ubuntu/Debian</div>
|
||||
<div class="whitespace-nowrap text-gray-300">
|
||||
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
|
||||
</div>
|
||||
<div class="whitespace-nowrap text-gray-300">sudo apt-get install -y nodejs</div>
|
||||
<div class="mb-2 mt-3"># Fedora</div>
|
||||
<div class="whitespace-nowrap text-gray-300">sudo dnf install nodejs</div>
|
||||
<div class="mb-2 mt-3"># Arch Linux</div>
|
||||
<div class="whitespace-nowrap text-gray-300">sudo pacman -S nodejs npm</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="rounded-lg border border-orange-200 bg-orange-50 p-3 dark:border-orange-500/40 dark:bg-orange-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-orange-800 dark:text-orange-300 sm:text-base">
|
||||
Linux / WSL2 注意事项
|
||||
</h6>
|
||||
<ul class="space-y-1 text-xs text-orange-700 dark:text-orange-300 sm:text-sm">
|
||||
<li>• WSL2 用户建议在 Linux 子系统中安装,而不是 Windows</li>
|
||||
<li>• 使用 nvm 可以避免权限问题</li>
|
||||
<li>• 确保 shell 配置文件正确加载了 nvm</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<VerifyInstall terminal="终端" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import VerifyInstall from './VerifyInstall.vue'
|
||||
|
||||
defineProps({
|
||||
platform: {
|
||||
type: String,
|
||||
required: true,
|
||||
validator: (value) => ['windows', 'macos', 'linux'].includes(value)
|
||||
},
|
||||
stepNumber: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
toolName: {
|
||||
type: String,
|
||||
default: 'CLI 工具'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
30
web/admin-spa/src/components/tutorial/VerifyInstall.vue
Normal file
30
web/admin-spa/src/components/tutorial/VerifyInstall.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div
|
||||
class="rounded-lg border border-green-200 bg-green-50 p-3 dark:border-green-500/40 dark:bg-green-950/30 sm:p-4"
|
||||
>
|
||||
<h6 class="mb-2 text-sm font-medium text-green-800 dark:text-green-300 sm:text-base">
|
||||
验证安装是否成功
|
||||
</h6>
|
||||
<p class="mb-2 text-xs text-green-700 dark:text-green-300 sm:mb-3 sm:text-sm">
|
||||
安装完成后,打开 {{ terminal }},输入以下命令:
|
||||
</p>
|
||||
<div
|
||||
class="overflow-x-auto rounded bg-gray-900 p-2 font-mono text-xs text-green-400 sm:p-3 sm:text-sm"
|
||||
>
|
||||
<div class="whitespace-nowrap text-gray-300">node --version</div>
|
||||
<div class="whitespace-nowrap text-gray-300">npm --version</div>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-green-700 dark:text-green-300 sm:text-sm">
|
||||
如果显示版本号,说明安装成功了!
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
terminal: {
|
||||
type: String,
|
||||
default: '终端'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -85,7 +85,7 @@
|
||||
<div
|
||||
:class="[
|
||||
'h-2 w-2 rounded-full',
|
||||
apiKey.isDeleted === 'true' || apiKey.deletedAt
|
||||
apiKey.isDeleted === true || apiKey.deletedAt
|
||||
? 'bg-gray-400'
|
||||
: apiKey.isActive
|
||||
? 'bg-green-400'
|
||||
@@ -97,7 +97,7 @@
|
||||
<div class="flex items-center">
|
||||
<p class="text-sm font-medium text-gray-900">{{ apiKey.name }}</p>
|
||||
<span
|
||||
v-if="apiKey.isDeleted === 'true' || apiKey.deletedAt"
|
||||
v-if="apiKey.isDeleted === true || apiKey.deletedAt"
|
||||
class="ml-2 inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-800"
|
||||
>
|
||||
Deleted
|
||||
|
||||
52
web/admin-spa/src/composables/useTutorialUrls.js
Normal file
52
web/admin-spa/src/composables/useTutorialUrls.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { computed } from 'vue'
|
||||
|
||||
export function useTutorialUrls() {
|
||||
const getBaseUrlPrefix = () => {
|
||||
const customPrefix = import.meta.env.VITE_API_BASE_PREFIX
|
||||
if (customPrefix) {
|
||||
return customPrefix.replace(/\/$/, '')
|
||||
}
|
||||
|
||||
let origin = ''
|
||||
if (window.location.origin) {
|
||||
origin = window.location.origin
|
||||
} else {
|
||||
const protocol = window.location.protocol
|
||||
const hostname = window.location.hostname
|
||||
const port = window.location.port
|
||||
origin = protocol + '//' + hostname
|
||||
if (
|
||||
port &&
|
||||
((protocol === 'http:' && port !== '80') || (protocol === 'https:' && port !== '443'))
|
||||
) {
|
||||
origin += ':' + port
|
||||
}
|
||||
}
|
||||
|
||||
if (!origin) {
|
||||
const currentUrl = window.location.href
|
||||
const pathStart = currentUrl.indexOf('/', 8)
|
||||
if (pathStart !== -1) {
|
||||
origin = currentUrl.substring(0, pathStart)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
return origin
|
||||
}
|
||||
|
||||
const currentBaseUrl = computed(() => getBaseUrlPrefix() + '/api')
|
||||
const geminiBaseUrl = computed(() => getBaseUrlPrefix() + '/gemini')
|
||||
const openaiBaseUrl = computed(() => getBaseUrlPrefix() + '/openai')
|
||||
const droidClaudeBaseUrl = computed(() => getBaseUrlPrefix() + '/droid/claude')
|
||||
const droidOpenaiBaseUrl = computed(() => getBaseUrlPrefix() + '/droid/openai')
|
||||
|
||||
return {
|
||||
currentBaseUrl,
|
||||
geminiBaseUrl,
|
||||
openaiBaseUrl,
|
||||
droidClaudeBaseUrl,
|
||||
droidOpenaiBaseUrl
|
||||
}
|
||||
}
|
||||
@@ -66,18 +66,14 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
|
||||
async function verifyToken() {
|
||||
try {
|
||||
// 获取当前用户信息
|
||||
// /web/auth/user 已做完整 token 验证(session 存在性、完整性)
|
||||
// 成功返回即表示 token 有效,无需再调用 dashboard
|
||||
const userResult = await apiClient.get('/web/auth/user')
|
||||
if (userResult.success && userResult.user) {
|
||||
username.value = userResult.user.username
|
||||
}
|
||||
|
||||
// 使用 dashboard 端点来验证 token
|
||||
// 如果 token 无效,会抛出错误
|
||||
const result = await apiClient.get('/admin/dashboard')
|
||||
if (!result.success) {
|
||||
if (!userResult.success || !userResult.user) {
|
||||
logout()
|
||||
return
|
||||
}
|
||||
username.value = userResult.user.username
|
||||
} catch (error) {
|
||||
// token 无效,需要重新登录
|
||||
logout()
|
||||
|
||||
@@ -2122,7 +2122,6 @@ import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showToast } from '@/utils/toast'
|
||||
import { apiClient } from '@/config/api'
|
||||
import { useClientsStore } from '@/stores/clients'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import * as XLSX from 'xlsx-js-style'
|
||||
import CreateApiKeyModal from '@/components/apikeys/CreateApiKeyModal.vue'
|
||||
@@ -2139,7 +2138,6 @@ import ActionDropdown from '@/components/common/ActionDropdown.vue'
|
||||
|
||||
// 响应式数据
|
||||
const router = useRouter()
|
||||
const clientsStore = useClientsStore()
|
||||
const authStore = useAuthStore()
|
||||
const apiKeys = ref([])
|
||||
|
||||
@@ -4803,7 +4801,8 @@ onMounted(async () => {
|
||||
fetchCostSortStatus()
|
||||
|
||||
// 先加载 API Keys(优先显示列表)
|
||||
await Promise.all([clientsStore.loadSupportedClients(), loadApiKeys(), loadUsedModels()])
|
||||
// supported-clients 由 Create/Edit 模态框按需加载,无需预加载
|
||||
await Promise.all([loadApiKeys(), loadUsedModels()])
|
||||
|
||||
// 初始化全选状态
|
||||
updateSelectAllState()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user