package main import ( "fmt" "strings" "gorm.io/driver/mysql" "gorm.io/gorm" ) func main() { dsn := "root:bindbox2025kdy@tcp(150.158.78.154:3306)/dev_game?charset=utf8mb4&parseTime=True&loc=Local" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { fmt.Println("连接失败:", err) return } channelID := 3 // 1. 成本统计(复用 calcCostByInventory 的 SQL 逻辑) type costRow struct { UnitCost int64 Multiplier int64 } var rows []costRow db.Table("user_inventory"). Select(` COALESCE(NULLIF(user_inventory.value_cents, 0), activity_reward_settings.price_snapshot_cents, products.price, 0) AS unit_cost, GREATEST(COALESCE(system_item_cards.reward_multiplier_x1000, 1000), 1000) AS multiplier `). Joins("JOIN users ON users.id = user_inventory.user_id"). Joins("LEFT JOIN orders ON orders.id = user_inventory.order_id"). Joins("LEFT JOIN activity_reward_settings ON activity_reward_settings.id = user_inventory.reward_id"). Joins("LEFT JOIN products ON products.id = user_inventory.product_id"). Joins("LEFT JOIN user_item_cards ON user_item_cards.id = orders.item_card_id"). Joins("LEFT JOIN system_item_cards ON system_item_cards.id = user_item_cards.card_id"). Where("users.channel_id = ? AND users.deleted_at IS NULL", channelID). Where("user_inventory.status IN ?", []int{1, 3}). Where("COALESCE(user_inventory.remark, '') NOT LIKE ?", "%void%"). Where("(orders.status = 2 OR user_inventory.order_id = 0 OR user_inventory.order_id IS NULL)"). Where("(orders.source_type IN (1,2,3,4) OR user_inventory.order_id = 0 OR user_inventory.order_id IS NULL)"). Scan(&rows) var totalCostBase, totalCostFinal int64 var withCard, withoutCard int for _, r := range rows { cost := r.UnitCost * r.Multiplier / 1000 totalCostFinal += cost totalCostBase += r.UnitCost if r.Multiplier > 1000 { withCard++ } else { withoutCard++ } } fmt.Println("========================================") fmt.Printf("渠道 %d 盈亏分析\n", channelID) fmt.Println("========================================") fmt.Println() fmt.Println("【成本统计】") fmt.Printf(" 资产记录数: %d 条\n", len(rows)) fmt.Printf(" 无道具卡: %d 条\n", withoutCard) fmt.Printf(" 有道具卡: %d 条(成本×倍数)\n", withCard) fmt.Printf(" 基础成本: %d 分 = %.2f 元\n", totalCostBase, float64(totalCostBase)/100) fmt.Printf(" 含卡成本: %d 分 = %.2f 元\n", totalCostFinal, float64(totalCostFinal)/100) if totalCostBase > 0 { fmt.Printf(" 道具卡加成: +%.2f 元 (%.1f%%)\n", float64(totalCostFinal-totalCostBase)/100, float64(totalCostFinal-totalCostBase)/float64(totalCostBase)*100) } fmt.Println() // 2. 收入统计(已有的 price_draw × count) // 简化:直接用 SQL 统计 actual_amount 作为对比参考 type amountResult struct { TotalCents int64 } var ar amountResult orderFilter := "users.channel_id = ? AND users.deleted_at IS NULL AND orders.status = 2 AND orders.actual_amount > 0 AND orders.source_type IN (1,2,3,4) AND (orders.ext_order_id = '' OR orders.ext_order_id IS NULL)" db.Table("orders"). Joins("JOIN users ON users.id = orders.user_id"). Select("COALESCE(SUM(orders.actual_amount), 0) as total_cents"). Where(orderFilter, channelID). Scan(&ar) fmt.Println("【收入参考 (actual_amount)】") fmt.Printf(" 实付金额: %d 分 = %.2f 元\n", ar.TotalCents, float64(ar.TotalCents)/100) fmt.Println() // 3. 盈亏 profit := ar.TotalCents - totalCostFinal fmt.Println("【盈亏】") fmt.Printf(" 收入(实付): %.2f 元\n", float64(ar.TotalCents)/100) fmt.Printf(" 成本(含卡): %.2f 元\n", float64(totalCostFinal)/100) fmt.Println(strings.Repeat("-", 40)) fmt.Printf(" 盈亏: %.2f 元\n", float64(profit)/100) if profit > 0 { fmt.Printf(" 状态: 盈利 ✅\n") } else if profit < 0 { fmt.Printf(" 状态: 亏损 ❌\n") } else { fmt.Printf(" 状态: 持平\n") } fmt.Println() // 4. 道具卡详情 type cardDetail struct { CardName string Multiplier int64 Count int64 } var cards []cardDetail db.Table("user_inventory"). Select(` system_item_cards.name as card_name, system_item_cards.reward_multiplier_x1000 as multiplier, COUNT(*) as count `). Joins("JOIN users ON users.id = user_inventory.user_id"). Joins("LEFT JOIN orders ON orders.id = user_inventory.order_id"). Joins("LEFT JOIN user_item_cards ON user_item_cards.id = orders.item_card_id"). Joins("LEFT JOIN system_item_cards ON system_item_cards.id = user_item_cards.card_id"). Where("users.channel_id = ? AND users.deleted_at IS NULL", channelID). Where("user_inventory.status IN ?", []int{1, 3}). Where("COALESCE(user_inventory.remark, '') NOT LIKE ?", "%void%"). Where("(orders.status = 2 OR user_inventory.order_id = 0 OR user_inventory.order_id IS NULL)"). Where("(orders.source_type IN (1,2,3,4) OR user_inventory.order_id = 0 OR user_inventory.order_id IS NULL)"). Where("system_item_cards.id IS NOT NULL"). Group("system_item_cards.id"). Scan(&cards) if len(cards) > 0 { fmt.Println("【道具卡使用详情】") fmt.Printf("%-20s %-10s %-10s\n", "卡名", "倍数", "次数") fmt.Println(strings.Repeat("-", 40)) for _, c := range cards { fmt.Printf("%-20s ×%.1f %-10d\n", c.CardName, float64(c.Multiplier)/1000, c.Count) } } else { fmt.Println("【道具卡使用详情】无道具卡使用记录") } }