backend v2.1: 公告管理功能 + 系统重构
- 新增 Announcement 数据模型,支持公告的增删改查 - 后台管理新增"公告管理"Tab(创建/编辑/删除/启用禁用) - 客户端 /api/announcement 改为从数据库读取 - 账号服务重构,新增无感换号、自动分析等功能 - 新增后台任务调度器、数据库迁移脚本 - Schema/Service/Config 全面升级至 v2.1 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
202
backend/migrations/upgrade_v2.sql
Normal file
202
backend/migrations/upgrade_v2.sql
Normal file
@@ -0,0 +1,202 @@
|
||||
-- 蜂鸟Pro v2.1 数据库迁移脚本
|
||||
-- 从旧版本迁移到新的数据模型
|
||||
|
||||
-- ==================== cursor_accounts 表迁移 ====================
|
||||
|
||||
-- 1. 重命名 access_token 为 token (如果存在旧列名)
|
||||
-- 注意: 如果已经是 token 列名则跳过
|
||||
SET @exist_access_token := (
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'cursor_accounts'
|
||||
AND COLUMN_NAME = 'access_token'
|
||||
);
|
||||
|
||||
SET @sql = IF(@exist_access_token > 0,
|
||||
'ALTER TABLE cursor_accounts CHANGE COLUMN access_token token TEXT NOT NULL COMMENT "认证Token (user_id::jwt)"',
|
||||
'SELECT 1'
|
||||
);
|
||||
PREPARE stmt FROM @sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 2. 添加新列 (如果不存在)
|
||||
|
||||
-- account_type 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'account_type');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN account_type ENUM("free_trial", "pro", "free", "business", "unknown") DEFAULT "unknown" COMMENT "账号类型"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- membership_type 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'membership_type');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN membership_type VARCHAR(50) NULL COMMENT "会员类型原始值"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- billing_cycle_start 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'billing_cycle_start');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN billing_cycle_start DATETIME NULL COMMENT "计费周期开始"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- billing_cycle_end 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'billing_cycle_end');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN billing_cycle_end DATETIME NULL COMMENT "计费周期结束"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- trial_days_remaining 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'trial_days_remaining');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN trial_days_remaining INT DEFAULT 0 COMMENT "试用剩余天数"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- usage_limit 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'usage_limit');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN usage_limit INT DEFAULT 0 COMMENT "用量上限"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- usage_used 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'usage_used');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN usage_used INT DEFAULT 0 COMMENT "已用用量"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- usage_remaining 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'usage_remaining');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN usage_remaining INT DEFAULT 0 COMMENT "剩余用量"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- usage_percent 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'usage_percent');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN usage_percent DECIMAL(5,2) DEFAULT 0 COMMENT "用量百分比"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- total_requests 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'total_requests');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN total_requests INT DEFAULT 0 COMMENT "总请求次数"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- total_input_tokens 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'total_input_tokens');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN total_input_tokens BIGINT DEFAULT 0 COMMENT "总输入Token"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- total_output_tokens 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'total_output_tokens');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN total_output_tokens BIGINT DEFAULT 0 COMMENT "总输出Token"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- total_cost_cents 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'total_cost_cents');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN total_cost_cents DECIMAL(10,2) DEFAULT 0 COMMENT "总花费(美分)"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- locked_by_key_id 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'locked_by_key_id');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN locked_by_key_id INT NULL COMMENT "被哪个激活码锁定"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- locked_at 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'locked_at');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN locked_at DATETIME NULL COMMENT "锁定时间"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- last_analyzed_at 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'last_analyzed_at');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN last_analyzed_at DATETIME NULL COMMENT "最后分析时间"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- analyze_error 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cursor_accounts' AND COLUMN_NAME = 'analyze_error');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE cursor_accounts ADD COLUMN analyze_error VARCHAR(500) NULL COMMENT "分析错误信息"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 3. 更新状态枚举值 (旧的 active -> available, expired -> exhausted)
|
||||
UPDATE cursor_accounts SET status = 'available' WHERE status = 'active';
|
||||
UPDATE cursor_accounts SET status = 'exhausted' WHERE status = 'expired';
|
||||
|
||||
-- 4. 修改 status 列的枚举类型
|
||||
ALTER TABLE cursor_accounts MODIFY COLUMN status ENUM('pending', 'analyzing', 'available', 'in_use', 'exhausted', 'invalid', 'disabled') DEFAULT 'pending' COMMENT '账号状态';
|
||||
|
||||
-- 5. 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_cursor_accounts_status ON cursor_accounts(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_cursor_accounts_account_type ON cursor_accounts(account_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_cursor_accounts_locked_by_key_id ON cursor_accounts(locked_by_key_id);
|
||||
|
||||
-- ==================== activation_keys 表迁移 ====================
|
||||
|
||||
-- 添加新列 (如果不存在)
|
||||
|
||||
-- master_key_id 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'master_key_id');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN master_key_id INT NULL COMMENT "主密钥ID"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- merged_count 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'merged_count');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN merged_count INT DEFAULT 0 COMMENT "已合并的子密钥数量"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- merged_at 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'merged_at');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN merged_at DATETIME NULL COMMENT "合并时间"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- duration_days 列 (旧版可能是 valid_days)
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'duration_days');
|
||||
SET @exist_valid_days := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'valid_days');
|
||||
SET @sql = IF(@exist = 0 AND @exist_valid_days > 0,
|
||||
'ALTER TABLE activation_keys CHANGE COLUMN valid_days duration_days INT DEFAULT 30 COMMENT "该密钥贡献的天数"',
|
||||
IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN duration_days INT DEFAULT 30 COMMENT "该密钥贡献的天数"', 'SELECT 1')
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- quota_contribution 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'quota_contribution');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN quota_contribution INT DEFAULT 500 COMMENT "该密钥贡献的积分"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- seamless_enabled 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'seamless_enabled');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN seamless_enabled BOOLEAN DEFAULT FALSE COMMENT "是否启用无感换号"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- last_active_at 列
|
||||
SET @exist := (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activation_keys' AND COLUMN_NAME = 'last_active_at');
|
||||
SET @sql = IF(@exist = 0, 'ALTER TABLE activation_keys ADD COLUMN last_active_at DATETIME NULL COMMENT "最后活跃时间"', 'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- 更新密钥状态枚举
|
||||
ALTER TABLE activation_keys MODIFY COLUMN status ENUM('unused', 'active', 'expired', 'disabled') DEFAULT 'unused' COMMENT '状态';
|
||||
|
||||
-- 更新套餐类型枚举 (free -> auto)
|
||||
UPDATE activation_keys SET membership_type = 'auto' WHERE membership_type = 'free';
|
||||
ALTER TABLE activation_keys MODIFY COLUMN membership_type ENUM('auto', 'pro') DEFAULT 'pro' COMMENT '套餐类型';
|
||||
|
||||
-- 添加索引
|
||||
CREATE INDEX IF NOT EXISTS idx_activation_keys_master_key_id ON activation_keys(master_key_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_activation_keys_device_id ON activation_keys(device_id);
|
||||
|
||||
-- ==================== global_settings 表 - 添加自动检测开关设置 ====================
|
||||
|
||||
-- 确保 global_settings 表存在
|
||||
CREATE TABLE IF NOT EXISTS global_settings (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
`key` VARCHAR(100) UNIQUE NOT NULL COMMENT '设置键',
|
||||
value VARCHAR(500) NOT NULL COMMENT '设置值',
|
||||
value_type VARCHAR(20) DEFAULT 'string' COMMENT '值类型',
|
||||
description VARCHAR(500) NULL COMMENT '描述',
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 添加自动检测开关设置
|
||||
INSERT INTO global_settings (`key`, value, value_type, description) VALUES
|
||||
('auto_analyze_enabled', 'false', 'bool', '是否启用自动账号分析'),
|
||||
('auto_switch_enabled', 'true', 'bool', '是否启用自动换号'),
|
||||
('account_analyze_interval', '300', 'int', '账号分析间隔(秒)'),
|
||||
('account_analyze_batch_size', '10', 'int', '每批分析账号数量'),
|
||||
('auto_switch_threshold', '98', 'int', 'Auto池自动换号阈值(用量百分比)'),
|
||||
('pro_switch_threshold', '98', 'int', 'Pro池自动换号阈值(用量百分比)'),
|
||||
('max_switch_per_day', '50', 'int', '每日最大换号次数'),
|
||||
('auto_daily_switches', '999', 'int', 'Auto密钥每日换号次数限制'),
|
||||
('pro_quota_per_switch', '1', 'int', 'Pro密钥每次换号消耗积分')
|
||||
ON DUPLICATE KEY UPDATE description = VALUES(description);
|
||||
|
||||
-- ==================== 完成 ====================
|
||||
SELECT '数据库迁移完成!' AS message;
|
||||
Reference in New Issue
Block a user