feat: 品牌重命名 Sub2API -> TianShuAPI (基于官方 v0.1.56)
基于官方最新代码 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
1
deploy/Untitled
Normal file
1
deploy/Untitled
Normal file
@@ -0,0 +1 @@
|
||||
docker-compose.1panel.yml
|
||||
130
deploy/docker-compose.1panel.yml
Normal file
130
deploy/docker-compose.1panel.yml
Normal file
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* API Client for Sub2API Backend
|
||||
* API Client for TianShuAPI Backend
|
||||
* Central export point for all API modules
|
||||
*/
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Sub2API is a powerful AI service gateway platform that helps you easily manage and distribute AI services.</p><p style="margin-bottom: 12px;"><b>🎯 Core Features:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>📦 <b>Group Management</b> - Create service tiers (VIP, Free Trial, etc.)</li><li>🔗 <b>Account Pool</b> - Connect multiple upstream AI service accounts</li><li>🔑 <b>Key Distribution</b> - Generate independent API Keys for users</li><li>💰 <b>Billing Control</b> - Flexible rate and quota management</li></ul><p style="color: #10b981; font-weight: 600;">Let\'s complete the initial setup in 3 minutes →</p></div>',
|
||||
title: '👋 Welcome to TianShuAPI',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">TianShuAPI is a powerful AI service gateway platform that helps you easily manage and distribute AI services.</p><p style="margin-bottom: 12px;"><b>🎯 Core Features:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>📦 <b>Group Management</b> - Create service tiers (VIP, Free Trial, etc.)</li><li>🔗 <b>Account Pool</b> - Connect multiple upstream AI service accounts</li><li>🔑 <b>Key Distribution</b> - Generate independent API Keys for users</li><li>💰 <b>Billing Control</b> - Flexible rate and quota management</li></ul><p style="color: #10b981; font-weight: 600;">Let\'s complete the initial setup in 3 minutes →</p></div>',
|
||||
nextBtn: 'Start Setup 🚀',
|
||||
prevBtn: 'Skip'
|
||||
},
|
||||
groupManage: {
|
||||
title: '📦 Step 1: Group Management',
|
||||
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>What is a Group?</b></p><p style="margin-bottom: 12px;">Groups are the core concept of Sub2API, like a "service package":</p><ul style="margin-left: 20px; margin-bottom: 12px; font-size: 13px;"><li>🎯 Each group can contain multiple upstream accounts</li><li>💰 Each group has independent billing multiplier</li><li>👥 Can be set as public or exclusive</li></ul><p style="margin-top: 12px; padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Example:</b> You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups</p><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 Click "Group Management" on the left sidebar</p></div>'
|
||||
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>What is a Group?</b></p><p style="margin-bottom: 12px;">Groups are the core concept of TianShuAPI, like a "service package":</p><ul style="margin-left: 20px; margin-bottom: 12px; font-size: 13px;"><li>🎯 Each group can contain multiple upstream accounts</li><li>💰 Each group has independent billing multiplier</li><li>👥 Can be set as public or exclusive</li></ul><p style="margin-top: 12px; padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 Example:</b> You can create "VIP Premium" (high rate) and "Free Trial" (low rate) groups</p><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 Click "Group Management" on the left sidebar</p></div>'
|
||||
},
|
||||
createGroup: {
|
||||
title: '➕ Create New Group',
|
||||
@@ -3031,8 +3031,8 @@ export default {
|
||||
// User tour steps
|
||||
user: {
|
||||
welcome: {
|
||||
title: '👋 Welcome to Sub2API',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Hello! Welcome to the Sub2API AI service platform.</p><p style="margin-bottom: 12px;"><b>🎯 Quick Start:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>🔑 Create API Key</li><li>📋 Copy key to your application</li><li>🚀 Start using AI services</li></ul><p style="color: #10b981; font-weight: 600;">Just 1 minute, let\'s get started →</p></div>',
|
||||
title: '👋 Welcome to TianShuAPI',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Hello! Welcome to the TianShuAPI AI service platform.</p><p style="margin-bottom: 12px;"><b>🎯 Quick Start:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>🔑 Create API Key</li><li>📋 Copy key to your application</li><li>🚀 Start using AI services</li></ul><p style="color: #10b981; font-weight: 600;">Just 1 minute, let\'s get started →</p></div>',
|
||||
nextBtn: 'Start 🚀',
|
||||
prevBtn: 'Skip'
|
||||
},
|
||||
|
||||
@@ -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: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">Sub2API 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。</p><p style="margin-bottom: 12px;"><b>🎯 核心功能:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>📦 <b>分组管理</b> - 创建不同的服务套餐(VIP、免费试用等)</li><li>🔗 <b>账号池</b> - 连接多个上游 AI 服务商账号</li><li>🔑 <b>密钥分发</b> - 为用户生成独立的 API Key</li><li>💰 <b>计费管理</b> - 灵活的费率和配额控制</li></ul><p style="color: #10b981; font-weight: 600;">接下来,我们将用 3 分钟带您完成首次配置 →</p></div>',
|
||||
title: '👋 欢迎使用 TianShuAPI',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">TianShuAPI 是一个强大的 AI 服务中转平台,让您轻松管理和分发 AI 服务。</p><p style="margin-bottom: 12px;"><b>🎯 核心功能:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>📦 <b>分组管理</b> - 创建不同的服务套餐(VIP、免费试用等)</li><li>🔗 <b>账号池</b> - 连接多个上游 AI 服务商账号</li><li>🔑 <b>密钥分发</b> - 为用户生成独立的 API Key</li><li>💰 <b>计费管理</b> - 灵活的费率和配额控制</li></ul><p style="color: #10b981; font-weight: 600;">接下来,我们将用 3 分钟带您完成首次配置 →</p></div>',
|
||||
nextBtn: '开始配置 🚀',
|
||||
prevBtn: '跳过'
|
||||
},
|
||||
groupManage: {
|
||||
title: '📦 第一步:分组管理',
|
||||
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>什么是分组?</b></p><p style="margin-bottom: 12px;">分组是 Sub2API 的核心概念,它就像一个"服务套餐":</p><ul style="margin-left: 20px; margin-bottom: 12px; font-size: 13px;"><li>🎯 每个分组可以包含多个上游账号</li><li>💰 每个分组有独立的计费倍率</li><li>👥 可以设置为公开或专属分组</li></ul><p style="margin-top: 12px; padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 示例:</b>您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组</p><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 点击左侧的"分组管理"开始</p></div>'
|
||||
description: '<div style="line-height: 1.7;"><p style="margin-bottom: 12px;"><b>什么是分组?</b></p><p style="margin-bottom: 12px;">分组是 TianShuAPI 的核心概念,它就像一个"服务套餐":</p><ul style="margin-left: 20px; margin-bottom: 12px; font-size: 13px;"><li>🎯 每个分组可以包含多个上游账号</li><li>💰 每个分组有独立的计费倍率</li><li>👥 可以设置为公开或专属分组</li></ul><p style="margin-top: 12px; padding: 8px 12px; background: #f0fdf4; border-left: 3px solid #10b981; border-radius: 4px; font-size: 13px;"><b>💡 示例:</b>您可以创建"VIP专线"(高倍率)和"免费试用"(低倍率)两个分组</p><p style="margin-top: 16px; color: #10b981; font-weight: 600;">👉 点击左侧的"分组管理"开始</p></div>'
|
||||
},
|
||||
createGroup: {
|
||||
title: '➕ 创建新分组',
|
||||
@@ -3181,8 +3181,8 @@ export default {
|
||||
// User tour steps
|
||||
user: {
|
||||
welcome: {
|
||||
title: '👋 欢迎使用 Sub2API',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">您好!欢迎来到 Sub2API AI 服务平台。</p><p style="margin-bottom: 12px;"><b>🎯 快速开始:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>🔑 创建 API 密钥</li><li>📋 复制密钥到您的应用</li><li>🚀 开始使用 AI 服务</li></ul><p style="color: #10b981; font-weight: 600;">只需 1 分钟,让我们开始吧 →</p></div>',
|
||||
title: '👋 欢迎使用 TianShuAPI',
|
||||
description: '<div style="line-height: 1.8;"><p style="margin-bottom: 16px;">您好!欢迎来到 TianShuAPI AI 服务平台。</p><p style="margin-bottom: 12px;"><b>🎯 快速开始:</b></p><ul style="margin-left: 20px; margin-bottom: 16px;"><li>🔑 创建 API 密钥</li><li>📋 复制密钥到您的应用</li><li>🚀 开始使用 AI 服务</li></ul><p style="color: #10b981; font-weight: 600;">只需 1 分钟,让我们开始吧 →</p></div>',
|
||||
nextBtn: '开始 🚀',
|
||||
prevBtn: '跳过'
|
||||
},
|
||||
|
||||
@@ -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`
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export const useAppStore = defineStore('app', () => {
|
||||
// Public settings cache state
|
||||
const publicSettingsLoaded = ref<boolean>(false)
|
||||
const publicSettingsLoading = ref<boolean>(false)
|
||||
const siteName = ref<string>('Sub2API')
|
||||
const siteName = ref<string>('TianShuAPI')
|
||||
const siteLogo = ref<string>('')
|
||||
const siteVersion = ref<string>('')
|
||||
const contactInfo = ref<string>('')
|
||||
@@ -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 || ''
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Core Type Definitions for Sub2API Frontend
|
||||
* Core Type Definitions for TianShuAPI Frontend
|
||||
*/
|
||||
|
||||
// ==================== Common Types ====================
|
||||
|
||||
@@ -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 || '')
|
||||
|
||||
@@ -1000,7 +1000,7 @@ const form = reactive<SettingsForm>({
|
||||
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: '',
|
||||
|
||||
@@ -206,7 +206,7 @@ const hasRegisterData = ref<boolean>(false)
|
||||
// Public settings
|
||||
const turnstileEnabled = ref<boolean>(false)
|
||||
const turnstileSiteKey = ref<string>('')
|
||||
const siteName = ref<string>('Sub2API')
|
||||
const siteName = ref<string>('TianShuAPI')
|
||||
|
||||
// Turnstile for resend
|
||||
const turnstileRef = ref<InstanceType<typeof TurnstileWidget> | 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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -262,7 +262,7 @@ const registrationEnabled = ref<boolean>(true)
|
||||
const emailVerifyEnabled = ref<boolean>(false)
|
||||
const turnstileEnabled = ref<boolean>(false)
|
||||
const turnstileSiteKey = ref<string>('')
|
||||
const siteName = ref<string>('Sub2API')
|
||||
const siteName = ref<string>('TianShuAPI')
|
||||
const linuxdoOAuthEnabled = ref<boolean>(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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 │ │
|
||||
│ │ ┌────────────────────────────────┐ │ │
|
||||
|
||||
207
项目介绍.md
Normal file
207
项目介绍.md
Normal file
@@ -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
|
||||
---
|
||||
现在你可以先在服务器上部署了,后续官方有更新时,就按照上面的流程操作!
|
||||
Reference in New Issue
Block a user