diff --git a/assets/Script/Revive.ts b/assets/Script/Revive.ts index fbcf604e..6cc54e57 100644 --- a/assets/Script/Revive.ts +++ b/assets/Script/Revive.ts @@ -203,14 +203,7 @@ export default class Revive extends cc.Component { let systemType = "Android"; try { //@ts-ignore - let systemInfo = null; - if (cc.sys.platform === cc.sys.WECHAT_GAME) - //@ts-ignore - systemInfo = wx.getSystemInfoSync(); - - else if (cc.sys.platform === cc.sys.BYTEDANCE_GAME) - //@ts-ignore - systemInfo = tt.getSystemInfoSync(); + const systemInfo = wx.getSystemInfoSync(); if (systemInfo.platform === 'ios') { systemType = "ios"; } @@ -263,7 +256,9 @@ export default class Revive extends cc.Component { console.log("错误原因:", res.errMsg); if (res.errMsg && res.errMsg.indexOf("fail App Store") !== -1) { console.log("走ios旧支付"); - this.iosOldPay(price, productId); + setTimeout(() => { + this.iosOldPay(price, productId); + }, 500); return; } MiniGameSdk.API.showToast("充值失败"); diff --git a/assets/Script/module/Pay/Utils.ts b/assets/Script/module/Pay/Utils.ts index 0a078ec1..c22ad872 100644 --- a/assets/Script/module/Pay/Utils.ts +++ b/assets/Script/module/Pay/Utils.ts @@ -243,7 +243,7 @@ export default class Utils { payment_num: iosPayInfo.payment_count, type: "ios", } - console.log("ios创建订单信息:", data); + console.log("________ios创建订单信息:", data); cc.fx.GameTool.shushu_Track("init_order", shushu_data); //@ts-ignore wx.openCustomerServiceConversation({ @@ -251,10 +251,10 @@ export default class Utils { showMessageCard: false, // 是否展示消息卡片 success() { callBack("success"); - //console.log('客服会话已successr'); + console.log('客服会话已successr'); }, fail() { - //console.log('客服会话已over'); + console.log('客服会话已over'); callBack("fail"); } }); diff --git a/assets/Script/monthlyCard.ts b/assets/Script/monthlyCard.ts index 7e40da63..778f330f 100644 --- a/assets/Script/monthlyCard.ts +++ b/assets/Script/monthlyCard.ts @@ -289,14 +289,7 @@ export default class NewClass extends cc.Component { let systemType = "Android"; try { //@ts-ignore - let systemInfo = null; - if (cc.sys.platform === cc.sys.WECHAT_GAME) - //@ts-ignore - systemInfo = wx.getSystemInfoSync(); - - else if (cc.sys.platform === cc.sys.BYTEDANCE_GAME) - //@ts-ignore - systemInfo = tt.getSystemInfoSync(); + const systemInfo = wx.getSystemInfoSync(); if (systemInfo.platform === 'ios') { systemType = "ios"; } @@ -493,7 +486,7 @@ export default class NewClass extends cc.Component { this.iosPrice = price; this.iosProductId = productId; this.iosCount = 1; - console.log("准备跳客服回话:"); + console.log("准备跳客服回话:", iosPayInfo); console.log(this.iosProductId); Utils.GoKEFu(iosPayInfo, (res) => { if (res == "success") { diff --git a/assets/action_bundle/script/NewbieGift.ts b/assets/action_bundle/script/NewbieGift.ts index 6083b68c..fc691714 100644 --- a/assets/action_bundle/script/NewbieGift.ts +++ b/assets/action_bundle/script/NewbieGift.ts @@ -342,14 +342,7 @@ export default class NewbieGift extends cc.Component { let systemType = "Android"; try { //@ts-ignore - let systemInfo = null; - if (cc.sys.platform === cc.sys.WECHAT_GAME) - //@ts-ignore - systemInfo = wx.getSystemInfoSync(); - - else if (cc.sys.platform === cc.sys.BYTEDANCE_GAME) - //@ts-ignore - systemInfo = tt.getSystemInfoSync(); + const systemInfo = wx.getSystemInfoSync(); if (systemInfo.platform === 'ios') { systemType = "ios"; } @@ -401,7 +394,9 @@ export default class NewbieGift extends cc.Component { console.log("错误原因:", res.errMsg); if (res.errMsg && res.errMsg.indexOf("fail App Store") !== -1) { console.log("走ios旧支付"); - this.iosOldPay(price, productId); + setTimeout(() => { + this.iosOldPay(price, productId); + }, 500); return; } MiniGameSdk.API.showToast("充值失败"); @@ -539,6 +534,8 @@ export default class NewbieGift extends cc.Component { this.iosPrice = price; this.iosProductId = productId; this.iosCount = 1; + console.log("准备跳客服回话:", iosPayInfo); + console.log(this.iosProductId); Utils.GoKEFu(iosPayInfo, (res) => { if (res == "success") { console.log("客服回话成功"); diff --git a/assets/shop/img/30.png b/assets/shop/img/30.png new file mode 100644 index 00000000..cb86bd35 Binary files /dev/null and b/assets/shop/img/30.png differ diff --git a/assets/shop/img/30.png.meta b/assets/shop/img/30.png.meta new file mode 100644 index 00000000..dc3dafb0 --- /dev/null +++ b/assets/shop/img/30.png.meta @@ -0,0 +1,38 @@ +{ + "ver": "2.3.7", + "uuid": "92fc9331-a068-4920-bb83-e12bf43754d0", + "importer": "texture", + "type": "sprite", + "wrapMode": "clamp", + "filterMode": "bilinear", + "premultiplyAlpha": false, + "genMipmaps": false, + "packable": true, + "width": 409, + "height": 181, + "platformSettings": {}, + "subMetas": { + "30": { + "ver": "1.0.6", + "uuid": "ec17e0d0-40d0-4c58-9a3c-c1c7857359a7", + "importer": "sprite-frame", + "rawTextureUuid": "92fc9331-a068-4920-bb83-e12bf43754d0", + "trimType": "auto", + "trimThreshold": 1, + "rotated": false, + "offsetX": 0, + "offsetY": 0, + "trimX": 0, + "trimY": 0, + "width": 409, + "height": 181, + "rawWidth": 409, + "rawHeight": 181, + "borderTop": 0, + "borderBottom": 0, + "borderLeft": 0, + "borderRight": 0, + "subMetas": {} + } + } +} \ No newline at end of file diff --git a/assets/shop/prefab/monthlyCard.prefab b/assets/shop/prefab/monthlyCard.prefab index 5caf43ce..026dca92 100644 --- a/assets/shop/prefab/monthlyCard.prefab +++ b/assets/shop/prefab/monthlyCard.prefab @@ -33,29 +33,32 @@ "__id__": 16 }, { - "__id__": 24 + "__id__": 19 }, { - "__id__": 34 + "__id__": 27 }, { - "__id__": 46 + "__id__": 37 }, { - "__id__": 59 + "__id__": 49 + }, + { + "__id__": 62 } ], "_active": true, "_components": [ { - "__id__": 86 + "__id__": 89 }, { - "__id__": 87 + "__id__": 90 } ], "_prefab": { - "__id__": 88 + "__id__": 91 }, "_opacity": 255, "_color": { @@ -575,6 +578,113 @@ "fileId": "8bZLLsI0hLcr+62zZt0LG/", "sync": false }, + { + "__type__": "cc.Node", + "_name": "30", + "_objFlags": 0, + "_parent": { + "__id__": 1 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 17 + } + ], + "_prefab": { + "__id__": 18 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 255, + "b": 255, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 409, + "height": 181 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 358.832, + 252.058, + 0, + 0, + 0, + 0, + 1, + 0.4, + 0.4, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Sprite", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 16 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, + "_spriteFrame": { + "__uuid__": "ec17e0d0-40d0-4c58-9a3c-c1c7857359a7" + }, + "_type": 0, + "_sizeMode": 1, + "_fillType": 0, + "_fillCenter": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_fillStart": 0, + "_fillRange": 0, + "_isTrimmedMode": true, + "_atlas": null, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 1 + }, + "asset": { + "__id__": 0 + }, + "fileId": "cfsnsWNhJB0p0r/wjHGGAd", + "sync": false + }, { "__type__": "cc.Node", "_name": "guanbi", @@ -584,20 +694,20 @@ }, "_children": [ { - "__id__": 17 + "__id__": 20 } ], "_active": true, "_components": [ { - "__id__": 20 + "__id__": 23 }, { - "__id__": 21 + "__id__": 24 } ], "_prefab": { - "__id__": 23 + "__id__": 26 }, "_opacity": 255, "_color": { @@ -651,17 +761,17 @@ "_name": "New Sprite", "_objFlags": 0, "_parent": { - "__id__": 16 + "__id__": 19 }, "_children": [], "_active": true, "_components": [ { - "__id__": 18 + "__id__": 21 } ], "_prefab": { - "__id__": 19 + "__id__": 22 }, "_opacity": 255, "_color": { @@ -715,7 +825,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 17 + "__id__": 20 }, "_enabled": true, "_materials": [ @@ -758,7 +868,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 16 + "__id__": 19 }, "_enabled": false, "alignMode": 1, @@ -785,7 +895,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 16 + "__id__": 19 }, "_enabled": true, "_normalMaterial": null, @@ -794,7 +904,7 @@ "zoomScale": 1.2, "clickEvents": [ { - "__id__": 22 + "__id__": 25 } ], "_N$interactable": true, @@ -850,7 +960,7 @@ "hoverSprite": null, "_N$disabledSprite": null, "_N$target": { - "__id__": 16 + "__id__": 19 }, "_id": "" }, @@ -884,16 +994,16 @@ }, "_children": [ { - "__id__": 25 + "__id__": 28 }, { - "__id__": 28 + "__id__": 31 } ], "_active": false, "_components": [], "_prefab": { - "__id__": 33 + "__id__": 36 }, "_opacity": 255, "_color": { @@ -947,17 +1057,17 @@ "_name": "New Sprite", "_objFlags": 0, "_parent": { - "__id__": 24 + "__id__": 27 }, "_children": [], "_active": true, "_components": [ { - "__id__": 26 + "__id__": 29 } ], "_prefab": { - "__id__": 27 + "__id__": 30 }, "_opacity": 255, "_color": { @@ -1011,7 +1121,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 25 + "__id__": 28 }, "_enabled": true, "_materials": [ @@ -1054,20 +1164,20 @@ "_name": "30yuan", "_objFlags": 0, "_parent": { - "__id__": 24 + "__id__": 27 }, "_children": [], "_active": true, "_components": [ { - "__id__": 29 + "__id__": 32 }, { - "__id__": 30 + "__id__": 33 } ], "_prefab": { - "__id__": 32 + "__id__": 35 }, "_opacity": 255, "_color": { @@ -1121,7 +1231,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 28 + "__id__": 31 }, "_enabled": true, "_materials": [ @@ -1153,7 +1263,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 28 + "__id__": 31 }, "_enabled": true, "_normalMaterial": null, @@ -1162,7 +1272,7 @@ "zoomScale": 1.1, "clickEvents": [ { - "__id__": 31 + "__id__": 34 } ], "_N$interactable": true, @@ -1218,7 +1328,7 @@ "hoverSprite": null, "_N$disabledSprite": null, "_N$target": { - "__id__": 28 + "__id__": 31 }, "_id": "" }, @@ -1263,19 +1373,19 @@ }, "_children": [ { - "__id__": 35 - }, - { - "__id__": 37 + "__id__": 38 }, { "__id__": 40 + }, + { + "__id__": 43 } ], "_active": false, "_components": [], "_prefab": { - "__id__": 45 + "__id__": 48 }, "_opacity": 255, "_color": { @@ -1329,13 +1439,13 @@ "_name": "time", "_objFlags": 0, "_parent": { - "__id__": 34 + "__id__": 37 }, "_children": [], "_active": true, "_components": [], "_prefab": { - "__id__": 36 + "__id__": 39 }, "_opacity": 255, "_color": { @@ -1400,17 +1510,17 @@ "_name": "New Sprite", "_objFlags": 0, "_parent": { - "__id__": 34 + "__id__": 37 }, "_children": [], "_active": true, "_components": [ { - "__id__": 38 + "__id__": 41 } ], "_prefab": { - "__id__": 39 + "__id__": 42 }, "_opacity": 255, "_color": { @@ -1464,7 +1574,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 37 + "__id__": 40 }, "_enabled": true, "_materials": [ @@ -1507,20 +1617,20 @@ "_name": "New Sprite", "_objFlags": 0, "_parent": { - "__id__": 34 + "__id__": 37 }, "_children": [], "_active": false, "_components": [ { - "__id__": 41 + "__id__": 44 }, { - "__id__": 42 + "__id__": 45 } ], "_prefab": { - "__id__": 44 + "__id__": 47 }, "_opacity": 255, "_color": { @@ -1574,7 +1684,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 40 + "__id__": 43 }, "_enabled": true, "_materials": [ @@ -1606,7 +1716,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 40 + "__id__": 43 }, "_enabled": true, "_normalMaterial": null, @@ -1615,7 +1725,7 @@ "zoomScale": 1.1, "clickEvents": [ { - "__id__": 43 + "__id__": 46 } ], "_N$interactable": true, @@ -1671,17 +1781,19 @@ "hoverSprite": null, "_N$disabledSprite": null, "_N$target": { - "__id__": 40 + "__id__": 43 }, "_id": "" }, { "__type__": "cc.ClickEvent", - "target": null, + "target": { + "__id__": 1 + }, "component": "", - "_componentId": "", - "handler": "", - "customEventData": "" + "_componentId": "191edqNaKdPtJiA4/cSsB1N", + "handler": "buyProduct", + "customEventData": "month_Card" }, { "__type__": "cc.PrefabInfo", @@ -1714,23 +1826,23 @@ }, "_children": [ { - "__id__": 47 - }, - { - "__id__": 51 + "__id__": 50 }, { "__id__": 54 + }, + { + "__id__": 57 } ], "_active": false, "_components": [ { - "__id__": 57 + "__id__": 60 } ], "_prefab": { - "__id__": 58 + "__id__": 61 }, "_opacity": 255, "_color": { @@ -1784,20 +1896,20 @@ "_name": "New Sprite(Splash)", "_objFlags": 0, "_parent": { - "__id__": 46 + "__id__": 49 }, "_children": [], "_active": true, "_components": [ { - "__id__": 48 + "__id__": 51 }, { - "__id__": 49 + "__id__": 52 } ], "_prefab": { - "__id__": 50 + "__id__": 53 }, "_opacity": 120, "_color": { @@ -1851,7 +1963,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 47 + "__id__": 50 }, "_enabled": true, "_materials": [ @@ -1883,7 +1995,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 47 + "__id__": 50 }, "_enabled": true, "_id": "" @@ -1891,7 +2003,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 46 + "__id__": 49 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -1904,17 +2016,17 @@ "_name": "load", "_objFlags": 0, "_parent": { - "__id__": 46 + "__id__": 49 }, "_children": [], "_active": true, "_components": [ { - "__id__": 52 + "__id__": 55 } ], "_prefab": { - "__id__": 53 + "__id__": 56 }, "_opacity": 255, "_color": { @@ -1968,7 +2080,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 51 + "__id__": 54 }, "_enabled": true, "_materials": [ @@ -1998,7 +2110,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 46 + "__id__": 49 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2011,17 +2123,17 @@ "_name": "New Label", "_objFlags": 0, "_parent": { - "__id__": 46 + "__id__": 49 }, "_children": [], "_active": true, "_components": [ { - "__id__": 55 + "__id__": 58 } ], "_prefab": { - "__id__": 56 + "__id__": 59 }, "_opacity": 255, "_color": { @@ -2075,7 +2187,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 54 + "__id__": 57 }, "_enabled": true, "_materials": [ @@ -2106,7 +2218,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 46 + "__id__": 49 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2119,7 +2231,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 46 + "__id__": 49 }, "_enabled": true, "alignMode": 1, @@ -2144,7 +2256,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 46 + "__id__": 49 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2161,10 +2273,7 @@ }, "_children": [ { - "__id__": 60 - }, - { - "__id__": 64 + "__id__": 63 }, { "__id__": 67 @@ -2177,16 +2286,19 @@ }, { "__id__": 76 + }, + { + "__id__": 79 } ], "_active": false, "_components": [ { - "__id__": 84 + "__id__": 87 } ], "_prefab": { - "__id__": 85 + "__id__": 88 }, "_opacity": 255, "_color": { @@ -2240,20 +2352,20 @@ "_name": "New Sprite(Splash)", "_objFlags": 0, "_parent": { - "__id__": 59 + "__id__": 62 }, "_children": [], "_active": true, "_components": [ { - "__id__": 61 + "__id__": 64 }, { - "__id__": 62 + "__id__": 65 } ], "_prefab": { - "__id__": 63 + "__id__": 66 }, "_opacity": 120, "_color": { @@ -2307,7 +2419,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 60 + "__id__": 63 }, "_enabled": true, "_materials": [ @@ -2339,7 +2451,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 60 + "__id__": 63 }, "_enabled": true, "_id": "" @@ -2347,7 +2459,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2360,17 +2472,17 @@ "_name": "bg", "_objFlags": 0, "_parent": { - "__id__": 59 + "__id__": 62 }, "_children": [], "_active": true, "_components": [ { - "__id__": 65 + "__id__": 68 } ], "_prefab": { - "__id__": 66 + "__id__": 69 }, "_opacity": 255, "_color": { @@ -2424,7 +2536,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 64 + "__id__": 67 }, "_enabled": true, "_materials": [ @@ -2454,7 +2566,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2467,17 +2579,17 @@ "_name": "title", "_objFlags": 0, "_parent": { - "__id__": 59 + "__id__": 62 }, "_children": [], "_active": true, "_components": [ { - "__id__": 68 + "__id__": 71 } ], "_prefab": { - "__id__": 69 + "__id__": 72 }, "_opacity": 255, "_color": { @@ -2531,7 +2643,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 67 + "__id__": 70 }, "_enabled": true, "_materials": [ @@ -2562,7 +2674,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2575,118 +2687,10 @@ "_name": "New Label", "_objFlags": 0, "_parent": { - "__id__": 59 + "__id__": 62 }, "_children": [], "_active": false, - "_components": [ - { - "__id__": 71 - } - ], - "_prefab": { - "__id__": 72 - }, - "_opacity": 255, - "_color": { - "__type__": "cc.Color", - "r": 255, - "g": 0, - "b": 0, - "a": 255 - }, - "_contentSize": { - "__type__": "cc.Size", - "width": 320, - "height": 195.6 - }, - "_anchorPoint": { - "__type__": "cc.Vec2", - "x": 0.5, - "y": 0.5 - }, - "_trs": { - "__type__": "TypedArray", - "ctor": "Float64Array", - "array": [ - 0, - 89.865, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1 - ] - }, - "_eulerAngles": { - "__type__": "cc.Vec3", - "x": 0, - "y": 0, - "z": 0 - }, - "_skewX": 0, - "_skewY": 0, - "_is3DNode": false, - "_groupIndex": 0, - "groupIndex": 0, - "_id": "" - }, - { - "__type__": "cc.Label", - "_name": "", - "_objFlags": 0, - "node": { - "__id__": 70 - }, - "_enabled": true, - "_materials": [ - { - "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" - } - ], - "_srcBlendFactor": 770, - "_dstBlendFactor": 771, - "_string": "网络异常\n请重新登录小游戏\n领取充值奖励", - "_N$string": "网络异常\n请重新登录小游戏\n领取充值奖励", - "_fontSize": 40, - "_lineHeight": 60, - "_enableWrapText": true, - "_N$file": null, - "_isSystemFontUsed": true, - "_spacingX": 0, - "_batchAsBitmap": false, - "_styleFlags": 0, - "_underlineHeight": 0, - "_N$horizontalAlign": 1, - "_N$verticalAlign": 1, - "_N$fontFamily": "Arial", - "_N$overflow": 0, - "_N$cacheMode": 0, - "_id": "" - }, - { - "__type__": "cc.PrefabInfo", - "root": { - "__id__": 59 - }, - "asset": { - "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" - }, - "fileId": "9149ix6q1AZ4VyIjmSGbdM", - "sync": false - }, - { - "__type__": "cc.Node", - "_name": "New Label", - "_objFlags": 0, - "_parent": { - "__id__": 59 - }, - "_children": [], - "_active": true, "_components": [ { "__id__": 74 @@ -2757,6 +2761,114 @@ ], "_srcBlendFactor": 770, "_dstBlendFactor": 771, + "_string": "网络异常\n请重新登录小游戏\n领取充值奖励", + "_N$string": "网络异常\n请重新登录小游戏\n领取充值奖励", + "_fontSize": 40, + "_lineHeight": 60, + "_enableWrapText": true, + "_N$file": null, + "_isSystemFontUsed": true, + "_spacingX": 0, + "_batchAsBitmap": false, + "_styleFlags": 0, + "_underlineHeight": 0, + "_N$horizontalAlign": 1, + "_N$verticalAlign": 1, + "_N$fontFamily": "Arial", + "_N$overflow": 0, + "_N$cacheMode": 0, + "_id": "" + }, + { + "__type__": "cc.PrefabInfo", + "root": { + "__id__": 62 + }, + "asset": { + "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" + }, + "fileId": "9149ix6q1AZ4VyIjmSGbdM", + "sync": false + }, + { + "__type__": "cc.Node", + "_name": "New Label", + "_objFlags": 0, + "_parent": { + "__id__": 62 + }, + "_children": [], + "_active": true, + "_components": [ + { + "__id__": 77 + } + ], + "_prefab": { + "__id__": 78 + }, + "_opacity": 255, + "_color": { + "__type__": "cc.Color", + "r": 255, + "g": 0, + "b": 0, + "a": 255 + }, + "_contentSize": { + "__type__": "cc.Size", + "width": 320, + "height": 195.6 + }, + "_anchorPoint": { + "__type__": "cc.Vec2", + "x": 0.5, + "y": 0.5 + }, + "_trs": { + "__type__": "TypedArray", + "ctor": "Float64Array", + "array": [ + 0, + 89.865, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1 + ] + }, + "_eulerAngles": { + "__type__": "cc.Vec3", + "x": 0, + "y": 0, + "z": 0 + }, + "_skewX": 0, + "_skewY": 0, + "_is3DNode": false, + "_groupIndex": 0, + "groupIndex": 0, + "_id": "" + }, + { + "__type__": "cc.Label", + "_name": "", + "_objFlags": 0, + "node": { + "__id__": 76 + }, + "_enabled": true, + "_materials": [ + { + "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" + } + ], + "_srcBlendFactor": 770, + "_dstBlendFactor": 771, "_string": "网络异常\n请检查网络连接后\n再次领取", "_N$string": "网络异常\n请检查网络连接后\n再次领取", "_fontSize": 40, @@ -2778,7 +2890,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2791,24 +2903,24 @@ "_name": "New Sprite", "_objFlags": 0, "_parent": { - "__id__": 59 + "__id__": 62 }, "_children": [ { - "__id__": 77 + "__id__": 80 } ], "_active": true, "_components": [ { - "__id__": 80 + "__id__": 83 }, { - "__id__": 81 + "__id__": 84 } ], "_prefab": { - "__id__": 83 + "__id__": 86 }, "_opacity": 255, "_color": { @@ -2862,17 +2974,17 @@ "_name": "New Label", "_objFlags": 0, "_parent": { - "__id__": 76 + "__id__": 79 }, "_children": [], "_active": true, "_components": [ { - "__id__": 78 + "__id__": 81 } ], "_prefab": { - "__id__": 79 + "__id__": 82 }, "_opacity": 255, "_color": { @@ -2926,7 +3038,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 77 + "__id__": 80 }, "_enabled": true, "_materials": [ @@ -2957,7 +3069,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -2970,7 +3082,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 76 + "__id__": 79 }, "_enabled": true, "_materials": [ @@ -3002,7 +3114,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 76 + "__id__": 79 }, "_enabled": true, "_normalMaterial": null, @@ -3011,7 +3123,7 @@ "zoomScale": 1.1, "clickEvents": [ { - "__id__": 82 + "__id__": 85 } ], "_N$interactable": true, @@ -3067,7 +3179,7 @@ "hoverSprite": null, "_N$disabledSprite": null, "_N$target": { - "__id__": 76 + "__id__": 79 }, "_id": "" }, @@ -3084,7 +3196,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -3097,7 +3209,7 @@ "_name": "", "_objFlags": 0, "node": { - "__id__": 59 + "__id__": 62 }, "_enabled": true, "alignMode": 1, @@ -3122,7 +3234,7 @@ { "__type__": "cc.PrefabInfo", "root": { - "__id__": 59 + "__id__": 62 }, "asset": { "__uuid__": "9fdc6671-8422-410b-b9af-36dab20f1488" @@ -3166,13 +3278,13 @@ }, "_enabled": true, "monthCardTime": { - "__id__": 35 + "__id__": 38 }, "monthCardBtn": { - "__id__": 28 + "__id__": 31 }, "monthCardBtn2": { - "__id__": 34 + "__id__": 37 }, "_id": "" }, diff --git a/assets/shop/script/passCheck.ts b/assets/shop/script/passCheck.ts index 1239cea7..d61c3c9d 100644 --- a/assets/shop/script/passCheck.ts +++ b/assets/shop/script/passCheck.ts @@ -600,7 +600,9 @@ export default class passCheck extends cc.Component { console.log("错误原因:", res.errMsg); if (res.errMsg && res.errMsg.indexOf("fail App Store") !== -1) { console.log("走ios旧支付"); - this.iosOldPay(price, productId); + setTimeout(() => { + this.iosOldPay(price, productId); + }, 500); return; } MiniGameSdk.API.showToast("充值失败"); diff --git a/assets/shop/script/shop.ts b/assets/shop/script/shop.ts index 9a7204eb..4052f195 100644 --- a/assets/shop/script/shop.ts +++ b/assets/shop/script/shop.ts @@ -629,7 +629,9 @@ export default class NewClass extends cc.Component { console.log("错误原因:", res.errMsg); if (res.errMsg && res.errMsg.indexOf("fail App Store") !== -1) { console.log("走ios旧支付"); - this.iosOldPay(price, productId); + setTimeout(() => { + this.iosOldPay(price, productId); + }, 500); return; } MiniGameSdk.API.showToast("充值失败"); @@ -891,7 +893,7 @@ export default class NewClass extends cc.Component { this.iosPrice = price; this.iosProductId = productId; this.iosCount = 1; - console.log("准备跳客服回话:"); + console.log("准备跳客服回话:", iosPayInfo); console.log(this.iosProductId); Utils.GoKEFu(iosPayInfo, (res) => { if (res == "success") { diff --git a/server/laf-cloud/functions/CDNKey.ts b/server/laf-cloud/functions/CDNKey.ts new file mode 100644 index 00000000..7c5ee5f7 --- /dev/null +++ b/server/laf-cloud/functions/CDNKey.ts @@ -0,0 +1,10 @@ +import cloud from '@lafjs/cloud' +const key:string="1.0.0"; +const testkey:string="1.0.0"; +export default async function (ctx: FunctionContext) { + const uid=ctx.body.uid; + if([].includes(uid)){ + return testkey; + } + return key; +} \ No newline at end of file diff --git a/server/laf-cloud/functions/CDNKey.yaml b/server/laf-cloud/functions/CDNKey.yaml new file mode 100644 index 00000000..42201692 --- /dev/null +++ b/server/laf-cloud/functions/CDNKey.yaml @@ -0,0 +1,6 @@ +name: CDNKey +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/TokenMgr.ts b/server/laf-cloud/functions/TokenMgr.ts new file mode 100644 index 00000000..61deda67 --- /dev/null +++ b/server/laf-cloud/functions/TokenMgr.ts @@ -0,0 +1,70 @@ +import cloud from '@lafjs/cloud'; +import * as crypto from 'crypto'; +const appid = 'wxdd145ced49158a1e'; // 微信小程序 AppId +const appsecret = '7f295245ffc4884b03306c64e30654db'; // 微信小程序 AppSecret + +const appid1 = "wxe69a671ea2c93af3"; // 广告微信小程序 AppId +const appsecret1 = '1eef42cd8810024eaea6dac961f9b3b0'; // 广告微信小程序 AppSecret +//定时获取Token +export default async function (ctx: FunctionContext) { + let res = await getWxToken(); + let res1= await getWxToken1(); + return { res: res } +} + +/**获取微信Token*/ +async function getWxToken() { + const api_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${appsecret}`; + const ret = await cloud.fetch({ + url: api_url, + method: "get", + }); + if (ret?.data?.access_token) { + cloud.shared.set('wxaccess_token', ret.data.access_token); + return ret.data.access_token; + } else { + //access_token = null; + return null; + } +} +/**获取广告版本token*/ +async function getWxToken1() { + const api_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid1}&secret=${appsecret1}`; + const ret = await cloud.fetch({ + url: api_url, + method: "get", + }); + if (ret?.data?.access_token) { + //console.log(ret.data.access_token); + cloud.shared.set('wxaccess_token1', ret.data.access_token); + PostToken(ret.data.access_token) + return ret.data.access_token; + } else { + //access_token = null; + return null; + } +} + +async function PostToken(wxToken) { + const token =`ZxCKV476ksJvu9j2bnqQIelYNeHP0XWz`; + const url = `https://backend.gravity-engine.com/event_center/api/v1/base/wx/access_token/refresh/?access_token=${token}`; + const time=Math.floor(Date.now()/1000); + const appkey =`zKUewiWbjqpbn7jzvrmPvhygftARptfwBxco69kXOsLuJnQrSDe5HgdYF0hEqNxk`; + const str: string = `app_key=${appkey}&wx_access_token=${wxToken}¤t_time=${time}`; + const sign: string = crypto.createHash('md5').update(str).digest('hex').toLowerCase(); + const data = { + "wx_access_token": wxToken, + "current_time": time, + "sign": sign + } + const res = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }) + const token1 = await res.json() + //console.log(data11); + return "ok" +} \ No newline at end of file diff --git a/server/laf-cloud/functions/TokenMgr.yaml b/server/laf-cloud/functions/TokenMgr.yaml new file mode 100644 index 00000000..9435f0b9 --- /dev/null +++ b/server/laf-cloud/functions/TokenMgr.yaml @@ -0,0 +1,6 @@ +name: TokenMgr +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/Utils.ts b/server/laf-cloud/functions/Utils.ts new file mode 100644 index 00000000..960bd12b --- /dev/null +++ b/server/laf-cloud/functions/Utils.ts @@ -0,0 +1,13 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +export default class Utils { + static checkToken(token,token1){ + if(token==token1){ + //console.error("校验成功") + return true; + }else{ + //console.log("校验不成攻:"+token,token1) + return false; + } + } +} diff --git a/server/laf-cloud/functions/Utils.yaml b/server/laf-cloud/functions/Utils.yaml new file mode 100644 index 00000000..970276f7 --- /dev/null +++ b/server/laf-cloud/functions/Utils.yaml @@ -0,0 +1,6 @@ +name: Utils +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/__init__.ts b/server/laf-cloud/functions/__init__.ts new file mode 100644 index 00000000..ea556242 --- /dev/null +++ b/server/laf-cloud/functions/__init__.ts @@ -0,0 +1,6 @@ +import cloud from '@lafjs/cloud' + +export default async function (ctx: FunctionContext) { + // var teSDK = ThinkingData.initWithLoggingMode('LOG_DIRECTORY'); + // console.log(teSDK); +} diff --git a/server/laf-cloud/functions/__init__.yaml b/server/laf-cloud/functions/__init__.yaml new file mode 100644 index 00000000..5a548b75 --- /dev/null +++ b/server/laf-cloud/functions/__init__.yaml @@ -0,0 +1,6 @@ +name: __init__ +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/address.ts b/server/laf-cloud/functions/address.ts new file mode 100644 index 00000000..94e80940 --- /dev/null +++ b/server/laf-cloud/functions/address.ts @@ -0,0 +1,127 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + const address = ctx.body.address; + let dbname = "users"; + const gameName = ctx.body.gameName; + let db1 = "691093093cf0c4532ba4fd9c"; + if (gameName == "iaa") { + dbname = "usersAd"; + db1 = "691097ac3cf0c4532ba4fd9e"; + } + let ret1 = await db.collection(dbname).where({ _id: uid }).getOne(); + let oldAddress=ret1.data.address; + if(address==oldAddress){ + return; + } + const token1 = ctx.body.token; + if (ret1.data && ret1.data.token) { + let istoken = Utils.checkToken(token1, ret1.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let ret = await db.collection(dbname).where({ _id: uid }).update({ address:address}); + if(ret1.data.isWhite==false){ + let res = await rank(db1, uid, ret1, oldAddress, address); + } + + return {code:1,data:{address:address},msg:"ok"} +} + +async function rank(db1,uid,res1,oldaddress,address) { + let add = res1.data.addLevel; + if (add < 5) { + return; + } + let rankInfo = await db.collection("sRank").where({ _id: db1 }).getOne(); + let total = rankInfo.data.total; + if (total != null) { + total = JSON.parse(total); + } else { + total = {}; + } + if(total[oldaddress]){ + for (let i = 0; i < total[oldaddress].length; i++) { + if (total[oldaddress][i].id == uid) { + total[oldaddress].splice(i, 1) + } + } + } + if (total[address]) { + let isHave = false; + for (let i = 0; i < total[address].length; i++) { + if (total[address][i].id == uid) { + isHave = true; + break; + } + } + if (isHave == false) { + let length = total[address].length; + if (length < 10 || add > total[address][length - 1].addLevel) { + total[address].push({ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: res1.data?.levelAmount + }); + } + } + } else { + total[address] = [{ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: res1.data?.levelAmount + }]; + } + total[address].sort((a, b) => { + if (a.addLevel !== b.addLevel) { + return b.addLevel - a.addLevel; + } + return a.time - b.time; + }); + if (total[address].length >= 10) { + total[address] = total[address].slice(0, 10); + } + if (!total["role"]) { + total["role"] = {}; + } + if (total["role"][oldaddress]>0){ + total["role"][oldaddress] -= 1; + let length = total[oldaddress]?.length||0; + if (length < 10) { + total["role"][oldaddress] = length; + } + } + if (!total["role"][address]) { + total["role"][address] = 1; + } else { + total["role"][address] += 1; + let length = total[address]?.length||0; + if (length < 10) { + total["role"][address] = length; + }; + } + //console.log(address); + let ret1 = await db.collection("sRank").where({ _id: db1 }).update({ total: JSON.stringify(total) }); + let rank = -1; + for (let i = 0; i < total[address].length; i++) { + if (total[address][i].id == uid) { + rank = i + 1; + break; + } + } + return rank; +} \ No newline at end of file diff --git a/server/laf-cloud/functions/address.yaml b/server/laf-cloud/functions/address.yaml new file mode 100644 index 00000000..39c6017b --- /dev/null +++ b/server/laf-cloud/functions/address.yaml @@ -0,0 +1,6 @@ +name: address +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/canRebornGift.ts b/server/laf-cloud/functions/canRebornGift.ts new file mode 100644 index 00000000..79c3707e --- /dev/null +++ b/server/laf-cloud/functions/canRebornGift.ts @@ -0,0 +1,41 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let uid = ctx.body.uid; + if (!uid) { + return { code: 0, data: null, msg: "参数错误" }; + } + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (res.data == null) { + return { code: 0, data: null, msg: "未获取到玩家数据" }; + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let rebornGiftTime = res.data.rebornGiftTime || 0; + let rebornGiftCount = res.data.rebornGiftCount || 0; + let times = getTodayStartTimestamp(); + if (rebornGiftTime < times) { + rebornGiftCount = 0; + } + if (rebornGiftCount >= 1) { + return { code: 0, data: null, msg: "今天购买次数已用完" }; + } + db.collection(dbname).where({ _id: uid }).update({ rebornGiftTime: rebornGiftTime, rebornGiftCount: rebornGiftCount }); + return { code: 1, data: { rebornGiftTime: rebornGiftTime, rebornGiftCount: rebornGiftCount }, msg: "可以购买" }; +} +function getTodayStartTimestamp() { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} \ No newline at end of file diff --git a/server/laf-cloud/functions/canRebornGift.yaml b/server/laf-cloud/functions/canRebornGift.yaml new file mode 100644 index 00000000..de0150cd --- /dev/null +++ b/server/laf-cloud/functions/canRebornGift.yaml @@ -0,0 +1,6 @@ +name: canRebornGift +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/clearPHBDataById.ts b/server/laf-cloud/functions/clearPHBDataById.ts new file mode 100644 index 00000000..eb75460c --- /dev/null +++ b/server/laf-cloud/functions/clearPHBDataById.ts @@ -0,0 +1,23 @@ +import cloud from '@lafjs/cloud' +const db=cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let db1 = "691093093cf0c4532ba4fd9c"; + const uid=ctx.body.uid; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + db1 = "691097ac3cf0c4532ba4fd9e"; + } + let rankInfo = await db.collection("sRank").where({ _id: db1 }).getOne(); + let total = JSON.parse(rankInfo.data.total); + for(var key in total){ + for(let i=0;i=3){ + return { + code: 0, data: null, msg: "评论数已达上限" + } + } + for(let i=0;i5){ + let list1=[]; + for (let i = 0; i < comment.length; i++) { + if (comment[i].like > max) { + index1 = i; + max = comment[i].like; + } + } + list1.push(index1); + if(comment.length>50){ + while(list1.length<5){ + let index2=Math.floor(Math.random()*comment.length); + if(!list1.includes(index2)){ + list1.push(index2); + } + } + }else{ + let m=comment.length-1; + while(list1.length<5){ + if(!list1.includes(m)){ + list1.push(m); + m--; + } + } + } + for(let i=0;i taskTime) { + for (var key in task) { + task[key].value = 0; + task[key].state = 0; + } + } + switch (action) { + case 'save': + let task1 = ctx.body.task; + if (!task1) { + return { code: 0, data: null, msg: "请输入task数据" }; + } + task1 = JSON.parse(task1); + for (var key in task) { + task[key].value = task1[key].value; + } + for (var key in task) { + if (task[key].state == 0) { + if (task[key].value >= task[key].target) { + task[key].state = 1; + } + } + } + await db.collection(dbname).where({ _id: uid }).update({ task: JSON.stringify(task), taskTime: Date.now() + 8 * 3600000 }); + return { code: 1, data: { task: task }, msg: "用户数据更新成功" } + case 'read': + for (var key in task) { + if (!task[key].state) { + task[key].state = 0; + } + if (task[key].state != 2) { + if (task[key].value >= task[key].target) { + task[key].state = 1; + } + } + + } + return { code: 1, data: { task: task }, msg: "成功" } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } + +} diff --git a/server/laf-cloud/functions/dayTaskInfo.yaml b/server/laf-cloud/functions/dayTaskInfo.yaml new file mode 100644 index 00000000..9eda780f --- /dev/null +++ b/server/laf-cloud/functions/dayTaskInfo.yaml @@ -0,0 +1,6 @@ +name: dayTaskInfo +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/drawHead.ts b/server/laf-cloud/functions/drawHead.ts new file mode 100644 index 00000000..0a8943c0 --- /dev/null +++ b/server/laf-cloud/functions/drawHead.ts @@ -0,0 +1,111 @@ +import cloud from '@lafjs/cloud'; +import Utils from "@/Utils"; +const db = cloud.database(); +const level1 = [19, 20, 21, 22, 23]; +const level2 = [24, 25]; +const level3 = [26]; +/**头像抽卡 */ +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (!res.data) { + return { + code: 0, data: null, msg: "未获取到玩家信息" + } + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let film = res.data.film; + if (!film && film != 0) { + film = res.data.levelAmount; + } + + let headArr = res.data.headArr; + if (!headArr) { + headArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] ]; + } + + + let list1 = []; + let list2 = []; + let list3 = []; + for (let i = 0; i < level1.length; i++) { + if (!headArr.includes(level1[i])) { + list1.push(level1[i]); + } + } + for (let i = 0; i < level2.length; i++) { + if (!headArr.includes(level2[i])) { + list2.push(level2[i]); + } + } + for (let i = 0; i < level3.length; i++) { + if (!headArr.includes(level3[i])) { + list3.push(level3[i]); + } + } + let total = list1.length * 150 + list2.length * 50 + list3.length * 8; + if (total == 0) { + return { code: 0, data: null, msg: "已抽取所有头像" } + } + + let totalCount = level1.length + level2.length + level3.length; + // 计算 + let count = totalCount - (list1.length + list2.length + list3.length); + // 阶梯消耗表:索引0对应消耗5,索引1对应消耗10,以此类推 + let filmConsumeTable = [5, 10, 25, 35, 55, 70, 100, 120]; + + // 根据数量获取对应的消耗,数量超过7时取最后一个(120) + let filmCost = filmConsumeTable[Math.min(count, 7)]; + + film = Number(film) || 0; + if (film < filmCost) { + return { code: 0, data: { film: film, cost: filmCost }, msg: "代币不足,闯关获取更多代币!" } + } + // 检查通过后再扣除,余额始终以服务端数据为准。 + film -= filmCost; + + let num = Math.floor(Math.random() * total); + let list = []; + if (num < list1.length * 150) { + list = list1; + } else if (num < list1.length * 150 + list2.length * 50) { + list = list2; + } else { + list = list3; + } + let num2 = Math.floor(Math.random() * list.length); + if (list[num2] == 26) { + for (let i = 0; i < level1.length; i++) { + if (!headArr.includes(level1[i])) { + headArr.push(level1[i]); + } + } + for (let i = 0; i < level2.length; i++) { + if (!headArr.includes(level2[i])) { + headArr.push(level2[i]); + } + } + for (let i = 0; i < level3.length; i++) { + if (!headArr.includes(level3[i])) { + headArr.push(level3[i]); + } + } + } else { + if (!headArr.includes(list[num2])) { + headArr.push(list[num2]); + } + } + await db.collection(dbname).where({ _id: uid }).update({ headArr: headArr, film: film }); + return { code: 1, data: { headArr: headArr, reward: list[num2], film: film }, msg: "成功" }; +} diff --git a/server/laf-cloud/functions/drawHead.yaml b/server/laf-cloud/functions/drawHead.yaml new file mode 100644 index 00000000..60d2aed5 --- /dev/null +++ b/server/laf-cloud/functions/drawHead.yaml @@ -0,0 +1,6 @@ +name: drawHead +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/getAddressRank.ts b/server/laf-cloud/functions/getAddressRank.ts new file mode 100644 index 00000000..009650a1 --- /dev/null +++ b/server/laf-cloud/functions/getAddressRank.ts @@ -0,0 +1,12 @@ +import cloud from '@lafjs/cloud' +const db=cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const address=ctx.body.address; + const res3 = await db.collection("sRank").where({ name: address }).getOne(); + // if(!res3.data?.totoal){ + // console.log("获取排行榜失败:"+address); + // console.log(res3.data); + // } + return {code:1,data:res3.data?.totoal,msg:"ok"} +} diff --git a/server/laf-cloud/functions/getAddressRank.yaml b/server/laf-cloud/functions/getAddressRank.yaml new file mode 100644 index 00000000..d503acb4 --- /dev/null +++ b/server/laf-cloud/functions/getAddressRank.yaml @@ -0,0 +1,6 @@ +name: getAddressRank +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/getFilm.ts b/server/laf-cloud/functions/getFilm.ts new file mode 100644 index 00000000..3642d7c1 --- /dev/null +++ b/server/laf-cloud/functions/getFilm.ts @@ -0,0 +1,33 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +import Utils from "@/Utils"; +const level1 = [19, 20, 21, 22, 23]; +const level2 = [24, 25]; +const level3 = [26]; +/**获取代币 */ +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (!res.data) { + return { + code: 0, data: null, msg: "未获取到玩家信息" + } + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let film = res.data.film; + if (!film && film != 0) { + film = res.data.levelAmount; + } + return { code: 1, data: { film: film }, msg: "成功" }; +} diff --git a/server/laf-cloud/functions/getFilm.yaml b/server/laf-cloud/functions/getFilm.yaml new file mode 100644 index 00000000..882203be --- /dev/null +++ b/server/laf-cloud/functions/getFilm.yaml @@ -0,0 +1,6 @@ +name: getFilm +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/getHeadInfo.ts b/server/laf-cloud/functions/getHeadInfo.ts new file mode 100644 index 00000000..869e348f --- /dev/null +++ b/server/laf-cloud/functions/getHeadInfo.ts @@ -0,0 +1,42 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +import Utils from "@/Utils"; +const level1 = [18, 19, 20, 21, 22]; +const level2 = [23, 24]; +const level3 = [25]; +/**头像抽卡 */ +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (!res.data) { + return { + code: 0, data: null, msg: "未获取到玩家信息" + } + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let headArr = res.data.headArr; + if (!headArr) { + headArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] ]; + } + let film = res.data.film; + if (!film && film != 0) { + film = res.data.levelAmount; + } + + return { code: 1, data: { headArr: headArr, film: film }, msg: "成功" }; + // if(res.data.isWhite){ + // return { code: 1, data: { headArr: headArr, film: film }, msg: "成功" }; + // } + // else return { code: 1, data: { headArr: headArr}, msg: "成功" }; +} diff --git a/server/laf-cloud/functions/getHeadInfo.yaml b/server/laf-cloud/functions/getHeadInfo.yaml new file mode 100644 index 00000000..83f86646 --- /dev/null +++ b/server/laf-cloud/functions/getHeadInfo.yaml @@ -0,0 +1,6 @@ +name: getHeadInfo +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/getRank.ts b/server/laf-cloud/functions/getRank.ts new file mode 100644 index 00000000..1f901bf7 --- /dev/null +++ b/server/laf-cloud/functions/getRank.ts @@ -0,0 +1,38 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let uid=ctx.body.uid; + const gameName = ctx.body.gameName; + let res1; + if (gameName == "iaa") { + res1 = await db.collection("rank").where({ _id: "68e92b7835004ffb5ab9ee89" }).getOne(); + }else{ + res1 = await db.collection("rank").where({ _id: "689db6c5cc79706182bd6a9f" }).getOne(); + } + let rank=JSON.parse(res1.data.rank) + let list=[]; + if(rank.length<200){ + list=rank; + }else{ + for (let i = 0; i < 200; i++) { + // if(rank[i].useravatar==""){ + // rank[i].useravatar=Math.floor(Math.random()*4)+""; + // } + list.push(rank[i]); + } + } + + let index=-1; + for(let i=0;i taskTime) { + for (var key in task) { + task[key].value = 0; + task[key].state = 0; + } + } + await db.collection(dbname).where({ _id: userData._id }).update({ session_key: session_key, distinctId: distinctId, isDebug: isDebug, isFirst: false, unionid: unionid, task: JSON.stringify(task), taskTime: Date.now() + 8 * 3600000, token: token }); + } + if (userData?.freeze) { + return { code: 0, data: "账号封禁", msg: "账号封禁" }; + } + await delayExecution(0.1); + userData = await getUserData(dbname, openid); + let res = null; + if (userData.openid) { + res = await db.collection("order").where({ state: 1, openid: userData.openid }).get(); + } + let outTradeNo: any = []; + if (res.data && res.data.length > 0) { + for (let i = 0; i < res.data.length; i++) { + outTradeNo.push(res.data[i]); + } + } + if (dbname == "users") { + let ret = await getIosOrder(userData.openid, ctx); + outTradeNo = outTradeNo.concat(ret); + userData.outTradeNo = outTradeNo; + } + + if (!userData.onlyId) { + let ref = await db.collection("idcount").field({ count: 1 }).where({ _id: idname }).getOne(); + await db.collection("idcount").where({ _id: idname }).update({ count: ref.data.count + 1 }); + userData.onlyId = ref.data.count; + await db.collection(dbname).where({ _id: userData._id }).update({ session_key: session_key, onlyId: ref.data.count }); + } + let share = userData.shareLv; + if (share) { + userData.shareLv = JSON.parse(share); + } else { + userData.shareLv = []; + } + userData.careerAmount = userData.careerAmount || 0; + let rebornGiftTime = userData?.rebornGiftTime || 0; + let times = getTodayStartTimestamp(); + if (rebornGiftTime < times) { + userData.rebornGiftCount = 0; + } + if (userData.isWhite && !userData.film && userData.film != 0) { + userData.film = userData.levelAmount; + } + userData.canIos = canIos; + userData.version = version; + //console.log(userData) + //console.log("查询时间:"); + return { code: 1, data: userData } +} +function stringToHash(input: string, algorithm: 'sha1' | 'sha256' | 'sha512' = 'sha256'): string { + return createHash(algorithm).update(input).digest('hex'); +} +function getTodayUTCMidnightTimestamp(): number { + const now = new Date(); + // 1. 获取当前 UTC 时间 + const utcMidnight = Date.UTC( + now.getUTCFullYear(), + now.getUTCMonth(), + now.getUTCDate(), + 0, 0, 0, 0 + ); + // 2. 加上 8 小时(北京时间 = UTC+8) + return utcMidnight + 8 * 60 * 60 * 1000; +} +const getClientIp = (req) => { + return ( + req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP + req.headers['x-real-ip'] || // Nginx 配置的 real-ip + req.socket.remoteAddress // 原始 IP(可能是代理) + ); +}; + +const propName = { + "金币包1": "gold_1", + "金币包2": "gold_2", + "金币包3": "gold_3", + "金币包4": "gold_4", + "金币包5": "gold_5", + "金币包6": "gold_6", + "无限体力组合包1": "unlimited_health_bundle_1", + "无限体力组合包2": "unlimited_health_bundle_2", + "无限体力组合包3": "unlimited_health_bundle_3", + "局内购买冻结": "freeze_in_game", + "局内购买锤子": "hammer_in_game", + "局内购买魔棒": "wand_in_gamerefill", + "补满体力": "health" +}; + +function getTodayStartTimestamp() { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} +async function getWXOpenId(code, dbname) { + let appid = "wxdd145ced49158a1e"; + let appsecret = "7f295245ffc4884b03306c64e30654db"; + if (dbname == "usersAd") { + appid = "wxe69a671ea2c93af3"; + appsecret = "1eef42cd8810024eaea6dac961f9b3b0"; + } + const api_url = `https://api.weixin.qq.com/sns/jscode2session`; + const param = `appid=${appid}&secret=${appsecret}&js_code=${code}&grant_type=authorization_code`; + let res = null; + try { + res = await cloud.fetch(`${api_url}?${param}`, { + headers: { + "Accept-Encoding": 'gzip' + } + }); + } catch { + + } + + + if (res == null || res.data.errcode > 0) { + return null + } + //console.log(res.data); + return [res?.data?.openid, res?.data?.session_key, res?.data?.unionid] +} +/**获取当前用户数据 */ +async function getUserData(dbname: string, openid: any, isFirst?) { + let { data } = await db.collection(dbname).where({ openid: openid }).get(); + if (data.length) { + return data[0]; + } + return null; +} + +async function delayExecution(seconds: number) { + return new Promise((resolve) => { + setTimeout(() => { + // 在这里编写需要延时执行的代码 + resolve("延时执行完成"); + }, seconds * 1000); + }); +} +async function getIosOrder(openid, ctx) { + let res = await db.collection("order").where({ state: 0, type: "ios", openid: openid }).get(); + let res1 = await db.collection("users").where({ openid: openid }).getOne(); + let list = []; + if (res.data.length > 0) { + for (let i = 0; i < res.data.length; i++) { + let ret = await getOrder(res.data[i].outTradeNo); + if (ret.trade_state == "SUCCESS") { + list.push(res.data[i]); + sead(res.data[i], res1.data, getClientIp(ctx)); + switch (res.data[i].itemid) { + case "month_Card": + const latestUser = await db.collection("users").where({ _id: res1.data._id }).getOne(); + const now = Date.now(); + const oldMonthCardTime = Number(latestUser.data?.monthCardTime) || 0; + const monthCardTime = Math.max(oldMonthCardTime, now) + 2592000000; + const monthCardReward = oldMonthCardTime > now ? (Number(latestUser.data?.monthCardReward) || 0) : 0; + await db.collection("users").where({ _id: res1.data._id }).update({ monthCardTime: monthCardTime, monthCardReward: monthCardReward, pay_user: true }); + await db.collection("order").where({ outTradeNo: res.data[i].outTradeNo }).update({ monthCardGranted: true }); + break; + case "reborn_Gift": + db.collection("users").where({ _id: res1.data._id }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 1, pay_user: true }); + break; + case "starter_pack": + db.collection("users").where({ _id: res1.data._id }).update({ starter_packState: 1, pay_user: true }); + break; + default: + db.collection("users").where({ _id: res1.data._id }).update({ pay_user: true }); + break; + } + // 月卡补单确认成功后进入待客户端补发状态,避免下次登录重复累计。 + if (res.data[i].itemid === "month_Card") { + await db.collection("order").where({ outTradeNo: res.data[i].outTradeNo }).update({ state: 1 }); + } + } else { + if (Date.now() - res.data[i].time > 3 * 3600000) { + let ret = await db.collection('order').where({ outTradeNo: res.data[i].outTradeNo }).remove({ multi: true }); + } + } + } + } + return list; +} +async function sead(order, userInfo, ip) { + if (!userInfo.distinctId) { + return; + } + let id = '87d18958cea145f29d3265470ecd3486'; + if (userInfo.isDebug != "true") { + id = '121591378fc1423893deb12041413eb3'; + } + let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', { + dryRun: false, // report data to TE or not + deviceId: "123456789",//设备唯一标识 + }); + let trackEvent = { + accountId: order.openid, + distinctId: userInfo.distinctId,//访客id + event: 'payment', + time: new Date(Date.now() + 8 * 3600000), + ip: ip, + properties: { + order_id: order.outTradeNo, + pay_amount: order.goodsPrice, + payment_name: order.itemid, + payment_num: order.itemCount, + payment_type: "ios", + current_level: userInfo.lv, //当前关卡等级 number + current_health: userInfo.healthAmount, //当前体力值 + tmp_coin: userInfo.coinAmount,//当前金币 + version: "1.6", + user_id: userInfo._id, //用户id + pay_user: userInfo.pay_user + }, + callback(e) { + if (e) { + console.log(e); + } + } + }; + teSDK.track(trackEvent); + teSDK.close(); + return; +} +/**获取订单*/ +async function getOrder(outTradeNo) { + const url = `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437`; + const nonceStr = crypto.randomBytes(16).toString('hex'); + const timestamp = Math.floor(Date.now() / 1000).toString(); + let au = await sign(outTradeNo, nonceStr, timestamp); + let res = await fetch(url, { + method: 'GET', // 默认是 GET,可省略 + headers: { + 'Authorization': au, // 认证令牌 + 'Content-Type': 'application/json', // 声明请求体类型(GET 请求通常不需要) + 'Accept': 'application/json', // 声明期望的响应类型 + } + }) + const data = await res.json(); + return data; +} +async function sign(outTradeNo, nonceStr, timestamp) { + const data = `GET\n/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437\n${timestamp}\n${nonceStr}\n\n` + // 创建签名对象 + const sign = crypto.createSign('RSA-SHA256'); + // 更新签名内容 + sign.update(data); + // 获取存储桶 + const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const privateKeyPem = await res.Body.transformToString(); + // 使用私钥签名(PKCS1 填充) + const signature = sign.sign({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, 'base64'); + // 构建Authorization头 + const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`; + return authorization; +} + +/** + * 根据 IP 获取省份名称 + * @param {string} ip - 用户 IP 地址 + * @returns {string} 省份名称(如 "广东省"),未知时返回 "未知" + */ +function getProvinceByIP(ip) { + try { + const result = query.search(ip); + //console.log(result); + if (!result || !result.country.includes('中国')) { + return '其他'; + } + + // ip2region 返回的格式示例:"中国|0|广东省|深圳市|电信" + const parts = result.province; + const provinceCode = parts[2]; // 省份代码在第三部分 + + // 检查是否是已知的省份代码 + // if (PROVCE_CODE_MAP[provinceCode]) { + // return PROVINCE_CODE_MAP[provinceCode]; + // } + + // 如果未映射,返回原始代码(可能是数据库更新后的新代码) + return parts || '其他'; + } catch (error) { + console.error('IP 解析失败:', error); + return '其他'; + } +} diff --git a/server/laf-cloud/functions/login.yaml b/server/laf-cloud/functions/login.yaml new file mode 100644 index 00000000..4ada9f9d --- /dev/null +++ b/server/laf-cloud/functions/login.yaml @@ -0,0 +1,6 @@ +name: login +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/monthGetReward.ts b/server/laf-cloud/functions/monthGetReward.ts new file mode 100644 index 00000000..fd499a55 --- /dev/null +++ b/server/laf-cloud/functions/monthGetReward.ts @@ -0,0 +1,33 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let monthCardTime=Number(res.data.monthCardTime) || 0; + if(monthCardTimetimestamp){ + return { code: 0, data: { monthCardReward: monthCardReward},msg:"今天已经领取"}; + }else{ + await db.collection(dbname).where({ _id: uid }).update({ monthCardReward:Date.now()}) + return { code: 1, data: { monthCardReward:Date.now()},msg:"可以领取"}; + } +} diff --git a/server/laf-cloud/functions/monthGetReward.yaml b/server/laf-cloud/functions/monthGetReward.yaml new file mode 100644 index 00000000..f3db2641 --- /dev/null +++ b/server/laf-cloud/functions/monthGetReward.yaml @@ -0,0 +1,6 @@ +name: monthGetReward +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/monthRewardState.ts b/server/laf-cloud/functions/monthRewardState.ts new file mode 100644 index 00000000..62672218 --- /dev/null +++ b/server/laf-cloud/functions/monthRewardState.ts @@ -0,0 +1,7 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +export default async function (ctx: FunctionContext) { + // let uid=ctx.body.uid; + // await db.collection("users").where({ _id: uid }).update({ monthCardReward: Date.now() }) + // return {code:1,data:null,msg:"成功"} +} diff --git a/server/laf-cloud/functions/monthRewardState.yaml b/server/laf-cloud/functions/monthRewardState.yaml new file mode 100644 index 00000000..4a2f601c --- /dev/null +++ b/server/laf-cloud/functions/monthRewardState.yaml @@ -0,0 +1,6 @@ +name: monthRewardState +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/monthlyCard.ts b/server/laf-cloud/functions/monthlyCard.ts new file mode 100644 index 00000000..29ed5ed1 --- /dev/null +++ b/server/laf-cloud/functions/monthlyCard.ts @@ -0,0 +1,118 @@ +import cloud from '@lafjs/cloud'; +import Utils from "@/Utils"; + +const db = cloud.database(); +const MONTH_CARD_DURATION = 30 * 24 * 60 * 60 * 1000; + +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + + const res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token = ctx.body.token; + if (res.data && res.data.token) { + const isTokenValid = Utils.checkToken(token, res.data.token); + if (!isTokenValid) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + + switch (action) { + case "save": { + const now = Date.now(); + const oldMonthCardTime = Number(res.data?.monthCardTime) || 0; + const oldMonthCardReward = Number(res.data?.monthCardReward) || 0; + const outTradeNo = ctx.body.outTradeNo; + + // 测试账号校验月卡订单,并确保同一订单只延长一次。 + if (outTradeNo) { + const order = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); + if (!order.data || + order.data.itemid !== "month_Card" || + order.data.openid !== res.data?.openid) { + return { code: 0, data: null, msg: "月卡订单校验失败" }; + } + if (order.data.state !== 2) { + return { code: 0, data: null, msg: "月卡订单尚未完成发货确认" }; + } + if (order.data.monthCardGranted === true) { + return { + code: 1, + data: { + monthCardTime: oldMonthCardTime, + monthCardReward: oldMonthCardReward, + alreadyGranted: true + }, + msg: "该月卡订单已续订" + }; + } + } + + // 有效期内续订:从原到期时间继续加30天; + // 已过期或首次购买:从当前时间加30天。 + const monthCardTime = Math.max(oldMonthCardTime, now) + MONTH_CARD_DURATION; + // 有效期内续订保留当天领取状态,避免同一天重复领取。 + const monthCardReward = oldMonthCardTime > now ? oldMonthCardReward : 0; + + await db.collection(dbname).where({ _id: uid }).update({ + monthCardTime: monthCardTime, + monthCardReward: monthCardReward + }); + + if (outTradeNo) { + await db.collection("order").where({ outTradeNo: outTradeNo }).update({ + monthCardGranted: true + }); + } + + return { + code: 1, + data: { + monthCardTime: monthCardTime, + monthCardReward: monthCardReward, + alreadyGranted: false + }, + msg: "月卡记录成功" + }; + } + + case "read": { + const monthCardTime = res.data?.monthCardTime || 0; + const monthCardReward = res.data?.monthCardReward || 0; + if (monthCardTime < Date.now()) { + return { + code: 0, + data: { + monthCardTime: monthCardTime, + monthCardReward: monthCardReward + }, + msg: "不在有效期" + }; + } + return { + code: 1, + data: { monthCardTime: monthCardTime }, + msg: "成功" + }; + } + + default: + return { + code: 400, + message: "无效的操作类型,请使用 save 或 read" + }; + } +} diff --git a/server/laf-cloud/functions/monthlyCard.yaml b/server/laf-cloud/functions/monthlyCard.yaml new file mode 100644 index 00000000..2b80db2c --- /dev/null +++ b/server/laf-cloud/functions/monthlyCard.yaml @@ -0,0 +1,6 @@ +name: monthlyCard +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/passCheck.ts b/server/laf-cloud/functions/passCheck.ts new file mode 100644 index 00000000..6c914fa3 --- /dev/null +++ b/server/laf-cloud/functions/passCheck.ts @@ -0,0 +1,52 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + switch (action) { + case 'save': + let passCheck =ctx.body.passCheck; + //console.log(passCheck); + if (!passCheck) { + return { code: 0, data: null, msg: "未获取到coinAmount" }; + } + let ret = await db.collection(dbname).where({ _id: uid }).update({passCheck:passCheck}); + return { code: 1, data: {passCheck:passCheck}, msg: "用户数据更新成功" } + case 'read': + let passCheck1 = res.data?.passCheck||null; + let time = await db.collection("idcount").where({ _id: "690c786db30b6944c56be7aa" }).getOne(); + let t = time.data.passcheckTime; + if (Date.now() >t+ 30*24*3600000) { + const endOfDay: any = new Date(); + endOfDay.setHours(16, 0, 0, 0); // 设置为明天的0点,等同于今天的24点 + t =endOfDay.getTime(); + await db.collection("idcount").where({ _id: "690c786db30b6944c56be7aa" }).update({ passcheckTime: t }); + } + return { code: 1, data: {passCheck:passCheck1,time:t}, msg: "成功" } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/passCheck.yaml b/server/laf-cloud/functions/passCheck.yaml new file mode 100644 index 00000000..0241cb56 --- /dev/null +++ b/server/laf-cloud/functions/passCheck.yaml @@ -0,0 +1,6 @@ +name: passCheck +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/passCheckLv.ts b/server/laf-cloud/functions/passCheckLv.ts new file mode 100644 index 00000000..69266c08 --- /dev/null +++ b/server/laf-cloud/functions/passCheckLv.ts @@ -0,0 +1,43 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + switch (action) { + case 'save': + let passCheckLv = ctx.body.passCheckLv; + if (!passCheckLv) { + return { code: 0, data: null, msg: "未获取到passCheckLv" }; + } + let ret = await db.collection(dbname).where({ _id: uid }).update({ passCheckLv: passCheckLv }); + return { code: 1, data: { passCheckLv: passCheckLv }, msg: "用户数据更新成功" } + case 'read': + let passCheckLv1 = res.data?.passCheckLv || null; + return { code: 1, data: { passCheckLv: passCheckLv1 }, msg: "成功" } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/passCheckLv.yaml b/server/laf-cloud/functions/passCheckLv.yaml new file mode 100644 index 00000000..d2ca38a1 --- /dev/null +++ b/server/laf-cloud/functions/passCheckLv.yaml @@ -0,0 +1,6 @@ +name: passCheckLv +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/passCheckTime.ts b/server/laf-cloud/functions/passCheckTime.ts new file mode 100644 index 00000000..ea16b2c9 --- /dev/null +++ b/server/laf-cloud/functions/passCheckTime.ts @@ -0,0 +1,14 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let time =await db.collection("idcount").where({ _id:"690c786db30b6944c56be7aa"}).getOne(); + let t=time.data.passcheckTime; + if(Date.now()>t+60*24*3600000){ + const endOfDay: any = new Date(); + endOfDay.setHours(0, 0, 0, 0); // 设置为明天的0点,等同于今天的24点 + t = endOfDay.getTime(); + await db.collection("idcount").where({ _id: "690c786db30b6944c56be7aa" }).update({ passcheckTime:t}); + } + return{code:1,data:{time:t},msg:"成功"} +} diff --git a/server/laf-cloud/functions/passCheckTime.yaml b/server/laf-cloud/functions/passCheckTime.yaml new file mode 100644 index 00000000..a32aa2ca --- /dev/null +++ b/server/laf-cloud/functions/passCheckTime.yaml @@ -0,0 +1,6 @@ +name: passCheckTime +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/rank.ts b/server/laf-cloud/functions/rank.ts new file mode 100644 index 00000000..6d5e4337 --- /dev/null +++ b/server/laf-cloud/functions/rank.ts @@ -0,0 +1,88 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +const CITY = { + "河北省": true, "山西省": true, "辽宁省": true, "吉林省": true, "黑龙江省": true, "江苏省": true, + "浙江省": true, "安徽省": true, "福建省": true, "江西省": true, "山东省": true, "河南省": true, "湖北省": true, + "湖南省": true, "广东省": true, "海南省": true, "四川省": true, "贵州省": true, "云南省": true, "陕西省": true, + "甘肃省": true, "青海省": true, "港澳台": true, "北京": true, "天津": true, "上海": true, "重庆": true, + "内蒙古": true, "广西": true, "西藏": true, "宁夏": true, "新疆": true, "其他": true +}; +export default async function (ctx: FunctionContext) { + let uid=ctx.body.uid; + let res=await sortBattle(uid); + // for(var key in CITY){ + // let res = await sortShengShi(key); + // } + return {code:1} +} +/**普通排行 + * @param userCollec + */ +async function sortBattle(uid) { + let res = await db.collection("users").aggregate().project({ + levelAmount: 1, // 1 表示包含该字段,其他字段默认排除 + endLevelNum: 1, + username:1, + useravatar:1, + useravatarIcon:1, + isWhite:1 + })//.addFields({ endLevelNum: { $toInt: "$endLevelNum" }}).addFields({ + // totalLevel: { $add: ["$levelAmount", "$endLevelNum"] }}) + .match({ + isWhite: false + }) + .sort({ + levelAmount:-1, + endLevelNum:-1 + //totalLevel: -1, + }).limit(1000).end(); + const res1 = await db.collection("rank").where({ _id:"689db6c5cc79706182bd6a9f"}) + .update({rank: JSON.stringify(res.data)}); + let res2 = await db.collection("usersAd").aggregate().project({ + levelAmount: 1, // 1 表示包含该字段,其他字段默认排除 + endLevelNum: 1, + username: 1, + useravatar: 1, + useravatarIcon: 1, + isWhite: 1 + }) + // .addFields({ endLevelNum: { $toInt: "$endLevelNum" } }).addFields({ + // totalLevel: { $add: ["$levelAmount", "$endLevelNum"] } + // }) + .match({ + isWhite: false + }) + .sort({ + levelAmount: -1, + endLevelNum: -1 + //totalLevel: -1, + }).limit(1000).end(); + const res3 = await db.collection("rank").where({ _id: "68e92b7835004ffb5ab9ee89" }) + .update({ rank: JSON.stringify(res2.data) }); + return true; +} + +// /**省市地区排名前100名*/ +// async function sortShengShi(address){ +// let res = await db.collection("users").aggregate().project({ +// addLevel:1, +// levelAmount:1, // 1 表示包含该字段,其他字段默认排除 +// endLevelNum: 1, +// username:1, +// useravatar:1, +// useravatarIcon: 1, +// isWhite: 1, +// address:1, +// }).addFields({ endLevelNum: { $toInt: "$endLevelNum" } }).addFields({ +// totalLevel: { $add: ["$levelAmount", "$endLevelNum"] } +// }).match({ +// address:address, +// isWhite: false, +// addLevel: {$gte:5}, +// }) +// .sort({ +// addLevel: -1, +// }).limit(100).end(); +// const res3 = await db.collection("sRank").where({ name: address }).update({ totoal: res.data }, { upsert: true }); +// return true; +// } \ No newline at end of file diff --git a/server/laf-cloud/functions/rank.yaml b/server/laf-cloud/functions/rank.yaml new file mode 100644 index 00000000..c3524050 --- /dev/null +++ b/server/laf-cloud/functions/rank.yaml @@ -0,0 +1,6 @@ +name: rank +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/readPem.ts b/server/laf-cloud/functions/readPem.ts new file mode 100644 index 00000000..5588cdb1 --- /dev/null +++ b/server/laf-cloud/functions/readPem.ts @@ -0,0 +1,12 @@ +import cloud from '@lafjs/cloud' +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const mjsonUrl = 'j3k323ol-colorblock-oss'; + // 获取存储桶 + const bucket = cloud.storage.bucket(mjsonUrl); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const data = await res.Body.transformToString() + cloud.shared.set("apiclient_key",data); + return data; +} diff --git a/server/laf-cloud/functions/readPem.yaml b/server/laf-cloud/functions/readPem.yaml new file mode 100644 index 00000000..4dc85c37 --- /dev/null +++ b/server/laf-cloud/functions/readPem.yaml @@ -0,0 +1,6 @@ +name: readPem +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/rebornGift.ts b/server/laf-cloud/functions/rebornGift.ts new file mode 100644 index 00000000..26d5b3b1 --- /dev/null +++ b/server/laf-cloud/functions/rebornGift.ts @@ -0,0 +1,41 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let uid = ctx.body.uid; + if (!uid) { + return { code: 0, data: null, msg: "参数错误" }; + } + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (res.data == null) { + return { code: 0, data: null, msg: "未获取到玩家数据" }; + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let rebornGiftTime=res.data.rebornGiftTime||0; + let rebornGiftCount=res.data.rebornGiftCount||0; + let times=getTodayStartTimestamp(); + if(rebornGiftTime=1){ + return { code: 0, data: null, msg: "今天购买次数已用完" }; + } + db.collection(dbname).where({ _id: uid }).update({ rebornGiftTime:Date.now(),rebornGiftCount:1}); + return { code: 1, data: { rebornGiftTime:Date.now(),rebornGiftCount:rebornGiftCount+1},msg:"可以购买"}; +} +function getTodayStartTimestamp() { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} diff --git a/server/laf-cloud/functions/rebornGift.yaml b/server/laf-cloud/functions/rebornGift.yaml new file mode 100644 index 00000000..c03a4ff0 --- /dev/null +++ b/server/laf-cloud/functions/rebornGift.yaml @@ -0,0 +1,6 @@ +name: rebornGift +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/redeem.ts b/server/laf-cloud/functions/redeem.ts new file mode 100644 index 00000000..2b3661ac --- /dev/null +++ b/server/laf-cloud/functions/redeem.ts @@ -0,0 +1,100 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +const CDKreward={ + wucaixiaoxiaole666:{ + 1001:1000, + 2001:1, + 2002:1, + 2003:1, + } +} +export default async function (ctx: FunctionContext) { + let uid = ctx.body.uid; + if (!uid) { + return { code: 0, data: null, msg: "参数错误" }; + } + let cdk= ctx.body.cdk; + if(!cdk){ + return {code:0, data:null, msg:"未获取到cdk"} + } + cdk = cdk.toLowerCase(); + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if (res.data == null) { + return { code: 0, data: null, msg: "未获取到玩家数据" }; + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let redeem = res.data.redeem || []; + if (redeem.includes(cdk)) { + return { code: 0, data: null, msg: "已获取奖励" }; + } + if (cdk.length == 5) { + let infos = await db.collection("cdk").where({ code: cdk }).getOne(); + if (infos.data == null) { + return { code: 0, data: null, msg: "cdk无效" } + } + let start = new Date(infos.data.start).getTime() - 8 * 3600000; + if (Date.now() < start) { + return { code: 0, data: null, msg: "活动未开始" } + } + let end = new Date(infos.data.end_time).getTime() - 8 * 3600000; + if (Date.now() > end) { + return { code: 0, data: null, msg: "活动已结束" } + } + redeem.push(cdk); + db.collection(dbname).where({ _id: uid }).update({ redeem: redeem }); + return { + code: 1, data: { + reward: { + 2001: 1, + 2002: 1, + 2003: 1, + } + }, msg: "可以购买" + }; + } + let info = await db.collection("idcount").where({ _id:"694e064b35004ffb5aba0dc6"}).getOne(); + let count= info.data.count; + if(count.includes(cdk)){ + let index=count.indexOf(cdk); + count.splice(index,1); + redeem.push(cdk); + db.collection(dbname).where({ _id: uid }).update({ redeem: redeem }); + await db.collection("idcount").where({ _id: "694e064b35004ffb5aba0dc6" }).update({count:count}); + let money=600; + let num=1; + if(cdk.length==6){ + money=1500; + num=3; + }else if(cdk.length==8){ + money=600; + num=1; + } + return { code: 1, data: { reward: { + 1001:money, + 2001: num, + 2002: num, + 2003: num, + } }, msg: "可以购买" }; + }else{ + let reward = CDKreward[cdk]; + if (!reward) { + return { code: 0, data: null, msg: "未获取到奖励信息" }; + } + redeem.push(cdk); + db.collection(dbname).where({ _id: uid }).update({ redeem: redeem }); + return { code: 1, data: { reward: reward }, msg: "可以购买" }; + } + +} diff --git a/server/laf-cloud/functions/redeem.yaml b/server/laf-cloud/functions/redeem.yaml new file mode 100644 index 00000000..97cdc86c --- /dev/null +++ b/server/laf-cloud/functions/redeem.yaml @@ -0,0 +1,6 @@ +name: redeem +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/searchOrder.ts b/server/laf-cloud/functions/searchOrder.ts new file mode 100644 index 00000000..f473131b --- /dev/null +++ b/server/laf-cloud/functions/searchOrder.ts @@ -0,0 +1,24 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let outTradeNo=ctx.body.outTradeNo; + const res = await db.collection("order").where({ outTradeNo:outTradeNo}).getOne(); + console.log(res) + return { data:res} +} +function formatMilliseconds(ms) { + // 创建一个新的Date对象 + const date = new Date(ms); + + // 获取各个时间部分 + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以要加1 + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + + // 组合成想要的格式 + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} \ No newline at end of file diff --git a/server/laf-cloud/functions/searchOrder.yaml b/server/laf-cloud/functions/searchOrder.yaml new file mode 100644 index 00000000..d0985b09 --- /dev/null +++ b/server/laf-cloud/functions/searchOrder.yaml @@ -0,0 +1,6 @@ +name: searchOrder +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/searchPlayerDataByLevel.ts b/server/laf-cloud/functions/searchPlayerDataByLevel.ts new file mode 100644 index 00000000..47156d6d --- /dev/null +++ b/server/laf-cloud/functions/searchPlayerDataByLevel.ts @@ -0,0 +1,56 @@ +import cloud from '@lafjs/cloud' +const { MongoClient} = require('mongodb'); +const db1 = cloud.database(); +export default async function (ctx: FunctionContext) { + const uri = 'mongodb://root:nlwrr6cr@dbconn.sealoshzh.site:48953/?directConnection=true'; + const dbName = 'sealaf-cno56wxmj7'; + // let res = await db1.collection("users").where({ totalLevel: { $gt: 10000 } }).update({ totalLevel:0},{multi:true}); + // return res; + let data=[]; + // for(let i=0;i item.name === collectionName); + if (!exists) { + console.log(`collection "${collectionName}" not found`); + return; + } + for(let i=0;i<3;i++){ + console.log(data[i]); + const user = await db.collection(collectionName).findOne({ _id:data[i]}); + let data1={ + endLevelNum: user.endLevelNum||0, + totalLevel: user.totalLevel||user.levelAmount, + userLevel: user.userLevel||0, + forcedUpdate: true, + } + if (user) { + //data1.coinAmount += 10000; + //console.log(data1); + let res22=await db1.collection("users").where({_id:data[i]}).update(data1); + //console.log(res22) + } + } + } catch (err) { + console.error('MongoDB error:', err); + } finally { + console.log("断开连接") + await client.close(); + } + // let res = await db1.collection("users").where({ endLevelNum:99999999999999 }).get(); + // let data=[]; + // for(let i=0;i20000){ + // data.push(res.data[i]._id); + // } + // } + // console.log(JSON.stringify(data)); +} diff --git a/server/laf-cloud/functions/searchPlayerDataByLevel.yaml b/server/laf-cloud/functions/searchPlayerDataByLevel.yaml new file mode 100644 index 00000000..95977ecd --- /dev/null +++ b/server/laf-cloud/functions/searchPlayerDataByLevel.yaml @@ -0,0 +1,6 @@ +name: searchPlayerDataByLevel +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/setForcedUpdate.ts b/server/laf-cloud/functions/setForcedUpdate.ts new file mode 100644 index 00000000..614c2456 --- /dev/null +++ b/server/laf-cloud/functions/setForcedUpdate.ts @@ -0,0 +1,29 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + //console.log(data); + let res1 = await db.collection(dbname).where({ _id: uid }).update({forcedUpdate:false }); + if (res.ok && res1.updated == 1) { + return { code: 1, data: null, msg: "用户数据更新成功" } + } else { + return { code: 0, data: null, msg: "用户数据更新失败" } + } +} diff --git a/server/laf-cloud/functions/setForcedUpdate.yaml b/server/laf-cloud/functions/setForcedUpdate.yaml new file mode 100644 index 00000000..074cd416 --- /dev/null +++ b/server/laf-cloud/functions/setForcedUpdate.yaml @@ -0,0 +1,6 @@ +name: setForcedUpdate +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/setHeadArr.ts b/server/laf-cloud/functions/setHeadArr.ts new file mode 100644 index 00000000..cd28f31e --- /dev/null +++ b/server/laf-cloud/functions/setHeadArr.ts @@ -0,0 +1,51 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let headArr = res.data?.headArr ?? []; + switch (action) { + case 'save': + let headNum = Number(ctx.body.headNum); + if (!headNum&&headNum!=0) { + return { code: 0, data: null, msg: "头像id错误" }; + } + if(headArr.includes(headNum)){ + return { code: 0, data: null, msg: "已保存头像" }; + } + headArr.push(headNum); + await db.collection(dbname).where({ _id: uid }).update({ headArr: headArr }); + return { code: 1, data: { headArr: headArr }, msg: "用户数据更新成功" } + case 'read': + + return { + code: 1, data: { headArr:headArr }, msg: "成功" + } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/setHeadArr.yaml b/server/laf-cloud/functions/setHeadArr.yaml new file mode 100644 index 00000000..bb2fe661 --- /dev/null +++ b/server/laf-cloud/functions/setHeadArr.yaml @@ -0,0 +1,6 @@ +name: setHeadArr +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/setUserLevel.ts b/server/laf-cloud/functions/setUserLevel.ts new file mode 100644 index 00000000..b8aa9b97 --- /dev/null +++ b/server/laf-cloud/functions/setUserLevel.ts @@ -0,0 +1,62 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let endLevelNum1 = res.data?.endLevelNum; + switch (action) { + case 'save': + let userLevel = ctx.body.userLevel; + if (!userLevel) { + return { code: 0, data: null, msg: "未获取到userLevel" }; + }; + userLevel=Number(userLevel); + let endLevelNum=ctx.body.endLevelNum; + if(!endLevelNum){ + endLevelNum=0; + } + if(endLevelNum10){ + console.error((endLevelNum-Number(endLevelNum1))+" 有作弊嫌疑 :"+uid); + return; + } + let totalLevel=userLevel+(endLevelNum/10000) + await db.collection(dbname).where({ _id: uid }).update({ userLevel:userLevel,endLevelNum:endLevelNum,totalLevel:totalLevel}); + return { code: 1, data: { userLevel: userLevel, endLevelNum: endLevelNum }, msg: "用户数据更新成功" } + case 'read': + let userLevel1 = res.data?.userLevel; + //let endLevelNum1=res.data?.endLevelNum; + return { + code: 1, data: { userLevel: userLevel1, endLevelNum: endLevelNum1 }, msg: "成功" + } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/setUserLevel.yaml b/server/laf-cloud/functions/setUserLevel.yaml new file mode 100644 index 00000000..d54f65bd --- /dev/null +++ b/server/laf-cloud/functions/setUserLevel.yaml @@ -0,0 +1,6 @@ +name: setUserLevel +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/setWinStreak.ts b/server/laf-cloud/functions/setWinStreak.ts new file mode 100644 index 00000000..5deecaa0 --- /dev/null +++ b/server/laf-cloud/functions/setWinStreak.ts @@ -0,0 +1,22 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let uid=ctx.body.uid; + let winStreak = ctx.body.winStreak; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let ret = await db.collection(dbname).where({ _id: uid }).update({ winStreak:winStreak }); + return { code: 1, data: { winStreak:winStreak }, msg: "用户数据更新成功" } +} diff --git a/server/laf-cloud/functions/setWinStreak.yaml b/server/laf-cloud/functions/setWinStreak.yaml new file mode 100644 index 00000000..02ec2700 --- /dev/null +++ b/server/laf-cloud/functions/setWinStreak.yaml @@ -0,0 +1,6 @@ +name: setWinStreak +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/shareLvSuccess.ts b/server/laf-cloud/functions/shareLvSuccess.ts new file mode 100644 index 00000000..86820581 --- /dev/null +++ b/server/laf-cloud/functions/shareLvSuccess.ts @@ -0,0 +1,45 @@ +import cloud from '@lafjs/cloud' +const db=cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + let otherUid=ctx.body.otherUid; + let uid=ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if(!uid){ + return {code:0,data:null,msg:"参数错误"}; + } + let shareLv=Number(ctx.body.shareLv); + if(!shareLv){ + return {code:0,data:null,msg:"参数错误"}; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + if(res.data==null){ + return {code:0,data:null,msg:"未获取到玩家数据"}; + } + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + let share=res.data.shareLv; + if(share){ + share=JSON.parse(share); + }else{ + share=[]; + } + if(share.length>0){ + if(share[0].lv total["all"][length - 1].addLevel) { + // total["all"].push({ + // id: uid, + // addLevel: add, + // time: Date.now(), + // username: res1.data?.username, + // useravatar: res1.data?.useravatar, + // useravatarIcon: res1.data?.useravatarIcon, + // levelAmount: levelAmount + // }); + // } + // } + // } else { + // total["all"] = [{ + // id: uid, + // addLevel: add, + // time: Date.now(), + // username: res1.data?.username, + // useravatar: res1.data?.useravatar, + // useravatarIcon: res1.data?.useravatarIcon, + // levelAmount: levelAmount + // }]; + // } + // total["all"].sort((a, b) => { + // if (a.addLevel !== b.addLevel) { + // return b.addLevel - a.addLevel; + // } + // return a.time - b.time; + // }); + // if (total["all"].length >= 10) { + // total["all"] = total["all"].slice(0, 10); + // } + // if (total[address]) { + // let isHave = false; + // for (let i = 0; i < total[address].length; i++) { + // if (total[address][i].id == uid) { + // isHave = true; + // total[address][i].useravatar = res1.data?.useravatar, + // total[address][i].username = res1.data?.username, + // total[address][i].useravatarIcon = res1.data?.useravatarIcon, + // total[address][i].addLevel = add; + // total[address][i].time = Date.now(); + // break; + // } + // } + // if (isHave == false) { + // let length = total[address].length; + // if (length < 10 || add > total[address][length - 1].addLevel) { + // total[address].push({ + // id: uid, + // addLevel: add, + // time: Date.now(), + // username: res1.data?.username, + // useravatar: res1.data?.useravatar, + // useravatarIcon: res1.data?.useravatarIcon, + // levelAmount: levelAmount + // }); + // } + // } + // } else { + // total[address] = [{ + // id: uid, + // addLevel: add, + // time: Date.now(), + // username: res1.data?.username, + // useravatar: res1.data?.useravatar, + // useravatarIcon: res1.data?.useravatarIcon, + // levelAmount: levelAmount + // }]; + // } + // total[address].sort((a, b) => { + // if (a.addLevel !== b.addLevel) { + // return b.addLevel - a.addLevel; + // } + // return a.time - b.time; + // }); + // if (total[address].length >= 10) { + // total[address] = total[address].slice(0, 10); + // } + // if (!total["role"]) { + // total["role"] = {}; + // } + // if (levelTJ == 0) { + + // if (!total["role"][address]) { + // total["role"][address] = 1; + // } else { + // total["role"][address] += 1; + // //console.log(address+"真实:"+total[address].length+"----"+total["role"][address]); + // let length = total[address].length; + // if (length < 10) { + // total["role"][address] = length; + // } + // //console.error(address + "真实:" + total[address].length + "----" + total["role"][address]) + // // const res3 = await db.collection("sRank").where({ name: address }).getOne(); + // // let length1=res3.data.totoal.length; + // // if(length1<100&&total["role"][address]>length1){ + // // total["role"][address]=length1; + // // } + // //console.error(address+":"+length); + // } + // } + // //console.log(address); + // let ret1 = await db.collection("sRank").where({ _id: db1 }).update({ total: JSON.stringify(total) }); + // let rank = -1; + // for (let i = 0; i < total[address].length; i++) { + // if (total[address][i].id == uid) { + // rank = i + 1; + // break; + // } + // } + // return rank; +} +function stringToHash(input: string, algorithm: 'sha1' | 'sha256' | 'sha512' = 'sha256'): string { + return createHash(algorithm).update(input).digest('hex'); +} + +async function updateAddLevel(){ + // const ret = await db1.collection('users').updateMany({ + // addLevel: { $exists: true } + // }, + // [ + // { + // $set: { + // addLevel: { $floor: ["$addLevel"] } + // } + // } + // ]); + let rankInfo = await db.collection("sRank").where({ _id: "691093093cf0c4532ba4fd9c" }).getOne(); + + let total = rankInfo.data.total; + total = JSON.parse(total); + for (var key in total) { + if (key !== "role") { + for (let i = 0; i < total[key].length; i++) { + total[key][i].addLevel = Math.floor(total[key][i].addLevel); + } + } + } + await db.collection("sRank").where({ _id: "691093093cf0c4532ba4fd9c" }).update({ total: JSON.stringify(total) }); +} +const propName = { + "金币包1": "gold_1", + "金币包2": "gold_2", + "金币包3": "gold_3", + "金币包4": "gold_4", + "金币包5": "gold_5", + "金币包6": "gold_6", + "无限体力组合包1": "unlimited_health_bundle_1", + "无限体力组合包2": "unlimited_health_bundle_2", + "无限体力组合包3": "unlimited_health_bundle_3", + "局内购买冻结": "freeze_in_game", + "局内购买锤子": "hammer_in_game", + "局内购买魔棒": "wand_in_gamerefill", + "补满体力": "health" +}; + +function getTodayStartTimestamp() { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} +async function getWXOpenId(code) { + let appid = "wxdd145ced49158a1e"; + let appsecret = "7f295245ffc4884b03306c64e30654db"; + const api_url = `https://api.weixin.qq.com/sns/jscode2session`; + const param = `appid=${appid}&secret=${appsecret}&js_code=${code}&grant_type=authorization_code`; + let res = null; + try { + res = await cloud.fetch(`${api_url}?${param}`, { + headers: { + "Accept-Encoding": 'gzip' + } + }); + } catch { + + } + + + if (res == null || res.data.errcode > 0) { + return null + } + + return [res?.data?.openid, res?.data?.session_key] +} +/**获取当前用户数据 */ +async function getUserData(dbname: string, openid: any, isFirst?) { + let { data } = await db.collection(dbname).where({ openid: openid }).get(); + if (data.length) { + return data[0]; + } + return null; +} + +async function delayExecution(seconds: number) { + return new Promise((resolve) => { + setTimeout(() => { + // 在这里编写需要延时执行的代码 + resolve("延时执行完成"); + }, seconds * 1000); + }); +} +async function getIosOrder(openid) { + let res = await db.collection("order").where({ state:0,type: "ios",openid: openid }).get(); + let list = []; + if (res.data.length > 0) { + for (let i = 0; i < res.data.length; i++) { + let ret = await getOrder(res.data[i].outTradeNo); + if (ret.trade_state == "SUCCESS") { + list.push(res.data[i]); + } else { + console.log(Date.now()-res.data[i].time); + if (Date.now() - res.data[i].time > 3 * 3600000) { + let ret = await db.collection('order').where({ outTradeNo: res.data[i].outTradeNo }).remove({ multi: true }); + } + } + } + } + return list; +} + +/**获取订单*/ +async function getOrder(outTradeNo) { + const url = `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437`; + const nonceStr = crypto.randomBytes(16).toString('hex'); + const timestamp = Math.floor(Date.now() / 1000).toString(); + let au = await sign(outTradeNo, nonceStr, timestamp); + let res = await fetch(url, { + method: 'GET', // 默认是 GET,可省略 + headers: { + 'Authorization': au, // 认证令牌 + 'Content-Type': 'application/json', // 声明请求体类型(GET 请求通常不需要) + 'Accept': 'application/json', // 声明期望的响应类型 + } + }) + const data = await res.json(); + return data; +} +async function sign(outTradeNo, nonceStr, timestamp) { + const data = `GET\n/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437\n${timestamp}\n${nonceStr}\n\n` + // 创建签名对象 + const sign = crypto.createSign('RSA-SHA256'); + // 更新签名内容 + sign.update(data); + // 获取存储桶 + const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const privateKeyPem = await res.Body.transformToString(); + // 使用私钥签名(PKCS1 填充) + const signature = sign.sign({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, 'base64'); + // 构建Authorization头 + const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`; + return authorization; +} \ No newline at end of file diff --git a/server/laf-cloud/functions/test.yaml b/server/laf-cloud/functions/test.yaml new file mode 100644 index 00000000..cc746c37 --- /dev/null +++ b/server/laf-cloud/functions/test.yaml @@ -0,0 +1,6 @@ +name: test +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/userCoin.ts b/server/laf-cloud/functions/userCoin.ts new file mode 100644 index 00000000..c52631c6 --- /dev/null +++ b/server/laf-cloud/functions/userCoin.ts @@ -0,0 +1,47 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + switch (action) { + case 'save': + let coinAmount = Number(ctx.body.coinAmount); + if (!coinAmount&&coinAmount!=0) { + return { code: 0, data: null, msg: "未获取到coinAmount" }; + } + if (coinAmount < 0) { + coinAmount = 0; + } + let ret = await db.collection(dbname).where({ _id: uid }).update({ coinAmount: coinAmount, timestamp:Date.now()}); + return { code: 1, data: { coinAmount: coinAmount, timestamp:Date.now()}, msg: "用户数据更新成功" } + case 'read': + let coinAmount1 = res.data?.coinAmount||0; + let timestamp=res.data?.timestamp||0; + return { code: 1, data: { coinAmount:coinAmount1, timestamp: timestamp}, msg: "成功" } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/userCoin.yaml b/server/laf-cloud/functions/userCoin.yaml new file mode 100644 index 00000000..a88cfc47 --- /dev/null +++ b/server/laf-cloud/functions/userCoin.yaml @@ -0,0 +1,6 @@ +name: userCoin +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/userData.ts b/server/laf-cloud/functions/userData.ts new file mode 100644 index 00000000..85354883 --- /dev/null +++ b/server/laf-cloud/functions/userData.ts @@ -0,0 +1,103 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action=ctx.body.action; + const uid=ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if(!action){ + return { code: 0, data: null, msg: "未获取到action" }; + } + if(!uid){ + return {code:0,data:null,msg:"未获取到uid"}; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + switch (action) { + case 'save': + const userData1 = JSON.parse(ctx.body.userData); + if(!userData1){ + return { code: 0, data: null, msg: "未获取到userData" }; + } + //console.error(userData1) + let data={ + // coinAmount:Number(userData1.coinAmount)||0, + // freezeAmount:Number(userData1.freezeAmount)||0, + // hammerAmount:Number(userData1.hammerAmount)||0, + // level:Number(userData1.level)||0, + // magicAmount:Number(userData1.magicAmount)||0, + // timestamp:Date.now(), + // register_time: Number(userData1.register_time)||Date.now(), + // userPowerTime: Number(userData1.userPowerTime) || 0, + useravatar:userData1.useravatar||Math.floor(Math.random()*4)+"", + username:userData1.username||"user", + useravatarIcon: userData1.useravatarIcon||"0", + } + //console.log(data); + let res2 = await db.collection(dbname).where({ _id: uid }).update(data); + if(res2.ok&&res2.updated==1){ + return { code:1, data: null, msg: "用户数据更新成功" } + }else{ + return { code: 0, data: null, msg: "用户数据更新失败" } + } + case 'read': + let ret = await db.collection(dbname).where({ _id: uid }).getOne(); + let userData=ret.data; + if(ret.data){ + let share = userData.shareLv; + if (share) { + share = JSON.parse(share); + } else { + share = []; + } + let rebornGiftTime = userData.rebornGiftTime || 0; + let rebornGiftCount = userData.rebornGiftCount || 0; + let times = getTodayStartTimestamp(); + if (rebornGiftTime < times) { + rebornGiftCount = 0; + } + let data = { + coinAmount: Number(userData.coinAmount) || 0, + freezeAmount: Number(userData.freezeAmount) || 0, + hammerAmount: Number(userData.hammerAmount) || 0, + level: Number(userData.level) || 0, + magicAmount: Number(userData.magicAmount) || 0, + timestamp: Number(userData.timestamp) || 0, + useravatar: userData.useravatar || "", + username: userData.username || "user", + register_time: Number(userData.register_time) || 0, + monthCardTime: Number(userData.monthCardTime) || 0, + monthCardReward: Number(userData.monthCardReward) || 0, + share: share, + rebornGiftTime: rebornGiftTime, + rebornGiftCount: rebornGiftCount + } + return {code:1,data:data,msg:"获取玩家数据成功"} + }else{ + return {code:0,data:null,msg:"获取玩家数据失败"} + } + //return 1; + default: + return { + code:400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} + +function getTodayStartTimestamp() { + const date = new Date(); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} + diff --git a/server/laf-cloud/functions/userData.yaml b/server/laf-cloud/functions/userData.yaml new file mode 100644 index 00000000..d2f5a62c --- /dev/null +++ b/server/laf-cloud/functions/userData.yaml @@ -0,0 +1,6 @@ +name: userData +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/userHealth.ts b/server/laf-cloud/functions/userHealth.ts new file mode 100644 index 00000000..8289bd15 --- /dev/null +++ b/server/laf-cloud/functions/userHealth.ts @@ -0,0 +1,50 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + + switch (action) { + case 'save': + let healthAmount = Number(ctx.body.healthAmount); + let healthtimestamp = Number(ctx.body.timestamp); + if (!healthAmount) { + return { code: 0, data: null, msg: "未获取到coinAmount" }; + } + if (healthAmount < 0) { + healthAmount = 0; + } + let ret = await db.collection(dbname).where({ _id: uid }).update({ healthAmount: healthAmount, healthtimestamp: healthtimestamp }); + return { code: 1, data: { healthAmount: healthAmount, timestamp: healthtimestamp }, msg: "用户数据更新成功" } + case 'read': + + return { + code: 1, data: { healthAmount: res.data.healthAmount, timestamp: res.data.healthtimestamp}, msg: "成功" } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} diff --git a/server/laf-cloud/functions/userHealth.yaml b/server/laf-cloud/functions/userHealth.yaml new file mode 100644 index 00000000..ec314fb0 --- /dev/null +++ b/server/laf-cloud/functions/userHealth.yaml @@ -0,0 +1,6 @@ +name: userHealth +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/userLevel.ts b/server/laf-cloud/functions/userLevel.ts new file mode 100644 index 00000000..efb6185a --- /dev/null +++ b/server/laf-cloud/functions/userLevel.ts @@ -0,0 +1,278 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +import Utils from "@/Utils"; +import Ip2region from 'ip2region'; +const query = new Ip2region(); +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + const isWuXian = ctx.body.isWuXian; + let db1 = "691093093cf0c4532ba4fd9c"; + if (gameName == "iaa") { + dbname = "usersAd"; + db1 = "691097ac3cf0c4532ba4fd9e"; + } + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res1 = await db.collection(dbname).where({ _id: uid }).getOne(); + const token = ctx.body.token; + if (res1.data && res1.data.token) { + let istoken = Utils.checkToken(token, res1.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" };; + } + } + let address = res1.data?.address; + const ip = ctx.headers['x-forwarded-for'] || ctx.headers['x-real-ip'] || ''; + let address1 = getProvinceByIP(ip); + if (!address || address == "其他") { + address = address1; + } + if (["香港", "澳门", "台湾省"].includes(address)) { + address = "港澳台"; + } + switch (action) { + case 'save': + let levelAmount = Number(ctx.body.levelAmount); + if (!levelAmount) { + return { code: 0, data: null, msg: "未获取到levelAmount" }; + } + let oldlevelAmount = res1.data?.levelAmount || 0; + let oldAdd = res1.data?.addLevel || 0; + let levelTJ = res1.data?.levelTJ || 0; + let count = levelAmount - oldlevelAmount; + if (count > 10 || count < -10) { + count = 1; + return; + } + let add = oldAdd + count; + let isWhite = res1.data?.isWhite; + let careerAmount = res1.data?.careerAmount || 0; + if (isWuXian == "true") { + add += 1; + //console.log("无线增加值:"+(add-oldAdd)); + } else { + //console.log("非无线增加值:"+(add-oldAdd)); + } + add = Math.floor(add); + // if (uid =="686513c8a173b1b78d21f881"){ + // console.error(add); + // console.log(isWhite); + // console.log(typeof isWhite); + // console.log(isWhite==false); + // console.error(levelAmount); + // } + let rankNum = -1; + if (add >= 5 && isWhite == false) { + rankNum = await rank(db1, uid, add, levelAmount, res1, address, levelTJ); + levelTJ = 1; + careerAmount += 1; + } + let film = res1.data.film; + if (!film && film != 0) { + film = res1.data.levelAmount; + } + film += count; + if (uid == "6866ac24a173b1b78d21f8c2") { + console.log("通关:" + levelAmount); + } + // console.error(add); + // console.log(oldAdd); + // console.log(levelAmount); + // console.log(oldlevelAmount); + // console.error("----------------------------------"); + let ret = await db.collection(dbname).where({ _id: uid }).update({ address: address, film: film, careerAmount: careerAmount, levelTJ: levelTJ, levelAmount: levelAmount, addLevel: add, timestamp: Date.now() }); + return { code: 1, data: { IP: ip, address: address, rank: rankNum, levelAmount: levelAmount, film: film, timestamp: Date.now() }, msg: "用户数据更新成功" } + case 'read': + return { + code: 1, data: { levelAmount: res1.data?.levelAmount || 0, film: res1.data?.film ?? res1.data?.levelAmount ?? 0, timestamp: res1.data?.timestamp || 0 }, msg: "成功" + } + default: + return { + code: 400, + message: '无效的操作类型,请使用 save 或 read' + } + } +} +function isSameDayUTC(timestamp1, timestamp2) { + const date1 = new Date(timestamp1); + const date2 = new Date(timestamp2); + + return date1.getUTCFullYear() === date2.getUTCFullYear() && + date1.getUTCMonth() === date2.getUTCMonth() && + date1.getUTCDate() === date2.getUTCDate(); +} +async function rank(db1, uid, add, levelAmount, res1, address, levelTJ) { + let rankInfo = await db.collection("sRank").where({ _id: db1 }).getOne(); + + let total = rankInfo.data.total; + if (total != null) { + total = JSON.parse(total); + } else { + total = {}; + } + if (total["all"]) { + let isHave = false; + for (let i = 0; i < total["all"].length; i++) { + if (total["all"][i].id == uid) { + isHave = true; + total["all"][i].useravatar = res1.data?.useravatar, + total["all"][i].username = res1.data?.username, + total["all"][i].useravatarIcon = res1.data?.useravatarIcon, + total["all"][i].addLevel = add; + total["all"][i].time = Date.now(); + break; + } + } + if (isHave == false) { + let length = total["all"].length; + if (length < 10 || add > total["all"][length - 1].addLevel) { + total["all"].push({ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: levelAmount + }); + } + } + } else { + total["all"] = [{ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: levelAmount + }]; + } + total["all"].sort((a, b) => { + if (a.addLevel !== b.addLevel) { + return b.addLevel - a.addLevel; + } + return a.time - b.time; + }); + if (total["all"].length >= 10) { + total["all"] = total["all"].slice(0, 10); + } + if (total[address]) { + let isHave = false; + for (let i = 0; i < total[address].length; i++) { + if (total[address][i].id == uid) { + isHave = true; + total[address][i].useravatar = res1.data?.useravatar, + total[address][i].username = res1.data?.username, + total[address][i].useravatarIcon = res1.data?.useravatarIcon, + total[address][i].addLevel = add; + total[address][i].time = Date.now(); + break; + } + } + if (isHave == false) { + let length = total[address].length; + if (length < 10 || add > total[address][length - 1].addLevel) { + total[address].push({ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: levelAmount + }); + } + } + } else { + total[address] = [{ + id: uid, + addLevel: add, + time: Date.now(), + username: res1.data?.username, + useravatar: res1.data?.useravatar, + useravatarIcon: res1.data?.useravatarIcon, + levelAmount: levelAmount + }]; + } + total[address].sort((a, b) => { + if (a.addLevel !== b.addLevel) { + return b.addLevel - a.addLevel; + } + return a.time - b.time; + }); + if (total[address].length >= 10) { + total[address] = total[address].slice(0, 10); + } + if (!total["role"]) { + total["role"] = {}; + } + if (levelTJ == 0) { + + if (!total["role"][address]) { + total["role"][address] = 1; + } else { + total["role"][address] += 1; + //console.log(address+"真实:"+total[address].length+"----"+total["role"][address]); + let length = total[address].length; + if (length < 10) { + total["role"][address] = length; + } + //console.error(address + "真实:" + total[address].length + "----" + total["role"][address]) + // const res3 = await db.collection("sRank").where({ name: address }).getOne(); + // let length1=res3.data.totoal.length; + // if(length1<100&&total["role"][address]>length1){ + // total["role"][address]=length1; + // } + //console.error(address+":"+length); + } + } + //console.log(address); + let ret1 = await db.collection("sRank").where({ _id: db1 }).update({ total: JSON.stringify(total) }); + let rank = -1; + for (let i = 0; i < total[address].length; i++) { + if (total[address][i].id == uid) { + rank = i + 1; + break; + } + } + return rank; +} + +/** + * 根据 IP 获取省份名称 + * @param {string} ip - 用户 IP 地址 + * @returns {string} 省份名称(如 "广东省"),未知时返回 "未知" + */ +function getProvinceByIP(ip) { + try { + const result = query.search(ip); + //console.log(result); + if (!result || !result.country.includes('中国')) { + return '其他'; + } + + // ip2region 返回的格式示例:"中国|0|广东省|深圳市|电信" + const parts = result.province; + const provinceCode = parts[2]; // 省份代码在第三部分 + + // 检查是否是已知的省份代码 + // if (PROVCE_CODE_MAP[provinceCode]) { + // return PROVINCE_CODE_MAP[provinceCode]; + // } + + // 如果未映射,返回原始代码(可能是数据库更新后的新代码) + return parts || '其他'; + } catch (error) { + console.error('IP 解析失败:', error); + return '其他'; + } +} diff --git a/server/laf-cloud/functions/userLevel.yaml b/server/laf-cloud/functions/userLevel.yaml new file mode 100644 index 00000000..9d86d5bb --- /dev/null +++ b/server/laf-cloud/functions/userLevel.yaml @@ -0,0 +1,6 @@ +name: userLevel +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/userPower.ts b/server/laf-cloud/functions/userPower.ts new file mode 100644 index 00000000..53ec8c89 --- /dev/null +++ b/server/laf-cloud/functions/userPower.ts @@ -0,0 +1,54 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +import Utils from "@/Utils"; +export default async function (ctx: FunctionContext) { + const action = ctx.body.action; + const uid = ctx.body.uid; + let dbname = "users"; + const gameName = ctx.body.gameName; + if (gameName == "iaa") { + dbname = "usersAd"; + } + if (!action) { + return { code: 0, data: null, msg: "未获取到action" }; + } + + if (!uid) { + return { code: 0, data: null, msg: "未获取到uid" }; + } + let res = await db.collection(dbname).where({ _id: uid }).getOne(); + const token1 = ctx.body.token; + if (res.data && res.data.token) { + let istoken = Utils.checkToken(token1, res.data.token); + if (!istoken) { + return { code: 0, data: null, msg: "token校验失败" }; + } + } + switch (action) { + case 'save': + let userPowerTime = Number(ctx.body.userPowerTime); + if (!userPowerTime) { + return { code: 0, data: null, msg: "未获取到coinAmount" }; + } + // let ret = await db.collection("users").where({ _id: uid }).getOne(); + // let time=ret.data?.userPowerTime||0; + // if(time { + //如果不是JSON,尝试读取文本 + return await res.text().catch(() => 'Empty response'); + }); + return data.prepay_id; + } + return null; +} +async function sign(nonceStr,timestamp,body) { + const data = `POST\n/v3/pay/transactions/jsapi\n${timestamp}\n${nonceStr}\n${JSON.stringify(body)}\n`; + // 创建签名对象 + const sign = crypto.createSign('RSA-SHA256'); + // 更新签名内容 + sign.update(data); + // 获取存储桶 + const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const privateKeyPem = await res.Body.transformToString(); + // 使用私钥签名(PKCS1 填充) + const signature = sign.sign({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, 'base64'); + // 构建Authorization头 + const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`; + return authorization; +} +/**前端签名*/ +async function frontsign(data) { + // 创建签名对象 + const sign = crypto.createSign('RSA-SHA256'); + // 更新签名内容 + sign.update(data); + // 获取存储桶 + const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const privateKeyPem = await res.Body.transformToString(); + // 使用私钥签名(PKCS1 填充) + const signature = sign.sign({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, 'base64'); + // 构建Authorization头 + return signature +} +const propName={ + gold_1: "金币包1", + gold_2: "金币包2", + gold_3: "金币包3", + gold_4: "金币包4", + gold_5: "金币包5", + gold_6: "金币包6", + unlimited_health_bundle_1:"无限体力组合包1", + unlimited_health_bundle_2:"无限体力组合包2", + unlimited_health_bundle_3:"无限体力组合包3", + freeze_in_game:"局内购买冻结", + hammer_in_game:"局内购买锤子", + wand_in_gamerefill:"局内购买魔棒", + health:"补满体力" +}; + +async function PostMsg(OpenId, msg) { + let token = cloud.shared.get('wxaccess_token'); + if (!token) { + return { code: 0, data: null, msg: "token获取失败" }; + } + const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token}`; + const data = { + "touser": OpenId, + "msgtype": "text", + "text": + { + "content": msg + } + } + + const res = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(data) + }) + return "ok" +} +async function PostImg(OpenId, outTradeNo, name, count, price) { + let token = cloud.shared.get('wxaccess_token'); + if (!token) { + return { code: 0, data: null, msg: "token获取失败" }; + } + const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${token}`; + const nonceStr = crypto.randomBytes(16).toString('hex'); + const timestamp = Math.floor(Date.now() / 1000).toString(); + const total=count*price; + let prepay_id = await getOrder(OpenId,total,outTradeNo,timestamp,nonceStr); + let frontBody={ + "appId": appid, //公众号ID,由商户传入 + "timeStamp": timestamp, //时间戳,自1970年以来的秒数 + "nonceStr": nonceStr, //随机串 + "package": "prepay_id=" + prepay_id + } + const data1 = `${frontBody.appId}\n${frontBody.timeStamp}\n${frontBody.nonceStr}\n${frontBody.package}\n`; + let paySign=await frontsign(data1); + + let user = await db.collection("users").where({ openid: OpenId }).update({iosTime:frontBody.timeStamp}); + let param={ + name:propName[name], + openid:OpenId, + outTradeNo: outTradeNo, + time:timestamp, + quantity:count, + price:price, + body:{ + "appId": frontBody.appId, //公众号ID,由商户传入 + "timeStamp": frontBody.timeStamp, //时间戳,自1970年以来的秒数 + "nonceStr": frontBody.nonceStr, //随机串 + "package": frontBody.package, + "signType": "RSA", //微信签名方式: + "paySign": paySign //微信签名 + } + } + await db.collection("iosOrder").add({ + openid: OpenId, + outTradeNo: outTradeNo, + itemid: name, + itemCount: count, + goodsPrice: Number(price), + time: Date.now(), + type: "ios", + state: 0, + }); + const data = { + "touser": OpenId, + "msgtype": "link", + "link": { + "title": "点我支付", + "description": "金额:" + (total/100).toFixed(2) + "元", + "url": `https://pay.nika4games.com/order2.html#data=${encodeURIComponent(JSON.stringify(param))}`, + "thumb_url": "https://static-host-j3k323ol-colorblock-oss.sealoshzh.site/icon.jpg" + } + } + //console.log(data); + const res = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json;charset=utf-8' + }, + body: JSON.stringify(data) + }) + const data11 = await res.json(); + if (data11.errcode == 40001){ + console.error("未获取到正确token,重新发送请求"); + let res = await getWxToken(); + await PostMsg(OpenId, "点击下方页面进行充值"); + await PostImg(OpenId, outTradeNo, name, count, price); + } + return "ok" +} + + +/**获取微信Token*/ +async function getWxToken() { + const api_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${appsecret}`; + const ret = await cloud.fetch({ + url: api_url, + method: "get", + }); + if (ret?.data?.access_token) { + cloud.shared.set('wxaccess_token', ret.data.access_token); + return ret.data.access_token; + } else { + //access_token = null; + return null; + } +} diff --git a/server/laf-cloud/functions/wx/KeFuInfo.yaml b/server/laf-cloud/functions/wx/KeFuInfo.yaml new file mode 100644 index 00000000..e2cd7a5c --- /dev/null +++ b/server/laf-cloud/functions/wx/KeFuInfo.yaml @@ -0,0 +1,6 @@ +name: wx/KeFuInfo +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/checkIos.ts b/server/laf-cloud/functions/wx/checkIos.ts new file mode 100644 index 00000000..9501fe0a --- /dev/null +++ b/server/laf-cloud/functions/wx/checkIos.ts @@ -0,0 +1,38 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +export default async function (ctx: FunctionContext) { + let openid=ctx.body.openid; + let time=ctx.body.time; + let outTradeNo = ctx.body.outTradeNo; + if(!openid||!time){ + return false; + } + let user = await db.collection("users").where({ openid:openid}).getOne(); + if(user.data){ + if (user.data.iosTime ==time){ + let res = await db.collection("iosOrder").where({ outTradeNo: outTradeNo }).getOne(); + if (res.data) { + await db.collection("order").add({ + openid: res.data.openid, + outTradeNo: res.data.outTradeNo, + itemid: res.data.itemid, + itemCount: res.data.itemCount, + goodsPrice: res.data.goodsPrice, + time: res.data.time, + type: "ios", + state: 0, + }); + db.collection("iosOrder").where({ outTradeNo: outTradeNo }).remove({ multi: true }); + return true; + } else { + let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); + if(res.data){ + console.log("验证成功"); + return true; + } + return false; + } + } + } + return false; +} diff --git a/server/laf-cloud/functions/wx/checkIos.yaml b/server/laf-cloud/functions/wx/checkIos.yaml new file mode 100644 index 00000000..31003a20 --- /dev/null +++ b/server/laf-cloud/functions/wx/checkIos.yaml @@ -0,0 +1,6 @@ +name: wx/checkIos +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/getOrderReward.ts b/server/laf-cloud/functions/wx/getOrderReward.ts new file mode 100644 index 00000000..659d819c --- /dev/null +++ b/server/laf-cloud/functions/wx/getOrderReward.ts @@ -0,0 +1,10 @@ +import cloud from '@lafjs/cloud' +const db = cloud.database(); +export default async function (ctx: FunctionContext) { + let outTradeNo = ctx.body.outTradeNo; + if(!outTradeNo){ + return { code: 0, data:null, msg: "未获取到outTradeNo" }; + } + let res=await db.collection("order").where({ outTradeNo: outTradeNo }).update({ state: 2 }); + return { code:1, data:"ok", msg: "成功" }; +} diff --git a/server/laf-cloud/functions/wx/getOrderReward.yaml b/server/laf-cloud/functions/wx/getOrderReward.yaml new file mode 100644 index 00000000..1d72577b --- /dev/null +++ b/server/laf-cloud/functions/wx/getOrderReward.yaml @@ -0,0 +1,6 @@ +name: wx/getOrderReward +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/getPayInfo.ts b/server/laf-cloud/functions/wx/getPayInfo.ts new file mode 100644 index 00000000..7584a884 --- /dev/null +++ b/server/laf-cloud/functions/wx/getPayInfo.ts @@ -0,0 +1,172 @@ +import cloud from '@lafjs/cloud' +import * as crypto from 'crypto'; +const db = cloud.database(); +const ThinkingData = require('thinkingdata-node'); +export default async function (ctx: FunctionContext) { + let uid = ctx.body.uid; + let outTradeNo = ctx.body.outTradeNo; + let user = await db.collection("users").where({ _id: uid }).getOne(); + if (user.data == null) { + return { code: 0, data: null, msg: "未获取到玩家数据" }; + } + let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); + if (res.data.state == 1) { + return { + code: 1, data: { + pay_state: 2 + }, msg: "成功" + }; + } else if (res.data.state == 2) { + return { + code: 1, data: { + pay_state: 1, + }, msg: "已领取奖励" + } + } else { + return { + code: 0, data: { + pay_state: 1, + }, msg: "充值未成功" + } + }; + // let time =Date.now(); + // let uid = ctx.body.uid; + // let outTradeNo = ctx.body.outTradeNo; + // let user = await db.collection("users").where({ _id: uid }).getOne(); + // if (user.data == null) { + // return { code: 0, data: null, msg: "未获取到玩家数据" }; + // } + + // let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); + // if (res.data.state == 1) { + // return { code: 1, data:{ + // pay_state:2 + // }, msg: "成功" }; + // }else{ + // return {code:1,data:{ + // pay_state:1, + // },msg:"失败"} + // }; + // let session_key = user.data.session_key; + // let token = cloud.shared.get('wxaccess_token'); + // if (!token) { + // return { code: 0, data: null, msg: "token获取失败" }; + // } + // const info = { + // "openid": user.data.openid, + // "offer_id": "1450390549", + // "ts": Math.floor(Date.now() / 1000), + // "zone_id": "1", + // "env": 0, + // "out_trade_no": outTradeNo, + // "biz_id": 2 + // } + // const signature = hmacSha256(session_key, JSON.stringify(info)); + // const key = "4HfZwqLjVkLb6s4TfIxRGKaTxgvvL1rl"; + // let data = '/wxa/game/queryorderinfo' + '&' + JSON.stringify(info); + // const pay_sig = hmacSha256(key, data); + // const url = `https://api.weixin.qq.com/wxa/game/queryorderinfo?access_token=${token}&signature=${signature}&sig_method=hmac_sha256&pay_sig=${pay_sig}`; + // const response = await cloud.fetch(url, { + // url: url, + // method: 'POST', + // headers: { + // 'Content-Type': 'application/json;charset=utf-8' + // }, + // data: JSON.stringify(info) + // }) + // // console.log("查询充值结果"); + // // console.log(response.data); + // let ret = await db.collection("order").where({ "outTradeNo": outTradeNo }).getOne(); + // let payment_name = ""; + // if (ret.data) { + // if(propName[ret.data.itemid]){ + // payment_name = propName[ret.data.itemid]; + // }else{ + // payment_name = ret.data.itemid; + // } + // } + // response.data.payment_name=payment_name; + // response.data.goodsPrice=ret.data.goodsPrice; + // //console.error("充值结果"); + // //console.log(response.data); + // if (response.data.pay_state==2){ + // let res = await db.collection("order").where({ outTradeNo:outTradeNo}).getOne(); + // // console.log(res); + // // console.log + // if(res.data&&res.data.state==0){ + // await db.collection("order").where({ outTradeNo:outTradeNo}).update({ state: 1 }); + // sead(res.data, user.data, getClientIp(ctx)); + // console.error("充值结果:"+(Date.now()-time)); + // } + // } + //return { code: 1, data: response.data, msg: "成功" }; +} +const propName = { + "金币包1": "gold_1", + "金币包2": "gold_2", + "金币包3": "gold_3", + "金币包4": "gold_4", + "金币包5": "gold_5", + "金币包6": "gold_6", + "无限体力组合包1": "unlimited_health_bundle_1", + "无限体力组合包2": "unlimited_health_bundle_2", + "无限体力组合包3": "unlimited_health_bundle_3", + "局内购买冻结": "freeze_in_game", + "局内购买锤子": "hammer_in_game", + "局内购买魔棒": "wand_in_gamerefill", + "补满体力": "health", + "新手礼包": "starter_pack", +}; +function hmacSha256(sessionKey, signData) { + const hmac = crypto.createHmac('sha256', sessionKey); + hmac.update(signData); + return hmac.digest('hex'); +} +const getClientIp = (req) => { + return ( + req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP + req.headers['x-real-ip'] || // Nginx 配置的 real-ip + req.socket.remoteAddress // 原始 IP(可能是代理) + ); +}; +async function sead(order, userInfo, ip) { + console.error("上传数数"); + //db.collection("susu").add({order: order,time: Date.now()}); + if (!userInfo.distinctId) { + console.log("未找到distinctId无法上传数数") + return; + } + let id = '87d18958cea145f29d3265470ecd3486'; + if (userInfo.isDebug != "true") { + id = '121591378fc1423893deb12041413eb3'; + } + let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', { + dryRun: false, // report data to TE or not + deviceId: "123456789",//设备唯一标识 + }); + let trackEvent = { + accountId: order.openid, + distinctId: userInfo.distinctId,//访客id + event: 'payment', + time: new Date(Date.now() + 8 * 3600000), + ip: ip, + properties: { + order_id: order.outTradeNo, + pay_amount: order.goodsPrice, + payment_name: order.itemid, + payment_num: order.itemCount, + payment_type: "Android", + current_level: userInfo.levelAmount, //当前关卡等级 number + current_health: userInfo.healthAmount, //当前体力值 + tmp_coin: userInfo.coinAmount,//当前金币 + version: "1.6", + user_id: userInfo._id, //用户id + pay_user: userInfo.pay_user, + register_time: userInfo.register_time + }, + callback(e) {if (e) {}} + }; + teSDK.track(trackEvent); + teSDK.close(); + return; +} diff --git a/server/laf-cloud/functions/wx/getPayInfo.yaml b/server/laf-cloud/functions/wx/getPayInfo.yaml new file mode 100644 index 00000000..2cc40098 --- /dev/null +++ b/server/laf-cloud/functions/wx/getPayInfo.yaml @@ -0,0 +1,6 @@ +name: wx/getPayInfo +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/iosPayCall.ts b/server/laf-cloud/functions/wx/iosPayCall.ts new file mode 100644 index 00000000..2e5d02eb --- /dev/null +++ b/server/laf-cloud/functions/wx/iosPayCall.ts @@ -0,0 +1,5 @@ +import cloud from '@lafjs/cloud' + +export default async function (ctx: FunctionContext) { + return { data:'scuess' } +} diff --git a/server/laf-cloud/functions/wx/iosPayCall.yaml b/server/laf-cloud/functions/wx/iosPayCall.yaml new file mode 100644 index 00000000..e9e6fcf8 --- /dev/null +++ b/server/laf-cloud/functions/wx/iosPayCall.yaml @@ -0,0 +1,6 @@ +name: wx/iosPayCall +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/iosgetPayInfo.ts b/server/laf-cloud/functions/wx/iosgetPayInfo.ts new file mode 100644 index 00000000..fd44c302 --- /dev/null +++ b/server/laf-cloud/functions/wx/iosgetPayInfo.ts @@ -0,0 +1,157 @@ +import cloud from '@lafjs/cloud' +import crypto from 'crypto'; +const mchid = "1719895437";//商户id +const serialNo = "2A97ED6ED441E55600EBC8830B9EC889ED41496E";//证书序列号 +const db = cloud.database(); +const ThinkingData = require('thinkingdata-node'); +export default async function (ctx: FunctionContext) { + let outTradeNo = ctx.body.outTradeNo; + if (!outTradeNo) { + return { code: 0, data: null, msg: "未获取到充值订单" }; + } + const uid = ctx.body.uid; + let res = await getOrder(outTradeNo); + let ret = await db.collection("order").where({ "outTradeNo": outTradeNo }).getOne(); + let iosOrder = cloud.shared.get("iosOrder"); // 获取 wsMap + if (!ret.data) { + console.error("ios找不到充值订单:" + outTradeNo); + return { code: 0, data: null, msg: "未获取到充值信息" }; + } + if (ret.data.state == 2) { + console.error("ios已经获取奖励"); + return { code: 0, data: null, msg: "已经获取到奖励" }; + } + let payment_name = ret.data?.itemid; + if (res) { + if (uid) { + let res1 = await db.collection("users").where({ _id: uid }).getOne(); + if (!iosOrder) { + iosOrder = {}; + } else { + //console.log(iosOrder); + } + if (!iosOrder[outTradeNo]) { + sead(ret.data, res1.data, getClientIp(ctx)); + iosOrder[outTradeNo] = 2; + } else { + } + + cloud.shared.set("iosOrder", iosOrder); // 设置 wsMap + switch (payment_name) { + case "month_Card": + const now = Date.now(); + const oldMonthCardTime = Number(res1.data.monthCardTime) || 0; + const monthCardTime = Math.max(oldMonthCardTime, now) + 2592000000; + const monthCardReward = oldMonthCardTime > now ? (Number(res1.data.monthCardReward) || 0) : 0; + await db.collection("users").where({ _id: uid }).update({ monthCardTime: monthCardTime, monthCardReward: monthCardReward, pay_user: true }); + await db.collection("order").where({ outTradeNo: outTradeNo }).update({ monthCardGranted: true }); + break; + case "reborn_Gift": + db.collection("users").where({ _id: uid }).update({ rebornGiftTime: Date.now(), rebornGiftCount: 1, pay_user: true }); + break; + case "starter_pack": + db.collection("users").where({ _id: uid }).update({ starter_packState: 1, pay_user: true }); + break; + default: + db.collection("users").where({ _id: uid }).update({ pay_user: true }); + break; + } + } + await db.collection("order").where({ outTradeNo: outTradeNo }).update({ state: 2 }, { multi: true }); + return { code: 1, data: { goodsPrice: ret.data?.goodsPrice, payment_name: payment_name }, msg: "充值成功" }; + } else { + console.log("充值不成功:" + outTradeNo); + return { code: 0, data: { goodsPrice: ret.data?.goodsPrice, payment_name: payment_name }, msg: "充值失败" }; + } + +} +const getClientIp = (req) => { + return ( + req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP + req.headers['x-real-ip'] || // Nginx 配置的 real-ip + req.socket.remoteAddress // 原始 IP(可能是代理) + ); +}; +/**获取订单*/ +async function getOrder(outTradeNo) { + const url = `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437`; + const nonceStr = crypto.randomBytes(16).toString('hex'); + const timestamp = Math.floor(Date.now() / 1000).toString(); + let au = await sign(outTradeNo, nonceStr, timestamp); + let res = await fetch(url, { + method: 'GET', // 默认是 GET,可省略 + headers: { + 'Authorization': au, // 认证令牌 + 'Content-Type': 'application/json', // 声明请求体类型(GET 请求通常不需要) + 'Accept': 'application/json', // 声明期望的响应类型 + } + }) + const data = await res.json(); + if (data.trade_state == 'SUCCESS') { + return true; + } else { + return false; + } +} +async function sign(outTradeNo, nonceStr, timestamp) { + const data = `GET\n/v3/pay/transactions/out-trade-no/${outTradeNo}?mchid=1719895437\n${timestamp}\n${nonceStr}\n\n` + // 创建签名对象 + const sign = crypto.createSign('RSA-SHA256'); + // 更新签名内容 + sign.update(data); + // 获取存储桶 + const bucket = cloud.storage.bucket('j3k323ol-colorblock-oss'); + // 获取文件列表 + const res = await bucket.readFile('apiclient_key.pem'); + const privateKeyPem = await res.Body.transformToString(); + // 使用私钥签名(PKCS1 填充) + const signature = sign.sign({ + key: privateKeyPem, + padding: crypto.constants.RSA_PKCS1_PADDING + }, 'base64'); + // 构建Authorization头 + const authorization = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonceStr}",signature="${signature}",timestamp="${timestamp}",serial_no="${serialNo}"`; + return authorization; +} +async function sead(order, userInfo, ip) { + if (!userInfo.distinctId) { + return; + } + let id = '87d18958cea145f29d3265470ecd3486'; + if (userInfo.isDebug != "true") { + id = '121591378fc1423893deb12041413eb3'; + } + let teSDK = ThinkingData.initWithBatchMode(id, 'https://data.nika4fun.com/sync_data', { + dryRun: false, // report data to TE or not + deviceId: "123456789",//设备唯一标识 + }); + let trackEvent = { + accountId: order.openid, + distinctId: userInfo.distinctId,//访客id + event: 'payment', + time: new Date(Date.now() + 8 * 3600000), + ip: ip, + properties: { + order_id: order.outTradeNo, + pay_amount: order.goodsPrice, + payment_name: order.itemid, + payment_num: order.itemCount, + payment_type: "ios_old", + current_level: userInfo.levelAmount, //当前关卡等级 number + current_health: userInfo.healthAmount, //当前体力值 + tmp_coin: userInfo.coinAmount,//当前金币 + version: "1.6", + user_id: userInfo._id, //用户id + pay_user: userInfo.pay_user, + register_time: userInfo.register_time + }, + callback(e) { + if (e) { + console.log(e); + } + } + }; + teSDK.track(trackEvent); + teSDK.close(); + return; +} diff --git a/server/laf-cloud/functions/wx/iosgetPayInfo.yaml b/server/laf-cloud/functions/wx/iosgetPayInfo.yaml new file mode 100644 index 00000000..f5580e81 --- /dev/null +++ b/server/laf-cloud/functions/wx/iosgetPayInfo.yaml @@ -0,0 +1,6 @@ +name: wx/iosgetPayInfo +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/orderPaySig.ts b/server/laf-cloud/functions/wx/orderPaySig.ts new file mode 100644 index 00000000..14bc19d0 --- /dev/null +++ b/server/laf-cloud/functions/wx/orderPaySig.ts @@ -0,0 +1,51 @@ +import cloud from '@lafjs/cloud' +import * as crypto from 'crypto'; +const db = cloud.database(); +export default async function (ctx: FunctionContext) { + let uid = ctx.body.uid; + let itemid = ctx.body.itemid; + let itemCount = ctx.body.itemCount; + let itemPrice = ctx.body.itemPrice; + let user = await db.collection("users").where({ _id: uid }).getOne(); + if (user.data == null) { + return { code: 0, data: null, msg: "未获取到玩家数据" }; + } + const outTradeNo = `wcx_` + Math.round(Math.random() * 10 ** 13) + Date.now(); + let signData = JSON.stringify({ + "mode": "goods", + "offerId": "1450390549", + "buyQuantity": Number(itemCount),//购买数量 + "env": 0,//正式环境 + "currencyType": "CNY",//人民币 + "platform": "android", + "zoneId": "1",//分区id + "productId": itemid, + "goodsPrice": Number(itemPrice), + "outTradeNo": outTradeNo, + "attach": "购买道具" + }); + let session_key = user.data.session_key; + const signature = hmacSha256(session_key, signData); + let key = "4HfZwqLjVkLb6s4TfIxRGKaTxgvvL1rl"; + let data = 'requestMidasPaymentGameItem' + '&' + signData; + const paySig = hmacSha256(key, data); + await db.collection("order").add({ + openid: user.data.openid, + outTradeNo: outTradeNo, + itemid: itemid, + itemCount: itemCount, + goodsPrice: Number(itemPrice), + time: Date.now(), + type:"and", + state: 0, + }); + // console.log("申请订单"); + // console.log(outTradeNo); + // 计算哈希值并转换为十六进制字符串 + return { code: 1, data: { paySig: paySig, signature: signature, signData: signData, outTradeNo: outTradeNo }, msg: "成功" } +} +function hmacSha256(sessionKey, signData) { + const hmac = crypto.createHmac('sha256', sessionKey); + hmac.update(signData); + return hmac.digest('hex'); +} \ No newline at end of file diff --git a/server/laf-cloud/functions/wx/orderPaySig.yaml b/server/laf-cloud/functions/wx/orderPaySig.yaml new file mode 100644 index 00000000..e582189b --- /dev/null +++ b/server/laf-cloud/functions/wx/orderPaySig.yaml @@ -0,0 +1,6 @@ +name: wx/orderPaySig +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wx/payCallBack.ts b/server/laf-cloud/functions/wx/payCallBack.ts new file mode 100644 index 00000000..dcdc33be --- /dev/null +++ b/server/laf-cloud/functions/wx/payCallBack.ts @@ -0,0 +1,125 @@ +import cloud from '@lafjs/cloud'; +const db = cloud.database(); +const ThinkingData = require('thinkingdata-node'); +export default async function (ctx: FunctionContext) { + let data = JSON.parse(ctx.body.MiniGame.Payload); + let OutTradeNo = data.OutTradeNo; + let res = await db.collection("order").where({ outTradeNo: OutTradeNo }).getOne(); + if(res.data){ + if(res.data.state!=2){ + await db.collection("order").where({ outTradeNo: OutTradeNo }).update({ state: 1 }); + let user = await db.collection("users").where({ openid: res.data.openid}).getOne(); + sead(res.data, user.data, getClientIp(ctx)); + switch (res.data.itemid) { + case "starter_pack": + db.collection("users").where({ _id:user.data._id}).update({ starter_packState: 1, pay_user: true }); + break; + } + if (!user.data.pay_user) { + db.collection("users").where({ _id:user.data._id }).update({ pay_user: true }); + } + } + } + + // let query={ + // signature: '1c1b5c1c72058436e2f1214e6aeafd258e50acd4', + // timestamp: '1751291889', + // nonce: '3122546041' + // } + /** + * ToUserName: 'gh_1092576a6ce7', + FromUserName: 'orm8I7IA-pMesygmTc5HPufGZHvA', + CreateTime: 1751292233, + MsgType: 'event', + MiniGame: { + Payload: '{"OpenId":"orm8I7BRTjhdQ3Mz9V9cg1jzTUcQ","OutTradeNo":"wcx_92778691620421751292218408","WeChatPayInfo":{"MchOrderNo":"20250630714915544","TransactionId":"4200002678202506307565098431"},"Env":0,"GoodsInfo":{"ProductId":"10011","Quantity":1,"ZoneId":"1","OrigPrice":100,"ActualPrice":100,"Attach":"购买道具","OrderSource":1},"PayChannel":0}', + PayEventSig: 'ecdaf472c239894706e28ab941d2aebf727b5bed45fe4073c645e922b6eefc1a', + IsMock: false + }, + Event: 'minigame_game_pay_goods_deliver_notify' + */ + return { "ErrCode": 0, "ErrMsg": "Success" }; + +} + +async function sead1(outTradeNo) { + let res = await db.collection("order").where({ outTradeNo: outTradeNo }).getOne(); + if (res.data.state == 1) { + return { + code: 1, data: { + pay_state: 2 + }, msg: "成功" + }; + } else if (res.data.state == 2) { + let userInfo = await db.collection("users").where({ openid: res.data.openid }).getOne(); + await sead(outTradeNo,userInfo.data,"") + console.log("1"); + return { + code: 1, data: { + pay_state: 1, + }, msg: "已领取奖励" + } + } else { + return { + code: 1, data: { + pay_state: 1, + }, msg: "充值未成功" + } + }; +} + +const getClientIp = (req) => { + return ( + req.headers['x-forwarded-for']?.split(',')[0]?.trim() || // 代理链中的第一个 IP + req.headers['x-real-ip'] || // Nginx 配置的 real-ip + req.socket.remoteAddress // 原始 IP(可能是代理) + ); +}; + + +async function sead(order, userInfo, ip) { + db.collection("susu").add({ + order:order, + time:Date.now() + }); + if (!userInfo.distinctId) { + console.log("未找到distinctId无法上传数数") + return; + } + let id = '87d18958cea145f29d3265470ecd3486'; + if (userInfo.isDebug != "true") { + id = '121591378fc1423893deb12041413eb3'; + } + let teSDK = ThinkingData.initWithBatchMode(id,'https://data.nika4fun.com/sync_data', { + dryRun: false, // report data to TE or not + deviceId: "123456789",//设备唯一标识 + }); + let trackEvent = { + accountId: order.openid, + distinctId: userInfo.distinctId,//访客id + event: 'payment', + time: new Date(Date.now() + 8 * 3600000), + ip: ip, + properties: { + order_id: order.outTradeNo, + pay_amount: order.goodsPrice, + payment_name: order.itemid, + payment_num: order.itemCount, + payment_type: "Android", + current_level: userInfo.levelAmount, //当前关卡等级 number + current_health: userInfo.healthAmount, //当前体力值 + tmp_coin: userInfo.coinAmount,//当前金币 + version: "1.6", + user_id: userInfo._id, //用户id + pay_user: userInfo.pay_user, + register_time: userInfo.register_time + }, + callback(e) { + if (e) { + } + } + }; + teSDK.track(trackEvent); + teSDK.close(); + return; +} \ No newline at end of file diff --git a/server/laf-cloud/functions/wx/payCallBack.yaml b/server/laf-cloud/functions/wx/payCallBack.yaml new file mode 100644 index 00000000..350ac73d --- /dev/null +++ b/server/laf-cloud/functions/wx/payCallBack.yaml @@ -0,0 +1,6 @@ +name: wx/payCallBack +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/functions/wxPerformanceCall.ts b/server/laf-cloud/functions/wxPerformanceCall.ts new file mode 100644 index 00000000..02972a80 --- /dev/null +++ b/server/laf-cloud/functions/wxPerformanceCall.ts @@ -0,0 +1,6 @@ +import cloud from '@lafjs/cloud' + +export default async function (ctx: FunctionContext) { + console.log('Hello World') + return { data: 'hi, laf' } +} diff --git a/server/laf-cloud/functions/wxPerformanceCall.yaml b/server/laf-cloud/functions/wxPerformanceCall.yaml new file mode 100644 index 00000000..ec27c92d --- /dev/null +++ b/server/laf-cloud/functions/wxPerformanceCall.yaml @@ -0,0 +1,6 @@ +name: wxPerformanceCall +desc: "" +methods: + - GET + - POST +tags: [] diff --git a/server/laf-cloud/tsconfig.json b/server/laf-cloud/tsconfig.json new file mode 100644 index 00000000..6c050871 --- /dev/null +++ b/server/laf-cloud/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "allowJs": false, + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "baseUrl": ".", + "paths": { + "@/*": [ + "functions/*" + ] + }, + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "importHelpers": false, + "module": "Node16", + "declarationMap": true, + // "declarationDir": "types", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "outDir": "dist", + "pretty": true, + "removeComments": true, + "stripInternal": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "target": "ES2022", + "alwaysStrict": true, + "lib": [ + "ES2022" + ] + }, + "include": [ + "functions/**/*", + "types/**/*" + ], + "exclude": [ + "tests" + ] +} \ No newline at end of file diff --git a/server/laf-cloud/types/global.d.ts b/server/laf-cloud/types/global.d.ts new file mode 100644 index 00000000..13373181 --- /dev/null +++ b/server/laf-cloud/types/global.d.ts @@ -0,0 +1,1218 @@ +/** + * The input parameters of cloud function calls + */ +declare interface FunctionContext { + __function_name: string + + /** + * This object is parsed from JWT Token Payload + */ + user?: { + [key: string]: any + } + + /** + * Uploaded file, the file object array + */ + files?: File[] + + /** + * HTTP headers + */ + headers?: IncomingHttpHeaders + + /** + * HTTP Query parameter (URL parameter), JSON object + */ + query?: any + + /** + * HTTP Body + */ + body?: any + + /** + * + */ + params?: any + + /** + * HTTP Request ID + */ + requestId?: string + + /** + * HTTP Method + */ + method?: string + + /** + * Express request object + */ + request?: HttpRequest + + /** + * Express response object + */ + response?: HttpResponse + + /** + * WebSocket object + */ + socket?: WebSocket + + [key: string]: any +} + + +// ============ The following is copied from another library and generally does not require direct modification============ + +class IncomingMessage extends Readable { + constructor(socket: Socket); + /** + * The 'message.aborted' property will be 'true' if the request has + * been aborted. + * @since v10.1.0 + * @deprecated Since v17.0.0,v16.12.0 - Check 'message.destroyed' from stream.Readable. + */ + aborted: boolean; + /** + * In case of server request, the HTTP version sent by the client. In the case of + * client response, the HTTP version of the connected-to server. + * Probably either ''1.1'' or ''1.0''. + * + * Also 'message.httpVersionMajor' is the first integer and'message.httpVersionMinor' is the second. + * @since v0.1.1 + */ + httpVersion: string; + httpVersionMajor: number; + httpVersionMinor: number; + /** + * The 'message.complete' property will be 'true' if a complete HTTP message has + * been received and successfully parsed. + * + * This property is particularly useful as a means of determining if a client or + * server fully transmitted a message before a connection was terminated: + * + * '''js + * const req = http.request({ + * host: '127.0.0.1', + * port: 8080, + * method: 'POST' + * }, (res) => { + * res.resume(); + * res.on('end', () => { + * if (!res.complete) + * console.error( + * 'The connection was terminated while the message was still being sent'); + * }); + * }); + * ''' + * @since v0.3.0 + */ + complete: boolean; + /** + * Alias for 'message.socket'. + * @since v0.1.90 + * @deprecated Since v16.0.0 - Use 'socket'. + */ + connection: Socket; + /** + * The 'net.Socket' object associated with the connection. + * + * With HTTPS support, use 'request.socket.getPeerCertificate()' to obtain the + * client's authentication details. + * + * This property is guaranteed to be an instance of the 'net.Socket' class, + * a subclass of 'stream.Duplex', unless the user specified a socket + * type other than 'net.Socket' or internally nulled. + * @since v0.3.0 + */ + socket: Socket; + /** + * The request/response headers object. + * + * Key-value pairs of header names and values. Header names are lower-cased. + * + * '''js + * // Prints something like: + * // + * // { 'user-agent': 'curl/7.22.0', + * // host: '127.0.0.1:8000', + * // accept: '*' } + * console.log(request.getHeaders()); + * ''' + * + * Duplicates in raw headers are handled in the following ways, depending on the + * header name: + * + * * Duplicates of 'age', 'authorization', 'content-length', 'content-type','etag', 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since','last-modified', 'location', + * 'max-forwards', 'proxy-authorization', 'referer','retry-after', 'server', or 'user-agent' are discarded. + * * 'set-cookie' is always an array. Duplicates are added to the array. + * * For duplicate 'cookie' headers, the values are joined together with '; '. + * * For all other headers, the values are joined together with ', '. + * @since v0.1.5 + */ + headers: IncomingHttpHeaders; + /** + * The raw request/response headers list exactly as they were received. + * + * The keys and values are in the same list. It is _not_ a + * list of tuples. So, the even-numbered offsets are key values, and the + * odd-numbered offsets are the associated values. + * + * Header names are not lowercased, and duplicates are not merged. + * + * '''js + * // Prints something like: + * // + * // [ 'user-agent', + * // 'this is invalid because there can be only one', + * // 'User-Agent', + * // 'curl/7.22.0', + * // 'Host', + * // '127.0.0.1:8000', + * // 'ACCEPT', + * // '*' ] + * console.log(request.rawHeaders); + * ''' + * @since v0.11.6 + */ + rawHeaders: string[]; + /** + * The request/response trailers object. Only populated at the ''end'' event. + * @since v0.3.0 + */ + trailers: NodeJS.Dict; + /** + * The raw request/response trailer keys and values exactly as they were + * received. Only populated at the ''end'' event. + * @since v0.11.6 + */ + rawTrailers: string[]; + /** + * Calls 'message.socket.setTimeout(msecs, callback)'. + * @since v0.5.9 + */ + setTimeout(msecs: number, callback?: () => void): this; + /** + * **Only valid for request obtained from {@link Server}.** + * + * The request method as a string. Read only. Examples: ''GET'', ''DELETE''. + * @since v0.1.1 + */ + method?: string | undefined; + /** + * **Only valid for request obtained from {@link Server}.** + * + * Request URL string. This contains only the URL that is present in the actual + * HTTP request. Take the following request: + * + * '''http + * GET /status?name=ryan HTTP/1.1 + * Accept: text/plain + * ''' + * + * To parse the URL into its parts: + * + * '''js + * new URL(request.url, 'http://\${request.getHeaders().host}'); + * ''' + * + * When 'request.url' is ''/status?name=ryan'' and'request.getHeaders().host' is ''localhost:3000'': + * + * '''console + * $ node + * > new URL(request.url, 'http://\${request.getHeaders().host}') + * URL { + * href: 'http://localhost:3000/status?name=ryan', + * origin: 'http://localhost:3000', + * protocol: 'http:', + * username: '', + * password: '', + * host: 'localhost:3000', + * hostname: 'localhost', + * port: '3000', + * pathname: '/status', + * search: '?name=ryan', + * searchParams: URLSearchParams { 'name' => 'ryan' }, + * hash: '' + * } + * ''' + * @since v0.1.90 + */ + url?: string | undefined; + /** + * **Only valid for response obtained from {@link ClientRequest}.** + * + * The 3-digit HTTP response status code. E.G. '404'. + * @since v0.1.1 + */ + statusCode?: number | undefined; + /** + * **Only valid for response obtained from {@link ClientRequest}.** + * + * The HTTP response status message (reason phrase). E.G. 'OK' or 'Internal Server Error'. + * @since v0.11.10 + */ + statusMessage?: string | undefined; + /** + * Calls 'destroy()' on the socket that received the 'IncomingMessage'. If 'error'is provided, an ''error'' event is emitted on the socket and 'error' is passed + * as an argument to any listeners on the event. + * @since v0.3.0 + */ + destroy(error?: Error): this; +} + + +/** +* @see https://expressjs.com/en/api.html#req.params +* +* @example +* app.get('/user/:id', (req, res) => res.send(req.params.id)); // implicitly 'ParamsDictionary' +* app.get(/user\/(.*)/, (req, res) => res.send(req.params[0])); +* app.get('/user/*', (req, res) => res.send(req.params[0])); +*/ +interface HttpRequest extends IncomingMessage { + /** + * Return request header. + * + * The 'Referrer' header field is special-cased, + * both 'Referrer' and 'Referer' are interchangeable. + * + * Examples: + * + * req.get('Content-Type'); + * // => "text/plain" + * + * req.get('content-type'); + * // => "text/plain" + * + * req.get('Something'); + * // => undefined + * + * Aliased as 'req.header()'. + */ + get(name: 'set-cookie'): string[] | undefined; + get(name: string): string | undefined; + + header(name: 'set-cookie'): string[] | undefined; + header(name: string): string | undefined; + + /** + * Check if the given 'type(s)' is acceptable, returning + * the best match when true, otherwise 'undefined', in which + * case you should respond with 406 "Not Acceptable". + * + * The 'type' value may be a single mime type string + * such as "application/json", the extension name + * such as "json", a comma-delimted list such as "json, html, text/plain", + * or an array '["json", "html", "text/plain"]'. When a list + * or array is given the _best_ match, if any is returned. + * + * Examples: + * + * // Accept: text/html + * req.accepts('html'); + * // => "html" + * + * // Accept: text/*, application/json + * req.accepts('html'); + * // => "html" + * req.accepts('text/html'); + * // => "text/html" + * req.accepts('json, text'); + * // => "json" + * req.accepts('application/json'); + * // => "application/json" + * + * // Accept: text/*, application/json + * req.accepts('image/png'); + * req.accepts('png'); + * // => undefined + * + * // Accept: text/*;q=.5, application/json + * req.accepts(['html', 'json']); + * req.accepts('html, json'); + * // => "json" + */ + accepts(): string[]; + accepts(type: string): string | false; + accepts(type: string[]): string | false; + accepts(...type: string[]): string | false; + + /** + * Returns the first accepted charset of the specified character sets, + * based on the request's Accept-Charset HTTP header field. + * If none of the specified charsets is accepted, returns false. + * + * For more information, or if you have issues or concerns, see accepts. + */ + acceptsCharsets(): string[]; + acceptsCharsets(charset: string): string | false; + acceptsCharsets(charset: string[]): string | false; + acceptsCharsets(...charset: string[]): string | false; + + /** + * Returns the first accepted encoding of the specified encodings, + * based on the request's Accept-Encoding HTTP header field. + * If none of the specified encodings is accepted, returns false. + * + * For more information, or if you have issues or concerns, see accepts. + */ + acceptsEncodings(): string[]; + acceptsEncodings(encoding: string): string | false; + acceptsEncodings(encoding: string[]): string | false; + acceptsEncodings(...encoding: string[]): string | false; + + /** + * Returns the first accepted language of the specified languages, + * based on the request's Accept-Language HTTP header field. + * If none of the specified languages is accepted, returns false. + * + * For more information, or if you have issues or concerns, see accepts. + */ + acceptsLanguages(): string[]; + acceptsLanguages(lang: string): string | false; + acceptsLanguages(lang: string[]): string | false; + acceptsLanguages(...lang: string[]): string | false; + + /** + * Parse Range header field, capping to the given 'size'. + * + * Unspecified ranges such as "0-" require knowledge of your resource length. In + * the case of a byte range this is of course the total number of bytes. + * If the Range header field is not given 'undefined' is returned. + * If the Range header field is given, return value is a result of range-parser. + * See more ./types/range-parser/index.d.ts + * + * NOTE: remember that ranges are inclusive, so for example "Range: users=0-3" + * should respond with 4 users when available, not 3. + * + */ + range(size: number, options?: RangeParserOptions): RangeParserRanges | RangeParserResult | undefined; + + /** + * Return an array of Accepted media types + * ordered from highest quality to lowest. + */ + accepted: MediaType[]; + + /** + * @deprecated since 4.11 Use either req.params, req.body or req.query, as applicable. + * + * Return the value of param 'name' when present or 'defaultValue'. + * + * - Checks route placeholders, ex: _/user/:id_ + * - Checks body params, ex: id=12, {"id":12} + * - Checks query string params, ex: ?id=12 + * + * To utilize request bodies, 'req.body' + * should be an object. This can be done by using + * the 'connect.bodyParser()' middleware. + */ + param(name: string, defaultValue?: any): string; + + /** + * Check if the incoming request contains the "Content-Type" + * header field, and it contains the give mime 'type'. + * + * Examples: + * + * // With Content-Type: text/html; charset=utf-8 + * req.is('html'); + * req.is('text/html'); + * req.is('text/*'); + * // => true + * + * // When Content-Type is application/json + * req.is('json'); + * req.is('application/json'); + * req.is('application/*'); + * // => true + * + * req.is('html'); + * // => false + */ + is(type: string | string[]): string | false | null; + + /** + * Return the protocol string "http" or "https" + * when requested with TLS. When the "trust proxy" + * setting is enabled the "X-Forwarded-Proto" header + * field will be trusted. If you're running behind + * a reverse proxy that supplies https for you this + * may be enabled. + */ + protocol: string; + + /** + * Short-hand for: + * + * req.protocol == 'https' + */ + secure: boolean; + + /** + * Return the remote address, or when + * "trust proxy" is 'true' return + * the upstream addr. + */ + ip: string; + + /** + * When "trust proxy" is 'true', parse + * the "X-Forwarded-For" ip address list. + * + * For example if the value were "client, proxy1, proxy2" + * you would receive the array '["client", "proxy1", "proxy2"]' + * where "proxy2" is the furthest down-stream. + */ + ips: string[]; + + /** + * Return subdomains as an array. + * + * Subdomains are the dot-separated parts of the host before the main domain of + * the app. By default, the domain of the app is assumed to be the last two + * parts of the host. This can be changed by setting "subdomain offset". + * + * For example, if the domain is "tobi.ferrets.example.com": + * If "subdomain offset" is not set, req.subdomains is '["ferrets", "tobi"]'. + * If "subdomain offset" is 3, req.subdomains is '["tobi"]'. + */ + subdomains: string[]; + + /** + * Short-hand for 'url.parse(req.url).pathname'. + */ + path: string; + + /** + * Parse the "Host" header field hostname. + */ + hostname: string; + + /** + * @deprecated Use hostname instead. + */ + host: string; + + /** + * Check if the request is fresh, aka + * Last-Modified and/or the ETag + * still match. + */ + fresh: boolean; + + /** + * Check if the request is stale, aka + * "Last-Modified" and / or the "ETag" for the + * resource has changed. + */ + stale: boolean; + + /** + * Check if the request was an _XMLHttpRequest_. + */ + xhr: boolean; + + //body: { username: string; password: string; remember: boolean; title: string; }; + body: ReqBody; + + //cookies: { string; remember: boolean; }; + cookies: any; + + method: string; + + params: P; + + query: ReqQuery; + + route: any; + + signedCookies: any; + + originalUrl: string; + + url: string; + + baseUrl: string; + + app: Application; + + /** + * After middleware.init executed, Request will contain res and next properties + * See: express/lib/middleware/init.js + */ + res?: Response | undefined; + next?: NextFunction | undefined; +} + + +declare class OutgoingMessage extends Writable { + readonly req: IncomingMessage; + chunkedEncoding: boolean; + shouldKeepAlive: boolean; + useChunkedEncodingByDefault: boolean; + sendDate: boolean; + /** + * @deprecated Use 'writableEnded' instead. + */ + // finished: boolean; + /** + * Read-only. 'true' if the headers were sent, otherwise 'false'. + * @since v0.9.3 + */ + readonly headersSent: boolean; + /** + * Aliases of 'outgoingMessage.socket' + * @since v0.3.0 + * @deprecated Since v15.12.0 - Use 'socket' instead. + */ + // readonly connection: Socket | null; + /** + * Reference to the underlying socket. Usually, users will not want to access + * this property. + * + * After calling 'outgoingMessage.end()', this property will be nulled. + * @since v0.3.0 + */ + readonly socket: Socket | null; + constructor(); + /** + * occurs, Same as binding to the 'timeout' event. + * + * Once a socket is associated with the message and is connected,'socket.setTimeout()' will be called with 'msecs' as the first parameter. + * @since v0.9.12 + * @param callback Optional function to be called when a timeout + */ + setTimeout(msecs: number, callback?: () => void): this; + /** + * Sets a single header value for the header object. + * @since v0.4.0 + * @param name Header name + * @param value Header value + */ + setHeader(name: string, value: number | string | ReadonlyArray): this; + /** + * Gets the value of HTTP header with the given name. If such a name doesn't + * exist in message, it will be 'undefined'. + * @since v0.4.0 + * @param name Name of header + */ + getHeader(name: string): number | string | string[] | undefined; + /** + * Returns a shallow copy of the current outgoing headers. Since a shallow + * copy is used, array values may be mutated without additional calls to + * various header-related HTTP module methods. The keys of the returned + * object are the header names and the values are the respective header + * values. All header names are lowercase. + * + * The object returned by the 'outgoingMessage.getHeaders()' method does + * not prototypically inherit from the JavaScript Object. This means that + * typical Object methods such as 'obj.toString()', 'obj.hasOwnProperty()', + * and others are not defined and will not work. + * + * outgoingMessage.setHeader('Foo', 'bar'); + * outgoingMessage.setHeader('Set-Cookie', ['foo=bar', 'bar=baz']); + * + * const headers = outgoingMessage.getHeaders(); + * // headers === { foo: 'bar', 'set-cookie': ['foo=bar', 'bar=baz'] } + * + * @since v8.0.0 + */ + getHeaders(): OutgoingHttpHeaders; + /** + * Returns an array of names of headers of the outgoing outgoingMessage. All + * names are lowercase. + * @since v8.0.0 + */ + getHeaderNames(): string[]; + /** + * Returns 'true' if the header identified by 'name' is currently set in the + * outgoing headers. The header name is case-insensitive. + * + * const hasContentType = outgoingMessage.hasHeader('content-type'); + * + * @since v8.0.0 + */ + hasHeader(name: string): boolean; + /** + * Removes a header that is queued for implicit sending. + * + * outgoingMessage.removeHeader('Content-Encoding'); + * + * @since v0.4.0 + */ + removeHeader(name: string): void; + /** + * Adds HTTP trailers (headers but at the end of the message) to the message. + * + * Trailers are **only** be emitted if the message is chunked encoded. If not, + * the trailer will be silently discarded. + * + * HTTP requires the 'Trailer' header to be sent to emit trailers, + * with a list of header fields in its value, e.g. + * + * message.writeHead(200, { 'Content-Type': 'text/plain', + * 'Trailer': 'Content-MD5' }); + * message.write(fileData); + * message.addTrailers({ 'Content-MD5': '7895bf4b8828b55ceaf47747b4bca667' }); + * message.end(); + * + * Attempting to set a header field name or value that contains invalid characters + * will result in a 'TypeError' being thrown. + * @since v0.3.0 + */ + addTrailers(headers: OutgoingHttpHeaders | ReadonlyArray<[string, string]>): void; + /** + * Compulsorily flushes the message headers + * + * For efficiency reason, Node.js normally buffers the message headers + * until 'outgoingMessage.end()' is called or the first chunk of message data + * is written. It then tries to pack the headers and data into a single TCP + * packet. + * + * It is usually desired (it saves a TCP round-trip), but not when the first + * data is not sent until possibly much later. 'outgoingMessage.flushHeaders()' bypasses the optimization and kickstarts the request. + * @since v1.6.0 + */ + flushHeaders(): void; +} + +declare class ServerResponse extends OutgoingMessage { + statusCode: number; + statusMessage: string; + + constructor(req: IncomingMessage); + + assignSocket(socket: Socket): void; + detachSocket(socket: Socket): void; + // https://github.com/nodejs/node/blob/master/test/parallel/test-http-write-callbacks.js#L53 + // no args in writeContinue callback + writeContinue(callback?: () => void): void; + writeHead(statusCode: number, reasonPhrase?: string, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this; + writeHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this; + writeProcessing(): void; +} + +interface HttpResponse extends ServerResponse { + /** + * Set status 'code'. + */ + status(code: StatusCode): this; + + /** + * Set the response HTTP status code to 'statusCode' and send its string representation as the response body. + * @link http://expressjs.com/4x/api.html#res.sendStatus + * + * Examples: + * + * res.sendStatus(200); // equivalent to res.status(200).send('OK') + * res.sendStatus(403); // equivalent to res.status(403).send('Forbidden') + * res.sendStatus(404); // equivalent to res.status(404).send('Not Found') + * res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error') + */ + sendStatus(code: StatusCode): this; + + /** + * Set Link header field with the given 'links'. + * + * Examples: + * + * res.links({ + * next: 'http://api.example.com/users?page=2', + * last: 'http://api.example.com/users?page=5' + * }); + */ + links(links: any): this; + + /** + * Send a response. + * + * Examples: + * + * res.send(new Buffer('wahoo')); + * res.send({ some: 'json' }); + * res.send('

some html

'); + * res.status(404).send('Sorry, cant find that'); + */ + send: Send; + + /** + * Send JSON response. + * + * Examples: + * + * res.json(null); + * res.json({ user: 'tj' }); + * res.status(500).json('oh noes!'); + * res.status(404).json('I dont have that'); + */ + json: Send; + + /** + * Send JSON response with JSONP callback support. + * + * Examples: + * + * res.jsonp(null); + * res.jsonp({ user: 'tj' }); + * res.status(500).jsonp('oh noes!'); + * res.status(404).jsonp('I dont have that'); + */ + jsonp: Send; + + /** + * Transfer the file at the given 'path'. + * + * Automatically sets the _Content-Type_ response header field. + * The callback 'fn(err)' is invoked when the transfer is complete + * or when an error occurs. Be sure to check 'res.headersSent' + * if you wish to attempt responding, as the header and some data + * may have already been transferred. + * + * Options: + * + * - 'maxAge' defaulting to 0 (can be string converted by 'ms') + * - 'root' root directory for relative filenames + * - 'headers' object of headers to serve with file + * - 'dotfiles' serve dotfiles, defaulting to false; can be '"allow"' to send them + * + * Other options are passed along to 'send'. + * + * Examples: + * + * The following example illustrates how 'res.sendFile()' may + * be used as an alternative for the 'static()' middleware for + * dynamic situations. The code backing 'res.sendFile()' is actually + * the same code, so HTTP cache support etc is identical. + * + * app.get('/user/:uid/photos/:file', function(req, res){ + * var uid = req.params.uid + * , file = req.params.file; + * + * req.user.mayViewFilesFrom(uid, function(yes){ + * if (yes) { + * res.sendFile('/uploads/' + uid + '/' + file); + * } else { + * res.send(403, 'Sorry! you cant see that.'); + * } + * }); + * }); + * + * @api public + */ + sendFile(path: string, fn?: Errback): void; + sendFile(path: string, options: any, fn?: Errback): void; + + /** + * @deprecated Use sendFile instead. + */ + // sendfile(path: string): void; + /** + * @deprecated Use sendFile instead. + */ + // sendfile(path: string, options: any): void; + /** + * @deprecated Use sendFile instead. + */ + // sendfile(path: string, fn: Errback): void; + /** + * @deprecated Use sendFile instead. + */ + // sendfile(path: string, options: any, fn: Errback): void; + + /** + * Transfer the file at the given 'path' as an attachment. + * + * Optionally providing an alternate attachment 'filename', + * and optional callback 'fn(err)'. The callback is invoked + * when the data transfer is complete, or when an error has + * ocurred. Be sure to check 'res.headersSent' if you plan to respond. + * + * The optional options argument passes through to the underlying + * res.sendFile() call, and takes the exact same parameters. + * + * This method uses 'res.sendfile()'. + */ + download(path: string, fn?: Errback): void; + download(path: string, filename: string, fn?: Errback): void; + download(path: string, filename: string, options: any, fn?: Errback): void; + + /** + * Set _Content-Type_ response header with 'type' through 'mime.lookup()' + * when it does not contain "/", or set the Content-Type to 'type' otherwise. + * + * Examples: + * + * res.type('.html'); + * res.type('html'); + * res.type('json'); + * res.type('application/json'); + * res.type('png'); + */ + contentType(type: string): this; + + /** + * Set _Content-Type_ response header with 'type' through 'mime.lookup()' + * when it does not contain "/", or set the Content-Type to 'type' otherwise. + * + * Examples: + * + * res.type('.html'); + * res.type('html'); + * res.type('json'); + * res.type('application/json'); + * res.type('png'); + */ + type(type: string): this; + + /** + * Respond to the Acceptable formats using an 'obj' + * of mime-type callbacks. + * + * This method uses 'req.accepted', an array of + * acceptable types ordered by their quality values. + * When "Accept" is not present the _first_ callback + * is invoked, otherwise the first match is used. When + * no match is performed the server responds with + * 406 "Not Acceptable". + * + * Content-Type is set for you, however if you choose + * you may alter this within the callback using 'res.type()' + * or 'res.set('Content-Type', ...)'. + * + * res.format({ + * 'text/plain': function(){ + * res.send('hey'); + * }, + * + * 'text/html': function(){ + * res.send('

hey

'); + * }, + * + * 'appliation/json': function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * In addition to canonicalized MIME types you may + * also use extnames mapped to these types: + * + * res.format({ + * text: function(){ + * res.send('hey'); + * }, + * + * html: function(){ + * res.send('

hey

'); + * }, + * + * json: function(){ + * res.send({ message: 'hey' }); + * } + * }); + * + * By default Express passes an 'Error' + * with a '.status' of 406 to 'next(err)' + * if a match is not made. If you provide + * a '.default' callback it will be invoked + * instead. + */ + format(obj: any): this; + + /** + * Set _Content-Disposition_ header to _attachment_ with optional 'filename'. + */ + attachment(filename?: string): this; + + /** + * Set header 'field' to 'val', or pass + * an object of header fields. + * + * Examples: + * + * res.set('Foo', ['bar', 'baz']); + * res.set('Accept', 'application/json'); + * res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' }); + * + * Aliased as 'res.header()'. + */ + set(field: any): this; + set(field: string, value?: string | string[]): this; + + header(field: any): this; + header(field: string, value?: string | string[]): this; + + // Property indicating if HTTP headers has been sent for the response. + headersSent: boolean; + + /** Get value for header 'field'. */ + get(field: string): string; + + /** Clear cookie 'name'. */ + clearCookie(name: string, options?: any): this; + + /** + * Set cookie 'name' to 'val', with the given 'options'. + * + * Options: + * + * - 'maxAge' max-age in milliseconds, converted to 'expires' + * - 'signed' sign the cookie + * - 'path' defaults to "/" + * + * Examples: + * + * // "Remember Me" for 15 minutes + * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); + * + * // save as above + * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) + */ + cookie(name: string, val: string, options: CookieOptions): this; + cookie(name: string, val: any, options: CookieOptions): this; + cookie(name: string, val: any): this; + + /** + * Set the location header to 'url'. + * + * The given 'url' can also be the name of a mapped url, for + * example by default express supports "back" which redirects + * to the _Referrer_ or _Referer_ headers or "/". + * + * Examples: + * + * res.location('/foo/bar').; + * res.location('http://example.com'); + * res.location('../login'); // /blog/post/1 -> /blog/login + * + * Mounting: + * + * When an application is mounted and 'res.location()' + * is given a path that does _not_ lead with "/" it becomes + * relative to the mount-point. For example if the application + * is mounted at "/blog", the following would become "/blog/login". + * + * res.location('login'); + * + * While the leading slash would result in a location of "/login": + * + * res.location('/login'); + */ + location(url: string): this; + + /** + * Redirect to the given 'url' with optional response 'status' + * defaulting to 302. + * + * The resulting 'url' is determined by 'res.location()', so + * it will play nicely with mounted apps, relative paths, + * '"back"' etc. + * + * Examples: + * + * res.redirect('/foo/bar'); + * res.redirect('http://example.com'); + * res.redirect(301, 'http://example.com'); + * res.redirect('http://example.com', 301); + * res.redirect('../login'); // /blog/post/1 -> /blog/login + */ + redirect(url: string): void; + redirect(status: number, url: string): void; + redirect(url: string, status: number): void; + + /** + * Render 'view' with the given 'options' and optional callback 'fn'. + * When a callback function is given a response will _not_ be made + * automatically, otherwise a response of _200_ and _text/html_ is given. + * + * Options: + * + * - 'cache' boolean hinting to the engine it should cache + * - 'filename' filename of the view being rendered + */ + render(view: string, options?: object, callback?: (err: Error, html: string) => void): void; + render(view: string, callback?: (err: Error, html: string) => void): void; + + locals: Locals; + + charset: string; + + /** + * Adds the field to the Vary response header, if it is not there already. + * Examples: + * + * res.vary('User-Agent').render('docs'); + * + */ + vary(field: string): this; + + // app: Application; + + /** + * Appends the specified value to the HTTP response header field. + * If the header is not already set, it creates the header with the specified value. + * The value parameter can be a string or an array. + * + * Note: calling res.set() after res.append() will reset the previously-set header value. + * + * @since 4.11.0 + */ + append(field: string, value?: string[] | string): this; + + /** + * After middleware.init executed, Response will contain req property + * See: express/lib/middleware/init.js + */ + // req?: Request; +} + + + + +// WebSocket socket. +declare class WebSocket extends EventEmitter { + /** The connection is not yet open. */ + static readonly CONNECTING: 0; + /** The connection is open and ready to communicate. */ + static readonly OPEN: 1; + /** The connection is in the process of closing. */ + static readonly CLOSING: 2; + /** The connection is closed. */ + static readonly CLOSED: 3; + + binaryType: "nodebuffer" | "arraybuffer" | "fragments"; + readonly bufferedAmount: number; + readonly extensions: string; + readonly protocol: string; + /** The current state of the connection */ + readonly readyState: + | typeof WebSocket.CONNECTING + | typeof WebSocket.OPEN + | typeof WebSocket.CLOSING + | typeof WebSocket.CLOSED; + readonly url: string; + + /** The connection is not yet open. */ + readonly CONNECTING: 0; + /** The connection is open and ready to communicate. */ + readonly OPEN: 1; + /** The connection is in the process of closing. */ + readonly CLOSING: 2; + /** The connection is closed. */ + readonly CLOSED: 3; + + onopen: (event: WebSocket.Event) => void; + onerror: (event: WebSocket.ErrorEvent) => void; + onclose: (event: WebSocket.CloseEvent) => void; + onmessage: (event: WebSocket.MessageEvent) => void; + + constructor(address: string | URL, options?: WebSocket.ClientOptions | ClientRequestArgs); + constructor( + address: string | URL, + protocols?: string | string[], + options?: WebSocket.ClientOptions | ClientRequestArgs, + ); + + close(code?: number, data?: string | Buffer): void; + ping(data?: any, mask?: boolean, cb?: (err: Error) => void): void; + pong(data?: any, mask?: boolean, cb?: (err: Error) => void): void; + send(data: any, cb?: (err?: Error) => void): void; + send( + data: any, + options: { mask?: boolean | undefined; binary?: boolean | undefined; compress?: boolean | undefined; fin?: boolean | undefined }, + cb?: (err?: Error) => void, + ): void; + terminate(): void; + + // HTML5 WebSocket events + addEventListener( + method: "message", + cb: (event: WebSocket.MessageEvent) => void, + options?: WebSocket.EventListenerOptions, + ): void; + addEventListener( + method: "close", + cb: (event: WebSocket.CloseEvent) => void, + options?: WebSocket.EventListenerOptions, + ): void; + addEventListener( + method: "error", + cb: (event: WebSocket.ErrorEvent) => void, + options?: WebSocket.EventListenerOptions, + ): void; + addEventListener( + method: "open", + cb: (event: WebSocket.Event) => void, + options?: WebSocket.EventListenerOptions, + ): void; + + removeEventListener(method: "message", cb: (event: WebSocket.MessageEvent) => void): void; + removeEventListener(method: "close", cb: (event: WebSocket.CloseEvent) => void): void; + removeEventListener(method: "error", cb: (event: WebSocket.ErrorEvent) => void): void; + removeEventListener(method: "open", cb: (event: WebSocket.Event) => void): void; + + // Events + on(event: "close", listener: (this: WebSocket, code: number, reason: Buffer) => void): this; + on(event: "error", listener: (this: WebSocket, err: Error) => void): this; + on(event: "upgrade", listener: (this: WebSocket, request: IncomingMessage) => void): this; + on(event: "message", listener: (this: WebSocket, data: WebSocket.RawData, isBinary: boolean) => void): this; + on(event: "open", listener: (this: WebSocket) => void): this; + on(event: "ping" | "pong", listener: (this: WebSocket, data: Buffer) => void): this; + on( + event: "unexpected-response", + listener: (this: WebSocket, request: ClientRequest, response: IncomingMessage) => void, + ): this; + on(event: string | symbol, listener: (this: WebSocket, ...args: any[]) => void): this; + + once(event: "close", listener: (this: WebSocket, code: number, reason: Buffer) => void): this; + once(event: "error", listener: (this: WebSocket, err: Error) => void): this; + once(event: "upgrade", listener: (this: WebSocket, request: IncomingMessage) => void): this; + once(event: "message", listener: (this: WebSocket, data: WebSocket.RawData, isBinary: boolean) => void): this; + once(event: "open", listener: (this: WebSocket) => void): this; + once(event: "ping" | "pong", listener: (this: WebSocket, data: Buffer) => void): this; + once( + event: "unexpected-response", + listener: (this: WebSocket, request: ClientRequest, response: IncomingMessage) => void, + ): this; + once(event: string | symbol, listener: (this: WebSocket, ...args: any[]) => void): this; + + off(event: "close", listener: (this: WebSocket, code: number, reason: Buffer) => void): this; + off(event: "error", listener: (this: WebSocket, err: Error) => void): this; + off(event: "upgrade", listener: (this: WebSocket, request: IncomingMessage) => void): this; + off(event: "message", listener: (this: WebSocket, data: WebSocket.RawData, isBinary: boolean) => void): this; + off(event: "open", listener: (this: WebSocket) => void): this; + off(event: "ping" | "pong", listener: (this: WebSocket, data: Buffer) => void): this; + off( + event: "unexpected-response", + listener: (this: WebSocket, request: ClientRequest, response: IncomingMessage) => void, + ): this; + off(event: string | symbol, listener: (this: WebSocket, ...args: any[]) => void): this; + + addListener(event: "close", listener: (code: number, reason: Buffer) => void): this; + addListener(event: "error", listener: (err: Error) => void): this; + addListener(event: "upgrade", listener: (request: IncomingMessage) => void): this; + addListener(event: "message", listener: (data: WebSocket.RawData, isBinary: boolean) => void): this; + addListener(event: "open", listener: () => void): this; + addListener(event: "ping" | "pong", listener: (data: Buffer) => void): this; + addListener( + event: "unexpected-response", + listener: (request: ClientRequest, response: IncomingMessage) => void, + ): this; + addListener(event: string | symbol, listener: (...args: any[]) => void): this; + + removeListener(event: "close", listener: (code: number, reason: Buffer) => void): this; + removeListener(event: "error", listener: (err: Error) => void): this; + removeListener(event: "upgrade", listener: (request: IncomingMessage) => void): this; + removeListener(event: "message", listener: (data: WebSocket.RawData, isBinary: boolean) => void): this; + removeListener(event: "open", listener: () => void): this; + removeListener(event: "ping" | "pong", listener: (data: Buffer) => void): this; + removeListener( + event: "unexpected-response", + listener: (request: ClientRequest, response: IncomingMessage) => void, + ): this; + removeListener(event: string | symbol, listener: (...args: any[]) => void): this; +} \ No newline at end of file