interface AgentData {
// 基本信息
username: string // 用户名 (必填)
name: string // 代理商名称 (必填)
parentUsername: string | null // 上级代理用户名,总代理填 null (必填)
level: number // 层级: 1=总代理, 2=一级代理, 3=二级代理 (必填)
// 账户状态
status: "active" | "suspended" | "inactive" // 账户状态 (必填)
// 比例配置
profitSharingRate: number // 分红比例 0-1 (必填)
dailySalaryRate: number // 日薪比例 0-1 (必填)
rebateRate: number // 返水比例 0-1 (必填)
// 可选字段
memberLevel?: string // 会员等级
memberGroup?: string // 会员组别
balance?: number // 余额
}
/**
*全局报表数据格式
*/
interface GlobalReportData {
// 基本信息
username: string // 用户名 (必填)
date: string // 数据日期 YYYY-MM-DD (必填)
// 存款相关
在线存款总计: number // 在线存款总计 (必填)
手动加款: number // 手动加款 (必填)
存款总计: number // 存款总计 = 在线存款总计 + 手动加款
// 提款相关
在线提款总计: number // 在线提款总计 (必填)
提款手续费总计: number // 提款手续费总计
手动扣款: number // 手动扣款
// 盈亏相关
现金盈利总计: number // 现金盈利总计
现金盈利总计_包含手动扣款: number // 包含手动扣款的现金盈利
// 彩票相关 (必填)
彩票下注总计: number // 彩票下注总计
彩票输赢: number // 彩票输赢
系统彩下注总计: number // 系统彩下注总计
系统彩输赢: number // 系统彩输赢
系统六合彩下注总计: number // 系统六合彩下注总计
系统六合彩输赢: number // 系统六合彩输赢
六合下注总计: number // 六合下注总计
六合彩输赢: number // 六合彩输赢
其他六合彩下注总计: number // 其他六合彩下注总计
其他六合彩输赢: number // 其他六合彩输赢
// 第三方游戏 (必填)
第三方体育下注总计: number // 第三方体育下注总计
第三方体育输赢: number // 第三方体育输赢
真人下注总计: number // 真人下注总计
真人输赢: number // 真人输赢
电子下注总计: number // 电子下注总计
电子输赢: number // 电子输赢
棋牌下注总计: number // 棋牌下注总计
棋牌输赢: number // 棋牌输赢
电竞下注总计: number // 电竞下注总计
电竞输赢: number // 电竞输赢
捕鱼下注总计: number // 捕鱼下注总计
捕鱼输赢: number // 捕鱼输赢
// 其他数据
其他加款金额: number // 其他加款金额 (日工资)
存提款赠送总计: number // 存提款赠送总计
代金券金额总计: number // 代金券金额总计
活动中奖总计: number // 活动中奖总计
红包中奖总计: number // 红包中奖总计
彩金扣款金额: number // 彩金扣款金额
代理返点合计: number // 代理返点合计
反水合计: number // 反水合计
}
/**
* 响应数据格式
*/
interface WebhookResponse {
success: boolean
timestamp: string
data: {
agents?: AgentData[]
reports?: GlobalReportData[]
}
metadata?: {
totalRecords: number
dateRange?: {
start: string
end: string
}
}
}
// ==================== 数据转换函数 ====================
* 📋 完整字段映射说明:
*
* 必填字段(8个):
* - username: 用户名/账号
* - name: 代理商姓名/名称
* - parentUsername: 上级代理用户名(总代理填null)
* - level: 层级(1=总代理,2=一级代理,3=二级代理...)
* - status: 状态(active/suspended/inactive)
* - profitSharingRate: 分红比例(0-1,例如0.5表示50%)
* - dailySalaryRate: 日薪比例(0-1)
* - rebateRate: 返水比例(0-1)
*
* 可选字段:
* - memberLevel: 会员等级(VIP1/VIP2等)
* - memberGroup: 会员组别(代理组/普通会员等)
* - balance: 账户余额
*
* ⚠️ 根据实际数据库修改以下字段名:
*/
function transformAgentData(externalData: any): AgentData {
return {
// ========== 基本信息字段 ==========
// 用户名 - 从以下字段查找(按优先级)
username: externalData.user_name // 常见字段名1
|| externalData.username // 常见字段名2
|| externalData.account // 常见字段名3
|| externalData.login_name // 常见字段名4
|| externalData.user_account // 常见字段名5
|| "",
// 代理商名称 - 从以下字段查找
name: externalData.full_name // 全名
|| externalData.name // 名称
|| externalData.display_name // 显示名称
|| externalData.real_name // 真实姓名
|| externalData.agent_name // 代理名称
|| externalData.nickname // 昵称
|| "",
// 上级代理用户名 - 如果是总代理则为null
parentUsername: externalData.parent_user // 常见字段名1
|| externalData.parent_username // 常见字段名2
|| externalData.parent_account // 常见字段名3
|| externalData.superior_account // 上级账号
|| externalData.referrer // 推荐人
|| externalData.upline // 上线
|| null,
// 代理层级 - 1=总代理,2=一级代理,3=二级代理...
level: parseInt(
externalData.agent_level // 常见字段名1
|| externalData.level // 常见字段名2
|| externalData.tier // 层级
|| externalData.hierarchy // 等级
|| externalData.rank // 级别
|| "1"
),
// ========== 账户状态字段 ==========
// 状态映射 - active(正常)/suspended(暂停)/inactive(禁用)
status: mapStatus(
externalData.status // 常见字段名1
|| externalData.account_status // 常见字段名2
|| externalData.state // 状态
|| externalData.is_active // 是否激活
|| "active"
),
// ========== 比例配置字段 ==========
// ⚠️ 重要:如果您的数据库存储的是百分比(例如50表示50%),需要除以100
// ⚠️ 如果存储的已经是小数(例如0.5表示50%),则不需要除以100
// 分红比例 - 基于团队净利润的分红百分比
profitSharingRate: parseFloat(
externalData.profit_rate // 利润比例
|| externalData.profit_sharing_rate // 分红比例
|| externalData.commission_rate // 佣金比例
|| externalData.dividend_rate // 红利比例
|| externalData.bonus_rate // 奖金比例
|| "0"
) / 100, // ⚠️ 如果数据库存储的是小数,删除 "/ 100"
// 日薪比例 - 基于彩票亏损的日薪百分比
dailySalaryRate: parseFloat(
externalData.daily_salary_rate // 日薪比例
|| externalData.daily_wage_rate // 日工资比例
|| externalData.daily_commission // 日佣金
|| externalData.salary_rate // 工资比例
|| "0"
) / 100, // ⚠️ 如果数据库存储的是小数,删除 "/ 100"
// 返水比例 - 基于投注额的返水百分比
rebateRate: parseFloat(
externalData.rebate_rate // 返水比例
|| externalData.cashback_rate // 回馈比例
|| externalData.refund_rate // 退水比例
|| externalData.kickback_rate // 回扣比例
|| "0"
) / 100, // ⚠️ 如果数据库存储的是小数,删除 "/ 100"
// ========== 可选字段 ==========
// 会员等级 - VIP等级或其他分级
memberLevel: externalData.member_level // 会员等级
|| externalData.vip_level // VIP等级
|| externalData.user_level // 用户等级
|| externalData.grade // 等级
|| undefined,
// 会员组别 - 分组信息
memberGroup: externalData.member_group // 会员组
|| externalData.user_group // 用户组
|| externalData.agent_group // 代理组
|| externalData.category // 分类
|| "默认组别",
// 账户余额 - 当前账户余额
balance: parseFloat(
externalData.balance // 余额
|| externalData.account_balance // 账户余额
|| externalData.wallet_balance // 钱包余额
|| externalData.available_balance // 可用余额
|| "0"
),
}
}
* 必填字段(2个):
* - username: 用户名
* - date: 报表日期(YYYY-MM-DD格式)
*
* 存款相关(3个字段):
* - 在线存款总计、手动加款、存款总计
*
* 提款相关(3个字段):
* - 在线提款总计、提款手续费总计、手动扣款
*
* 盈亏相关(2个字段):
* - 现金盈利总计、现金盈利总计_包含手动扣款
*
* 彩票相关(10个字段):
* - 彩票下注/输赢、系统彩、六合彩等
*
* 第三方游戏(12个字段):
* - 体育、真人、电子、棋牌、电竞、捕鱼各2个字段(下注+输赢)
*
* 其他财务数据(8个字段):
* - 加款、赠送、代金券、活动、红包、扣款、返点、反水
*
* ⚠️ 所有金额字段单位应为:元(人民币)
* ⚠️ 输赢字段:正数表示平台盈利,负数表示玩家盈利
*/
function transformReportData(externalData: any): GlobalReportData {
return {
// ========== 基本信息字段(必填)==========
// 用户名 - 必须与代理商表的username对应
username: externalData.user_name // 常见字段名1
|| externalData.username // 常见字段名2
|| externalData.account // 账号
|| externalData.agent_username // 代理用户名
|| externalData.login_name // 登录名
|| "",
// 报表日期 - 自动格式化为 YYYY-MM-DD
date: formatDate(
externalData.report_date // 常见字段名1
|| externalData.date // 常见字段名2
|| externalData.stat_date // 统计日期
|| externalData.betting_date // 投注日期
|| externalData.transaction_date // 交易日期
|| new Date()
),
// ========== 存款相关字段(3个)==========
// 在线存款总计 - 线上充值金额
在线存款总计: parseFloat(
externalData.online_deposit // 在线存款
|| externalData.deposit_online // 线上存款
|| externalData.online_recharge // 在线充值
|| externalData.auto_deposit // 自动存款
|| externalData.payment_deposit // 支付存款
|| "0"
),
// 手动加款 - 人工加款金额
手动加款: parseFloat(
externalData.manual_deposit // 手动存款
|| externalData.deposit_manual // 人工存款
|| externalData.manual_add // 手动加款
|| externalData.admin_deposit // 管理员存款
|| externalData.offline_deposit // 线下存款
|| "0"
),
// 存款总计 - 在线存款 + 手动加款(通常数据库已计算好)
存款总计: parseFloat(
externalData.total_deposit // 存款总计
|| externalData.deposit_total // 总存款
|| externalData.all_deposits // 全部存款
|| "0"
),
// ========== 提款相关字段(3个)==========
// 在线提款总计 - 线上提款金额
在线提款总计: parseFloat(
externalData.online_withdraw // 在线提款
|| externalData.withdrawal_online // 线上提款
|| externalData.online_withdrawal // 在线取款
|| externalData.auto_withdraw // 自动提款
|| "0"
),
// 提款手续费总计 - 提款产生的手续费
提款手续费总计: parseFloat(
externalData.withdraw_fee // 提款手续费
|| externalData.withdrawal_fee // 取款手续费
|| externalData.processing_fee // 处理费
|| externalData.transaction_fee // 交易费
|| "0"
),
// 手动扣款 - 人工扣款金额
手动扣款: parseFloat(
externalData.manual_deduction // 手动扣款
|| externalData.manual_deduct // 人工扣款
|| externalData.admin_deduction // 管理员扣款
|| externalData.manual_subtract // 手动减款
|| "0"
),
// ========== 盈亏相关字段(2个)==========
// 现金盈利总计 - 不含手动扣款的净盈利
现金盈利总计: parseFloat(
externalData.cash_profit // 现金盈利
|| externalData.net_profit // 净盈利
|| externalData.total_profit // 总盈利
|| externalData.profit_amount // 盈利金额
|| "0"
),
// 现金盈利总计_包含手动扣款 - 包含所有扣款的净盈利
现金盈利总计_包含手动扣款: parseFloat(
externalData.cash_profit_with_deduction // 含扣款盈利
|| externalData.adjusted_profit // 调整后盈利
|| externalData.final_profit // 最终盈利
|| "0"
),
// ========== 彩票相关字段(10个)==========
// 彩票下注总计 - 所有彩票类游戏的总投注额
彩票下注总计: parseFloat(
externalData.lottery_bet // 彩票投注
|| externalData.lottery_bet_total // 彩票总投注
|| externalData.total_lottery_bet // 总彩票投注
|| externalData.lottery_wager // 彩票下注额
|| "0"
),
// 彩票输赢 - 彩票输赢金额(正数=平台赢,负数=玩家赢)
彩票输赢: parseFloat(
externalData.lottery_winloss // 彩票输赢
|| externalData.lottery_profit // 彩票盈亏
|| externalData.lottery_net // 彩票净额
|| externalData.lottery_result // 彩票结果
|| "0"
),
// 系统彩下注总计 - 系统彩票投注额
系统彩下注总计: parseFloat(
externalData.system_lottery_bet // 系统彩投注
|| externalData.internal_lottery_bet // 内部彩票投注
|| externalData.platform_lottery_bet // 平台彩票投注
|| "0"
),
// 系统彩输赢 - 系统彩票输赢
系统彩输赢: parseFloat(
externalData.system_lottery_winloss // 系统彩输赢
|| externalData.internal_lottery_profit // 内部彩票盈亏
|| "0"
),
// 系统六合彩下注总计 - 系统六合彩投注额
系统六合彩下注总计: parseFloat(
externalData.system_mark6_bet // 系统六合彩投注
|| externalData.system_lotto_bet // 系统乐透投注
|| "0"
),
// 系统六合彩输赢 - 系统六合彩输赢
系统六合彩输赢: parseFloat(
externalData.system_mark6_winloss // 系统六合彩输赢
|| externalData.system_lotto_profit // 系统乐透盈亏
|| "0"
),
// 六合下注总计 - 六合彩投注额
六合下注总计: parseFloat(
externalData.mark6_bet // 六合彩投注
|| externalData.lotto_bet // 乐透投注
|| externalData.mark_six_bet // Mark Six投注
|| "0"
),
// 六合彩输赢 - 六合彩输赢
六合彩输赢: parseFloat(
externalData.mark6_winloss // 六合彩输赢
|| externalData.lotto_profit // 乐透盈亏
|| "0"
),
// 其他六合彩下注总计 - 其他六合彩类游戏投注
其他六合彩下注总计: parseFloat(
externalData.other_mark6_bet // 其他六合彩投注
|| externalData.third_party_lotto_bet // 第三方乐透投注
|| "0"
),
// 其他六合彩输赢 - 其他六合彩输赢
其他六合彩输赢: parseFloat(
externalData.other_mark6_winloss // 其他六合彩输赢
|| externalData.third_party_lotto_profit // 第三方乐透盈亏
|| "0"
),
// ========== 第三方游戏字段(12个,6类游戏×2字段)==========
// 第三方体育下注总计 - 体育投注额
第三方体育下注总计: parseFloat(
externalData.sports_bet // 体育投注
|| externalData.third_party_sports_bet // 第三方体育投注
|| externalData.sportsbook_bet // 体育博彩投注
|| externalData.sport_wager // 体育下注
|| "0"
),
// 第三方体育输赢 - 体育输赢
第三方体育输赢: parseFloat(
externalData.sports_winloss // 体育输赢
|| externalData.sports_profit // 体育盈亏
|| externalData.sportsbook_profit // 体育博彩盈亏
|| "0"
),
// 真人下注总计 - 真人娱乐场投注额
真人下注总计: parseFloat(
externalData.live_casino_bet // 真人投注
|| externalData.live_dealer_bet // 真人荷官投注
|| externalData.live_bet // 真人下注
|| externalData.casino_live_bet // 娱乐场真人投注
|| "0"
),
// 真人输赢 - 真人娱乐场输赢
真人输赢: parseFloat(
externalData.live_casino_winloss // 真人输赢
|| externalData.live_casino_profit // 真人盈亏
|| externalData.live_dealer_profit // 真人荷官盈亏
|| "0"
),
// 电子下注总计 - 电子游戏/老虎机投注额
电子下注总计: parseFloat(
externalData.slot_bet // 老虎机投注
|| externalData.slot_game_bet // 电子游戏投注
|| externalData.electronic_bet // 电子下注
|| externalData.slots_bet // 角子机投注
|| "0"
),
// 电子输赢 - 电子游戏输赢
电子输赢: parseFloat(
externalData.slot_winloss // 老虎机输赢
|| externalData.slot_profit // 老虎机盈亏
|| externalData.electronic_profit // 电子盈亏
|| "0"
),
// 棋牌下注总计 - 棋牌游戏投注额
棋牌下注总计: parseFloat(
externalData.card_bet // 棋牌投注
|| externalData.card_game_bet // 卡牌游戏投注
|| externalData.poker_bet // 扑克投注
|| externalData.table_game_bet // 桌面游戏投注
|| "0"
),
// 棋牌输赢 - 棋牌游戏输赢
棋牌输赢: parseFloat(
externalData.card_winloss // 棋牌输赢
|| externalData.card_profit // 棋牌盈亏
|| externalData.poker_profit // 扑克盈亏
|| "0"
),
// 电竞下注总计 - 电子竞技投注额
电竞下注总计: parseFloat(
externalData.esports_bet // 电竞投注
|| externalData.egame_bet // 电子游戏竞技投注
|| externalData.esport_wager // 电竞下注
|| "0"
),
// 电竞输赢 - 电子竞技输赢
电竞输赢: parseFloat(
externalData.esports_winloss // 电竞输赢
|| externalData.esports_profit // 电竞盈亏
|| externalData.egame_profit // 电子游戏竞技盈亏
|| "0"
),
// 捕鱼下注总计 - 捕鱼游戏投注额
捕鱼下注总计: parseFloat(
externalData.fishing_bet // 捕鱼投注
|| externalData.fishing_game_bet // 捕鱼游戏投注
|| externalData.fish_hunter_bet // 鱼猎人投注
|| "0"
),
// 捕鱼输赢 - 捕鱼游戏输赢
捕鱼输赢: parseFloat(
externalData.fishing_winloss // 捕鱼输赢
|| externalData.fishing_profit // 捕鱼盈亏
|| externalData.fish_hunter_profit // 鱼猎人盈亏
|| "0"
),
// ========== 其他财务数据(8个字段)==========
// 其他加款金额 - 日工资等其他加款
其他加款金额: parseFloat(
externalData.daily_salary // 日工资
|| externalData.other_deposit // 其他存款
|| externalData.other_credit // 其他入账
|| externalData.misc_deposit // 杂项存款
|| "0"
),
// 存提款赠送总计 - 存款/提款优惠
存提款赠送总计: parseFloat(
externalData.deposit_bonus // 存款奖金
|| externalData.deposit_gift // 存款赠送
|| externalData.promotion_bonus // 促销奖金
|| externalData.bonus_amount // 奖金金额
|| "0"
),
// 代金券金额总计 - 优惠券/代金券总额
代金券金额总计: parseFloat(
externalData.voucher_amount // 代金券金额
|| externalData.coupon_amount // 优惠券金额
|| externalData.credit_voucher // 信用券
|| "0"
),
// 活动中奖总计 - 活动奖励总额
活动中奖总计: parseFloat(
externalData.activity_prize // 活动奖金
|| externalData.event_prize // 事件奖金
|| externalData.campaign_prize // 营销活动奖金
|| "0"
),
// 红包中奖总计 - 红包奖励总额
红包中奖总计: parseFloat(
externalData.redpacket_prize // 红包奖金
|| externalData.red_envelope_prize // 红包奖励
|| externalData.lucky_money // 幸运红包
|| "0"
),
// 彩金扣款金额 - 彩金回收金额
彩金扣款金额: parseFloat(
externalData.bonus_deduction // 彩金扣款
|| externalData.bonus_recovery // 彩金回收
|| externalData.bonus_charge // 彩金收回
|| "0"
),
// 代理返点合计 - 代理佣金/返点总额
代理返点合计: parseFloat(
externalData.agent_rebate // 代理返点
|| externalData.agent_commission // 代理佣金
|| externalData.affiliate_rebate // 联盟返点
|| "0"
),
// 反水合计 - 投注返水总额
反水合计: parseFloat(
externalData.rebate_total // 返水总计
|| externalData.cashback_total // 回馈总计
|| externalData.refund_total // 退水总计
|| "0"
),
}
}
/**
* 状态映射辅助函数
*/
function mapStatus(externalStatus: string): "active" | "suspended" | "inactive" {
const status = (externalStatus || "").toLowerCase()
if (status === "active" || status === "1" || status === "enabled") return "active"
if (status === "suspended" || status === "2" || status === "frozen") return "suspended"
return "inactive"
}
/**
* 日期格式化辅助函数
*/
function formatDate(date: any): string {
if (!date) return new Date().toISOString().split('T')[0]
// 如果已经是 YYYY-MM-DD 格式
if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
return date
}
// 转换为 Date 对象后格式化
const d = new Date(date)
return d.toISOString().split('T')[0]
}
// ==================== API 端点实现 ====================
/**
* Express.js 示例实现
*
* 使用方法:
* ```typescript
* import express from 'express'
* import { handleBoyuWebhook } from './webhook-endpoint'
*
* const app = express()
* app.get('/api/webhook/boyu-sync', handleBoyuWebhook)
* app.listen(3000)
* ```
*/
export async function handleBoyuWebhook(req: any, res: any) {
try {
// 1. 验证请求(可选,建议添加)
const authHeader = req.headers.authorization
if (!authHeader || !verifyAuth(authHeader)) {
return res.status(401).json({
success: false,
error: "Unauthorized"
})
}
// 2. 获取查询参数
const dataType = req.query.type || "all" // agents | reports | all
const startDate = req.query.start_date // YYYY-MM-DD
const endDate = req.query.end_date // YYYY-MM-DD
// 3. 从数据库获取数据
const response: WebhookResponse = {
success: true,
timestamp: new Date().toISOString(),
data: {},
metadata: {
totalRecords: 0
}
}
// 获取代理商数据
if (dataType === "agents" || dataType === "all") {
const agentsData = await fetchAgentsFromDatabase()
response.data.agents = agentsData.map(transformAgentData)
response.metadata!.totalRecords += agentsData.length
}
// 获取报表数据
if (dataType === "reports" || dataType === "all") {
const reportsData = await fetchReportsFromDatabase(startDate, endDate)
response.data.reports = reportsData.map(transformReportData)
response.metadata!.totalRecords += reportsData.length
if (startDate && endDate) {
response.metadata!.dateRange = {
start: startDate,
end: endDate
}
}
}
// 4. 返回响应
res.status(200).json(response)
} catch (error) {
console.error("Boyu webhook error:", error)
res.status(500).json({
success: false,
error: "Internal server error",
message: error instanceof Error ? error.message : "Unknown error"
})
}
}
/**
* Next.js API Route 示例实现
*
* 文件位置:pages/api/webhook/boyu-sync.ts 或 app/api/webhook/boyu-sync/route.ts
*
* ```typescript
* import { NextRequest, NextResponse } from 'next/server'
* import { handleBoyuWebhookNextJS } from './webhook-endpoint'
*
* export async function GET(request: NextRequest) {
* return handleBoyuWebhookNextJS(request)
* }
* ```
*/
export async function handleBoyuWebhookNextJS(request: any) {
try {
// 验证授权
const authHeader = request.headers.get("authorization")
if (!authHeader || !verifyAuth(authHeader)) {
return new Response(JSON.stringify({
success: false,
error: "Unauthorized"
}), {
status: 401,
headers: { "Content-Type": "application/json" }
})
}
// 获取查询参数
const { searchParams } = new URL(request.url)
const dataType = searchParams.get("type") || "all"
const startDate = searchParams.get("start_date")
const endDate = searchParams.get("end_date")
// 准备响应
const response: WebhookResponse = {
success: true,
timestamp: new Date().toISOString(),
data: {},
metadata: { totalRecords: 0 }
}
// 获取数据
if (dataType === "agents" || dataType === "all") {
const agentsData = await fetchAgentsFromDatabase()
response.data.agents = agentsData.map(transformAgentData)
response.metadata!.totalRecords += agentsData.length
}
if (dataType === "reports" || dataType === "all") {
const reportsData = await fetchReportsFromDatabase(startDate, endDate)
response.data.reports = reportsData.map(transformReportData)
response.metadata!.totalRecords += reportsData.length
}
return new Response(JSON.stringify(response), {
status: 200,
headers: { "Content-Type": "application/json" }
})
} catch (error) {
return new Response(JSON.stringify({
success: false,
error: "Internal server error"
}), {
status: 500,
headers: { "Content-Type": "application/json" }
})
}
}
// ==================== 数据库查询函数(需要根据实际情况实现) ====================
/**
* 从数据库获取代理商数据
*
* 请根据您的数据库类型和ORM实现此函数
* 支持: MySQL, PostgreSQL, MongoDB, etc.
*/
async function fetchAgentsFromDatabase(): Promise
{
// 示例: MySQL with mysql2
// const [rows] = await db.query(`
// SELECT
// user_name,
// full_name,
// parent_user,
// agent_level,
// status,
// profit_rate,
// daily_salary_rate,
// rebate_rate,
// member_level,
// balance
// FROM agents
// WHERE status != 'deleted'
// ORDER BY agent_level, user_name
// `)
// return rows
// 示例: PostgreSQL with pg
// const result = await pool.query(`
// SELECT * FROM agents WHERE status != 'deleted'
// `)
// return result.rows
// 示例: MongoDB with mongoose
// const agents = await AgentModel.find({ status: { $ne: 'deleted' } })
// return agents.map(a => a.toObject())
// 示例: Prisma ORM
// const agents = await prisma.agent.findMany({
// where: { status: { not: 'deleted' } }
// })
// return agents
// TODO: 在此处添加您的数据库查询代码
throw new Error("fetchAgentsFromDatabase not implemented")
}
/**
* 从数据库获取报表数据
*/
async function fetchReportsFromDatabase(
startDate?: string | null,
endDate?: string | null
): Promise {
// 设置默认日期范围(最近30天)
const end = endDate || new Date().toISOString().split('T')[0]
const start = startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)
.toISOString().split('T')[0]
// 示例: MySQL
// const [rows] = await db.query(`
// SELECT
// user_name,
// report_date,
// online_deposit,
// manual_deposit,
// lottery_bet,
// lottery_winloss,
// sports_bet,
// sports_winloss,
// -- ... 其他字段
// FROM daily_reports
// WHERE report_date BETWEEN ? AND ?
// ORDER BY report_date DESC, user_name
// `, [start, end])
// return rows
// TODO: 在此处添加您的数据库查询代码
throw new Error("fetchReportsFromDatabase not implemented")
}
/**
* 验证授权令牌
*/
function verifyAuth(authHeader: string): boolean {
// 示例: Bearer Token 验证
const token = authHeader.replace("Bearer ", "")
// TODO: 实现您的验证逻辑
// 方法1: 验证固定的 API Key
// return token === process.env.BOYU_API_KEY
// 方法2: 验证 JWT Token
// try {
// const decoded = jwt.verify(token, process.env.JWT_SECRET)
// return decoded.app === 'boyu-agent-system'
// } catch {
// return false
// }
// 方法3: 查询数据库验证
// const isValid = await db.query('SELECT * FROM api_tokens WHERE token = ?', [token])
// return isValid.length > 0
// 临时:开发环境下跳过验证(生产环境必须删除!)
return process.env.NODE_ENV === "development" || token === "your-secret-api-key"
}
// ==================== 测试和调试 ====================
/**
* 测试数据生成器(用于开发测试)
*/
export function generateTestData(): WebhookResponse {
return {
success: true,
timestamp: new Date().toISOString(),
data: {
agents: [
{
username: "test_agent_001",
name: "测试代理001",
parentUsername: null,
level: 1,
status: "active",
profitSharingRate: 0.5,
dailySalaryRate: 0.08,
rebateRate: 0.015,
memberLevel: "总代",
memberGroup: "默认组别",
balance: 10000
},
{
username: "test_agent_002",
name: "测试代理002",
parentUsername: "test_agent_001",
level: 2,
status: "active",
profitSharingRate: 0.3,
dailySalaryRate: 0.05,
rebateRate: 0.01,
memberLevel: "V1",
memberGroup: "默认组别",
balance: 5000
}
],
reports: [
{
username: "test_agent_001",
date: "2025-01-04",
在线存款总计: 50000,
手动加款: 0,
存款总计: 50000,
在线提款总计: 20000,
提款手续费总计: 100,
手动扣款: 0,
现金盈利总计: 15000,
现金盈利总计_包含手动扣款: 15000,
彩票下注总计: 100000,
彩票输赢: 5000,
系统彩下注总计: 0,
系统彩输赢: 0,
系统六合彩下注总计: 0,
系统六合彩输赢: 0,
六合下注总计: 0,
六合彩输赢: 0,
其他六合彩下注总计: 0,
其他六合彩输赢: 0,
第三方体育下注总计: 50000,
第三方体育输赢: 2000,
真人下注总计: 30000,
真人输赢: 1000,
电子下注总计: 20000,
电子输赢: 500,
棋牌下注总计: 0,
棋牌输赢: 0,
电竞下注总计: 0,
电竞输赢: 0,
捕鱼下注总计: 0,
捕鱼输赢: 0,
其他加款金额: 1000,
存提款赠送总计: 500,
代金券金额总计: 0,
活动中奖总计: 0,
红包中奖总计: 0,
彩金扣款金额: 0,
代理返点合计: 800,
反水合计: 1500
}
]
},
metadata: {
totalRecords: 3,
dateRange: {
start: "2025-01-04",
end: "2025-01-04"
}
}
}
}
/**
* 本地测试服务器(用于开发调试)
*
* 运行方法:
* ```bash
* npm install express
* npx ts-node webhook-endpoint.ts
* ```
*/
if (require.main === module) {
const express = require("express")
const app = express()
// 测试端点
app.get("/api/webhook/boyu-sync", async (req: any, res: any) => {
console.log("收到同步请求:", req.query)
// 使用测试数据
const testData = generateTestData()
res.json(testData)
})
// 健康检查端点
app.get("/health", (req: any, res: any) => {
res.json({ status: "ok", timestamp: new Date().toISOString() })
})
const PORT = process.env.PORT || 8080
app.listen(PORT, () => {
console.log(`\n🚀 博鱼数据同步 Webhook 服务器已启动`)
console.log(`📡 监听端口: ${PORT}`)
console.log(`🔗 同步端点: http://localhost:${PORT}/api/webhook/boyu-sync`)
console.log(`💚 健康检查: http://localhost:${PORT}/health`)
console.log(`\n测试命令:`)
console.log(`curl "http://localhost:${PORT}/api/webhook/boyu-sync?type=all"`)
console.log(`\n在博鱼系统中配置此 URL 即可开始自动同步数据!\n`)
})
}
export default handleBoyuWebhook