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()
|
flag.Parse()
|
||||||
|
|
||||||
if *showVersion {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func runSetupServer() {
|
|||||||
// This allows users to run setup on a different address if needed
|
// This allows users to run setup on a different address if needed
|
||||||
addr := config.GetServerAddress()
|
addr := config.GetServerAddress()
|
||||||
log.Printf("Setup wizard available at http://%s", addr)
|
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 {
|
if err := r.Run(addr); err != nil {
|
||||||
log.Fatalf("Failed to start setup server: %v", err)
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Accept", "application/vnd.github.v3+json")
|
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)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
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) {
|
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(), "/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(), "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.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = w.Write([]byte(releaseJSON))
|
_, _ = w.Write([]byte(releaseJSON))
|
||||||
|
|||||||
@@ -272,14 +272,14 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
service.SettingKeySMTPUsername: "user",
|
service.SettingKeySMTPUsername: "user",
|
||||||
service.SettingKeySMTPPassword: "secret",
|
service.SettingKeySMTPPassword: "secret",
|
||||||
service.SettingKeySMTPFrom: "no-reply@example.com",
|
service.SettingKeySMTPFrom: "no-reply@example.com",
|
||||||
service.SettingKeySMTPFromName: "Sub2API",
|
service.SettingKeySMTPFromName: "TianShuAPI",
|
||||||
service.SettingKeySMTPUseTLS: "true",
|
service.SettingKeySMTPUseTLS: "true",
|
||||||
|
|
||||||
service.SettingKeyTurnstileEnabled: "true",
|
service.SettingKeyTurnstileEnabled: "true",
|
||||||
service.SettingKeyTurnstileSiteKey: "site-key",
|
service.SettingKeyTurnstileSiteKey: "site-key",
|
||||||
service.SettingKeyTurnstileSecretKey: "secret-key",
|
service.SettingKeyTurnstileSecretKey: "secret-key",
|
||||||
|
|
||||||
service.SettingKeySiteName: "Sub2API",
|
service.SettingKeySiteName: "TianShuAPI",
|
||||||
service.SettingKeySiteLogo: "",
|
service.SettingKeySiteLogo: "",
|
||||||
service.SettingKeySiteSubtitle: "Subtitle",
|
service.SettingKeySiteSubtitle: "Subtitle",
|
||||||
service.SettingKeyAPIBaseURL: "https://api.example.com",
|
service.SettingKeyAPIBaseURL: "https://api.example.com",
|
||||||
@@ -309,7 +309,7 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
"smtp_username": "user",
|
"smtp_username": "user",
|
||||||
"smtp_password_configured": true,
|
"smtp_password_configured": true,
|
||||||
"smtp_from_email": "no-reply@example.com",
|
"smtp_from_email": "no-reply@example.com",
|
||||||
"smtp_from_name": "Sub2API",
|
"smtp_from_name": "TianShuAPI",
|
||||||
"smtp_use_tls": true,
|
"smtp_use_tls": true,
|
||||||
"turnstile_enabled": true,
|
"turnstile_enabled": true,
|
||||||
"turnstile_site_key": "site-key",
|
"turnstile_site_key": "site-key",
|
||||||
@@ -322,7 +322,7 @@ func TestAPIContracts(t *testing.T) {
|
|||||||
"ops_realtime_monitoring_enabled": true,
|
"ops_realtime_monitoring_enabled": true,
|
||||||
"ops_query_mode_default": "auto",
|
"ops_query_mode_default": "auto",
|
||||||
"ops_metrics_interval_seconds": 60,
|
"ops_metrics_interval_seconds": 60,
|
||||||
"site_name": "Sub2API",
|
"site_name": "TianShuAPI",
|
||||||
"site_logo": "",
|
"site_logo": "",
|
||||||
"site_subtitle": "Subtitle",
|
"site_subtitle": "Subtitle",
|
||||||
"api_base_url": "https://api.example.com",
|
"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 {
|
if s.settingService != nil {
|
||||||
siteName = s.settingService.GetSiteName(ctx)
|
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 {
|
if s.settingService != nil {
|
||||||
siteName = s.settingService.GetSiteName(ctx)
|
siteName = s.settingService.GetSiteName(ctx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings
|
|||||||
EmailVerifyEnabled: settings[SettingKeyEmailVerifyEnabled] == "true",
|
EmailVerifyEnabled: settings[SettingKeyEmailVerifyEnabled] == "true",
|
||||||
TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true",
|
TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true",
|
||||||
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
||||||
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"),
|
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"),
|
||||||
SiteLogo: settings[SettingKeySiteLogo],
|
SiteLogo: settings[SettingKeySiteLogo],
|
||||||
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
||||||
APIBaseURL: settings[SettingKeyAPIBaseURL],
|
APIBaseURL: settings[SettingKeyAPIBaseURL],
|
||||||
@@ -247,7 +247,7 @@ func (s *SettingService) IsEmailVerifyEnabled(ctx context.Context) bool {
|
|||||||
func (s *SettingService) GetSiteName(ctx context.Context) string {
|
func (s *SettingService) GetSiteName(ctx context.Context) string {
|
||||||
value, err := s.settingRepo.GetValue(ctx, SettingKeySiteName)
|
value, err := s.settingRepo.GetValue(ctx, SettingKeySiteName)
|
||||||
if err != nil || value == "" {
|
if err != nil || value == "" {
|
||||||
return "Sub2API"
|
return "TianShuAPI"
|
||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
@@ -292,7 +292,7 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
|||||||
defaults := map[string]string{
|
defaults := map[string]string{
|
||||||
SettingKeyRegistrationEnabled: "true",
|
SettingKeyRegistrationEnabled: "true",
|
||||||
SettingKeyEmailVerifyEnabled: "false",
|
SettingKeyEmailVerifyEnabled: "false",
|
||||||
SettingKeySiteName: "Sub2API",
|
SettingKeySiteName: "TianShuAPI",
|
||||||
SettingKeySiteLogo: "",
|
SettingKeySiteLogo: "",
|
||||||
SettingKeyDefaultConcurrency: strconv.Itoa(s.cfg.Default.UserConcurrency),
|
SettingKeyDefaultConcurrency: strconv.Itoa(s.cfg.Default.UserConcurrency),
|
||||||
SettingKeyDefaultBalance: strconv.FormatFloat(s.cfg.Default.UserBalance, 'f', 8, 64),
|
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",
|
TurnstileEnabled: settings[SettingKeyTurnstileEnabled] == "true",
|
||||||
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
||||||
TurnstileSecretKeyConfigured: settings[SettingKeyTurnstileSecretKey] != "",
|
TurnstileSecretKeyConfigured: settings[SettingKeyTurnstileSecretKey] != "",
|
||||||
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"),
|
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "TianShuAPI"),
|
||||||
SiteLogo: settings[SettingKeySiteLogo],
|
SiteLogo: settings[SettingKeySiteLogo],
|
||||||
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
||||||
APIBaseURL: settings[SettingKeyAPIBaseURL],
|
APIBaseURL: settings[SettingKeyAPIBaseURL],
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func RunCLI() error {
|
|||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
fmt.Println("╔═══════════════════════════════════════════╗")
|
fmt.Println("╔═══════════════════════════════════════════╗")
|
||||||
fmt.Println("║ Sub2API Installation Wizard ║")
|
fmt.Println("║ TianShuAPI Installation Wizard ║")
|
||||||
fmt.Println("╚═══════════════════════════════════════════╝")
|
fmt.Println("╚═══════════════════════════════════════════╝")
|
||||||
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
|
* Central export point for all API modules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ import { ref, computed, onMounted } from 'vue'
|
|||||||
import { getPublicSettings } from '@/api/auth'
|
import { getPublicSettings } from '@/api/auth'
|
||||||
import { sanitizeUrl } from '@/utils/url'
|
import { sanitizeUrl } from '@/utils/url'
|
||||||
|
|
||||||
const siteName = ref('Sub2API')
|
const siteName = ref('TianShuAPI')
|
||||||
const siteLogo = ref('')
|
const siteLogo = ref('')
|
||||||
const siteSubtitle = ref('Subscription to API Conversion Platform')
|
const siteSubtitle = ref('Subscription to API Conversion Platform')
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ const currentYear = computed(() => new Date().getFullYear())
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
try {
|
try {
|
||||||
const settings = await getPublicSettings()
|
const settings = await getPublicSettings()
|
||||||
siteName.value = settings.site_name || 'Sub2API'
|
siteName.value = settings.site_name || 'TianShuAPI'
|
||||||
siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true })
|
siteLogo.value = sanitizeUrl(settings.site_logo || '', { allowRelative: true })
|
||||||
siteSubtitle.value = settings.site_subtitle || 'Subscription to API Conversion Platform'
|
siteSubtitle.value = settings.site_subtitle || 'Subscription to API Conversion Platform'
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Layout Components
|
# 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
|
## Components
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ export default {
|
|||||||
|
|
||||||
// Setup Wizard
|
// Setup Wizard
|
||||||
setup: {
|
setup: {
|
||||||
title: 'Sub2API Setup',
|
title: 'TianShuAPI Setup',
|
||||||
description: 'Configure your Sub2API instance',
|
description: 'Configure your TianShuAPI instance',
|
||||||
database: {
|
database: {
|
||||||
title: 'Database Configuration',
|
title: 'Database Configuration',
|
||||||
description: 'Connect to your PostgreSQL database',
|
description: 'Connect to your PostgreSQL database',
|
||||||
@@ -2686,7 +2686,7 @@ export default {
|
|||||||
secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.' },
|
secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.' },
|
||||||
linuxdo: {
|
linuxdo: {
|
||||||
title: 'LinuxDo Connect Login',
|
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',
|
enable: 'Enable LinuxDo Login',
|
||||||
enableHint: 'Show LinuxDo login on the login/register pages',
|
enableHint: 'Show LinuxDo login on the login/register pages',
|
||||||
clientId: 'Client ID',
|
clientId: 'Client ID',
|
||||||
@@ -2716,7 +2716,7 @@ export default {
|
|||||||
title: 'Site Settings',
|
title: 'Site Settings',
|
||||||
description: 'Customize site branding',
|
description: 'Customize site branding',
|
||||||
siteName: 'Site Name',
|
siteName: 'Site Name',
|
||||||
siteNamePlaceholder: 'Sub2API',
|
siteNamePlaceholder: 'TianShuAPI',
|
||||||
siteNameHint: 'Displayed in emails and page titles',
|
siteNameHint: 'Displayed in emails and page titles',
|
||||||
siteSubtitle: 'Site Subtitle',
|
siteSubtitle: 'Site Subtitle',
|
||||||
siteSubtitlePlaceholder: 'Subscription to API Conversion Platform',
|
siteSubtitlePlaceholder: 'Subscription to API Conversion Platform',
|
||||||
@@ -2762,7 +2762,7 @@ export default {
|
|||||||
fromEmail: 'From Email',
|
fromEmail: 'From Email',
|
||||||
fromEmailPlaceholder: "noreply{'@'}example.com",
|
fromEmailPlaceholder: "noreply{'@'}example.com",
|
||||||
fromName: 'From Name',
|
fromName: 'From Name',
|
||||||
fromNamePlaceholder: 'Sub2API',
|
fromNamePlaceholder: 'TianShuAPI',
|
||||||
useTls: 'Use TLS',
|
useTls: 'Use TLS',
|
||||||
useTlsHint: 'Enable TLS encryption for SMTP connection'
|
useTlsHint: 'Enable TLS encryption for SMTP connection'
|
||||||
},
|
},
|
||||||
@@ -2931,14 +2931,14 @@ export default {
|
|||||||
// Admin tour steps
|
// Admin tour steps
|
||||||
admin: {
|
admin: {
|
||||||
welcome: {
|
welcome: {
|
||||||
title: '👋 Welcome to Sub2API',
|
title: '👋 Welcome to TianShuAPI',
|
||||||
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>',
|
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 🚀',
|
nextBtn: 'Start Setup 🚀',
|
||||||
prevBtn: 'Skip'
|
prevBtn: 'Skip'
|
||||||
},
|
},
|
||||||
groupManage: {
|
groupManage: {
|
||||||
title: '📦 Step 1: Group Management',
|
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: {
|
createGroup: {
|
||||||
title: '➕ Create New Group',
|
title: '➕ Create New Group',
|
||||||
@@ -3031,8 +3031,8 @@ export default {
|
|||||||
// User tour steps
|
// User tour steps
|
||||||
user: {
|
user: {
|
||||||
welcome: {
|
welcome: {
|
||||||
title: '👋 Welcome to Sub2API',
|
title: '👋 Welcome to TianShuAPI',
|
||||||
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>',
|
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 🚀',
|
nextBtn: 'Start 🚀',
|
||||||
prevBtn: 'Skip'
|
prevBtn: 'Skip'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ export default {
|
|||||||
|
|
||||||
// Setup Wizard
|
// Setup Wizard
|
||||||
setup: {
|
setup: {
|
||||||
title: 'Sub2API 安装向导',
|
title: 'TianShuAPI 安装向导',
|
||||||
description: '配置您的 Sub2API 实例',
|
description: '配置您的 TianShuAPI 实例',
|
||||||
database: {
|
database: {
|
||||||
title: '数据库配置',
|
title: '数据库配置',
|
||||||
description: '连接到您的 PostgreSQL 数据库',
|
description: '连接到您的 PostgreSQL 数据库',
|
||||||
@@ -2840,7 +2840,7 @@ export default {
|
|||||||
secretKeyConfiguredHint: '密钥已配置,留空以保留当前值。' },
|
secretKeyConfiguredHint: '密钥已配置,留空以保留当前值。' },
|
||||||
linuxdo: {
|
linuxdo: {
|
||||||
title: 'LinuxDo Connect 登录',
|
title: 'LinuxDo Connect 登录',
|
||||||
description: '配置 LinuxDo Connect OAuth,用于 Sub2API 用户登录',
|
description: '配置 LinuxDo Connect OAuth,用于 TianShuAPI 用户登录',
|
||||||
enable: '启用 LinuxDo 登录',
|
enable: '启用 LinuxDo 登录',
|
||||||
enableHint: '在登录/注册页面显示 LinuxDo 登录入口',
|
enableHint: '在登录/注册页面显示 LinuxDo 登录入口',
|
||||||
clientId: 'Client ID',
|
clientId: 'Client ID',
|
||||||
@@ -2870,7 +2870,7 @@ export default {
|
|||||||
description: '自定义站点品牌',
|
description: '自定义站点品牌',
|
||||||
siteName: '站点名称',
|
siteName: '站点名称',
|
||||||
siteNameHint: '显示在邮件和页面标题中',
|
siteNameHint: '显示在邮件和页面标题中',
|
||||||
siteNamePlaceholder: 'Sub2API',
|
siteNamePlaceholder: 'TianShuAPI',
|
||||||
siteSubtitle: '站点副标题',
|
siteSubtitle: '站点副标题',
|
||||||
siteSubtitleHint: '显示在登录和注册页面',
|
siteSubtitleHint: '显示在登录和注册页面',
|
||||||
siteSubtitlePlaceholder: '订阅转 API 转换平台',
|
siteSubtitlePlaceholder: '订阅转 API 转换平台',
|
||||||
@@ -2914,7 +2914,7 @@ export default {
|
|||||||
fromEmail: '发件人邮箱',
|
fromEmail: '发件人邮箱',
|
||||||
fromEmailPlaceholder: "noreply{'@'}example.com",
|
fromEmailPlaceholder: "noreply{'@'}example.com",
|
||||||
fromName: '发件人名称',
|
fromName: '发件人名称',
|
||||||
fromNamePlaceholder: 'Sub2API',
|
fromNamePlaceholder: 'TianShuAPI',
|
||||||
useTls: '使用 TLS',
|
useTls: '使用 TLS',
|
||||||
useTlsHint: '为 SMTP 连接启用 TLS 加密'
|
useTlsHint: '为 SMTP 连接启用 TLS 加密'
|
||||||
},
|
},
|
||||||
@@ -3081,14 +3081,14 @@ export default {
|
|||||||
// Admin tour steps
|
// Admin tour steps
|
||||||
admin: {
|
admin: {
|
||||||
welcome: {
|
welcome: {
|
||||||
title: '👋 欢迎使用 Sub2API',
|
title: '👋 欢迎使用 TianShuAPI',
|
||||||
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>',
|
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: '开始配置 🚀',
|
nextBtn: '开始配置 🚀',
|
||||||
prevBtn: '跳过'
|
prevBtn: '跳过'
|
||||||
},
|
},
|
||||||
groupManage: {
|
groupManage: {
|
||||||
title: '📦 第一步:分组管理',
|
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: {
|
createGroup: {
|
||||||
title: '➕ 创建新分组',
|
title: '➕ 创建新分组',
|
||||||
@@ -3181,8 +3181,8 @@ export default {
|
|||||||
// User tour steps
|
// User tour steps
|
||||||
user: {
|
user: {
|
||||||
welcome: {
|
welcome: {
|
||||||
title: '👋 欢迎使用 Sub2API',
|
title: '👋 欢迎使用 TianShuAPI',
|
||||||
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>',
|
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: '开始 🚀',
|
nextBtn: '开始 🚀',
|
||||||
prevBtn: '跳过'
|
prevBtn: '跳过'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const appStore = useAppStore()
|
|||||||
appStore.initFromInjectedConfig()
|
appStore.initFromInjectedConfig()
|
||||||
|
|
||||||
// Set document title immediately after config is loaded
|
// 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`
|
document.title = `${appStore.siteName} - AI API Gateway`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Overview
|
## 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
|
## 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
|
* Defines all application routes with lazy loading and navigation guards
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -347,7 +347,7 @@ router.beforeEach((to, _from, next) => {
|
|||||||
|
|
||||||
// Set page title
|
// Set page title
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const siteName = appStore.siteName || 'Sub2API'
|
const siteName = appStore.siteName || 'TianShuAPI'
|
||||||
if (to.meta.title) {
|
if (to.meta.title) {
|
||||||
document.title = `${to.meta.title} - ${siteName}`
|
document.title = `${to.meta.title} - ${siteName}`
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Pinia Stores Documentation
|
# 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
|
## Stores Overview
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
// Public settings cache state
|
// Public settings cache state
|
||||||
const publicSettingsLoaded = ref<boolean>(false)
|
const publicSettingsLoaded = ref<boolean>(false)
|
||||||
const publicSettingsLoading = ref<boolean>(false)
|
const publicSettingsLoading = ref<boolean>(false)
|
||||||
const siteName = ref<string>('Sub2API')
|
const siteName = ref<string>('TianShuAPI')
|
||||||
const siteLogo = ref<string>('')
|
const siteLogo = ref<string>('')
|
||||||
const siteVersion = ref<string>('')
|
const siteVersion = ref<string>('')
|
||||||
const contactInfo = ref<string>('')
|
const contactInfo = ref<string>('')
|
||||||
@@ -284,7 +284,7 @@ export const useAppStore = defineStore('app', () => {
|
|||||||
*/
|
*/
|
||||||
function applySettings(config: PublicSettings): void {
|
function applySettings(config: PublicSettings): void {
|
||||||
cachedPublicSettings.value = config
|
cachedPublicSettings.value = config
|
||||||
siteName.value = config.site_name || 'Sub2API'
|
siteName.value = config.site_name || 'TianShuAPI'
|
||||||
siteLogo.value = config.site_logo || ''
|
siteLogo.value = config.site_logo || ''
|
||||||
siteVersion.value = config.version || ''
|
siteVersion.value = config.version || ''
|
||||||
contactInfo.value = config.contact_info || ''
|
contactInfo.value = config.contact_info || ''
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Core Type Definitions for Sub2API Frontend
|
* Core Type Definitions for TianShuAPI Frontend
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ==================== Common Types ====================
|
// ==================== Common Types ====================
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ const authStore = useAuthStore()
|
|||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
// Site settings - directly from appStore (already initialized from injected config)
|
// 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 siteLogo = computed(() => appStore.cachedPublicSettings?.site_logo || appStore.siteLogo || '')
|
||||||
const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'AI API Gateway Platform')
|
const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'AI API Gateway Platform')
|
||||||
const docUrl = computed(() => appStore.cachedPublicSettings?.doc_url || appStore.docUrl || '')
|
const docUrl = computed(() => appStore.cachedPublicSettings?.doc_url || appStore.docUrl || '')
|
||||||
|
|||||||
@@ -1000,7 +1000,7 @@ const form = reactive<SettingsForm>({
|
|||||||
email_verify_enabled: false,
|
email_verify_enabled: false,
|
||||||
default_balance: 0,
|
default_balance: 0,
|
||||||
default_concurrency: 1,
|
default_concurrency: 1,
|
||||||
site_name: 'Sub2API',
|
site_name: 'TianShuAPI',
|
||||||
site_logo: '',
|
site_logo: '',
|
||||||
site_subtitle: 'Subscription to API Conversion Platform',
|
site_subtitle: 'Subscription to API Conversion Platform',
|
||||||
api_base_url: '',
|
api_base_url: '',
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ const hasRegisterData = ref<boolean>(false)
|
|||||||
// Public settings
|
// Public settings
|
||||||
const turnstileEnabled = ref<boolean>(false)
|
const turnstileEnabled = ref<boolean>(false)
|
||||||
const turnstileSiteKey = ref<string>('')
|
const turnstileSiteKey = ref<string>('')
|
||||||
const siteName = ref<string>('Sub2API')
|
const siteName = ref<string>('TianShuAPI')
|
||||||
|
|
||||||
// Turnstile for resend
|
// Turnstile for resend
|
||||||
const turnstileRef = ref<InstanceType<typeof TurnstileWidget> | null>(null)
|
const turnstileRef = ref<InstanceType<typeof TurnstileWidget> | null>(null)
|
||||||
@@ -241,7 +241,7 @@ onMounted(async () => {
|
|||||||
const settings = await getPublicSettings()
|
const settings = await getPublicSettings()
|
||||||
turnstileEnabled.value = settings.turnstile_enabled
|
turnstileEnabled.value = settings.turnstile_enabled
|
||||||
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
||||||
siteName.value = settings.site_name || 'Sub2API'
|
siteName.value = settings.site_name || 'TianShuAPI'
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load public settings:', error)
|
console.error('Failed to load public settings:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Authentication Views
|
# 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
|
## Components
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ const registrationEnabled = ref<boolean>(true)
|
|||||||
const emailVerifyEnabled = ref<boolean>(false)
|
const emailVerifyEnabled = ref<boolean>(false)
|
||||||
const turnstileEnabled = ref<boolean>(false)
|
const turnstileEnabled = ref<boolean>(false)
|
||||||
const turnstileSiteKey = ref<string>('')
|
const turnstileSiteKey = ref<string>('')
|
||||||
const siteName = ref<string>('Sub2API')
|
const siteName = ref<string>('TianShuAPI')
|
||||||
const linuxdoOAuthEnabled = ref<boolean>(false)
|
const linuxdoOAuthEnabled = ref<boolean>(false)
|
||||||
|
|
||||||
// Turnstile
|
// Turnstile
|
||||||
@@ -308,7 +308,7 @@ onMounted(async () => {
|
|||||||
emailVerifyEnabled.value = settings.email_verify_enabled
|
emailVerifyEnabled.value = settings.email_verify_enabled
|
||||||
turnstileEnabled.value = settings.turnstile_enabled
|
turnstileEnabled.value = settings.turnstile_enabled
|
||||||
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
turnstileSiteKey.value = settings.turnstile_site_key || ''
|
||||||
siteName.value = settings.site_name || 'Sub2API'
|
siteName.value = settings.site_name || 'TianShuAPI'
|
||||||
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
linuxdoOAuthEnabled.value = settings.linuxdo_oauth_enabled
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load public settings:', error)
|
console.error('Failed to load public settings:', error)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Authentication Views Usage Examples
|
# 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
|
## Quick Start
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ This document provides practical examples of how to use the authentication views
|
|||||||
// - On success:
|
// - On success:
|
||||||
// - Token stored in localStorage
|
// - Token stored in localStorage
|
||||||
// - User data stored in state
|
// - User data stored in state
|
||||||
// - Success toast: "Account created successfully! Welcome to Sub2API."
|
// - Success toast: "Account created successfully! Welcome to TianShuAPI."
|
||||||
// - Redirect to /dashboard
|
// - Redirect to /dashboard
|
||||||
// - On error:
|
// - On error:
|
||||||
// - Error message displayed inline
|
// - 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" │ │
|
│ │ "Subscription to API Conversion" │ │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ └─────────────────────────────────────┘ │
|
│ └─────────────────────────────────────┘ │
|
||||||
@@ -39,7 +39,7 @@ Centered: Both horizontally and vertically
|
|||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────┐
|
||||||
│ │
|
│ │
|
||||||
│ 🔷 Sub2API │
|
│ 🔷 TianShuAPI │
|
||||||
│ Subscription to API Conversion Platform │
|
│ Subscription to API Conversion Platform │
|
||||||
│ │
|
│ │
|
||||||
│ ┌─────────────────────────────────────┐ │
|
│ ┌─────────────────────────────────────┐ │
|
||||||
@@ -133,13 +133,13 @@ Centered: Both horizontally and vertically
|
|||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────┐
|
||||||
│ │
|
│ │
|
||||||
│ 🔷 Sub2API │
|
│ 🔷 TianShuAPI │
|
||||||
│ Subscription to API Conversion Platform │
|
│ Subscription to API Conversion Platform │
|
||||||
│ │
|
│ │
|
||||||
│ ┌─────────────────────────────────────┐ │
|
│ ┌─────────────────────────────────────┐ │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ │ Create Account │ │
|
│ │ Create Account │ │
|
||||||
│ │ Sign up to start using Sub2API │ │
|
│ │ Sign up to start using TianShuAPI │ │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ │ Username │ │
|
│ │ 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