pigflower пре 1 месец
родитељ
комит
dacf83b63f

+ 15 - 0
script/module/scene/Handler.lua

@@ -102,6 +102,21 @@ function CG_TEST_PROTO(fd,msg)
 			appBanInfo = param.appBanInfo
 		}
 		BanLogic.Update_Ban_Info(banInfo)
+	elseif param.type == "deliverGoods" then
+		local uTag = RoleDBLogic.Generateuuid(param.channel_id, msg.account, msg.serverTag)
+		local human = ObjHuman.onlineNewUniqueTag[uTag]
+		if not human then
+			Log.write(Log.LOGID_DEBUG, "[deliverGoods] 玩家不在线 account=" .. tostring(msg.account) .. " orderId=" .. tostring(param.orderId))
+			return
+		end
+		local items = {}
+		if param.goods and #param.goods > 0 then
+			for _, good in ipairs(param.goods) do
+				table.insert(items, {good.Id, good.Num})
+			end
+		end
+		Log.write(Log.LOGID_DEBUG, "[deliverGoods] 开始发货 account=" .. tostring(msg.account) .. " orderId=" .. tostring(param.orderId) .. " itemCnt=" .. #items)
+		youxiSdkReward(human, items)
 	end
 end
 

+ 42 - 7
script/module/zhuanpan/ZhuanpanLogic.lua

@@ -1764,6 +1764,31 @@ local function getWeekProgress(field)
 	return weekTotal
 end
 
+-- 检查账号下是否有任何角色已领取指定游戏圈任务(账号级别判断)
+local function checkAccountYouxiTaskClaimed(account, taskId)
+	if not account then return false end
+	local config = YOUXI_TASK_CONFIG[taskId]
+	if not config then return false end
+	LuaMongo.find(DB.db_char, {account = account}, {zhuanpan = 1})
+	while true do
+		local data = {}
+		if not LuaMongo.next(data) then break end
+		local yt = data.zhuanpan and data.zhuanpan.youxiTask
+		if yt then
+			if config.taskType == "once" then
+				if yt.joinGetTime then return true end
+			elseif config.taskType == "daily" then
+				local field = (taskId == 2) and yt.dailyLike or yt.dailyComment
+				if field and field.getTime and Util.isSameDay(field.getTime) then return true end
+			elseif config.taskType == "weekly" then
+				local field = (taskId == 4) and yt.dailyLike or yt.dailyComment
+				if field and field.weekGetTime and isCurrentWeek(field.weekGetTime) then return true end
+			end
+		end
+	end
+	return false
+end
+
 -- 游戏圈任务查询(前端上传 SDK 数据,后端存储并计算进度)
 function youxiTaskQuery(human, msg)
 	local msgRet = Msg.gc.GC_ZHUANPAN_YOUXI_TASK_QUERY
@@ -1802,7 +1827,8 @@ function youxiTaskQuery(human, msg)
 
 			if config.taskType == "once" then
 				taskData.progress = yt.joined and 1 or 0
-				if yt.joinGetTime then
+				local claimed = yt.joinGetTime or checkAccountYouxiTaskClaimed(human.db.account, taskId)
+				if claimed then
 					taskData.status = 2
 				elseif yt.joined then
 					taskData.status = 1
@@ -1815,7 +1841,8 @@ function youxiTaskQuery(human, msg)
 				local dayCount = (field and field.dayTime and Util.isSameDay(field.dayTime)) and (field.count or 0) or 0
 				taskData.progress = math.min(dayCount, config.target)
 				local getTime = field and field.getTime
-				if getTime and Util.isSameDay(getTime) then
+				local claimed = (getTime and Util.isSameDay(getTime)) or checkAccountYouxiTaskClaimed(human.db.account, taskId)
+				if claimed then
 					taskData.status = 2
 				elseif dayCount >= config.target then
 					taskData.status = 1
@@ -1828,7 +1855,8 @@ function youxiTaskQuery(human, msg)
 				local weekCount = getWeekProgress(field)
 				taskData.progress = math.min(weekCount, config.target)
 				local weekGetTime = field and field.weekGetTime
-				if weekGetTime and isCurrentWeek(weekGetTime) then
+				local claimed = (weekGetTime and isCurrentWeek(weekGetTime)) or checkAccountYouxiTaskClaimed(human.db.account, taskId)
+				if claimed then
 					taskData.status = 2
 				elseif weekCount >= config.target then
 					taskData.status = 1
@@ -1864,9 +1892,12 @@ function youxiTaskGetReward(human, taskId)
 	local yt = human.db.zhuanpan.youxiTask
 	local now = os.time()
 
-	-- 校验条件 & 重复领取
+	-- 校验条件 & 重复领取(账号级别判断,同账号多角色共享)
+	-- 先查当前角色内存,没有再查 DB 其他角色(与美团订阅奖励模式一致)
+	local account = human.db.account
 	if config.taskType == "once" then
-		if yt.joinGetTime then
+		local claimed = yt.joinGetTime or checkAccountYouxiTaskClaimed(account, taskId)
+		if claimed then
 			return Broadcast.sendErr(human, "已领取过")
 		end
 		if not yt.joined then
@@ -1875,7 +1906,9 @@ function youxiTaskGetReward(human, taskId)
 
 	elseif config.taskType == "daily" then
 		local field = (taskId == 2) and yt.dailyLike or yt.dailyComment
-		if field and field.getTime and Util.isSameDay(field.getTime) then
+		local getTime = field and field.getTime
+		local claimed = (getTime and Util.isSameDay(getTime)) or checkAccountYouxiTaskClaimed(account, taskId)
+		if claimed then
 			return Broadcast.sendErr(human, "今日已领取")
 		end
 		local dayCount = (field and field.dayTime and Util.isSameDay(field.dayTime)) and (field.count or 0) or 0
@@ -1885,7 +1918,9 @@ function youxiTaskGetReward(human, taskId)
 
 	elseif config.taskType == "weekly" then
 		local field = (taskId == 4) and yt.dailyLike or yt.dailyComment
-		if field and field.weekGetTime and isCurrentWeek(field.weekGetTime) then
+		local weekGetTime = field and field.weekGetTime
+		local claimed = (weekGetTime and isCurrentWeek(weekGetTime)) or checkAccountYouxiTaskClaimed(account, taskId)
+		if claimed then
 			return Broadcast.sendErr(human, "本周已领取")
 		end
 		if getWeekProgress(field) < config.target then

+ 31 - 27
webServer/src/channels/handlers/MiniappChannelHandler.ts

@@ -9,6 +9,7 @@ import {PaymentHelper} from "../../utils/PaymentHelper";
 
 import Msg from "../../utils/msg";
 import axios from "axios";
+import { insertMailToPlayer } from "../../mongo/mongodb";
 
 const Order = require("../../model/OrderModel");
 const CryptoJS = require("crypto-js");
@@ -1484,7 +1485,7 @@ export class MiniappChannelHandler implements ChannelHandler {
     async deliverGoods(ctx: Context, config: ChannelConfig): Promise<LoginResult> {
         try {
             const body = ctx.request.body as any;
-            const { timestamp, nonce, signature, wxMsg } = body;
+            const { timestamp, nonce, signature, wxMsg,uid } = body;
 
             // 验证签名(签名算法1:SHA1)
             const verifyConfig = this.getChannel11Config('miniapp');
@@ -1501,48 +1502,51 @@ export class MiniappChannelHandler implements ChannelHandler {
             }
 
             const { OrderId, ToUserOpenid, GiftTypeId, GiftId, GoodsList, Zone, IsPreview } = miniGame;
-            if (!OrderId || !ToUserOpenid || !GoodsList) {
-                logger.error("游戏圈发货:缺少必要参数", { OrderId, ToUserOpenid });
+            if (!OrderId || !uid || !GoodsList) {
+                logger.error("游戏圈发货:缺少必要参数", { OrderId, uid });
                 return { code: 0, msg: "ok" };
             }
 
-            logger.info("游戏圈发货请求", { OrderId, ToUserOpenid, GiftTypeId, GiftId, Zone, IsPreview });
+            logger.info("游戏圈发货请求", { OrderId, ToUserOpenid, GiftTypeId, GiftId, Zone, IsPreview,uid });
 
             // 查询玩家最近登录的服务器
             const Server = require("../../model/ServerModel");
-            const serverList = await Server.getEnterServerListByUid(ToUserOpenid, 11);
+            const serverList = await Server.getEnterServerListByUid(uid, 11);
             if (!serverList || serverList.length === 0) {
-                logger.warn("游戏圈发货:未找到玩家服务器记录", { ToUserOpenid });
+                logger.warn("游戏圈发货:未找到玩家服务器记录", { uid });
                 return { code: 0, msg: "ok" };
             }
 
             // 取最近登录的服务器
             const serverInfo = serverList[0];
-            const url = serverInfo.wss || `ws://${serverInfo.ip}:${serverInfo.port}`;
-
-            const params = JSON.stringify({
-                type: "deliverGoods",
-                account: ToUserOpenid,
-                channel_id: 11,
-                orderId: OrderId,
-                giftTypeId: GiftTypeId,
-                giftId: GiftId,
-                goods: GoodsList,
-                zone: Zone,
-            });
 
-            logger.info("游戏圈发货 - 通知游戏服务器", { url, params });
+            // 将 GoodsList 转换为邮件道具格式 [[itemId, count], ...]
+            const items: Array<[number, number]> = (GoodsList as any[]).map(good => [
+                Number(good.Id),
+                Number(good.Num),
+            ]);
 
-            const sendMsg = new Msg();
-            sendMsg.connect(url, Account);
-            await new Promise<void>((resolve) => {
-                setTimeout(() => {
-                    sendMsg.CG_TEST_PROTO(ToUserOpenid, params, serverInfo.server_id);
-                    resolve();
-                }, 1000);
+            // newUniqueTag 格式与 Lua 保持一致:"channelId|serverId|account"
+            const newUniqueTag = `11|${serverInfo.server_id}|${uid}`;
+
+            logger.info("游戏圈发货 - 直接写邮件到DB", {
+                OrderId, uid, dbName: serverInfo.db_name, newUniqueTag, itemCnt: items.length,
             });
 
-            logger.info("游戏圈发货成功", { OrderId, ToUserOpenid });
+            const ok = await insertMailToPlayer(
+                serverInfo.db_name,
+                newUniqueTag,
+                "游戏圈礼物",
+                "您有一份游戏圈礼物待领取",
+                items,
+            );
+
+            if (!ok) {
+                logger.warn("游戏圈发货:邮件写入失败", { OrderId, uid });
+            } else {
+                logger.info("游戏圈发货成功", { OrderId,uid });
+            }
+
             return { code: 0, msg: "ok" };
 
         } catch (error) {

+ 60 - 1
webServer/src/mongo/mongodb.ts

@@ -110,4 +110,63 @@ async function getRoleInfoByUidAndServerId(newUniqueTag: string, dbName: string)
     }
 }
 
-export { getDb, getCollection, closeConnection, getRoleInfoById, connectToMongo, getGuildInfoById, getRoleInfoByUidAndServerId };
+/**
+ * 向玩家发送系统邮件(直接写入 MongoDB)
+ * @param dbName    游戏服数据库名,如 "ckwy_fy_S001"
+ * @param newUniqueTag  玩家唯一标识,格式 "channelId|serverId|account"
+ * @param title     邮件标题
+ * @param content   邮件内容
+ * @param items     道具列表,格式 [[itemId, count], ...]
+ * @returns 发送是否成功
+ */
+async function insertMailToPlayer(
+    dbName: string,
+    newUniqueTag: string,
+    title: string,
+    content: string,
+    items: Array<[number, number]>
+): Promise<boolean> {
+    try {
+        if (!client) {
+            await connectToMongo();
+        }
+        const database = client!.db(dbName);
+
+        // 通过 newUniqueTag 找到角色,取出 _id
+        const charCol = database.collection('char');
+        const charDoc = await charCol.findOne({ newUniqueTag });
+        if (!charDoc) {
+            console.warn(`[insertMailToPlayer] 找不到角色 newUniqueTag=${newUniqueTag} dbName=${dbName}`);
+            return false;
+        }
+
+        const receiverUuid = charDoc._id.toString();
+
+        const mailDoc: any = {
+            type: 1,                    // SYSTEM
+            receiverUuid,
+            title,
+            senderName: title,
+            head: 0,
+            content,
+            time: Math.floor(Date.now() / 1000),
+        };
+
+        if (items && items.length > 0) {
+            mailDoc.items = items;
+            mailDoc.flag = 1;           // 有道具未领取
+        } else {
+            mailDoc.get = 1;            // 无道具,直接已读
+        }
+
+        const mailCol = database.collection('mail');
+        await mailCol.insertOne(mailDoc);
+        console.log(`[insertMailToPlayer] 邮件发送成功 receiverUuid=${receiverUuid} itemCnt=${items.length}`);
+        return true;
+    } catch (error) {
+        console.error('[insertMailToPlayer] 发送邮件失败:', error);
+        return false;
+    }
+}
+
+export { getDb, getCollection, closeConnection, getRoleInfoById, connectToMongo, getGuildInfoById, getRoleInfoByUidAndServerId, insertMailToPlayer };