server/laf-cloud/functions/userLevel.ts
2026-09-24 17:59:52 +08:00

311 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as GoldMinerServiceModule from "@/goldMiner/service";
import * as GoldMinerRulesModule from "@/goldMiner/config";
const GoldMinerService: any = GoldMinerServiceModule;
const GoldMinerRules: any = GoldMinerRulesModule;
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 = process.env.SRANK_ID;
// if (gameName == "iaa") {
// dbname = "usersAd";
// db1 = "69fabd418463a95668c5e5d3";
// }
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;
}
// B组前15关只推进主线;补报跨过15关时也只计算门槛之后的胜利。
let assignments = res1.data?.abTests;
if (typeof assignments === "string") {
try { assignments = JSON.parse(assignments); } catch { assignments = null; }
}
const assignment = assignments?.layer_1;
const isNewPlayerB = !!assignment && assignment.name === "new1_50" && assignment.enabled !== false
&& ["B", "2"].includes(String(assignment.group).toUpperCase());
const careerCount = isNewPlayerB
? Math.max(levelAmount - 15, 0) - Math.max(oldlevelAmount - 15, 0)
: count;
let add = oldAdd + careerCount;
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);
let rankNum = -1;
if (add >= 5 && isWhite == false) {
rankNum = await rank(db1, uid, add, levelAmount, res1, address, levelTJ);
sendRank(uid, res1.data?.useravatar, res1.data?.username, res1.data?.useravatarIcon, res1.data?.userCat, add, levelTJ, address, res1.data?.unionid);
levelTJ = 1;
careerAmount += 1;
}
let film = res1.data.film;
if (!film && film != 0) {
film = res1.data.levelAmount;
}
film += count;
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() });
let goldMiner: any;
if (ctx.body.goldMiner != null) {
try {
GoldMinerService.authorize(res1.data, ctx.body);
const event = GoldMinerRules.parseObject(ctx.body.goldMiner);
const mode = isWuXian === true || isWuXian === "true" ? "endless" : "main";
if (event.mode !== mode) GoldMinerRules.reject("INVALID_INPUT");
goldMiner = { code: 1, ...await GoldMinerService.recordProgress(uid, { ...res1.data, levelAmount }, event) };
} catch (error) {
goldMiner = GoldMinerRules.failure(error);
}
}
return { code: 1, data: { ...(goldMiner ? { goldMiner } : {}), 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'
}
}
}
async function sendRank(uid, useravatar, username, useravatarIcon, userCat, count, levelTJ, address, unionid) {
let res = await fetch("https://bx7gi3d4oq.sealoshzh.site/userLevel", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
uid: uid,
unionid: unionid,
useravatar: useravatar,
username: username,
useravatarIcon: useravatarIcon,
userCat: userCat,
count: count,
levelTJ: levelTJ,
address: address
})
})
const token1 = await res.json()
return token1;
}
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].userCat = res1.data?.userCat,
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,
userCat: res1.data?.userCat,
levelAmount: levelAmount
});
}
}
} else {
total["all"] = [{
id: uid,
addLevel: add,
time: Date.now(),
username: res1.data?.username,
useravatar: res1.data?.useravatar,
useravatarIcon: res1.data?.useravatarIcon,
userCat: res1.data?.userCat,
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].userCat = res1.data?.userCat,
total[address][i].addLevel = add;
total[address][i].time = Date.now();
break;
}
}
if (isHave == false) {
let length = total[address].length;
if (length < 30 || 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,
userCat: res1.data?.userCat,
levelAmount: levelAmount
});
}
}
} else {
total[address] = [{
id: uid,
addLevel: add,
time: Date.now(),
username: res1.data?.username,
useravatar: res1.data?.useravatar,
useravatarIcon: res1.data?.useravatarIcon,
userCat: res1.data?.userCat,
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 >= 30) {
total[address] = total[address].slice(0, 30);
}
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.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 '其他';
}
}