- 在小程序天梯排名页添加“定位我”按钮,点击可滚动到当前用户所在位置 - 新增获取用户排名接口 `/ladder/my-rank` 用于定位计算 - 调整挑战赛权重从 1.5 降至 1.0,与日常畅打保持一致 - 新增数据库脚本 `setChallengeMatchWeightTo1.js` 用于更新历史数据 - 在管理员界面创建天梯用户时,根据所选等级自动填充默认战力值 - 修复管理员更新比赛时挑战赛权重强制设置为 1.0 的问题 - 新增天梯汇总大屏页面及相关路由 - 添加大屏比赛列表接口 `/match/display-list` 用于展示进行中和近期比赛 - 优化用户详情页的胜负场和胜率显示逻辑 - 修复小程序用户注册时的性别选择逻辑
693 lines
21 KiB
JavaScript
693 lines
21 KiB
JavaScript
const { Match, MatchGame, MatchPlayer, MatchRound, LadderUser, User, Store, sequelize } = require('../models');
|
||
const { MATCH_TYPES, MATCH_STATUS, RANKING_STAGE, CONFIRM_STATUS } = require('../config/constants');
|
||
const { generateMatchCode, success, error, getPagination, pageResult } = require('../utils/helper');
|
||
const PowerCalculator = require('../services/powerCalculator');
|
||
const { broadcastToUsers } = require('../websocket');
|
||
const { Op } = require('sequelize');
|
||
|
||
class MatchAdminController {
|
||
// 获取比赛列表
|
||
async getList(req, res) {
|
||
try {
|
||
const { page = 1, pageSize = 20, type, status, store_id } = req.query;
|
||
const { limit, offset } = getPagination(page, pageSize);
|
||
const admin = req.admin;
|
||
|
||
const where = {};
|
||
|
||
// 门店权限过滤
|
||
if (admin.role === 'super_admin') {
|
||
if (store_id) {
|
||
where.store_id = store_id;
|
||
}
|
||
} else {
|
||
where.store_id = admin.store_id;
|
||
}
|
||
|
||
if (type) {
|
||
where.type = type;
|
||
}
|
||
if (status !== undefined && status !== '') {
|
||
where.status = status;
|
||
}
|
||
|
||
const { rows, count } = await Match.findAndCountAll({
|
||
where,
|
||
include: [
|
||
{ model: Store, as: 'store', attributes: ['id', 'name'] },
|
||
{ model: User, as: 'referee', attributes: ['id', 'nickname'] }
|
||
],
|
||
order: [['created_at', 'DESC']],
|
||
limit,
|
||
offset
|
||
});
|
||
|
||
res.json(pageResult(rows.map(match => ({
|
||
id: match.id,
|
||
matchCode: match.match_code,
|
||
type: match.type,
|
||
name: match.name,
|
||
weight: match.weight,
|
||
storeId: match.store_id,
|
||
storeName: match.store?.name,
|
||
refereeName: match.referee?.nickname,
|
||
status: match.status,
|
||
stage: match.stage,
|
||
startTime: match.start_time,
|
||
endTime: match.end_time,
|
||
createdAt: match.created_at
|
||
})), count, page, pageSize));
|
||
} catch (err) {
|
||
console.error('获取比赛列表失败:', err);
|
||
res.status(500).json(error('获取失败'));
|
||
}
|
||
}
|
||
|
||
// 创建排位赛
|
||
async create(req, res) {
|
||
try {
|
||
const { store_id, name, weight, referee_id } = req.body;
|
||
const admin = req.admin;
|
||
|
||
const targetStoreId = admin.role === 'super_admin' ? store_id : admin.store_id;
|
||
if (!targetStoreId) {
|
||
return res.status(400).json(error('请选择门店', 400));
|
||
}
|
||
|
||
const match = await Match.create({
|
||
store_id: targetStoreId,
|
||
match_code: generateMatchCode(),
|
||
type: MATCH_TYPES.RANKING,
|
||
name: name || `排位赛 ${new Date().toLocaleDateString()}`,
|
||
weight: weight || 1.5,
|
||
referee_id,
|
||
status: MATCH_STATUS.PENDING,
|
||
stage: RANKING_STAGE.SIGNUP
|
||
});
|
||
|
||
res.json(success({
|
||
id: match.id,
|
||
matchCode: match.match_code
|
||
}, '创建成功'));
|
||
} catch (err) {
|
||
console.error('创建比赛失败:', err);
|
||
res.status(500).json(error('创建失败'));
|
||
}
|
||
}
|
||
|
||
// 获取比赛详情
|
||
async getDetail(req, res) {
|
||
try {
|
||
const { id } = req.params;
|
||
|
||
const match = await Match.findByPk(id, {
|
||
include: [
|
||
{ model: Store, as: 'store' },
|
||
{ model: User, as: 'referee' },
|
||
{
|
||
model: MatchPlayer,
|
||
as: 'players',
|
||
include: [{ model: LadderUser, as: 'ladderUser', include: [{ model: User, as: 'user' }] }]
|
||
},
|
||
{
|
||
model: MatchRound,
|
||
as: 'rounds',
|
||
include: [{ model: MatchGame, as: 'games' }]
|
||
},
|
||
{ model: MatchGame, as: 'games' }
|
||
]
|
||
});
|
||
|
||
if (!match) {
|
||
return res.status(404).json(error('比赛不存在', 404));
|
||
}
|
||
|
||
res.json(success({
|
||
id: match.id,
|
||
matchCode: match.match_code,
|
||
type: match.type,
|
||
name: match.name,
|
||
weight: match.weight,
|
||
status: match.status,
|
||
stage: match.stage,
|
||
eliminationSize: match.elimination_size,
|
||
storeId: match.store_id,
|
||
storeName: match.store?.name,
|
||
refereeId: match.referee_id,
|
||
refereeName: match.referee?.nickname,
|
||
startTime: match.start_time,
|
||
endTime: match.end_time,
|
||
players: match.players.map(p => ({
|
||
id: p.id,
|
||
ladderUserId: p.ladder_user_id,
|
||
realName: p.ladderUser?.real_name,
|
||
nickname: p.ladderUser?.user?.nickname,
|
||
level: p.ladderUser?.level,
|
||
initialPower: p.initial_power,
|
||
finalPower: p.final_power,
|
||
winCount: p.win_count,
|
||
loseCount: p.lose_count,
|
||
rank: p.rank,
|
||
status: p.player_status
|
||
})),
|
||
rounds: match.rounds.map(r => ({
|
||
id: r.id,
|
||
roundNumber: r.round_number,
|
||
roundType: r.round_type,
|
||
roundName: r.round_name,
|
||
status: r.status,
|
||
games: r.games.map(g => ({
|
||
id: g.id,
|
||
player1Id: g.player1_id,
|
||
player2Id: g.player2_id,
|
||
player1Score: g.player1_score,
|
||
player2Score: g.player2_score,
|
||
winnerId: g.winner_id,
|
||
confirmStatus: g.confirm_status,
|
||
status: g.status
|
||
}))
|
||
})),
|
||
games: match.games
|
||
}));
|
||
} catch (err) {
|
||
console.error('获取比赛详情失败:', err);
|
||
res.status(500).json(error('获取失败'));
|
||
}
|
||
}
|
||
|
||
// 更新比赛
|
||
async update(req, res) {
|
||
try {
|
||
const { id } = req.params;
|
||
const { name, weight, referee_id } = req.body;
|
||
|
||
const match = await Match.findByPk(id);
|
||
if (!match) {
|
||
return res.status(404).json(error('比赛不存在', 404));
|
||
}
|
||
|
||
const updateData = {};
|
||
if (name !== undefined) updateData.name = name;
|
||
if (referee_id !== undefined) updateData.referee_id = referee_id;
|
||
|
||
if (weight !== undefined) {
|
||
const normalizedWeight = parseFloat(weight);
|
||
if (!Number.isFinite(normalizedWeight) || normalizedWeight <= 0) {
|
||
return res.status(400).json(error('权重参数无效', 400));
|
||
}
|
||
updateData.weight = normalizedWeight;
|
||
}
|
||
|
||
if (match.type === MATCH_TYPES.CHALLENGE) {
|
||
updateData.weight = 1.0;
|
||
}
|
||
|
||
await match.update(updateData);
|
||
res.json(success(null, '更新成功'));
|
||
} catch (err) {
|
||
console.error('更新比赛失败:', err);
|
||
res.status(500).json(error('更新失败'));
|
||
}
|
||
}
|
||
|
||
// 开始排位赛(进入循环赛)
|
||
startMatch = async (req, res) => {
|
||
const t = await sequelize.transaction();
|
||
try {
|
||
const { id } = req.params;
|
||
|
||
const match = await Match.findByPk(id, {
|
||
include: [{ model: MatchPlayer, as: 'players' }],
|
||
transaction: t
|
||
});
|
||
|
||
if (!match || match.type !== MATCH_TYPES.RANKING) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('比赛不存在或类型错误', 400));
|
||
}
|
||
|
||
if (match.stage !== RANKING_STAGE.SIGNUP) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('比赛已开始', 400));
|
||
}
|
||
|
||
if (match.players.length < 2) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('参赛人数不足', 400));
|
||
}
|
||
|
||
// 更新比赛状态
|
||
await match.update({
|
||
status: MATCH_STATUS.ONGOING,
|
||
stage: RANKING_STAGE.ROUND_ROBIN,
|
||
start_time: new Date()
|
||
}, { transaction: t });
|
||
|
||
// 创建循环赛轮次和对局
|
||
const players = match.players;
|
||
const n = players.length;
|
||
|
||
// 生成单循环赛配对
|
||
const games = [];
|
||
for (let i = 0; i < n; i++) {
|
||
for (let j = i + 1; j < n; j++) {
|
||
games.push({
|
||
player1_id: players[i].ladder_user_id,
|
||
player2_id: players[j].ladder_user_id
|
||
});
|
||
}
|
||
}
|
||
|
||
// 随机打乱顺序
|
||
for (let i = games.length - 1; i > 0; i--) {
|
||
const j = Math.floor(Math.random() * (i + 1));
|
||
[games[i], games[j]] = [games[j], games[i]];
|
||
}
|
||
|
||
// 创建轮次
|
||
const round = await MatchRound.create({
|
||
match_id: match.id,
|
||
round_number: 1,
|
||
round_type: 'round_robin',
|
||
round_name: '循环赛',
|
||
status: 1
|
||
}, { transaction: t });
|
||
|
||
// 创建对局
|
||
for (const game of games) {
|
||
await MatchGame.create({
|
||
match_id: match.id,
|
||
round_id: round.id,
|
||
player1_id: game.player1_id,
|
||
player2_id: game.player2_id,
|
||
status: 0
|
||
}, { transaction: t });
|
||
}
|
||
|
||
// 自动匹配第一轮
|
||
// 注意:这里需要传入 transaction,并且在 _autoMatchPlayers 中使用该 transaction 查询刚创建的数据
|
||
await this._autoMatchPlayers(match.id, t);
|
||
|
||
await t.commit();
|
||
res.json(success(null, '比赛已开始'));
|
||
} catch (err) {
|
||
await t.rollback();
|
||
console.error('开始比赛失败 (Stack):', err.stack || err); // 打印完整堆栈
|
||
console.error('开始比赛失败 (Msg):', err.message || err);
|
||
res.status(500).json(error('操作失败: ' + (err.message || '未知错误')));
|
||
}
|
||
}
|
||
|
||
// 开始淘汰赛
|
||
async startElimination(req, res) {
|
||
const t = await sequelize.transaction();
|
||
try {
|
||
const { id } = req.params;
|
||
const { elimination_size } = req.body; // 4, 8, 16
|
||
|
||
const match = await Match.findByPk(id, {
|
||
include: [{ model: MatchPlayer, as: 'players' }]
|
||
});
|
||
|
||
if (!match || match.stage !== RANKING_STAGE.ROUND_ROBIN) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('比赛状态错误', 400));
|
||
}
|
||
|
||
// 检查循环赛是否结束
|
||
const unfinishedGames = await MatchGame.count({
|
||
where: {
|
||
match_id: id,
|
||
confirm_status: { [Op.ne]: CONFIRM_STATUS.CONFIRMED }
|
||
},
|
||
include: [{
|
||
model: MatchRound,
|
||
as: 'round',
|
||
where: { round_type: 'round_robin' }
|
||
}]
|
||
});
|
||
|
||
if (unfinishedGames > 0) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('循环赛尚未结束', 400));
|
||
}
|
||
|
||
// 根据胜场排名
|
||
const rankedPlayers = match.players.sort((a, b) => {
|
||
if (b.win_count !== a.win_count) return b.win_count - a.win_count;
|
||
return b.initial_power - a.initial_power;
|
||
});
|
||
|
||
const size = Math.min(elimination_size, rankedPlayers.length);
|
||
const qualifiedPlayers = rankedPlayers.slice(0, size);
|
||
|
||
// 更新比赛状态
|
||
await match.update({
|
||
stage: RANKING_STAGE.ELIMINATION,
|
||
elimination_size: size
|
||
}, { transaction: t });
|
||
|
||
// 创建淘汰赛首轮(1 vs 最后, 2 vs 倒数第二...)
|
||
const roundName = size === 4 ? '半决赛' : size === 8 ? '四分之一决赛' : '淘汰赛首轮';
|
||
const round = await MatchRound.create({
|
||
match_id: match.id,
|
||
round_number: 100, // 淘汰赛轮次从100开始
|
||
round_type: 'elimination',
|
||
round_name: roundName,
|
||
status: 1
|
||
}, { transaction: t });
|
||
|
||
// 配对:1 vs size, 2 vs size-1, ...
|
||
for (let i = 0; i < size / 2; i++) {
|
||
await MatchGame.create({
|
||
match_id: match.id,
|
||
round_id: round.id,
|
||
player1_id: qualifiedPlayers[i].ladder_user_id,
|
||
player2_id: qualifiedPlayers[size - 1 - i].ladder_user_id,
|
||
status: 0
|
||
}, { transaction: t });
|
||
}
|
||
|
||
await t.commit();
|
||
res.json(success(null, '淘汰赛已开始'));
|
||
} catch (err) {
|
||
await t.rollback();
|
||
console.error('开始淘汰赛失败:', err);
|
||
res.status(500).json(error('操作失败'));
|
||
}
|
||
}
|
||
|
||
// 结束比赛
|
||
async endMatch(req, res) {
|
||
const t = await sequelize.transaction();
|
||
try {
|
||
const { id } = req.params;
|
||
|
||
const match = await Match.findByPk(id, {
|
||
include: [{ model: MatchPlayer, as: 'players' }]
|
||
});
|
||
|
||
if (!match) {
|
||
await t.rollback();
|
||
return res.status(404).json(error('比赛不存在', 404));
|
||
}
|
||
|
||
// 计算最终排名和战力值
|
||
const players = match.players.sort((a, b) => {
|
||
if (b.win_count !== a.win_count) return b.win_count - a.win_count;
|
||
return b.initial_power - a.initial_power;
|
||
});
|
||
|
||
for (let i = 0; i < players.length; i++) {
|
||
const player = players[i];
|
||
const ladderUser = await LadderUser.findByPk(player.ladder_user_id);
|
||
|
||
await player.update({
|
||
rank: i + 1,
|
||
final_power: ladderUser.power_score,
|
||
player_status: 'finished'
|
||
}, { transaction: t });
|
||
|
||
// 处理升降级(如果是月度排位赛)
|
||
if (match.type === MATCH_TYPES.RANKING) {
|
||
const promotion = PowerCalculator.determinePromotion(i + 1, players.length);
|
||
if (promotion === 'promote' && ladderUser.level < 5) {
|
||
await ladderUser.update({ level: ladderUser.level + 1 }, { transaction: t });
|
||
} else if (promotion === 'demote' && ladderUser.level > 1) {
|
||
await ladderUser.update({ level: ladderUser.level - 1 }, { transaction: t });
|
||
}
|
||
}
|
||
}
|
||
|
||
await match.update({
|
||
status: MATCH_STATUS.FINISHED,
|
||
stage: RANKING_STAGE.FINISHED,
|
||
end_time: new Date()
|
||
}, { transaction: t });
|
||
|
||
await t.commit();
|
||
res.json(success(null, '比赛已结束'));
|
||
} catch (err) {
|
||
await t.rollback();
|
||
console.error('结束比赛失败:', err);
|
||
res.status(500).json(error('操作失败'));
|
||
}
|
||
}
|
||
|
||
// 修改对局结果
|
||
async updateGameResult(req, res) {
|
||
try {
|
||
const { id, gameId } = req.params;
|
||
const { player1_score, player2_score } = req.body;
|
||
|
||
const game = await MatchGame.findOne({
|
||
where: { id: gameId, match_id: id }
|
||
});
|
||
|
||
if (!game) {
|
||
return res.status(404).json(error('对局不存在', 404));
|
||
}
|
||
|
||
if (game.confirm_status === CONFIRM_STATUS.CONFIRMED) {
|
||
return res.status(400).json(error('已确认的对局不能修改', 400));
|
||
}
|
||
|
||
const winnerId = player1_score > player2_score ? game.player1_id : game.player2_id;
|
||
const loserId = player1_score > player2_score ? game.player2_id : game.player1_id;
|
||
|
||
await game.update({
|
||
player1_score,
|
||
player2_score,
|
||
winner_id: winnerId,
|
||
loser_id: loserId
|
||
});
|
||
|
||
res.json(success(null, '更新成功'));
|
||
} catch (err) {
|
||
console.error('修改对局结果失败:', err);
|
||
res.status(500).json(error('修改失败'));
|
||
}
|
||
}
|
||
|
||
// 裁判确认对局结果
|
||
async confirmGameResult(req, res) {
|
||
const t = await sequelize.transaction();
|
||
try {
|
||
const { id, gameId } = req.params;
|
||
|
||
const game = await MatchGame.findOne({
|
||
where: { id: gameId, match_id: id },
|
||
include: [{ model: Match, as: 'match' }]
|
||
});
|
||
|
||
if (!game) {
|
||
await t.rollback();
|
||
return res.status(404).json(error('对局不存在', 404));
|
||
}
|
||
|
||
if (!game.winner_id) {
|
||
await t.rollback();
|
||
return res.status(400).json(error('请先填写比分', 400));
|
||
}
|
||
|
||
// 计算战力值变动
|
||
const winner = await LadderUser.findByPk(game.winner_id);
|
||
const loser = await LadderUser.findByPk(game.loser_id);
|
||
|
||
const { winnerChange, loserChange } = PowerCalculator.calculate(
|
||
{ powerScore: winner.power_score, level: winner.level, protectedMatches: winner.protected_matches },
|
||
{ powerScore: loser.power_score, level: loser.level, protectedMatches: loser.protected_matches },
|
||
parseFloat(game.match.weight)
|
||
);
|
||
|
||
// 更新游戏记录
|
||
await game.update({
|
||
confirm_status: CONFIRM_STATUS.CONFIRMED,
|
||
confirmed_by: req.admin.id,
|
||
confirmed_at: new Date(),
|
||
winner_power_change: winnerChange,
|
||
loser_power_change: loserChange,
|
||
status: 2
|
||
}, { transaction: t });
|
||
|
||
// 更新战力值
|
||
await winner.update({
|
||
power_score: winner.power_score + winnerChange,
|
||
match_count: winner.match_count + 1,
|
||
monthly_match_count: winner.monthly_match_count + 1,
|
||
win_count: winner.win_count + 1,
|
||
last_match_time: new Date()
|
||
}, { transaction: t });
|
||
|
||
await loser.update({
|
||
power_score: Math.max(0, loser.power_score + loserChange),
|
||
match_count: loser.match_count + 1,
|
||
monthly_match_count: loser.monthly_match_count + 1,
|
||
last_match_time: new Date()
|
||
}, { transaction: t });
|
||
|
||
// 更新选手统计
|
||
await MatchPlayer.increment('win_count', {
|
||
where: { match_id: id, ladder_user_id: game.winner_id },
|
||
transaction: t
|
||
});
|
||
await MatchPlayer.increment('lose_count', {
|
||
where: { match_id: id, ladder_user_id: game.loser_id },
|
||
transaction: t
|
||
});
|
||
|
||
await t.commit();
|
||
res.json(success({ winnerChange, loserChange }, '确认成功'));
|
||
} catch (err) {
|
||
await t.rollback();
|
||
console.error('确认对局失败:', err);
|
||
res.status(500).json(error('确认失败'));
|
||
}
|
||
}
|
||
|
||
// 手动添加比赛选手
|
||
async addPlayer(req, res) {
|
||
try {
|
||
const { id } = req.params;
|
||
const { user_id } = req.body;
|
||
|
||
const match = await Match.findByPk(id);
|
||
if (!match) {
|
||
return res.status(404).json(error('比赛不存在', 404));
|
||
}
|
||
|
||
if (match.status !== MATCH_STATUS.PENDING) {
|
||
return res.status(400).json(error('比赛已开始或结束,无法添加选手', 400));
|
||
}
|
||
|
||
// 查找该用户在对应门店的选手信息
|
||
const ladderUser = await LadderUser.findOne({
|
||
where: {
|
||
user_id,
|
||
store_id: match.store_id
|
||
}
|
||
});
|
||
|
||
if (!ladderUser) {
|
||
return res.status(400).json(error('该用户未在本店注册选手信息', 400));
|
||
}
|
||
|
||
// 检查是否已参赛
|
||
const existingPlayer = await MatchPlayer.findOne({
|
||
where: {
|
||
match_id: id,
|
||
ladder_user_id: ladderUser.id
|
||
}
|
||
});
|
||
|
||
if (existingPlayer) {
|
||
return res.status(400).json(error('该选手已在比赛中', 400));
|
||
}
|
||
|
||
// 添加选手
|
||
await MatchPlayer.create({
|
||
match_id: id,
|
||
ladder_user_id: ladderUser.id,
|
||
initial_power: ladderUser.power_score,
|
||
player_status: 'waiting'
|
||
});
|
||
|
||
res.json(success(null, '添加成功'));
|
||
} catch (err) {
|
||
console.error('添加选手失败:', err);
|
||
res.status(500).json(error('添加失败'));
|
||
}
|
||
}
|
||
|
||
// 移除比赛选手
|
||
async removePlayer(req, res) {
|
||
try {
|
||
const { id, playerId } = req.params;
|
||
|
||
const match = await Match.findByPk(id);
|
||
if (!match) {
|
||
return res.status(404).json(error('比赛不存在', 404));
|
||
}
|
||
|
||
if (match.status !== MATCH_STATUS.PENDING) {
|
||
return res.status(400).json(error('比赛已开始或结束,无法移除选手', 400));
|
||
}
|
||
|
||
// 查找选手记录
|
||
const matchPlayer = await MatchPlayer.findOne({
|
||
where: {
|
||
match_id: id,
|
||
id: playerId
|
||
}
|
||
});
|
||
|
||
if (!matchPlayer) {
|
||
return res.status(404).json(error('该选手未参加此比赛', 404));
|
||
}
|
||
|
||
// 移除选手
|
||
await matchPlayer.destroy();
|
||
|
||
res.json(success(null, '移除成功'));
|
||
} catch (err) {
|
||
console.error('移除选手失败:', err);
|
||
res.status(500).json(error('移除失败'));
|
||
}
|
||
}
|
||
|
||
// 自动匹配选手
|
||
async _autoMatchPlayers(matchId, transaction) {
|
||
const match = await Match.findByPk(matchId, {
|
||
include: [{ model: MatchPlayer, as: 'players' }],
|
||
transaction
|
||
});
|
||
|
||
// 获取等待中的选手
|
||
const waitingPlayers = match.players.filter(p => p.player_status === 'waiting');
|
||
if (waitingPlayers.length < 2) return;
|
||
|
||
// 获取未完成的对局
|
||
const pendingGames = await MatchGame.findAll({
|
||
where: {
|
||
match_id: matchId,
|
||
status: 0
|
||
},
|
||
transaction
|
||
});
|
||
|
||
// 找到可以匹配的选手对
|
||
for (const game of pendingGames) {
|
||
// 使用 == 比较,避免 string/number 类型不一致问题
|
||
// 注意:player1_id 和 player2_id 是 bigint,可能是 string 类型
|
||
// ladder_user_id 也是 bigint,可能是 string 类型
|
||
const player1 = waitingPlayers.find(p => String(p.ladder_user_id) === String(game.player1_id));
|
||
const player2 = waitingPlayers.find(p => String(p.ladder_user_id) === String(game.player2_id));
|
||
|
||
if (player1 && player2) {
|
||
// 更新选手状态
|
||
await MatchPlayer.update(
|
||
{ player_status: 'playing', current_opponent_id: game.player2_id },
|
||
{ where: { id: player1.id }, transaction }
|
||
);
|
||
await MatchPlayer.update(
|
||
{ player_status: 'playing', current_opponent_id: game.player1_id },
|
||
{ where: { id: player2.id }, transaction }
|
||
);
|
||
|
||
// 更新对局状态
|
||
await game.update({ status: 1 }, { transaction });
|
||
|
||
// 从等待列表移除
|
||
const idx1 = waitingPlayers.indexOf(player1);
|
||
const idx2 = waitingPlayers.indexOf(player2);
|
||
waitingPlayers.splice(Math.max(idx1, idx2), 1);
|
||
waitingPlayers.splice(Math.min(idx1, idx2), 1);
|
||
|
||
if (waitingPlayers.length < 2) break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = new MatchAdminController();
|