2026-01-23 16:31:54 +08:00
|
|
|
|
/**
|
2026-01-25 19:37:59 +08:00
|
|
|
|
* 数据库初始化/升级API
|
|
|
|
|
|
* 用于添加缺失的字段,确保表结构完整
|
2026-01-23 16:31:54 +08:00
|
|
|
|
*/
|
|
|
|
|
|
|
2026-01-25 19:37:59 +08:00
|
|
|
|
import { NextRequest, NextResponse } from 'next/server'
|
|
|
|
|
|
import { query } from '@/lib/db'
|
2026-01-21 15:49:12 +08:00
|
|
|
|
|
2026-01-23 16:31:54 +08:00
|
|
|
|
/**
|
2026-01-25 19:37:59 +08:00
|
|
|
|
* GET - 初始化/升级数据库表结构
|
2026-01-23 16:31:54 +08:00
|
|
|
|
*/
|
2026-01-25 19:37:59 +08:00
|
|
|
|
export async function GET(request: NextRequest) {
|
|
|
|
|
|
const results: string[] = []
|
|
|
|
|
|
|
2026-01-21 15:49:12 +08:00
|
|
|
|
try {
|
2026-01-25 19:37:59 +08:00
|
|
|
|
console.log('[DB Init] 开始检查并升级数据库结构...')
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 检查users表是否存在
|
|
|
|
|
|
try {
|
|
|
|
|
|
await query('SELECT 1 FROM users LIMIT 1')
|
|
|
|
|
|
results.push('✅ users表已存在')
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
// 创建users表
|
|
|
|
|
|
await query(`
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
|
|
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
|
|
|
|
open_id VARCHAR(100) UNIQUE,
|
|
|
|
|
|
session_key VARCHAR(100),
|
|
|
|
|
|
nickname VARCHAR(100),
|
|
|
|
|
|
avatar VARCHAR(500),
|
|
|
|
|
|
phone VARCHAR(20),
|
|
|
|
|
|
password VARCHAR(100),
|
|
|
|
|
|
wechat_id VARCHAR(100),
|
|
|
|
|
|
referral_code VARCHAR(20) UNIQUE,
|
|
|
|
|
|
referred_by VARCHAR(50),
|
|
|
|
|
|
purchased_sections JSON DEFAULT '[]',
|
|
|
|
|
|
has_full_book BOOLEAN DEFAULT FALSE,
|
|
|
|
|
|
is_admin BOOLEAN DEFAULT FALSE,
|
|
|
|
|
|
earnings DECIMAL(10,2) DEFAULT 0,
|
|
|
|
|
|
pending_earnings DECIMAL(10,2) DEFAULT 0,
|
|
|
|
|
|
withdrawn_earnings DECIMAL(10,2) DEFAULT 0,
|
|
|
|
|
|
referral_count INT DEFAULT 0,
|
|
|
|
|
|
match_count_today INT DEFAULT 0,
|
|
|
|
|
|
last_match_date DATE,
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
|
|
|
|
`)
|
|
|
|
|
|
results.push('✅ 创建users表')
|
2026-01-23 16:31:54 +08:00
|
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 修改open_id字段允许NULL(后台添加用户时可能没有openId)
|
|
|
|
|
|
try {
|
|
|
|
|
|
await query('ALTER TABLE users MODIFY COLUMN open_id VARCHAR(100) NULL')
|
|
|
|
|
|
results.push('✅ 修改open_id允许NULL')
|
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
|
results.push(`⏭️ open_id字段: ${e.message?.includes('Duplicate') ? '已处理' : e.message}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 添加可能缺失的字段(用ALTER TABLE)
|
|
|
|
|
|
const columnsToAdd = [
|
|
|
|
|
|
{ name: 'password', type: 'VARCHAR(100)' },
|
|
|
|
|
|
{ name: 'session_key', type: 'VARCHAR(100)' },
|
|
|
|
|
|
{ name: 'referred_by', type: 'VARCHAR(50)' },
|
|
|
|
|
|
{ name: 'is_admin', type: 'BOOLEAN DEFAULT FALSE' },
|
|
|
|
|
|
{ name: 'match_count_today', type: 'INT DEFAULT 0' },
|
|
|
|
|
|
{ name: 'last_match_date', type: 'DATE' },
|
|
|
|
|
|
{ name: 'withdrawn_earnings', type: 'DECIMAL(10,2) DEFAULT 0' },
|
|
|
|
|
|
{ name: 'avatar', type: 'VARCHAR(500)' },
|
|
|
|
|
|
{ name: 'wechat_id', type: 'VARCHAR(100)' }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
for (const col of columnsToAdd) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 先检查列是否存在
|
|
|
|
|
|
const checkResult = await query(`
|
|
|
|
|
|
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
|
|
|
|
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = ?
|
|
|
|
|
|
`, [col.name]) as any[]
|
|
|
|
|
|
|
|
|
|
|
|
if (checkResult.length === 0) {
|
|
|
|
|
|
// 列不存在,添加
|
|
|
|
|
|
await query(`ALTER TABLE users ADD COLUMN ${col.name} ${col.type}`)
|
|
|
|
|
|
results.push(`✅ 添加字段: ${col.name}`)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
results.push(`⏭️ 字段已存在: ${col.name}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
|
results.push(`⚠️ 处理字段${col.name}时出错: ${e.message}`)
|
2026-01-23 16:31:54 +08:00
|
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
|
}
|
2026-01-23 16:31:54 +08:00
|
|
|
|
|
2026-01-25 19:37:59 +08:00
|
|
|
|
// 3. 添加索引(如果不存在)
|
|
|
|
|
|
const indexesToAdd = [
|
|
|
|
|
|
{ name: 'idx_open_id', column: 'open_id' },
|
|
|
|
|
|
{ name: 'idx_phone', column: 'phone' },
|
|
|
|
|
|
{ name: 'idx_referral_code', column: 'referral_code' },
|
|
|
|
|
|
{ name: 'idx_referred_by', column: 'referred_by' }
|
|
|
|
|
|
]
|
2026-01-23 16:31:54 +08:00
|
|
|
|
|
2026-01-25 19:37:59 +08:00
|
|
|
|
for (const idx of indexesToAdd) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const checkResult = await query(`
|
|
|
|
|
|
SHOW INDEX FROM users WHERE Key_name = ?
|
|
|
|
|
|
`, [idx.name]) as any[]
|
|
|
|
|
|
|
|
|
|
|
|
if (checkResult.length === 0) {
|
|
|
|
|
|
await query(`CREATE INDEX ${idx.name} ON users(${idx.column})`)
|
|
|
|
|
|
results.push(`✅ 添加索引: ${idx.name}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
|
// 忽略索引错误
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-23 16:31:54 +08:00
|
|
|
|
|
2026-01-25 19:37:59 +08:00
|
|
|
|
// 4. 检查提现记录表
|
|
|
|
|
|
try {
|
|
|
|
|
|
await query('SELECT 1 FROM withdrawals LIMIT 1')
|
|
|
|
|
|
results.push('✅ withdrawals表已存在')
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
await query(`
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS withdrawals (
|
|
|
|
|
|
id VARCHAR(50) PRIMARY KEY,
|
|
|
|
|
|
user_id VARCHAR(50) NOT NULL,
|
|
|
|
|
|
amount DECIMAL(10,2) NOT NULL,
|
|
|
|
|
|
status ENUM('pending', 'processing', 'success', 'failed') DEFAULT 'pending',
|
|
|
|
|
|
wechat_openid VARCHAR(100),
|
|
|
|
|
|
transaction_id VARCHAR(100),
|
|
|
|
|
|
error_message VARCHAR(500),
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
processed_at TIMESTAMP,
|
|
|
|
|
|
INDEX idx_user_id (user_id),
|
|
|
|
|
|
INDEX idx_status (status)
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
|
|
|
|
`)
|
|
|
|
|
|
results.push('✅ 创建withdrawals表')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 检查系统配置表
|
|
|
|
|
|
try {
|
|
|
|
|
|
await query('SELECT 1 FROM system_config LIMIT 1')
|
|
|
|
|
|
results.push('✅ system_config表已存在')
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
await query(`
|
|
|
|
|
|
CREATE TABLE IF NOT EXISTS system_config (
|
|
|
|
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
config_key VARCHAR(100) UNIQUE NOT NULL,
|
|
|
|
|
|
config_value JSON NOT NULL,
|
|
|
|
|
|
description VARCHAR(200),
|
|
|
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
|
|
|
|
`)
|
|
|
|
|
|
results.push('✅ 创建system_config表')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[DB Init] 数据库升级完成')
|
2026-01-23 16:31:54 +08:00
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({
|
|
|
|
|
|
success: true,
|
2026-01-25 19:37:59 +08:00
|
|
|
|
message: '数据库初始化/升级完成',
|
|
|
|
|
|
results
|
2026-01-23 16:31:54 +08:00
|
|
|
|
})
|
2026-01-25 19:37:59 +08:00
|
|
|
|
|
2026-01-23 16:31:54 +08:00
|
|
|
|
} catch (error) {
|
2026-01-25 19:37:59 +08:00
|
|
|
|
console.error('[DB Init] 错误:', error)
|
2026-01-23 16:31:54 +08:00
|
|
|
|
return NextResponse.json({
|
|
|
|
|
|
success: false,
|
2026-01-25 19:37:59 +08:00
|
|
|
|
error: '数据库初始化失败: ' + (error as Error).message,
|
|
|
|
|
|
results
|
2026-01-23 16:31:54 +08:00
|
|
|
|
}, { status: 500 })
|
|
|
|
|
|
}
|
2026-01-25 19:37:59 +08:00
|
|
|
|
}
|