Files
soul/lib/db.ts

323 lines
11 KiB
TypeScript
Raw Normal View History

/**
*
* 使MySQL数据库存储用户广
*/
import mysql from 'mysql2/promise'
// 腾讯云外网数据库配置
const DB_CONFIG = {
host: '56b4c23f6853c.gz.cdb.myqcloud.com',
port: 14413,
user: 'cdb_outerroot',
password: 'Zhiqun1984',
database: 'soul_miniprogram',
charset: 'utf8mb4',
timezone: '+08:00',
acquireTimeout: 60000,
timeout: 60000,
reconnect: true
}
// 连接池
let pool: mysql.Pool | null = null
/**
*
*/
export function getPool() {
if (!pool) {
pool = mysql.createPool({
...DB_CONFIG,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
}
return pool
}
/**
* SQL查询
*/
export async function query(sql: string, params?: any[]) {
try {
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,
session_key VARCHAR(100) COMMENT '微信session_key',
nickname VARCHAR(100),
avatar VARCHAR(500),
phone VARCHAR(20),
password VARCHAR(100) COMMENT '密码(可选)',
wechat_id VARCHAR(100) COMMENT '用户填写的微信号',
referral_code VARCHAR(20) UNIQUE,
referred_by VARCHAR(50) COMMENT '推荐人ID',
purchased_sections JSON DEFAULT '[]',
has_full_book BOOLEAN DEFAULT FALSE,
is_admin BOOLEAN DEFAULT FALSE COMMENT '是否管理员',
earnings DECIMAL(10,2) DEFAULT 0 COMMENT '已提现收益',
pending_earnings DECIMAL(10,2) DEFAULT 0 COMMENT '待提现收益',
withdrawn_earnings DECIMAL(10,2) DEFAULT 0 COMMENT '累计已提现',
referral_count INT DEFAULT 0 COMMENT '推广人数',
match_count_today INT DEFAULT 0 COMMENT '今日匹配次数',
last_match_date DATE COMMENT '最后匹配日期',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_open_id (open_id),
INDEX idx_phone (phone),
INDEX idx_referral_code (referral_code),
INDEX idx_referred_by (referred_by)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`)
// 尝试添加可能缺失的字段(用于升级已有数据库)
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS session_key VARCHAR(100)')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS password VARCHAR(100)')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS referred_by VARCHAR(50)')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS is_admin BOOLEAN DEFAULT FALSE')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS match_count_today INT DEFAULT 0')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS last_match_date DATE')
} catch (e) { /* 忽略 */ }
try {
await query('ALTER TABLE users ADD COLUMN IF NOT EXISTS withdrawn_earnings DECIMAL(10,2) DEFAULT 0')
} catch (e) { /* 忽略 */ }
console.log('用户表初始化完成')
// 订单表
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
`)
// 章节内容表 - 存储书籍所有章节
await query(`
CREATE TABLE IF NOT EXISTS chapters (
id VARCHAR(20) PRIMARY KEY COMMENT '章节ID如1.1、preface等',
part_id VARCHAR(20) NOT NULL COMMENT '所属篇ID如part-1',
part_title VARCHAR(100) NOT NULL COMMENT '篇标题,如第一篇|真实的人',
chapter_id VARCHAR(20) NOT NULL COMMENT '所属章ID如chapter-1',
chapter_title VARCHAR(200) NOT NULL COMMENT '章标题如第1章人与人之间的底层逻辑',
section_title VARCHAR(200) NOT NULL COMMENT '节标题',
content LONGTEXT NOT NULL COMMENT '章节正文内容Markdown格式',
word_count INT DEFAULT 0 COMMENT '字数统计',
is_free BOOLEAN DEFAULT FALSE COMMENT '是否免费章节',
price DECIMAL(10,2) DEFAULT 1.00 COMMENT '单章价格',
sort_order INT DEFAULT 0 COMMENT '排序顺序',
status ENUM('draft', 'published', 'archived') DEFAULT 'published' COMMENT '状态',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_part_id (part_id),
INDEX idx_chapter_id (chapter_id),
INDEX idx_status (status),
INDEX idx_sort_order (sort_order)
) 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)
return false
}
}
// 导出数据库实例
export default { getPool, query, initDatabase, getConfig, setConfig }