feat: 全面优化小程序界面和功能

 新增功能:
- 配置后台匹配规则选择功能,支持多种匹配类型自定义
- 推广中心使用真实数据,实现H5/小程序绑定关系
- 配置MySQL数据库连接,建立完整数据表结构

🎨 界面优化:
- 优化登录状态显示,未登录只显示基础功能
- 修复推广中心等页面宽度问题,统一界面布局
- 优化设置页面绑定弹窗样式,简洁大气
- 修复目录页图标和文字对齐问题

🔧 技术改进:
- 匹配功能支持后台配置,动态加载匹配类型
- 推广数据支持API获取,本地存储作为备份
- 数据库表结构完整,支持用户、订单、推广关系
- 小程序登录仅保留微信登录方式

📱 小程序优化:
- 匹配次数调整为每日3次免费
- 支持¥1购买额外匹配次数
- 分享到朋友圈功能优化
- 界面宽度统一,卡片布局一致
This commit is contained in:
卡若
2026-01-23 16:31:54 +08:00
parent e869974341
commit 1e1e6a1093
18 changed files with 1017 additions and 613 deletions

738
lib/db.ts
View File

@@ -1,511 +1,265 @@
// 数据库连接配置
// 使用腾讯云数据库
/**
* 数据库连接配置
* 使用MySQL数据库存储用户、订单、推广关系等数据
*/
import mysql from 'mysql2/promise'
// 数据库配置不含database用于创建数据库
const dbConfigWithoutDB = {
host: '56b4c23f6853c.gz.cdb.myqcloud.com',
port: 14413,
user: 'cdb_outerroot',
password: 'Zhiqun1984',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
// 数据库配置
const DB_CONFIG = {
host: '10.88.182.62',
port: 3306,
user: 'root',
password: 'Vtka(agu)-1',
database: 'soul_miniprogram',
charset: 'utf8mb4',
timezone: '+08:00',
acquireTimeout: 60000,
timeout: 60000,
reconnect: true
}
// 数据库配置含database
const dbConfig = {
...dbConfigWithoutDB,
database: 'soul_experiment',
}
// 创建连接池
// 连接池
let pool: mysql.Pool | null = null
/**
* 获取数据库连接池
*/
export function getPool() {
if (!pool) {
pool = mysql.createPool(dbConfig)
pool = mysql.createPool({
...DB_CONFIG,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
}
return pool
}
// 创建数据库(如果不存在)
export async function createDatabaseIfNotExists() {
const conn = await mysql.createConnection(dbConfigWithoutDB)
/**
* 执行SQL查询
*/
export async function query(sql: string, params?: any[]) {
try {
await conn.execute('CREATE DATABASE IF NOT EXISTS soul_experiment CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci')
console.log('Database soul_experiment created or already exists')
const connection = getPool()
const [results] = await connection.execute(sql, params)
return results
} catch (error) {
console.error('数据库查询错误:', error)
throw error
}
}
/**
* 初始化数据库表结构
*/
export async function initDatabase() {
try {
console.log('开始初始化数据库表结构...')
// 用户表
await query(`
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(50) PRIMARY KEY,
open_id VARCHAR(100) UNIQUE NOT NULL,
nickname VARCHAR(100),
avatar VARCHAR(500),
phone VARCHAR(20),
wechat_id VARCHAR(100),
referral_code VARCHAR(20) UNIQUE,
purchased_sections JSON,
has_full_book BOOLEAN DEFAULT FALSE,
earnings DECIMAL(10,2) DEFAULT 0,
pending_earnings DECIMAL(10,2) DEFAULT 0,
referral_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_open_id (open_id),
INDEX idx_referral_code (referral_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
// 订单表
await query(`
CREATE TABLE IF NOT EXISTS orders (
id VARCHAR(50) PRIMARY KEY,
order_sn VARCHAR(50) UNIQUE NOT NULL,
user_id VARCHAR(50) NOT NULL,
open_id VARCHAR(100) NOT NULL,
product_type ENUM('section', 'fullbook', 'match') NOT NULL,
product_id VARCHAR(50),
amount DECIMAL(10,2) NOT NULL,
description VARCHAR(200),
status ENUM('pending', 'paid', 'cancelled', 'refunded') DEFAULT 'pending',
transaction_id VARCHAR(100),
pay_time TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_order_sn (order_sn),
INDEX idx_user_id (user_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
// 推广绑定关系表
await query(`
CREATE TABLE IF NOT EXISTS referral_bindings (
id VARCHAR(50) PRIMARY KEY,
referrer_id VARCHAR(50) NOT NULL,
referee_id VARCHAR(50) NOT NULL,
referral_code VARCHAR(20) NOT NULL,
status ENUM('active', 'converted', 'expired') DEFAULT 'active',
binding_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expiry_date TIMESTAMP NOT NULL,
conversion_date TIMESTAMP NULL,
commission_amount DECIMAL(10,2) DEFAULT 0,
order_id VARCHAR(50) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (referrer_id) REFERENCES users(id),
FOREIGN KEY (referee_id) REFERENCES users(id),
FOREIGN KEY (order_id) REFERENCES orders(id),
UNIQUE KEY unique_referrer_referee (referrer_id, referee_id),
INDEX idx_referrer_id (referrer_id),
INDEX idx_referee_id (referee_id),
INDEX idx_status (status),
INDEX idx_expiry_date (expiry_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
// 匹配记录表
await query(`
CREATE TABLE IF NOT EXISTS match_records (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
match_type ENUM('partner', 'investor', 'mentor', 'team') NOT NULL,
phone VARCHAR(20),
wechat_id VARCHAR(100),
matched_user_id VARCHAR(50),
match_score INT,
status ENUM('pending', 'matched', 'contacted') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_user_id (user_id),
INDEX idx_match_type (match_type),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
// 系统配置表
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,
INDEX idx_config_key (config_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
console.log('数据库表结构初始化完成')
// 插入默认配置
await initDefaultConfig()
} catch (error) {
console.error('初始化数据库失败:', error)
throw error
}
}
/**
* 初始化默认配置
*/
async function initDefaultConfig() {
try {
// 匹配类型配置
const matchConfig = {
matchTypes: [
{ id: 'partner', label: '创业合伙', matchLabel: '创业伙伴', icon: '⭐', matchFromDB: true, showJoinAfterMatch: false, enabled: true },
{ id: 'investor', label: '资源对接', matchLabel: '资源对接', icon: '👥', matchFromDB: false, showJoinAfterMatch: true, enabled: true },
{ id: 'mentor', label: '导师顾问', matchLabel: '商业顾问', icon: '❤️', matchFromDB: false, showJoinAfterMatch: true, enabled: true },
{ id: 'team', label: '团队招募', matchLabel: '加入项目', icon: '🎮', matchFromDB: false, showJoinAfterMatch: true, enabled: true }
],
freeMatchLimit: 3,
matchPrice: 1,
settings: {
enableFreeMatches: true,
enablePaidMatches: true,
maxMatchesPerDay: 10
}
}
await query(`
INSERT INTO system_config (config_key, config_value, description)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)
`, ['match_config', JSON.stringify(matchConfig), '匹配功能配置'])
// 推广配置
const referralConfig = {
distributorShare: 90, // 推广者分成比例
minWithdrawAmount: 10, // 最小提现金额
bindingDays: 30, // 绑定有效期(天)
userDiscount: 5 // 用户优惠比例
}
await query(`
INSERT INTO system_config (config_key, config_value, description)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)
`, ['referral_config', JSON.stringify(referralConfig), '推广功能配置'])
console.log('默认配置初始化完成')
} catch (error) {
console.error('初始化默认配置失败:', error)
}
}
/**
* 获取系统配置
*/
export async function getConfig(key: string) {
try {
const results = await query(
'SELECT config_value FROM system_config WHERE config_key = ?',
[key]
) as any[]
if (results.length > 0) {
return results[0].config_value
}
return null
} catch (error) {
console.error('获取配置失败:', error)
return null
}
}
/**
* 设置系统配置
*/
export async function setConfig(key: string, value: any, description?: string) {
try {
await query(`
INSERT INTO system_config (config_key, config_value, description)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
config_value = VALUES(config_value),
description = COALESCE(VALUES(description), description)
`, [key, JSON.stringify(value), description])
return true
} catch (error) {
console.error('Error creating database:', error)
throw error
} finally {
await conn.end()
console.error('设置配置失败:', error)
return false
}
}
// 执行查询
export async function query<T = any>(sql: string, params?: any[]): Promise<T[]> {
const pool = getPool()
const [rows] = await pool.execute(sql, params)
return rows as T[]
}
// 执行单条插入/更新/删除
export async function execute(sql: string, params?: any[]): Promise<mysql.ResultSetHeader> {
const pool = getPool()
const [result] = await pool.execute(sql, params)
return result as mysql.ResultSetHeader
}
// 用户相关操作
export const userDB = {
// 获取所有用户
async getAll() {
return query(`SELECT * FROM users ORDER BY created_at DESC`)
},
// 根据ID获取用户
async getById(id: string) {
const rows = await query(`SELECT * FROM users WHERE id = ?`, [id])
return rows[0] || null
},
// 根据手机号获取用户
async getByPhone(phone: string) {
const rows = await query(`SELECT * FROM users WHERE phone = ?`, [phone])
return rows[0] || null
},
// 创建用户
async create(user: {
id: string
phone: string
nickname: string
password?: string
is_admin?: boolean
referral_code: string
referred_by?: string
}) {
await execute(
`INSERT INTO users (id, phone, nickname, password, is_admin, referral_code, referred_by, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`,
[user.id, user.phone, user.nickname, user.password || '', user.is_admin || false, user.referral_code, user.referred_by || null]
)
return user
},
// 更新用户
async update(id: string, updates: Partial<{
nickname: string
password: string
is_admin: boolean
has_full_book: boolean
earnings: number
pending_earnings: number
withdrawn_earnings: number
referral_count: number
match_count_today: number
last_match_date: string
}>) {
const fields: string[] = []
const values: any[] = []
Object.entries(updates).forEach(([key, value]) => {
if (value !== undefined) {
fields.push(`${key} = ?`)
values.push(value)
}
})
if (fields.length === 0) return
values.push(id)
await execute(`UPDATE users SET ${fields.join(', ')} WHERE id = ?`, values)
},
// 删除用户
async delete(id: string) {
await execute(`DELETE FROM users WHERE id = ?`, [id])
},
// 验证密码
async verifyPassword(phone: string, password: string) {
const rows = await query(`SELECT * FROM users WHERE phone = ? AND password = ?`, [phone, password])
return rows[0] || null
},
// 更新匹配次数
async updateMatchCount(userId: string) {
const today = new Date().toISOString().split('T')[0]
const user = await this.getById(userId)
if (user?.last_match_date === today) {
await execute(
`UPDATE users SET match_count_today = match_count_today + 1 WHERE id = ?`,
[userId]
)
} else {
await execute(
`UPDATE users SET match_count_today = 1, last_match_date = ? WHERE id = ?`,
[today, userId]
)
}
},
// 获取今日匹配次数
async getMatchCount(userId: string) {
const today = new Date().toISOString().split('T')[0]
const rows = await query(
`SELECT match_count_today FROM users WHERE id = ? AND last_match_date = ?`,
[userId, today]
)
return rows[0]?.match_count_today || 0
}
}
// 购买记录相关操作
export const purchaseDB = {
async getAll() {
return query(`SELECT * FROM purchases ORDER BY created_at DESC`)
},
async getByUserId(userId: string) {
return query(`SELECT * FROM purchases WHERE user_id = ? ORDER BY created_at DESC`, [userId])
},
async create(purchase: {
id: string
user_id: string
type: 'section' | 'fullbook' | 'match'
section_id?: string
section_title?: string
amount: number
payment_method?: string
referral_code?: string
referrer_earnings?: number
status: string
}) {
await execute(
`INSERT INTO purchases (id, user_id, type, section_id, section_title, amount, payment_method, referral_code, referrer_earnings, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`,
[purchase.id, purchase.user_id, purchase.type, purchase.section_id || null, purchase.section_title || null,
purchase.amount, purchase.payment_method || null, purchase.referral_code || null, purchase.referrer_earnings || 0, purchase.status]
)
return purchase
}
}
// 分销绑定相关操作
export const distributionDB = {
async getAllBindings() {
return query(`SELECT * FROM referral_bindings ORDER BY bound_at DESC`)
},
async getBindingsByReferrer(referrerId: string) {
return query(`SELECT * FROM referral_bindings WHERE referrer_id = ? ORDER BY bound_at DESC`, [referrerId])
},
async createBinding(binding: {
id: string
referrer_id: string
referee_id: string
referrer_code: string
bound_at: string
expires_at: string
status: string
}) {
await execute(
`INSERT INTO referral_bindings (id, referrer_id, referee_id, referrer_code, bound_at, expires_at, status)
VALUES (?, ?, ?, ?, ?, ?, ?)`,
[binding.id, binding.referrer_id, binding.referee_id, binding.referrer_code, binding.bound_at, binding.expires_at, binding.status]
)
return binding
},
async updateBindingStatus(id: string, status: string) {
await execute(`UPDATE referral_bindings SET status = ? WHERE id = ?`, [status, id])
},
async getActiveBindingByReferee(refereeId: string) {
const rows = await query(
`SELECT * FROM referral_bindings WHERE referee_id = ? AND status = 'active' AND expires_at > NOW()`,
[refereeId]
)
return rows[0] || null
},
// 佣金记录
async getAllCommissions() {
return query(`SELECT * FROM distribution_commissions ORDER BY created_at DESC`)
},
async createCommission(commission: {
id: string
binding_id: string
referrer_id: string
referee_id: string
order_id: string
amount: number
commission_rate: number
commission_amount: number
status: string
}) {
await execute(
`INSERT INTO distribution_commissions (id, binding_id, referrer_id, referee_id, order_id, amount, commission_rate, commission_amount, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())`,
[commission.id, commission.binding_id, commission.referrer_id, commission.referee_id, commission.order_id,
commission.amount, commission.commission_rate, commission.commission_amount, commission.status]
)
return commission
}
}
// 提现记录相关操作
export const withdrawalDB = {
async getAll() {
return query(`SELECT * FROM withdrawals ORDER BY created_at DESC`)
},
async getByUserId(userId: string) {
return query(`SELECT * FROM withdrawals WHERE user_id = ? ORDER BY created_at DESC`, [userId])
},
async create(withdrawal: {
id: string
user_id: string
amount: number
method: string
account: string
name: string
status: string
}) {
await execute(
`INSERT INTO withdrawals (id, user_id, amount, method, account, name, status, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`,
[withdrawal.id, withdrawal.user_id, withdrawal.amount, withdrawal.method, withdrawal.account, withdrawal.name, withdrawal.status]
)
return withdrawal
},
async updateStatus(id: string, status: string) {
const completedAt = status === 'completed' ? ', completed_at = NOW()' : ''
await execute(`UPDATE withdrawals SET status = ?${completedAt} WHERE id = ?`, [status, id])
}
}
// 系统设置相关操作
export const settingsDB = {
async get() {
const rows = await query(`SELECT * FROM settings WHERE id = 1`)
return rows[0] || null
},
async update(settings: Record<string, any>) {
const json = JSON.stringify(settings)
await execute(
`INSERT INTO settings (id, data, updated_at) VALUES (1, ?, NOW())
ON DUPLICATE KEY UPDATE data = ?, updated_at = NOW()`,
[json, json]
)
}
}
// book内容相关操作
export const bookDB = {
async getAllSections() {
return query(`SELECT * FROM book_sections ORDER BY sort_order ASC`)
},
async getSection(id: string) {
const rows = await query(`SELECT * FROM book_sections WHERE id = ?`, [id])
return rows[0] || null
},
async updateSection(id: string, updates: { title?: string; content?: string; price?: number; is_free?: boolean }) {
const fields: string[] = []
const values: any[] = []
Object.entries(updates).forEach(([key, value]) => {
if (value !== undefined) {
fields.push(`${key} = ?`)
values.push(value)
}
})
if (fields.length === 0) return
fields.push('updated_at = NOW()')
values.push(id)
await execute(`UPDATE book_sections SET ${fields.join(', ')} WHERE id = ?`, values)
},
async createSection(section: {
id: string
part_id: string
chapter_id: string
title: string
content: string
price: number
is_free: boolean
sort_order: number
}) {
await execute(
`INSERT INTO book_sections (id, part_id, chapter_id, title, content, price, is_free, sort_order, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())`,
[section.id, section.part_id, section.chapter_id, section.title, section.content, section.price, section.is_free, section.sort_order]
)
return section
},
// 导出所有章节
async exportAll() {
const sections = await this.getAllSections()
return JSON.stringify(sections, null, 2)
},
// 导入章节
async importSections(sectionsJson: string) {
const sections = JSON.parse(sectionsJson)
for (const section of sections) {
const existing = await this.getSection(section.id)
if (existing) {
await this.updateSection(section.id, section)
} else {
await this.createSection(section)
}
}
return sections.length
}
}
// 初始化数据库表
export async function initDatabase() {
// 先创建数据库
await createDatabaseIfNotExists()
const pool = getPool()
// 用户表
await pool.execute(`
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(50) PRIMARY KEY,
phone VARCHAR(20) UNIQUE NOT NULL,
nickname VARCHAR(100) NOT NULL,
password VARCHAR(100) DEFAULT '',
is_admin BOOLEAN DEFAULT FALSE,
has_full_book BOOLEAN DEFAULT FALSE,
referral_code VARCHAR(20) UNIQUE,
referred_by VARCHAR(20),
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 DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_phone (phone),
INDEX idx_referral_code (referral_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// 购买记录表
await pool.execute(`
CREATE TABLE IF NOT EXISTS purchases (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
type ENUM('section', 'fullbook', 'match') NOT NULL,
section_id VARCHAR(20),
section_title VARCHAR(200),
amount DECIMAL(10,2) NOT NULL,
payment_method VARCHAR(20),
referral_code VARCHAR(20),
referrer_earnings DECIMAL(10,2) DEFAULT 0,
status ENUM('pending', 'completed', 'refunded') DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// 分销绑定表
await pool.execute(`
CREATE TABLE IF NOT EXISTS referral_bindings (
id VARCHAR(50) PRIMARY KEY,
referrer_id VARCHAR(50) NOT NULL,
referee_id VARCHAR(50) NOT NULL,
referrer_code VARCHAR(20) NOT NULL,
bound_at DATETIME NOT NULL,
expires_at DATETIME NOT NULL,
status ENUM('active', 'converted', 'expired') DEFAULT 'active',
INDEX idx_referrer (referrer_id),
INDEX idx_referee (referee_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// 分销佣金表
await pool.execute(`
CREATE TABLE IF NOT EXISTS distribution_commissions (
id VARCHAR(50) PRIMARY KEY,
binding_id VARCHAR(50) NOT NULL,
referrer_id VARCHAR(50) NOT NULL,
referee_id VARCHAR(50) NOT NULL,
order_id VARCHAR(50) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
commission_rate DECIMAL(5,2) NOT NULL,
commission_amount DECIMAL(10,2) NOT NULL,
status ENUM('pending', 'paid', 'cancelled') DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
paid_at DATETIME,
INDEX idx_referrer (referrer_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// 提现记录表
await pool.execute(`
CREATE TABLE IF NOT EXISTS withdrawals (
id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
amount DECIMAL(10,2) NOT NULL,
method ENUM('wechat', 'alipay') NOT NULL,
account VARCHAR(100) NOT NULL,
name VARCHAR(50) NOT NULL,
status ENUM('pending', 'completed', 'rejected') DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
completed_at DATETIME,
INDEX idx_user_id (user_id),
INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// 系统设置表
await pool.execute(`
CREATE TABLE IF NOT EXISTS settings (
id INT PRIMARY KEY,
data JSON,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
// book章节表
await pool.execute(`
CREATE TABLE IF NOT EXISTS book_sections (
id VARCHAR(20) PRIMARY KEY,
part_id VARCHAR(20) NOT NULL,
chapter_id VARCHAR(20) NOT NULL,
title VARCHAR(200) NOT NULL,
content LONGTEXT,
price DECIMAL(10,2) DEFAULT 1,
is_free BOOLEAN DEFAULT FALSE,
sort_order INT DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_part (part_id),
INDEX idx_chapter (chapter_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`)
console.log('Database tables initialized successfully')
}
// 导出数据库实例
export default { getPool, query, initDatabase, getConfig, setConfig }