Kaynağa Gözat

Merge branch 'miniApp' into 360test

flowerpig 7 ay önce
ebeveyn
işleme
1a14cf53d2
48 değiştirilmiş dosya ile 11856 ekleme ve 3046 silme
  1. 46 0
      script/common/InnerHandler.lua
  2. 70 1
      script/common/InnerProto.lua
  3. 11 1
      script/common/InnerProtoID.lua
  4. 2 1
      script/excel/ssecy/combat.lua
  5. 22 0
      script/excel/ssecy/peakBattlefieldReward.lua
  6. 2 1
      script/module/combat/CombatDefine.lua
  7. 22 0
      script/module/serverCommerce/Handler.lua
  8. 51 0
      script/module/serverCommerce/Proto.lua
  9. 719 0
      script/module/serverCommerce/ServerCommerceActPeakBettle.lua
  10. 85 0
      script/module/serverCommerce/ServerCommerceActPeakBettleCombat.lua
  11. 117 0
      script/module/serverCommerce/ServerCommerceActPeakBettleMiddle.lua
  12. BIN
      webServer.zip
  13. 20 0
      webServer/.vscode/launch.json
  14. 133 0
      webServer/iosApi.md
  15. 81 0
      webServer/miniAppApi.md
  16. 5306 1689
      webServer/package-lock.json
  17. 3 1
      webServer/package.json
  18. 233 0
      webServer/serverListApi.md
  19. 8 0
      webServer/src/channels/factory/ChannelFactory.ts
  20. 2 2
      webServer/src/channels/handlers/FourThreeNineNineChannelHandler.ts
  21. 161 0
      webServer/src/channels/handlers/HupuChannelHandler.ts
  22. 469 0
      webServer/src/channels/handlers/MianyouChannelHandler.ts
  23. 1124 0
      webServer/src/channels/handlers/MiniappChannelHandler.ts
  24. 2 2
      webServer/src/channels/handlers/MuZiChannelHandler.ts
  25. 2 2
      webServer/src/channels/handlers/MuZiIosChannelHandler.ts
  26. 3 3
      webServer/src/channels/handlers/QQChannelHandler.ts
  27. 2 2
      webServer/src/channels/handlers/QiAiH5ChannelHandler.ts
  28. 505 0
      webServer/src/channels/handlers/SYIOSChannelHandler.ts
  29. 2 2
      webServer/src/channels/handlers/SanLiAndroidChannelHandler.ts
  30. 2 2
      webServer/src/channels/handlers/SanLiH5ChannelHandler.ts
  31. 2 2
      webServer/src/channels/handlers/SanLiIOSChannelHandler.ts
  32. 2 2
      webServer/src/channels/handlers/ThreeSixZeroChannelHandler.ts
  33. 235 176
      webServer/src/config/channelConfig.ts
  34. 8 0
      webServer/src/config/dbConfig.ts
  35. 29 1
      webServer/src/config/thirdParams.ts
  36. 1316 1130
      webServer/src/controller/ApiController.ts
  37. 489 0
      webServer/src/controller/MiniAppController.ts
  38. 6 2
      webServer/src/model/ServerModel.ts
  39. 113 0
      webServer/src/mongo/mongodb.ts
  40. 4 4
      webServer/src/router/admin.ts
  41. 7 0
      webServer/src/router/index.ts
  42. 25 0
      webServer/src/router/miniapp.ts
  43. 38 8
      webServer/src/server.ts
  44. 45 6
      webServer/src/utils/msg.ts
  45. 8 6
      webServer/src/utils/serverManager.ts
  46. 242 0
      webServer/syiosApi.md
  47. 32 0
      webServer/webpack.config.js
  48. 50 0
      苍空新增协议v1.txt

+ 46 - 0
script/common/InnerHandler.lua

@@ -25,6 +25,7 @@ local MiddleCommonRank = require("middle.MiddleCommonRank")
 local BanLogic = require("scene.BanLogic")
 local JjcNewLadderMidder = require("jjcnewladder.jjcNewLadderMiddle")
 local RebateLogic = require("platform.RebateLogic")
+local ServerCommerceActPeakBettleMiddle = require("serverCommerce.ServerCommerceActPeakBettleMiddle")
 local GodsAreaNS = require("godsArea.GodsAreaNS")
 local GodsAreaCS = require("godsArea.GodsAreaCS")
 local BattleDataNS = require("battleDataManager.BattleDataNS")
@@ -579,6 +580,51 @@ end
 
 -------------------- 天梯赛结束 ---------------------------
 
+-------------------- 巅峰战场跨服协议开始 ---------------------------
+-- 普通服请求跨服排名数据(普通->中心)
+function LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    ServerCommerceActPeakBettleMiddle.LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C(fd, msg)
+end
+
+-- 请求跨服排名数据(中心->数据服)
+function WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D(fd, msg)
+    ServerCommerceActPeakBettleMiddle.WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D(fd, msg)
+end
+
+-- 请求跨服排名数据(数据服->中心)
+function LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    ServerCommerceActPeakBettleMiddle.LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C(fd, msg)
+end
+
+-- 获取到跨服排名数据(中心->普通)
+function WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O(fd, msg)
+    ServerCommerceActPeakBettleMiddle.WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O(fd, msg)
+end
+
+-- 普通服通知排名变化(普通->中心)
+function LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    ServerCommerceActPeakBettleMiddle.LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C(fd, msg)
+end
+
+-- 排名变化通知(中心->数据服)
+function WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D(fd, msg)
+    ServerCommerceActPeakBettleMiddle.WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D(fd, msg)
+end
+
+-- 发送排名奖励(数据服->中心)
+function LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    ServerCommerceActPeakBettleMiddle.LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C(fd, msg)
+end
+
+-- 发送排名奖励(中心->普通)
+function WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O(fd, msg)
+    ServerCommerceActPeakBettleMiddle.WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O(fd, msg)
+end
+-------------------- 巅峰战场跨服协议结束 ---------------------------
 
 -------------------- 返利开始 ---------------------------
 -- 向跨服查询该角色能否返利

+ 70 - 1
script/common/InnerProto.lua

@@ -959,4 +959,73 @@ WL_AREABATTLE_VIDEOSHOW_QUERY = {
   {"videoShowData",         "table"},   -- 录像数据
   {"srvInfo",               "table"},   -- 区服数据
   {"playerUuid",            "string"},  -- 玩家uuid
-}
+}
+
+--------------------- 巅峰战场跨服协议开始 -----------------------------------
+-- 普通服请求跨服排名数据(普通->中心)
+LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C = {
+  {"nSrcServerID",          "int"},       -- 服务器ID
+  {"nRankType",             "int"},       -- 排名类型(1=个人排名,2=服务器排名)
+}
+
+-- 请求跨服排名数据(中心->数据服)
+WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D = {
+  {"nSrcServerID",          "int"},       -- 服务器ID
+  {"nRankType",             "int"},       -- 排名类型
+}
+
+-- 请求跨服排名数据(数据服->中心)
+LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C = {
+  {"nSrcServerID",          "int"},       -- 服务器ID
+  {"nRankType",             "int"},       -- 排名类型
+  {"nIsEnd",                "int"},       -- 是否发送完成 0 未 1 发送完
+  {"tRankInfo",             "table"},     -- 排行榜数据
+  {"nFirst",                "int"},       -- 首次发送 1 是 0 否
+}
+
+-- 获取到跨服排名数据(中心->普通)
+WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O = {
+  {"nFirst",                "int"},       -- 首次发送 1 是 0 否
+  {"nIsEnd",                "int"},       -- 是否发送完成 0 未 1 发送完
+  {"tRankInfo",             "table"},     -- 排行榜数据
+}
+
+-- 普通服通知排名变化(普通->中心)
+LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C = {
+  {"uuid",                  "string"},    -- 玩家uuid
+  {"name",                  "string"},    -- 玩家名字
+  {"head",                  "int"},       -- 玩家头像ID
+  {"headFrame",             "int"},       -- 玩家头像框
+  {"nSrcServerID",          "int"},       -- 服务器ID
+  {"nRank",                 "int"},       -- 当前排名
+  {"nValue",                "int"},       -- 排名值(如积分等)
+  {"servername",            "string"},    -- 服务器名称
+}
+
+-- 排名变化通知(中心->数据服)
+WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D = {
+  {"uuid",                  "string"},    -- 玩家uuid
+  {"name",                  "string"},    -- 玩家名字
+  {"head",                  "int"},       -- 玩家头像ID
+  {"headFrame",             "int"},       -- 玩家头像框
+  {"nSrcServerID",          "int"},       -- 服务器ID
+  {"nRank",                 "int"},       -- 当前排名
+  {"nValue",                "int"},       -- 排名值
+  {"servername",            "string"},    -- 服务器名称
+}
+
+-- 发送排名奖励(数据服->中心)
+LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C = {
+  {"uuid",                  "string"},    -- 玩家uid
+  {"nServerID",             "int"},       -- 服务器ID
+  {"nRank",                 "int"},       -- 排名
+  {"tReward",               "table"},     -- 奖励列表
+}
+
+-- 发送排名奖励(中心->普通)
+WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O = {
+  {"uuid",                  "string"},    -- 玩家uid
+  {"nRank",                 "int"},       -- 排名
+  {"tReward",               "table"},     -- 奖励列表
+}
+--------------------- 巅峰战场跨服协议结束 -----------------------------------

+ 11 - 1
script/common/InnerProtoID.lua

@@ -120,4 +120,14 @@ _ENV[120] = 'LW_AREABATTLE_MATCHLIST_QUERY'
 _ENV[121] = 'WL_AREABATTLE_MATCHLIST_QUERY'
 _ENV[122] = 'WL_AREABATTLE_SEND_REWARD'
 _ENV[123] = 'LW_AREABATTLE_VIDEOSHOW_QUERY'
-_ENV[124] = 'WL_AREABATTLE_VIDEOSHOW_QUERY'
+_ENV[124] = 'WL_AREABATTLE_VIDEOSHOW_QUERY'
+
+-- 巅峰战场跨服协议
+_ENV[125] = 'LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C'
+_ENV[126] = 'WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D'
+_ENV[127] = 'LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C'
+_ENV[128] = 'WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O'
+_ENV[129] = 'LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C'
+_ENV[130] = 'WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D'
+_ENV[131] = 'LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C'
+_ENV[132] = 'WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O'

+ 2 - 1
script/excel/ssecy/combat.lua

@@ -24,7 +24,8 @@
 [25]={name="妖族试炼",mapID=2002,moduleFn="racialTrial.RacialTrialLogic",systemID=0,isQuickTime="10,2,3",isQuick=1,teamType=31,group=0,isAttack=1,panelIDs={1721},maxRound=17,isSkip=0,hpLimit=0,fightMode={},PVP=0},
 [26]={name="人族试炼",mapID=2002,moduleFn="racialTrial.RacialTrialLogic",systemID=0,isQuickTime="10,2,3",isQuick=1,teamType=32,group=0,isAttack=1,panelIDs={1722},maxRound=17,isSkip=0,hpLimit=0,fightMode={},PVP=0},
 [27]={name="兽族试炼",mapID=2002,moduleFn="racialTrial.RacialTrialLogic",systemID=0,isQuickTime="10,2,3",isQuick=1,teamType=33,group=0,isAttack=1,panelIDs={1723},maxRound=17,isSkip=0,hpLimit=0,fightMode={},PVP=0},
-[28]={name="仙魔试炼",mapID=2002,moduleFn="racialTrial.RacialTrialLogic",systemID=0,isQuickTime="10,2,3",isQuick=1,teamType=34,group=0,isAttack=1,panelIDs={1724},maxRound=17,isSkip=0,hpLimit=0,fightMode={},PVP=0}}end)();
+[28]={name="仙魔试炼",mapID=2002,moduleFn="racialTrial.RacialTrialLogic",systemID=0,isQuickTime="10,2,3",isQuick=1,teamType=34,group=0,isAttack=1,panelIDs={1724},maxRound=17,isSkip=0,hpLimit=0,fightMode={},PVP=0},
+[35]={name="调教英雄",mapID=1016,moduleFn="battle.BattleLogic",systemID=0,isQuickTime="10,1,1",isQuick=1,teamType=35,group=0,isAttack=1,panelIDs={},maxRound=33,isSkip=0,hpLimit=0,fightMode={},PVP=0}}end)();
 (function()gm={
 [1]={atk={{405009,4,340,13},{405007,2,340,13},{405006,6,340,13},{405005,7,340,13},{405004,9,340,13}},def={{305009,2,340,13},{305010,6,340,13},{305011,4,340,13},{305006,7,340,13},{305007,9,340,13}},atkF=1,defF=1,atkPet=0,defPet=0,items={}},
 [2]={atk={{505004,4,340,13},{505005,2,340,13},{505006,6,340,13},{505007,7,340,13},{505008,9,340,13}},def={{305009,2,340,13},{305010,6,340,13},{305011,4,340,13},{305006,7,340,13},{305007,9,340,13}},atkF=1,defF=1,atkPet=0,defPet=0,items={}},

+ 22 - 0
script/excel/ssecy/peakBattlefieldReward.lua

@@ -0,0 +1,22 @@
+-- 巅峰战场奖励配置表
+-- 奖励类型:1=挑战奖励,2=活动名次奖励,3=扩展排名奖励
+-- 奖励编号:1001=战胜,1002=战败,2001-2009=排名奖励
+-- rank字段:数组格式 [minRank, maxRank],挑战奖励可为空或[0,0]
+
+(function()rankReward={
+-- 挑战奖励(奖励类型=1)
+[1001]={rewardType=1,rewardID=1001,rank={0,0},reward={{101,10},{102,10}}},
+[1002]={rewardType=1,rewardID=1002,rank={0,0},reward={{101,1},{102,1}}},
+-- 活动名次奖励(奖励类型=2)
+[2001]={rewardType=2,rewardID=2001,rank={1,1},reward={{101,10},{102,10}}},
+[2002]={rewardType=2,rewardID=2002,rank={2,2},reward={{101,10},{102,10}}},
+[2003]={rewardType=2,rewardID=2003,rank={3,3},reward={{101,10},{102,10}}},
+[2004]={rewardType=2,rewardID=2004,rank={4,5},reward={{101,10},{102,10}}},
+[2005]={rewardType=2,rewardID=2005,rank={6,10},reward={{101,10},{102,10}}},
+[2006]={rewardType=2,rewardID=2006,rank={11,20},reward={{101,10},{102,10}}},
+[2007]={rewardType=2,rewardID=2007,rank={21,50},reward={{101,10},{102,10}}},
+[2008]={rewardType=2,rewardID=2008,rank={51,100},reward={{101,10},{102,10}}},
+-- 扩展排名奖励(奖励类型=3)
+[2009]={rewardType=3,rewardID=2009,rank={101,99999},reward={{101,10},{102,10}}}
+}end)();
+

+ 2 - 1
script/module/combat/CombatDefine.lua

@@ -207,6 +207,7 @@ COMBAT_TYPE31 = 31 --幽暗禁地
 COMBAT_TYPE32 = 32 --诸神圣域
 COMBAT_TYPE33 = 33 -- 战区争霸
 COMBAT_TYPE34 = 34 --节日活动BOSS
+COMBAT_TYPE35 = 35 --巅峰战场
 
 -- 如果新加阵容的 teamType 和 COMBAT_TYPE1的 teamType 一样, 则需要在下方增加
 -- 一个英雄不能同时上阵的阵容列表, 即一个英雄在key代表阵容上阵后,就不能同时在value列表中的战斗阵容里上阵
@@ -225,7 +226,7 @@ COMBAT_EXCLUSION_LIST = {
 
 
 
-COMBAT_TYPE_MAX = 24 --阵容最大数
+COMBAT_TYPE_MAX = 35 --阵容最大数
 --对象类型
 COMBAT_OBJ_TYPE1 = 1 --玩家 
 COMBAT_OBJ_TYPE2 = 2 --怪物

+ 22 - 0
script/module/serverCommerce/Handler.lua

@@ -2,6 +2,7 @@ local CommerceActCharge = require("serverCommerce.ServerCommerceActCharge")
 local CommerceActShop = require("serverCommerce.ServerCommerceActShop")
 local CommerceActRank = require("serverCommerce.ServerCommerceActRank")
 local CommerceActTask =  require("serverCommerce.ServerCommerceActTask")
+local CommerceActPeakBettle = require("serverCommerce.ServerCommerceActPeakBettle")
 
 -- 请求战区集结任务信息
 function CG_SERVEERCOMMERCE_ACT_TASKQUERY(human, msg)
@@ -46,4 +47,25 @@ end
 ----------------------------------------- 排行榜协议请求开始 -------------------------------------
 function CG_SERVEERCOMMERCE_ACT_RANK_QUERY(human, msg)
     CommerceActRank.CommercerActRank_Query(human, msg.nRankType)
+end
+
+----------------------------------------- 巅峰战场协议请求开始 -------------------------------------
+-- 查询巅峰战场数据
+function CG_PEAK_BATTLEFIELD_QUERY(human)
+    CommerceActPeakBettle.CommerceActPeakBettle_Query(human)
+end
+
+-- 刷新对手列表
+function CG_PEAK_BATTLEFIELD_REFRESH(human)
+    CommerceActPeakBettle.CommerceActPeakBettle_Refresh(human)
+end
+
+-- 挑战对手
+function CG_PEAK_BATTLEFIELD_CHALLENGE(human, msg)
+    CommerceActPeakBettle.CommerceActPeakBettle_Challenge(human, msg.opponentUuid)
+end
+
+-- 查询排名奖励
+function CG_PEAK_BATTLEFIELD_RANK_REWARD_QUERY(human)
+    CommerceActPeakBettle.CommerceActPeakBettle_RankRewardQuery(human)
 end

+ 51 - 0
script/module/serverCommerce/Proto.lua

@@ -1,5 +1,6 @@
 local ItemData = require("bag.Proto").ItemData
 local BuyItem = require("topup.Proto").BuyItem
+local RoleBase = require("role.Proto").RoleBase
 
 tActInfo = 
 {
@@ -162,4 +163,54 @@ CG_SERVEERCOMMERCE_ACT_RANK_QUERY = {
 GC_SERVEERCOMMERCE_ACT_RANK_QUERY = {                  
     {"list",            22,         ServerCommerceActRankList},      -- 排行名次列表
     {"ownerData",       1,          ServerCommerceActOnwerData},     -- 自己排名数据
+}
+
+----------------------------------------- 巅峰战场协议开始 -------------------------------------
+-- 对手信息
+PeakBattlefieldOpponent = {
+    {"uuid",        1,      "string"},      -- 对手uuid
+    {"rank",        1,      "int"},        -- 对手排名
+    {"roleBase",    1,      RoleBase},     -- 对手角色信息
+}
+
+-- 查询巅峰战场数据
+CG_PEAK_BATTLEFIELD_QUERY = {}
+
+-- 查询巅峰战场数据 - 回包
+GC_PEAK_BATTLEFIELD_QUERY = {
+    {"rank",            1,      "int"},                    -- 当前排名
+    {"freeChallengeCnt", 1,      "byte"},                   -- 免费挑战次数
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 对手列表
+    {"unlockedHeroes",  50,     "int"},                     -- 已解锁英雄ID列表
+    {"leftTime",        1,      "int"},                     -- 活动剩余时间(秒)
+}
+
+-- 刷新对手列表
+CG_PEAK_BATTLEFIELD_REFRESH = {}
+
+-- 刷新对手列表 - 回包
+GC_PEAK_BATTLEFIELD_REFRESH = {
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 对手列表
+}
+
+-- 挑战对手
+CG_PEAK_BATTLEFIELD_CHALLENGE = {
+    {"opponentUuid",    1,      "string"},                 -- 对手uuid
+}
+
+-- 挑战对手 - 回包
+GC_PEAK_BATTLEFIELD_CHALLENGE = {
+    {"result",          1,      "byte"},                     -- 战斗结果 1-胜利 2-失败
+    {"newRank",         1,      "int"},                     -- 新排名
+    {"reward",          10,     ItemData},                   -- 奖励列表
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 新的对手列表(胜利时返回)
+}
+
+-- 查询排名奖励
+CG_PEAK_BATTLEFIELD_RANK_REWARD_QUERY = {}
+
+-- 查询排名奖励 - 回包
+GC_PEAK_BATTLEFIELD_RANK_REWARD_QUERY = {
+    {"rank",            1,      "int"},                    -- 当前排名
+    {"rewardList",      20,     "int"},                     -- 排名奖励ID列表
 }

+ 719 - 0
script/module/serverCommerce/ServerCommerceActPeakBettle.lua

@@ -0,0 +1,719 @@
+--------------------------------
+-- 文件名       :   ServerCommerceActPeakBettle.lua
+-- 文件说明     :   巅峰战场
+-- 创建时间     :   2025/11/13
+-- 创建人       :   WWF
+--------------------------------
+
+local Util = require("common.Util")
+local Lang = require("common.Lang")
+local Msg = require("core.Msg")
+local ObjHuman = require("core.ObjHuman")
+local Broadcast = require("broadcast.Broadcast")
+local BagLogic = require("bag.BagLogic")
+local Grid = require("bag.Grid")
+local ItemDefine = require("bag.ItemDefine")
+local CombatLogic = require("combat.CombatLogic")
+local CombatDefine = require("combat.CombatDefine")
+local CombatPosLogic = require("combat.CombatPosLogic")
+local RoleLogic = require("role.RoleLogic")
+local RoleDBLogic = require("role.RoleDBLogic")
+local MailManager = require("mail.MailManager")
+local MailExcel = require("excel.mail")
+local ServerCommerceManager = require("serverCommerce.ServerCommerceManager")
+local ServerCommerceActDefine = require("serverCommerce.ServerCommerceActDefine")
+
+-- Excel配置表
+local PeakBattlefieldRewardExcel = require("excel.peakbattlefieldReward")
+
+-- 巅峰战场常量定义
+local INIT_RANK = 999
+local MATCH_RANK_MIN_OFFSET = 50  -- 向下偏移
+local MATCH_RANK_MAX_OFFSET = 10  -- 向上偏移
+local MATCH_RANK_MIN = 1          -- 最小排名
+local MATCH_RANK_MAX = 999        -- 最大排名
+local OPPONENT_LIST_SIZE = 5
+local DAILY_FREE_CHALLENGE_CNT = 5
+local CHALLENGE_COST_ITEM_ID = 115
+local CHALLENGE_COST_ITEM_CNT = 3
+local REWARD_ID_WIN = 1001      -- 战胜奖励
+local REWARD_ID_LOSE = 1002     -- 战败奖励
+local INIT_HERO_CNT_PER_CAMP = 5
+local MAIL_ID_DEFEAT = 1  -- 战败通知邮件ID
+local MAIL_ID_RANK_REWARD = 0  -- 排名奖励邮件ID
+
+-- 战斗类型
+local COMBAT_TYPE_PEAK_BATTLEFIELD = CombatDefine.COMBAT_TYPE35 or 35
+
+-- 数据库相关
+local LuaMongo = _G.lua_mongo
+local DB = require("common.DB")
+
+-- 排名映射:uuid -> rank
+local UUID_2_RANK = {}
+-- 排名数据:rank -> data
+local RANK_2_DATA = {}
+
+-- 查询条件
+local QueryByUuid = {_id = nil}
+
+----------------------------------------- 内部处理开始 -------------------------------------
+
+-- 获取玩家排名
+local function getRank(uuid)
+    local rank = UUID_2_RANK[uuid]
+    return rank or 0
+end
+
+-- 获取玩家数据
+local function getData(uuid)
+    local rank = UUID_2_RANK[uuid]
+    if not rank then return end
+    return RANK_2_DATA[rank]
+end
+
+-- 获取对手列表
+local function getOpponentList(uuid)
+    local data = getData(uuid)
+    if not data then return {} end
+    return data.opponentList or {}
+end
+
+-- 获取已解锁英雄列表
+local function getUnlockedHeroes(uuid)
+    local data = getData(uuid)
+    if not data then return {} end
+    return data.unlockedHeroes or {}
+end
+
+-- 获取每日免费挑战次数
+local function getFreeChallengeCnt(uuid)
+    local data = getData(uuid)
+    if not data then return DAILY_FREE_CHALLENGE_CNT end
+    
+    -- 检查是否需要重置(跨天)
+    local lastResetTime = data.lastResetTime or 0
+    if not Util.isSameDay(lastResetTime, os.time()) then
+        return DAILY_FREE_CHALLENGE_CNT
+    end
+    
+    return data.freeChallengeCnt or DAILY_FREE_CHALLENGE_CNT
+end
+
+-- 消耗免费挑战次数
+local function consumeFreeChallenge(uuid)
+    local data = getData(uuid)
+    if not data then return false end
+    
+    local lastResetTime = data.lastResetTime or 0
+    local freeCnt = getFreeChallengeCnt(uuid)
+    
+    if freeCnt <= 0 then
+        return false
+    end
+    
+    -- 跨天重置
+    if not Util.isSameDay(lastResetTime, os.time()) then
+        data.freeChallengeCnt = DAILY_FREE_CHALLENGE_CNT
+        data.lastResetTime = os.time()
+    end
+    
+    data.freeChallengeCnt = (data.freeChallengeCnt or DAILY_FREE_CHALLENGE_CNT) - 1
+    updateData(data)
+    return true
+end
+
+-- 排名比较函数(排名越小越靠前)
+local function rankCmp(a, b)
+    if a.rank ~= b.rank then
+        return a.rank < b.rank
+    end
+    return (a.time or 0) < (b.time or 0)
+end
+
+-- 排序排名
+local function sortRank()
+    if #RANK_2_DATA > 1 then
+        table.sort(RANK_2_DATA, rankCmp)
+    end
+    for rank = 1, #RANK_2_DATA do
+        local uuid = RANK_2_DATA[rank]._id
+        UUID_2_RANK[uuid] = rank
+        RANK_2_DATA[rank].rank = rank
+    end
+end
+
+-- 添加玩家
+local function addPlayer(human)
+    local rank = UUID_2_RANK[human.db._id]
+    if rank then return end
+    
+    local data = {}
+    data._id = human.db._id
+    data.rank = INIT_RANK
+    data.opponentList = {}
+    data.unlockedHeroes = {}
+    data.freeChallengeCnt = DAILY_FREE_CHALLENGE_CNT
+    data.lastResetTime = os.time()
+    data.time = os.time()
+    data.name = human.db.name or ""
+    data.lv = human.db.lv or 1
+    data.head = human.db.head or 0
+    data.zhandouli = human.db.zhandouli or 0
+    
+    LuaMongo.insert(DB.db_peak_battlefield, data)
+    
+    RANK_2_DATA[#RANK_2_DATA + 1] = data
+    sortRank()
+end
+
+-- 交换排名(挑战胜利时)
+local function swapRank(atkUuid, defUuid)
+    local atkRank = UUID_2_RANK[atkUuid]
+    local defRank = UUID_2_RANK[defUuid]
+    
+    if not atkRank or not defRank then return end
+    
+    local atkData = RANK_2_DATA[atkRank]
+    local defData = RANK_2_DATA[defRank]
+    
+    if not atkData or not defData then return end
+    
+    -- 交换排名
+    local tempRank = atkData.rank
+    atkData.rank = defData.rank
+    defData.rank = tempRank
+    
+    atkData.time = os.time()
+    defData.time = os.time()
+    
+    -- 清空对手列表(需要重新匹配)
+    atkData.opponentList = {}
+    defData.opponentList = {}
+    
+    updateData(atkData)
+    updateData(defData)
+    
+    sortRank()
+end
+
+-- 设置对手列表
+local function setOpponentList(uuid, opponentList)
+    local data = getData(uuid)
+    if not data then return end
+    
+    data.opponentList = opponentList or {}
+    updateData(data)
+end
+
+-- 更新已解锁英雄
+local function updateUnlockedHeroes(uuid, heroList)
+    local data = getData(uuid)
+    if not data then return end
+    
+    data.unlockedHeroes = heroList or {}
+    updateData(data)
+end
+
+-- 更新数据库
+local function updateData(data)
+    QueryByUuid._id = data._id
+    LuaMongo.update(DB.db_peak_battlefield, QueryByUuid, data)
+end
+
+-- 获取排名范围内的玩家(用于匹配)
+local function getPlayersInRankRange(minRank, maxRank, excludeUuid)
+    local result = {}
+    excludeUuid = excludeUuid or ""
+    
+    for rank = 1, #RANK_2_DATA do
+        local data = RANK_2_DATA[rank]
+        if data.rank >= minRank and data.rank <= maxRank and data._id ~= excludeUuid then
+            result[#result + 1] = data
+        end
+    end
+    
+    return result
+end
+
+-- 获取活动剩余时间(秒)
+local function getActivityLeftTime()
+    local nStartTime, nEndTime = ServerCommerceManager.CommerceAct_GetOpenAndEndTime()
+    if not nEndTime or nEndTime == 0 then
+        return 0
+    end
+    
+    local now = os.time()
+    local leftTime = math.max(nEndTime - now, 0)
+    return leftTime
+end
+
+-- 生成对手列表
+local function generateOpponents(uuid, rank)
+    if rank <= 0 then
+        rank = INIT_RANK
+    end
+    
+    local minRank = math.max(rank - MATCH_RANK_MIN_OFFSET, MATCH_RANK_MIN)
+    local maxRank = math.min(rank + MATCH_RANK_MAX_OFFSET, MATCH_RANK_MAX)
+    
+    local candidates = getPlayersInRankRange(minRank, maxRank, uuid)
+    
+    -- 随机选择5个对手
+    local opponentList = {}
+    local selected = {}
+    local needCnt = OPPONENT_LIST_SIZE
+    
+    if #candidates > 0 then
+        for i = 1, math.min(needCnt, #candidates) do
+            local idx = math.random(1, #candidates)
+            while selected[idx] do
+                idx = math.random(1, #candidates)
+            end
+            selected[idx] = true
+            opponentList[#opponentList + 1] = {
+                uuid = candidates[idx]._id,
+                rank = candidates[idx].rank
+            }
+        end
+    end
+    
+    return opponentList
+end
+
+-- 检查并解锁英雄(使用系统英雄表,按阵营解锁)
+local function checkAndUnlockHeroes(human, rank)
+    local HeroExcel = require("excel.hero").hero
+    
+    local currentUnlocked = getUnlockedHeroes(human.db._id)
+    local newUnlocked = {}
+    
+    -- 根据排名解锁英雄:初始排名时解锁每个阵营的初始英雄
+    if rank <= INIT_RANK then
+        -- 使用 CombatDefine 中的阵营定义
+        local camps = {
+            CombatDefine.CAMP_TYPE1,  -- 恶魔(人族)
+            CombatDefine.CAMP_TYPE2,  -- 圣堂(妖族)
+            CombatDefine.CAMP_TYPE3   -- 不死(兽族)
+        }
+        
+        for _, camp in ipairs(camps) do
+            -- 从HeroExcel中获取该阵营的所有英雄
+            local campHeroes = {}
+            for heroId, heroConfig in pairs(HeroExcel) do
+                if heroConfig.camp == camp then
+                    campHeroes[#campHeroes + 1] = heroId
+                end
+            end
+            
+            -- 随机选择初始数量的英雄
+            if #campHeroes > 0 then
+                local count = INIT_HERO_CNT_PER_CAMP
+                local maxSelect = math.min(count, #campHeroes)
+                for i = 1, maxSelect do
+                    local idx = math.random(1, #campHeroes)
+                    local heroId = campHeroes[idx]
+                    
+                    -- 检查是否已解锁
+                    local found = false
+                    for k = 1, #currentUnlocked do
+                        if currentUnlocked[k] == heroId then
+                            found = true
+                            break
+                        end
+                    end
+                    
+                    if not found then
+                        newUnlocked[#newUnlocked + 1] = heroId
+                        currentUnlocked[#currentUnlocked + 1] = heroId
+                    end
+                    
+                    -- 移除已选择的英雄,避免重复
+                    table.remove(campHeroes, idx)
+                    if #campHeroes == 0 then break end
+                end
+            end
+        end
+    end
+    
+    if #newUnlocked > 0 then
+        updateUnlockedHeroes(human.db._id, currentUnlocked)
+        -- 发送提示
+        Broadcast.sendErr(human, "解锁新英雄!")
+    end
+end
+
+-- 发送战败邮件
+local function sendDefeatMail(defeatedUuid, attackerUuid, newRank)
+    local attackerDb = RoleDBLogic.getDb(attackerUuid)
+    if not attackerDb then return end
+    
+    -- 获取邮件配置
+    local mailID = MAIL_ID_DEFEAT
+    if not mailID or mailID == 0 then
+        return
+    end
+    
+    local mailConfig = MailExcel.mail[mailID]
+    if not mailConfig then 
+        print("[sendDefeatMail] 邮件配置不存在,mailID=" .. (mailID or 0))
+        return 
+    end
+    
+    -- 格式化邮件内容
+    local content = Util.format(mailConfig.content or "", attackerDb.name or "", newRank)
+    
+    -- 发送邮件
+    MailManager.add(MailManager.SYSTEM, defeatedUuid, mailConfig.title or "巅峰战区赛", content, nil, mailConfig.senderName or "系统")
+end
+
+----------------------------------------- 外部调用 -------------------------------------
+
+-- 起服初始化
+function Init()
+    -- 从数据库加载所有玩家数据
+    local cursor = LuaMongo.find(DB.db_peak_battlefield, {})
+    if cursor then
+        RANK_2_DATA = {}
+        UUID_2_RANK = {}
+        
+        local data = LuaMongo.next(cursor)
+        while data do
+            RANK_2_DATA[#RANK_2_DATA + 1] = data
+            data = LuaMongo.next(cursor)
+        end
+        
+        sortRank()
+        print("[ServerCommerceActPeakBettle - Init] 巅峰战场数据加载完成")
+    end
+    return true
+end
+
+-- 活动结束
+function End()
+    -- 活动结束后可以重置数据(如果需要)
+end
+
+-- 重置玩家数据
+function ResetData(human)
+    if not human then
+        return
+    end
+end
+
+----------------------------------------- 客户端请求 -------------------------------------
+
+-- 查询巅峰战场数据
+function CommerceActPeakBettle_Query(human)
+    -- 确保玩家已加入
+    if not getData(human.db._id) then
+        addPlayer(human)
+    end
+    
+    local data = getData(human.db._id)
+    if not data then return end
+    
+    local rank = getRank(human.db._id)
+    local freeCnt = getFreeChallengeCnt(human.db._id)
+    local opponentList = getOpponentList(human.db._id)
+    local unlockedHeroes = getUnlockedHeroes(human.db._id)
+    
+    -- 如果没有对手列表,生成对手
+    if not opponentList or #opponentList == 0 then
+        opponentList = generateOpponents(human.db._id, rank)
+        setOpponentList(human.db._id, opponentList)
+    end
+    
+    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_QUERY
+    msgRet.rank = rank
+    msgRet.freeChallengeCnt = freeCnt
+    
+    -- 填充对手列表
+    local len = 0
+    for i = 1, #opponentList do
+        if len >= OPPONENT_LIST_SIZE then break end
+        local opponent = opponentList[i]
+        local opponentData = getData(opponent.uuid)
+        if opponentData then
+            len = len + 1
+            local net = msgRet.opponentList[len]
+            net.uuid = opponent.uuid
+            net.rank = opponent.rank or opponentData.rank
+            
+            -- 填充角色信息
+            local db = RoleDBLogic.getDb(opponent.uuid)
+            if db then
+                RoleLogic.makeRoleBase(db, net.roleBase)
+            else
+                -- 如果是NPC或离线玩家,使用缓存数据
+                net.roleBase.name = opponentData.name or ""
+                net.roleBase.lv = opponentData.lv or 1
+                net.roleBase.head = opponentData.head or 0
+                net.roleBase.zhandouli = opponentData.zhandouli or 0
+            end
+        end
+    end
+    msgRet.opponentList[0] = len
+    
+    -- 填充已解锁英雄
+    len = 0
+    for i = 1, #unlockedHeroes do
+        if len >= 50 then break end
+        len = len + 1
+        msgRet.unlockedHeroes[len] = unlockedHeroes[i]
+    end
+    msgRet.unlockedHeroes[0] = len
+    
+    -- 活动剩余时间
+    msgRet.leftTime = getActivityLeftTime()
+    
+    Msg.send(msgRet, human.fd)
+end
+
+-- 刷新对手列表
+function CommerceActPeakBettle_Refresh(human)
+    local rank = getRank(human.db._id)
+    local opponentList = generateOpponents(human.db._id, rank)
+    setOpponentList(human.db._id, opponentList)
+    
+    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_REFRESH
+    local len = 0
+    for i = 1, #opponentList do
+        if len >= OPPONENT_LIST_SIZE then break end
+        local opponent = opponentList[i]
+        local opponentData = getData(opponent.uuid)
+        if opponentData then
+            len = len + 1
+            local net = msgRet.opponentList[len]
+            net.uuid = opponent.uuid
+            net.rank = opponent.rank or opponentData.rank
+            
+            local db = RoleDBLogic.getDb(opponent.uuid)
+            if db then
+                RoleLogic.makeRoleBase(db, net.roleBase)
+            else
+                net.roleBase.name = opponentData.name or ""
+                net.roleBase.lv = opponentData.lv or 1
+                net.roleBase.head = opponentData.head or 0
+                net.roleBase.zhandouli = opponentData.zhandouli or 0
+            end
+        end
+    end
+    msgRet.opponentList[0] = len
+    
+    Msg.send(msgRet, human.fd)
+end
+
+-- 挑战对手
+function CommerceActPeakBettle_Challenge(human, opponentUuid)
+    -- 检查对手是否在对手列表中
+    local opponentList = getOpponentList(human.db._id)
+    local found = false
+    for i = 1, #opponentList do
+        if opponentList[i].uuid == opponentUuid then
+            found = true
+            break
+        end
+    end
+    
+    if not found then
+        return Broadcast.sendErr(human, "对手不在列表中")
+    end
+    
+    -- 检查挑战次数
+    local freeCnt = getFreeChallengeCnt(human.db._id)
+    if freeCnt > 0 then
+        -- 使用免费次数
+        if not consumeFreeChallenge(human.db._id) then
+            return Broadcast.sendErr(human, "免费挑战次数不足")
+        end
+    else
+        -- 消耗道具
+        if not BagLogic.checkItem(human, CHALLENGE_COST_ITEM_ID, CHALLENGE_COST_ITEM_CNT) then
+            return Broadcast.sendErr(human, "挑战券不足")
+        end
+        BagLogic.delItem(human, CHALLENGE_COST_ITEM_ID, CHALLENGE_COST_ITEM_CNT, "peak_battlefield_challenge")
+    end
+    
+    -- 启动战斗
+    local cbParam = {
+        opponentUuid = opponentUuid,
+        combatType = COMBAT_TYPE_PEAK_BATTLEFIELD
+    }
+    
+    CombatLogic.combatBegin(human, nil, {opponentUuid = opponentUuid}, COMBAT_TYPE_PEAK_BATTLEFIELD, cbParam, false)
+end
+
+-- 战斗结束回调
+function CommerceActPeakBettle_OnFightEnd(human, result, combatType, cbParam, combatInfo, param)
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return end
+    if not cbParam or not cbParam.opponentUuid then return end
+    
+    local opponentUuid = cbParam.opponentUuid
+    local isWin = (result == CombatDefine.RESULT_WIN)
+    
+    local oldRank = getRank(human.db._id)
+    local newRank = oldRank
+    
+    -- 胜利:交换排名
+    if isWin then
+        swapRank(human.db._id, opponentUuid)
+        newRank = getRank(human.db._id)
+        
+        -- 刷新对手列表
+        local rank = getRank(human.db._id)
+        local opponentList = generateOpponents(human.db._id, rank)
+        setOpponentList(human.db._id, opponentList)
+        
+        -- 检查英雄解锁
+        checkAndUnlockHeroes(human, newRank)
+    end
+    
+    -- 失败:发送邮件通知(给被挑战者)
+    if not isWin then
+        sendDefeatMail(opponentUuid, human.db._id, newRank)
+    end
+    
+    -- 发放奖励(挑战奖励,rewardType=1)
+    local rewardId = isWin and REWARD_ID_WIN or REWARD_ID_LOSE
+    local rewardConfig = PeakBattlefieldRewardExcel.rankReward[rewardId]
+    if rewardConfig and rewardConfig.rewardType == 1 and rewardConfig.reward then
+        BagLogic.addItemList(human, rewardConfig.reward, "peak_battlefield_challenge")
+    end
+    
+    -- 发送结果
+    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_CHALLENGE
+    msgRet.result = isWin and 1 or 2
+    msgRet.newRank = newRank
+    
+    -- 填充奖励
+    msgRet.reward[0] = 0
+    if rewardConfig and rewardConfig.rewardType == 1 and rewardConfig.reward then
+        for i = 1, #rewardConfig.reward do
+            local item = rewardConfig.reward[i]
+            msgRet.reward[0] = msgRet.reward[0] + 1
+            Grid.makeItem(msgRet.reward[msgRet.reward[0]], item[1], item[2])
+        end
+    end
+    
+    -- 胜利时发送新的对手列表
+    if isWin then
+        local opponentList = getOpponentList(human.db._id)
+        local len = 0
+        for i = 1, #opponentList do
+            if len >= OPPONENT_LIST_SIZE then break end
+            local opponent = opponentList[i]
+            local opponentData = getData(opponent.uuid)
+            if opponentData then
+                len = len + 1
+                local net = msgRet.opponentList[len]
+                net.uuid = opponent.uuid
+                net.rank = opponent.rank or opponentData.rank
+                
+                local db = RoleDBLogic.getDb(opponent.uuid)
+                if db then
+                    RoleLogic.makeRoleBase(db, net.roleBase)
+                else
+                    net.roleBase.name = opponentData.name or ""
+                    net.roleBase.lv = opponentData.lv or 1
+                    net.roleBase.head = opponentData.head or 0
+                    net.roleBase.zhandouli = opponentData.zhandouli or 0
+                end
+            end
+        end
+        msgRet.opponentList[0] = len
+    else
+        msgRet.opponentList[0] = 0
+    end
+    
+    Msg.send(msgRet, human.fd)
+end
+
+-- 查询排名奖励
+function CommerceActPeakBettle_RankRewardQuery(human)
+    local rank = getRank(human.db._id)
+    
+    local msgRet = Msg.gc.GC_PEAK_BATTLEFIELD_RANK_REWARD_QUERY
+    msgRet.rank = rank
+    
+    -- 填充奖励列表(从Excel配置读取,只读取排名奖励 rewardType=2或3)
+    local len = 0
+    if PeakBattlefieldRewardExcel.rankReward then
+        for rewardID, config in pairs(PeakBattlefieldRewardExcel.rankReward) do
+            -- 只处理排名奖励(rewardType=2或3),排除挑战奖励(rewardType=1)
+            if config.rewardType and (config.rewardType == 2 or config.rewardType == 3) then
+                if config.rank and type(config.rank) == "table" and #config.rank >= 2 then
+                    local rankMin = config.rank[1]
+                    local rankMax = config.rank[2]
+                    if rank >= rankMin and rank <= rankMax then
+                        len = len + 1
+                        if len <= 20 then
+                            msgRet.rewardList[len] = rewardID
+                        end
+                    end
+                end
+            end
+        end
+    end
+    msgRet.rewardList[0] = len
+    
+    Msg.send(msgRet, human.fd)
+end
+
+-- 活动结算(活动结束时发放排名奖励)
+function CommerceActPeakBettle_OnActivityEnd()
+    -- 获取所有玩家数据
+    if not RANK_2_DATA then return end
+    
+    -- 遍历所有排名,发放奖励
+    for rank = 1, #RANK_2_DATA do
+        local data = RANK_2_DATA[rank]
+        if data and data._id then
+            -- 根据排名查找对应的奖励配置(只处理排名奖励 rewardType=2或3)
+            if PeakBattlefieldRewardExcel.rankReward then
+                for rewardID, config in pairs(PeakBattlefieldRewardExcel.rankReward) do
+                    -- 只处理排名奖励,排除挑战奖励
+                    if config.rewardType and (config.rewardType == 2 or config.rewardType == 3) then
+                        if config.rank and type(config.rank) == "table" and #config.rank >= 2 then
+                            local rankMin = config.rank[1]
+                            local rankMax = config.rank[2]
+                            if rank >= rankMin and rank <= rankMax then
+                                -- 发放排名奖励(通过邮件)
+                                local mailID = MAIL_ID_RANK_REWARD
+                                if mailID and mailID > 0 then
+                                    local mailConfig = MailExcel.mail[mailID]
+                                    if mailConfig and config.reward then
+                                        local content = Util.format(mailConfig.content or "", rank)
+                                        MailManager.add(MailManager.SYSTEM, data._id, mailConfig.title or "巅峰战场排名奖励", content, config.reward, mailConfig.senderName or "系统")
+                                    end
+                                end
+                                break  -- 找到对应奖励后跳出
+                            end
+                        end
+                    end
+                end
+            end
+        end
+    end
+end
+
+-- 检查红点
+function isRed(human)
+    -- 可以根据需要实现红点逻辑
+    return false
+end
+
+----------------------------------------- 战斗模块接口 -------------------------------------
+-- 供战斗模块使用的公共接口
+
+-- 获取玩家数据(供战斗模块使用)
+function GetData(uuid)
+    return getData(uuid)
+end
+
+-- 检查对手是否存在(供战斗模块使用)
+function CheckOpponent(opponentUuid)
+    local data = getData(opponentUuid)
+    return data ~= nil
+end
+

+ 85 - 0
script/module/serverCommerce/ServerCommerceActPeakBettleCombat.lua

@@ -0,0 +1,85 @@
+----------------------------------------------------------------
+-- 巅峰战场战斗模块
+-- 用于注册到 CombatLogic 的战斗模块系统
+----------------------------------------------------------------
+
+local CombatDefine = require("combat.CombatDefine")
+local CombatLogic = require("combat.CombatLogic")
+local ServerCommerceActPeakBettle = require("serverCommerce.ServerCommerceActPeakBettle")
+local RoleDBLogic = require("role.RoleDBLogic")
+local CombatPosLogic = require("combat.CombatPosLogic")
+
+-- 战斗类型(需要在 CombatDefine 中添加,或使用 Excel 配置)
+local COMBAT_TYPE_PEAK_BATTLEFIELD = CombatDefine.COMBAT_TYPE35 or 35
+
+local module = {}
+
+-- 获取对手的战斗对象列表(防守方)
+function module.getCombatObjList(human, side, args, combatType)
+    if side ~= CombatDefine.DEFEND_SIDE then return end
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return end
+    
+    local opponentUuid = args.opponentUuid
+    if not opponentUuid then return end
+    
+    -- 获取对手数据(通过 serverCommerce 模块)
+    -- 注意:这里需要访问 ServerCommerceActPeakBettle 的内部函数
+    -- 由于是 local 函数,可能需要添加公共接口或使用其他方式
+    
+    -- 如果是玩家,使用玩家的防守阵容
+    local target = CombatLogic.createCombatFakeHuman(opponentUuid)
+    if target then
+        return CombatLogic.getHumanObjList(target, COMBAT_TYPE_PEAK_BATTLEFIELD)
+    end
+    
+    -- 如果是NPC或系统数据,使用系统提供的英雄数据
+    -- 这里需要根据实际需求实现系统英雄数据的创建
+    -- 暂时返回 nil,需要后续实现
+    return nil
+end
+
+-- 获取地图ID
+function module.getMapID(human, param)
+    -- 巅峰战场使用固定地图,或从配置读取
+    return nil  -- 使用默认地图
+end
+
+-- 检查是否可以打开上阵界面
+function module.checkCombatPos(human, args, combatType)
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return true end
+    
+    -- 检查对手是否存在
+    local opponentUuid = args.opponentUuid
+    if not opponentUuid then return false end
+    
+    -- 使用公共接口检查对手
+    if not ServerCommerceActPeakBettle.CheckOpponent(opponentUuid) then
+        return false
+    end
+    
+    return true, {opponentUuid = opponentUuid}
+end
+
+-- 战斗开始前的处理
+function module.fight(human, args, combatType)
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return end
+    
+    -- 战斗已经在 ServerCommerceActPeakBettle.CommerceActPeakBettle_Challenge 中启动
+    -- 这里可以做额外的处理
+end
+
+-- 战斗结束回调
+function module.onFightEnd(human, result, combatType, cbParam, combatInfo, param, isSaodang)
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return end
+    
+    ServerCommerceActPeakBettle.CommerceActPeakBettle_OnFightEnd(human, result, combatType, cbParam, combatInfo, param)
+end
+
+-- 获取战斗名称
+function module.getCombatName(human, args, combatType)
+    if combatType ~= COMBAT_TYPE_PEAK_BATTLEFIELD then return "" end
+    return "巅峰战场"
+end
+
+return module
+

+ 117 - 0
script/module/serverCommerce/ServerCommerceActPeakBettleMiddle.lua

@@ -0,0 +1,117 @@
+--------------------------------
+-- 文件名       :   ServerCommerceActPeakBettleMiddle.lua
+-- 文件说明     :   巅峰战场跨服相关
+-- 创建时间     :   2025/11/13
+-- 创建人       :   WWF
+--------------------------------
+
+local Util = require("common.Util")
+local MiddleConnect = require("middle.MiddleConnect")
+local MiddleManager = require("middle.MiddleManager")
+local InnerMsg = require("core.InnerMsg")
+local Config = require("Config")
+local CommonDB = require("common.CommonDB")
+local Log = require("common.Log")
+local ServerCommerceActPeakBettle = require("serverCommerce.ServerCommerceActPeakBettle")
+local CommonDefine = require("common.CommonDefine")
+
+----------------------------------- 内部操作 ---------------------------
+
+local function PeakBettleMiddle_WriteLog(szLogText)
+    Log.write(Log.LOGID_OSS_COMMON_ACT, szLogText)
+end
+
+--------------------------- 跨服请求 ------------------------------
+
+-- 普通服请求跨服排名数据(普通->中心)
+function LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    
+    print("[LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C] 收到普通服请求跨服排名数据 nSrcServerID = "..msg.nSrcServerID.." nRankType = "..msg.nRankType)
+    
+    -- 转发到数据服(如果需要跨服排名)
+    -- 这里可以根据实际需求实现跨服排名逻辑
+    -- 暂时先记录日志
+    PeakBettleMiddle_WriteLog("[LW_PEAK_BATTLEFIELD_QUERY_RANK_O2C] 收到跨服排名请求")
+end
+
+-- 请求跨服排名数据(中心->数据服)
+function WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D(fd, msg)
+    print("[WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D] 数据服收到跨服排名请求")
+    
+    -- 这里需要实现从数据库获取跨服排名数据的逻辑
+    -- 暂时先记录日志
+    PeakBettleMiddle_WriteLog("[WL_PEAK_BATTLEFIELD_QUERY_RANK_C2D] 数据服收到跨服排名请求")
+end
+
+-- 请求跨服排名数据(数据服->中心)
+function LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    
+    print("[LW_PEAK_BATTLEFIELD_QUERY_RANK_D2C] 数据服回复跨服排名数据")
+    
+    -- 转发到普通服
+    local nSrcFD = MiddleManager.getFDBySvrIndex(msg.nSrcServerID)
+    if nSrcFD then
+        local tMsgData = InnerMsg.wl.WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O
+        tMsgData.nFirst = msg.nFirst
+        tMsgData.nIsEnd = msg.nIsEnd
+        tMsgData.tRankInfo = msg.tRankInfo
+        InnerMsg.sendMsg(nSrcFD, tMsgData)
+    end
+end
+
+-- 获取到跨服排名数据(中心->普通)
+function WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O(fd, msg)
+    print("[WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O] 普通服收到跨服排名数据")
+    
+    -- 这里可以调用 ServerCommerceActPeakBettle 的处理函数
+    -- 暂时先记录日志
+    PeakBettleMiddle_WriteLog("[WL_PEAK_BATTLEFIELD_QUERY_RANK_C2O] 普通服收到跨服排名数据")
+end
+
+-- 普通服通知排名变化(普通->中心)
+function LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    
+    print("[LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C] 收到排名变化通知 uuid = "..msg.uuid.." nRank = "..msg.nRank)
+    
+    -- 转发到数据服
+    -- 这里可以根据实际需求实现跨服排名更新逻辑
+    PeakBettleMiddle_WriteLog("[LW_PEAK_BATTLEFIELD_RANK_CHANGE_O2C] 收到排名变化通知")
+end
+
+-- 排名变化通知(中心->数据服)
+function WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D(fd, msg)
+    print("[WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D] 数据服收到排名变化通知")
+    
+    -- 这里需要实现更新跨服排名数据的逻辑
+    PeakBettleMiddle_WriteLog("[WL_PEAK_BATTLEFIELD_RANK_CHANGE_C2D] 数据服收到排名变化通知")
+end
+
+-- 发送排名奖励(数据服->中心)
+function LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C(fd, msg)
+    if _G.is_middle ~= true then return end
+    
+    print("[LW_PEAK_BATTLEFIELD_SEND_RANK_REWARD_D2C] 数据服发送排名奖励 uuid = "..msg.uuid.." nRank = "..msg.nRank)
+    
+    -- 转发到普通服
+    local nSrcFD = MiddleManager.getFDBySvrIndex(msg.nServerID)
+    if nSrcFD then
+        local tMsgData = InnerMsg.wl.WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O
+        tMsgData.uuid = msg.uuid
+        tMsgData.nRank = msg.nRank
+        tMsgData.tReward = msg.tReward
+        InnerMsg.sendMsg(nSrcFD, tMsgData)
+    end
+end
+
+-- 发送排名奖励(中心->普通)
+function WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O(fd, msg)
+    print("[WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O] 普通服收到排名奖励 uuid = "..msg.uuid)
+    
+    -- 调用 ServerCommerceActPeakBettle 的处理函数发送奖励
+    -- 暂时先记录日志
+    PeakBettleMiddle_WriteLog("[WL_PEAK_BATTLEFIELD_SEND_RANK_REWARD_C2O] 普通服收到排名奖励")
+end
+

BIN
webServer.zip


+ 20 - 0
webServer/.vscode/launch.json

@@ -0,0 +1,20 @@
+{
+    // 使用 IntelliSense 了解相关属性。 
+    // 悬停以查看现有属性的描述。
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "node",
+            "request": "launch",
+            "name": "启动程序",
+            "skipFiles": [
+                "<node_internals>/**"
+            ],
+            "program": "${workspaceFolder}/src/router/index.ts",
+            "outFiles": [
+                "${workspaceFolder}/**/*.js"
+            ]
+        }
+    ]
+}

+ 133 - 0
webServer/iosApi.md

@@ -0,0 +1,133 @@
+# iOS SDK API 文档
+
+## 接口说明
+
+根据第三方 API 文档实现 iOS 平台的鉴权功能。
+
+---
+
+## 1. 用户鉴权接口
+
+### 接口地址
+- **GET/POST** `/ios/checkUserToken`
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| userToken | string | 是 | 鉴权凭证,从 URL 上获取 |
+| gameid | number | 是 | 游戏的ID,商户后台游戏添加完成后可获取 |
+
+### 请求示例
+```bash
+# GET 请求
+GET /ios/checkUserToken?userToken=your_token_here&gameid=1540
+
+# POST 请求
+POST /ios/checkUserToken
+Content-Type: application/json
+
+{
+  "userToken": "your_token_here",
+  "gameid": 1540
+}
+```
+
+### 响应参数
+```json
+{
+  "uid": "",           // 用户UID
+  "nickname": "",      // 用户昵称
+  "headimgurl": "",    // 用户头像地址
+  "sex": "",           // 用户性别 0未知 1男 2女
+  "focus": "",         // 是否关注公众号 0否 1是
+  "usertype": "",      // 用户类型 1为微信用户 -1为非微信用户
+  "error": 0           // 错误码,0表示成功
+}
+```
+
+### 错误响应
+
+#### 参数错误 (401)
+```json
+{
+  "error": 401,
+  "msg": "参数有误,请检查接口所需参数是否都已经填写正确",
+  "uid": "",
+  "nickname": "",
+  "headimgurl": "",
+  "sex": "",
+  "focus": "",
+  "usertype": ""
+}
+```
+
+#### Token验证失败 (403)
+```json
+{
+  "error": 403,
+  "msg": "token验证失败,同一个userToken只能验证一次,可通过刷新游戏重新获取",
+  "uid": "",
+  "nickname": "",
+  "headimgurl": "",
+  "sex": "",
+  "focus": "",
+  "usertype": ""
+}
+```
+
+#### 系统错误 (-1)
+```json
+{
+  "error": -1,
+  "msg": "鉴权失败,请稍后重试",
+  "uid": "",
+  "nickname": "",
+  "headimgurl": "",
+  "sex": "",
+  "focus": "",
+  "usertype": ""
+}
+```
+
+---
+
+## 2. 获取用户信息接口(备用)
+
+### 接口地址
+- **GET/POST** `/ios/getUserInfo`
+
+### 请求参数
+同鉴权接口
+
+### 响应参数
+同鉴权接口
+
+---
+
+## 错误码说明
+
+| 错误码 | 类型 | 说明 |
+|--------|------|------|
+| 0 | Number | 成功 |
+| 401 | Number | 参数有误,请检查接口所需参数是否都已经填写正确 |
+| 403 | Number | token验证失败,同一个userToken只能验证一次,可通过刷新游戏重新获取 |
+| -1 | Number | 系统错误,鉴权失败,请稍后重试 |
+
+## 重要说明
+
+⚠️ **同一个token只能验证一次,不能多次重复请求**
+
+## 第三方API
+
+- **请求方式**: GET
+- **URL**: `https://api.11h5.com/login?cmd=checkUserToken`
+- **参数**: userToken, gameid
+
+## 实现特点
+
+1. **支持 GET 和 POST 请求**
+2. **参数验证**:检查必要参数
+3. **错误处理**:统一的错误响应格式
+4. **日志记录**:详细的请求和响应日志
+5. **超时设置**:10秒请求超时
+6. **直接透传**:直接返回第三方API的响应数据

+ 81 - 0
webServer/miniAppApi.md

@@ -0,0 +1,81 @@
+根据 `MiniAppController.ts` 里的实际参数获取和校验,下面是各接口的详细 API 文档:
+
+---
+
+### 1. 小程序登录鉴权
+
+- **接口地址**:`POST /wxLogin`
+- **请求参数**(JSON):
+    - `token`:用户登录 token(string,必填)
+- **响应参数**(JSON):
+    - `code`:0 成功,-1 失败
+    - `msg`:提示信息
+    - `data`:微信登录接口返回的数据
+
+---
+
+### 2. 小程序支付回调
+
+- **接口地址**:`GET /wxPay`
+- **请求参数**(Query):
+    - `uid`:用户 ID(string,必填)
+    - `rmb`:支付金额(string,必填)
+    - `reqid`:订单号(string,必填)
+    - `trans_id`:交易号(string,必填)
+    - `product_id`:商品 ID(string,必填)
+    - `notify_id`:平台通知 ID(string,必填)
+    - `sign`:签名(string,必填)
+- **响应**:
+    - `SUCCESS` 或 `FAIL`(字符串)
+
+---
+
+### 3. 内容安全审核
+
+- **接口地址**:`POST /contentSecurityCheck`
+- **请求参数**(JSON):
+    - `uid`:用户 ID(string,必填)
+    - `gameid`:游戏 ID(string,必填)
+    - `signature`:签名(string,必填)
+    - `timestamp`:时间戳(string,必填)
+    - `nonce`:随机串(string,必填)
+    - `scene`:场景(string,必填)
+    - `content`:待审核内容(string,必填)
+    - `nickname`:昵称(string,选填)
+    - `title`:标题(string,选填)
+    - `usersign`:用户签名(string,选填)
+- **响应参数**(JSON):
+    - `code`:0 成功,-1 失败
+    - `msg`:提示信息
+    - `data`:审核结果(如 suggest、label、trace_id、detail)
+
+---
+
+### 4. 角色名称修改上报
+
+- **接口地址**:`POST /editUserRoleInfo`
+- **请求参数**(JSON):
+    - `openId`:用户 openId(string,必填)
+    - `time`:时间戳(string,必填)
+    - `gameid`:游戏 ID(string,必填)
+    - `serverid`:区服 ID(string,必填)
+    - `playerName`:角色名(string,必填)
+    - `sign`:签名(string,必填)
+- **响应参数**(JSON):
+    - `error`:0 成功,-1 失败
+    - `errmsg`:提示信息
+
+---
+
+### 5. 验证支付是否成功
+
+- **接口地址**:`POST /wxOrderCheck`
+- **请求参数**(JSON):
+    - `notifyId`:平台通知 ID(string,必填)
+- **响应参数**(JSON):
+    - `success`:true/false
+    - `message`:结果说明
+
+---
+
+所有接口参数均需按实际代码校验和签名规则传递。

Dosya farkı çok büyük olduğundan ihmal edildi
+ 5306 - 1689
webServer/package-lock.json


+ 3 - 1
webServer/package.json

@@ -27,7 +27,7 @@
     "koa-logger": "^3.2.1",
     "koa-redis": "^4.0.1",
     "moment-timezone": "^0.5.45",
-    "mongodb": "^4.17.1",
+    "mongodb": "^2.2.36",
     "mongodb-client-encryption": "^6.3.0",
     "mongoose": "^8.14.0",
     "mysql": "^2.18.1",
@@ -39,6 +39,7 @@
     "snappy": "^7.2.2",
     "socks": "^2.8.4",
     "stream-browserify": "^3.0.0",
+    "string_decoder": "^1.3.0",
     "ts-md5": "^1.3.1",
     "typescript": "^5.5.4",
     "utf-8-validate": "^6.0.3",
@@ -48,6 +49,7 @@
     "xml2js": "^0.6.2"
   },
   "devDependencies": {
+    "@types/eslint": "^9.6.1",
     "@types/node": "^22.15.3",
     "node-loader": "^2.1.0",
     "terser-webpack-plugin": "^5.3.10",

+ 233 - 0
webServer/serverListApi.md

@@ -0,0 +1,233 @@
+# 服务器列表接口 API 文档
+
+## 接口说明
+
+`getAllServerList` 和 `getLastServerList` 接口已升级,支持查询玩家在各个服务器的角色信息。
+
+---
+
+## 1. 获取所有服务器列表
+
+### 接口地址
+- **GET** `/getAllServerList`
+- **POST** `/getAllServerList`
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| channel_id | number | 否 | 渠道ID,默认为1 |
+| uid | string | 否 | 玩家ID,提供时会查询角色信息。不提供时只返回基本服务器信息 |
+
+### 请求示例
+
+#### 不查询角色信息
+```bash
+GET /getAllServerList?channel_id=11
+```
+
+#### 查询角色信息
+```bash
+GET /getAllServerList?channel_id=11&uid=12345678
+```
+
+#### POST请求
+```bash
+POST /getAllServerList
+Content-Type: application/json
+
+{
+  "channel_id": 11,
+  "uid": "12345678"
+}
+```
+
+### 响应参数
+
+#### 不提供uid时的响应
+```json
+[
+  {
+    "id": 1,
+    "name": "1区",
+    "ip": "192.168.1.100",
+    "port": 8080,
+    "status": 0,
+    "tips": "正常"
+  }
+]
+```
+
+#### 提供uid时的响应
+```json
+[
+  {
+    "id": 1,
+    "name": "1区",
+    "ip": "192.168.1.100",
+    "port": 8080,
+    "status": 0,
+    "tips": "正常",
+    "roleName": "玩家昵称",
+    "roleLevel": 50,
+    "head": "avatar_001.png",
+    "hasRole": true
+  },
+  {
+    "id": 2,
+    "name": "2区",
+    "ip": "192.168.1.101",
+    "port": 8080,
+    "status": 0,
+    "tips": "正常",
+    "roleName": null,
+    "roleLevel": null,
+    "head": null,
+    "hasRole": false
+  }
+]
+```
+
+---
+
+## 2. 获取最近登录服务器列表
+
+### 接口地址
+- **POST** `/getLastServerList`
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| uid | string | 否 | 玩家ID,用于查询角色信息。不提供时只返回基本服务器信息 |
+| channel_id | number | 否 | 渠道ID,默认为1 |
+
+### 请求示例
+
+#### 查询角色信息
+```bash
+POST /getLastServerList
+Content-Type: application/json
+
+{
+  "uid": "12345678",
+  "channel_id": 11
+}
+```
+
+#### 不查询角色信息
+```bash
+POST /getLastServerList
+Content-Type: application/json
+
+{
+  "channel_id": 11
+}
+```
+
+### 响应参数
+```json
+[
+  {
+    "channel": "小程序",
+    "minSid": 1,
+    "maxSid": 10,
+    "isNewAccount": 0,
+    "sid": 1,
+    "id": 1,
+    "name": "1区",
+    "tips": "正常",
+    "server": "ws://192.168.1.100:8080",
+    "status": 0,
+    "roleName": "玩家昵称",
+    "roleLevel": 50,
+    "head": "avatar_001.png",
+    "hasRole": true
+  }
+]
+```
+
+---
+
+## 3. 角色信息字段说明
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| roleName | string/null | 角色名称,无角色时为null |
+| roleLevel | number/null | 角色等级,无角色时为null |
+| head | string/null | 角色头像,无角色时为null |
+| hasRole | boolean | 是否有角色,true表示有角色,false表示无角色 |
+
+---
+
+## 4. 数据库查询逻辑
+
+### 数据库名称生成规则
+```
+数据库名称 = "ckwy_fy_S" + (350001 + 服务器ID).padStart(3, '0')
+```
+
+### 查询条件
+- 集合名称:`char`
+- 查询条件:`{uid: 玩家ID}`
+
+### 返回字段
+- `name`: 角色名称
+- `lv`: 角色等级
+- `roleId`: 角色ID
+- `head`: 角色头像
+
+---
+
+## 5. 错误处理
+
+- 如果查询角色信息失败,会记录错误日志,但不会影响服务器列表的返回
+- 查询失败时,角色相关字段会设置为null或false
+- 数据库连接失败时会返回默认值
+
+---
+
+## 6. 性能优化
+
+- 使用 `Promise.all` 并行查询多个服务器的角色信息
+- 查询失败时不会阻塞其他服务器的查询
+- 只查询有玩家ID的请求,避免不必要的数据库查询
+
+---
+
+## 7. 使用示例
+
+### JavaScript示例
+```javascript
+// 获取所有服务器列表(带角色信息)
+const getAllServers = async (uid) => {
+  const response = await fetch(`/getAllServerList?uid=${uid}&channel_id=11`);
+  const servers = await response.json();
+  
+  servers.forEach(server => {
+    if (server.hasRole) {
+      console.log(`服务器${server.name}: ${server.roleName} (等级${server.roleLevel}) 头像: ${server.head}`);
+    } else {
+      console.log(`服务器${server.name}: 无角色`);
+    }
+  });
+};
+
+// 获取最近登录服务器列表
+const getLastServers = async (uid) => {
+  const response = await fetch('/getLastServerList', {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify({ uid, channel_id: 11 })
+  });
+  const servers = await response.json();
+  return servers;
+};
+```
+
+---
+
+## 8. 重要说明
+
+- **向后兼容**: 不提供uid时,接口行为与之前完全一致
+- **性能考虑**: 提供uid时会查询所有服务器的角色信息,可能影响响应时间
+- **数据一致性**: 角色信息来自MongoDB,与游戏服务器数据保持同步
+- **错误容错**: 单个服务器查询失败不会影响整体结果

+ 8 - 0
webServer/src/channels/factory/ChannelFactory.ts

@@ -8,6 +8,10 @@ import { ThreeSixZeroChannelHandler } from "../handlers/ThreeSixZeroChannelHandl
 import { MuZiChannelHandler } from "../handlers/MuZiChannelHandler";
 import { QiAiH5ChannelHandler } from "../handlers/QiAiH5ChannelHandler";
 import { MuZiIosChannelHandler } from "../handlers/MuZiIosChannelHandler";
+import { MiniappChannelHandler } from "../handlers/MiniappChannelHandler";
+import { SYIOSChannelHandler } from "../handlers/SYIOSChannelHandler";
+import { MianyouChannelHandler } from "../handlers/MianyouChannelHandler";
+import { HupuChannelHandler } from "../handlers/HupuChannelHandler";
 
 
 const logger = require("../../utils/log");
@@ -39,6 +43,10 @@ class ChannelFactory {
     this.registerHandler(8, new QiAiH5ChannelHandler()); // qi ai
     this.registerHandler(9, new MuZiIosChannelHandler()); // muzi ios
     this.registerHandler(10, new SanLiAndroidChannelHandler()); // muzi ios
+    this.registerHandler(11, new MiniappChannelHandler()); // miniapp
+    this.registerHandler(12, new SYIOSChannelHandler()); // sy ios
+    this.registerHandler(13, new MianyouChannelHandler()); // 面游渠道
+    this.registerHandler(14, new HupuChannelHandler()); // 面游渠道
   }
 
   /**

+ 2 - 2
webServer/src/channels/handlers/FourThreeNineNineChannelHandler.ts

@@ -11,7 +11,7 @@ const logger = require("../../utils/log");
 
 export class FourThreeNineNineChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("4399登录请求参数:", { data });
 
     const secondsTimestamp = Math.floor(Date.now() / 1000);
@@ -45,7 +45,7 @@ export class FourThreeNineNineChannelHandler implements ChannelHandler {
       msg: "发货失败",
     };
 
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     const orderId = data.mark;
     const out_trade_no = data.orderId;
 

+ 161 - 0
webServer/src/channels/handlers/HupuChannelHandler.ts

@@ -0,0 +1,161 @@
+import {Context} from "koa";
+import axios from "axios";
+import {parseString} from "xml2js";
+
+import {ChannelHandler, LoginResult, PaymentResult} from "../interfaces/ChannelHandler";
+import {ChannelConfig} from "../../config/channelConfig";
+import {SignatureVerifier} from "../../utils/SignatureVerifier";
+import QuickAsy from "../../utils/quickAsy";
+import {PaymentHelper} from "../../utils/PaymentHelper";
+
+const logger = require("../../utils/log");
+
+/**
+ * Hupu(QuickSDK)渠道处理器
+ * 负责登录验证与支付回调处理
+ */
+export class HupuChannelHandler implements ChannelHandler {
+
+    /**
+     * QuickSDK 登录验证
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        const data = ctx.request.body as any;
+        const {token, uid, channel_code, product_code} = data || {};
+        const finalProductCode = product_code || config.loginConfig?.productCode;
+
+        if (!token || !uid) {
+            logger.warn("Hupu登录验证失败: 缺少必要参数", {token, uid});
+            return {code: 0, msg: "缺少必要参数 token 或 uid"};
+        }
+
+        if (!finalProductCode) {
+            logger.error("Hupu登录验证失败: 未配置productCode");
+            return {code: 0, msg: "服务器未配置productCode"};
+        }
+
+        const requestUrl = "http://checkuser.quickapi.net/v2/checkUserInfo";
+        const params: Record<string, string> = {
+            token,
+            uid,
+            product_code: finalProductCode
+        };
+        if (channel_code) {
+            params.channel_code = channel_code;
+        }
+
+        logger.info("Hupu登录验证请求", {url: requestUrl, params});
+
+        try {
+            const response = await axios.get(requestUrl, {params, timeout: 8000});
+            logger.info("Hupu登录验证响应", {data: response.data});
+
+            if (response.data === "1") {
+                return {code: 1, msg: "success"};
+            }
+
+            logger.warn("Hupu登录验证失败: 接口返回非1", {data: response.data});
+            return {code: 0, msg: "登录验证失败"};
+        } catch (error) {
+            logger.error("Hupu登录验证异常", error);
+            return {code: 0, msg: "登录验证异常"};
+        }
+    }
+
+    /**
+     * QuickSDK 支付回调
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
+        const data = ctx.request.body as any;
+        logger.info("Hupu支付回调参数", {url: ctx.href, params: data});
+
+        const {nt_data, sign, md5Sign} = data || {};
+        if (!nt_data || !sign || !md5Sign) {
+            logger.warn("Hupu支付回调失败: 缺少必要参数", {nt_data, sign, md5Sign});
+            return {code: 0, msg: "缺少必要参数"};
+        }
+
+        const md5Key = config.paymentConfig?.signKey;
+        const callbackKey = config.paymentConfig?.callbackKey;
+
+        if (!md5Key || !callbackKey) {
+            logger.error("Hupu支付回调失败: 未配置QuickSDK密钥");
+            return {code: 0, msg: "服务器未配置渠道密钥"};
+        }
+
+        if (!SignatureVerifier.verifyQuickSign(data, md5Key)) {
+            logger.warn("Hupu支付回调失败: 签名验证失败");
+            return {code: 0, msg: "签名验证失败"};
+        }
+
+        try {
+            const xmlData = QuickAsy.decode(nt_data, callbackKey);
+            const parsed = await this.parseQuickXml(xmlData);
+
+            const message = parsed.quicksdk_message.message[0];
+            const orderId = message.game_order?.[0];
+            const outTradeNo = message.order_no?.[0];
+            const status = message.status?.[0];
+            const amountStr = message.amount?.[0];
+
+            if (!orderId || !outTradeNo || typeof status === "undefined" || !amountStr) {
+                logger.error("Hupu支付回调失败: XML缺少必要字段", {message});
+                return {code: 0, msg: "回调数据不完整"};
+            }
+
+            if (status !== "0") {
+                logger.warn("Hupu支付状态非成功", {status});
+                return {code: 0, msg: "支付状态失败"};
+            }
+
+            const amount = parseFloat(amountStr);
+
+            const validation = await PaymentHelper.validateOrder(orderId);
+            if (!validation.valid) {
+                return {
+                    code: validation.message?.includes("重复发货") ? 1 : 0,
+                    msg: validation.message || "订单验证失败"
+                };
+            }
+
+            const orderInfo = validation.orderInfo;
+            if (Number(orderInfo.amount) !== amount) {
+                logger.warn("Hupu支付金额不匹配", {
+                    orderId,
+                    requestAmount: amount,
+                    orderAmount: orderInfo.amount
+                });
+                return {code: 0, msg: "订单金额不一致"};
+            }
+
+            logger.info(`Hupu支付订单${orderId}开始发货`);
+            const result = await PaymentHelper.deliverOrder(
+                orderInfo,
+                ctx.request.ip,
+                validation.url,
+                outTradeNo
+            );
+            logger.info(`Hupu支付订单${orderId}发货完成`, {result});
+            return result;
+        } catch (error) {
+            logger.error("Hupu支付回调解析异常", error);
+            return {code: 0, msg: "回调解析异常"};
+        }
+    }
+
+    private parseQuickXml(xml: string): Promise<any> {
+        return new Promise((resolve, reject) => {
+            parseString(xml, (err, result) => {
+                if (err) {
+                    return reject(err);
+                }
+                resolve(result);
+            });
+        });
+    }
+}
+

+ 469 - 0
webServer/src/channels/handlers/MianyouChannelHandler.ts

@@ -0,0 +1,469 @@
+import {Context} from 'koa';
+import * as crypto from 'crypto';
+import {ChannelHandler, LoginResult, PaymentResult} from '../interfaces/ChannelHandler';
+import {ChannelConfig} from '../../config/channelConfig';
+import {PaymentHelper} from '../../utils/PaymentHelper';
+import axios from 'axios';
+
+const logger = require('../../utils/log');
+
+// 开服同步接口定义
+export interface ServerSyncParams {
+    GAME_ID: number;
+    SID: number;
+    _SID: number | string;
+    NAME: string;
+    START_TIME: string;
+    timestamp: number;
+    sign: string;
+}
+
+export interface ServerSyncResult {
+    status: number;
+    msg: string;
+}
+
+export class MianyouChannelHandler implements ChannelHandler {
+    /**
+     * 处理登录验证
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     * @returns 登录结果
+     */
+    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const data = ctx.request.body as any;
+            const {uid, timestamp, token} = data;
+            let username = uid;
+            // 验证必要参数
+            if (!username || !timestamp || !token) {
+                logger.warn('Mianyou登录验证失败: 缺少必要参数', {username, timestamp, token});
+                return {
+                    code: 400,
+                    msg: '缺少必要参数: username, timestamp, token'
+                };
+            }
+
+            // 获取登录验证密钥
+            const loginKey = config.loginConfig?.signKey;
+            if (!loginKey) {
+                logger.error('Mianyou登录验证失败: 未配置登录密钥');
+                return {
+                    code: 500,
+                    msg: '服务器配置错误: 未配置登录密钥'
+                };
+            }
+
+            // 验证token
+            const expectedToken = this.generateToken(username, timestamp, loginKey);
+            if (token.toLowerCase() !== expectedToken.toLowerCase()) {
+                console.log("timestamp:", timestamp,username,loginKey);
+                logger.warn('Mianyou登录验证失败: token验证失败', {
+                    loginKey,
+                    username,
+                    timestamp,
+                    receivedToken: token,
+                    expectedToken
+                });
+                return {
+                    code: 401,
+                    msg: '登录验证失败: token无效'
+                };
+            }
+
+            // 验证时间戳(可选:检查时间戳是否在有效期内,比如5分钟内)
+            const currentTime = Math.floor(Date.now() / 1000);
+            const timeDiff = Math.abs(currentTime - timestamp);
+            const maxTimeDiff = 300; // 5分钟
+
+            if (timeDiff > maxTimeDiff) {
+                logger.warn('Mianyou登录验证失败: 时间戳过期', {
+                    username,
+                    timestamp,
+                    currentTime,
+                    timeDiff
+                });
+                return {
+                    code: 401,
+                    msg: '登录验证失败: 时间戳过期'
+                };
+            }
+
+            logger.info('Mianyou登录验证成功', {username, timestamp});
+
+            return {
+                code: 0,
+                msg: '登录验证成功',
+                data: {
+                    username,
+                    timestamp,
+                    channelId: config.channelId,
+                    platform: config.platform
+                }
+            };
+
+        } catch (error) {
+            logger.error('Mianyou登录验证异常', error);
+            return {
+                code: 500,
+                msg: '服务器内部错误'
+            };
+        }
+    }
+
+    /**
+     * 处理支付验证
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     * @returns 支付结果
+     */
+    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
+        try {
+            // 获取GET请求参数
+            const params = ctx.query as any;
+            const {
+                username,
+                order_id,
+                server,
+                amount,
+                extra,
+                sandbox,
+                timestamp,
+                sign
+            } = params;
+            let cpOrderId = extra
+            // 验证必要参数
+            if (!username || !order_id || !server || !amount || !extra|| !sandbox || !timestamp || !sign) {
+                logger.warn('Mianyou支付验证失败: 缺少必要参数', {
+                    username, order_id, server, amount, extra, sandbox, timestamp, sign
+                });
+                return {
+                    code: 400,
+                    msg: '缺少必要参数'
+                };
+            }
+
+            // 获取支付回调密钥
+            const paymentKey = config.paymentConfig?.signKey;
+            if (!paymentKey) {
+                logger.error('Mianyou支付验证失败: 未配置支付回调密钥');
+                return {
+                    code: 500,
+                    msg: '服务器配置错误: 未配置支付回调密钥'
+                };
+            }
+
+            // 验证签名
+            const expectedSign = this.generatePaymentSign(
+                username,
+                order_id,
+                server,
+                amount,
+                extra,
+                sandbox,
+                timestamp,
+                paymentKey
+            );
+
+            if (sign.toLowerCase() !== expectedSign.toLowerCase()) {
+                logger.warn('Mianyou支付验证失败: 签名验证失败', {
+                    username,
+                    order_id,
+                    receivedSign: sign,
+                    expectedSign
+                });
+                return {
+                    code: 401,
+                    msg: '支付验证失败: 签名无效'
+                };
+            }
+
+            // 验证时间戳(5分钟内有效)
+            const currentTime = Math.floor(Date.now() / 1000);
+            const timeDiff = Math.abs(currentTime - parseInt(timestamp));
+            const maxTimeDiff = 300; // 5分钟
+
+            // if (timeDiff > maxTimeDiff) {
+            //     logger.warn('Mianyou支付验证失败: 时间戳过期', {
+            //         username,
+            //         order_id,
+            //         timestamp,
+            //         currentTime,
+            //         timeDiff
+            //     });
+            //     return {
+            //         code: 401,
+            //         msg: '支付验证失败: 时间戳过期'
+            //     };
+            // }
+
+            // 验证金额格式
+            const paymentAmount = parseFloat(amount);
+            if (isNaN(paymentAmount) || paymentAmount <= 0) {
+                logger.warn('Mianyou支付验证失败: 金额格式错误', {
+                    username,
+                    cpOrderId,
+                    amount
+                });
+                return {
+                    code: 400,
+                    msg: '支付验证失败: 金额格式错误'
+                };
+            }
+
+            // 验证沙盒参数
+            const sandboxValue = parseInt(sandbox);
+            if (sandboxValue !== 0 && sandboxValue !== 1) {
+                logger.warn('Mianyou支付验证失败: 沙盒参数错误', {
+                    username,
+                    order_id,
+                    sandbox
+                });
+                return {
+                    code: 400,
+                    msg: '支付验证失败: 沙盒参数错误'
+                };
+            }
+
+            logger.info('Mianyou支付验证成功,开始处理发货', {
+                username,
+                cpOrderId,
+                order_id,
+                server,
+                amount: paymentAmount,
+                extra,
+                sandbox: sandboxValue === 1
+            });
+
+            // 验证订单
+            const validation = await PaymentHelper.validateOrder(cpOrderId);
+            if (!validation.valid) {
+                return {
+                    code: validation.message?.includes("重复发货") ? 1 : 0,
+                    msg: validation.message || "订单验证失败"
+                };
+            }
+            const orderInfo = validation.orderInfo;
+
+            // 直接调用系统封装的发货函数
+            const result = await PaymentHelper.deliverOrder(
+                orderInfo,
+                "127.0.0.1", // 使用默认IP地址
+                validation.url,
+                order_id // 使用订单号作为外部交易号
+            );
+
+            // 处理支付成功逻辑
+            logger.info(`Mianyou支付成功 - 用户: ${username}, 金额: ${paymentAmount}, 订单: ${cpOrderId}, 发货结果:`, result);
+            return result;
+
+        } catch (error) {
+            logger.error('Mianyou支付验证异常', error);
+            return {
+                code: 500,
+                msg: '服务器内部错误'
+            };
+        }
+    }
+
+    /**
+     * 生成token
+     * 根据文档:token = md5(username + timestamp + KEY)
+     * @param username 用户名
+     * @param timestamp 时间戳
+     * @param key 密钥
+     * @returns MD5哈希值(小写)
+     */
+    private generateToken(username: string, timestamp: number, key: string): string {
+        const data = username + timestamp + key;
+        console.log('generateToken data:', data);
+        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
+    }
+
+    /**
+     * 生成支付签名
+     * 根据文档:sign = md5(username + order_id + server + amount + extra + sandbox + timestamp + KEY)
+     * @param username 用户名
+     * @param order_id 订单号
+     * @param server 区服ID
+     * @param amount 支付金额
+     * @param extra 透传参数
+     * @param sandbox 沙盒标识
+     * @param timestamp 时间戳
+     * @param key 密钥
+     * @returns MD5哈希值(小写)
+     */
+    private generatePaymentSign(
+        username: string,
+        order_id: string,
+        server: string,
+        amount: string,
+        extra: string,
+        sandbox: string,
+        timestamp: string,
+        key: string
+    ): string {
+        const data = username + order_id + server + amount + extra + sandbox + timestamp + key;
+        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
+    }
+
+    /**
+     * 开服同步
+     * @param params 开服同步参数
+     * @param config 渠道配置
+     * @returns 同步结果
+     */
+    async syncServerOpen(params: Omit<ServerSyncParams, 'sign'>, config: ChannelConfig): Promise<ServerSyncResult> {
+        try {
+            // 获取游戏ID和密钥
+            const gameId = config.paymentConfig?.gameId;
+            const signKey = config.paymentConfig?.signKey;
+
+            if (!gameId || !signKey) {
+                logger.error('Mianyou开服同步失败: 缺少游戏ID或签名密钥');
+                return {
+                    status: -2,
+                    msg: '配置错误: 缺少游戏ID或签名密钥'
+                };
+            }
+
+            // 构建参数对象
+            const syncParams: Omit<ServerSyncParams, 'sign'> = {
+                GAME_ID: parseInt(gameId.toString()),
+                SID: params.SID,
+                _SID: params._SID,
+                NAME: params.NAME,
+                START_TIME: params.START_TIME,
+                timestamp: params.timestamp || Math.floor(Date.now() / 1000)
+            };
+
+            // 生成签名
+            const sign = this.generateServerSyncSign(syncParams, signKey);
+
+            // 构建完整参数
+            const fullParams: ServerSyncParams = {
+                ...syncParams,
+                sign
+            };
+
+            // 发送开服同步请求
+            const result = await this.sendServerSyncRequest(fullParams, config);
+
+            logger.info('Mianyou开服同步结果', {
+                params: syncParams,
+                result
+            });
+
+            return result;
+
+        } catch (error) {
+            logger.error('Mianyou开服同步异常', error);
+            return {
+                status: -9,
+                msg: '开服同步失败: 服务器内部错误'
+            };
+        }
+    }
+
+    /**
+     * 生成开服同步签名
+     * 根据文档:将所有参数按a-z升序排序后,将值直接拼接起来后再与密钥拼接,然后md5
+     * @param params 参数对象(不包含sign)
+     * @param key 签名密钥
+     * @returns MD5哈希值(小写)
+     */
+    private generateServerSyncSign(params: Omit<ServerSyncParams, 'sign'>, key: string): string {
+        // 按a-z升序排序参数
+        const sortedKeys = Object.keys(params).sort();
+
+        // 拼接所有参数值
+        const toSign = sortedKeys.map(key => params[key as keyof typeof params]).join('');
+
+        // 与密钥拼接后MD5
+        const data = toSign + key;
+        return crypto.createHash('md5').update(data).digest('hex').toLowerCase();
+    }
+
+    /**
+     * 发送开服同步请求
+     * @param params 完整参数(包含sign)
+     * @param config 渠道配置
+     * @returns 同步结果
+     */
+    private async sendServerSyncRequest(params: ServerSyncParams, config: ChannelConfig): Promise<ServerSyncResult> {
+        try {
+            // 构建请求URL
+            const sdkDomain = config.paymentConfig?.apiUrl;
+            const url = `${sdkDomain}/game/center/sync_server`;
+
+            // 构建form-data格式的请求体
+            const formData = new URLSearchParams();
+            Object.entries(params).forEach(([key, value]) => {
+                formData.append(key, value.toString());
+            });
+
+            logger.info('发送开服同步请求', {url, params});
+
+            // 发送POST请求
+            const response = await axios.post(url, formData, {
+                headers: {
+                    'Content-Type': 'application/x-www-form-urlencoded'
+                },
+                timeout: 10000
+            });
+
+            // 解析响应
+            const result = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;
+
+            logger.info('开服同步响应', {result});
+
+            return {
+                status: result.status || 0,
+                msg: result.msg || '未知响应'
+            };
+
+        } catch (error) {
+            logger.error('发送开服同步请求失败', error);
+            return {
+                status: -9,
+                msg: '网络请求失败'
+            };
+        }
+    }
+
+    /**
+     * 便捷的开服同步方法
+     * @param serverId 区服序号
+     * @param gameServerId 游戏区服ID
+     * @param serverName 区服名称
+     * @param startTime 开服时间
+     * @param config 渠道配置
+     * @returns 同步结果
+     */
+    async openServer(
+        serverId: number,
+        gameServerId: number | string,
+        serverName: string,
+        startTime: string,
+        config: ChannelConfig
+    ): Promise<ServerSyncResult> {
+        // 获取游戏ID
+        const gameId = config.paymentConfig?.gameId;
+        if (!gameId) {
+            return {
+                status: -2,
+                msg: '配置错误: 缺少游戏ID'
+            };
+        }
+
+        return await this.syncServerOpen({
+            GAME_ID: parseInt(gameId.toString()),
+            SID: serverId,
+            _SID: gameServerId,
+            NAME: serverName,
+            START_TIME: startTime,
+            timestamp: Math.floor(Date.now() / 1000)
+        }, config);
+    }
+
+}

+ 1124 - 0
webServer/src/channels/handlers/MiniappChannelHandler.ts

@@ -0,0 +1,1124 @@
+import {Context} from "koa";
+import * as crypto from 'crypto';
+import {ChannelHandler, LoginResult, PaymentResult,} from "../interfaces/ChannelHandler";
+import {ChannelConfig} from "../../config/channelConfig";
+import {ChannelConfigManager} from "../../utils/ChannelConfigManager";
+import {formatDate, getServerList} from "../../utils/common";
+import {Account} from "../../config/thirdParams";
+import {PaymentHelper} from "../../utils/PaymentHelper";
+
+import Msg from "../../utils/msg";
+import axios from "axios";
+
+const Order = require("../../model/OrderModel");
+const CryptoJS = require("crypto-js");
+const logger = require("../../utils/log");
+
+export class MiniappChannelHandler implements ChannelHandler {
+    /**
+     * 获取HTTPS代理配置
+     * @returns HTTPS代理配置
+     */
+    private getHttpsAgent() {
+        const https = require('https');
+        return new https.Agent({
+            rejectUnauthorized: false,
+            secureProtocol: 'TLSv1_2_method',
+            timeout: 10000
+        });
+    }
+
+    /**
+     * 获取通用请求头
+     * @returns 请求头配置
+     */
+    private getCommonHeaders() {
+        return {
+            'User-Agent': 'Mozilla/5.0 (compatible; WebServer/1.0)',
+            'Accept': 'application/json',
+            'Content-Type': 'application/json'
+        };
+    }
+
+    /**
+     * 统一登录鉴权(支持小程序和iOS)
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const data = ctx.request.body as any;
+            const platform = data.platform; // 平台参数:ios、Android、miniapp、h5
+
+            logger.info("统一登录请求", { platform, data });
+
+            // 根据平台选择不同的登录方式
+            if (platform === 'ios') {
+                return await this.handleIOSLogin(data, config);
+            } else {
+                // 默认使用小程序登录方式
+                return await this.handleMiniappLogin(data, config);
+            }
+        } catch (error) {
+            logger.error('统一登录错误:', error);
+            return {
+                code: -1,
+                msg: error.message || "登录验证失败",
+                data: null,
+            };
+        }
+    }
+
+    /**
+     * 小程序登录鉴权
+     * @param data 请求数据
+     * @param config 渠道配置
+     */
+    private async handleMiniappLogin(data: any, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const token = data.token;
+
+            if (!token) {
+                return {
+                    code: -1,
+                    msg: "缺少token参数",
+                    data: null
+                };
+            }
+
+            const loginUrl = `https://wxlogin.${config.paymentConfig.apiUrl}/wxlogin?cmd=checkUserToken&token=${token}`;
+            logger.info("小程序登录请求", {token, loginUrl});
+
+            const wxLogin = await axios.get(loginUrl, {
+                httpsAgent: this.getHttpsAgent(),
+                headers: this.getCommonHeaders()
+            });
+            logger.info("小程序登录响应", {data: wxLogin.data});
+            if (!wxLogin.data || Object.keys(wxLogin.data).length === 0) {
+                return {
+                    code: -1,
+                    msg: "登录验证失败",
+                    data: null,
+                };
+            }
+            return {
+                code: 0,
+                msg: "success",
+                data: wxLogin.data,
+            };
+        } catch (error) {
+            logger.error('小程序登录错误:', error);
+            return {
+                code: -1,
+                msg: error.message || "登录验证失败",
+                data: null,
+            };
+        }
+    }
+
+    /**
+     * iOS登录鉴权
+     * @param data 请求数据
+     * @param config 渠道配置
+     */
+    private async handleIOSLogin(data: any, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const { token } = data;
+            const gameid = '1550';
+            // 验证必要参数
+            if (!token) {
+                logger.error("iOS登录鉴权失败 - 缺少token参数");
+                return {
+                    code: -1,
+                    msg: "缺少必要参数: token",
+                    data: null
+                };
+            }
+
+            logger.info("iOS登录鉴权请求参数:", { token,gameid });
+
+            // 调用第三方鉴权API
+            const apiUrl = `https://api.11h5.com/login?cmd=checkUserToken&userToken=${encodeURIComponent(token)}&gameid=${gameid}`;
+            
+            logger.info("调用iOS鉴权API:", { url: apiUrl });
+
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: this.getCommonHeaders(),
+                httpsAgent: this.getHttpsAgent()
+            });
+
+            logger.info("iOS鉴权API响应:", response.data);
+
+            // 根据错误码判断成功与否
+            const responseData = response.data;
+            
+            if (responseData.error === 0) {
+                // 成功:error = 0
+                logger.info("iOS登录鉴权成功:", {
+                    uid: responseData.uid,
+                    nickname: responseData.nickname,
+                    usertype: responseData.usertype
+                });
+                
+                return {
+                    code: 0,
+                    msg: "登录成功",
+                    data: {
+                        uid: responseData.uid,
+                        nickname: responseData.nickname,
+                        headimgurl: responseData.headimgurl,
+                        sex: responseData.sex,
+                        focus: responseData.focus,
+                        usertype: responseData.usertype
+                    }
+                };
+            } else if (responseData.error === 401) {
+                // 参数有误
+                logger.error("iOS登录鉴权失败 - 参数有误:", responseData);
+                return {
+                    code: -1,
+                    msg: "参数有误,请检查接口所需参数是否都已经填写正确",
+                    data: null
+                };
+            } else if (responseData.error === 403) {
+                // token验证失败
+                logger.error("iOS登录鉴权失败 - token验证失败:", responseData);
+                return {
+                    code: -1,
+                    msg: "token验证失败,同一个userToken只能验证一次,可通过刷新游戏重新获取",
+                    data: null
+                };
+            } else {
+                // 其他错误
+                logger.error("iOS登录鉴权失败 - 未知错误:", responseData);
+                return {
+                    code: -1,
+                    msg: "鉴权失败,请稍后重试",
+                    data: null
+                };
+            }
+
+        } catch (error) {
+            logger.error("iOS登录鉴权出错:", error);
+            return {
+                code: -1,
+                msg: "登录鉴权失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * 统一支付回调处理
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
+        try {
+            // 获取请求参数 - 支持GET和POST请求
+            const params = ctx.request.query as any;
+
+            const platform = params.platform || 'miniapp'; // 平台参数:ios、Android、miniapp、h5,默认为miniapp
+            
+            logger.info("统一支付回调请求", { platform, url: ctx.href, params: params });
+
+            // 根据平台选择不同的支付处理方式和配置
+            if (platform === 'ios') {
+                // iOS使用渠道12的配置
+                const iosConfig = ChannelConfigManager.getConfig(12);
+                if (!iosConfig) {
+                    logger.error("未找到iOS渠道配置");
+                    return {
+                        code: -1,
+                        msg: "iOS渠道配置不存在",
+                        data: null
+                    };
+                }
+                return await this.handleIOSPayment(params, iosConfig);
+            } else {
+                // 默认使用小程序支付方式和渠道11的配置
+                const miniappConfig = ChannelConfigManager.getConfig(11);
+                if (!miniappConfig) {
+                    logger.error("未找到小程序渠道配置");
+                    return {
+                        code: -1,
+                        msg: "小程序渠道配置不存在",
+                        data: null
+                    };
+                }
+                return await this.handleMiniappPayment(params, miniappConfig);
+            }
+        } catch (error) {
+            logger.error('统一支付处理错误:', error);
+            return {
+                code: -1,
+                msg: error.message || "支付处理失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * iOS支付回调处理
+     * @param params 请求参数
+     * @param config 渠道配置
+     */
+    private async handleIOSPayment(params: any, config: ChannelConfig): Promise<PaymentResult> {
+        try {
+            // 验证必要参数
+            const requiredParams = ['openid', 'rmb', 'reqid', 'trans_id', 'product_id', 'notify_id', 'sign','txid'];
+            for (const param of requiredParams) {
+                if (!params[param]) {
+                    logger.error(`缺少必要参数: ${param}`);
+                    return {
+                        code: -1,
+                        msg: `缺少必要参数: ${param}`,
+                        data: null
+                    };
+                }
+            }
+
+            // 验证签名(使用iOS的签名算法)
+            const isValidSignature = this.verifyPaymentSignature(params, config);
+            if (!isValidSignature) {
+                logger.error("iOS支付签名验证失败", {
+                    received: params.sign,
+                    params: params
+                });
+                return {
+                    code: -1,
+                    msg: "签名验证失败",
+                    data: null
+                };
+            }
+
+            // 订单校验
+            const orderCheckResult = await this.verifyOrderInternal(params.notify_id, config.paymentConfig.gameId, config);
+            if (!orderCheckResult.success) {
+                logger.error(`订单${params.reqid}校验失败: ${orderCheckResult.message}`);
+                return {
+                    code: -1,
+                    msg: `订单校验失败: ${orderCheckResult.message}`,
+                    data: null
+                };
+            }
+            const orderId = params.txid;//订单号
+            const out_trade_no = params.trans_id;//平台订单号
+            const validation = await PaymentHelper.validateOrder(orderId);
+            if (!validation.valid) {
+                return {
+                    code: validation.message?.includes("重复发货") ? 1 : 0,
+                    msg: validation.message || "订单验证失败"
+                };
+            }
+            const orderInfo = validation.orderInfo;
+    
+            logger.info("IOS订单校验成功,开始处理支付发货逻辑");
+            const result = await PaymentHelper.deliverOrder(
+                orderInfo,
+                "127.0.0.1", // 使用默认IP地址,因为iOS支付没有客户端IP
+                validation.url,
+                out_trade_no
+            );
+            // 处理支付成功逻辑
+            logger.info(`iOS支付成功 - 用户: ${params.openid}, 金额: ${params.rmb}, 订单: ${out_trade_no}, 发货结果:`, result);
+            return result;
+
+        } catch (error) {
+            logger.error("iOS支付处理出错:", error);
+            return {
+                code: -1,
+                msg: "iOS支付处理失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * 小程序支付回调处理
+     * @param params 请求参数
+     * @param config 渠道配置
+     */
+    private async handleMiniappPayment(params: any, config: ChannelConfig): Promise<PaymentResult> {
+        try {
+
+            // 验证必要参数
+            const requiredParams = ['uid', 'rmb', 'reqid', 'trans_id', 'product_id', 'notify_id', 'sign'];
+            for (const param of requiredParams) {
+                if (!params[param]) {
+                    logger.error(`缺少必要参数: ${param}`);
+                    return {
+                        code: -1,
+                        msg: `缺少必要参数: ${param}`,
+                        data: null
+                    };
+                }
+            }
+
+            // 验证签名 - 排除platform和channel_id参数
+            const parameters = Object.keys(params)
+                .filter(key => key !== 'sign')
+                .map(key => `${key}=${params[key]}`);
+
+            const expectedSignature = this.generateSignature(parameters, config.paymentConfig.signKey!);
+            if (params.sign !== expectedSignature) {
+                logger.error("小程序支付签名验证失败", {
+                    received: params.sign,
+                    expected: expectedSignature
+                });
+                return {
+                    code: -1,
+                    msg: "签名验证失败",
+                    data: null
+                };
+            }
+            const orderId = params.txid;//订单号
+            const out_trade_no = params.trans_id;//平台订单号
+            // 订单校验 - 验证支付是否成功
+            const orderCheckResult = await this.wxOrderCheck(params.notify_id, config);
+            if (!orderCheckResult.success) {
+                logger.error(`订单${orderId}校验失败: ${orderCheckResult.message}`);
+                return {
+                    code: -1,
+                    msg: `订单校验失败: ${orderCheckResult.message}`,
+                    data: null
+                };
+            }
+
+            const validation = await PaymentHelper.validateOrder(orderId);
+            if (!validation.valid) {
+                return {
+                    code: validation.message?.includes("重复发货") ? 1 : 0,
+                    msg: validation.message || "订单验证失败"
+                };
+            }
+            const orderInfo = validation.orderInfo;
+            // 发货处理
+            logger.info(`小程序支付订单${orderId}通知游戏发货开始`);
+            const result = await PaymentHelper.deliverOrder(
+                orderInfo,
+                "127.0.0.1", // 使用默认IP地址,因为小程序支付没有客户端IP
+                validation.url,
+                out_trade_no
+            );
+            // 处理支付成功逻辑
+            logger.info(`小程序支付成功 - 用户: ${params.uid}, 金额: ${params.rmb}, 订单: ${out_trade_no}, 发货结果:`, result);
+            return result;
+        } catch (error) {
+            logger.error("小程序支付处理出错:", error);
+            return {
+                code: -1,
+                msg: "支付处理失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * 订单校验 - 验证支付是否成功
+     * @param notifyId 平台通知ID
+     * @param config 渠道配置
+     * @returns 校验结果
+     */
+    async wxOrderCheck(notifyId: string, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
+        try {
+            // 构建验证参数
+            const parameters = [
+                `gameid=${config.paymentConfig.gameId}`,
+                `notify_id=${notifyId}`
+            ];
+
+            // 生成签名
+            const signature = this.generateSignature(parameters, config.paymentConfig.signKey!);
+
+            // 构建验证URL
+            const verifyUrl = `https://login.${config.paymentConfig.apiUrl}/pay/paygate/verify.php?gameid=${config.paymentConfig.gameId}&notify_id=${notifyId}&sign=${signature}`;
+
+            logger.info("订单校验请求", {notifyId, verifyUrl});
+
+            // 调用平台验证接口
+            const response = await axios.get(verifyUrl, {
+                httpsAgent: this.getHttpsAgent(),
+                headers: {
+                    ...this.getCommonHeaders(),
+                    'Accept': 'text/plain'
+                }
+            });
+
+            logger.info("订单校验响应", {notifyId, response: response.data});
+
+            // 检查返回结果
+            if (response.data === "SUCCESS") {
+                return {
+                    success: true,
+                    message: "订单支付成功"
+                };
+            } else {
+                return {
+                    success: false,
+                    message: "订单支付失败或无效"
+                };
+            }
+
+        } catch (error) {
+            logger.error("订单校验出错:", {notifyId, error: error.message});
+            return {
+                success: false,
+                message: "订单校验失败"
+            };
+        }
+    }
+
+    /**
+     * 内容安全审核接口
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async contentSecurityCheck(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const data = ctx.request.body as any;
+            logger.info("内容安全审核请求参数:", data);
+
+            // 验证必要参数
+            const requiredParams = ['uid', 'scene', 'content'];
+            for (const param of requiredParams) {
+                if (!data[param]) {
+                    logger.error(`缺少必要参数: ${param}`);
+                    return {
+                        code: -1,
+                        msg: `缺少必要参数: ${param}`,
+                        data: null
+                    };
+                }
+            }
+            data['timestamp'] = Math.floor(Date.now() / 1000); // 添加时间戳参数
+            data['gameid'] = config.paymentConfig.gameId; // 添加游戏ID参数
+            data['nonce'] = Math.floor(Math.random() * 1000000); // 添加随机数参数
+            //生成签名
+            data['signature'] = this.generateContentSecuritySignature(data, config);
+            if (!data['signature']) {
+                return {
+                    code: -1,
+                    msg: "签名生成失败",
+                    data: null
+                };
+            }
+            // 构建请求参数
+            const requestData = {
+                uid: data.uid,
+                gameid: data.gameid,
+                signature: data.signature,
+                timestamp: data.timestamp,
+                nonce: data.nonce,
+                scene: data.scene,
+                content: data.content,
+                nickname: data.nickname || '',
+                title: data.title || '',
+                usersign: data.usersign || ''
+            };
+
+            // 调用内容安全API
+            const apiUrl = `https://api.${config.paymentConfig.apiUrl}/mpcommon/?cmd=wxaMsgSecCheck`;
+            logger.info("调用内容安全API:", {url: apiUrl, data: requestData});
+
+            const response = await axios.post(apiUrl, requestData, {
+                httpsAgent: this.getHttpsAgent(),
+                headers: this.getCommonHeaders()
+            });
+
+            logger.info("内容安全API响应:", response.data);
+
+            // 处理响应结果
+            if (response.data && response.data.error === 0) {
+                const result = response.data.result;
+                return {
+                    code: 0,
+                    msg: "success",
+                    data: {
+                        suggest: result.suggest, // pass/review/reject
+                        label: result.label,
+                        trace_id: response.data.trace_id,
+                        detail: response.data.detail
+                    }
+                };
+            } else {
+                return {
+                    code: -1,
+                    msg: response.data?.errmsg || "内容安全检测失败",
+                    data: null
+                };
+            }
+
+        } catch (error) {
+            logger.error("内容安全审核出错:", error);
+            return {
+                code: -1,
+                msg: "内容安全审核失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * 角色名称修改上报
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async editUserRoleInfo(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const data = ctx.request.body as any;
+            logger.info("角色名称修改上报请求参数:", data);
+            // 验证必要参数
+            const requiredParams = ['openId', 'serverid', 'playerName'];
+            for (const param of requiredParams) {
+                if (!data[param]) {
+                    logger.error(`缺少必要参数: ${param}`);
+                    return {
+                        code: -1,
+                        msg: `缺少必要参数: ${param}`,
+                        data: null
+                    };
+                }
+            }
+            data['time'] = Math.floor(Date.now() / 1000); // 添加时间戳参数
+            data['gameid'] = config.paymentConfig.gameId; // 添加游戏ID参数
+            
+            // 处理playerName的各种编码格式
+            let decodedPlayerName = data.playerName;
+            try {
+                // 检查是否是URL编码格式
+                if (data.playerName.includes('%')) {
+                    decodedPlayerName = decodeURIComponent(data.playerName);
+                    console.log("playerName URL decoded from:", data.playerName);
+                    console.log("playerName URL decoded to:", decodedPlayerName);
+                }
+                // 检查是否是Unicode转义序列格式
+                else if (data.playerName.includes('\\u')) {
+                    decodedPlayerName = JSON.parse('"' + data.playerName + '"');
+                    console.log("playerName Unicode decoded from:", data.playerName);
+                    console.log("playerName Unicode decoded to:", decodedPlayerName);
+                } else {
+                    console.log("playerName is not encoded:", data.playerName);
+                }
+            } catch (error) {
+                console.log("playerName decode error, using original:", error.message);
+                decodedPlayerName = data.playerName;
+            }
+            
+            // 更新data中的playerName为解码后的值
+            data.playerName = decodedPlayerName;
+            console.log("playerName for signature:", data.playerName);
+            
+            //生成签名
+            data['sign'] = this.generateRoleInfoSignature(data, config);
+            
+            // 构建请求参数 - 对playerName进行URL编码
+            const encodedPlayerName = encodeURIComponent(data.playerName);
+            console.log("playerName for request:", encodedPlayerName);
+            
+            // 手动构建URL查询字符串,避免对已编码参数进行二次编码
+            const queryString = [
+                `openId=${encodeURIComponent(data.openId)}`,
+                `time=${encodeURIComponent(data.time)}`,
+                `gameid=${encodeURIComponent(data.gameid)}`,
+                `serverid=${encodeURIComponent(data.serverid)}`,
+                `playerName=${encodedPlayerName}`, // 已经编码过的playerName,不再编码
+                `sign=${encodeURIComponent(data.sign)}`
+            ].join('&');
+            
+            // 调用角色信息修改API
+            const apiUrl = `https://platform.${config.paymentConfig.apiUrl}/stat/api/?cmd=editUserRoleInfo&${queryString}`;
+            logger.info("调用角色信息修改API:", {url: apiUrl});
+
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: {
+                    'User-Agent': 'Mozilla/5.0 (compatible; WebServer/1.0)',
+                    'Accept': 'application/json'
+                },
+                httpsAgent: this.getHttpsAgent()
+            });
+            logger.info("角色信息修改API响应:", response.data);
+
+            // 处理响应结果
+            if (response.data && response.data.error === 0) {
+                return {
+                    code: 0,
+                    msg: "success",
+                    data: null
+                };
+            } else {
+                return {
+                    code: -1,
+                    msg: response.data?.errmsg || "角色信息修改失败",
+                    data: null
+                };
+            }
+
+        } catch (error) {
+            logger.error("角色名称修改上报出错:", error);
+            return {
+                code: -1,
+                msg: "角色信息修改失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * 签名算法2验证
+     * @param data 请求数据
+     * @param config 渠道配置
+     * @returns 验证结果
+     */
+    private verifySignatureAlgorithm2(data: any, config: ChannelConfig): boolean {
+        try {
+            // 固定密钥
+            const secret = 'qka8qKcvRcGN1u0bLA8O';
+            
+            // 准备签名参数
+            const signParams: any = {
+                gameId: data.gameid || config.paymentConfig.gameId,
+                openId: data.openId,
+                playerName: encodeURIComponent(data.playerName), // 中文URL编码
+                secret: secret,
+                serverId: data.serverid,
+                time: data.time
+            };
+            
+            // 按字典排序参数名
+            const sortedKeys = Object.keys(signParams).sort();
+            
+            // 构建签名字符串(去掉[])
+            const signString = sortedKeys.map(key => {
+                return `${key}=${signParams[key]}`;
+            }).join('');
+            
+            console.log("验证签名参数:", signParams);
+            console.log("验证签名字符串:", signString);
+            
+            // 计算MD5签名
+            const expectedSignature = CryptoJS.MD5(signString).toString();
+            const actualSignature = data.sign;
+            
+            console.log("期望签名:", expectedSignature);
+            console.log("实际签名:", actualSignature);
+            
+            return expectedSignature === actualSignature;
+        } catch (error) {
+            logger.error("签名算法2验证出错:", error);
+            return false;
+        }
+    }
+
+    /**
+     * 生成角色信息修改签名(签名算法2)
+     * @param params 签名参数
+     * @param config 渠道配置
+     * @returns 签名结果
+     */
+    generateRoleInfoSignature(params: any, config: ChannelConfig): string | null {
+        try {
+            // 固定密钥
+            const secret = 'qka8qKcvRcGN1u0bLA8O';
+            
+            // 准备签名参数
+            const signParams: any = {
+                gameid: params.gameid || config.paymentConfig.gameId,
+                openId: params.openId,
+                playerName: encodeURIComponent(params.playerName), // 中文URL编码
+                secret: secret,
+                serverid: params.serverid,
+                time: params.time
+            };
+            
+            // 按字典排序参数名
+            const sortedKeys = Object.keys(signParams).sort();
+            
+            // 构建签名字符串(去掉[])
+            const signString = sortedKeys.map(key => {
+                return `${key}=${signParams[key]}`;
+            }).join('');
+            
+            console.log("角色信息签名参数:", signParams);
+            console.log("角色信息签名字符串:", signString);
+            
+            // 计算MD5签名
+            const signature = CryptoJS.MD5(signString).toString();
+            
+            console.log("角色信息签名结果:", signature);
+            
+            return signature;
+        } catch (error) {
+            logger.error("生成角色信息修改签名出错:", error);
+            return null;
+        }
+    }
+
+    /**
+     * 签名算法1验证
+     * @param data 请求数据
+     * @param config 渠道配置
+     * @returns 验证结果
+     */
+    private verifySignatureAlgorithm1(data: any, config: ChannelConfig): boolean {
+        return this.verifyCommonSignature(
+            data,
+            config.loginConfig?.apiKey || '',
+            'signature',
+            ['signature'],
+            false // 内容安全签名不需要URL编码
+        );
+    }
+
+    /**
+     * 生成内容安全签名(供客户端使用)
+     * @param params 签名参数
+     * @param config 渠道配置
+     * @returns 签名结果
+     */
+    generateContentSecuritySignature(params: any, config: ChannelConfig): string | null {
+        try {
+            let arr = [config.loginConfig.apiKey, params.timestamp, params.nonce];
+            arr.sort();
+            let str = arr.join('');
+            return crypto.createHash('sha1').update(str).digest('hex');
+        } catch (error) {
+            logger.error("生成内容安全签名出错:", error);
+            return null;
+        }
+    }
+
+    /**
+     * 发货处理方法
+     * @param orderInfo 订单信息
+     * @param ip 客户端IP
+     * @param url 游戏服务器URL
+     * @param out_trade_no 外部交易号
+     * @returns 发货结果
+     */
+    private async deliverOrder(orderInfo: any, ip: string, url: string, out_trade_no: string): Promise<{
+        code: number;
+        msg: string
+    }> {
+        return new Promise((resolve) => {
+            const sendMsg = new Msg();
+            logger.info("通知游戏服务器url", {url: url});
+
+            sendMsg.connect(url, Account);
+            setTimeout(async () => {
+                try {
+                    // 构建消息参数
+                    const params = JSON.stringify({
+                        account: orderInfo.uid,
+                        channel_id: orderInfo.channel_id,
+                        order: orderInfo.order_id,
+                        id: orderInfo.product_id,
+                        cnt: 100,
+                        money: orderInfo.amount,
+                    });
+
+                    logger.info("通知游戏服务器参数", {data: params});
+                    logger.info("通知游戏服务器orderInfo", {orderInfo: orderInfo});
+                    let send_res = sendMsg.CG_ASK_LOGIN(
+                        Account,
+                        0,
+                        "",
+                        "cn",
+                        "CN",
+                        ip,
+                        params,
+                        orderInfo.server_id
+                    );
+
+                    if (!send_res) {
+                        resolve({code: 0, msg: "通知服务器失败"});
+                        return;
+                    }
+
+                    // 更新订单状态
+                    const update_time = formatDate(new Date());
+                    const res = await Order.updateOrderStats(
+                        orderInfo.order_id,
+                        2,
+                        out_trade_no,
+                        update_time,
+                        orderInfo.uid
+                    );
+
+                    if (res.affectedRows <= 0) {
+                        logger.info(`订单${orderInfo.order_id} 发货失败`);
+                        resolve({code: 0, msg: "发货失败"});
+                        return;
+                    }
+
+                    resolve({code: 1, msg: "发货成功"});
+                } catch (error) {
+                    logger.error("发货过程出错:", error);
+                    resolve({code: 0, msg: "发货失败"});
+                }
+            }, 1500);
+        });
+    }
+
+    /**
+     * 通用签名生成函数
+     * @param params 参数对象
+     * @param privateKey 私钥
+     * @param excludeKeys 需要排除的键(如sign)
+     * @param needUrlEncode 是否需要URL编码
+     * @returns 签名结果
+     */
+    public generateCommonSignature(
+        params: any,
+        privateKey: string,
+        excludeKeys: string[] = ['sign'],
+        needUrlEncode: boolean = true
+    ): string {
+        try {
+            // 1. 过滤掉空值和排除的键
+            const filteredParams: any = {};
+            Object.keys(params).forEach(key => {
+                if (!excludeKeys.includes(key) && params[key] !== null && params[key] !== undefined && params[key] !== '') {
+                    filteredParams[key] = params[key].toString();
+                }
+            });
+
+            // 2. 按字母顺序排序并构建查询字符串
+            const sortedKeys = Object.keys(filteredParams).sort();
+            const queryString = sortedKeys.map(key => {
+                const value = filteredParams[key];
+                const encodedValue = needUrlEncode ? encodeURIComponent(value) : value;
+                return `${key}=${encodedValue}`;
+            }).join('&');
+
+            // 3. 拼接私钥
+            const stringToSign = `${queryString}&key=${privateKey}`;
+            console.log("String to Sign:", stringToSign);
+            // 4. 计算MD5并转大写
+            const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
+
+            logger.info("通用签名生成详情:", {
+                filteredParams,
+                queryString,
+                stringToSign,
+                signature
+            });
+
+            return signature;
+        } catch (error) {
+            logger.error("通用签名生成出错:", error);
+            return '';
+        }
+    }
+
+    /**
+     * 小程序签名函数(签名算法3)- 兼容旧接口
+     * @param parameters 参数数组
+     * @param privateKey 私钥
+     * @returns 签名结果
+     */
+    private generateSignature(parameters: string[], privateKey: string): string {
+        // 按照签名算法3处理
+        // 1. 过滤掉空值参数
+        const filteredParams = parameters.filter(param => {
+            const [key, value] = param.split('=');
+            return key && value && value.trim() !== '';
+        });
+
+        // 2. 按字母顺序排序
+        filteredParams.sort();
+
+        // 3. 对参数值进行URL编码,然后用&连接
+        const encodedParams = filteredParams.map(param => {
+            const [key, value] = param.split('=');
+            return `${key}=${encodeURIComponent(value)}`;
+        });
+        const queryString = encodedParams.join('&');
+
+        // 4. 添加私钥
+        const stringToSign = `${queryString}&key=${privateKey}`;
+
+        // 5. MD5哈希并转大写
+        const signature = CryptoJS.MD5(stringToSign).toString().toUpperCase();
+
+        logger.info("签名算法3生成详情:", {
+            filteredParams,
+            encodedParams,
+            queryString,
+            stringToSign,
+            signature
+        });
+
+        return signature;
+    }
+
+    /**
+     * 通用签名验证函数
+     * @param data 请求数据
+     * @param privateKey 私钥
+     * @param signKey 签名字段名
+     * @param excludeKeys 需要排除的键
+     * @param needUrlEncode 是否需要URL编码
+     * @returns 验证结果
+     */
+    private verifyCommonSignature(
+        data: any,
+        privateKey: string,
+        signKey: string = 'sign',
+        excludeKeys: string[] = ['sign'],
+        needUrlEncode: boolean = true
+    ): boolean {
+        try {
+            const receivedSignature = data[signKey];
+            if (!receivedSignature) {
+                return false;
+            }
+
+            const expectedSignature = this.generateCommonSignature(data, privateKey, excludeKeys, needUrlEncode);
+
+            logger.info("通用签名验证详情:", {
+                receivedSignature,
+                expectedSignature,
+                isValid: receivedSignature === expectedSignature
+            });
+
+            return receivedSignature === expectedSignature;
+        } catch (error) {
+            logger.error("通用签名验证出错:", error);
+            return false;
+        }
+    }
+
+    /**
+     * 验证iOS支付签名(签名算法3)
+     * @param params 请求参数
+     * @param config 渠道配置
+     * @returns 验证结果
+     */
+    private verifyPaymentSignature(params: any, config: ChannelConfig): boolean {
+        try {
+            // 获取签名密钥
+            const signKey = config.paymentConfig.signKey;
+            if (!signKey) {
+                logger.error("iOS支付签名密钥未配置");
+                return false;
+            }
+
+            // 过滤掉sign参数,按参数名排序
+            const sortedParams = Object.keys(params)
+                .filter(key => key !== 'sign')
+                .sort()
+                .map(key => `${key}=${params[key]}`);
+
+            // 构建签名字符串
+            const signString = sortedParams.join('&') + `&key=${signKey}`;
+
+            // 计算MD5签名
+            const expectedSignature = CryptoJS.MD5(signString).toString().toUpperCase();
+
+            logger.info("iOS支付签名验证", {
+                signString,
+                receivedSignature: params.sign,
+                expectedSignature,
+                isValid: params.sign === expectedSignature
+            });
+
+            return params.sign === expectedSignature;
+        } catch (error) {
+            logger.error("iOS支付签名验证出错:", error);
+            return false;
+        }
+    }
+
+    /**
+     * 内部订单校验方法
+     * @param notifyId 平台通知ID
+     * @param gameId 游戏ID
+     * @param config 渠道配置
+     * @returns 校验结果
+     */
+    private async verifyOrderInternal(notifyId: string, gameId: string, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
+        try {
+            // 构建验证参数
+            const parameters = [
+                `gameid=${gameId}`,
+                `notify_id=${notifyId}`
+            ];
+
+            // 生成签名
+            const signature = this.generatePaymentSignature(parameters, config.paymentConfig.signKey!);
+            const apiUrl = `https://login.11h5.com/pay/paygate/verify.php?${parameters.join('&')}&sign=${signature}`;
+
+            logger.info("iOS订单校验请求", { apiUrl });
+
+            // 调用第三方API验证订单
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: {
+                    'User-Agent': 'Mozilla/5.0 (compatible; GameServer/1.0)'
+                }
+            });
+
+            logger.info("iOS订单校验响应", { 
+                status: response.status, 
+                data: response.data 
+            });
+
+            if (response.status === 200) {
+                const result = response.data;
+                // 处理纯文本"SUCCESS"响应
+                if (result === "SUCCESS") {
+                    return { success: true, message: "订单校验成功" };
+                } 
+                // 处理JSON格式响应
+                else if (result && typeof result === 'object' && result.code === 0) {
+                    return { success: true, message: "订单校验成功" };
+                } else {
+                    return { 
+                        success: false, 
+                        message: result?.msg || "订单校验失败" 
+                    };
+                }
+            } else {
+                return { 
+                    success: false, 
+                    message: `HTTP错误: ${response.status}` 
+                };
+            }
+        } catch (error) {
+            logger.error("iOS订单校验出错:", error);
+            return { 
+                success: false, 
+                message: error.message || "订单校验异常" 
+            };
+        }
+    }
+
+    /**
+     * 生成iOS支付签名(签名算法3)
+     * @param parameters 参数数组
+     * @param signKey 签名密钥
+     * @returns 签名字符串
+     */
+    private generatePaymentSignature(parameters: string[], signKey: string): string {
+        try {
+            // 构建签名字符串
+            const signString = parameters.join('&') + `&key=${signKey}`;
+            
+            // 计算MD5签名并转为大写
+            const signature = CryptoJS.MD5(signString).toString().toUpperCase();
+            
+            logger.info("生成iOS支付签名", {
+                signString,
+                signature
+            });
+            
+            return signature;
+        } catch (error) {
+            logger.error("生成iOS支付签名出错:", error);
+            return "";
+        }
+    }
+}

+ 2 - 2
webServer/src/channels/handlers/MuZiChannelHandler.ts

@@ -11,7 +11,7 @@ const logger = require("../../utils/log");
 
 export class MuZiChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360登录请求参数:", { data });
 
     // 验证签名
@@ -38,7 +38,7 @@ export class MuZiChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360支付回调参数:", { url: ctx.href, params: data });
 
     // 验证签名

+ 2 - 2
webServer/src/channels/handlers/MuZiIosChannelHandler.ts

@@ -11,7 +11,7 @@ const logger = require("../../utils/log");
 
 export class MuZiIosChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360登录请求参数:", { data });
 
     // 验证签名
@@ -38,7 +38,7 @@ export class MuZiIosChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360ios支付回调参数:", { url: ctx.href, params: data,config:config });
 
     // 验证签名

+ 3 - 3
webServer/src/channels/handlers/QQChannelHandler.ts

@@ -6,8 +6,8 @@ import CryptoJS from 'crypto-js';
 const logger = require('../../utils/log');
 
 export class QQChannelHandler implements ChannelHandler {
-    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-        const data = ctx.request.body;
+  async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+    const data = ctx.request.body as any;
         logger.info("QQ登录请求参数:", { data });
         
         // 验证签名
@@ -29,7 +29,7 @@ export class QQChannelHandler implements ChannelHandler {
     }
 
     async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
-        const data = ctx.request.body;
+        const data = ctx.request.body as any;
         logger.info("QQ支付回调参数:", { url: ctx.href, params: data });
         
         // 验证签名

+ 2 - 2
webServer/src/channels/handlers/QiAiH5ChannelHandler.ts

@@ -15,7 +15,7 @@ const logger = require("../../utils/log");
 
 export class QiAiH5ChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     // 构建七艾登录验证请求URL
     const reqUrl = `http://checkuser.quickapi.net/v2/checkUserInfo?token=${data.token}&uid=${data.uid}&product_code=${config.loginConfig?.productCode}`;
@@ -50,7 +50,7 @@ export class QiAiH5ChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     logger.info("七艾支付回调参数:", { url: ctx.href, params: data });
     let ntData = data.nt_data;

+ 505 - 0
webServer/src/channels/handlers/SYIOSChannelHandler.ts

@@ -0,0 +1,505 @@
+import { Context } from "koa";
+import { ChannelHandler, LoginResult, PaymentResult } from "../interfaces/ChannelHandler";
+import { ChannelConfig } from "../../config/channelConfig";
+import axios from "axios";
+import {PaymentHelper} from "../../utils/PaymentHelper";
+
+const logger = require("../../utils/log");
+
+/**
+ * 三一iOS渠道处理器
+ * 渠道ID: 12
+ * 处理iOS平台的登录鉴权和支付回调
+ */
+export class SYIOSChannelHandler implements ChannelHandler {
+    /**
+     * 获取HTTPS代理配置
+     * @returns HTTPS代理配置
+     */
+    private getHttpsAgent() {
+        const https = require('https');
+        return new https.Agent({
+            rejectUnauthorized: false,
+            secureProtocol: 'TLSv1_2_method',
+            timeout: 10000
+        });
+    }
+
+    /**
+     * 获取通用请求头
+     * @returns 请求头配置
+     */
+    private getCommonHeaders() {
+        return {
+            'User-Agent': 'Mozilla/5.0 (compatible; WebServer/1.0)',
+            'Accept': 'application/json',
+            'Content-Type': 'application/json'
+        };
+    }
+
+    /**
+     * iOS登录鉴权
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
+        try {
+            const { userToken } = ctx.request.body || ctx.request.query;
+            
+            // 验证必要参数
+            if (!userToken) {
+                logger.error("iOS登录鉴权失败 - 缺少userToken参数");
+                return {
+                    code: -1,
+                    msg: "缺少必要参数: userToken",
+                    data: null
+                };
+            }
+            const gameid = config.paymentConfig?.gameId || '1550';
+            logger.info("iOS登录鉴权请求参数:", { userToken, gameid });
+
+            // 调用第三方鉴权API
+            const apiUrl = `https://api.11h5.com/login?cmd=checkUserToken&userToken=${encodeURIComponent(userToken)}&gameid=${gameid}`;
+            
+            logger.info("调用iOS鉴权API:", { url: apiUrl });
+
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: this.getCommonHeaders(),
+                httpsAgent: this.getHttpsAgent()
+            });
+
+            logger.info("iOS鉴权API响应:", response.data);
+
+            // 根据错误码判断成功与否
+            const responseData = response.data;
+            
+            if (responseData.error === 0) {
+                // 成功:error = 0
+                logger.info("iOS登录鉴权成功:", {
+                    uid: responseData.uid,
+                    nickname: responseData.nickname,
+                    usertype: responseData.usertype
+                });
+                
+                return {
+                    code: 1,
+                    msg: "登录成功",
+                    data: {
+                        uid: responseData.uid,
+                        nickname: responseData.nickname,
+                        headimgurl: responseData.headimgurl,
+                        sex: responseData.sex,
+                        focus: responseData.focus,
+                        usertype: responseData.usertype
+                    }
+                };
+            } else if (responseData.error === 401) {
+                // 参数有误
+                logger.error("iOS登录鉴权失败 - 参数有误:", responseData);
+                return {
+                    code: -1,
+                    msg: "参数有误,请检查接口所需参数是否都已经填写正确",
+                    data: null
+                };
+            } else if (responseData.error === 403) {
+                // token验证失败
+                logger.error("iOS登录鉴权失败 - token验证失败:", responseData);
+                return {
+                    code: -1,
+                    msg: "token验证失败,同一个userToken只能验证一次,可通过刷新游戏重新获取",
+                    data: null
+                };
+            } else {
+                // 其他错误
+                logger.error("iOS登录鉴权失败 - 未知错误:", responseData);
+                return {
+                    code: -1,
+                    msg: "鉴权失败,请稍后重试",
+                    data: null
+                };
+            }
+
+        } catch (error) {
+            logger.error("iOS登录鉴权出错:", error);
+            return {
+                code: -1,
+                msg: "登录鉴权失败",
+                data: null
+            };
+        }
+    }
+
+    /**
+     * iOS支付回调处理
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async handlePayment(ctx: Context, config: ChannelConfig): Promise<PaymentResult> {
+        try {
+            const data = ctx.request.query || ctx.request.body;
+            logger.info("iOS支付回调参数:", data);
+
+            // 验证必要参数(根据API文档)
+            const requiredParams = ['openid', 'rmb', 'reqid', 'trans_id', 'product_id', 'notify_id', 'sign','txid'];
+            for (const param of requiredParams) {
+                if (!data[param]) {
+                    logger.error(`iOS支付回调缺少必要参数: ${param}`);
+                    return {
+                        code: 0,
+                        msg: `缺少必要参数: ${param}`
+                    };
+                }
+            }
+
+            // 验证签名(使用签名算法3)
+            if (!this.verifyPaymentSignature(data, config)) {
+                logger.error("iOS支付回调签名验证失败");
+                return {
+                    code: 0,
+                    msg: "签名验证失败"
+                };
+            }
+
+            // 提取notify_id进行订单校验
+            const notify_id = data.notify_id;
+            const gameid =  config.paymentConfig?.gameId || '1550';
+            
+            logger.info(`开始订单校验 - notify_id: ${notify_id}, gameid: ${gameid}`);
+
+            // 调用订单校验
+            const verifyResult = await this.verifyOrderInternal(gameid, notify_id, config);
+            
+            if (!verifyResult.success) {
+                logger.error("订单校验失败:", verifyResult.message);
+                return {
+                    code: 0,
+                    msg: `订单校验失败: ${verifyResult.message}`
+                };
+            }
+            const orderId = data.txid;//订单号
+            const out_trade_no = data.trans_id;//平台订单号
+            const validation = await PaymentHelper.validateOrder(orderId);
+            if (!validation.valid) {
+                return {
+                    code: validation.message?.includes("重复发货") ? 1 : 0,
+                    msg: validation.message || "订单验证失败"
+                };
+            }
+            const orderInfo = validation.orderInfo;
+
+            logger.info("订单校验成功,开始处理支付发货逻辑");
+            const result = await PaymentHelper.deliverOrder(
+                orderInfo,
+                ctx.request.ip,
+                validation.url,
+                out_trade_no
+            );
+            // 处理支付成功逻辑
+            logger.info(`iOS支付成功 - 用户: ${data.openid}, 金额: ${data.rmb}, 订单: ${out_trade_no}, 发货结果:`, result);
+            
+            // 返回SUCCESS表示处理成功(根据API文档要求)
+            ctx.body = "SUCCESS";
+            
+            return {
+                code: 1,
+                msg: "支付处理成功",
+                data: {
+                    openid: data.openid,
+                    rmb: data.rmb,
+                    reqid: data.reqid,
+                    trans_id: data.trans_id,
+                    product_id: data.product_id,
+                    notify_id: data.notify_id,
+                    userdata: data.userdata,
+                    txid: data.txid,
+                    product_count: data.product_count
+                }
+            };
+
+        } catch (error) {
+            logger.error("iOS支付回调处理出错:", error);
+            return {
+                code: 0,
+                msg: "支付处理失败"
+            };
+        }
+    }
+
+    /**
+     * 验证支付签名(签名算法3)
+     * @param data 支付数据
+     * @param config 渠道配置
+     * @returns 验证结果
+     */
+    private verifyPaymentSignature(data: any, config: ChannelConfig): boolean {
+        try {
+            const privateKey = config.paymentConfig?.signKey || '';
+            if (!privateKey) {
+                logger.error("iOS支付签名验证失败 - 缺少私钥");
+                return false;
+            }
+
+            // 1. 除去为空的参数
+            const filteredParams: any = {};
+            Object.keys(data).forEach(key => {
+                if (key !== 'sign' && data[key] !== null && data[key] !== undefined && data[key] !== '') {
+                    filteredParams[key] = data[key].toString();
+                }
+            });
+
+            // 2. 对参数名按字母顺序排序
+            const sortedKeys = Object.keys(filteredParams).sort();
+
+            // 3. 构建待签名字符串
+            const queryString = sortedKeys.map(key => {
+                return `${key}=${filteredParams[key]}`;
+            }).join('&');
+
+            // 4. 拼接私钥
+            const stringToSign = `${queryString}&key=${privateKey}`;
+
+            // 5. 计算MD5签名并转大写
+            const crypto = require('crypto');
+            const expectedSignature = crypto.createHash('md5').update(stringToSign).digest('hex').toUpperCase();
+            const actualSignature = data.sign;
+
+            logger.info("iOS支付签名验证详情:", {
+                filteredParams,
+                queryString,
+                stringToSign,
+                expectedSignature,
+                actualSignature,
+                isValid: expectedSignature === actualSignature
+            });
+
+            return expectedSignature === actualSignature;
+        } catch (error) {
+            logger.error("iOS支付签名验证出错:", error);
+            return false;
+        }
+    }
+
+    /**
+     * 生成支付签名(签名算法3)
+     * @param params 签名参数
+     * @param config 渠道配置
+     * @returns 签名字符串
+     */
+    private generatePaymentSignature(params: any, config: ChannelConfig): string {
+        try {
+            const privateKey = config.paymentConfig?.signKey || '';
+            if (!privateKey) {
+                logger.error("iOS支付签名生成失败 - 缺少私钥");
+                return "";
+            }
+
+            // 1. 除去为空的参数
+            const filteredParams: any = {};
+            Object.keys(params).forEach(key => {
+                if (key !== 'sign' && params[key] !== null && params[key] !== undefined && params[key] !== '') {
+                    filteredParams[key] = params[key].toString();
+                }
+            });
+
+            // 2. 对参数名按字母顺序排序
+            const sortedKeys = Object.keys(filteredParams).sort();
+
+            // 3. 构建待签名字符串
+            const queryString = sortedKeys.map(key => {
+                return `${key}=${filteredParams[key]}`;
+            }).join('&');
+
+            // 4. 拼接私钥
+            const stringToSign = `${queryString}&key=${privateKey}`;
+
+            // 5. 计算MD5签名并转大写
+            const crypto = require('crypto');
+            const signature = crypto.createHash('md5').update(stringToSign).digest('hex').toUpperCase();
+
+            logger.info("iOS支付签名生成详情:", {
+                filteredParams,
+                queryString,
+                stringToSign,
+                signature
+            });
+
+            return signature;
+        } catch (error) {
+            logger.error("iOS支付签名生成出错:", error);
+            return "";
+        }
+    }
+
+    /**
+     * 内部订单校验方法(不依赖Koa上下文)
+     * @param gameid 游戏ID
+     * @param notify_id 平台通知ID
+     * @param config 渠道配置
+     */
+    private async verifyOrderInternal(gameid: string, notify_id: string, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
+        try {
+            // 生成订单校验签名
+            const sign = this.generateOrderVerifySignature(gameid, notify_id, config);
+            
+            if (!sign) {
+                logger.error("订单校验签名生成失败");
+                return {
+                    success: false,
+                    message: "签名生成失败"
+                };
+            }
+
+            logger.info("订单校验请求参数:", { gameid, notify_id, sign });
+
+            // 调用第三方订单校验API
+            const apiUrl = `https://login.11h5.com/pay/paygate/verify.php?gameid=${gameid}&notify_id=${encodeURIComponent(notify_id)}&sign=${encodeURIComponent(sign)}`;
+            
+            logger.info("调用订单校验API:", { url: apiUrl });
+
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: this.getCommonHeaders(),
+                httpsAgent: this.getHttpsAgent()
+            });
+
+            logger.info("订单校验API响应:", response.data);
+
+            // 检查响应结果
+            const responseText = response.data.toString().trim();
+            if (responseText === "SUCCESS") {
+                logger.info("订单校验成功:", { notify_id, gameid });
+                return {
+                    success: true,
+                    message: "订单校验成功"
+                };
+            } else {
+                logger.warn("订单校验失败:", { notify_id, gameid, response: responseText });
+                return {
+                    success: false,
+                    message: `订单校验失败: ${responseText}`
+                };
+            }
+
+        } catch (error) {
+            logger.error("订单校验出错:", error);
+            return {
+                success: false,
+                message: "订单校验失败"
+            };
+        }
+    }
+
+    /**
+     * 订单校验(公开接口)
+     * @param ctx Koa上下文
+     * @param config 渠道配置
+     */
+    async verifyOrder(ctx: Context, config: ChannelConfig): Promise<{ success: boolean; message: string }> {
+        try {
+            const { gameid, notify_id, sign } = ctx.request.query || ctx.request.body;
+            
+            // 验证必要参数
+            if (!gameid) {
+                logger.error("订单校验失败 - 缺少gameid参数");
+                return {
+                    success: false,
+                    message: "缺少必要参数: gameid"
+                };
+            }
+
+            if (!notify_id) {
+                logger.error("订单校验失败 - 缺少notify_id参数");
+                return {
+                    success: false,
+                    message: "缺少必要参数: notify_id"
+                };
+            }
+
+            if (!sign) {
+                logger.error("订单校验失败 - 缺少sign参数");
+                return {
+                    success: false,
+                    message: "缺少必要参数: sign"
+                };
+            }
+
+            logger.info("订单校验请求参数:", { gameid, notify_id, sign });
+
+            // 验证签名
+            const verifyData = { gameid, notify_id, sign };
+            if (!this.verifyPaymentSignature(verifyData, config)) {
+                logger.error("订单校验签名验证失败");
+                return {
+                    success: false,
+                    message: "签名验证失败"
+                };
+            }
+
+            // 调用第三方订单校验API
+            const apiUrl = `https://login.11h5.com/pay/paygate/verify.php?gameid=${gameid}&notify_id=${encodeURIComponent(notify_id)}&sign=${encodeURIComponent(sign)}`;
+            
+            logger.info("调用订单校验API:", { url: apiUrl });
+
+            const response = await axios.get(apiUrl, {
+                timeout: 10000,
+                headers: this.getCommonHeaders(),
+                httpsAgent: this.getHttpsAgent()
+            });
+
+            logger.info("订单校验API响应:", response.data);
+
+            // 检查响应结果
+            const responseText = response.data.toString().trim();
+            if (responseText === "SUCCESS") {
+                logger.info("订单校验成功:", { notify_id, gameid });
+                return {
+                    success: true,
+                    message: "订单校验成功"
+                };
+            } else {
+                logger.warn("订单校验失败:", { notify_id, gameid, response: responseText });
+                return {
+                    success: false,
+                    message: `订单校验失败: ${responseText}`
+                };
+            }
+
+        } catch (error) {
+            logger.error("订单校验出错:", error);
+            return {
+                success: false,
+                message: "订单校验失败"
+            };
+        }
+    }
+
+    /**
+     * 生成订单校验签名
+     * @param gameid 游戏ID
+     * @param notify_id 平台通知ID
+     * @param config 渠道配置
+     * @returns 签名字符串
+     */
+    private generateOrderVerifySignature(gameid: string, notify_id: string, config: ChannelConfig): string {
+        try {
+            const privateKey = config.paymentConfig?.signKey || '';
+            if (!privateKey) {
+                logger.error("订单校验签名生成失败 - 缺少私钥");
+                return "";
+            }
+
+            // 构建参数对象
+            const params = {
+                gameid: gameid,
+                notify_id: notify_id
+            };
+
+            // 使用签名算法3生成签名
+            return this.generatePaymentSignature(params, config);
+        } catch (error) {
+            logger.error("订单校验签名生成出错:", error);
+            return "";
+        }
+    }
+}

+ 2 - 2
webServer/src/channels/handlers/SanLiAndroidChannelHandler.ts

@@ -15,7 +15,7 @@ const logger = require("../../utils/log");
 
 export class SanLiAndroidChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     // 构建三狸H5登录验证请求URL
     const reqUrl = `http://checkuser.quickapi.net/v2/checkUserInfo?token=${data.token}&uid=${data.uid}&product_code=${config.loginConfig?.productCode}`;
@@ -50,7 +50,7 @@ export class SanLiAndroidChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     logger.info("三狸安卓支付回调参数:", { url: ctx.href, params: data });
     let ntData = data.nt_data;

+ 2 - 2
webServer/src/channels/handlers/SanLiH5ChannelHandler.ts

@@ -15,7 +15,7 @@ const logger = require("../../utils/log");
 
 export class SanLiH5ChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     // 构建三狸H5登录验证请求URL
     const reqUrl = `http://checkuser.quickapi.net/v2/checkUserInfo?token=${data.token}&uid=${data.uid}&product_code=${config.loginConfig?.productCode}`;
@@ -50,7 +50,7 @@ export class SanLiH5ChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     logger.info("三狸H5支付回调参数:", { url: ctx.href, params: data });
     let ntData = data.nt_data;

+ 2 - 2
webServer/src/channels/handlers/SanLiIOSChannelHandler.ts

@@ -14,7 +14,7 @@ const logger = require("../../utils/log");
 
 export class SanLiIOSChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
 
     // 构建三狸iOS登录验证请求URL
     const reqUrl = `http://sdkapi.3ligame.com/webapi/checkUserInfo?token=${data.token}&uid=${data.uid}&product_code=${config.loginConfig?.productCode}`;
@@ -49,7 +49,7 @@ export class SanLiIOSChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("三狸iOS支付回调参数:", { url: ctx.href, params: data });
     let ntData = data.nt_data;
 

+ 2 - 2
webServer/src/channels/handlers/ThreeSixZeroChannelHandler.ts

@@ -11,7 +11,7 @@ const logger = require("../../utils/log");
 
 export class ThreeSixZeroChannelHandler implements ChannelHandler {
   async handleLogin(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360登录请求参数:", { data });
 
     if (!data.iaaq) {
@@ -49,7 +49,7 @@ export class ThreeSixZeroChannelHandler implements ChannelHandler {
     ctx: Context,
     config: ChannelConfig
   ): Promise<PaymentResult> {
-    const data = ctx.request.body;
+    const data = ctx.request.body as any;
     logger.info("360支付回调参数:", { url: ctx.href, params: data });
 
     // 验证签名

+ 235 - 176
webServer/src/config/channelConfig.ts

@@ -1,201 +1,260 @@
 import {
-  QUICK_MD5_KEY,
-  QUICK_CALLBACK_KEY,
-  QUICK_PRODUCT_CODE,
-  QUICK_H5_CALLBACK_KEY,
-  QUICK_H5_PRODUCT_CODE,
-  QUICK_H5_MD5_KEY,
-  QUICK_IOS_PRODUCT_CODE,
-  QUICK_IOS_CALLBACK_KEY,
-  QUICK_IOS_MD5_KEY,
-  AppSecret360,
-  AppKey360,
-  MuziIosLoginKey,
-  MuziIosPayKey,
-  CALLBACK_KEY_4399,
-  SECRET_KEY_4399,
-  CALLBACK_KEY_4399_V2,
-  SECRET_KEY_4399_V2,
-  APP_ID_4399,
-  APP_ID_4399_V2,
-  SECRET_KEY_QIHU,
-  QIAI_QUICK_H5_CALLBACK_KEY,
-  QIAI_QUICK_H5_PRODUCT_CODE,
-  QIAI_QUICK_H5_MD5_KEY,
+    QUICK_MD5_KEY,
+    QUICK_CALLBACK_KEY,
+    QUICK_PRODUCT_CODE,
+    QUICK_H5_CALLBACK_KEY,
+    QUICK_H5_PRODUCT_CODE,
+    QUICK_H5_MD5_KEY,
+    QUICK_IOS_PRODUCT_CODE,
+    QUICK_IOS_CALLBACK_KEY,
+    QUICK_IOS_MD5_KEY,
+    AppSecret360,
+    AppKey360,
+    MuziIosLoginKey,
+    MuziIosPayKey,
+    CALLBACK_KEY_4399,
+    SECRET_KEY_4399,
+    CALLBACK_KEY_4399_V2,
+    SECRET_KEY_4399_V2,
+    APP_ID_4399,
+    APP_ID_4399_V2,
+    SECRET_KEY_QIHU,
+    QIAI_QUICK_H5_CALLBACK_KEY,
+    QIAI_QUICK_H5_PRODUCT_CODE,
+    QIAI_QUICK_H5_MD5_KEY,
+    MINI_APP_DOMAIN,
+    MINI_APP_PRIVATE_KEY,
+    MINI_APP_GAME_ID,
+    MINI_APP_API_KEY,
+    MINI_APP_STAT_API_KEY,
+    SY_IOS_PRIVATE_KEY, 
+    SY_IOS_GAME_ID,
+    MIANYOU_LOGIN_KEY,
+    MIANYOU_PAYMENT_KEY,
+    MIANYOU_GAME_ID,
+    MIANYOU_SDK_DOMAIN,
+    HUPU_QUICK_MD5_KEY,
+    HUPU_QUICK_CALLBACK_KEY,
+    HUPU_QUICK_PRODUCT_CODE
 } from "./thirdParams";
 
 // 渠道配置接口定义
 export interface ChannelConfig {
-  channelId: number; // 渠道ID
-  name: string; // 渠道名称
-  platform: string; // 平台标识
-  paymentConfig: {
-    // 支付相关配置
-    signKey?: string; // 签名密钥
-    callbackKey?: string; // 回调密钥
-    appSecret?: string; // 应用密钥
-    apiUrl?: string; // API地址
-    clientSecret?: string; // 客户端密钥
-    ClientId?: string; // 客户端id
-  };
-  loginConfig?: {
-    // 登录相关配置
-    productCode?: string; // 产品代码
-    appId?: string; // 应用ID
-    signKey?: string; // 签名密钥
-    callKey?: string; // 签名密钥
-  };
+    channelId: number; // 渠道ID
+    name: string; // 渠道名称
+    platform: string; // 平台标识
+    paymentConfig: {
+        // 支付相关配置
+        signKey?: string; // 签名密钥
+        callbackKey?: string; // 回调密钥
+        appSecret?: string; // 应用密钥
+        apiUrl?: string; // API地址
+        clientSecret?: string; // 客户端密钥
+        ClientId?: string; // 客户端id
+        gameId?: string; // 游戏ID
+    };
+    loginConfig?: {
+        // 登录相关配置
+        productCode?: string; // 产品代码
+        appId?: string; // 应用ID
+        signKey?: string; // 签名密钥
+        callKey?: string; // 签名密钥
+        apiKey?: string; // API密钥
+        statApiKey?: string; // 统计API密钥
+    };
 }
 
 // 渠道配置对象
 export const channelConfigs: Record<number, ChannelConfig> = {
-  1: {
-    // 木子
-    channelId: 1,
-    name: "木子",
-    platform: "木子",
-    paymentConfig: {
-      signKey: AppSecret360,
+    1: {
+        // 木子
+        channelId: 1,
+        name: "木子",
+        platform: "木子",
+        paymentConfig: {
+            signKey: AppSecret360,
+        },
+        loginConfig: {
+            signKey: AppKey360,
+        },
     },
-    loginConfig: {
-      signKey: AppKey360,
+    2: {
+        // 三狸安卓
+        channelId: 2,
+        name: "三狸安卓",
+        platform: "quick",
+        paymentConfig: {
+            signKey: QUICK_MD5_KEY,
+            callbackKey: QUICK_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: QUICK_PRODUCT_CODE,
+        },
     },
-  },
-  2: {
-    // 三狸安卓
-    channelId: 2,
-    name: "三狸安卓",
-    platform: "quick",
-    paymentConfig: {
-      signKey: QUICK_MD5_KEY,
-      callbackKey: QUICK_CALLBACK_KEY,
+    3: {
+        // 三狸iOS
+        channelId: 3,
+        name: "三狸iOS",
+        platform: "quickIos",
+        paymentConfig: {
+            signKey: QUICK_IOS_MD5_KEY,
+            callbackKey: QUICK_IOS_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: QUICK_IOS_PRODUCT_CODE,
+        },
     },
-    loginConfig: {
-      productCode: QUICK_PRODUCT_CODE,
-    },
-  },
-  3: {
-    // 三狸iOS
-    channelId: 3,
-    name: "三狸iOS",
-    platform: "quickIos",
-    paymentConfig: {
-      signKey: QUICK_IOS_MD5_KEY,
-      callbackKey: QUICK_IOS_CALLBACK_KEY,
+    4: {
+        // QQ大厅
+        channelId: 4,
+        name: "QQ大厅",
+        platform: "qqgame",
+        paymentConfig: {},
     },
-    loginConfig: {
-      productCode: QUICK_IOS_PRODUCT_CODE,
+    5: {
+        // 三狸H5
+        channelId: 5,
+        name: "三狸H5",
+        platform: "quickH5",
+        paymentConfig: {
+            signKey: QUICK_H5_MD5_KEY,
+            callbackKey: QUICK_H5_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: QUICK_H5_PRODUCT_CODE,
+        },
     },
-  },
-  4: {
-    // QQ大厅
-    channelId: 4,
-    name: "QQ大厅",
-    platform: "qqgame",
-    paymentConfig: {},
-  },
-  5: {
-    // 三狸H5
-    channelId: 5,
-    name: "三狸H5",
-    platform: "quickH5",
-    paymentConfig: {
-      signKey: QUICK_H5_MD5_KEY,
-      callbackKey: QUICK_H5_CALLBACK_KEY,
+    6: {
+        // 4399
+        channelId: 6,
+        name: "4399",
+        platform: "4399h5",
+        paymentConfig: {
+            signKey: CALLBACK_KEY_4399,
+        },
+        loginConfig: {
+            signKey: SECRET_KEY_4399,
+            callKey: CALLBACK_KEY_4399,
+            appId: APP_ID_4399
+        },
     },
-    loginConfig: {
-      productCode: QUICK_H5_PRODUCT_CODE,
+    7: {
+        // 360
+        channelId: 7,
+        name: "360",
+        platform: "360",
+        paymentConfig: {
+            signKey: SECRET_KEY_QIHU,
+        },
+        loginConfig: {
+            signKey: SECRET_KEY_QIHU,
+        },
     },
-  },
-  6: {
-    // 4399
-    channelId: 6,
-    name: "4399",
-    platform: "4399h5",
-    paymentConfig: {
-      signKey: CALLBACK_KEY_4399,
+    999: {
+        // 4399
+        channelId: 6,
+        name: "4399new",
+        platform: "4399h5new",
+        paymentConfig: {
+            signKey: CALLBACK_KEY_4399_V2,
+        },
+        loginConfig: {
+            signKey: SECRET_KEY_4399_V2,
+            callKey: CALLBACK_KEY_4399_V2,
+            appId: APP_ID_4399_V2
+        },
     },
-    loginConfig: {
-      signKey: SECRET_KEY_4399,
-      callKey:CALLBACK_KEY_4399,
-      appId: APP_ID_4399
+    8: {
+        // 七艾H5
+        channelId: 8,
+        name: "七艾",
+        platform: "qiaiH5",
+        paymentConfig: {
+            signKey: QIAI_QUICK_H5_MD5_KEY,
+            callbackKey: QIAI_QUICK_H5_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: QIAI_QUICK_H5_PRODUCT_CODE,
+        },
     },
-  },
-  7: {
-    // 360
-    channelId: 7,
-    name: "360",
-    platform: "360",
-    paymentConfig: {
-      signKey: SECRET_KEY_QIHU,
+    9: {
+        // 木子
+        channelId: 9,
+        name: "木子ios",
+        platform: "木子ios",
+        paymentConfig: {
+            signKey: MuziIosPayKey,
+        },
+        loginConfig: {
+            signKey: MuziIosLoginKey,
+        },
     },
-    loginConfig: {
-        signKey: SECRET_KEY_QIHU,
+    10: {
+        // 三狸安卓
+        channelId: 10,
+        name: "互视",
+        platform: "quick",
+        paymentConfig: {
+            signKey: QUICK_MD5_KEY,
+            callbackKey: QUICK_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: QUICK_PRODUCT_CODE,
+        },
     },
-  },
-  999: {
-    // 4399
-    channelId: 6,
-    name: "4399new",
-    platform: "4399h5new",
-    paymentConfig: {
-      signKey: CALLBACK_KEY_4399_V2,
+    11: {
+        // 小程序
+        channelId: 11,
+        name: "小程序",
+        platform: "miniapp",
+        paymentConfig: {
+            signKey: MINI_APP_PRIVATE_KEY,
+            apiUrl: MINI_APP_DOMAIN,
+            gameId: MINI_APP_GAME_ID,
+        },
+        loginConfig: {
+            apiKey: MINI_APP_API_KEY,
+            statApiKey: MINI_APP_STAT_API_KEY,
+        },
     },
-    loginConfig: {
-      signKey: SECRET_KEY_4399_V2,
-      callKey:CALLBACK_KEY_4399_V2,
-      appId: APP_ID_4399_V2
+    12: {
+        // ios
+        channelId: 12,
+        name: "ios",
+        platform: "sy_ios",
+        paymentConfig: {
+            signKey: SY_IOS_PRIVATE_KEY,
+            gameId: SY_IOS_GAME_ID,
+        },
+        loginConfig: {
+            signKey: SY_IOS_PRIVATE_KEY,
+        },
     },
-  },
-  8: {
-    // 七艾H5
-    channelId: 8,
-    name: "七艾",
-    platform: "qiaiH5",
-    paymentConfig: {
-      signKey: QIAI_QUICK_H5_MD5_KEY,
-      callbackKey: QIAI_QUICK_H5_CALLBACK_KEY,
-    },
-    loginConfig: {
-      productCode: QIAI_QUICK_H5_PRODUCT_CODE,
-    },
-  },
-  9: {
-    // 木子
-    channelId: 9,
-    name: "木子ios",
-    platform: "木子ios",
-    paymentConfig: {
-      signKey: MuziIosPayKey,
-    },
-    loginConfig: {
-      signKey: MuziIosLoginKey,
-    },
-  },
-  10: {
-    // 三狸安卓
-    channelId: 10,
-    name: "互视",
-    platform: "quick",
-    paymentConfig: {
-      signKey: QUICK_MD5_KEY,
-      callbackKey: QUICK_CALLBACK_KEY,
-    },
-    loginConfig: {
-      productCode: QUICK_PRODUCT_CODE,
-    },
-  },
-  11: {
-    // 三狸安卓
-    channelId: 11,
-    name: "小游戏",
-    platform: "minigame",
-    paymentConfig: {
-      signKey: QUICK_MD5_KEY,
-      callbackKey: QUICK_CALLBACK_KEY,
+    13: {
+        // 勉游渠道
+        channelId: 13,
+        name: "勉游",
+        platform: "mianyou",
+        paymentConfig: {
+            signKey: MIANYOU_PAYMENT_KEY,
+            gameId: MIANYOU_GAME_ID,
+            apiUrl: MIANYOU_SDK_DOMAIN,
+        },
+        loginConfig: {
+            signKey: MIANYOU_LOGIN_KEY,
+        },
     },
-    loginConfig: {
-      productCode: QUICK_PRODUCT_CODE,
+    14: {
+        // Hupu QuickSDK
+        channelId: 14,
+        name: "虎扑",
+        platform: "hupu",
+        paymentConfig: {
+            signKey: HUPU_QUICK_MD5_KEY,
+            callbackKey: HUPU_QUICK_CALLBACK_KEY,
+        },
+        loginConfig: {
+            productCode: HUPU_QUICK_PRODUCT_CODE,
+        },
     },
-  },
 };

+ 8 - 0
webServer/src/config/dbConfig.ts

@@ -7,6 +7,14 @@ export const mysqlConfig = {
     port: 3306, //数据库端口
 };
 
+// export const mysqlConfig = {
+//   user: "admin", //账号
+//   password: "aEsf$sfd@#411", //密码
+//   database: "sdk", //数据库
+//   host: "118.145.139.78", //服务器地址
+//   port: 3306, //数据库端口
+// };
+
 export const redisConfig = {
     host: 'localhost',
     port: 6379,

+ 29 - 1
webServer/src/config/thirdParams.ts

@@ -89,4 +89,32 @@ export const SECRET_KEY_QIHU = "IrIRKXs674NiNZiNSaaPQsgX904LwFgu";
 
 export const QIAI_QUICK_H5_MD5_KEY = "qnevushjm7deklbc1mbr55iqejzxnyco";
 export const QIAI_QUICK_H5_CALLBACK_KEY = "37750567448382738619439231053656";
-export const QIAI_QUICK_H5_PRODUCT_CODE = "80939198711722706880933346971719";
+export const QIAI_QUICK_H5_PRODUCT_CODE = "80939198711722706880933346971719";
+
+//小程序
+
+export const MINI_APP_DOMAIN = "wefunol.com";
+export const MINI_APP_PRIVATE_KEY = "lxq05Tka0pXR8IxK5Imz61qF1XZVwhEj";
+export const MINI_APP_GAME_ID = "1540";
+export const MINI_APP_API_KEY = "your_api_key_here";
+export const MINI_APP_STAT_API_KEY = "your_stat_api_key_here";
+
+//圣扬ios
+export const SY_IOS_PRIVATE_KEY = "rDfOG8nq4y9dH0oXfUwghcBQqllmJwrR";
+export const SY_IOS_GAME_ID = "1550";
+export const SY_IOS_API_KEY = "your_api_key_here";
+export const SY_IOS_STAT_API_KEY = "your_stat_api_key_here";
+
+//勉游渠道
+export const MIANYOU_LOGIN_KEY = "5881827684e373b286b94f0091be0b6e";
+export const MIANYOU_PAYMENT_KEY = "5881827684e373b286b94f0091be0b6e";
+export const MIANYOU_GAME_ID = "109";
+export const MIANYOU_SDK_DOMAIN = "https://i.fist-game.com";
+
+// Hupu QuickSDK
+export const HUPU_QUICK_MD5_KEY = "jjbzkexkkar01pcpkrwgb7i0plwnpmu8";
+export const HUPU_QUICK_CALLBACK_KEY = "50008469510564927526915032459625";
+export const HUPU_QUICK_PRODUCT_CODE = "06273907688357351140953453508499";
+export const HUPU_QUICK_PRODUCT_KEY = "12641617";
+
+

+ 1316 - 1130
webServer/src/controller/ApiController.ts

@@ -1,23 +1,24 @@
 import Msg from "../utils/msg";
 import {
-  RefreshToken,
-  PackageName,
-  ProductId,
-  IosUrl,
-  Account,
-  ClientSecret,
-  ClientId,
-  ORDER_SIGN_KEY,
+    RefreshToken,
+    PackageName,
+    ProductId,
+    IosUrl,
+    Account,
+    ClientSecret,
+    ClientId,
+    ORDER_SIGN_KEY,
 } from "../config/thirdParams";
 import {
-  generateOrderNumber,
-  formatDate,
-  getServerList,
-  getClientIp,
+    generateOrderNumber,
+    formatDate,
+    getServerList,
+    getClientIp,
 } from "../utils/common";
-import { PaymentHelper } from "../utils/PaymentHelper";
-import { SignatureVerifier } from "../utils/SignatureVerifier";
-import { ChannelConfigManager } from "../utils/ChannelConfigManager";
+import {PaymentHelper} from "../utils/PaymentHelper";
+import {SignatureVerifier} from "../utils/SignatureVerifier";
+import {ChannelConfigManager} from "../utils/ChannelConfigManager";
+import {getRoleInfoByUidAndServerId} from "../mongo/mongodb";
 
 // 导入依赖
 const CryptoJS = require("crypto-js");
@@ -27,1295 +28,1480 @@ const System = require("../model/SystemModel");
 const User = require("../model/UserModel");
 const logger = require("../utils/log");
 const axios = require("axios");
-const { channelFactory } = require("../channels/factory/ChannelFactory");
+const {channelFactory} = require("../channels/factory/ChannelFactory");
+const {MianyouChannelHandler} = require("../channels/handlers/MianyouChannelHandler");
 
 /**
  * Google支付回调处理
  */
 const googleCallPay = async (ctx, config) => {
-  let data = ctx.request.body;
-  let orderId = data.orderId;
-  let googleToken = data.purchaseToken;
-  let out_trade_no = "";
+    let data = ctx.request.body;
+    let orderId = data.orderId;
+    let googleToken = data.purchaseToken;
+    let out_trade_no = "";
+
+    logger.info("Google支付回调参数:", {url: ctx.href, params: data});
+
+    // 更新订单Token
+    await Order.updateOrderToken(orderId, googleToken, "google");
+
+    // 获取Google访问令牌
+    const redisClient = ctx.redis.client;
+    let access_token = await redisClient.get("access_token");
+
+    if (!access_token) {
+        logger.info("请求Google API获取token");
+        const apiData = {
+            grant_type: "refresh_token",
+            client_id: ClientId,
+            client_secret: ClientSecret,
+            refresh_token: RefreshToken,
+        };
 
-  logger.info("Google支付回调参数:", { url: ctx.href, params: data });
+        try {
+            const response = await axios.post(
+                "https://accounts.google.com/o/oauth2/token",
+                apiData,
+                {
+                    headers: {
+                        "Content-Type": "application/x-www-form-urlencoded",
+                    },
+                }
+            );
+
+            logger.info("Google token响应:", {data: response.data});
+
+            if (!response.data.access_token) {
+                return PaymentHelper.DEFAULT_RESULT;
+            }
 
-  // 更新订单Token
-  await Order.updateOrderToken(orderId, googleToken, "google");
+            access_token = response.data.access_token;
+            await redisClient.set("access_token", response.data.access_token);
+            await redisClient.expire("access_token", 1800);
+        } catch (error) {
+            logger.error("获取Google token失败:", error);
+            return PaymentHelper.DEFAULT_RESULT;
+        }
+    }
 
-  // 获取Google访问令牌
-  const redisClient = ctx.redis.client;
-  let access_token = await redisClient.get("access_token");
+    if (!access_token) {
+        return PaymentHelper.DEFAULT_RESULT;
+    }
 
-  if (!access_token) {
-    logger.info("请求Google API获取token");
-    const apiData = {
-      grant_type: "refresh_token",
-      client_id: ClientId,
-      client_secret: ClientSecret,
-      refresh_token: RefreshToken,
-    };
+    // 验证订单
+    const validation = await PaymentHelper.validateOrder(orderId);
+    if (!validation.valid) {
+        return {
+            code: validation.message?.includes("重复发货") ? 1 : 0,
+            msg: validation.message,
+        };
+    }
 
-    try {
-      const response = await axios.post(
-        "https://accounts.google.com/o/oauth2/token",
-        apiData,
-        {
-          headers: {
-            "Content-Type": "application/x-www-form-urlencoded",
-          },
+    const orderInfo = validation.orderInfo;
+
+    // 验证Google订单
+    const productId = ProductId + orderInfo.product_id;
+    let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}`;
+    let maxRetries = 3;
+    let currentRetry = 0;
+    let isCheck = false;
+
+    // 使用循环进行重试
+    while (currentRetry < maxRetries) {
+        try {
+            const googleRes = await axios.get(apiUrl, {
+                headers: {
+                    "Content-Type": "application/x-www-form-urlencoded",
+                },
+            });
+
+            logger.info("Google验证响应:", googleRes.data);
+
+            if (googleRes.data.purchaseState == 0) {
+                out_trade_no = googleRes.data.orderId;
+                isCheck = true;
+                break;
+            }
+        } catch (error) {
+            logger.error("Google验证请求失败:", error);
         }
-      );
 
-      logger.info("Google token响应:", { data: response.data });
+        currentRetry++;
+    }
 
-      if (!response.data.access_token) {
+    if (!isCheck) {
         return PaymentHelper.DEFAULT_RESULT;
-      }
-
-      access_token = response.data.access_token;
-      await redisClient.set("access_token", response.data.access_token);
-      await redisClient.expire("access_token", 1800);
-    } catch (error) {
-      logger.error("获取Google token失败:", error);
-      return PaymentHelper.DEFAULT_RESULT;
-    }
-  }
-
-  if (!access_token) {
-    return PaymentHelper.DEFAULT_RESULT;
-  }
-
-  // 验证订单
-  const validation = await PaymentHelper.validateOrder(orderId);
-  if (!validation.valid) {
-    return {
-      code: validation.message?.includes("重复发货") ? 1 : 0,
-      msg: validation.message,
-    };
-  }
-
-  const orderInfo = validation.orderInfo;
-
-  // 验证Google订单
-  const productId = ProductId + orderInfo.product_id;
-  let apiUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}?access_token=${access_token}`;
-  let maxRetries = 3;
-  let currentRetry = 0;
-  let isCheck = false;
-
-  // 使用循环进行重试
-  while (currentRetry < maxRetries) {
-    try {
-      const googleRes = await axios.get(apiUrl, {
-        headers: {
-          "Content-Type": "application/x-www-form-urlencoded",
-        },
-      });
-
-      logger.info("Google验证响应:", googleRes.data);
-
-      if (googleRes.data.purchaseState == 0) {
-        out_trade_no = googleRes.data.orderId;
-        isCheck = true;
-        break;
-      }
-    } catch (error) {
-      logger.error("Google验证请求失败:", error);
     }
 
-    currentRetry++;
-  }
-
-  if (!isCheck) {
-    return PaymentHelper.DEFAULT_RESULT;
-  }
-
-  // 发货处理
-  const result = await PaymentHelper.deliverOrder(
-    orderInfo,
-    ctx.request.ip,
-    validation.url,
-    out_trade_no
-  );
-
-  // 确认和消费Google订单
-  try {
-    // 确认订单
-    let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`;
-    await axios.post(
-      acknowledgeUrl,
-      { developerPayload: "" },
-      { headers: { "Content-Type": "application/json" } }
+    // 发货处理
+    const result = await PaymentHelper.deliverOrder(
+        orderInfo,
+        ctx.request.ip,
+        validation.url,
+        out_trade_no
     );
 
-    // 消费订单
-    let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}`;
-    await axios.post(
-      consumeUrl,
-      { developerPayload: "" },
-      { headers: { "Content-Type": "application/json" } }
-    );
+    // 确认和消费Google订单
+    try {
+        // 确认订单
+        let acknowledgeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:acknowledge?access_token=${access_token}`;
+        await axios.post(
+            acknowledgeUrl,
+            {developerPayload: ""},
+            {headers: {"Content-Type": "application/json"}}
+        );
+
+        // 消费订单
+        let consumeUrl = `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${PackageName}/purchases/products/${productId}/tokens/${googleToken}:consume?access_token=${access_token}`;
+        await axios.post(
+            consumeUrl,
+            {developerPayload: ""},
+            {headers: {"Content-Type": "application/json"}}
+        );
 
-    logger.info("Google订单处理完成:", { orderId: orderId });
-  } catch (error) {
-    logger.error("Google订单确认/消费失败:", error);
-    // 即使确认/消费失败,我们仍然返回发货结果,因为发货可能已经成功
-  }
+        logger.info("Google订单处理完成:", {orderId: orderId});
+    } catch (error) {
+        logger.error("Google订单确认/消费失败:", error);
+        // 即使确认/消费失败,我们仍然返回发货结果,因为发货可能已经成功
+    }
 
-  return result;
+    return result;
 };
 
 /**
  * Apple支付回调处理
  */
 const appleCallPay = async (ctx, config) => {
-  let data = ctx.request.body;
-  logger.info("Apple支付回调参数:", { url: ctx.href, params: data });
+    let data = ctx.request.body;
+    logger.info("Apple支付回调参数:", {url: ctx.href, params: data});
 
-  if (!data.purchaseToken || !data.orderId) {
-    return PaymentHelper.DEFAULT_RESULT;
-  }
+    if (!data.purchaseToken || !data.orderId) {
+        return PaymentHelper.DEFAULT_RESULT;
+    }
 
-  let receipt_data = data.purchaseToken.replace(/ /g, "+");
-  let orderId = data.orderId;
-  let out_trade_no = orderId;
+    let receipt_data = data.purchaseToken.replace(/ /g, "+");
+    let orderId = data.orderId;
+    let out_trade_no = orderId;
 
-  // 更新订单Token
-  await Order.updateOrderToken(orderId, receipt_data, "apple");
+    // 更新订单Token
+    await Order.updateOrderToken(orderId, receipt_data, "apple");
 
-  // 验证Apple收据
-  let maxRetries = 5;
-  let currentRetry = 0;
-  let isCheck = false;
+    // 验证Apple收据
+    let maxRetries = 5;
+    let currentRetry = 0;
+    let isCheck = false;
 
-  while (currentRetry < maxRetries) {
-    try {
-      const apiData = {
-        "receipt-data": receipt_data,
-      };
-
-      const response = await axios.post(IosUrl, apiData, {
-        headers: {
-          "Content-Type": "application/json",
-        },
-      });
-
-      logger.info(`Apple验证响应状态:${response.data.status}`);
-
-      if (response.data.status == 0) {
-        isCheck = true;
-        break;
-      }
-    } catch (error) {
-      logger.error("Apple验证请求失败:", error);
+    while (currentRetry < maxRetries) {
+        try {
+            const apiData = {
+                "receipt-data": receipt_data,
+            };
+
+            const response = await axios.post(IosUrl, apiData, {
+                headers: {
+                    "Content-Type": "application/json",
+                },
+            });
+
+            logger.info(`Apple验证响应状态:${response.data.status}`);
+
+            if (response.data.status == 0) {
+                isCheck = true;
+                break;
+            }
+        } catch (error) {
+            logger.error("Apple验证请求失败:", error);
+        }
+
+        currentRetry++;
     }
 
-    currentRetry++;
-  }
-
-  if (!isCheck) {
-    logger.info(`Apple票据验证失败!`);
-    return { code: 0, msg: "票据验证失败!" };
-  }
-
-  // 验证订单
-  const validation = await PaymentHelper.validateOrder(orderId);
-  if (!validation.valid) {
-    return {
-      code: validation.message?.includes("重复发货") ? 1 : 0,
-      msg: validation.message,
-    };
-  }
-
-  const orderInfo = validation.orderInfo;
-
-  // 发货处理
-  logger.info(`订单${orderId}通知游戏发货开始`);
-  const result = await PaymentHelper.deliverOrder(
-    orderInfo,
-    ctx.request.ip,
-    validation.url,
-    out_trade_no
-  );
-  logger.info(`订单${orderId}通知游戏发货结束,结果:`, result);
-
-  return result;
+    if (!isCheck) {
+        logger.info(`Apple票据验证失败!`);
+        return {code: 0, msg: "票据验证失败!"};
+    }
+
+    // 验证订单
+    const validation = await PaymentHelper.validateOrder(orderId);
+    if (!validation.valid) {
+        return {
+            code: validation.message?.includes("重复发货") ? 1 : 0,
+            msg: validation.message,
+        };
+    }
+
+    const orderInfo = validation.orderInfo;
+
+    // 发货处理
+    logger.info(`订单${orderId}通知游戏发货开始`);
+    const result = await PaymentHelper.deliverOrder(
+        orderInfo,
+        ctx.request.ip,
+        validation.url,
+        out_trade_no
+    );
+    logger.info(`订单${orderId}通知游戏发货结束,结果:`, result);
+
+    return result;
 };
 
 function splitString(input: string, separator: string): string[] {
-  return input.split(separator);
+    return input.split(separator);
 }
+
 //验证账号
 const checkUserToken = async (ctx) => {
-  let ip = getClientIp(ctx);
-
-  let {
-    uid,
-    channel_id,
-    device_no,
-    reg_device,
-    device_type,
-    device_model,
-    device_version,
-    system_version,
-  } = ctx.request.body;
-
-  const create_time = formatDate(new Date());
-  const accountInfo = (await User.checkAccountIsExist(uid, channel_id))[0];
-
-  let accountRes = null;
-  let res = null;
-  if (!accountInfo) {
-    accountRes = await User.createAccount(
-      uid,
-      channel_id,
-      ip,
-      device_no,
-      reg_device,
-      create_time
-    );
-
-    if (accountRes.affectedRows <= 0) {
-      return ApiController.fail("添加账户失败");
-    }
-  }
-
-  res = await User.logAccountLogin(
-    uid,
-    ip,
-    device_type,
-    device_no,
-    device_model,
-    device_version,
-    system_version,
-    create_time,
-    channel_id
-  );
-
-  if (res.affectedRows <= 0) {
-    return ApiController.fail("添加日志失败");
-  }
-
-  return ApiController.success("请求成功", 1, false, { ip: ip });
-};
+    let ip = getClientIp(ctx);
 
-class ApiController {
-  /**
-   * 生成成功响应
-   * @param msg 成功消息
-   * @param code 成功码,默认为1(部分API使用0表示成功)
-   * @param useMessage 是否使用message字段而不是msg字段,默认为false
-   * @param data 响应数据
-   * @returns 标准化的成功响应对象
-   */
-  static success(
-    msg: string = "请求成功",
-    code: number = 1,
-    useMessage: boolean = false,
-    data: any = null
-  ) {
-    return {
-      code: code,
-      [useMessage ? "message" : "msg"]: msg,
-      data: data,
-    };
-  }
-
-  /**
-   * 生成失败响应
-   * @param msg 错误消息
-   * @param code 错误码,默认为0
-   * @param data 额外的错误数据
-   * @param useMessage 是否使用message字段而不是msg字段,默认为false
-   * @returns 标准化的失败响应对象
-   */
-  static fail(
-    msg: string = "请求失败",
-    code: number = 0,
-    data: any = null,
-    useMessage: boolean = false
-  ) {
-    return {
-      code: code,
-      [useMessage ? "message" : "msg"]: msg,
-      data: data,
-    };
-  }
-
-  async createOrder(ctx) {
     let {
-      uid,
-      level,
-      amount,
-      role_id,
-      role_name,
-      product_id,
-      server_id,
-      channel_id,
+        uid,
+        channel_id,
+        device_no,
+        reg_device,
+        device_type,
+        device_model,
+        device_version,
+        system_version,
     } = ctx.request.body;
 
-    logger.info("create params:", { params: ctx.request.body });
-
-    if (
-      !product_id ||
-      !server_id ||
-      !role_name ||
-      !role_id ||
-      !amount ||
-      !uid ||
-      !channel_id
-    ) {
-      ctx.body = ApiController.fail("参数错误,创建订单失败!!", -1);
-      return;
-    }
+    const create_time = formatDate(new Date());
+    const accountInfo = (await User.checkAccountIsExist(uid, channel_id))[0];
 
-    const data = ctx.request.body;
-    if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
-      logger.error("创建订单签名验证失败");
-      ctx.body = ApiController.fail("签名错误,创建订单失败!!", -1);
-      return;
-    }
+    let accountRes = null;
+    let res = null;
+    if (!accountInfo) {
+        accountRes = await User.createAccount(
+            uid,
+            channel_id,
+            ip,
+            device_no,
+            reg_device,
+            create_time
+        );
 
-    if (amount < 1) {
-      ctx.body = ApiController.fail("金额错误,创建订单失败!!", -1);
-      return;
+        if (accountRes.affectedRows <= 0) {
+            return ApiController.fail("添加账户失败");
+        }
     }
 
-    const orderId = generateOrderNumber(); // 生成一个长度为8的订单号
-    const create_time = formatDate(new Date());
-    const res = await Order.createOrder(
-      orderId,
-      uid,
-      level,
-      amount,
-      role_id,
-      role_name,
-      product_id,
-      server_id,
-      channel_id,
-      create_time
+    res = await User.logAccountLogin(
+        uid,
+        ip,
+        device_type,
+        device_no,
+        device_model,
+        device_version,
+        system_version,
+        create_time,
+        channel_id
     );
 
-    if (res.affectedRows > 0) {
-      ctx.body = ApiController.success("创建订单成功", 0, false, orderId);
-    } else {
-      ctx.body = ApiController.fail("创建订单失败", -1, null);
+    if (res.affectedRows <= 0) {
+        return ApiController.fail("添加日志失败");
     }
 
-    logger.info("创建订单返回结果:", { params: ctx.body });
-  }
-
-  async checkUserToken(ctx) {
-    let { channel_id } = ctx.request.body;
-    const channelConfig = ChannelConfigManager.getConfig(channel_id);
-    if (!channelConfig) {
-      logger.info("未找到渠道配置:", { channel_id });
-      ctx.body = {
-        code: 0,
-        msg: "未知渠道id",
-      };
-      return;
-    }
+    return ApiController.success("请求成功", 1, false, {ip: ip});
+};
 
-    var result = await checkUserToken(ctx);
-    ctx.body = result;
-  }
+class ApiController {
+    /**
+     * 生成成功响应
+     * @param msg 成功消息
+     * @param code 成功码,默认为1(部分API使用0表示成功)
+     * @param useMessage 是否使用message字段而不是msg字段,默认为false
+     * @param data 响应数据
+     * @returns 标准化的成功响应对象
+     */
+    static success(
+        msg: string = "请求成功",
+        code: number = 1,
+        useMessage: boolean = false,
+        data: any = null
+    ) {
+        return {
+            code: code,
+            [useMessage ? "message" : "msg"]: msg,
+            data: data,
+        };
+    }
 
-  async thirdLogin(ctx) {
-    const data = ctx.request.body;
-    let channelId = parseInt(data.channel_id) || 1;
+    /**
+     * 生成失败响应
+     * @param msg 错误消息
+     * @param code 错误码,默认为0
+     * @param data 额外的错误数据
+     * @param useMessage 是否使用message字段而不是msg字段,默认为false
+     * @returns 标准化的失败响应对象
+     */
+    static fail(
+        msg: string = "请求失败",
+        code: number = 0,
+        data: any = null,
+        useMessage: boolean = false
+    ) {
+        return {
+            code: code,
+            [useMessage ? "message" : "msg"]: msg,
+            data: data,
+        };
+    }
 
-    logger.info("thirdLogin请求参数:", { data, channelId });
+    async createOrder(ctx) {
+        let {
+            uid,
+            level,
+            amount,
+            role_id,
+            role_name,
+            product_id,
+            server_id,
+            channel_id,
+        } = ctx.request.body;
+
+        logger.info("create params:", {params: ctx.request.body});
+
+        if (
+            !product_id ||
+            !server_id ||
+            !role_name ||
+            !role_id ||
+            !amount ||
+            !uid ||
+            !channel_id
+        ) {
+            ctx.body = ApiController.fail("参数错误,创建订单失败!!", -1);
+            return;
+        }
 
-    // 获取渠道配置
-    let channelConfig = ChannelConfigManager.getConfig(channelId);
+        const data = ctx.request.body;
+        if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
+            logger.error("创建订单签名验证失败");
+            ctx.body = ApiController.fail("签名错误,创建订单失败!!", -1);
+            return;
+        }
 
-    if (data.is_new == 1 ) {
-        if(channelId == 6){
-            channelConfig = ChannelConfigManager.getConfig(999);
+        if (amount <= 0) {
+            ctx.body = ApiController.fail("金额错误,创建订单失败!!", -1);
+            return;
         }
 
-        if(channelId == 1){
-            channelConfig = ChannelConfigManager.getConfig(9);
+        const orderId = generateOrderNumber(); // 生成一个长度为8的订单号
+        const create_time = formatDate(new Date());
+        const res = await Order.createOrder(
+            orderId,
+            uid,
+            level,
+            amount,
+            role_id,
+            role_name,
+            product_id,
+            server_id,
+            channel_id,
+            create_time
+        );
+
+        if (res.affectedRows > 0) {
+            ctx.body = ApiController.success("创建订单成功", 0, false, orderId);
+        } else {
+            ctx.body = ApiController.fail("创建订单失败", -1, null);
         }
-    }
 
-    if (!channelConfig) {
-      logger.info("未找到渠道配置:", { channelId });
-      ctx.body = ApiController.fail("未知渠道id");
-      return;
+        logger.info("创建订单返回结果:", {params: ctx.body});
     }
 
-    // 从工厂获取对应的渠道处理器
-    const handler = channelFactory.getHandler(channelId);
+    async checkUserToken(ctx) {
+        let {channel_id} = ctx.request.body;
+        const channelConfig = ChannelConfigManager.getConfig(channel_id);
+        if (!channelConfig) {
+            logger.info("未找到渠道配置:", {channel_id});
+            ctx.body = {
+                code: 0,
+                msg: "未知渠道id",
+            };
+            return;
+        }
 
-    if (!handler) {
-      logger.info("未找到渠道处理器:", { channelId });
-      ctx.body = ApiController.fail("未知渠道id");
-      return;
+        var result = await checkUserToken(ctx);
+        ctx.body = result;
     }
 
-    logger.info("使用渠道处理器处理登录:", {
-      channelId: channelId,
-      channelName: channelConfig.name,
-    });
+    async thirdLogin(ctx) {
+        const data = ctx.request.body;
+        let channelId = parseInt(data.channel_id) || 1;
+        const platform = data.platform; // 平台参数:ios、Android、miniapp、h5
 
-    // 调用渠道处理器的登录方法
-    const result = await handler.handleLogin(ctx, channelConfig);
+        logger.info("thirdLogin请求参数:", {data, channelId, platform});
 
-    // 根据不同渠道的返回格式要求处理结果
-    ctx.body = result;
-  }
+        // 渠道11和渠道12数据打通,统一使用渠道11
+        if (channelId === 12) {
+            channelId = 11;
+            logger.info("渠道12映射到渠道11,平台参数:", platform);
+        }
 
-  async callPay(ctx) {
-    const data = ctx.request.body;
-    let channelId = 1; // 默认渠道ID
+        // 获取渠道配置
+        let channelConfig = ChannelConfigManager.getConfig(channelId);
 
+        if (data.is_new == 1) {
+            if (channelId == 6) {
+                channelConfig = ChannelConfigManager.getConfig(999);
+            }
 
-    // 从请求中获取渠道ID
-    if (ctx.query.channel_id) {
-      channelId = parseInt(ctx.query.channel_id);
-    }
+            if (channelId == 1) {
+                channelConfig = ChannelConfigManager.getConfig(9);
+            }
+        }
 
-    if (data.channel_id) {
-      channelId = parseInt(data.channel_id);
-    }
+        if (!channelConfig) {
+            logger.info("未找到渠道配置:", {channelId});
+            ctx.body = ApiController.fail("未知渠道id");
+            return;
+        }
 
-    logger.info("当前支付渠道id:", { channelId });
+        // 从工厂获取对应的渠道处理器
+        const handler = channelFactory.getHandler(channelId);
 
-    // 获取渠道配置
-    let channelConfig = ChannelConfigManager.getConfig(channelId);
-    if (!channelConfig) {
-      logger.info("未找到渠道配置:", { channelId });
-      ctx.body = ApiController.fail("未知渠道id");
-      return;
-    }
-
-    if (ctx.query.is_new && ctx.query.is_new == 1 ) {
-        if(channelId == 6){
-            channelConfig = ChannelConfigManager.getConfig(999);
+        if (!handler) {
+            logger.info("未找到渠道处理器:", {channelId});
+            ctx.body = ApiController.fail("未知渠道id");
+            return;
         }
 
-        if(channelId == 1){
-            channelConfig = ChannelConfigManager.getConfig(9);
-        }
-    }
+        logger.info("使用渠道处理器处理登录:", {
+            channelId: channelId,
+            channelName: channelConfig.name,
+            platform: platform
+        });
 
-    const handler = channelFactory.getHandler(channelId);
+        // 调用渠道处理器的登录方法
+        const result = await handler.handleLogin(ctx, channelConfig);
 
-    if (!handler) {
-      logger.info("未找到渠道处理器:", { channelId });
-      ctx.body = ApiController.fail("未知渠道id");
-      return;
-    }
+        // 在返回结果中添加平台信息
+        if (result && result.data) {
+            result.data.platform = platform || 'unknown';
+        }
 
-    logger.info("使用渠道处理器处理支付:", {
-      channelId: channelId,
-      channelName: channelConfig.name,
-    });
-
-    // 调用渠道处理器的支付方法
-    const result = await handler.handlePayment(ctx, channelConfig);
-
-    // 根据不同渠道的返回格式要求处理结果
-    switch (channelConfig.channelId) {
-      case 6:
-        ctx.body = result.code === 1 ? 1 : result.code;
-        break;
-      case 2:
-      case 3:
-      case 5:
-      case 8:
-        ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
-        break;
-      case 7:
-        ctx.body = result.code === 1 ? "success" : "fail";
-        break;
-      default:
+        // 根据不同渠道的返回格式要求处理结果
         ctx.body = result;
     }
-  }
 
-  async getServerList(ctx) {
-    let tag = ctx.query.channel_id || 1;
-    let data = ctx.request.body;
-    let ip = getClientIp(ctx);
+    async callPay(ctx) {
+        const data = ctx.request.body;
+        let channelId = 1; // 默认渠道ID
+        //打印回调参数
+        logger.info("callPay支付回调参数:", {url: ctx.href, params: data, query: ctx.query});
 
-    // 尝试从渠道ID获取配置
-    const channelConfig = ChannelConfigManager.getConfig(1);
-    const signStr = data.timestamp + channelConfig.loginConfig?.signKey;
-    let newSign = CryptoJS.MD5(signStr).toString();
-
-    if (data.sign != newSign) {
-      console.log("signStr:", signStr);
-      logger.info(
-        `签名错误: 签名串 ${signStr} newSign ${newSign} sign ${data.sign}`
-      );
-      ctx.body = ApiController.fail("签名错误");
-      return;
-    }
+        // 从请求中获取渠道ID
+        if (ctx.query.channel_id) {
+            channelId = parseInt(ctx.query.channel_id);
+        }
 
-    let sort = data.sort == 0 ? "asc" : "desc";
-    logger.info("区服接口", { ip: ip });
-    const servers = await Server.getServerList(tag, 0, sort);
+        if (data.channel_id) {
+            channelId = parseInt(data.channel_id);
+        }
+
+        logger.info("当前支付渠道id:", {channelId});
 
-    let serverList = [];
-    if (servers.length > 0) {
-      servers.forEach(function (element) {
-        let status = element.status;
-        if ((status == 0 || status == 3) && element.white_list) {
-          const list = element.white_list.split(",");
+        // 获取渠道配置
+        let channelConfig = ChannelConfigManager.getConfig(channelId);
+        if (!channelConfig) {
+            logger.info("未找到渠道配置:", {channelId});
+            ctx.body = ApiController.fail("未知渠道id");
+            return;
+        }
 
-          if (list.length > 0) {
-            if (list.includes(ip)) {
-              status = 1;
+        if (ctx.query.is_new && ctx.query.is_new == 1) {
+            if (channelId == 6) {
+                channelConfig = ChannelConfigManager.getConfig(999);
+            }
+
+            if (channelId == 1) {
+                channelConfig = ChannelConfigManager.getConfig(9);
             }
-          }
         }
 
-        serverList.push({
-          serverId: element.id,
-          serverName: element.name,
-        });
-      });
-    }
+        const handler = channelFactory.getHandler(channelId);
 
-    ctx.body = ApiController.success("成功", 1, false, serverList);
-  }
-  async getAllServerList(ctx) {
-    let tag = ctx.query.channel_id || 1;
-    let ip = getClientIp(ctx);
-    logger.info("getAllServerList 区服接口", { tag: tag, ip: ip });
-    const servers = await Server.getAllServerList(tag, ip);
-    ctx.body = servers;
-    // ctx.body = ApiController.success("获取服务器列表成功", 1, false, servers);
-  }
-
-  async enterServer(ctx) {
-    let { uid, server_id, channel_id } = ctx.request.body;
-
-    let url = await getServerList(server_id, channel_id || 1);
-    if (!url) {
-      ctx.body = ApiController.fail(`区服id错误: serverId ${server_id}`, -1);
-      return;
-    }
+        if (!handler) {
+            logger.info("未找到渠道处理器:", {channelId});
+            ctx.body = ApiController.fail("未知渠道id");
+            return;
+        }
 
-    logger.info("create params:", { params: ctx.request.body });
+        logger.info("使用渠道处理器处理支付:", {
+            channelId: channelId,
+            channelName: channelConfig.name,
+        });
 
-    if (!server_id || !uid) {
-      ctx.body = ApiController.fail("参数错误!!", -1);
-      return;
+        // 调用渠道处理器的支付方法
+        const result = await handler.handlePayment(ctx, channelConfig);
+        // 根据不同渠道的返回格式要求处理结果
+        switch (channelConfig.channelId) {
+            case 6:
+                ctx.body = result.code === 1 ? 1 : result.code;
+                break;
+            case 2:
+            case 3:
+            case 5:
+            case 8:
+                ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
+                break;
+            case 7:
+                ctx.body = result.code === 1 ? "success" : "fail";
+                break;
+            case 11:
+                ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
+                break;
+            case 12:
+                ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
+                break;
+            case 13:
+                //{"status":0,"msg":"status 非 0 时,传入失败信息"}
+                ctx.body = {status: result.code === 1 ? 0 : -1, msg: result.msg};
+                break;
+            case 14:
+                ctx.body = result.code === 1 ? "SUCCESS" : "Fail";
+                break;
+            default:
+                ctx.body = result;
+        }
     }
 
-    const create_time = formatDate(new Date());
-    const serverInfo = (
-      await Server.checkEnterServerByUid(uid, server_id, channel_id)
-    )[0];
-    let res = null;
+    async getServerList(ctx) {
+        let tag = ctx.query.channel_id || 1;
+        let data = ctx.request.body;
+        let ip = getClientIp(ctx);
+
+        // 尝试从渠道ID获取配置
+        const channelConfig = ChannelConfigManager.getConfig(1);
+        const signStr = data.timestamp + channelConfig.loginConfig?.signKey;
+        let newSign = CryptoJS.MD5(signStr).toString();
+
+        if (data.sign != newSign) {
+            console.log("signStr:", signStr);
+            logger.info(
+                `签名错误: 签名串 ${signStr} newSign ${newSign} sign ${data.sign}`
+            );
+            ctx.body = ApiController.fail("签名错误");
+            return;
+        }
+
+        let sort = data.sort == 0 ? "asc" : "desc";
+        logger.info("区服接口", {ip: ip});
+        const servers = await Server.getServerList(tag, 0, sort);
+
+        let serverList = [];
+        if (servers.length > 0) {
+            servers.forEach(function (element) {
+                let status = element.status;
+                if ((status == 0 || status == 3) && element.white_list) {
+                    const list = element.white_list.split(",");
+
+                    if (list.length > 0) {
+                        if (list.includes(ip)) {
+                            status = 1;
+                        }
+                    }
+                }
+
+                serverList.push({
+                    serverId: element.id,
+                    serverName: element.name,
+                });
+            });
+        }
 
-    if (serverInfo) {
-      res = await Server.updateEnterServer(serverInfo.id, create_time);
-    } else {
-      res = await Server.enterServer(uid, server_id, create_time, channel_id);
+        ctx.body = ApiController.success("成功", 1, false, serverList);
     }
 
-    if (res.affectedRows > 0) {
-      ctx.body = ApiController.success("请求成功", 0, true, "");
-    } else {
-      ctx.body = ApiController.fail("请求失败", -1, null, true);
+    async getAllServerList(ctx) {
+        let tag = ctx.query.channel_id || 1;
+        let uid = ctx.query.uid || ctx.request.body?.uid; // uid是可选参数,支持GET和POST请求
+        let ip = getClientIp(ctx);
+        logger.info("getAllServerList 区服接口", {tag: tag, uid: uid, ip: ip});
+
+        const servers = await Server.getAllServerList(tag, ip);
+
+        // 如果提供了玩家ID,则查询每个服务器的角色信息;否则只返回基本服务器信息
+        if (uid) {
+            const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
+
+            // 为每个服务器添加角色信息
+            const serversWithRoleInfo = await Promise.all(
+                servers.map(async (server) => {
+                    try {
+                        const newUniqueTag = `${server.tag}|${server.sid}|${uid}`;
+                        const roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, server.db_name);
+                        return {
+                            ...server,
+                            roleName: roleInfo?.roleName || null,
+                            roleLevel: roleInfo?.roleLevel || null,
+                            head: roleInfo?.head || null,
+                            hasRole: !!roleInfo
+                        };
+                    } catch (error) {
+                        logger.error(`查询服务器${server.id}角色信息失败:`, error);
+                        return {
+                            ...server,
+                            roleName: null,
+                            roleLevel: null,
+                            head: null,
+                            hasRole: false
+                        };
+                    }
+                })
+            );
+
+            ctx.body = serversWithRoleInfo;
+        } else {
+            ctx.body = servers;
+        }
     }
-  }
 
-  async getLastServerList(ctx) {
-    let { uid, channel_id } = ctx.request.body;
+    async enterServer(ctx) {
+        let {uid, server_id, channel_id} = ctx.request.body;
 
-    let tag = channel_id || 1;
-    let data = [];
-    let isNewAccount = 1;
-    let enterServerList = await Server.getEnterServerListByUid(uid, channel_id);
-    let ip = getClientIp(ctx);
-    logger.info("getLastServerList 区服接口", { ip: ip });
-
-    // 获取渠道配置
-    const channelConfig = ChannelConfigManager.getConfig(tag);
-    if (!channelConfig) {
-      logger.info("未找到渠道配置:", { tag });
-      ctx.body = ApiController.fail("未知渠道id");
-      return;
-    }
+        let url = await getServerList(server_id, channel_id || 1);
+        if (!url) {
+            ctx.body = ApiController.fail(`区服id错误: serverId ${server_id}`, -1);
+            return;
+        }
 
-    if (enterServerList.length > 0) {
-      isNewAccount = 0;
-      // const servers = (await Server.getServerList(tag, 1))
-      const servers = await Server.getAllServerList(tag, ip);
-      enterServerList.forEach(function (element) {
-        data.push({
-          channel: channelConfig.name, //渠道固定
-          minSid: 1, //最小服务器
-          maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
-          isNewAccount: isNewAccount, //1为新号 会弹出用户协议
-          //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
-          sid: element.server_id || 1,
-          id: element.server_id || 1,
-          name: element.name || "1区",
-          tips: element.tips || "",
-          server: element.wss
-            ? element.wss
-            : `ws://${element.ip}:${element.port}`,
-          status: element.status || 0,
-        });
-      });
-      logger.info("getLastServerList 区服接口 enterServerList", {
-        enterServerList: enterServerList,
-      });
-    } else {
-      const servers = await Server.getAllServerList(tag, ip);
-
-      if (servers.length > 0) {
-        const serverInfo = servers[servers.length - 1];
-        logger.info("getLastServerList 区服接口 serverInfo", {
-          serverInfo: serverInfo,
-        });
-        data.push({
-          channel: channelConfig.name, //渠道固定
-          minSid: 1, //最小服务器
-          maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
-          isNewAccount: isNewAccount, //1为新号 会弹出用户协议
-          //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
-          sid: serverInfo.sid || 1,
-          id: serverInfo.id || 1,
-          name: serverInfo.name || "1区",
-          tips: serverInfo.tips || "",
-          server: serverInfo.server
-            ? serverInfo.server
-            : `ws://${serverInfo.ip}:${serverInfo.port}/`,
-          status: serverInfo.status || 0,
-        });
-      } else {
-        data.push({
-          channel: "未知", //渠道固定
-          minSid: 1, //最小服务器
-          maxSid: 10, //最大服务器 这里会控制 服务器列表显示的数量
-          isNewAccount: isNewAccount, //1为新号 会弹出用户协议
-          //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
-          sid: 1,
-          id: 1,
-          name: "1区",
-          tips: "",
-          server: "",
-          status: 0,
-        });
-      }
-    }
-    ctx.body = data;
-    // ctx.body = ApiController.success("获取最近服务器列表成功", 1, false, data);
-  }
+        logger.info("create params:", {params: ctx.request.body});
 
-  async getNotice(ctx) {
-    let tag = ctx.query.channel_id || 1;
+        if (!server_id || !uid) {
+            ctx.body = ApiController.fail("参数错误!!", -1);
+            return;
+        }
 
-    let content = "";
-    let content_wh = "";
-    const system = await System.getSystemConfig(tag);
+        const create_time = formatDate(new Date());
+        const serverInfo = (
+            await Server.checkEnterServerByUid(uid, server_id, channel_id)
+        )[0];
+        let res = null;
 
-    if (system) {
-      system.forEach((element) => {
-        if (element.key == "content") {
-          content = element.value;
+        if (serverInfo) {
+            res = await Server.updateEnterServer(serverInfo.id, create_time);
+        } else {
+            res = await Server.enterServer(uid, server_id, create_time, channel_id);
         }
 
-        if (element.key == "content_wh") {
-          content_wh = element.value;
+        if (res.affectedRows > 0) {
+            ctx.body = ApiController.success("请求成功", 0, true, "");
+        } else {
+            ctx.body = ApiController.fail("请求失败", -1, null, true);
         }
-      });
     }
 
-    let notice_data = [
-      {
-        status: 1,
-        content: content,
-        content_wh: content_wh,
-      },
-    ];
-    ctx.body = notice_data;
-    // ctx.body = ApiController.success("获取公告成功", 1, false, notice_data);
-  }
-
-  // 维护服务器,踢掉所有玩家
-  async maintenance(ctx) {
-    let data = {
-      channel_id: parseInt(ctx.query.channel_id),
-      serverId: parseInt(ctx.query.serverId) || "",
-    };
-
-    logger.info("maintenance :", { channelId: data.channel_id });
-
-    let url = await getServerList(data.serverId, data.channel_id || 1);
-    if (!url) {
-      ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
-      return;
-    }
-    let param = JSON.stringify({
-      type: "kickAllUser",
-    });
-    let sendMsg = new Msg();
-    sendMsg.connect(url, Account);
-    new Promise((resolve) => {
-      setTimeout(async () => {
-        sendMsg.CG_TEST_PROTO("test", param);
-      }, 1000);
-    });
-    ctx.body = ApiController.success("success", 0, false, null);
-  }
-
-  async maintenanceAll(ctx) {
-    let channelId = parseInt(ctx.query.channel_id);
-    let isMaintenance = ctx.query.isMaintenance;
-    let key = ctx.query.key;
-    logger.info("maintenanceAll :", {
-      channelId: channelId,
-      isMaintenance: isMaintenance,
-    });
-
-    if (key != "dsdadsadajkkjkxab") {
-      ctx.body = ApiController.fail("无权使用", -1);
-      return;
-    }
+    async getLastServerList(ctx) {
+        let {uid, channel_id} = ctx.request.body;
+        // uid是可选参数,如果不提供则只返回基本服务器信息
+
+        let tag = channel_id || 1;
+        let data = [];
+        let isNewAccount = 1;
+        let enterServerList = [];
+        let ip = getClientIp(ctx);
+        logger.info("getLastServerList 区服接口", {uid: uid, ip: ip});
+
+        // 获取渠道配置
+        const channelConfig = ChannelConfigManager.getConfig(tag);
+        if (!channelConfig) {
+            logger.info("未找到渠道配置:", {tag});
+            ctx.body = ApiController.fail("未知渠道id");
+            return;
+        }
 
-    const servers = await Server.getAllServerList(channelId, "");
-    logger.info("maintenanceAll servers:", { servers: servers });
+        // 如果提供了uid,查询用户进入过的服务器列表
+        if (uid) {
+            enterServerList = await Server.getEnterServerListByUid(uid, channel_id);
+        }
 
-    if (servers.length === 0) {
-      ctx.body = ApiController.fail("不存在可操作区服", -1);
-      return;
-    }
-    const serversId = servers.map((obj) => obj.id);
+        if (enterServerList.length > 0) {
+            isNewAccount = 0;
+            const servers = await Server.getAllServerList(tag, ip);
+            const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
+
+            // 为每个进入过的服务器添加角色信息
+            for (const element of enterServerList) {
+                let roleInfo = null;
+                // 只有在提供了uid时才查询角色信息
+                if (uid) {
+                    try {
+                        const newUniqueTag = `${tag}|${element.server_id}|${uid}`;
+                        roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, element.db_name);
+                    } catch (error) {
+                        logger.error(`查询服务器${element.server_id}角色信息失败:`, error);
+                    }
+                }
+
+                data.push({
+                    channel: channelConfig.name, //渠道固定
+                    minSid: 1, //最小服务器
+                    maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
+                    isNewAccount: isNewAccount, //1为新号 会弹出用户协议
+                    //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
+                    sid: element.server_id || 1,
+                    id: element.server_id || 1,
+                    name: element.name || "1区",
+                    tips: element.tips || "",
+                    server: element.wss
+                        ? element.wss
+                        : `ws://${element.ip}:${element.port}`,
+                    status: element.status || 0,
+                    // 角色信息(只有在提供了uid时才包含)
+                    roleName: roleInfo?.roleName || null,
+                    roleLevel: roleInfo?.roleLevel || null,
+                    head: roleInfo?.head || null,
+                    hasRole: !!roleInfo
+                });
 
-    if (isMaintenance == "true") {
-      const res = await Server.updateServerStatus(serversId, 3);
+            }
+            logger.info("getLastServerList 区服接口 enterServerList", {
+                enterServerList: enterServerList,
+            });
+        } else {
+            const servers = await Server.getAllServerList(tag, ip);
+            let roleInfo = null;
+
+            if (servers.length > 0) {
+                const serverInfo = servers[servers.length - 1];
+                logger.info("getLastServerList 区服接口 serverInfo", {
+                    serverInfo: serverInfo,
+                });
+
+                // 只有在提供了uid时才查询最后一个服务器的角色信息
+                if (uid) {
+                    const {getRoleInfoByUidAndServerId} = require("../mongo/mongodb");
+                    try {
+                        const newUniqueTag = `${serverInfo.tag}|${serverInfo.sid}|${uid}`;
+                        roleInfo = await getRoleInfoByUidAndServerId(newUniqueTag, serverInfo.db_name);
+                    } catch (error) {
+                        logger.error(`查询服务器${serverInfo.id}角色信息失败:`, error);
+                    }
+                }
+
+                data.push({
+                    channel: channelConfig.name, //渠道固定
+                    minSid: 1, //最小服务器
+                    maxSid: servers.length, //最大服务器 这里会控制 服务器列表显示的数量
+                    isNewAccount: isNewAccount, //1为新号 会弹出用户协议
+                    //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
+                    sid: serverInfo.sid || 1,
+                    id: serverInfo.id || 1,
+                    name: serverInfo.name || "1区",
+                    tips: serverInfo.tips || "",
+                    server: serverInfo.server
+                        ? serverInfo.server
+                        : `ws://${serverInfo.ip}:${serverInfo.port}/`,
+                    status: serverInfo.status || 0,
+                    // 角色信息
+                    roleName: roleInfo?.roleName || null,
+                    roleLevel: roleInfo?.roleLevel || null,
+                    head: roleInfo?.head || null,
+                    hasRole: !!roleInfo
+                });
+            } else {
+                data.push({
+                    channel: "未知", //渠道固定
+                    minSid: 1, //最小服务器
+                    maxSid: 10, //最大服务器 这里会控制 服务器列表显示的数量
+                    isNewAccount: isNewAccount, //1为新号 会弹出用户协议
+                    //以下是最近登陆的服务器 (不可为空 如果没有参数可以填最后一个区)
+                    sid: 1,
+                    id: 1,
+                    name: "1区",
+                    tips: "",
+                    server: "",
+                    status: 0,
+                    // 角色信息(新用户,无角色)
+                    roleName: null,
+                    roleLevel: null,
+                    head: null,
+                    hasRole: false
+                });
+            }
+        }
+        ctx.body = data;
+        // ctx.body = ApiController.success("获取最近服务器列表成功", 1, false, data);
     }
 
-    servers.forEach(function (element) {
-      let url = "ws://" + element.ip + ":" + element.port;
-      if (!url) {
-        ctx.body = ApiController.fail(`区服id错误: serverId ${element.id}`, 1);
-        return;
-      }
-
-      let param = JSON.stringify({
-        type: "kickAllUser",
-      });
-      // Msg.connect(url, Account);
-      let sendMsg = new Msg();
-      sendMsg.connect(url, Account);
-      new Promise((resolve) => {
-        setTimeout(async () => {
-          sendMsg.CG_TEST_PROTO("test", param);
-        }, 1000);
-      });
-    });
-
-    logger.info("maintenanceAll 更新的区服id:", { serversId: serversId });
-
-    ctx.body = ApiController.success("success", 0, false, null);
-  }
-
-  async sendMail(ctx) {
-    let data = ctx.request.body;
-    let url = await getServerList(data.serverId, data.channel_id || 1);
-    if (!url) {
-      ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
-      return;
-    }
-    let param = JSON.stringify({
-      type: "sendMail",
-      mail: JSON.stringify({
-        uuid: data.uuid,
-        title: data.title,
-        content: data.content,
-        items: JSON.parse(data.items),
-        expire: data.expire,
-      }),
-    });
-    // Msg.connect(url, Account);
-    let sendMsg = new Msg();
-    sendMsg.connect(url, Account);
-    new Promise((resolve) => {
-      setTimeout(async () => {
-        sendMsg.CG_TEST_PROTO("test", param);
-      }, 1000);
-    });
-    ctx.body = ApiController.success("success", 0, false, null);
-  }
-
-  async sendAllMail(ctx) {
-    let data = ctx.request.body;
+    async getNotice(ctx) {
+        let tag = ctx.query.channel_id || 1;
 
-    if (!data.server_list || data.server_list.length === 0) {
-      ctx.body = ApiController.fail("区服不能为空", -1);
-      return;
-    }
+        let content = "";
+        let content_wh = "";
+        const system = await System.getSystemConfig(tag);
 
-    logger.info("sendAllMail 接口请求 data:", { data: data });
+        if (system) {
+            system.forEach((element) => {
+                if (element.key == "content") {
+                    content = element.value;
+                }
 
-    const server_list = data.server_list;
-    const servers = await Server.getServerList(data.channel_id || 1);
-    const filteredServer = servers.filter((item) =>
-      server_list.includes(item.id)
-    );
+                if (element.key == "content_wh") {
+                    content_wh = element.value;
+                }
+            });
+        }
 
-    filteredServer.forEach(function (element) {
-      let url = "ws://" + element.ip + ":" + element.port;
-      if (!url) {
-        ctx.body = ApiController.fail(
-          `区服id错误: serverId ${element.server_id}`,
-          1
-        );
-        return;
-      }
-
-      let param = JSON.stringify({
-        type: "sendAllMail",
-        mail: JSON.stringify({
-          title: data.title,
-          content: data.content,
-          items: JSON.parse(data.items),
-          expire: data.expire,
-        }),
-      });
-      let sendMsg = new Msg();
-      sendMsg.connect(url, Account);
-      new Promise((resolve) => {
-        setTimeout(async () => {
-          sendMsg.CG_TEST_PROTO("test", param);
-        }, 1000);
-      });
-    });
-
-    ctx.body = ApiController.success("success", 0);
-  }
-
-  async useCDKV2(ctx) {
-    let body = ctx.request.body;
-
-    logger.info("useCDKV2接口请求参数:", { data: body });
-
-    let data = {
-      code: body.code,
-      userId: body.account,
-      channelId: body.channel_id || 0,
-    };
-
-    if (body.uuid) {
-      data.userId = body.uuid;
+        let notice_data = [
+            {
+                status: 1,
+                content: content,
+                content_wh: content_wh,
+            },
+        ];
+        ctx.body = notice_data;
+        // ctx.body = ApiController.success("获取公告成功", 1, false, notice_data);
     }
 
-    let serverUrl = await getServerList(body.serverId, body.channel_id);
-    let err = "";
-    if (!serverUrl) {
-      ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
-      return;
-    }
-    let port = 8004;
-    let host = "127.0.0.1";
-    let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
+    // 维护服务器,踢掉所有玩家
+    async maintenance(ctx) {
+        let data = {
+            channel_id: parseInt(ctx.query.channel_id),
+            serverId: parseInt(ctx.query.serverId) || "",
+        };
 
-    logger.info("接口请求后台 data:", { data: data, url: url });
+        logger.info("maintenance :", {channelId: data.channel_id});
 
-    try {
-      const specialCodes = [
-        "gfyx555",
-        "gfyx666",
-        "gfyx777",
-        "gfyx1000",
-        "gfyx2000",
-        "gfyx3000",
-        "gfyxrqlb",
-        "GFYX555",
-        "GFYX666",
-        "GFYX777",
-        "GFYX1000",
-        "GFYX2000",
-        "GFYX3000",
-        "GFYXrqlb",
-        "GFYX000",
-        "GFYX222",
-        "GFYX333",
-        "GFYX888",
-        "GFYX1818",
-      ];
-      let param: string = "";
-
-      const h5Codes = ["gfyx000", "gfyx222", "gfyx333", "gfyx888", "gfyx1818"];
-      if (h5Codes.includes(data.code) && body.channel_id != 5) {
-        ctx.body = ApiController.fail("该激活码无法在h5渠道使用", 1);
-      }
-
-      if (specialCodes.includes(data.code) || h5Codes.includes(data.code)) {
-        param = JSON.stringify({
-          code: data.code,
-          type: "UseFixCDK",
-          channel_id: body.channel_id,
+        let url = await getServerList(data.serverId, data.channel_id || 1);
+        if (!url) {
+            ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
+            return;
+        }
+        let param = JSON.stringify({
+            type: "kickAllUser",
         });
-      } else {
-        const response = await axios.post(url, data, {
-          headers: {
-            "Content-Type": "application/json",
-          },
-          timeout: 10000,
+        let sendMsg = new Msg();
+        sendMsg.connect(url, Account);
+        new Promise((resolve) => {
+            setTimeout(async () => {
+                sendMsg.CG_TEST_PROTO("test", param);
+            }, 1000);
         });
-        logger.info("接口请求后台 接口返回 response:", { data: response.data });
-        if (response.data.code != 200) {
-          ctx.body = ApiController.fail(response.data.msg, 1);
-          return;
+        ctx.body = ApiController.success("success", 0, false, null);
+    }
+
+    async maintenanceAll(ctx) {
+        let channelId = parseInt(ctx.query.channel_id);
+        let isMaintenance = ctx.query.isMaintenance;
+        let key = ctx.query.key;
+        logger.info("maintenanceAll :", {
+            channelId: channelId,
+            isMaintenance: isMaintenance,
+        });
+
+        if (key != "dsdadsadajkkjkxab") {
+            ctx.body = ApiController.fail("无权使用", -1);
+            return;
+        }
+
+        const servers = await Server.getAllServerList(channelId, "");
+        logger.info("maintenanceAll servers:", {servers: servers});
+
+        if (servers.length === 0) {
+            ctx.body = ApiController.fail("不存在可操作区服", -1);
+            return;
         }
-        const result = splitString(response.data.data, ";");
-        // 重构itemList
-        let itemList = Array();
-        for (let i = 0; i < result.length; i++) {
-          let elem = splitString(result[i], ":");
-          let output0 = parseInt(elem[0], 10);
-          let output1 = parseInt(elem[1], 10);
-          itemList.push([output0, output1]);
+        const serversId = servers.map((obj) => obj.id);
+
+        if (isMaintenance == "true") {
+            const res = await Server.updateServerStatus(serversId, 3);
         }
-        param = JSON.stringify({
-          type: "UseCDKV2",
-          itemList: itemList,
-          channel_id: body.channel_id,
+
+        servers.forEach(function (element) {
+            let url = "ws://" + element.ip + ":" + element.port;
+            if (!url) {
+                ctx.body = ApiController.fail(`区服id错误: serverId ${element.id}`, 1);
+                return;
+            }
+
+            let param = JSON.stringify({
+                type: "kickAllUser",
+            });
+            // Msg.connect(url, Account);
+            let sendMsg = new Msg();
+            sendMsg.connect(url, Account);
+            new Promise((resolve) => {
+                setTimeout(async () => {
+                    sendMsg.CG_TEST_PROTO("test", param);
+                }, 1000);
+            });
         });
-      }
-
-      let sendMsg = new Msg();
-      sendMsg.connect(serverUrl, Account);
-      logger.info("api cdk 发送服务器 param:", { param: param });
-      new Promise((resolve) => {
-        setTimeout(async () => {
-          sendMsg.CG_TEST_PROTO(body.account, param, body.serverId);
-        }, 1000);
-      });
-    } catch (error) {
-      console.log(error);
-    }
-    ctx.body = ApiController.success("success", 0);
-  }
 
-  async banUser(ctx) {
-    let data = ctx.request.body;
-    logger.info("banUser 接口请求 data:", { data: data });
+        logger.info("maintenanceAll 更新的区服id:", {serversId: serversId});
 
-    if (!data.server_tag) {
-      ctx.body = ApiController.fail("区服id不能为空", -1, "");
-      return;
+        ctx.body = ApiController.success("success", 0, false, null);
     }
 
-    let banInfo = {};
-
-    switch (parseInt(data.ban_type)) {
-      case 1:
-        banInfo = {
-          roleBanInfo: {
-            channelTag: data.channel_id,
-            serverTag: data.server_tag,
-            roleTag: data.role_tag,
-            banTime: data.ban_time,
-          },
-          type: "setBan",
-        };
-        break;
-      case 2:
-        banInfo = {
-          accountBanInfo: {
-            channelTag: data.channel_id,
-            accountTag: data.account_tag,
-            banTime: data.ban_time,
-          },
-          type: "setBan",
-        };
-        break;
-      case 3:
-        banInfo = {
-          appBanInfo: {
-            appId: data.device_id,
-            banTime: data.ban_time,
-          },
-          type: "setBan",
-        };
-        break;
-      default:
+    async sendMail(ctx) {
+        let data = ctx.request.body;
+        let url = await getServerList(data.serverId, data.channel_id || 1);
+        if (!url) {
+            ctx.body = ApiController.fail(`区服id错误: serverId ${data.serverId}`, 1);
+            return;
+        }
+        let param = JSON.stringify({
+            type: "sendMail",
+            mail: JSON.stringify({
+                uuid: data.uuid,
+                title: data.title,
+                content: data.content,
+                items: JSON.parse(data.items),
+                expire: data.expire,
+            }),
+        });
+        // Msg.connect(url, Account);
+        let sendMsg = new Msg();
+        sendMsg.connect(url, Account);
+        new Promise((resolve) => {
+            setTimeout(async () => {
+                sendMsg.CG_TEST_PROTO("test", param);
+            }, 1000);
+        });
+        ctx.body = ApiController.success("success", 0, false, null);
     }
 
-    logger.info("banUser 发送服务器 banInfo:", banInfo);
+    async sendAllMail(ctx) {
+        let data = ctx.request.body;
 
-    let url = await getServerList(data.server_tag, data.channel_id);
-    if (!url) {
-      ctx.body = ApiController.fail(
-        `区服id错误: serverId ${data.server_tag}`,
-        1
-      );
-      return;
-    }
+        if (!data.server_list || data.server_list.length === 0) {
+            ctx.body = ApiController.fail("区服不能为空", -1);
+            return;
+        }
 
-    let param = JSON.stringify(banInfo);
+        logger.info("sendAllMail 接口请求 data:", {data: data});
 
-    logger.info("banUser 发送服务器 json字符串: " + param);
+        const server_list = data.server_list;
+        const servers = await Server.getServerList(data.channel_id || 1);
+        const filteredServer = servers.filter((item) =>
+            server_list.includes(item.id)
+        );
 
-    let sendMsg = new Msg();
-    sendMsg.connect(url, Account);
-    new Promise((resolve) => {
-      setTimeout(async () => {
-        sendMsg.CG_TEST_PROTO("test", param, data.server_tag);
-        // sendMsg.CG_SET_BAN(param);
-      }, 1000);
-    });
-    ctx.body = ApiController.success("success", 0);
-  }
+        filteredServer.forEach(function (element) {
+            let url = "ws://" + element.ip + ":" + element.port;
+            if (!url) {
+                ctx.body = ApiController.fail(
+                    `区服id错误: serverId ${element.server_id}`,
+                    1
+                );
+                return;
+            }
 
-  async uicFilter4399(ctx) {
-    let body = ctx.request.body;
+            let param = JSON.stringify({
+                type: "sendAllMail",
+                mail: JSON.stringify({
+                    title: data.title,
+                    content: data.content,
+                    items: JSON.parse(data.items),
+                    expire: data.expire,
+                }),
+            });
+            let sendMsg = new Msg();
+            sendMsg.connect(url, Account);
+            new Promise((resolve) => {
+                setTimeout(async () => {
+                    sendMsg.CG_TEST_PROTO("test", param);
+                }, 1000);
+            });
+        });
 
-    let channelConfig = ChannelConfigManager.getConfig(6);
-    if (body.is_new == 1){
-        channelConfig = ChannelConfigManager.getConfig(999);
+        ctx.body = ApiController.success("success", 0);
     }
-    logger.info("uicFilter4399 body:", { data: body });
 
-    let toCheck = body.toCheck;
-    let signStr = channelConfig.loginConfig?.signKey + toCheck;
-    logger.info("uicFilter4399 signStr:", { signStr: signStr });
+    async useCDKV2(ctx) {
+        let body = ctx.request.body;
 
-    let apiParams = {
-      toCheck: toCheck,
-      app: channelConfig.loginConfig.appId,
-      byPinyin: true,
-      isBatch: false,
-      sig: CryptoJS.MD5(signStr).toString(),
-    };
+        logger.info("useCDKV2接口请求参数:", {data: body});
 
-    logger.info("uicFilter4399 apiParams:", { data: apiParams });
+        let data = {
+            code: body.code,
+            userId: body.account,
+            channelId: body.channel_id || 0,
+        };
 
-    const queryStr = Object.entries(apiParams)
-      .map(
-        ([key, value]) =>
-          `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
-      )
-      .join("&");
+        if (body.uuid) {
+            data.userId = body.uuid;
+        }
 
-    let url = "https://wo.webgame138.com/test/matchService.do" + "?" + queryStr;
-    // let url = "https://wo.webgame138.com/test/matchService.do";
-    logger.info("uicFilter4399 url:", { url: url });
+        let serverUrl = await getServerList(body.serverId, body.channel_id);
+        let err = "";
+        if (!serverUrl) {
+            ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
+            return;
+        }
+        let port = 8004;
+        let host = "127.0.0.1";
+        let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
+
+        logger.info("接口请求后台 data:", {data: data, url: url});
+
+        try {
+            const specialCodes = [
+                "gfyx555",
+                "gfyx666",
+                "gfyx777",
+                "gfyx1000",
+                "gfyx2000",
+                "gfyx3000",
+                "gfyxrqlb",
+                "GFYX555",
+                "GFYX666",
+                "GFYX777",
+                "GFYX1000",
+                "GFYX2000",
+                "GFYX3000",
+                "GFYXrqlb",
+                "GFYX000",
+                "GFYX222",
+                "GFYX333",
+                "GFYX888",
+                "GFYX1818",
+                "GQ888",
+                "ZQ888",
+                "gfyx8888",
+                "gfyx6666",
+                "gfyx7777",
+                "gfyxxjbc",
+                "LIDONGLB",
+                "XIAOXULB",
+                "GANENLB",
+                "WANSHLB",
+                "HERO666",
+                "HERO777",
+                "HERO888",
+                "gfyx9999",
+                "aiqi6666",
+                "aiqi7777",
+                "aiqi8888",
+                "aiqi9999",
+            ];
+            let param: string = "";
+
+            const h5Codes = ["gfyx000", "gfyx222", "gfyx333", "gfyx888", "gfyx1818"];
+            if (h5Codes.includes(data.code) && body.channel_id != 5) {
+                ctx.body = ApiController.fail("该激活码无法在h5渠道使用", 1);
+            }
 
-    try {
-      //   let response = await axios.get(url, {
-      //     timeout: 10000, // 设置10秒超时
-      //   });
-
-      const response = await axios.post(url, apiParams, {
-        headers: {
-          "Content-Type": "application/json",
-        },
-      });
-      logger.info("uicFilter4399 接口返回 response:", { data: response.data });
-
-      ctx.body = ApiController.success("success", 0, false, response.data);
-    } catch (error) {
-      console.log(error);
-      ctx.body = ApiController.fail(error.message || "请求失败", 1);
+            if (specialCodes.includes(data.code) || h5Codes.includes(data.code)) {
+                param = JSON.stringify({
+                    code: data.code,
+                    type: "UseFixCDK",
+                    channel_id: body.channel_id,
+                });
+            } else {
+                const response = await axios.post(url, data, {
+                    headers: {
+                        "Content-Type": "application/json",
+                    },
+                    timeout: 10000,
+                });
+                logger.info("接口请求后台 接口返回 response:", {data: response.data});
+                if (response.data.code != 200) {
+                    ctx.body = ApiController.fail(response.data.msg, 1);
+                    return;
+                }
+                const result = splitString(response.data.data, ";");
+                // 重构itemList
+                let itemList = Array();
+                for (let i = 0; i < result.length; i++) {
+                    let elem = splitString(result[i], ":");
+                    let output0 = parseInt(elem[0], 10);
+                    let output1 = parseInt(elem[1], 10);
+                    itemList.push([output0, output1]);
+                }
+                param = JSON.stringify({
+                    type: "UseCDKV2",
+                    itemList: itemList,
+                    channel_id: body.channel_id,
+                });
+            }
+
+            let sendMsg = new Msg();
+            sendMsg.connect(serverUrl, Account);
+            logger.info("api cdk 发送服务器 param:", {param: param});
+            new Promise((resolve) => {
+                setTimeout(async () => {
+                    sendMsg.CG_TEST_PROTO(body.account, param, body.serverId);
+                }, 1000);
+            });
+        } catch (error) {
+            console.log(error);
+        }
+        ctx.body = ApiController.success("success", 0);
     }
-  }
 
-  async roleList4399(ctx) {
-    let body = ctx.request.body;
-    logger.info("RoleList4399 请求参数:", { body: body });
+    async banUser(ctx) {
+        let data = ctx.request.body;
+        logger.info("banUser 接口请求 data:", {data: data});
 
-    let data = {
-      userId: body.userId,
-      server: body.server,
-      is_new: ctx.query.is_new || 0
-    };
+        if (!data.server_tag) {
+            ctx.body = ApiController.fail("区服id不能为空", -1, "");
+            return;
+        }
 
-    let port = 8004;
-    let host = "127.0.0.1";
-    let url = "http://" + host + ":" + port + "/api/roleList/checkBy4399";
+        let banInfo = {};
+
+        switch (parseInt(data.ban_type)) {
+            case 1:
+                banInfo = {
+                    roleBanInfo: {
+                        channelTag: data.channel_id,
+                        serverTag: data.server_tag,
+                        roleTag: data.role_tag,
+                        banTime: data.ban_time,
+                    },
+                    type: "setBan",
+                };
+                break;
+            case 2:
+                banInfo = {
+                    accountBanInfo: {
+                        channelTag: data.channel_id,
+                        accountTag: data.account_tag,
+                        banTime: data.ban_time,
+                    },
+                    type: "setBan",
+                };
+                break;
+            case 3:
+                banInfo = {
+                    appBanInfo: {
+                        appId: data.device_id,
+                        banTime: data.ban_time,
+                    },
+                    type: "setBan",
+                };
+                break;
+            default:
+        }
 
-    logger.info("RoleList4399 url:", { url: url });
+        logger.info("banUser 发送服务器 banInfo:", banInfo);
 
-    try {
-      const response = await axios.post(url, data, {
-        headers: {
-          "Content-Type": "application/json",
-        },
-      });
+        let url = await getServerList(data.server_tag, data.channel_id);
+        if (!url) {
+            ctx.body = ApiController.fail(
+                `区服id错误: serverId ${data.server_tag}`,
+                1
+            );
+            return;
+        }
 
-      logger.info("RoleList4399 返回 response:", { data: response.data });
+        let param = JSON.stringify(banInfo);
 
-      ctx.body = response.data;
-    } catch (error) {
-      console.log(error);
-    }
-  }
+        logger.info("banUser 发送服务器 json字符串: " + param);
 
-  async cdkBy4399(ctx) {
-    let body = ctx.request.body;
+        let sendMsg = new Msg();
+        sendMsg.connect(url, Account);
+        new Promise((resolve) => {
+            setTimeout(async () => {
+                sendMsg.CG_TEST_PROTO("test", param, data.server_tag);
+                // sendMsg.CG_SET_BAN(param);
+            }, 1000);
+        });
+        ctx.body = ApiController.success("success", 0);
+    }
 
-    logger.info("cdkBy4399:", { data: body });
-    let server = body.server || 1;
-    let channel = 5;
+    async uicFilter4399(ctx) {
+        let body = ctx.request.body;
 
-    let data = {
-      code: body.giftId,
-      userId: body.userId,
-      channelId: channel,
-    };
+        let channelConfig = ChannelConfigManager.getConfig(6);
+        if (body.is_new == 1) {
+            channelConfig = ChannelConfigManager.getConfig(999);
+        }
+        logger.info("uicFilter4399 body:", {data: body});
+
+        let toCheck = body.toCheck;
+        let signStr = channelConfig.loginConfig?.signKey + toCheck;
+        logger.info("uicFilter4399 signStr:", {signStr: signStr});
+
+        let apiParams = {
+            toCheck: toCheck,
+            app: channelConfig.loginConfig.appId,
+            byPinyin: true,
+            isBatch: false,
+            sig: CryptoJS.MD5(signStr).toString(),
+        };
 
-    if (body.uuid) {
-      data.userId = body.uuid;
+        logger.info("uicFilter4399 apiParams:", {data: apiParams});
+
+        const queryStr = Object.entries(apiParams)
+            .map(
+                ([key, value]) =>
+                    `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
+            )
+            .join("&");
+
+        let url = "https://wo.webgame138.com/test/matchService.do" + "?" + queryStr;
+        // let url = "https://wo.webgame138.com/test/matchService.do";
+        logger.info("uicFilter4399 url:", {url: url});
+
+        try {
+            //   let response = await axios.get(url, {
+            //     timeout: 10000, // 设置10秒超时
+            //   });
+
+            const response = await axios.post(url, apiParams, {
+                headers: {
+                    "Content-Type": "application/json",
+                },
+            });
+            logger.info("uicFilter4399 接口返回 response:", {data: response.data});
+
+            ctx.body = ApiController.success("success", 0, false, response.data);
+        } catch (error) {
+            console.log(error);
+            ctx.body = ApiController.fail(error.message || "请求失败", 1);
+        }
     }
 
-    let serverUrl = await getServerList(server, channel);
-    let err = "";
-    if (!serverUrl) {
-      ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
-      return;
-    }
-    let port = 8004;
-    let host = "127.0.0.1";
-    let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
+    async roleList4399(ctx) {
+        let body = ctx.request.body;
+        logger.info("RoleList4399 请求参数:", {body: body});
 
-    logger.info("cdkBy4399接口请求后台 data:", { data: data, url: url });
+        let data = {
+            userId: body.userId,
+            server: body.server,
+            is_new: ctx.query.is_new || 0
+        };
 
-    try {
-      const response = await axios.post(url, data, {
-        headers: {
-          "Content-Type": "application/json",
-        },
-        timeout: 10000,
-      });
-      logger.info("cdkBy4399接口请求后台 接口返回 response:", {
-        data: response.data,
-      });
-      if (response.data.code != 200) {
-        ctx.body = ApiController.fail(response.data.msg, 10004);
-        return;
-      }
-      const result = splitString(response.data.data, ";");
-      // 重构itemList
-      let itemList = Array();
-      for (let i = 0; i < result.length; i++) {
-        let elem = splitString(result[i], ":");
-        let output0 = parseInt(elem[0], 10);
-        let output1 = parseInt(elem[1], 10);
-        itemList.push([output0, output1]);
-      }
-      let param = JSON.stringify({
-        type: "UseCDKV2",
-        itemList: itemList,
-        channel_id: channel,
-      });
-
-      let sendMsg = new Msg();
-      sendMsg.connect(serverUrl, Account);
-      logger.info("cdkBy4399 cdk 发送服务器 param:", { param: param });
-      new Promise((resolve) => {
-        setTimeout(async () => {
-          sendMsg.CG_TEST_PROTO("test", param, server);
-        }, 1000);
-      });
-    } catch (error) {
-      console.log(error);
+        let port = 8004;
+        let host = "127.0.0.1";
+        let url = "http://" + host + ":" + port + "/api/roleList/checkBy4399";
+
+        logger.info("RoleList4399 url:", {url: url});
+
+        try {
+            const response = await axios.post(url, data, {
+                headers: {
+                    "Content-Type": "application/json",
+                },
+            });
+
+            logger.info("RoleList4399 返回 response:", {data: response.data});
+
+            ctx.body = response.data;
+        } catch (error) {
+            console.log(error);
+        }
     }
-    ctx.body = ApiController.success("success", 10000);
-  }
-
-  async roleListYfy(ctx) {
-    let gameCode = ctx.query.gameCode;
-    let timestamp = ctx.query.timestamp;
-    let uid = ctx.query.uid;
-    let sign = ctx.query.sign;
-    let AppSecret = "H1EqhbpA80jt0Jw6Q3T2";
-
-    logger.info("roleListYfy 请求参数:", {
-      uid: uid,
-      gameCode: gameCode,
-      timestamp: timestamp,
-    });
-
-    const signStr = `gameCode-${gameCode}&timestamp=${timestamp}&uid=${uid}${AppSecret}`;
-    const newSign = CryptoJS.MD5(signStr).toString();
-    if (newSign != sign) {
-      logger.info("roleListYfy 签名错误:", {
-        signStr: signStr,
-        sign: sign,
-        newSign: newSign,
-      });
-      ctx.body = ApiController.fail("签名错误!!", -1);
+
+    async cdkBy4399(ctx) {
+        let body = ctx.request.body;
+
+        logger.info("cdkBy4399:", {data: body});
+        let server = body.server || 1;
+        let channel = 5;
+
+        let data = {
+            code: body.giftId,
+            userId: body.userId,
+            channelId: channel,
+        };
+
+        if (body.uuid) {
+            data.userId = body.uuid;
+        }
+
+        let serverUrl = await getServerList(server, channel);
+        let err = "";
+        if (!serverUrl) {
+            ctx.body = ApiController.fail(`区服id错误: serverId ${body.serverId}`, 1);
+            return;
+        }
+        let port = 8004;
+        let host = "127.0.0.1";
+        let url = "http://" + host + ":" + port + "/api/giftCode/exchange";
+
+        logger.info("cdkBy4399接口请求后台 data:", {data: data, url: url});
+
+        try {
+            const response = await axios.post(url, data, {
+                headers: {
+                    "Content-Type": "application/json",
+                },
+                timeout: 10000,
+            });
+            logger.info("cdkBy4399接口请求后台 接口返回 response:", {
+                data: response.data,
+            });
+            if (response.data.code != 200) {
+                ctx.body = ApiController.fail(response.data.msg, 10004);
+                return;
+            }
+            const result = splitString(response.data.data, ";");
+            // 重构itemList
+            let itemList = Array();
+            for (let i = 0; i < result.length; i++) {
+                let elem = splitString(result[i], ":");
+                let output0 = parseInt(elem[0], 10);
+                let output1 = parseInt(elem[1], 10);
+                itemList.push([output0, output1]);
+            }
+            let param = JSON.stringify({
+                type: "UseCDKV2",
+                itemList: itemList,
+                channel_id: channel,
+            });
+
+            let sendMsg = new Msg();
+            sendMsg.connect(serverUrl, Account);
+            logger.info("cdkBy4399 cdk 发送服务器 param:", {param: param});
+            new Promise((resolve) => {
+                setTimeout(async () => {
+                    sendMsg.CG_TEST_PROTO("test", param, server);
+                }, 1000);
+            });
+        } catch (error) {
+            console.log(error);
+        }
+        ctx.body = ApiController.success("success", 10000);
     }
 
-    let port = 8004;
-    let host = "127.0.0.1";
-    let url = "http://" + host + ":" + port + "/api/roleList/checkByYfy";
+    async roleListYfy(ctx) {
+        let gameCode = ctx.query.gameCode;
+        let timestamp = ctx.query.timestamp;
+        let uid = ctx.query.uid;
+        let sign = ctx.query.sign;
+        let AppSecret = "H1EqhbpA80jt0Jw6Q3T2";
+
+        logger.info("roleListYfy 请求参数:", {
+            uid: uid,
+            gameCode: gameCode,
+            timestamp: timestamp,
+        });
 
-    logger.info("roleListYfy url:", { url: url });
+        const signStr = `gameCode-${gameCode}&timestamp=${timestamp}&uid=${uid}${AppSecret}`;
+        const newSign = CryptoJS.MD5(signStr).toString();
+        if (newSign != sign) {
+            logger.info("roleListYfy 签名错误:", {
+                signStr: signStr,
+                sign: sign,
+                newSign: newSign,
+            });
+            ctx.body = ApiController.fail("签名错误!!", -1);
+        }
 
-    try {
-      const response = await axios.post(
-        url,
-        {
-          userId: uid,
-        },
-        {
-          headers: {
-            "Content-Type": "application/json",
-          },
+        let port = 8004;
+        let host = "127.0.0.1";
+        let url = "http://" + host + ":" + port + "/api/roleList/checkByYfy";
+
+        logger.info("roleListYfy url:", {url: url});
+
+        try {
+            const response = await axios.post(
+                url,
+                {
+                    userId: uid,
+                },
+                {
+                    headers: {
+                        "Content-Type": "application/json",
+                    },
+                }
+            );
+
+            logger.info("roleListYfy 返回 response:", {data: response.data});
+
+            ctx.body = response.data;
+        } catch (error) {
+            console.log(error);
         }
-      );
+    }
 
-      logger.info("roleListYfy 返回 response:", { data: response.data });
+    async getQuickSign(ctx) {
+        let data = ctx.request.body;
+        logger.info("getQuickSign 请求参数:", {body: data});
 
-      ctx.body = response.data;
-    } catch (error) {
-      console.log(error);
+        if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
+            logger.error("签名验证失败");
+            ctx.body = ApiController.fail("签名错误!!", -1);
+            return;
+        }
+
+        let key = "H1EqhbpA80jt0Jw6Q3T2";
+        let signStr =
+            "uid=" +
+            data.uid +
+            "&username=" +
+            data.username +
+            "&serverId=" +
+            data.serverId +
+            "&serverName=" +
+            data.serverName +
+            "&userRoleId=" +
+            data.userRoleId +
+            "&userRoleName=" +
+            data.userRoleName +
+            "&userRoleLevel=" +
+            data.userRoleLevel +
+            "&vipLevel=" +
+            data.vipLevel +
+            "&gameRolePower=" +
+            data.gameRolePower +
+            "&key=" +
+            key;
+        logger.info("getQuickSign signStr:", {signStr: signStr});
+
+        data.sign = CryptoJS.MD5(signStr).toString();
+
+        ctx.body = ApiController.success("success", 0, false, data);
     }
-  }
 
-  async getQuickSign(ctx) {
-    let data = ctx.request.body;
-    logger.info("getQuickSign 请求参数:", { body: data });
+    /**
+     * mianyou开服同步处理
+     * @param ctx Koa上下文
+     */
+    async mianyouSyncServer(ctx) {
+        try {
+            const data = ctx.request.body;
+            logger.info("mianyou开服同步请求参数:", {data});
+
+            // 验证必要参数
+            const {serverId, gameServerId, serverName, startTime, channelId} = data;
+            
+            if (!serverId || !gameServerId || !serverName || !startTime) {
+                logger.warn("mianyou开服同步失败: 缺少必要参数", {data});
+                ctx.body = ApiController.fail("缺少必要参数: serverId, gameServerId, serverName, startTime");
+                return;
+            }
 
-    if (!SignatureVerifier.verifyMD5Sign(data, ORDER_SIGN_KEY)) {
-      logger.error("签名验证失败");
-      ctx.body = ApiController.fail("签名错误!!", -1);
-      return;
+            // 获取渠道配置
+            const channelConfig = ChannelConfigManager.getConfig(channelId || 1);
+            if (!channelConfig) {
+                logger.error("mianyou开服同步失败: 未找到渠道配置", {channelId});
+                ctx.body = ApiController.fail("未找到渠道配置");
+                return;
+            }
+
+            // 创建MianyouChannelHandler实例
+            const mianyouHandler = new MianyouChannelHandler();
+
+            // 调用开服同步方法
+            const result = await mianyouHandler.openServer(
+                parseInt(serverId),
+                gameServerId,
+                serverName,
+                startTime,
+                channelConfig
+            );
+
+            logger.info("mianyou开服同步结果:", {result});
+
+            // 根据返回结果设置响应
+            if (result.status === 0) {
+                ctx.body = ApiController.success("开服同步成功", 0, false, result);
+            } else {
+                ctx.body = ApiController.fail(result.msg || "开服同步失败", result.status);
+            }
+
+        } catch (error) {
+            logger.error("mianyou开服同步异常:", error);
+            ctx.body = ApiController.fail("服务器内部错误", -1);
+        }
     }
 
-    let key = "H1EqhbpA80jt0Jw6Q3T2";
-    let signStr =
-      "uid=" +
-      data.uid +
-      "&username=" +
-      data.username +
-      "&serverId=" +
-      data.serverId +
-      "&serverName=" +
-      data.serverName +
-      "&userRoleId=" +
-      data.userRoleId +
-      "&userRoleName=" +
-      data.userRoleName +
-      "&userRoleLevel=" +
-      data.userRoleLevel +
-      "&vipLevel=" +
-      data.vipLevel +
-      "&gameRolePower=" +
-      data.gameRolePower +
-      "&key=" +
-      key;
-    logger.info("getQuickSign signStr:", { signStr: signStr });
-
-    data.sign = CryptoJS.MD5(signStr).toString();
-
-    ctx.body = ApiController.success("success", 0, false, data);
-  }
+
 }
 
 module.exports = new ApiController();

+ 489 - 0
webServer/src/controller/MiniAppController.ts

@@ -0,0 +1,489 @@
+import { Context } from "koa";
+import { getRoleInfoById,getGuildInfoById } from "../mongo/mongodb";
+import { getServerList } from "../utils/common";
+import axios from "axios";
+
+const logger = require("../utils/log");
+
+// 导入小程序配置
+import {
+  MINI_APP_DOMAIN,
+  MINI_APP_PRIVATE_KEY,
+  MINI_APP_GAME_ID,
+  MINI_APP_API_KEY,
+  MINI_APP_STAT_API_KEY, Account
+} from "../config/thirdParams";
+
+// 导入渠道处理器和配置
+import { channelFactory } from "../channels/factory/ChannelFactory";
+import { channelConfigs } from "../config/channelConfig";
+import Msg from "../utils/msg";
+
+/**
+ * 小程序控制器
+ * 处理内容安全审核和角色名称修改上报功能
+ */
+class MiniappController {
+  constructor() {
+    // 初始化配置
+  }
+
+  /**
+   * 获取小程序渠道处理器
+   * @returns 渠道处理器实例
+   */
+  private static getChannelHandler() {
+    return channelFactory.getHandler(11); // 小程序渠道ID
+  }
+
+  /**
+   * 获取小程序渠道配置
+   * @returns 渠道配置
+   */
+  private static getChannelConfig() {
+    return channelConfigs[11]; // 小程序渠道ID
+  }
+
+  /**
+   * 内容安全审核接口
+   * @param ctx Koa上下文
+   */
+  async contentSecurityCheck(ctx: Context) {
+    try {
+      const handler = MiniappController.getChannelHandler();
+      const config = MiniappController.getChannelConfig();
+      
+      if (!handler) {
+        ctx.body = {
+          code: -1,
+          msg: "渠道处理器未找到",
+          data: null
+        };
+        return;
+      }
+
+      // 调用渠道处理器的内容安全审核方法
+      const result = await (handler as any).contentSecurityCheck(ctx, config);
+      ctx.body = result;
+
+    } catch (error) {
+      logger.error("内容安全审核出错:", error);
+      ctx.body = {
+        code: -1,
+        msg: "内容安全审核失败",
+        data: null
+      };
+    }
+  }
+
+  /**
+   * 角色名称修改上报
+   * @param ctx Koa上下文
+   */
+  async editUserRoleInfo(ctx: Context) {
+    try {
+      const handler = MiniappController.getChannelHandler();
+      const config = MiniappController.getChannelConfig();
+      
+      if (!handler) {
+        ctx.body = {
+          error: -1,
+          errmsg: "渠道处理器未找到"
+        };
+        return;
+      }
+
+      // 调用渠道处理器的角色名称修改上报方法
+      const result = await (handler as any).editUserRoleInfo(ctx, config);
+      ctx.body = result;
+
+    } catch (error) {
+      logger.error("角色名称修改上报出错:", error);
+      ctx.body = {
+        error: -1,
+        errmsg: "角色信息修改失败"
+      };
+    }
+  }
+
+  /**
+   * 禁言接口
+   * @param ctx Koa上下文
+   */
+  async forbidChat(ctx: Context) {
+    try {
+      const data = ctx.request.body as any;
+      logger.info("禁言接口请求参数:", data);
+
+      // 验证必要参数
+      const requiredParams = ['gameid', 'openid', 'accountid', 'roleid', 'forbidDays', 'reason', 'time', 'sign'];
+      for (const param of requiredParams) {
+        if (!data[param]) {
+          logger.error(`缺少必要参数: ${param}`);
+          ctx.body = {
+            error: -1,
+            errmsg: `缺少必要参数: ${param}`
+          };
+          return;
+        }
+      }
+
+      const handler = MiniappController.getChannelHandler();
+      const expectedSignature = (handler as any).generateCommonSignature(
+        data, 
+        MINI_APP_STAT_API_KEY, 
+        ['sign'],
+        false // 禁言接口签名不需要URL编码
+      );
+      // 验证签名
+      if (expectedSignature !== data.sign) {
+        logger.error("禁言接口签名验证失败");
+        ctx.body = {
+          error: -1,
+          errmsg: "签名验证失败"
+        };
+        return;
+      }
+
+      // 验证禁言天数
+      const forbidDays = parseInt(data.forbidDays);
+      if (forbidDays < -1 || forbidDays === 0 || forbidDays > 30) {
+        logger.error("禁言天数参数错误:", forbidDays);
+        ctx.body = {
+          error: -1,
+          errmsg: "禁言天数参数错误,应为1-30天或-1(永久)"
+        };
+        return;
+      }
+
+      // 调用游戏服禁言接口
+      const gameResult = await MiniappController.callGameForbidChat(data);
+      
+      if (gameResult) {
+        ctx.body = {
+          error: 0,
+          errmsg: ""
+        };
+      } else {
+        ctx.body = {
+          error: -1,
+          errmsg: "禁言失败"
+        };
+      }
+
+    } catch (error) {
+      logger.error("禁言接口出错:", error);
+      ctx.body = {
+        error: -1,
+        errmsg: "禁言失败"
+      };
+    }
+  }
+
+
+  /**
+   * 解除禁言接口
+   * @param ctx Koa上下文
+   */
+  async freeChat(ctx: Context) {
+    try {
+      const data = ctx.request.body as any;
+      logger.info("解除禁言接口请求参数:", data);
+
+      // 验证必要参数
+      const requiredParams = ['gameid', 'openid', 'accountid', 'roleid', 'time', 'sign'];
+      for (const param of requiredParams) {
+        if (!data[param]) {
+          logger.error(`缺少必要参数: ${param}`);
+          ctx.body = {
+            error: -1,
+            errmsg: `缺少必要参数: ${param}`
+          };
+          return;
+        }
+      }
+
+      const handler = MiniappController.getChannelHandler();
+      const expectedSignature = (handler as any).generateCommonSignature(
+        data, 
+        MINI_APP_STAT_API_KEY, 
+        ['sign'],
+        false // 解除禁言接口签名不需要URL编码
+      );
+      
+      // 验证签名
+      if (expectedSignature !== data.sign) {
+        logger.error("解除禁言接口签名验证失败");
+        ctx.body = {
+          error: -1,
+          errmsg: "签名验证失败"
+        };
+        return;
+      }
+
+      // 调用游戏服解除禁言接口
+      const gameResult = await MiniappController.callGameFreeChat(data);
+      
+      if (gameResult) {
+        ctx.body = {
+          error: 0,
+          errmsg: ""
+        };
+      } else {
+        ctx.body = {
+          error: -1,
+          errmsg: "解除禁言失败"
+        };
+      }
+
+    } catch (error) {
+      logger.error("解除禁言接口出错:", error);
+      ctx.body = {
+        error: -1,
+        errmsg: "解除禁言失败"
+      };
+    }
+  }
+
+  /**
+   * 角色查询接口
+   * @param ctx Koa上下文
+   */
+  async roleQuery(ctx: Context) {
+    try {
+      const data = ctx.request.body as any;
+      logger.info("角色查询接口请求参数:", data);
+
+      // 验证必要参数
+      const requiredParams = ['gameid', 'serverid', 'openid', 'accountid', 'roleid', 'time', 'sign'];
+      for (const param of requiredParams) {
+        if (!data[param]) {
+          logger.error(`缺少必要参数: ${param}`);
+          ctx.body = {
+            error: -1,
+            errmsg: `缺少必要参数: ${param}`
+          };
+          return;
+        }
+      }
+
+      const handler = MiniappController.getChannelHandler();
+      const expectedSignature = (handler as any).generateCommonSignature(
+        data, 
+        MINI_APP_STAT_API_KEY, 
+        ['sign'],
+        false // 角色查询接口签名不需要URL编码
+      );
+      
+      // 验证签名
+      if (expectedSignature !== data.sign) {
+        logger.error("角色查询接口签名验证失败");
+        ctx.body = {
+          error: -1,
+          errmsg: "签名验证失败"
+        };
+        return;
+      }
+
+      // 调用游戏服角色查询接口
+      const roleData = await MiniappController.callGameRoleQuery(data);
+      
+      if (roleData) {
+        ctx.body = {
+          error: 0,
+          errmsg: "",
+          role: roleData
+        };
+      } else {
+        ctx.body = {
+          error: -1,
+          errmsg: "角色查询失败"
+        };
+      }
+
+    } catch (error) {
+      logger.error("角色查询接口出错:", error);
+      ctx.body = {
+        error: -1,
+        errmsg: "角色查询失败"
+      };
+    }
+  }
+
+  /**
+   * 调用游戏服禁言接口
+   * @param data 禁言数据
+   * @returns 调用结果
+   */
+  private static callGameForbidChat(data: any): boolean {
+    try {
+      logger.info("调用游戏服禁言接口:", {
+        gameid: data.gameid,
+        openid: data.openid,
+        accountid: data.accountid,
+        roleid: data.roleid,
+        forbidDays: data.forbidDays,
+        reason: data.reason,
+        ext: data.ext
+      });
+
+      let url = getServerList(data.serverId, data.channel_id || 1);
+      if (!url) {
+        logger.error("区服id错误,无法获取游戏服地址:", data.serverId);
+        return;
+      }
+      //调用游戏服禁言接口
+      let param = JSON.stringify({
+        uuid: data.roleid,
+        type: "forbidChat",
+        time: data.forbidDays,
+        reason: data.reason
+      });
+      let sendMsg = new Msg();
+      sendMsg.connect(url, Account);
+      new Promise((resolve) => {
+        setTimeout(async () => {
+          sendMsg.CG_TEST_PROTO(data.accountid, param);
+        }, 1000);
+      });
+      return true
+
+    } catch (error) {
+      logger.error("调用游戏服禁言接口出错:", error);
+      return false
+    }
+  }
+
+  /**
+   * 调用游戏服解除禁言接口
+   * @param data 解除禁言数据
+   * @returns 调用结果
+   */
+  private static callGameFreeChat(data: any): boolean {
+    try {
+      
+      logger.info("调用游戏服解除禁言接口:", {
+        gameid: data.gameid,
+        openid: data.openid,
+        accountid: data.accountid,
+        roleid: data.roleid,
+        ext: data.ext
+      });
+      let url = getServerList(data.serverId, data.channel_id || 1);
+      if (!url) {
+        logger.error("区服id错误,无法获取游戏服地址:", data.serverId);
+        return;
+      }
+      //调用游戏服禁言接口
+      let param = JSON.stringify({
+        uuid: data.roleid,
+        type: "freeChat",
+      });
+      let sendMsg = new Msg();
+      sendMsg.connect(url, Account);
+      new Promise((resolve) => {
+        setTimeout(async () => {
+          sendMsg.CG_TEST_PROTO(data.accountid, param);
+        }, 1000);
+      });
+      return true
+
+    } catch (error) {
+      logger.error("调用游戏服解除禁言接口出错:", error);
+      return false
+    }
+  }
+
+  /**
+   * 调用游戏服角色查询接口
+   * @param data 角色查询数据
+   * @returns 角色数据
+   */
+  private static async callGameRoleQuery(data: any): Promise<any> {
+    try {
+      
+     logger.info("调用游戏服角色查询接口:", {
+        gameid: data.gameid,
+        serverid: data.serverid,
+        openid: data.openid,
+        accountid: data.accountid,
+        roleid: data.roleid,
+        ext: data.ext
+      });
+       
+      // 根据服务器ID生成数据库名称
+      let dbName = "ckwy_fy_S"+(String(350001+parseInt(data.serverid)).padStart(3,'0'));
+      
+      // 从MongoDB查询角色信息
+      const roleInfo = await getRoleInfoById(dbName, data.roleid);
+      
+      if (roleInfo) {
+        // 如果找到角色信息,返回格式化的数据
+        const data =  {
+          rolename: roleInfo.name || "未知角色",
+          rolelv: roleInfo.lv || 1,
+          rolepwr: roleInfo.rolepwr || 0, //战力
+          viplv: roleInfo.viplv || 0, //vip等级
+          alliance: roleInfo.alliance || "", //帮派
+          paymoney: roleInfo.topupAcount || 0 //累计充值金额
+        };
+        if(roleInfo.guildId){
+        const guildInfo = await getGuildInfoById(dbName, roleInfo.guildId);
+        if (guildInfo) {
+            data.alliance = guildInfo.name;
+          }
+        }
+        return data;
+
+      } else {
+        // 如果没有找到角色信息,返回默认数据
+        logger.warn(`未找到角色信息: ${data.roleid}`);
+        return {
+          rolename: "未知角色",
+          rolelv: 1,
+          rolepwr: 0,
+          viplv: 0,
+          alliance: "",
+          paymoney: 0
+        };
+      }
+
+    } catch (error) {
+      logger.error("调用游戏服角色查询接口出错:", error);
+      return null;
+    }
+  }
+
+  /**
+   * 订单校验接口
+   * @param ctx Koa上下文
+   */
+  async verifyOrder(ctx: Context) {
+    try {
+      const handler = MiniappController.getChannelHandler();
+      const config = MiniappController.getChannelConfig();
+      
+      if (!handler) {
+        ctx.body = {
+          success: false,
+          message: "渠道处理器未找到"
+        };
+        return;
+      }
+
+      // 调用渠道处理器的订单校验方法
+      const result = await (handler as any).verifyOrder(ctx, config);
+      ctx.body = result;
+
+    } catch (error) {
+      logger.error("订单校验出错:", error);
+      ctx.body = {
+        success: false,
+        message: "订单校验失败"
+      };
+    }
+  }
+  
+}
+
+module.exports = new MiniappController();

+ 6 - 2
webServer/src/model/ServerModel.ts

@@ -19,7 +19,7 @@ class ServerModel {
     return await query(`SELECT *  FROM game_enter_server WHERE  id = ? `, [id]);
   }
   async getAllServerList(tag: any = 1, ip: string) {
-    const rows = await query(`SELECT * FROM game_server WHERE tag = ? and is_show = 1`, [tag]);
+    const rows = await query(`SELECT * FROM game_server WHERE tag = ? and is_show = 1` , [tag]);
     const resultArray = (rows as any[]).map((row) => {
       let status = row.status;
       if ((status == 0 || status == 3) && row.white_list) {
@@ -48,6 +48,8 @@ class ServerModel {
         tips: row.tips,
         ip: row.ip,
         port: row.port,
+        db_name: row.db_name,
+        tag:row.tag,
       };
     });
     return resultArray;
@@ -62,7 +64,9 @@ class ServerModel {
 
   async getEnterServerListByUid(uid: any, tag: any) {
     return await query(
-      `SELECT ges.id, ges.uid, ges.server_id, ges.create_time as last_login_time , gs.ip, gs.port,gs.status,gs.name,gs.tips,gs.wss FROM game_enter_server as ges left join game_server as gs on ges.server_id = gs.sid and ges.tag = gs.tag  WHERE ges.uid = ? and ges.tag = ? order by ges.create_time desc `,
+      `SELECT ges.id, ges.uid, ges.server_id, ges.create_time as last_login_time , gs.ip, gs.port,gs.status,gs.name,
+           gs.tips,gs.wss,gs.db_name,gs.is_show FROM game_enter_server as ges left join game_server as gs on ges.server_id = gs.sid and
+            ges.tag = gs.tag  WHERE ges.uid = ? and ges.tag = ? AND gs.is_show=1 order by ges.create_time desc `,
       [uid, tag]
     );
   }

+ 113 - 0
webServer/src/mongo/mongodb.ts

@@ -0,0 +1,113 @@
+import {mongoConfig} from '../config/dbConfig'
+import * as mongodb from 'mongodb';
+const {Db, MongoClient, ObjectId} = mongodb;
+
+let db: mongodb.Db | null = null;
+let client: mongodb.MongoClient | null = null;
+
+async function connectToMongo() {
+    if (db) {
+        return db;
+    }
+    try {
+        console.log('开始初始化MongoDB');
+        const url = `mongodb://${mongoConfig.url}:${mongoConfig.port}`;
+        console.log('MongoDB连接URL:', url);
+        
+        // MongoDB 2.x 使用旧式连接方式
+        client = await MongoClient.connect(url);
+        
+        db = client.db('sdk');
+        console.log('MongoDB连接成功');
+        return db;
+    } catch (error) {
+        console.error('连接到MongoDB失败:', error);
+        throw error;
+    }
+}
+
+// 获取某一个数据库连接
+async function getDb(): Promise<mongodb.Db> {
+    if (!db) {
+        db = await connectToMongo();
+    }
+    return db;
+}
+
+// 查询某一个db的集合
+async function getCollection(collectionName: string) {
+    const database = await getDb();
+    return database.collection(collectionName);
+}
+
+//关闭连接
+async function closeConnection() {
+    if (client) {
+        await client.close();
+        db = null;
+        client = null;
+        console.log("MongoDB连接已关闭");
+    }
+}
+
+//通过id和db查询某一个角色信息
+async function getRoleInfoById(dbName: string, roleId: string) {
+    try {
+        if (!client) {
+            await connectToMongo();
+        }
+        const database = client!.db(dbName);
+        const collection = database.collection('char');
+        const roleInfo = await collection.findOne({roleId: roleId});
+        return roleInfo;
+    } catch (error) {
+        console.error('查询角色信息失败:', error);
+        return null;
+    }
+}
+
+//查询工会信息
+async function getGuildInfoById(dbName: string, uuid: string) {
+    try {
+        if (!client) {
+            await connectToMongo();
+        }
+        const database = client!.db(dbName);
+        const collection = database.collection('guild');
+        const guildInfo = await collection.findOne({_id: new ObjectId(uuid)});
+        return guildInfo;
+    } catch (error) {
+        console.error('查询工会信息失败:', error);
+        return null;
+    }
+}
+
+//根据用户ID和服务器ID查询角色信息
+async function getRoleInfoByUidAndServerId(newUniqueTag: string, dbName: string) {
+    try {
+        if (!client) {
+            await connectToMongo();
+        }
+        const database = client!.db(dbName);
+        const collection = database.collection('char');
+        
+        // 查询该用户在该服务器上的角色信息
+        const roleInfo = await collection.findOne({newUniqueTag: newUniqueTag});
+        
+        if (roleInfo) {
+            return {
+                roleName: roleInfo.name || "未知角色",
+                roleLevel: roleInfo.lv || 1,
+                roleId: roleInfo.roleId || "",
+                head: roleInfo.head || "",
+            };
+        }
+        
+        return null;
+    } catch (error) {
+        console.error('查询角色信息失败:', error);
+        return null;
+    }
+}
+
+export { getDb, getCollection, closeConnection, getRoleInfoById, connectToMongo, getGuildInfoById, getRoleInfoByUidAndServerId };

+ 4 - 4
webServer/src/router/admin.ts

@@ -9,13 +9,13 @@ const adminRouter = new Router({
 adminRouter.get('/ports', (ctx) => {
   ctx.body = {
     success: true,
-    ports: serverManager.getActivePorts()
+    ports: serverManager().getActivePorts()
   };
 });
 
 // 添加新端口
 adminRouter.post('/ports', (ctx) => {
-  const { port } = ctx.request.body;
+  const { port } = (ctx.request.body as any);
   
   if (!port || isNaN(parseInt(port))) {
     ctx.status = 400;
@@ -23,7 +23,7 @@ adminRouter.post('/ports', (ctx) => {
     return;
   }
   
-  const success = serverManager.createServer(parseInt(port));
+  const success = serverManager().createServer(parseInt(port));
   ctx.body = { success, port };
 });
 
@@ -37,7 +37,7 @@ adminRouter.delete('/ports/:port', (ctx) => {
     return;
   }
   
-  const success = serverManager.removeServer(port);
+  const success = serverManager().removeServer(port);
   ctx.body = { success, port };
 });
 

+ 7 - 0
webServer/src/router/index.ts

@@ -1,9 +1,12 @@
 import Router from "@koa/router";
 import adminRouter from "./admin";
+import miniApprouter from "./miniapp";
 const router = new Router();
 
 // 使用管理员路由
 router.use(adminRouter.routes(), adminRouter.allowedMethods());
+//小程序路由
+router.use("/miniapp", miniApprouter.routes(), miniApprouter.allowedMethods());
 
 //用户
 const ApiController = require("../controller/ApiController");
@@ -86,4 +89,8 @@ router.get("/qqGift", TencentController.qqGift);
 
 router.post("/qqReport", TencentController.qqReport);
 
+// mianyou开服同步
+router.post("/mianyou/syncServer", ApiController.mianyouSyncServer);
+
+
 module.exports = router;

+ 25 - 0
webServer/src/router/miniapp.ts

@@ -0,0 +1,25 @@
+import Router from "@koa/router";
+const MiniAppController = require("../controller/MiniappController");
+
+const miniAppRouter = new Router();
+
+// 内容安全审核
+miniAppRouter.post("/contentSecurityCheck", MiniAppController.contentSecurityCheck);
+
+// 角色名称修改上报
+miniAppRouter.post("/editUserRoleInfo", MiniAppController.editUserRoleInfo);
+
+// 禁言接口
+miniAppRouter.post("/forbidChat", MiniAppController.forbidChat);
+
+// 订单校验接口
+miniAppRouter.get("/verifyOrder", MiniAppController.verifyOrder);
+miniAppRouter.post("/verifyOrder", MiniAppController.verifyOrder);
+
+// 解除禁言接口
+miniAppRouter.post("/freeChat", MiniAppController.freeChat);
+
+// 角色查询接口
+miniAppRouter.post("/roleQuery", MiniAppController.roleQuery);
+
+export default miniAppRouter;

+ 38 - 8
webServer/src/server.ts

@@ -2,21 +2,51 @@
 import { ServerManager } from './utils/serverManager';
 import { serverConfig } from './config/serverConfig';
 import Task from './utils/task';
+import { connectToMongo } from './mongo/mongodb';
 const router = require('./router/index');
 
+// 初始化MongoDB连接
+async function initializeMongoDB() {
+  try {
+    console.log('开始初始化MongoDB');
+    await connectToMongo();
+    console.log('MongoDB初始化成功');
+  } catch (error) {
+    console.error('MongoDB初始化失败:', error);
+    process.exit(1); // 如果MongoDB连接失败,退出进程
+  }
+}
+
 // 创建服务器管理器实例
-const serverManager = new ServerManager(router);
+let serverManager: ServerManager;
 
-// 启动所有配置的端口
-serverConfig.ports.forEach(port => {
-  const success = serverManager.createServer(port);
-  if (success) {
-    console.log(`启动成功,服务端口为:${port}`);
-  }
+// 启动服务器
+async function startServer() {
+  // 先初始化MongoDB
+  await initializeMongoDB();
+  
+  // 创建服务器管理器实例
+  serverManager = new ServerManager(router);
+
+  // 启动所有配置的端口
+  serverConfig.ports.forEach(port => {
+    const success = serverManager.createServer(port);
+    if (success) {
+      console.log(`启动成功,服务端口为:${port}`);
+    }
+  });
+
+  return serverManager;
+}
+
+// 启动服务器
+startServer().catch(error => {
+  console.error('服务器启动失败:', error);
+  process.exit(1);
 });
 
 // 导出服务器管理器以便其他模块可以使用
-export default serverManager;
+export default () => serverManager;
 
 // 注释掉的任务相关代码保留
 // const appTask = new Task();

+ 45 - 6
webServer/src/utils/msg.ts

@@ -163,6 +163,12 @@ export default class Msg {
   }
 
   writeString(str) {
+    // 参数验证:确保 str 不为 undefined 或 null
+    if (str === undefined || str === null) {
+      console.error("writeString 接收到 undefined 或 null 参数:", str);
+      str = ""; // 使用空字符串作为默认值
+    }
+    
     var oldPos = this.sendBufLen;
     this.writeShort(0);
     var totalByte = 0;
@@ -223,14 +229,23 @@ export default class Msg {
     logger.info("发送发货消息开始", {params:params, readyState: this.websocket.readyState, isConnect: this.isConnect });
     // console.log("发送登录消息", this.websocket.readyState, this.isConnect);
     if (this.isConnect != true || this.websocket.readyState != 1) return false;
+    
+    // 参数验证和默认值处理
+    const safeAccount = account || "";
+    const safeAuthkey = authkey || "";
+    const safeLang = lang || "cn";
+    const safeRegion = region || "CN";
+    const safeIp = ip || "127.0.0.1";
+    const safeParams = params || "{}";
+    
     this.sendBufLen = 4;
-    this.writeString(account);
+    this.writeString(safeAccount);
     this.writeInt(timestamp);
-    this.writeString(authkey);
-    this.writeString(lang);
-    this.writeString(region);
-    this.writeString(ip);
-    this.writeString(params);
+    this.writeString(safeAuthkey);
+    this.writeString(safeLang);
+    this.writeString(safeRegion);
+    this.writeString(safeIp);
+    this.writeString(safeParams);
     this.writeInt(server_id);
     this.sendBufDV.setInt16(2, 62);
     this.sendBufDV.setInt16(0, this.sendBufLen - 4);
@@ -267,4 +282,28 @@ export default class Msg {
     this.close(); // 主动断开连接
     return true;
   }
+
+  CG_CHAT_NEW_BAN(
+      uuid: string,
+      type: number,
+      time: number,
+      reason: string,
+  ) {
+    logger.info("发送禁言消息开始", {uuid:uuid,type:type,time:time,reason:reason, readyState: this.websocket.readyState, isConnect: this.isConnect });
+    // console.log("发送登录消息", this.websocket.readyState, this.isConnect);
+    if (this.isConnect != true || this.websocket.readyState != 1) return false;
+    this.sendBufLen = 4;
+    this.writeString(uuid);
+    this.writeInt(type);
+    this.writeInt(time);
+    this.writeString(reason);
+    this.sendBufDV.setInt16(2, 62);
+    this.sendBufDV.setInt16(0, this.sendBufLen - 4);
+    this.send(62);
+    this.close(); // 主动断开连接
+    return true;
+  }
+
+
+
 }

+ 8 - 6
webServer/src/utils/serverManager.ts

@@ -2,9 +2,10 @@ import Koa from 'koa';
 import bodyParser from 'koa-bodyparser';
 import koaRedis from 'koa-redis';
 import { redisConfig } from '../config/dbConfig';
+import { Server } from 'http';
 
 export class ServerManager {
-  private servers: Map<number, Koa> = new Map();
+  private servers: Map<number, { app: Koa; server: Server }> = new Map();
   private router: any;
   
   constructor(router: any) {
@@ -23,7 +24,7 @@ export class ServerManager {
       app.proxy = true;
       
       // 配置Redis
-      app.context.redis = koaRedis(redisConfig);
+      app.context.redis = koaRedis(redisConfig as any);
       
       // 配置中间件
       this.setupMiddlewares(app);
@@ -34,7 +35,7 @@ export class ServerManager {
       });
       
       // 存储服务器实例
-      this.servers.set(port, app);
+      this.servers.set(port, { app, server });
       return true;
     } catch (error) {
       console.error(`在端口 ${port} 启动服务器失败:`, error);
@@ -44,15 +45,15 @@ export class ServerManager {
   
   // 停止并移除一个服务器实例
   public removeServer(port: number): boolean {
-    const app = this.servers.get(port);
-    if (!app) {
+    const serverInfo = this.servers.get(port);
+    if (!serverInfo) {
       console.log(`端口 ${port} 没有运行中的服务器`);
       return false;
     }
     
     try {
       // 关闭服务器
-      app.callback().server?.close();
+      serverInfo.server.close();
       this.servers.delete(port);
       console.log(`端口 ${port} 的服务器已关闭`);
       return true;
@@ -88,5 +89,6 @@ export class ServerManager {
     
     // 路由中间件
     app.use(this.router.routes());
+    app.use(this.router.allowedMethods());
   }
 }

+ 242 - 0
webServer/syiosApi.md

@@ -0,0 +1,242 @@
+# SYIOS 渠道 API 文档
+
+## 渠道信息
+- **渠道ID**: 12
+- **平台**: sy_ios
+- **处理器**: SYIOSChannelHandler
+
+---
+
+## 1. 登录鉴权接口
+
+### 接口地址
+- **GET/POST** `/thirdLogin` (通过渠道ID=12调用)
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| userToken | string | 是 | 鉴权凭证,从 URL 上获取 |
+| gameid | number | 是 | 游戏的ID,商户后台游戏添加完成后可获取 |
+
+### 请求示例
+```bash
+# POST 请求
+POST /thirdLogin
+Content-Type: application/json
+
+{
+  "channelId": 12,
+  "userToken": "your_token_here",
+  "gameid": 1540
+}
+```
+
+### 响应参数
+```json
+{
+  "code": 1,           // 1成功,-1失败
+  "msg": "登录成功",    // 提示信息
+  "data": {
+    "uid": "",         // 用户UID
+    "nickname": "",    // 用户昵称
+    "headimgurl": "",  // 用户头像地址
+    "sex": "",         // 用户性别 0未知 1男 2女
+    "focus": "",       // 是否关注公众号 0否 1是
+    "usertype": ""     // 用户类型 1为微信用户 -1为非微信用户
+  }
+}
+```
+
+### 错误响应
+```json
+{
+  "code": -1,
+  "msg": "参数有误,请检查接口所需参数是否都已经填写正确",
+  "data": null
+}
+```
+
+---
+
+## 2. 支付回调接口
+
+### 接口地址
+- **GET** `/callback` (通过渠道ID=12调用)
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| openid | string | 是 | 用户UID |
+| rmb | number | 是 | 付费金额,单位人民币 |
+| reqid | string | 是 | 不重复的请求ID |
+| trans_id | number | 是 | 平台支付订单号 |
+| product_id | number | 是 | 商品ID |
+| notify_id | string | 是 | 平台通知ID |
+| userdata | string | 否 | 支付的透传参数,商户自定义参数,最多128个字节 |
+| txid | string | 否 | 支付的透传参数,商户订单号,最多64个字节 |
+| product_count | number | 否 | 购买的商品数量,默认为1 |
+| sign | string | 是 | 签名,签名算法3 |
+
+### 请求示例
+```bash
+GET /callback?openid=12345678&rmb=1&reqid=20152392834940&trans_id=123456&product_id=6000&notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c&userdata=test_data&txid=merchant_order_123&product_count=1&sign=7761AF5E944ABC6060B3192861FA0281
+```
+
+### 响应
+- **成功**: 返回字符串 `"SUCCESS"` (不包含引号,全大写)
+- **失败**: 返回错误信息
+
+### 支付处理流程
+1. **接收支付回调**: 接收第三方支付平台的回调通知
+2. **验证支付签名**: 使用签名算法3验证支付回调的签名
+3. **提取notify_id**: 从支付回调中提取 `notify_id` 参数
+4. **订单校验**: 调用第三方订单校验API验证订单是否真实有效
+5. **发货处理**: 只有订单校验成功后才进行实际的发货处理
+6. **返回响应**: 返回 `"SUCCESS"` 给第三方支付平台
+
+### 订单校验集成
+支付回调处理中会自动进行订单校验,确保:
+- 防止恶意第三方通知
+- 验证订单的真实性
+- 只有校验成功的订单才会发货
+- 提高支付安全性
+
+---
+
+## 3. 订单校验接口
+
+### 接口地址
+- **GET/POST** `/miniapp/verifyOrder`
+
+### 请求参数
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| gameid | number | 是 | 游戏ID,商户后台游戏添加完成后可获取 |
+| notify_id | string | 是 | 平台通知ID,商户通过notify_id查询订单是否付费成功 |
+| sign | string | 是 | 签名,签名算法3 |
+
+### 请求示例
+```bash
+# GET 请求
+GET /miniapp/verifyOrder?gameid=1540&notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c&sign=A3EA3EF39B43BA762DFBFB78229DB33B
+
+# POST 请求
+POST /miniapp/verifyOrder
+Content-Type: application/json
+
+{
+  "gameid": 1540,
+  "notify_id": "f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c",
+  "sign": "A3EA3EF39B43BA762DFBFB78229DB33B"
+}
+```
+
+### 响应参数
+```json
+{
+  "success": true,        // 校验是否成功
+  "message": "订单校验成功" // 提示信息
+}
+```
+
+### 错误响应
+```json
+{
+  "success": false,
+  "message": "缺少必要参数: gameid"
+}
+```
+
+### 第三方API
+- **请求方式**: GET
+- **URL**: `https://login.11h5.com/pay/paygate/verify.php`
+- **成功响应**: `"SUCCESS"` (不包含引号,全大写)
+- **失败响应**: 其他任何信息
+
+---
+
+## 4. 签名算法3
+
+### 算法步骤
+
+1. **除去为空的参数**: 过滤掉值为空、null、undefined的参数,以及sign参数
+2. **参数排序**: 对参数名按字母顺序排序 (a-z)
+3. **构建字符串**: 用 `&` 连接所有参数,格式为 `key=value`
+4. **拼接私钥**: 在字符串末尾添加 `&key=私钥`
+5. **MD5签名**: 对最终字符串进行MD5哈希,并转换为大写
+
+### 示例
+
+**原始参数**:
+```
+openid=12345678
+rmb=1
+reqid=20152392834940
+trans_id=123456
+product_id=6000
+notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c
+nick=                    // 空参数,会被过滤
+userdata=test_data
+txid=merchant_order_123
+product_count=1
+```
+
+**排序后的待签名字符串**:
+```
+notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c&openid=12345678&product_count=1&product_id=6000&reqid=20152392834940&rmb=1&trans_id=123456&txid=merchant_order_123&userdata=test_data
+```
+
+**最终签名字符串**:
+```
+notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c&openid=12345678&product_count=1&product_id=6000&reqid=20152392834940&rmb=1&trans_id=123456&txid=merchant_order_123&userdata=test_data&key=yduLY3ovg4NwTHMMemGg1vO6VHuYBcYD
+```
+
+**生成的签名**:
+```
+7761AF5E944ABC6060B3192861FA0281
+```
+
+### 订单校验签名示例
+
+**原始参数**:
+```
+gameid=1540
+notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c
+```
+
+**排序后的待签名字符串**:
+```
+gameid=1540&notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c
+```
+
+**最终签名字符串**:
+```
+gameid=1540&notify_id=f2c90bc120cdef27c8cc4d1bdf8341a74625588c6edcd9c&key=yduLY3ovg4NwTHMMemGg1vO6VHuYBcYD
+```
+
+**生成的签名**:
+```
+A3EA3EF39B43BA762DFBFB78229DB33B
+```
+
+---
+
+## 4. 错误码说明
+
+| 错误码 | 说明 |
+|--------|------|
+| 0 | 参数有误,请检查接口所需参数是否都已经填写正确 |
+| 403 | token验证失败,同一个userToken只能验证一次,可通过刷新游戏重新获取 |
+| -1 | 系统错误,鉴权失败,请稍后重试 |
+
+---
+
+## 5. 重要说明
+
+⚠️ **同一个token只能验证一次,不能多次重复请求**
+
+## 6. 第三方API
+
+- **登录鉴权**: `https://api.11h5.com/login?cmd=checkUserToken`
+- **私钥**: `yduLY3ovg4NwTHMMemGg1vO6VHuYBcYD`
+- **游戏ID**: `1540`

+ 32 - 0
webServer/webpack.config.js

@@ -20,4 +20,36 @@ module.exports = {
     filename: 'app.js', // 输出的打包文件
     path: path.resolve(__dirname, 'dist'), 
   },
+  externals: {
+    // 排除有问题的二进制模块和可选依赖
+    'kerberos': 'commonjs kerberos',
+    'snappy': 'commonjs snappy',
+    'bson-ext': 'commonjs bson-ext',
+    '@mongodb-js/zstd': 'commonjs @mongodb-js/zstd',
+    'mongodb-client-encryption': 'commonjs mongodb-client-encryption',
+    '@napi-rs/snappy-darwin-arm64': 'commonjs @napi-rs/snappy-darwin-arm64',
+    '@napi-rs/snappy-darwin-x64': 'commonjs @napi-rs/snappy-darwin-x64',
+    '@napi-rs/snappy-linux-x64-gnu': 'commonjs @napi-rs/snappy-linux-x64-gnu',
+    '@napi-rs/snappy-linux-x64-musl': 'commonjs @napi-rs/snappy-linux-x64-musl',
+    '@napi-rs/snappy-linux-arm64-gnu': 'commonjs @napi-rs/snappy-linux-arm64-gnu',
+    '@napi-rs/snappy-linux-arm64-musl': 'commonjs @napi-rs/snappy-linux-arm64-musl',
+    '@napi-rs/snappy-linux-arm-gnueabihf': 'commonjs @napi-rs/snappy-linux-arm-gnueabihf',
+    '@napi-rs/snappy-linux-arm-musleabihf': 'commonjs @napi-rs/snappy-linux-arm-musleabihf',
+    '@napi-rs/snappy-linux-riscv64-gnu': 'commonjs @napi-rs/snappy-linux-riscv64-gnu',
+    '@napi-rs/snappy-linux-riscv64-musl': 'commonjs @napi-rs/snappy-linux-riscv64-musl',
+    '@napi-rs/snappy-linux-ppc64-gnu': 'commonjs @napi-rs/snappy-linux-ppc64-gnu',
+    '@napi-rs/snappy-linux-s390x-gnu': 'commonjs @napi-rs/snappy-linux-s390x-gnu',
+    '@napi-rs/snappy-openharmony-arm64': 'commonjs @napi-rs/snappy-openharmony-arm64',
+    '@napi-rs/snappy-openharmony-x64': 'commonjs @napi-rs/snappy-openharmony-x64',
+    '@napi-rs/snappy-openharmony-arm': 'commonjs @napi-rs/snappy-openharmony-arm',
+    '@napi-rs/snappy-wasm32-wasi': 'commonjs @napi-rs/snappy-wasm32-wasi',
+    '@napi-rs/snappy-freebsd-x64': 'commonjs @napi-rs/snappy-freebsd-x64',
+    '@napi-rs/snappy-freebsd-arm64': 'commonjs @napi-rs/snappy-freebsd-arm64'
+  },
+  // 添加忽略警告的配置
+  ignoreWarnings: [
+    /Critical dependency: the request of a dependency is an expression/,
+    /Module not found: Error: Can't resolve 'bson-ext'/,
+    /Package path .* is not exported from package/
+  ],
 };

+ 50 - 0
苍空新增协议v1.txt

@@ -82,4 +82,54 @@ CG_HERO_TIAO_JIAO_UNLOCK {
 CG_HERO_TIAO_JIAO_USE_ITEM {
 	id : int 	--英雄id
 	itemId : int 	--道具id
+}
+
+----------------------------------------- 巅峰战场协议开始 -------------------------------------
+-- 对手信息
+PeakBattlefieldOpponent = {
+    {"uuid",        1,      "string"},      -- 对手uuid
+    {"rank",        1,      "int"},        -- 对手排名
+    {"roleBase",    1,      RoleBase},     -- 对手角色信息
+}
+
+-- 查询巅峰战场数据
+CG_PEAK_BATTLEFIELD_QUERY = {}
+
+-- 查询巅峰战场数据 - 回包
+GC_PEAK_BATTLEFIELD_QUERY = {
+    {"rank",            1,      "int"},                    -- 当前排名
+    {"freeChallengeCnt", 1,      "byte"},                   -- 免费挑战次数
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 对手列表
+    {"unlockedHeroes",  50,     "int"},                     -- 已解锁英雄ID列表
+    {"leftTime",        1,      "int"},                     -- 活动剩余时间(秒)
+}
+
+-- 刷新对手列表
+CG_PEAK_BATTLEFIELD_REFRESH = {}
+
+-- 刷新对手列表 - 回包
+GC_PEAK_BATTLEFIELD_REFRESH = {
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 对手列表
+}
+
+-- 挑战对手
+CG_PEAK_BATTLEFIELD_CHALLENGE = {
+    {"opponentUuid",    1,      "string"},                 -- 对手uuid
+}
+
+-- 挑战对手 - 回包
+GC_PEAK_BATTLEFIELD_CHALLENGE = {
+    {"result",          1,      "byte"},                     -- 战斗结果 1-胜利 2-失败
+    {"newRank",         1,      "int"},                     -- 新排名
+    {"reward",          10,     ItemData},                   -- 奖励列表
+    {"opponentList",    5,      PeakBattlefieldOpponent},  -- 新的对手列表(胜利时返回)
+}
+
+-- 查询排名奖励
+CG_PEAK_BATTLEFIELD_RANK_REWARD_QUERY = {}
+
+-- 查询排名奖励 - 回包
+GC_PEAK_BATTLEFIELD_RANK_REWARD_QUERY = {
+    {"rank",            1,      "int"},                    -- 当前排名
+    {"rewardList",      20,     "int"},                     -- 排名奖励ID列表
 }

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor