import BaseModel from './BaseModel'; import { index, getModelForClass, prop, DocumentType, mongoose, Ref } from '@typegoose/typegoose'; import Role, { RoleType } from '../db/Role'; import { genCode } from '../pubUtils/util'; import { GuildType } from './Guild'; import { LEAGUE_AUTH } from '../consts'; class Member { @prop({ required: true }) roleId: string; @prop({ required: true }) guildCode: string; @prop({ required: true }) auth: number; } @index({ leagueCode: 1, status: 1 }) @index({ guildCodes: 1, status: 1 }) @index({ 'members.roleId': 1, status: 1 }) export default class GVGLeague extends BaseModel { @prop({ required: true }) leagueCode: string; // 唯一id @prop({ required: true, type: String }) guildCodes: string[]; // 包含军团 @prop({ required: true, ref: () => Role, type: mongoose.Schema.Types.ObjectId }) leader: Ref; @prop({ required: true, default: '' }) name: string; // 名称 @prop({ required: true, default: 1 }) icon: number; // 图标 @prop({ required: true, default: '' }) notice: string; // 公告 @prop({ required: true, default: 0 }) guildCnt: number; // 军团数量 @prop({ required: true, default: 0 }) memberCnt: number; // 玩家人数 @prop({ required: true, default: false }) isAuto: boolean; // 是否是自动创建的 @prop({ required: true, default: 1 }) status: number; // 1-健在 0-解散 @prop({ required: true, default: 1 }) type: number; // 1-单服 2-跨服 @prop({ required: true, default: 1 }) serverId: number; // 服务器id @prop({ required: true, default: [], type: Member, _id: false }) members: Member[]; public static async checkName(name: string) { const result = await GVGLeagueModel.exists({ name, status: 1 }); return result; } public static async createLeague(guild: GuildType, params: GVGLeagueUpdate) { const { code, name, memberCnt, leader, members } = guild; const doc = new GVGLeagueModel(); const leagueCode = genCode(6); let _leader = leader; let _members = members.map(roleId => ({ roleId, auth: _leader.roleId == roleId? LEAGUE_AUTH.LEADER: LEAGUE_AUTH.MEMBER, guildCode: code })); const update = Object.assign(doc.toJSON(), { guildCodes: [code], name: `${name}联军`, guildCnt: 1, memberCnt, isAuto: true, leader: _leader?._id, members: _members, leagueCode }, params); delete update._id; const result: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ guildCodes: code, status: 1 }, { $setOnInsert: update }, { upsert: true, new: true }) .select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 }) .populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role') .lean(); return result; } public static async findLeagueByGuild(guildCode: string) { const league: GVGLeagueType = await GVGLeagueModel.findOne({ guildCodes: guildCode, status: 1 }) .populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role') .lean(); return league } public static async findByCondition(type: number, serverIds: number[], page: number, name: string) { let query = { status: 1, type, serverId: { $in: serverIds } }; if(name) { query['name'] = { $regex: new RegExp(name, 'i') }; } const league: GVGLeagueType[] = await GVGLeagueModel.find(query) .populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role') .skip((page - 1) * 30).limit(30) .lean(); return league } public static async findByCode(leagueCode: string, select = '') { const league: GVGLeagueType = await GVGLeagueModel.findOne({ leagueCode, status: 1 }) .populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, _id: 0 }, 'Role') .select(select) .lean(); return league } public static async findByCodeWithoutPopulate(leagueCode: string, select = '') { const league: GVGLeagueType = await GVGLeagueModel.findOne({ leagueCode, status: 1 }).select(select).lean(); return league } public static async findByCodes(leagueCodes: string[]) { const leagues: GVGLeagueType[] = await GVGLeagueModel.find({ leagueCode: { $in: leagueCodes }, status: 1 }) .populate('leader', { roleId: 1, roleName: 1, head: 1, frame: 1, spine: 1, lv: 1, quitTime: 1, ce: 1, title: 1, serverId: 1, guildName: 1, _id: 0 }, 'Role') .lean(); return leagues } public static async findByCodesWithoutPopulate(leagueCodes: string[], select = '') { const leagues: GVGLeagueType[] = await GVGLeagueModel.find({ leagueCode: { $in: leagueCodes }, status: 1 }).select(select).lean(); return leagues } public static async joinGuild(leagueCode: string, guild: GuildType) { const { code, memberCnt, leader, members } = guild; let _leader = leader; let _members = members.map(roleId => ({ roleId, auth: _leader.roleId == roleId? LEAGUE_AUTH.SUB_LEADER: LEAGUE_AUTH.MEMBER, guildCode: code })); const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $push: { guildCodes: code, members: { $each: _members } }, $inc: { guildCnt: 1, memberCnt: memberCnt } }, { new: true }).lean(); return league } public static async findAllLeague() { const leagues: { leagueCode: string, memberCnt: number, serverId: number }[] = await GVGLeagueModel.aggregate([ { $match: { status: 1 } }, { $project: { leagueCode: 1, memberCnt: 1, serverId: 1 } } ]); return leagues; } public static async findActiveLeagueMembers() { const leagues: { members: Member[] }[] = await GVGLeagueModel.aggregate([ { $match: { status: 1 } }, { $project: { members: 1 } } ]); return leagues; } public static async quitGuild(leagueCode: string, guild: GuildType) { const { code, memberCnt, members } = guild; const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $pull: { guildCodes: code, members: { roleId: { $in: members } } }, $inc: { guildCnt: -1, memberCnt: -memberCnt } }, { new: true }).lean(); return league } public static async dismiss(leagueCode: string) { const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $set: { status: 0 }}, { new: true }).lean(); return league } public static async dismissByIds(_ids: string[]) { await GVGLeagueModel.updateMany({ _id: { $in: _ids } }, { $set: { status: 0 }}); } public static async abdicate(leagueCode: string, fromRoleId: string, toRoleId: string, leader: string) { let league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': fromRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.SUB_LEADER }}, { new: true }).lean(); league = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': toRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.LEADER, leader }}, { new: true }).lean(); return league } public static async setInfo(leagueCode: string, name: string, notice: string, icon: number) { let updateInfo: GVGLeagueUpdate = {}; if(name != undefined) updateInfo.name = name; if(notice != undefined) updateInfo.notice = notice; if(icon != undefined) updateInfo.icon = icon; const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $set: updateInfo }, { new: true }).lean(); return league; } public static async joinMember(leagueCode: string, roleId: string, guildCode: string) { const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $push: { members: { roleId, auth: LEAGUE_AUTH.MEMBER, guildCode } }, $inc: { memberCnt: 1 } }, { new: true }).lean(); return league; } public static async quitMember(leagueCode: string, roleId: string) { const league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1 }, { $pull: { members: { roleId } }, $inc: { memberCnt: -1 } }, { new: true }).lean(); return league; } public static async abdicateGuild(leagueCode: string, fromRoleId: string, toRoleId: string, leader: string) { let league: GVGLeagueType = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': fromRoleId }, { $set: { 'members.$.auth': LEAGUE_AUTH.MEMBER }}).lean(); const member = league.members.find(cur => cur.roleId == fromRoleId); const updateInfo = { 'members.$.auth': member?.auth }; if(member?.auth == LEAGUE_AUTH.LEADER) updateInfo['leader'] = leader; league = await GVGLeagueModel.findOneAndUpdate({ leagueCode, status: 1, 'members.roleId': toRoleId }, { $set: updateInfo }, { new: true }).lean(); return league } public static async findAutoCreateLeague() { let leagues: GVGLeagueType[] = await GVGLeagueModel.find({ isAuto: true, status: 1 }).lean(); return leagues } } export const GVGLeagueModel = getModelForClass(GVGLeague); export interface GVGLeagueType extends Pick, keyof GVGLeague> { id: number; }; export type GVGLeagueUpdate = Partial; // 将所有字段变成可选项