云环境和本地调试 添加
This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
// 登录认证模块
|
||||
const {
|
||||
getNewUserInitData,
|
||||
mergeUserDataWithDefaults,
|
||||
checkDataVersionCompatibility
|
||||
} = require('../user_init_data');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 用户登录处理
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {Object} wxContext 微信上下文
|
||||
* @returns {Object} 登录结果
|
||||
*/
|
||||
async function login(db, wxContext) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, wxContext.OPENID);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "Failed to get or create user"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: user._id,
|
||||
openid: user._openid,
|
||||
regist_time: user.regist_time,
|
||||
data: user.data,
|
||||
fight_heros: user.fight_heros,
|
||||
heros: user.heros,
|
||||
items: user.items,
|
||||
tals: user.tals,
|
||||
equips: user.equips,
|
||||
data_version: user.data_version,
|
||||
last_save_time: user.last_save_time || null
|
||||
},
|
||||
msg: "Login successful"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Login error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Login error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或创建用户
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 用户数据
|
||||
*/
|
||||
async function getOrCreaterUser(db, openid) {
|
||||
try {
|
||||
let res = await db.collection(user_db_name).where({ _openid: openid }).get();
|
||||
let userData = null;
|
||||
|
||||
if (res == null || res.data == null || res.data.length <= 0) {
|
||||
// 创建新用户时使用初始化数据配置
|
||||
let initData = getNewUserInitData();
|
||||
userData = {
|
||||
_openid: openid,
|
||||
regist_time: Date.now(),
|
||||
data: initData.data,
|
||||
fight_heros: initData.fight_heros,
|
||||
heros: initData.heros,
|
||||
items: initData.items,
|
||||
tals: initData.tals,
|
||||
equips: initData.equips,
|
||||
data_version: initData.data_version,
|
||||
init_time: initData.init_time
|
||||
};
|
||||
|
||||
let addResult = await db.collection(user_db_name).add({
|
||||
data: userData
|
||||
});
|
||||
userData._id = addResult._id;
|
||||
|
||||
console.log(`New user created: ${openid}, version: ${initData.data_version}`);
|
||||
} else {
|
||||
userData = res.data[0];
|
||||
|
||||
// 检查数据版本兼容性
|
||||
const versionCheck = checkDataVersionCompatibility(userData.data_version);
|
||||
console.log(`User ${openid} data version check:`, versionCheck);
|
||||
|
||||
if (versionCheck.needsUpgrade) {
|
||||
// 使用新的数据管理系统合并和升级数据
|
||||
const upgradedData = mergeUserDataWithDefaults({
|
||||
data: userData.data,
|
||||
fight_heros: userData.fight_heros,
|
||||
heros: userData.heros,
|
||||
items: userData.items,
|
||||
tals: userData.tals,
|
||||
equips: userData.equips,
|
||||
data_version: userData.data_version
|
||||
});
|
||||
|
||||
// 更新用户数据
|
||||
userData.data = upgradedData.data;
|
||||
userData.fight_heros = upgradedData.fight_heros;
|
||||
userData.heros = upgradedData.heros;
|
||||
userData.items = upgradedData.items;
|
||||
userData.tals = upgradedData.tals;
|
||||
userData.equips = upgradedData.equips;
|
||||
userData.data_version = upgradedData.data_version;
|
||||
|
||||
console.log(`User ${openid} data upgraded to version: ${upgradedData.data_version}`);
|
||||
}
|
||||
}
|
||||
|
||||
return userData;
|
||||
} catch (err) {
|
||||
console.error(`Get or create user err`, err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户基本信息
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 用户基本信息
|
||||
*/
|
||||
async function getUserInfo(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_id: user._id,
|
||||
openid: user._openid,
|
||||
regist_time: user.regist_time,
|
||||
init_time: user.init_time,
|
||||
data_version: user.data_version,
|
||||
last_save_time: user.last_save_time
|
||||
},
|
||||
msg: "User info retrieved successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Get user info error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get user info error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户数据版本
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 版本检查结果
|
||||
*/
|
||||
async function checkVersion(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const versionCheck = checkDataVersionCompatibility(user.data_version);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
user_version: user.data_version || "unknown",
|
||||
current_version: require('../user_init_data').DATA_VERSION,
|
||||
compatibility: versionCheck,
|
||||
init_time: user.init_time,
|
||||
regist_time: user.regist_time,
|
||||
last_save_time: user.last_save_time
|
||||
},
|
||||
msg: "Version information retrieved successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Check version error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Check version error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制升级用户数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 升级结果
|
||||
*/
|
||||
async function upgradeUserData(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 强制升级用户数据
|
||||
const upgradedData = mergeUserDataWithDefaults({
|
||||
data: user.data,
|
||||
fight_heros: user.fight_heros,
|
||||
heros: user.heros,
|
||||
items: user.items,
|
||||
tals: user.tals,
|
||||
equips: user.equips,
|
||||
data_version: user.data_version
|
||||
});
|
||||
|
||||
let upgradeDataRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(upgradedData.data),
|
||||
fight_heros: _.set(upgradedData.fight_heros),
|
||||
heros: _.set(upgradedData.heros),
|
||||
items: _.set(upgradedData.items),
|
||||
tals: _.set(upgradedData.tals),
|
||||
equips: _.set(upgradedData.equips),
|
||||
data_version: _.set(upgradedData.data_version),
|
||||
last_save_time: _.set(Date.now()),
|
||||
upgrade_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (upgradeDataRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
old_version: user.data_version || "unknown",
|
||||
new_version: upgradedData.data_version,
|
||||
upgrade_time: Date.now(),
|
||||
data: upgradedData.data,
|
||||
fight_heros: upgradedData.fight_heros,
|
||||
heros: upgradedData.heros,
|
||||
items: upgradedData.items,
|
||||
tals: upgradedData.tals,
|
||||
equips: upgradedData.equips
|
||||
},
|
||||
msg: "Data upgrade completed successfully"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Upgrade fail, ${JSON.stringify(upgradeDataRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Upgrade user data error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Upgrade error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
login,
|
||||
getOrCreaterUser,
|
||||
getUserInfo,
|
||||
checkVersion,
|
||||
upgradeUserData
|
||||
};
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
// 出战英雄操作模块
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取出战英雄配置
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getFightHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.fight_heros,
|
||||
msg: "Fight heros retrieved successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Get fight heros error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get fight heros error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置出战英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} position 出战位置 (0-4)
|
||||
* @param {number} heroId 英雄ID,0表示移除
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setFightHero(db, openid, position, heroId) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证位置参数
|
||||
if (position < 0 || position > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid position, must be 0-4"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证英雄ID
|
||||
if (typeof heroId !== 'number' || heroId < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid hero ID"
|
||||
};
|
||||
}
|
||||
|
||||
// 如果不是移除操作,检查英雄是否存在
|
||||
if (heroId > 0 && !user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "Hero not owned"
|
||||
};
|
||||
}
|
||||
|
||||
const oldHeroId = user.fight_heros[position];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`fight_heros.${position}`]: _.set(heroId),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
position: position,
|
||||
old_hero_id: oldHeroId,
|
||||
new_hero_id: heroId
|
||||
},
|
||||
msg: `Fight hero position ${position} updated successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Set fight hero fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Set fight hero error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Set fight hero error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量设置出战英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {Object} fightHeros 出战英雄配置对象
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateFightHeros(db, openid, fightHeros) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证数据格式
|
||||
if (!fightHeros || typeof fightHeros !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid fight heros data format"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证每个位置和英雄ID
|
||||
for (const pos in fightHeros) {
|
||||
const position = parseInt(pos);
|
||||
const heroId = fightHeros[pos];
|
||||
|
||||
if (isNaN(position) || position < 0 || position > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid position: ${pos}`
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof heroId !== 'number' || heroId < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid hero ID for position ${pos}: ${heroId}`
|
||||
};
|
||||
}
|
||||
|
||||
// 如果不是移除操作,检查英雄是否存在
|
||||
if (heroId > 0 && !user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `Hero ${heroId} not owned for position ${pos}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const newFightHeros = { ...user.fight_heros, ...fightHeros };
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
fight_heros: _.set(newFightHeros),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newFightHeros,
|
||||
msg: "Fight heros updated successfully"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Update fight heros fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Update fight heros error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Update fight heros error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前出战英雄列表(不包含空位)
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getActiveFightHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const activeHeros = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const heroId = user.fight_heros[i];
|
||||
if (heroId && heroId > 0) {
|
||||
activeHeros.push({
|
||||
position: i,
|
||||
hero_id: heroId,
|
||||
hero_data: user.heros[heroId] || null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
active_heros: activeHeros,
|
||||
total_count: activeHeros.length
|
||||
},
|
||||
msg: "Active fight heros retrieved successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Get active fight heros error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get active fight heros error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 交换两个出战位置的英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} position1 位置1 (0-4)
|
||||
* @param {number} position2 位置2 (0-4)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function swapFightHeros(db, openid, position1, position2) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证位置参数
|
||||
if (position1 < 0 || position1 > 4 || position2 < 0 || position2 > 4) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid positions, must be 0-4"
|
||||
};
|
||||
}
|
||||
|
||||
if (position1 === position2) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Cannot swap same position"
|
||||
};
|
||||
}
|
||||
|
||||
const hero1 = user.fight_heros[position1];
|
||||
const hero2 = user.fight_heros[position2];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`fight_heros.${position1}`]: _.set(hero2),
|
||||
[`fight_heros.${position2}`]: _.set(hero1),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
position1: position1,
|
||||
position2: position2,
|
||||
hero1_moved_to: hero1,
|
||||
hero2_moved_to: hero2
|
||||
},
|
||||
msg: `Fight heros swapped successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Swap fight heros fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Swap fight heros error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Swap fight heros error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置出战英雄配置
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetFightHeros(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
fight_heros: _.set(defaultData.fight_heros),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData.fight_heros,
|
||||
msg: "Fight heros reset successfully"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Reset fail, ${JSON.stringify(resetRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Reset fight heros error:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Reset fight heros error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFightHeros,
|
||||
setFightHero,
|
||||
updateFightHeros,
|
||||
getActiveFightHeros,
|
||||
swapFightHeros,
|
||||
resetFightHeros
|
||||
};
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
// 基础游戏数据操作模块 (data字段)
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
const { validateDataStructure, mergeUserDataWithDefaults } = require('../user_init_data');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getData(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.data,
|
||||
msg: "游戏数据获取成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {Object} updateData 要更新的数据
|
||||
* @param {boolean} merge 是否合并更新(默认true)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateData(db, openid, updateData, merge = true) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证数据格式
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的更新数据格式"
|
||||
};
|
||||
}
|
||||
|
||||
let newData;
|
||||
if (merge) {
|
||||
// 合并更新
|
||||
newData = { ...user.data, ...updateData };
|
||||
} else {
|
||||
// 完全替换
|
||||
newData = updateData;
|
||||
}
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(newData),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newData,
|
||||
msg: "游戏数据更新成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新失败, ${JSON.stringify(updateRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `更新游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} field 字段名
|
||||
* @param {number} amount 增加的数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addDataField(db, openid, field, amount) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof amount !== 'number') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是数字"
|
||||
};
|
||||
}
|
||||
|
||||
const currentValue = user.data[field] || 0;
|
||||
const newValue = Math.max(0, currentValue + amount);
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`data.${field}`]: _.set(newValue),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
field: field,
|
||||
old_value: currentValue,
|
||||
new_value: newValue,
|
||||
change: amount
|
||||
},
|
||||
msg: `${field} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新 ${field} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`增加 ${field} 错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `增加 ${field} 错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} field 字段名
|
||||
* @param {number} amount 消耗的数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function spendDataField(db, openid, field, amount) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof amount !== 'number' || amount < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "数量必须是正数"
|
||||
};
|
||||
}
|
||||
|
||||
const currentValue = user.data[field] || 0;
|
||||
if (currentValue < amount) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${field} 不足, 当前: ${currentValue}, 需要: ${amount}`
|
||||
};
|
||||
}
|
||||
|
||||
return await addDataField(db, openid, field, -amount);
|
||||
} catch (error) {
|
||||
console.error(`消耗 ${field} 错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `消耗 ${field} 错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置指定字段的数值
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} field 字段名
|
||||
* @param {any} value 新的值
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setDataField(db, openid, field, value) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
const oldValue = user.data[field];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`data.${field}`]: _.set(value),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
field: field,
|
||||
old_value: oldValue,
|
||||
new_value: value
|
||||
},
|
||||
msg: `${field} 设置成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置 ${field} 失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`设置 ${field} 错误:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置 ${field} 错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置基础游戏数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetData(db, openid) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "用户未找到"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
data: _.set(defaultData.data),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData.data,
|
||||
msg: "游戏数据重置成功"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `重置失败, ${JSON.stringify(resetRes)}`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("重置游戏数据错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `重置游戏数据错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getData,
|
||||
updateData,
|
||||
addDataField,
|
||||
spendDataField,
|
||||
setDataField,
|
||||
resetData
|
||||
};
|
||||
@@ -0,0 +1,456 @@
|
||||
// 英雄数据操作模块
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
/**
|
||||
* 获取所有英雄数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getHeros(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user.heros,
|
||||
msg: "获取英雄列表成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取英雄列表错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取英雄列表错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个英雄数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getHero(db, openid, heroId) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const hero = user.heros[heroId];
|
||||
if (!hero) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: hero,
|
||||
msg: "获取英雄成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {Object} heroData 英雄数据(可选)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addHero(db, openid, heroId, heroData = null) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否已存在
|
||||
if (user.heros[heroId]) {
|
||||
return {
|
||||
code: -7,
|
||||
msg: "英雄已存在"
|
||||
};
|
||||
}
|
||||
|
||||
// 使用提供的数据或默认数据
|
||||
const newHero = heroData || {
|
||||
uuid: heroId,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
star: 1,
|
||||
power: 100
|
||||
};
|
||||
|
||||
// 确保uuid字段正确
|
||||
newHero.uuid = heroId;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.set(newHero),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newHero,
|
||||
msg: `英雄 ${heroId} 添加成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `添加英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("添加英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `添加英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新英雄属性
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {Object} updateData 要更新的属性
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateHero(db, openid, heroId, updateData) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证更新数据
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "无效的更新数据格式"
|
||||
};
|
||||
}
|
||||
|
||||
const currentHero = user.heros[heroId];
|
||||
const newHero = { ...currentHero, ...updateData };
|
||||
|
||||
// 确保uuid字段不被修改
|
||||
newHero.uuid = heroId;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.set(newHero),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
old_data: currentHero,
|
||||
new_data: newHero
|
||||
},
|
||||
msg: `英雄 ${heroId} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `更新英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("更新英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `更新英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置英雄属性
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {string} property 属性名
|
||||
* @param {any} value 属性值
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setHeroProperty(db, openid, heroId, property, value) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 防止修改uuid
|
||||
if (property === 'uuid') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "不可修改英雄UUID"
|
||||
};
|
||||
}
|
||||
|
||||
const oldValue = user.heros[heroId][property];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}.${property}`]: _.set(value),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
hero_id: heroId,
|
||||
property: property,
|
||||
old_value: oldValue,
|
||||
new_value: value
|
||||
},
|
||||
msg: `英雄 ${heroId} 属性 ${property} 更新成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `设置英雄属性失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("设置英雄属性错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `设置英雄属性错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 英雄升级
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @param {number} levels 升级级数(默认1级)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function levelUpHero(db, openid, heroId, exp,gold,levels = 1) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof levels !== 'number' || levels < 1) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "等级必须为正数"
|
||||
};
|
||||
}
|
||||
|
||||
let exp_result=await spendDataField(db, openid, 'exp', exp);
|
||||
if(exp_result.code!==200){
|
||||
return {
|
||||
code: -1,
|
||||
msg: `升级失败,经验不足`
|
||||
};
|
||||
}
|
||||
let gold_result=await spendDataField(db, openid, 'gold', gold);
|
||||
if(gold_result.code!==200){
|
||||
await addDataField(db, openid, 'exp', exp);
|
||||
return {
|
||||
code: -1,
|
||||
msg: `升级失败,金币不足`
|
||||
};
|
||||
}
|
||||
const currentLevel = user.heros[heroId].lv || 1;
|
||||
const newLevel = currentLevel + levels;
|
||||
return await setHeroProperty(db, openid, heroId, 'lv', newLevel);
|
||||
} catch (error) {
|
||||
console.error("英雄升级错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `英雄升级错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除英雄
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {number} heroId 英雄ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function deleteHero(db, openid, heroId) {
|
||||
try {
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否存在
|
||||
if (!user.heros[heroId]) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: "未找到英雄"
|
||||
};
|
||||
}
|
||||
|
||||
// 检查英雄是否在出战阵容中
|
||||
for (let pos = 0; pos < 5; pos++) {
|
||||
if (user.fight_heros[pos] === heroId) {
|
||||
return {
|
||||
code: -8,
|
||||
msg: `英雄位于出战位置 ${pos},请先从出战阵容移除`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const deletedHero = user.heros[heroId];
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`heros.${heroId}`]: _.remove(),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: deletedHero,
|
||||
msg: `英雄 ${heroId} 删除成功`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `删除英雄失败`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("删除英雄错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `删除英雄错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已拥有的英雄ID列表
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getOwnedHeroIds(db, openid) {
|
||||
try {
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "未找到用户"
|
||||
};
|
||||
}
|
||||
|
||||
const heroIds = Object.keys(user.heros).map(Number);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
hero_ids: heroIds,
|
||||
total_count: heroIds.length
|
||||
},
|
||||
msg: "获取已拥有英雄ID成功"
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("获取已拥有英雄ID错误:", error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `获取已拥有英雄ID错误: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getHeros,
|
||||
getHero,
|
||||
addHero,
|
||||
updateHero,
|
||||
setHeroProperty,
|
||||
levelUpHero,
|
||||
deleteHero,
|
||||
getOwnedHeroIds
|
||||
};
|
||||
|
||||
@@ -0,0 +1,498 @@
|
||||
// 通用库存操作模块 (items, tals, equips)
|
||||
const { getOrCreaterUser } = require('./auth');
|
||||
|
||||
const user_db_name = "cocos_users";
|
||||
|
||||
// 支持的数据类型
|
||||
const SUPPORTED_TYPES = ['items', 'tals', 'equips'];
|
||||
|
||||
/**
|
||||
* 验证数据类型
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {boolean} 是否有效
|
||||
*/
|
||||
function validateDataType(dataType) {
|
||||
return SUPPORTED_TYPES.includes(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取库存数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型 ('items', 'tals', 'equips')
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getInventory(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: user[dataType],
|
||||
msg: `${dataType} retrieved successfully`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Get ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单个物品数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getInventoryItem(db, openid, dataType, itemId) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const itemCount = user[dataType][itemId];
|
||||
if (itemCount === undefined) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} not found`
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
count: itemCount
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} retrieved successfully`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Get ${dataType} item error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get ${dataType} item error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加物品
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 添加数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function addInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Count must be a non-negative number"
|
||||
};
|
||||
}
|
||||
|
||||
const currentCount = user[dataType][itemId] || 0;
|
||||
const newCount = currentCount + count;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`${dataType}.${itemId}`]: _.set(newCount),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
old_count: currentCount,
|
||||
new_count: newCount,
|
||||
added: count
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} added successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Add ${dataType.slice(0, -1)} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Add ${dataType} item error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Add ${dataType} item error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 消耗物品
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 消耗数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function consumeInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Count must be a non-negative number"
|
||||
};
|
||||
}
|
||||
|
||||
const currentCount = user[dataType][itemId] || 0;
|
||||
if (currentCount < count) {
|
||||
return {
|
||||
code: -6,
|
||||
msg: `Insufficient ${dataType.slice(0, -1)} ${itemId}, current: ${currentCount}, required: ${count}`
|
||||
};
|
||||
}
|
||||
|
||||
return await addInventoryItem(db, openid, dataType, itemId, -count);
|
||||
} catch (error) {
|
||||
console.error(`Consume ${dataType} item error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Consume ${dataType} item error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置物品数量
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {number} itemId 物品ID
|
||||
* @param {number} count 新的数量
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function setInventoryItem(db, openid, dataType, itemId, count) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Count must be a non-negative number"
|
||||
};
|
||||
}
|
||||
|
||||
const oldCount = user[dataType][itemId] || 0;
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[`${dataType}.${itemId}`]: _.set(count),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
item_id: itemId,
|
||||
old_count: oldCount,
|
||||
new_count: count
|
||||
},
|
||||
msg: `${dataType.slice(0, -1)} ${itemId} set successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Set ${dataType.slice(0, -1)} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Set ${dataType} item error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Set ${dataType} item error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新库存
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @param {Object} updateData 更新数据对象
|
||||
* @param {boolean} merge 是否合并更新(默认true)
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function updateInventory(db, openid, dataType, updateData, merge = true) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证更新数据
|
||||
if (!updateData || typeof updateData !== 'object') {
|
||||
return {
|
||||
code: -3,
|
||||
msg: "Invalid update data format"
|
||||
};
|
||||
}
|
||||
|
||||
// 验证所有值都是非负数
|
||||
for (const itemId in updateData) {
|
||||
const count = updateData[itemId];
|
||||
if (typeof count !== 'number' || count < 0) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid count for item ${itemId}: ${count}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let newData;
|
||||
if (merge) {
|
||||
// 合并更新
|
||||
newData = { ...user[dataType], ...updateData };
|
||||
} else {
|
||||
// 完全替换
|
||||
newData = updateData;
|
||||
}
|
||||
|
||||
let updateRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[dataType]: _.set(newData),
|
||||
last_save_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (updateRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: newData,
|
||||
msg: `${dataType} updated successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Update ${dataType} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Update ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Update ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置库存数据
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function resetInventory(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
const _ = db.command;
|
||||
const { getNewUserInitData } = require('../user_init_data');
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const defaultData = getNewUserInitData();
|
||||
|
||||
let resetRes = await db.collection(user_db_name).doc(user._id).update({
|
||||
data: {
|
||||
[dataType]: _.set(defaultData[dataType]),
|
||||
last_save_time: _.set(Date.now()),
|
||||
reset_time: _.set(Date.now())
|
||||
}
|
||||
});
|
||||
|
||||
if (resetRes?.stats?.updated >= 1) {
|
||||
return {
|
||||
code: 200,
|
||||
data: defaultData[dataType],
|
||||
msg: `${dataType} reset successfully`
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
code: -1,
|
||||
msg: `Reset ${dataType} fail`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Reset ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Reset ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取拥有的物品列表(数量大于0的)
|
||||
* @param {Object} db 数据库实例
|
||||
* @param {string} openid 用户openid
|
||||
* @param {string} dataType 数据类型
|
||||
* @returns {Object} 操作结果
|
||||
*/
|
||||
async function getOwnedItems(db, openid, dataType) {
|
||||
try {
|
||||
if (!validateDataType(dataType)) {
|
||||
return {
|
||||
code: -3,
|
||||
msg: `Invalid data type: ${dataType}`
|
||||
};
|
||||
}
|
||||
|
||||
let user = await getOrCreaterUser(db, openid);
|
||||
if (!user) {
|
||||
return {
|
||||
code: -4,
|
||||
msg: "User not found"
|
||||
};
|
||||
}
|
||||
|
||||
const ownedItems = [];
|
||||
for (const itemId in user[dataType]) {
|
||||
const count = user[dataType][itemId];
|
||||
if (count > 0) {
|
||||
ownedItems.push({
|
||||
item_id: parseInt(itemId),
|
||||
count: count
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
owned_items: ownedItems,
|
||||
total_types: ownedItems.length
|
||||
},
|
||||
msg: `Owned ${dataType} retrieved successfully`
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Get owned ${dataType} error:`, error);
|
||||
return {
|
||||
code: -5,
|
||||
msg: `Get owned ${dataType} error: ${error.message}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getInventory,
|
||||
getInventoryItem,
|
||||
addInventoryItem,
|
||||
consumeInventoryItem,
|
||||
setInventoryItem,
|
||||
updateInventory,
|
||||
resetInventory,
|
||||
getOwnedItems,
|
||||
SUPPORTED_TYPES
|
||||
};
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
// 统一响应处理模块
|
||||
const { DATA_VERSION } = require('../user_init_data');
|
||||
|
||||
/**
|
||||
* 成功响应
|
||||
* @param {any} data 返回数据
|
||||
* @param {string} message 成功消息
|
||||
* @param {Object} extra 额外信息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function success(data = null, message = "Success", extra = {}) {
|
||||
return {
|
||||
code: 200,
|
||||
data: data,
|
||||
msg: message,
|
||||
timestamp: Date.now(),
|
||||
version: DATA_VERSION,
|
||||
...extra
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应
|
||||
* @param {number} code 错误码
|
||||
* @param {string} message 错误消息
|
||||
* @param {any} data 错误相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function error(code, message, data = null) {
|
||||
return {
|
||||
code: code,
|
||||
msg: message,
|
||||
data: data,
|
||||
timestamp: Date.now(),
|
||||
version: DATA_VERSION
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数错误响应
|
||||
* @param {string} message 错误消息
|
||||
* @param {any} data 错误相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function badRequest(message = "Bad request", data = null) {
|
||||
return error(-3, message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户未找到响应
|
||||
* @param {string} message 错误消息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function userNotFound(message = "User not found") {
|
||||
return error(-4, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统错误响应
|
||||
* @param {string} message 错误消息
|
||||
* @param {Error} err 错误对象
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function systemError(message = "System error", err = null) {
|
||||
const errorData = err ? {
|
||||
error_message: err.message,
|
||||
error_stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
|
||||
} : null;
|
||||
|
||||
return error(-5, message, errorData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源不足响应
|
||||
* @param {string} resource 资源名称
|
||||
* @param {number} current 当前数量
|
||||
* @param {number} required 需要数量
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function insufficientResource(resource, current = 0, required = 0) {
|
||||
return error(-6, `Insufficient ${resource}`, {
|
||||
resource: resource,
|
||||
current: current,
|
||||
required: required,
|
||||
shortage: required - current
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 资源已存在响应
|
||||
* @param {string} resource 资源名称
|
||||
* @param {any} identifier 资源标识
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function resourceExists(resource, identifier = null) {
|
||||
return error(-7, `${resource} already exists`, {
|
||||
resource: resource,
|
||||
identifier: identifier
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作被拒绝响应
|
||||
* @param {string} reason 拒绝原因
|
||||
* @param {any} data 相关数据
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function operationDenied(reason, data = null) {
|
||||
return error(-8, `Operation denied: ${reason}`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未知命令响应
|
||||
* @param {string} command 命令名
|
||||
* @param {Array} availableCommands 可用命令列表
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function unknownCommand(command, availableCommands = []) {
|
||||
return error(-2, `Unknown command: ${command}`, {
|
||||
command: command,
|
||||
available_commands: availableCommands
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装异步操作,统一错误处理
|
||||
* @param {Function} operation 异步操作函数
|
||||
* @param {string} operationName 操作名称
|
||||
* @returns {Function} 包装后的函数
|
||||
*/
|
||||
function wrapAsync(operation, operationName = "Operation") {
|
||||
return async (...args) => {
|
||||
try {
|
||||
const result = await operation(...args);
|
||||
|
||||
// 如果操作返回的是错误格式,直接返回
|
||||
if (result && typeof result === 'object' && result.code !== undefined) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// 如果是成功结果,包装为成功响应
|
||||
return success(result, `${operationName} completed successfully`);
|
||||
} catch (error) {
|
||||
console.error(`${operationName} error:`, error);
|
||||
return systemError(`${operationName} failed`, error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证必需参数
|
||||
* @param {Object} params 参数对象
|
||||
* @param {Array} requiredFields 必需字段列表
|
||||
* @returns {Object|null} 如果验证失败返回错误响应,否则返回null
|
||||
*/
|
||||
function validateRequiredParams(params, requiredFields) {
|
||||
if (!params || typeof params !== 'object') {
|
||||
return badRequest("Invalid parameters");
|
||||
}
|
||||
|
||||
const missingFields = [];
|
||||
for (const field of requiredFields) {
|
||||
if (params[field] === undefined || params[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return badRequest(`Missing required parameters: ${missingFields.join(', ')}`, {
|
||||
missing_fields: missingFields,
|
||||
required_fields: requiredFields
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数值参数
|
||||
* @param {any} value 要验证的值
|
||||
* @param {string} fieldName 字段名
|
||||
* @param {Object} options 验证选项
|
||||
* @returns {Object|null} 如果验证失败返回错误响应,否则返回null
|
||||
*/
|
||||
function validateNumber(value, fieldName, options = {}) {
|
||||
const {
|
||||
min = Number.NEGATIVE_INFINITY,
|
||||
max = Number.POSITIVE_INFINITY,
|
||||
integer = false
|
||||
} = options;
|
||||
|
||||
if (typeof value !== 'number' || isNaN(value)) {
|
||||
return badRequest(`${fieldName} must be a number`);
|
||||
}
|
||||
|
||||
if (integer && !Number.isInteger(value)) {
|
||||
return badRequest(`${fieldName} must be an integer`);
|
||||
}
|
||||
|
||||
if (value < min) {
|
||||
return badRequest(`${fieldName} must be at least ${min}`);
|
||||
}
|
||||
|
||||
if (value > max) {
|
||||
return badRequest(`${fieldName} must be at most ${max}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分页响应
|
||||
* @param {Array} items 数据项
|
||||
* @param {number} total 总数
|
||||
* @param {number} page 当前页
|
||||
* @param {number} pageSize 页大小
|
||||
* @param {string} message 成功消息
|
||||
* @returns {Object} 响应对象
|
||||
*/
|
||||
function paginated(items, total, page, pageSize, message = "Data retrieved successfully") {
|
||||
const totalPages = Math.ceil(total / pageSize);
|
||||
|
||||
return success({
|
||||
items: items,
|
||||
pagination: {
|
||||
current_page: page,
|
||||
page_size: pageSize,
|
||||
total_items: total,
|
||||
total_pages: totalPages,
|
||||
has_next: page < totalPages,
|
||||
has_prev: page > 1
|
||||
}
|
||||
}, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误码常量
|
||||
*/
|
||||
const ERROR_CODES = {
|
||||
SUCCESS: 200,
|
||||
OPERATION_FAILED: -1,
|
||||
UNKNOWN_COMMAND: -2,
|
||||
BAD_REQUEST: -3,
|
||||
USER_NOT_FOUND: -4,
|
||||
SYSTEM_ERROR: -5,
|
||||
INSUFFICIENT_RESOURCE: -6,
|
||||
RESOURCE_EXISTS: -7,
|
||||
OPERATION_DENIED: -8
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
success,
|
||||
error,
|
||||
badRequest,
|
||||
userNotFound,
|
||||
systemError,
|
||||
insufficientResource,
|
||||
resourceExists,
|
||||
operationDenied,
|
||||
unknownCommand,
|
||||
wrapAsync,
|
||||
validateRequiredParams,
|
||||
validateNumber,
|
||||
paginated,
|
||||
ERROR_CODES
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user