From 868f75a79205ce9647e1b2f083938c58f86c26e7 Mon Sep 17 00:00:00 2001 From: huangzhenpc Date: Sat, 17 Jan 2026 01:52:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=93=81=E7=89=8C=E9=87=8D=E5=91=BD?= =?UTF-8?q?=E5=90=8D=20Sub2API=20->=20TianShuAPI=20(=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?=E5=AE=98=E6=96=B9=20v0.1.56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基于官方最新代码 upstream/main (dae0d53) 新功能: - 添加 5小时窗口费用控制和会话数量限制 - Caddy 静态资源长期缓存配置 - 前端性能优化(路由预加载、移除 Google Fonts 改用系统字体) - 修复 api_contract_test 缺少 SessionLimitCache 参数问题 品牌修改: - 仅修改品牌显示名称为 TianShuAPI - 保持所有功能完整 - 恢复 docker-compose.1panel.yml 配置文件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- backend/cmd/server/main.go | 4 +- .../repository/github_release_service.go | 2 +- .../repository/github_release_service_test.go | 2 +- backend/internal/server/api_contract_test.go | 8 +- backend/internal/service/auth_service.go | 4 +- backend/internal/service/setting_service.go | 8 +- backend/internal/setup/cli.go | 2 +- deploy/Untitled | 1 + deploy/docker-compose.1panel.yml | 130 +++++++++++ frontend/src/api/index.ts | 2 +- frontend/src/components/layout/AuthLayout.vue | 4 +- frontend/src/components/layout/README.md | 2 +- frontend/src/i18n/locales/en.ts | 20 +- frontend/src/i18n/locales/zh.ts | 20 +- frontend/src/main.ts | 2 +- frontend/src/router/README.md | 2 +- frontend/src/router/index.ts | 4 +- frontend/src/stores/README.md | 2 +- frontend/src/stores/app.ts | 4 +- frontend/src/types/index.ts | 2 +- frontend/src/views/HomeView.vue | 2 +- frontend/src/views/admin/SettingsView.vue | 2 +- frontend/src/views/auth/EmailVerifyView.vue | 4 +- frontend/src/views/auth/README.md | 2 +- frontend/src/views/auth/RegisterView.vue | 4 +- frontend/src/views/auth/USAGE_EXAMPLES.md | 4 +- frontend/src/views/auth/VISUAL_GUIDE.md | 8 +- 项目介绍.md | 207 ++++++++++++++++++ 28 files changed, 398 insertions(+), 60 deletions(-) create mode 100644 deploy/Untitled create mode 100644 deploy/docker-compose.1panel.yml create mode 100644 项目介绍.md diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go index c9dc57bb..5b7a01cc 100644 --- a/backend/cmd/server/main.go +++ b/backend/cmd/server/main.go @@ -51,7 +51,7 @@ func main() { flag.Parse() if *showVersion { - log.Printf("Sub2API %s (commit: %s, built: %s)\n", Version, Commit, Date) + log.Printf("TianShuAPI %s (commit: %s, built: %s)\n", Version, Commit, Date) return } @@ -101,7 +101,7 @@ func runSetupServer() { // This allows users to run setup on a different address if needed addr := config.GetServerAddress() log.Printf("Setup wizard available at http://%s", addr) - log.Println("Complete the setup wizard to configure Sub2API") + log.Println("Complete the setup wizard to configure TianShuAPI") if err := r.Run(addr); err != nil { log.Fatalf("Failed to start setup server: %v", err) diff --git a/backend/internal/repository/github_release_service.go b/backend/internal/repository/github_release_service.go index 77839626..f38d4d13 100644 --- a/backend/internal/repository/github_release_service.go +++ b/backend/internal/repository/github_release_service.go @@ -52,7 +52,7 @@ func (c *githubReleaseClient) FetchLatestRelease(ctx context.Context, repo strin return nil, err } req.Header.Set("Accept", "application/vnd.github.v3+json") - req.Header.Set("User-Agent", "Sub2API-Updater") + req.Header.Set("User-Agent", "TianShuAPI-Updater") resp, err := c.httpClient.Do(req) if err != nil { diff --git a/backend/internal/repository/github_release_service_test.go b/backend/internal/repository/github_release_service_test.go index d375a193..291da3b1 100644 --- a/backend/internal/repository/github_release_service_test.go +++ b/backend/internal/repository/github_release_service_test.go @@ -223,7 +223,7 @@ func (s *GitHubReleaseServiceSuite) TestFetchLatestRelease_Success() { s.srv = newLocalTestServer(s.T(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { require.Equal(s.T(), "/repos/test/repo/releases/latest", r.URL.Path) require.Equal(s.T(), "application/vnd.github.v3+json", r.Header.Get("Accept")) - require.Equal(s.T(), "Sub2API-Updater", r.Header.Get("User-Agent")) + require.Equal(s.T(), "TianShuAPI-Updater", r.Header.Get("User-Agent")) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(releaseJSON)) diff --git a/backend/internal/server/api_contract_test.go b/backend/internal/server/api_contract_test.go index 356b4a4e..28cab36c 100644 --- a/backend/internal/server/api_contract_test.go +++ b/backend/internal/server/api_contract_test.go @@ -272,14 +272,14 @@ func TestAPIContracts(t *testing.T) { service.SettingKeySMTPUsername: "user", service.SettingKeySMTPPassword: "secret", service.SettingKeySMTPFrom: "no-reply@example.com", - service.SettingKeySMTPFromName: "Sub2API", + service.SettingKeySMTPFromName: "TianShuAPI", service.SettingKeySMTPUseTLS: "true", service.SettingKeyTurnstileEnabled: "true", service.SettingKeyTurnstileSiteKey: "site-key", service.SettingKeyTurnstileSecretKey: "secret-key", - service.SettingKeySiteName: "Sub2API", + service.SettingKeySiteName: "TianShuAPI", service.SettingKeySiteLogo: "", service.SettingKeySiteSubtitle: "Subtitle", service.SettingKeyAPIBaseURL: "https://api.example.com", @@ -309,7 +309,7 @@ func TestAPIContracts(t *testing.T) { "smtp_username": "user", "smtp_password_configured": true, "smtp_from_email": "no-reply@example.com", - "smtp_from_name": "Sub2API", + "smtp_from_name": "TianShuAPI", "smtp_use_tls": true, "turnstile_enabled": true, "turnstile_site_key": "site-key", @@ -322,7 +322,7 @@ func TestAPIContracts(t *testing.T) { "ops_realtime_monitoring_enabled": true, "ops_query_mode_default": "auto", "ops_metrics_interval_seconds": 60, - "site_name": "Sub2API", + "site_name": "TianShuAPI", "site_logo": "", "site_subtitle": "Subtitle", "api_base_url": "https://api.example.com", diff --git a/backend/internal/service/auth_service.go b/backend/internal/service/auth_service.go index 386b43fc..2bb46c87 100644 --- a/backend/internal/service/auth_service.go +++ b/backend/internal/service/auth_service.go @@ -207,7 +207,7 @@ func (s *AuthService) SendVerifyCode(ctx context.Context, email string) error { } // 获取网站名称 - siteName := "Sub2API" + siteName := "TianShuAPI" if s.settingService != nil { siteName = s.settingService.GetSiteName(ctx) } @@ -247,7 +247,7 @@ func (s *AuthService) SendVerifyCodeAsync(ctx context.Context, email string) (*S } // 获取网站名称 - siteName := "Sub2API" + siteName := "TianShuAPI" if s.settingService != nil { siteName = s.settingService.GetSiteName(ctx) } diff --git a/backend/internal/service/setting_service.go b/backend/internal/service/setting_service.go index 0a7426f8..6e026b90 100644 --- a/backend/internal/service/setting_service.go +++ b/backend/internal/service/setting_service.go @@ -89,7 +89,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings EmailVerifyEnabled: settings[SettingKeyEmailVerifyEnabled] == "true", TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true", TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey], - SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"), + SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"), SiteLogo: settings[SettingKeySiteLogo], SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"), APIBaseURL: settings[SettingKeyAPIBaseURL], @@ -247,7 +247,7 @@ func (s *SettingService) IsEmailVerifyEnabled(ctx context.Context) bool { func (s *SettingService) GetSiteName(ctx context.Context) string { value, err := s.settingRepo.GetValue(ctx, SettingKeySiteName) if err != nil || value == "" { - return "Sub2API" + return "TianShuAPI" } return value } @@ -292,7 +292,7 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error { defaults := map[string]string{ SettingKeyRegistrationEnabled: "true", SettingKeyEmailVerifyEnabled: "false", - SettingKeySiteName: "Sub2API", + SettingKeySiteName: "TianShuAPI", SettingKeySiteLogo: "", SettingKeyDefaultConcurrency: strconv.Itoa(s.cfg.Default.UserConcurrency), SettingKeyDefaultBalance: strconv.FormatFloat(s.cfg.Default.UserBalance, 'f', 8, 64), @@ -332,7 +332,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true", TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey], TurnstileSecretKeyConfigured: settings[SettingKeyTurnstileSecretKey] != "", - SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"), + SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"), SiteLogo: settings[SettingKeySiteLogo], SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"), APIBaseURL: settings[SettingKeyAPIBaseURL], diff --git a/backend/internal/setup/cli.go b/backend/internal/setup/cli.go index 03ac3f66..a0a74a63 100644 --- a/backend/internal/setup/cli.go +++ b/backend/internal/setup/cli.go @@ -51,7 +51,7 @@ func RunCLI() error { fmt.Println() fmt.Println("╔═══════════════════════════════════════════╗") - fmt.Println("║ Sub2API Installation Wizard ║") + fmt.Println("║ TianShuAPI Installation Wizard ║") fmt.Println("╚═══════════════════════════════════════════╝") fmt.Println() diff --git a/deploy/Untitled b/deploy/Untitled new file mode 100644 index 00000000..26e73d2c --- /dev/null +++ b/deploy/Untitled @@ -0,0 +1 @@ +docker-compose.1panel.yml \ No newline at end of file diff --git a/deploy/docker-compose.1panel.yml b/deploy/docker-compose.1panel.yml new file mode 100644 index 00000000..ee628ba0 --- /dev/null +++ b/deploy/docker-compose.1panel.yml @@ -0,0 +1,130 @@ +# ============================================================================= +# TianShuAPI Docker Compose - 1Panel 环境配置 +# ============================================================================= +# 此配置文件适用于已有 1Panel 环境,复用现有 Redis +# ============================================================================= + +services: + # =========================================================================== + # TianShuAPI Application + # =========================================================================== + sub2api: + # 方式1:使用官方镜像(快速部署) + # image: weishaw/sub2api:latest + + # 方式2:从本地代码构建(二次开发) + build: + context: ../ + dockerfile: Dockerfile + args: + - BUILD_TAGS=embed + image: sub2api:local + container_name: sub2api + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + ports: + - "${BIND_HOST:-0.0.0.0}:${SERVER_PORT:-8080}:8080" + volumes: + - sub2api_data:/app/data + environment: + # Auto Setup + - AUTO_SETUP=true + + # Server Configuration + - SERVER_HOST=0.0.0.0 + - SERVER_PORT=8080 + - SERVER_MODE=${SERVER_MODE:-release} + - RUN_MODE=${RUN_MODE:-standard} + + # Database Configuration + - DATABASE_HOST=postgres + - DATABASE_PORT=5432 + - DATABASE_USER=${POSTGRES_USER:-sub2api} + - DATABASE_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + - DATABASE_DBNAME=${POSTGRES_DB:-sub2api} + - DATABASE_SSLMODE=disable + + # Redis Configuration - 使用外部 Redis + - REDIS_HOST=${REDIS_HOST} + - REDIS_PORT=${REDIS_PORT:-6379} + - REDIS_PASSWORD=${REDIS_PASSWORD} + - REDIS_DB=${REDIS_DB:-0} + + # Admin Account + - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@sub2api.local} + - ADMIN_PASSWORD=${ADMIN_PASSWORD:-} + + # JWT Configuration + - JWT_SECRET=${JWT_SECRET:-} + - JWT_EXPIRE_HOUR=${JWT_EXPIRE_HOUR:-24} + + # Timezone + - TZ=${TZ:-Asia/Shanghai} + + # Gemini OAuth (可选) + - GEMINI_OAUTH_CLIENT_ID=${GEMINI_OAUTH_CLIENT_ID:-} + - GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-} + - GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-} + - GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-} + depends_on: + postgres: + condition: service_healthy + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - sub2api-network + - 1panel-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + + # =========================================================================== + # PostgreSQL Database + # =========================================================================== + postgres: + image: postgres:18-alpine + container_name: sub2api-postgres + restart: unless-stopped + ulimits: + nofile: + soft: 100000 + hard: 100000 + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=${POSTGRES_USER:-sub2api} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} + - POSTGRES_DB=${POSTGRES_DB:-sub2api} + - TZ=${TZ:-Asia/Shanghai} + networks: + - sub2api-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-sub2api} -d ${POSTGRES_DB:-sub2api}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + +# ============================================================================= +# Volumes +# ============================================================================= +volumes: + sub2api_data: + driver: local + postgres_data: + driver: local + +# ============================================================================= +# Networks +# ============================================================================= +networks: + sub2api-network: + driver: bridge + 1panel-network: + external: true diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 50b14c4c..e80cc753 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -1,5 +1,5 @@ /** - * API Client for Sub2API Backend + * API Client for TianShuAPI Backend * Central export point for all API modules */ diff --git a/frontend/src/components/layout/AuthLayout.vue b/frontend/src/components/layout/AuthLayout.vue index 3cfc1d4d..bd20b3c4 100644 --- a/frontend/src/components/layout/AuthLayout.vue +++ b/frontend/src/components/layout/AuthLayout.vue @@ -65,7 +65,7 @@ import { ref, computed, onMounted } from 'vue' import { getPublicSettings } from '@/api/auth' import { sanitizeUrl } from '@/utils/url' -const siteName = ref('Sub2API') +const siteName = ref('TianShuAPI') const siteLogo = ref('') const siteSubtitle = ref('Subscription to API Conversion Platform') @@ -74,7 +74,7 @@ const currentYear = computed(() => new Date().getFullYear()) onMounted(async () => { try { const settings = await getPublicSettings() - siteName.value = settings.site_name || 'Sub2API' + siteName.value = settings.site_name || 'TianShuAPI' siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true }) siteSubtitle.value = settings.site_subtitle || 'Subscription to API Conversion Platform' } catch (error) { diff --git a/frontend/src/components/layout/README.md b/frontend/src/components/layout/README.md index e2cbdd17..e94aa31c 100644 --- a/frontend/src/components/layout/README.md +++ b/frontend/src/components/layout/README.md @@ -1,6 +1,6 @@ # Layout Components -Vue 3 layout components for the Sub2API frontend, built with Composition API, TypeScript, and TailwindCSS. +Vue 3 layout components for the TianShuAPI frontend, built with Composition API, TypeScript, and TailwindCSS. ## Components diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index b25b5a0b..7dbb556b 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -43,8 +43,8 @@ export default { // Setup Wizard setup: { - title: 'Sub2API Setup', - description: 'Configure your Sub2API instance', + title: 'TianShuAPI Setup', + description: 'Configure your TianShuAPI instance', database: { title: 'Database Configuration', description: 'Connect to your PostgreSQL database', @@ -2686,7 +2686,7 @@ export default { secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.' }, linuxdo: { title: 'LinuxDo Connect Login', - description: 'Configure LinuxDo Connect OAuth for Sub2API end-user login', + description: 'Configure LinuxDo Connect OAuth for TianShuAPI end-user login', enable: 'Enable LinuxDo Login', enableHint: 'Show LinuxDo login on the login/register pages', clientId: 'Client ID', @@ -2716,7 +2716,7 @@ export default { title: 'Site Settings', description: 'Customize site branding', siteName: 'Site Name', - siteNamePlaceholder: 'Sub2API', + siteNamePlaceholder: 'TianShuAPI', siteNameHint: 'Displayed in emails and page titles', siteSubtitle: 'Site Subtitle', siteSubtitlePlaceholder: 'Subscription to API Conversion Platform', @@ -2762,7 +2762,7 @@ export default { fromEmail: 'From Email', fromEmailPlaceholder: "noreply{'@'}example.com", fromName: 'From Name', - fromNamePlaceholder: 'Sub2API', + fromNamePlaceholder: 'TianShuAPI', useTls: 'Use TLS', useTlsHint: 'Enable TLS encryption for SMTP connection' }, @@ -2931,14 +2931,14 @@ export default { // Admin tour steps admin: { welcome: { - title: '👋 Welcome to Sub2API', - description: '

Sub2API is a powerful AI service gateway platform that helps you easily manage and distribute AI services.

🎯 Core Features:

  • 📦 Group Management - Create service tiers (VIP, Free Trial, etc.)
  • 🔗 Account Pool - Connect multiple upstream AI service accounts
  • 🔑 Key Distribution - Generate independent API Keys for users
  • 💰 Billing Control - Flexible rate and quota management

Let\'s complete the initial setup in 3 minutes →

', + title: '👋 Welcome to TianShuAPI', + description: '

TianShuAPI is a powerful AI service gateway platform that helps you easily manage and distribute AI services.

🎯 Core Features:

  • 📦 Group Management - Create service tiers (VIP, Free Trial, etc.)
  • 🔗 Account Pool - Connect multiple upstream AI service accounts
  • 🔑 Key Distribution - Generate independent API Keys for users
  • 💰 Billing Control - Flexible rate and quota management

Let\'s complete the initial setup in 3 minutes →

', nextBtn: 'Start Setup 🚀', prevBtn: 'Skip' }, groupManage: { title: '📦 Step 1: Group Management', - description: '

What is a Group?

Groups are the core concept of Sub2API, like a "service package":

  • 🎯 Each group can contain multiple upstream accounts
  • 💰 Each group has independent billing multiplier
  • 👥 Can be set as public or exclusive

💡 Example: You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups

👉 Click "Group Management" on the left sidebar

' + description: '

What is a Group?

Groups are the core concept of TianShuAPI, like a "service package":

  • 🎯 Each group can contain multiple upstream accounts
  • 💰 Each group has independent billing multiplier
  • 👥 Can be set as public or exclusive

💡 Example: You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups

👉 Click "Group Management" on the left sidebar

' }, createGroup: { title: '➕ Create New Group', @@ -3031,8 +3031,8 @@ export default { // User tour steps user: { welcome: { - title: '👋 Welcome to Sub2API', - description: '

Hello! Welcome to the Sub2API AI service platform.

🎯 Quick Start:

  • 🔑 Create API Key
  • 📋 Copy key to your application
  • 🚀 Start using AI services

Just 1 minute, let\'s get started →

', + title: '👋 Welcome to TianShuAPI', + description: '

Hello! Welcome to the TianShuAPI AI service platform.

🎯 Quick Start:

  • 🔑 Create API Key
  • 📋 Copy key to your application
  • 🚀 Start using AI services

Just 1 minute, let\'s get started →

', nextBtn: 'Start 🚀', prevBtn: 'Skip' }, diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index b7be8557..ec9e3473 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -40,8 +40,8 @@ export default { // Setup Wizard setup: { - title: 'Sub2API 安装向导', - description: '配置您的 Sub2API 实例', + title: 'TianShuAPI 安装向导', + description: '配置您的 TianShuAPI 实例', database: { title: '数据库配置', description: '连接到您的 PostgreSQL 数据库', @@ -2840,7 +2840,7 @@ export default { secretKeyConfiguredHint: '密钥已配置,留空以保留当前值。' }, linuxdo: { title: 'LinuxDo Connect 登录', - description: '配置 LinuxDo Connect OAuth,用于 Sub2API 用户登录', + description: '配置 LinuxDo Connect OAuth,用于 TianShuAPI 用户登录', enable: '启用 LinuxDo 登录', enableHint: '在登录/注册页面显示 LinuxDo 登录入口', clientId: 'Client ID', @@ -2870,7 +2870,7 @@ export default { description: '自定义站点品牌', siteName: '站点名称', siteNameHint: '显示在邮件和页面标题中', - siteNamePlaceholder: 'Sub2API', + siteNamePlaceholder: 'TianShuAPI', siteSubtitle: '站点副标题', siteSubtitleHint: '显示在登录和注册页面', siteSubtitlePlaceholder: '订阅转 API 转换平台', @@ -2914,7 +2914,7 @@ export default { fromEmail: '发件人邮箱', fromEmailPlaceholder: "noreply{'@'}example.com", fromName: '发件人名称', - fromNamePlaceholder: 'Sub2API', + fromNamePlaceholder: 'TianShuAPI', useTls: '使用 TLS', useTlsHint: '为 SMTP 连接启用 TLS 加密' }, @@ -3081,14 +3081,14 @@ export default { // Admin tour steps admin: { welcome: { - title: '👋 欢迎使用 Sub2API', - description: '

Sub2API 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。

🎯 核心功能:

  • 📦 分组管理 - 创建不同的服务套餐(VIP、免费试用等)
  • 🔗 账号池 - 连接多个上游 AI 服务商账号
  • 🔑 密钥分发 - 为用户生成独立的 API Key
  • 💰 计费管理 - 灵活的费率和配额控制

接下来,我们将用 3 分钟带您完成首次配置 →

', + title: '👋 欢迎使用 TianShuAPI', + description: '

TianShuAPI 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。

🎯 核心功能:

  • 📦 分组管理 - 创建不同的服务套餐(VIP、免费试用等)
  • 🔗 账号池 - 连接多个上游 AI 服务商账号
  • 🔑 密钥分发 - 为用户生成独立的 API Key
  • 💰 计费管理 - 灵活的费率和配额控制

接下来,我们将用 3 分钟带您完成首次配置 →

', nextBtn: '开始配置 🚀', prevBtn: '跳过' }, groupManage: { title: '📦 第一步:分组管理', - description: '

什么是分组?

分组是 Sub2API 的核心概念,它就像一个"服务套餐":

  • 🎯 每个分组可以包含多个上游账号
  • 💰 每个分组有独立的计费倍率
  • 👥 可以设置为公开或专属分组

💡 示例:您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组

👉 点击左侧的"分组管理"开始

' + description: '

什么是分组?

分组是 TianShuAPI 的核心概念,它就像一个"服务套餐":

  • 🎯 每个分组可以包含多个上游账号
  • 💰 每个分组有独立的计费倍率
  • 👥 可以设置为公开或专属分组

💡 示例:您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组

👉 点击左侧的"分组管理"开始

' }, createGroup: { title: '➕ 创建新分组', @@ -3181,8 +3181,8 @@ export default { // User tour steps user: { welcome: { - title: '👋 欢迎使用 Sub2API', - description: '

您好!欢迎来到 Sub2API AI 服务平台。

🎯 快速开始:

  • 🔑 创建 API 密钥
  • 📋 复制密钥到您的应用
  • 🚀 开始使用 AI 服务

只需 1 分钟,让我们开始吧 →

', + title: '👋 欢迎使用 TianShuAPI', + description: '

您好!欢迎来到 TianShuAPI AI 服务平台。

🎯 快速开始:

  • 🔑 创建 API 密钥
  • 📋 复制密钥到您的应用
  • 🚀 开始使用 AI 服务

只需 1 分钟,让我们开始吧 →

', nextBtn: '开始 🚀', prevBtn: '跳过' }, diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 11c0b1e8..80c24d07 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -16,7 +16,7 @@ const appStore = useAppStore() appStore.initFromInjectedConfig() // Set document title immediately after config is loaded -if (appStore.siteName && appStore.siteName !== 'Sub2API') { +if (appStore.siteName && appStore.siteName !== 'TianShuAPI') { document.title = `${appStore.siteName} - AI API Gateway` } diff --git a/frontend/src/router/README.md b/frontend/src/router/README.md index 4ffacb8f..e5518e75 100644 --- a/frontend/src/router/README.md +++ b/frontend/src/router/README.md @@ -2,7 +2,7 @@ ## Overview -This directory contains the Vue Router configuration for the Sub2API frontend application. The router implements a comprehensive navigation system with authentication guards, role-based access control, and lazy loading. +This directory contains the Vue Router configuration for the TianShuAPI frontend application. The router implements a comprehensive navigation system with authentication guards, role-based access control, and lazy loading. ## Files diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 96127063..9dce8624 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -1,5 +1,5 @@ /** - * Vue Router configuration for Sub2API frontend + * Vue Router configuration for TianShuAPI frontend * Defines all application routes with lazy loading and navigation guards */ @@ -347,7 +347,7 @@ router.beforeEach((to, _from, next) => { // Set page title const appStore = useAppStore() - const siteName = appStore.siteName || 'Sub2API' + const siteName = appStore.siteName || 'TianShuAPI' if (to.meta.title) { document.title = `${to.meta.title} - ${siteName}` } else { diff --git a/frontend/src/stores/README.md b/frontend/src/stores/README.md index 35c7df41..50393c94 100644 --- a/frontend/src/stores/README.md +++ b/frontend/src/stores/README.md @@ -1,6 +1,6 @@ # Pinia Stores Documentation -This directory contains all Pinia stores for the Sub2API frontend application. +This directory contains all Pinia stores for the TianShuAPI frontend application. ## Stores Overview diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index 55476ca0..f80c9718 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -24,7 +24,7 @@ export const useAppStore = defineStore('app', () => { // Public settings cache state const publicSettingsLoaded = ref(false) const publicSettingsLoading = ref(false) - const siteName = ref('Sub2API') + const siteName = ref('TianShuAPI') const siteLogo = ref('') const siteVersion = ref('') const contactInfo = ref('') @@ -284,7 +284,7 @@ export const useAppStore = defineStore('app', () => { */ function applySettings(config: PublicSettings): void { cachedPublicSettings.value = config - siteName.value = config.site_name || 'Sub2API' + siteName.value = config.site_name || 'TianShuAPI' siteLogo.value = config.site_logo || '' siteVersion.value = config.version || '' contactInfo.value = config.contact_info || '' diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 6fa57c26..f15b6d6a 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -1,5 +1,5 @@ /** - * Core Type Definitions for Sub2API Frontend + * Core Type Definitions for TianShuAPI Frontend */ // ==================== Common Types ==================== diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index 6a3753f1..dd94f78e 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -417,7 +417,7 @@ const authStore = useAuthStore() const appStore = useAppStore() // Site settings - directly from appStore (already initialized from injected config) -const siteName = computed(() => appStore.cachedPublicSettings?.site_name || appStore.siteName || 'Sub2API') +const siteName = computed(() => appStore.cachedPublicSettings?.site_name || appStore.siteName || 'TianShuAPI') const siteLogo = computed(() => appStore.cachedPublicSettings?.site_logo || appStore.siteLogo || '') const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'AI API Gateway Platform') const docUrl = computed(() => appStore.cachedPublicSettings?.doc_url || appStore.docUrl || '') diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index d46c3329..ecdacc48 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -1000,7 +1000,7 @@ const form = reactive({ email_verify_enabled: false, default_balance: 0, default_concurrency: 1, - site_name: 'Sub2API', + site_name: 'TianShuAPI', site_logo: '', site_subtitle: 'Subscription to API Conversion Platform', api_base_url: '', diff --git a/frontend/src/views/auth/EmailVerifyView.vue b/frontend/src/views/auth/EmailVerifyView.vue index 3b6b45ba..3c119e37 100644 --- a/frontend/src/views/auth/EmailVerifyView.vue +++ b/frontend/src/views/auth/EmailVerifyView.vue @@ -206,7 +206,7 @@ const hasRegisterData = ref(false) // Public settings const turnstileEnabled = ref(false) const turnstileSiteKey = ref('') -const siteName = ref('Sub2API') +const siteName = ref('TianShuAPI') // Turnstile for resend const turnstileRef = ref | null>(null) @@ -241,7 +241,7 @@ onMounted(async () => { const settings = await getPublicSettings() turnstileEnabled.value = settings.turnstile_enabled turnstileSiteKey.value = settings.turnstile_site_key || '' - siteName.value = settings.site_name || 'Sub2API' + siteName.value = settings.site_name || 'TianShuAPI' } catch (error) { console.error('Failed to load public settings:', error) } diff --git a/frontend/src/views/auth/README.md b/frontend/src/views/auth/README.md index 65c3a190..27d38474 100644 --- a/frontend/src/views/auth/README.md +++ b/frontend/src/views/auth/README.md @@ -1,6 +1,6 @@ # Authentication Views -This directory contains Vue 3 authentication views for the Sub2API frontend application. +This directory contains Vue 3 authentication views for the TianShuAPI frontend application. ## Components diff --git a/frontend/src/views/auth/RegisterView.vue b/frontend/src/views/auth/RegisterView.vue index bfdc08e8..bca497ea 100644 --- a/frontend/src/views/auth/RegisterView.vue +++ b/frontend/src/views/auth/RegisterView.vue @@ -262,7 +262,7 @@ const registrationEnabled = ref(true) const emailVerifyEnabled = ref(false) const turnstileEnabled = ref(false) const turnstileSiteKey = ref('') -const siteName = ref('Sub2API') +const siteName = ref('TianShuAPI') const linuxdoOAuthEnabled = ref(false) // Turnstile @@ -308,7 +308,7 @@ onMounted(async () => { emailVerifyEnabled.value = settings.email_verify_enabled turnstileEnabled.value = settings.turnstile_enabled turnstileSiteKey.value = settings.turnstile_site_key || '' - siteName.value = settings.site_name || 'Sub2API' + siteName.value = settings.site_name || 'TianShuAPI' linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled } catch (error) { console.error('Failed to load public settings:', error) diff --git a/frontend/src/views/auth/USAGE_EXAMPLES.md b/frontend/src/views/auth/USAGE_EXAMPLES.md index 735dbe13..d912f67e 100644 --- a/frontend/src/views/auth/USAGE_EXAMPLES.md +++ b/frontend/src/views/auth/USAGE_EXAMPLES.md @@ -1,6 +1,6 @@ # Authentication Views Usage Examples -This document provides practical examples of how to use the authentication views in the Sub2API frontend. +This document provides practical examples of how to use the authentication views in the TianShuAPI frontend. ## Quick Start @@ -61,7 +61,7 @@ This document provides practical examples of how to use the authentication views // - On success: // - Token stored in localStorage // - User data stored in state -// - Success toast: "Account created successfully! Welcome to Sub2API." +// - Success toast: "Account created successfully! Welcome to TianShuAPI." // - Redirect to /dashboard // - On error: // - Error message displayed inline diff --git a/frontend/src/views/auth/VISUAL_GUIDE.md b/frontend/src/views/auth/VISUAL_GUIDE.md index a978b731..e4beabcc 100644 --- a/frontend/src/views/auth/VISUAL_GUIDE.md +++ b/frontend/src/views/auth/VISUAL_GUIDE.md @@ -11,7 +11,7 @@ Both LoginView and RegisterView use the AuthLayout component, which provides: │ │ │ ┌─────────────────────────────────────┐ │ │ │ │ │ -│ │ Sub2API Logo │ │ +│ │ TianShuAPI Logo │ │ │ │ "Subscription to API Conversion" │ │ │ │ │ │ │ └─────────────────────────────────────┘ │ @@ -39,7 +39,7 @@ Centered: Both horizontally and vertically ``` ┌─────────────────────────────────────────────┐ │ │ -│ 🔷 Sub2API │ +│ 🔷 TianShuAPI │ │ Subscription to API Conversion Platform │ │ │ │ ┌─────────────────────────────────────┐ │ @@ -133,13 +133,13 @@ Centered: Both horizontally and vertically ``` ┌─────────────────────────────────────────────┐ │ │ -│ 🔷 Sub2API │ +│ 🔷 TianShuAPI │ │ Subscription to API Conversion Platform │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ │ │ │ │ Create Account │ │ -│ │ Sign up to start using Sub2API │ │ +│ │ Sign up to start using TianShuAPI │ │ │ │ │ │ │ │ Username │ │ │ │ ┌────────────────────────────────┐ │ │ diff --git a/项目介绍.md b/项目介绍.md new file mode 100644 index 00000000..1303b6e8 --- /dev/null +++ b/项目介绍.md @@ -0,0 +1,207 @@ +● 完全正确!标准的二次开发工作流程就是这样的: + + 🔄 正确的工作流程 + + ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ + │ 官方仓库 │ │ 你的仓库 │ │ 生产服务器 │ + │ (upstream) │────┐ │ (origin) │────────▶│ /opt/sub2api │ + │ GitHub │ │ │ git.586vip.cn │ │ │ + └─────────────────┘ │ └──────────────────┘ └─────────────────┘ + │ ▲ │ + │ │ │ + │ │ push │ pull + │ │ │ + │ ┌─────────┴──────────┐ │ + └───▶│ 本地开发环境 │ │ + fetch/pull │ (你的 WSL) │◀──────────────┘ + │ /mnt/d/tmp/... │ 仅用于测试 + └────────────────────┘ + + --- + 📋 具体操作流程 + + 1️⃣ 本地环境(你的 WSL - 主要工作区) + + cd /mnt/d/tmp/claude相关/sub2api + + # 查看当前 remote 配置 + git remote -v + # origin https://git.586vip.cn/oadmin/sub2api.git + # upstream https://github.com/Wei-Shaw/sub2api.git + + # ===== 同步官方更新 ===== + + # 1. 拉取官方最新代码 + git fetch upstream + + # 2. 查看官方更新了什么 + git log HEAD..upstream/main --oneline --graph + + # 3. 详细对比差异(重要!) + git diff HEAD..upstream/main + + # 查看某个文件的差异 + git diff HEAD..upstream/main -- backend/internal/service/gateway_service.go + + # 4. 合并官方更新到你的本地 + git merge upstream/main + + # 5. 如果有冲突,解决冲突 + # (编辑冲突文件,保留你需要的代码) + git add . + git commit -m "merge: 合并官方更新 vX.X.X" + + # 6. 推送到你的仓库 + git push origin main + + 2️⃣ 服务器环境(生产服务器 - 只拉取你的仓库) + + cd /opt/sub2api-dev + + # 查看 remote(应该只有 origin 指向你的仓库) + git remote -v + # origin https://git.586vip.cn/oadmin/sub2api.git + + # ===== 更新服务器代码 ===== + + # 1. 拉取你的仓库最新代码 + git pull origin main + + # 2. 重新部署 + cd deploy + docker-compose pull + docker-compose up -d + + # 3. 查看日志确认 + docker-compose logs -f + + --- + 🎯 完整示例场景 + + 场景:官方发布了 v1.5.0 版本 + + 第 1 步:本地对比更新 + + # 在你的 WSL 中 + cd /mnt/d/tmp/claude相关/sub2api + + # 拉取官方更新 + git fetch upstream + + # 查看更新内容 + git log HEAD..upstream/main --oneline + # a1b2c3d (upstream/main) feat: 新增 XX 功能 + # d4e5f6g fix: 修复 YY 问题 + # ... + + # 对比差异 + git diff HEAD..upstream/main + + # 如果改动太多,可以查看修改的文件列表 + git diff --name-only HEAD..upstream/main + + # 查看某个关键文件的详细差异 + git diff HEAD..upstream/main -- backend/internal/service/gateway_service.go + + 第 2 步:本地合并更新 + + # 确保工作区干净 + git status + + # 如果有未提交的修改,先提交 + git add . + git commit -m "feat: 我的二开功能" + + # 合并官方更新 + git merge upstream/main + + # 如果有冲突 + # <<<<<<< HEAD + # 你的代码 + # ======= + # 官方代码 + # >>>>>>> upstream/main + + # 手动编辑冲突文件,选择保留哪部分代码 + nano backend/internal/service/gateway_service.go + + # 解决冲突后 + git add . + git commit -m "merge: 合并官方 v1.5.0 更新" + + 第 3 步:推送到你的仓库 + + # 推送到你的仓库 + git push origin main + + 第 4 步:服务器更新 + + # SSH 到服务器 + ssh root@你的服务器IP + + # 进入项目目录 + cd /opt/sub2api-dev + + # 拉取最新代码 + git pull origin main + + # 如果代码有更新,重新部署 + cd deploy + docker-compose pull + docker-compose up -d + + # 查看日志 + docker-compose logs -f sub2api + + --- + ⚠️ 重要注意事项 + + ✅ 正确做法 + + - ✅ 本地开发:拉取官方更新、对比、合并 + - ✅ 本地测试:确保合并后代码能正常运行 + - ✅ 推送到自己仓库:git push origin main + - ✅ 服务器拉取:git pull origin main + + ❌ 错误做法 + + - ❌ 服务器直接拉取官方代码(跳过本地对比) + - ❌ 不测试就直接推送到生产 + - ❌ 直接在服务器上修改代码(应该在本地改) + + --- + 📝 快速命令速查 + + 本地(开发环境) + + # 同步官方更新 + git fetch upstream + git log HEAD..upstream/main --oneline + git diff HEAD..upstream/main + git merge upstream/main + git push origin main + + 服务器(生产环境) + + # 更新代码 + cd /opt/sub2api-dev + git pull origin main + + # 重新部署 + cd deploy + docker-compose pull + docker-compose up -d + docker-compose logs -f + +cd deploy/ + # 如果没有输出,说明需要重新复制 + cp docker-compose.1panel.yml docker-compose.yml + + docker-compose build --no-cache + + docker-compose up -d + + # 或者一条命令 + docker-compose up -d --build + --- + 现在你可以先在服务器上部署了,后续官方有更新时,就按照上面的流程操作! \ No newline at end of file