diff --git a/apps/character/AvatarCard.js b/apps/character/AvatarCard.js index cf80155a..0534a647 100644 --- a/apps/character/AvatarCard.js +++ b/apps/character/AvatarCard.js @@ -1,12 +1,14 @@ -import { Character, Avatar, MysApi } from '../../models/index.js' -import { Cfg, Common, Profile } from '../../components/index.js' +import { Character, Avatar, MysApi, Player } from '../../models/index.js' +import { Cfg, Common } from '../../components/index.js' import lodash from 'lodash' import { segment } from 'oicq' +import moment from 'moment' export async function renderAvatar (e, avatar, renderType = 'card') { // 如果传递的是名字,则获取 let uid = e.uid if (typeof (avatar) === 'string') { + // 检查角色 let char = Character.get(avatar) if (!char) { return false @@ -17,21 +19,12 @@ export async function renderAvatar (e, avatar, renderType = 'card') { if (!char.isRelease) { avatar = { id: char.id, name: char.name, detail: false } } else { - let profile = Profile.get(uid, char.id, true) - if (profile && profile.hasData) { - // 优先使用Profile数据 - avatar = profile - } else { - // 使用Mys数据兜底 - let charData = await mys.getCharacter() - if (!charData) return true - - let avatars = charData.avatars - if (char.isTraveler) { - char = await char.checkAvatars(avatars, uid) - } - avatars = lodash.keyBy(avatars, 'id') - avatar = avatars[char.id] || { id: char.id, name: char.name, detail: false } + let player = Player.create(e) + await player.refreshMys() + await player.refreshTalent(char.id) + avatar = player.getAvatar(char.id) + if (!avatar) { + avatar = { id: char.id, name: char.name, detail: false } } } } @@ -39,8 +32,8 @@ export async function renderAvatar (e, avatar, renderType = 'card') { } // 渲染角色卡片 -async function renderCard (e, ds, renderType = 'card') { - let char = Character.get(ds) +async function renderCard (e, avatar, renderType = 'card') { + let char = Character.get(avatar.id) if (!char) { return false } @@ -54,11 +47,13 @@ async function renderCard (e, ds, renderType = 'card') { let custom = char.isCustom let isRelease = char.isRelease if (isRelease) { - let mys = await MysApi.init(e) - let avatar = new Avatar(ds, uid, mys.isSelfCookie) - data = avatar.getData('id,name,sName,level,fetter,cons,weapon,elem,artis,artisSet,imgs,dataSourceName,updateTime') - data.talent = await avatar.getTalent(mys) - if (data.talent) { + data = avatar.getDetail() + data.imgs = char.imgs + data.source = avatar._source + data.artis = avatar.getArtisDetail() + data.updateTime = moment(new Date(avatar._time)).format('MM-DD HH:mm') + if (data.hasTalent) { + data.talent = avatar.talent data.talentMap = ['a', 'e', 'q'] // 计算皇冠个数 data.crownNum = lodash.filter(lodash.map(data.talent, (d) => d.original), (d) => d >= 10).length @@ -66,6 +61,7 @@ async function renderCard (e, ds, renderType = 'card') { } else { data = char.getData('id,name,sName') } + let width = 600 let imgCss = '' let scale = 1.2 @@ -92,33 +88,3 @@ async function renderCard (e, ds, renderType = 'card') { } return true } - -export async function getAvatarList (e, type, mys) { - let data = await mys.getCharacter() - if (!data) return false - - let avatars = data.avatars - - if (!avatars || avatars.length <= 0) { - return false - } - let list = [] - for (let val of avatars) { - if (type !== false) { - if (!Character.checkWifeType(val.id, type)) { - continue - } - } - if (val.rarity > 5) { - val.rarity = 5 - } - list.push(val) - } - - if (list.length <= 0) { - return false - } - let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level' - list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(',')) - return list -} diff --git a/apps/character/AvatarWife.js b/apps/character/AvatarWife.js index 0de0d71d..a3e13aae 100644 --- a/apps/character/AvatarWife.js +++ b/apps/character/AvatarWife.js @@ -1,8 +1,8 @@ // #老婆 import lodash from 'lodash' import { Common } from '../../components/index.js' -import { Character, MysApi, AvatarList } from '../../models/index.js' -import { getAvatarList, renderAvatar } from './AvatarCard.js' +import { Character, MysApi, Player } from '../../models/index.js' +import { renderAvatar } from './AvatarCard.js' const relationMap = { wife: { @@ -74,6 +74,7 @@ export async function wife (e) { if (!mys || !mys.uid) { return true } + let player = Player.create(e) let selfUser = mys.selfUser let isSelf = true let renderType = (action === '卡片' ? 'card' : 'photo') @@ -92,7 +93,7 @@ export async function wife (e) { if (wifeList && wifeList.length > 0 && isSelf && !e.isPoke) { if (wifeList[0] === '随机') { // 如果选择为全部,则从列表中随机选择一个 - avatarList = await getAvatarList(e, targetCfg.type, mys) + avatarList = await getAvatarList(player, targetCfg.type, mys) let avatar = lodash.sample(avatarList) return renderAvatar(e, avatar, renderType) } else { @@ -101,19 +102,11 @@ export async function wife (e) { } } } - // 如果未指定过,则从列表中排序并随机选择前5个 - if (e.isPoke) { - avatarList = await getAvatarList(e, false, mys) - if (avatarList && avatarList.length > 0) { - avatar = lodash.sample(avatarList) - return await renderAvatar(e, avatar, renderType) - } - } else { - avatarList = await getAvatarList(e, targetCfg.type, mys) - if (avatarList && avatarList.length > 0) { - avatar = lodash.sample(avatarList.slice(0, 5)) - return await renderAvatar(e, avatar, renderType) - } + // 如果未指定过,则从列表中排序并随机选择 + avatarList = await getAvatarList(player, e.isPoke ? false : targetCfg.type, mys) + if (avatarList && avatarList.length > 0) { + avatar = lodash.sample(avatarList) + return await renderAvatar(e, avatar, renderType) } e.reply('在当前米游社公开展示的角色中未能找到适合展示的角色..') return true @@ -169,3 +162,23 @@ export async function wife (e) { export async function pokeWife (e, components) { return await wife(e, components) } + +async function getAvatarList (player, type, mys) { + await player.refreshMys() + let list = [] + player.forEachAvatar((avatar) => { + if (type !== false) { + if (!Character.checkWifeType(avatar.id, type)) { + return true + } + } + list.push(avatar) + }) + + if (list.length <= 0) { + return false + } + let sortKey = 'level,fetter,weapon_level,rarity,weapon_rarity,cons,weapon_affix_level' + list = lodash.orderBy(list, sortKey, lodash.repeat('desc,', sortKey.length).split(',')) + return list +} diff --git a/apps/profile.js b/apps/profile.js index 05c1e067..13a002e7 100644 --- a/apps/profile.js +++ b/apps/profile.js @@ -1,5 +1,5 @@ import { Common, App, Data, Cfg } from '../components/index.js' -import { Character } from '../models/index.js' +import { Character, Player } from '../models/index.js' import { getTargetUid, getProfile, profileHelp } from './profile/ProfileCommon.js' import { profileArtis, profileArtisList } from './profile/ProfileArtis.js' import { renderProfile } from './profile/ProfileDetail.js' diff --git a/apps/profile/ProfileArtis.js b/apps/profile/ProfileArtis.js index 80c41032..7bb81342 100644 --- a/apps/profile/ProfileArtis.js +++ b/apps/profile/ProfileArtis.js @@ -3,9 +3,9 @@ * * */ import lodash from 'lodash' -import { Cfg, Profile, Common } from '../../components/index.js' +import { Cfg, Common } from '../../components/index.js' import { getTargetUid, profileHelp, autoGetProfile } from './ProfileCommon.js' -import { Artifact, Character, ProfileArtis } from '../../models/index.js' +import { Artifact, Character, ProfileArtis, Player } from '../../models/index.js' /* * 角色圣遗物面板 @@ -64,14 +64,12 @@ export async function profileArtisList (e) { } let artis = [] - let profiles = Profile.getAll(uid) || {} - - if (!profiles || profiles.length === 0) { - e.reply('暂无角色圣遗物详情') - return true - } - - lodash.forEach(profiles || [], (profile) => { + let player = Player.create(uid) + player.forEachAvatar((avatar) => { + let profile = avatar.getProfile() + if (!profile) { + return true + } let name = profile.name let char = Character.get(name) if (!profile.hasData || !profile.hasArtis()) { diff --git a/apps/profile/ProfileChange.js b/apps/profile/ProfileChange.js index e5a76965..ea4535ab 100644 --- a/apps/profile/ProfileChange.js +++ b/apps/profile/ProfileChange.js @@ -2,8 +2,8 @@ * 面板数据替换相关逻辑 */ import lodash from 'lodash' -import { Profile, Data } from '../../components/index.js' -import { Character, ProfileData, Weapon } from '../../models/index.js' +import { Data } from '../../components/index.js' +import { Character, ProfileData, Weapon,Player } from '../../models/index.js' const keyMap = { artis: '圣遗物', @@ -153,8 +153,9 @@ const ProfileChange = { if (!charid) { return false } + let player = Player.create(uid) - let source = Profile.get(uid, charid) + let source = player.getProfile(charid) let dc = ds.char || {} if (!source || !source.hasData) { source = {} @@ -168,7 +169,7 @@ const ProfileChange = { let profiles = {} if (source && source.id) { - profiles[`${source.uid}:${source.id}`] = source + profiles[`${player.uid}:${source.id}`] = source } // 获取source let getSource = function (cfg) { @@ -176,10 +177,11 @@ const ProfileChange = { return source } let cuid = cfg.uid || uid + let cPlayer = Player.create(uid) let id = cfg.char || source.id let key = cuid + ':' + id if (!profiles[key]) { - profiles[key] = Profile.get(cuid, id) || {} + profiles[key] = cPlayer.getProfile(id) || {} } return profiles[key]?.id ? profiles[key] : source } diff --git a/apps/profile/ProfileCommon.js b/apps/profile/ProfileCommon.js index 4afe2966..e53dd35c 100644 --- a/apps/profile/ProfileCommon.js +++ b/apps/profile/ProfileCommon.js @@ -4,8 +4,8 @@ import lodash from 'lodash' import { segment } from 'oicq' import { profileList } from './ProfileList.js' -import { Profile, Version } from '../../components/index.js' -import { Character, MysApi } from '../../models/index.js' +import { Version } from '../../components/index.js' +import { Character, MysApi, Player } from '../../models/index.js' /* * 获取面板查询的 目标uid @@ -87,7 +87,8 @@ export async function autoRefresh (e) { e.isRefreshed = true // 数据更新 - let data = await Profile.request(uid, e) + let player = Player.create(uid) + let data = await player.refreshProfile(e) if (!data) { return false } @@ -127,7 +128,7 @@ export async function autoGetProfile (e, uid, avatar, callback) { return { err: true } } - let profile = Profile.get(uid, char.id) + let profile = Player.getAvatar(uid, char.id) if (!profile || !profile.hasData) { if (await refresh()) { return { err: true } @@ -155,17 +156,18 @@ export async function getProfile (e) { } // 数据更新 - let data = await Profile.request(uid, e) - if (!data) { + let player = Player.create(uid) + let ret = await player.refreshProfile(e) + if (!ret) { return true } - if (!data.chars) { + if (!player._update.length === 0) { e.reply('获取角色面板数据失败,请确认角色已在游戏内橱窗展示,并开放了查看详情。设置完毕后请5分钟后再进行请求~') } else { let ret = {} - lodash.forEach(data.chars, (ds) => { - let char = Character.get(ds.id) + lodash.forEach(player._update, (id) => { + let char = Character.get(id) if (char) { ret[char.name] = true } @@ -180,41 +182,6 @@ export async function getProfile (e) { return true } -/* -* 获取面板列表 -* */ -export async function getProfileAll (e) { - let uid = await getTargetUid(e) - if (!uid) { - return true - } - - let profiles = Profile.getAll(uid) || {} - - let chars = [] - lodash.forEach(profiles || [], (ds) => { - if (!['enka', 'miao'].includes(ds.dataSource)) { - return true - } - ds.name && chars.push(ds.name) - }) - - if (chars.length === 0) { - if (await autoRefresh(e)) { - await getProfileAll(e) - return true - } else { - e.reply('尚未获取任何角色数据') - await profileHelp(e) - } - return true - } - - e.reply(`uid${uid} 已获取面板角色: ` + chars.join(', ')) - - return true -} - /* * 面板帮助 * */ diff --git a/apps/profile/ProfileDetail.js b/apps/profile/ProfileDetail.js index dfeb1061..c1877e06 100644 --- a/apps/profile/ProfileDetail.js +++ b/apps/profile/ProfileDetail.js @@ -1,7 +1,7 @@ import lodash from 'lodash' import { autoRefresh } from './ProfileCommon.js' -import { Common, Format, Profile } from '../../components/index.js' -import { MysApi, Avatar, ProfileRank, ProfileArtis } from '../../models/index.js' +import { Common, Format } from '../../components/index.js' +import { MysApi, Avatar, ProfileRank, ProfileArtis, Player } from '../../models/index.js' export async function renderProfile (e, char, mode = 'profile', params = {}) { let selfUser = await MysApi.initUser(e) @@ -18,7 +18,8 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) { return true } - let profile = e._profile || Profile.get(uid, char.id) + let player = Player.create(uid) + let profile = e._profile || player.getProfile(char.id) let refresh = async () => { let refreshRet = await autoRefresh(e) @@ -116,7 +117,7 @@ export async function renderProfile (e, char, mode = 'profile', params = {}) { bodyClass: `char-${char.name}`, mode, changeProfile: e._profileMsg - }, { e, scale: 1.6,retMsgId: true }) + }, { e, scale: 1.6, retMsgId: true }) if (msgRes && msgRes.message_id) { // 如果消息发送成功,就将message_id和图片路径存起来,3小时过期 await redis.set(`miao:original-picture:${msgRes.message_id}`, imgs.splash0, { EX: 3600 * 3 }) diff --git a/apps/profile/ProfileList.js b/apps/profile/ProfileList.js index 44bd6585..64fa0fb9 100644 --- a/apps/profile/ProfileList.js +++ b/apps/profile/ProfileList.js @@ -1,7 +1,7 @@ import lodash from 'lodash' import { autoRefresh, getTargetUid } from './ProfileCommon.js' -import { ProfileRank } from '../../models/index.js' -import { Common, Profile, Data } from '../../components/index.js' +import { ProfileRank, Player } from '../../models/index.js' +import { Common, Data } from '../../components/index.js' export async function profileList (e) { let uid = await getTargetUid(e) @@ -14,7 +14,7 @@ export async function profileList (e) { isSelfUid = uids.join(',').split(',').includes(uid + '') } let rank = false - let servName = Profile.getServName(uid) + let servName = Player.getProfileServName(uid) let hasNew = false let newCount = 0 @@ -27,7 +27,8 @@ export async function profileList (e) { } const cfg = await Data.importCfg('cfg') // 获取面板数据 - let profiles = Profile.getAll(uid) + let player = Player.create(uid) + let profiles = player.getProfiles() // 检测标志位 let qq = (e.at && !e.atBot) ? e.at : e.qq await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: isSelfUid ? 'ck' : 'bind' }) @@ -38,8 +39,9 @@ export async function profileList (e) { } const rankCfg = await ProfileRank.getGroupCfg(groupId) const groupRank = rank && (cfg?.diyCfg?.groupRank || false) && rankCfg.status !== 1 - await Profile.forEach(uid, async function (profile) { - if (!profile.hasData) { + await player.forEachAvatarAsync(async function (avatar) { + let profile = avatar.getProfile() + if (!profile) { return true } let char = profile.char diff --git a/apps/profile/ProfileRank.js b/apps/profile/ProfileRank.js index 226d44ce..4efe0700 100644 --- a/apps/profile/ProfileRank.js +++ b/apps/profile/ProfileRank.js @@ -1,6 +1,6 @@ -import { Character, ProfileRank, ProfileDmg, Avatar } from '../../models/index.js' +import { Character, ProfileRank, ProfileDmg, Avatar, Player } from '../../models/index.js' import { renderProfile } from './ProfileDetail.js' -import { Data, Profile, Common, Format } from '../../components/index.js' +import { Data, Common, Format } from '../../components/index.js' import lodash from 'lodash' export async function groupRank (e) { @@ -115,7 +115,8 @@ export async function refreshRank (e) { let count = 0 for (let qq in groupUids) { for (let { uid, type } of groupUids[qq]) { - let profiles = Profile.getAll(uid) + let player = new Player(uid) + let profiles = player.getProfiles() // 刷新rankLimit await ProfileRank.setUidInfo({ uid, profiles, qq, uidType: type }) let rank = await ProfileRank.create({ groupId, uid, qq }) @@ -156,13 +157,14 @@ async function renderCharRankList ({ e, uids, char, mode, groupId }) { let list = [] for (let ds of uids) { let uid = ds.uid || ds.value - let profile = Profile.get(uid, ds.charId || char.id) + let player = Player.create(uid) + let avatar = player.getAvatar(ds.charId || char.id) + let profile = avatar.getProfile() if (profile) { let profileRank = await ProfileRank.create({ groupId, uid }) let data = await profileRank.getRank(profile, true) let mark = data?.mark?.data - let avatar = new Avatar(profile, uid) let tmp = { uid, isMax: !char, diff --git a/apps/profile/ProfileStat.js b/apps/profile/ProfileStat.js index bec77af8..2c8e9a32 100644 --- a/apps/profile/ProfileStat.js +++ b/apps/profile/ProfileStat.js @@ -1,41 +1,52 @@ import lodash from 'lodash' -import {Cfg, Common, Data } from '../../components/index.js' -import { AvatarList, ProfileRank } from '../../models/index.js' +import { Cfg, Common, Data } from '../../components/index.js' +import { MysApi, ProfileRank, Player } from '../../models/index.js' export async function profileStat (e) { let isMatch = /^#(面板|喵喵|角色|武器|天赋|技能|圣遗物)练度统计?$/.test(e.original_msg || e.msg || '') if (!Cfg.get('profileStat', false) && !isMatch) { return false -} - // 缓存时间,单位小时 + } + // 缓存时间,单位小时 let msg = e.msg.replace('#', '').trim() if (msg === '角色统计' || msg === '武器统计') { // 暂时避让一下抽卡分析的关键词 return false } - let avatars = await AvatarList.getAll(e) - if (!avatars) { - return true - } - let uid = avatars.uid + let mys = await MysApi.init(e) + if (!mys || !mys.uid) return false + + const uid = mys.uid + + let player = Player.create(e) + // 更新角色信息 + await player.refreshMys() + + // 更新天赋信息 + await player.refreshTalent() + let rank = false if (e.group_id) { rank = await ProfileRank.create({ group: e.group_id, uid, qq: e.user_id }) } - let talentData = await avatars.getTalentData() - // 天赋等级背景 + let avatarRet = [] - lodash.forEach(talentData, (avatar) => { - let { talent, id } = avatar - avatar.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3 - avatarRet.push(avatar) - let profile = avatars.getProfile(id) + player.forEachAvatar((avatar) => { + let { talent } = avatar + let ds = avatar.getDetail() + ds.aeq = talent?.a?.original + talent?.e?.original + talent?.q?.original || 3 + avatarRet.push(ds) + + let profile = avatar.getProfile() + if (!profile) { + return true + } if (profile) { if (profile.hasData) { let mark = profile.getArtisMark(false) - avatar.artisMark = Data.getData(mark, 'mark,markClass,names') + ds.artisMark = Data.getData(mark, 'mark,markClass,names') if (rank) { rank.getRank(profile) } @@ -47,9 +58,6 @@ export async function profileStat (e) { avatarRet = lodash.orderBy(avatarRet, sortKey) avatarRet = avatarRet.reverse() let talentNotice = '' - if (!avatars.isSelfCookie || avatarRet.length <= 8) { - talentNotice = '未绑定CK,信息可能展示不完全。回复#体力帮助获取CK配置帮助' - } return await Common.render('character/profile-stat', { save_id: uid, diff --git a/apps/stat.js b/apps/stat.js index 583205ac..42342033 100644 --- a/apps/stat.js +++ b/apps/stat.js @@ -4,7 +4,7 @@ * */ import lodash from 'lodash' import { Cfg, Common, App, Data } from '../components/index.js' -import { Abyss, AvatarList, Character, MysApi } from '../models/index.js' +import { Abyss, Character, MysApi, Player } from '../models/index.js' import HutaoApi from './wiki/HutaoApi.js' let app = App.init({ @@ -195,6 +195,9 @@ async function abyssTeam (e) { if (!mys || !mys.uid || !mys.isSelfCookie) { return true } + let player = Player.create(e) + await player.refreshMys() + await player.refreshTalent() let abyssData = await HutaoApi.getAbyssTeam() if (!abyssData || !abyssData.data) { @@ -202,18 +205,7 @@ async function abyssTeam (e) { return true } abyssData = abyssData.data - let avatars - try { - avatars = await AvatarList.getAll(e, mys) - // resDetail = await mys.getCharacter() - if (!avatars) { - e.reply('角色信息获取失败') - return true - } - } catch (err) { - // console.log(err); - } - let avatarData = await avatars.getTalentData() + let avatarData = player.getAvatarData() let avatarRet = {} let data = {} let noAvatar = {} @@ -397,6 +389,7 @@ async function uploadData (e) { } let ret = {} let uid = mys.uid + let player = Player.create(e) let resDetail, resAbyss try { resAbyss = await mys.getSpiralAbyss(1) @@ -413,9 +406,6 @@ async function uploadData (e) { return false } } - if (resAbyss.floors.length > 0 && !await AvatarList.hasTalentCache(uid)) { - e.reply('正在获取用户信息,请稍候...') - } resDetail = await mys.getCharacter() if (!resDetail || !resAbyss || !resDetail.avatars || resDetail.avatars.length <= 3) { e.reply('角色信息获取失败') @@ -431,6 +421,9 @@ async function uploadData (e) { } catch (err) { // console.log(err); } + // 更新player信息 + player.setMysCharData(resDetail) + if (ret && ret.retcode === 0) { let stat = [] if (ret.data) { @@ -440,7 +433,6 @@ async function uploadData (e) { } let abyss = new Abyss(resAbyss) let abyssData = abyss.getData() - let avatars = new AvatarList(uid, resDetail.avatars) let avatarIds = abyss.getAvatars() let overview = ret.info || (await HutaoApi.getOverview())?.data || {} let addMsg = function (title, ds) { @@ -484,7 +476,8 @@ async function uploadData (e) { } addMsg('最强一击', ret.data?.damage || abyssData?.stat?.dmg || {}) addMsg('最高承伤', ret.data?.takeDamage || abyssData?.stat.takeDmg || {}) - let avatarData = await avatars.getTalentData(avatarIds, mys) + await player.refreshTalent(avatarIds) + let avatarData = player.getAvatarData(avatarIds) return await Common.render('stat/abyss-summary', { abyss: abyssData, avatars: avatarData, diff --git a/components/Profile.js b/components/Profile.js deleted file mode 100644 index 3139fe0d..00000000 --- a/components/Profile.js +++ /dev/null @@ -1,129 +0,0 @@ -import fs from 'fs' -import lodash from 'lodash' -import { Character, ProfileReq, ProfileData } from '../models/index.js' -import Miao from './profile-data/miao.js' -import Enka from './profile-data/enka.js' - -const _path = process.cwd() -const userPath = `${_path}/data/UserData/` -if (!fs.existsSync(userPath)) { - fs.mkdirSync(userPath) -} - -ProfileReq.regServ({ Miao, Enka }) - -let Profile = { - async request (uid, e) { - if (uid.toString().length !== 9) { - return false - } - let req = new ProfileReq({ e, uid }) - let data - try { - data = await req.request() - if (!data) { - return false - } - return Profile.save(uid, data) - } catch (err) { - console.log(err) - e.reply('请求失败') - return false - } - }, - - save (uid, data) { - let userData = {} - const userFile = `${userPath}/${uid}.json` - if (fs.existsSync(userFile)) { - try { - userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {} - } catch (e) { - userData = {} - } - } - lodash.assignIn(userData, lodash.pick(data, 'uid,name,lv,avatar'.split(','))) - userData.chars = userData.chars || {} - lodash.forEach(data.chars, (char, charId) => { - userData.chars[charId] = char - }) - fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ') - return data - }, - - _get (uid, charId) { - const userFile = `${userPath}/${uid}.json` - let userData = {} - if (fs.existsSync(userFile)) { - try { - userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {} - } catch (e) { - } - } - if (userData && userData.chars) { - let char = Character.get(charId) - if (char.isTraveler) { - let charData = userData.chars['10000005'] || userData.chars['10000007'] || false - if (charData) { - char.checkAvatars(charData, uid) - } - return charData - } else { - return userData.chars[charId] - } - } - return false - }, - - get (uid, charId, onlyHasData = false) { - let data = Profile._get(uid, charId) - if (data) { - let profile = new ProfileData(data, uid) - if (onlyHasData && !profile.hasData) { - return false - } - return profile - } else { - return false - } - }, - - getAll (uid) { - const userFile = `${userPath}/${uid}.json` - let userData = {} - if (fs.existsSync(userFile)) { - try { - userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {} - } catch (e) { - userData = {} - } - } - if (userData && userData.chars) { - let ret = {} - lodash.forEach(userData.chars, (ds, id) => { - let profile = new ProfileData(ds, uid) - if (profile.hasData) { - ret[id] = profile - } - }) - return ret - } - return false - }, - - async forEach (uid, fn) { - let profiles = Profile.getAll(uid) - for (let id in profiles) { - let ret = await fn(profiles[id], id) - if (ret === false) { - return false - } - } - }, - - getServName (uid) { - let Serv = ProfileReq.getServ(uid) - return Serv.name - } -} -export default Profile diff --git a/components/index.js b/components/index.js index d08f02b3..84f165e6 100644 --- a/components/index.js +++ b/components/index.js @@ -3,7 +3,6 @@ import Format from './Format.js' import Common from './Common.js' import Cfg from './Cfg.js' import Version from './Version.js' -import Profile from './Profile.js' import App from './App.js' -export { Data, Cfg, Format, Common, Version, Profile, App } +export { Data, Cfg, Format, Common, Version, App } diff --git a/components/profile-data/input.js b/components/profile-data/input.js deleted file mode 100644 index e69de29b..00000000 diff --git a/components/profile-data/miao-meta.js b/components/profile-data/miao-meta.js deleted file mode 100644 index 745f1722..00000000 --- a/components/profile-data/miao-meta.js +++ /dev/null @@ -1,48 +0,0 @@ -import { Data } from '../index.js' -import lodash from 'lodash' - -const _path = process.cwd() - -export const artiIdx = { - 生之花: 1, - 死之羽: 2, - 时之沙: 3, - 空之杯: 4, - 理之冠: 5 -} - -let relis = Data.readJSON('resources/meta/artifact/data.json') -let setMap = {} - -lodash.forEach(relis, (ds) => { - if (ds.sets) { - lodash.forEach(ds.sets, (tmp) => { - if (tmp.name) { - setMap[tmp.name] = ds.name - } - }) - } -}) -export const artiSetMap = setMap - -export const attrMap = { - HP: '小生命', - HP_PERCENT: '大生命', - ATTACK: '小攻击', - ATTACK_PERCENT: '大攻击', - DEFENSE: '小防御', - DEFENSE_PERCENT: '大防御', - FIRE_ADD_HURT: '火元素伤害加成', - ICE_ADD_HURT: '冰元素伤害加成', - ROCK_ADD_HURT: '岩元素伤害加成', - ELEC_ADD_HURT: '雷元素伤害加成', - WIND_ADD_HURT: '风元素伤害加成', - WATER_ADD_HURT: '水元素伤害加成', - PHYSICAL_ADD_HURT: '物理伤害加成', - GRASS_ADD_HURT: '草元素伤害加成', - HEAL_ADD: '治疗加成', - ELEMENT_MASTERY: '元素精通', - CRITICAL: '暴击率', - CRITICAL_HURT: '暴击伤害', - CHARGE_EFFICIENCY: '充能效率' -} diff --git a/components/profile-data/original.js b/components/profile-data/original.js deleted file mode 100644 index b5612471..00000000 --- a/components/profile-data/original.js +++ /dev/null @@ -1,203 +0,0 @@ -import lodash from 'lodash' -import Character from '../models/Character.js' - -const artifactMap = { - 生命值: { - title: '小生命' - }, - 生命值_百分比: { - title: '大生命', - pct: true - }, - 暴击率: { - title: '暴击率', - pct: true - }, - 暴击伤害: { - title: '暴击伤害', - pct: true - }, - 防御力: { - title: '小防御' - }, - 防御力_百分比: { - title: '大防御', - pct: true - }, - 攻击力: { - title: '小攻击' - }, - 攻击力_百分比: { - title: '大攻击', - pct: true - }, - 元素精通: { - title: '元素精通' - }, - 元素充能效率: { - title: '充能效率', - pct: true - }, - 治疗加成: { - title: '治疗加成', - pct: true - } -} - -let posIdx = { - 生之花: { - idx: 1 - }, - 死之羽: { - idx: 2 - }, - 时之沙: { - idx: 3 - }, - 空之杯: { - idx: 4 - }, - 理之冠: { - idx: 5 - } -} - -let Data = { - getData (uid, data) { - let ret = { - uid, - chars: {} - } - - lodash.forEach({ - name: '角色名称', - avatar: '头像ID', - level: '冒险等阶' - }, (title, key) => { - ret[key] = data[title] || '' - }) - - lodash.forEach(data.items, (ds) => { - let char = Data.getAvatar(ds) - ret.chars[char.id] = char - }) - - return ret - }, - getAvatar (data) { - let char = Character.get(data['英雄Id']) - return { - id: data['英雄Id'], - name: char ? char.name : '', - level: data['等级'], - attr: Data.getAttr(data), - // weapon: Data.getWeapon(data), - artis: Data.getArtifact(data) - // cons: data["命之座数量"] * 1 || 0, - // talent: Data.getTalent(data) - } - }, - getAttr (data) { - let ret = {} - let attrKey = { - atk: '攻击力_总', - atkBase: '属性攻击力', - def: '防御力_总', - defBase: '属性防御力', - hp: '生命值上限_总', - hpBase: '属性生命值上限', - mastery: '属性元素精通', - cRate: { - title: '属性暴击率', - pct: true - }, - cDmg: { - title: '属性暴击伤害', - pct: true - }, - hInc: { - title: '属性治疗加成', - pct: true - }, - recharge: { - title: '属性元素充能效率', - pct: true - } - } - lodash.forEach(attrKey, (cfg, key) => { - if (typeof (cfg) === 'string') { - cfg = { title: cfg } - } - let val = data[cfg.title] || '' - if (cfg.pct) { - val = (val * 100).toFixed(2) - } - ret[key] = val - }) - let maxDmg = 0 - lodash.forEach('火水草雷风冰岩'.split(''), (key) => { - maxDmg = Math.max(data[`属性${key}元素伤害加成`] * 1, maxDmg) - }) - ret.dmgBonus = (maxDmg * 100).toFixed(2) - ret.phyBonus = (data['属性物理伤害加成'] * 100).toFixed(2) - - return ret - }, - getWeapon (data) { - return { - name: data['武器名称'], - level: data['武器等级'], - refine: data['武器精炼'] - } - }, - getArtifact (data) { - let ret = {} - let get = function (idx, key) { - let v = data[`圣遗物${idx}${key}`] - let ret = /^([^\d]*)([\d\.\-]*)$/.exec(v) - if (ret && ret[1]) { - let title = ret[1]; let val = ret[2] - if (artifactMap[title]) { - if (artifactMap[title].pct) { - val = (val * 100).toFixed(2) - } - title = artifactMap[title].title - } - return [title, val] - } - return [] - } - - for (let idx = 1; idx <= 5; idx++) { - ret[`arti${idx}`] = { - name: data[`圣遗物${idx}名称`], - type: data[`圣遗物${idx}类型`], - main: get(idx, '主词条'), - attrs: [ - get(idx, '副词条1'), - get(idx, '副词条2'), - get(idx, '副词条3'), - get(idx, '副词条4') - ] - } - } - return ret - }, - getTalent (data) { - let ret = {} - lodash.forEach({ - a: 1, - e: 2, - q: 3 - }, (idx, key) => { - let val = data[`天赋主动名称${idx}`] - let regRet = /等级(\d*)$/.exec(val) - if (regRet && regRet[1]) { - ret[key] = regRet[1] * 1 || 1 - } else { - ret[key] = 1 - } - }) - return ret - } -} diff --git a/models/Avatar.js b/models/Avatar.js index 2c31fabb..9e4e245b 100644 --- a/models/Avatar.js +++ b/models/Avatar.js @@ -4,8 +4,7 @@ * */ import Base from './Base.js' import lodash from 'lodash' -import { Profile } from '../components/index.js' -import { Artifact, Character, Weapon, ArtifactSet } from './index.js' +import { Artifact, Character, Weapon, ArtifactSet, Player } from './index.js' import moment from 'moment' const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName,elem'.split(',') @@ -34,7 +33,7 @@ export default class Avatar extends Base { profile = pd } else if (/\d{9}/.test(pd)) { uid = pd - profile = Profile.get(pd, char.id, true) + profile = Player.getAvatar(pd, char.id, true) } } if (profile && profile.isProfile && profile.hasData) { diff --git a/models/AvatarArtis.js b/models/AvatarArtis.js new file mode 100644 index 00000000..a335cdd2 --- /dev/null +++ b/models/AvatarArtis.js @@ -0,0 +1,257 @@ +/** + * 面板圣遗物 + */ +import lodash from 'lodash' +import Base from './Base.js' +import { Artifact, ArtifactSet } from './index.js' +import { Format, Data } from '../components/index.js' +import ArtisMark from './profile-lib/ArtisMark.js' + +export default class AvatarArtis extends Base { + constructor (charid = 0) { + super() + this.charid = charid + this.artis = {} + } + + static isProfileArtis (ds) { + let ret = true + for (let idx = 1; idx <= 5; idx++) { + if (ds[idx]) { + if (!ds[idx].main || !ds[idx].attrs) { + ret = false + return ret + } + } + } + return ret + } + + setArtisData (ds = {}, dataSource) { + if (!this.hasArtis || AvatarArtis.isProfileArtis(ds) || !AvatarArtis.isProfileArtis(this.artis)) { + for (let idx = 1; idx <= 5; idx++) { + if (ds[idx]) { + this.setArtis(idx, ds[idx] || {}) + } + } + return true + } + return false + } + + setArtis (idx = 1, ds = {}) { + idx = idx.toString().replace('arti', '') + let ret = {} + ret.name = ds.name || ArtifactSet.getArtiNameBySet(ds.set, idx) || '' + ret.set = ds.set || Artifact.getSetNameByArti(ret.name) || '' + ret.level = ds.level || 1 + if (ds.main && ds.attrs) { + ret.main = ArtisMark.formatAttr(ds.main || {}) + ret.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + ret.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + this.artis[idx] = ret + } + + forEach (fn) { + lodash.forEach(this.artis, (ds, idx) => { + if (ds.name) { + fn(ds, idx) + } + }) + } + + _get (key) { + let artis = this.artis + switch (key) { + case 'length': + return lodash.keys(artis).length + } + if (artis[key]) { + return artis[key] + } + } + + toJSON () { + let ret = {} + for (let idx = 1; idx <= 5; idx++) { + let ds = this.artis[idx] + if (ds) { + let tmp = { + name: ds.name || '', + level: ds.level || 1 + } + if (ds.main && ds.attrs) { + tmp.main = ds.main || null + tmp.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + ret[idx] = tmp + } + } + return ret + } + + getDetail () { + let ret = {} + for (let idx = 1; idx <= 5; idx++) { + let ds = this.artis[idx] + if (ds) { + let artis = Artifact.get(ds.name) + let tmp = { + ...artis?.getData('img,name,set'), + level: ds.level || 1 + } + if (ds.main && ds.attrs) { + tmp.main = ds.main || null + tmp.attrs = [] + for (let attrIdx in ds.attrs || []) { + if (ds.attrs[attrIdx]) { + tmp.attrs.push(ArtisMark.formatAttr(ds.attrs[attrIdx])) + } + } + } + ret[idx] = tmp + } + } + return ret + } + + get sets () { + return this.getSetData().sets || {} + } + + get names () { + return this.getSetData().names || [] + } + + get hasArtis () { + return !lodash.isEmpty(this.artis) + } + + mainAttr (idx = '') { + if (!idx) { + let ret = {} + for (let i = 1; i <= 5; i++) { + ret[i] = this.mainAttr(i) + } + return ret + } + let main = this.artis[idx]?.main + if (!main) { + return '' + } + return main.key || '' + } + + is (check, pos = '') { + if (pos) { + return this.isAttr(check, pos) + } + let sets = this.getSetData()?.abbrs || [] + let ret = false + Data.eachStr(check, (s) => { + if (sets.includes(s)) { + ret = true + return false + } + }) + return ret + } + + isAttr (attr, pos = '3,4,5') { + let mainAttr = this.mainAttr() + let check = true + Data.eachStr(pos.toString(), (p) => { + let attrs = attr.split(',') + if (!attrs.includes(mainAttr[p]) && (p === '4' && !attrs.includes('dmg') && Format.isElem(mainAttr[p]))) { + check = false + return false + } + }) + return check + } + + // 获取圣遗物数据 + getArtisData () { + let ret = {} + this.forEach((ds, idx) => { + let arti = Artifact.get(ds.name) + ret[idx] = { + ...ds, + name: arti.name, + img: arti.img + } + }) + return ret + } + + /** + * 获取圣遗物套装数据 + * @returns {*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}} + * sets: 套装名:2/4 + * names: [套装名] + * imgs: [img] + * abbrs:[别名] + * name: '组合名字', 若为4件套会使用套装完整名 + * sName: '简写名字',若为4件套也会使用简写 + */ + geSetData () { + let setCount = {} + this.forEach((arti, idx) => { + setCount[arti.set] = (setCount[arti.set] || 0) + 1 + }) + let sets = {} + let names = [] + let imgs = [] + let abbrs = [] + let abbrs2 = [] + for (let set in setCount) { + if (setCount[set] >= 2) { + let count = setCount[set] >= 4 ? 4 : 2 + sets[set] = count + let artiSet = ArtifactSet.get(set) + names.push(artiSet.name) + imgs.push(artiSet.img) + abbrs.push(artiSet.abbr + count) + abbrs2.push(artiSet.name + count) + } + } + return { + sets, + names, + imgs, + abbrs: [...abbrs, ...abbrs2], + name: (abbrs.length > 1 || abbrs2[0]?.length > 7) ? abbrs.join('+') : abbrs2[0], + sName: abbrs.join('+') + } + } + + static _eachArtisSet (sets, fn) { + lodash.forEach(sets || [], (v, k) => { + let artisSet = ArtifactSet.get(k) + if (artisSet) { + if (v >= 4) { + fn(artisSet, 2) + } + fn(artisSet, v) + } + }) + } + + eachArtisSet (fn) { + AvatarArtis._eachArtisSet(this.sets, fn) + } + + static getArtisKeyTitle () { + return ArtisMark.getKeyTitleMap() + } +} diff --git a/models/AvatarData.js b/models/AvatarData.js new file mode 100644 index 00000000..994c4ba3 --- /dev/null +++ b/models/AvatarData.js @@ -0,0 +1,244 @@ +import lodash from 'lodash' +import Base from './Base.js' +import moment from 'moment' +import { Character, AvatarArtis, ProfileData, Weapon } from './index.js' +import { Data } from '../components/index.js' +import AttrCalc from './profile-lib/AttrCalc.js' + +const charKey = 'name,abbr,sName,star,imgs,face,side,gacha,weaponTypeName'.split(',') + +export default class AvatarData extends Base { + constructor (ds = {}, dataSource) { + super() + let char = Character.get({ id: ds.id, elem: ds.elem }) + if (!char) { + return false + } + this.id = char.id + this.char = char + this.artis = new AvatarArtis(this.id) + this.setAvatar(ds, dataSource) + } + + static create (ds, dataSource) { + let avatar = new AvatarData(ds) + if (!avatar) { + return false + } + return avatar + } + + _get (key) { + if (charKey.includes(key)) { + return this.char[key] + } + } + + setAvatar (ds, source = '') { + this._now = new Date() * 1 + this.setBasic(ds, source) + ds.weapon && this.setWeapon(ds.weapon) + ds.talent && this.setTalent(ds.talent, source) + ds.artis && this.setArtis(ds) + delete this._now + } + + /** + * 设置角色基础数据 + * @param ds + * @param source + */ + setBasic (ds = {}, source = '') { + const now = this._now || (new Date()) * 1 + this.level = ds.lv || ds.level || this.level || 1 + this.cons = ds.cons || this.cons || 0 + this.fetter = ds.fetter || this.fetter || 0 + this._costume = ds.costume || this._costume || 0 + this.elem = ds.elem || this.elem || this.char.elem || '' + this.promote = lodash.isUndefined(ds.promote) ? (this.promote || AttrCalc.calcPromote(this.level)) : (ds.promote || 0) + + this._source = ds._source || ds.dataSource || this._source || '' + this._time = ds._time || this._time || now + this._update = ds._update || this._update || ds._time || now + this._talent = ds._talent || this._talent || ds._time || now + // 存在数据源时更新时间 + if (source) { + this._update = now + if (source !== 'mys') { + this._source = source + this._time = now + } else { + this._source = this._source || source + this._time = this._source !== 'mys' ? (this._time || now) : now + } + } + } + + setWeapon (ds = {}) { + let w = Weapon.get(ds.name) || {} + this.weapon = { + name: ds.name, + level: ds.level || ds.lv || 1, + promote: lodash.isUndefined(ds.promote) ? AttrCalc.calcPromote(ds.level || ds.lv || 1) : (ds.promote || 0), + affix: ds.affix, + ...w?.getData('star,abbr,type,img') + } + if (this.weapon.level < 20) { + this.weapon.promote = 0 + } + } + + setTalent (ds = {}, source = '', mode = 'original') { + const now = this._now || (new Date()) * 1 + let ret = this.char.getAvatarTalent(ds, this.cons, mode) + this.talent = ret || this.talent + // 设置天赋更新时间 + this._talent = ds._talent || this._talent || ds._time || now + if (source && ret) { + this._talent = now + } + } + + /** + * 当前数据是否需要更新天赋 + * @returns {boolean} + */ + needRefreshTalent () { + // 不存在天赋数据 + if (!this.hasTalent) { + return true + } + // 超过2个小时的天赋数据进行请求 + return (new Date() * 1) - this._talent > 3600 * 2 * 1000 + } + + async refreshTalent (mys) { + if (mys && mys.isSelfCookie) { + let char = this.char + if (!char) { + return false + } + let id = char.id + let talent = {} + let talentRes = await mys.getDetail(id) + // { data: null, message: '请先登录', retcode: -100, api: 'detail' } + if (talentRes && talentRes.skill_list) { + let talentList = lodash.orderBy(talentRes.skill_list, ['id'], ['asc']) + for (let val of talentList) { + let { max_level: maxLv, level_current: lv } = val + if (val.name.includes('普通攻击')) { + talent.a = lv + continue + } + if (maxLv >= 10 && !talent.e) { + talent.e = lv + continue + } + if (maxLv >= 10 && !talent.q) { + talent.q = lv + } + } + } + let ret = char.getAvatarTalent(talent, this.cons, 'original') + if (ret) { + this.setTalent(ret, 'mys') + } + return true + } + return false + } + + setArtis (ds, source) { + this.artis.setArtisData(ds.artis, source) + } + + get hasTalent () { + return this.talent && !lodash.isEmpty(this.talent) && !!this._talent + } + + get name () { + return this.char?.name || '' + } + + /** + * + */ + get isProfile () { + // 检查数据源 + if (!this._source || !['enka', 'change', 'miao'].includes(this._source)) { + return false + } + // 检查属性 + if (!this.weapon || !this.talent || !this.artis) { + return false + } + // 检查旅行者 + if (['空', '荧'].includes(this.name)) { + return !!this.elem + } + return true + } + + getProfile () { + if (!this.isProfile) { + return false + } + return ProfileData.create(this) + } + + // 判断当前profileData是否具备有效圣遗物信息 + hasArtis () { + return this.hasData && this.artis.length > 0 + } + + get costume () { + let costume = this._costume + if (lodash.isArray(costume)) { + costume = costume[0] + } + return costume + } + + get originalTalent () { + return lodash.mapValues(this.talent, (ds) => ds.original) + } + + // toJSON 供保存使用 + toJSON () { + return { + ...this.getData('name,id,elem,level,promote,fetter,costume,cons,talent:originalTalent'), + weapon: Data.getData(this.weapon, 'name,level,promote,affix'), + ...this.getData('artis,_source,_time,_update,_talent') + } + } + + getDetail (keys = '') { + return this.getData(keys || 'id,name,level,star,cons,fetter,elem,face,side,gacha,abbr,weapon,talent,artisSet') || {} + } + + get updateTime () { + let time = this._time + if (!time) { + return '' + } + if (lodash.isString(time)) { + return moment(time).format('MM-DD HH:mm') + } + if (lodash.isNumber(time)) { + return moment(new Date(time)).format('MM-DD HH:mm') + } + return '' + } + + /** + * 获取圣遗物套装属性 + * @returns {boolean|*|{imgs: *[], names: *[], sets: {}, abbrs: *[], sName: string, name: (string|*)}|{}} + */ + get artisSet () { + return this.artis.geSetData() + } + + getArtisDetail () { + return this.artis.getDetail() + } +} diff --git a/models/AvatarList.js b/models/AvatarList.js index 130a07b0..04c710a0 100644 --- a/models/AvatarList.js +++ b/models/AvatarList.js @@ -6,8 +6,8 @@ * */ import Base from './Base.js' import lodash from 'lodash' -import { Data, Common, Profile } from '../components/index.js' -import { Avatar, MysApi } from './index.js' +import { Data, Common } from '../components/index.js' +import { Avatar, MysApi, Player } from './index.js' export default class AvatarList extends Base { constructor (uid, datas = [], withProfile = false) { @@ -18,8 +18,9 @@ export default class AvatarList extends Base { this.uid = uid let avatars = {} let profiles = {} + let player = Player.create(uid) if (withProfile) { - profiles = Profile.getAll(uid) + // TODO } lodash.forEach(datas, (ds) => { let avatar = new Avatar(ds, profiles[ds.id] || false) diff --git a/models/Player.js b/models/Player.js new file mode 100644 index 00000000..8189423a --- /dev/null +++ b/models/Player.js @@ -0,0 +1,236 @@ +/** + * 用户数据文件 + */ +import Base from './Base.js' +import { Data } from '../components/index.js' +import fs from 'fs' +import { ProfileReq, AvatarData } from './index.js' +import Profile from './player-lib/profile.js' +import lodash from 'lodash' + +import MysAvatar from './player-lib/MysAvatar.js' + +const _path = process.cwd() +const userPath = `${_path}/data/UserData/` +if (!fs.existsSync(userPath)) { + fs.mkdirSync(userPath) +} + +export default class Player extends Base { + constructor (uid) { + super() + if (!uid) { + return false + } + let cacheObj = this._getCache(`player:${uid}`) + if (cacheObj) { + return cacheObj + } + this.uid = uid + this.reload() + return this._cache() + } + + static create (e) { + if (e?._mys?.uid) { + // 传入为e + let player = new Player(e?._mys?.uid) + player.e = e + return player + } else { + return new Player(e) + } + } + + /** + * 重新加载json文件 + */ + reload () { + let data + data = Data.readJSON(`/data/UserData/${this.uid}.json`, 'root') + this.setBasicData(data) + if (data.chars) { + this.setAvatars(data.chars) + this._chars = data.chars + } + this.setAvatars(data.avatars || []) + } + + /** + * 保存json文件 + */ + save () { + let ret = Data.getData(this, 'uid,name,level,word,face,card,sign,_mys,_profile') + ret.avatars = {} + lodash.forEach(this._avatars, (ds) => { + ret.avatars[ds.id] = ds.toJSON() + }) + if (this._chars) { + ret.chars = this._chars + } + Data.writeJSON(`/data/UserData/${this.uid}.json`, ret, '', 'root') + } + + /** + * 设置玩家基础数据 + * @param ds + */ + setBasicData (ds) { + this.name = ds.name || this.name || '' + this.level = ds.level || this.level || 1 + this.word = ds.word || this.word || 1 + this.face = ds.face || this.face || '' + this.card = ds.card || this.card || '' + this.sign = ds.sign || this.sign || '' + this._avatars = this._avatars || {} + this._profile = ds._profile || this._profile + this._mys = ds._mys || this._mys + } + + /** + * 设置角色列表 + * @param ds + */ + setAvatars (ds) { + lodash.forEach(ds, (avatar) => { + this.setAvatar(avatar) + }) + } + + /** + * 设置角色 + * @param ds + * @param dataSource + */ + setAvatar (ds, source) { + let avatar = this.getAvatar(ds.id) + avatar.setAvatar(ds, source) + } + + /** + * 获取角色 + * @param id + * @returns {*} + */ + getAvatar (id) { + if (!this._avatars[id]) { + this._avatars[id] = AvatarData.create({ id }) + } + return this._avatars[id] + } + + /** + * 循环角色 + * @param fn + * @returns {Promise} + */ + async forEachAvatarAsync (fn) { + for (let id in this._avatars) { + let ret = await fn(this._avatars[id], id) + if (ret === false) { + return false + } + } + } + + forEachAvatar (fn) { + for (let id in this._avatars) { + let ret = fn(this._avatars[id], id) + if (ret === false) { + return false + } + } + } + + getAvatarData (ids = '') { + let ret = {} + if (!ids) { + this.forEachAvatar((avatar) => { + ret[avatar.id] = avatar.getDetail() + }) + } else { + lodash.forEach(ids, (id) => { + ret[id] = this.getAvatar(id) + }) + } + return ret + } + + /** + * 获取当前用户指定charid面板数据 + * @param id + * @returns {*} + */ + getProfile (id) { + let avatar = this.getAvatar(id) + return avatar.getProfile() + } + + /** + * 获取当前用户所有面板数据 + * @returns {{}} + */ + getProfiles () { + let ret = {} + lodash.forEach(this._avatars, (avatar) => { + let profile = avatar.getProfile() + if (profile) { + ret[profile.id] = profile + } + }) + return ret + } + + /** + * 更新面板 + * @param e + * @returns {Promise} + */ + async refreshProfile (e, force = true) { + this._update = [] + let { uid } = this + if (uid.toString().length !== 9) { + return false + } + let req = new ProfileReq({ e, uid }) + try { + await req.request(this) + this._profile = new Date() * 1 + this.save() + return this._update.length + } catch (err) { + console.log(err) + e.reply('请求失败') + return false + } + } + + // 更新米游社数据 + async refreshMys (force = false) { + return MysAvatar.refreshMys(this, force) + } + + // 通过已有的Mys CharData更新 + setMysCharData (charData) { + MysAvatar.setMysCharData(this, charData) + } + + // 使用MysApi刷新指定角色的天赋信息 + async refreshTalent (ids = '', force = false) { + return await MysAvatar.refreshTalent(this, ids, force) + } + + /** + * 获取面板更新服务名 + * @param uid + * @returns {*} + */ + static getProfileServName (uid) { + let Serv = ProfileReq.getServ(uid) + return Serv.name + } + + static getAvatar (uid, charId, onlyHasData = false) { + return Profile.get(uid, charId, onlyHasData) + } +} diff --git a/models/Profile.js b/models/Profile.js deleted file mode 100644 index 26efde9d..00000000 --- a/models/Profile.js +++ /dev/null @@ -1,30 +0,0 @@ -import Base from './Base.js' - -export default class Profile extends Base { - constructor (uid) { - super() - if (!uid) { - return false - } - let cacheObj = this._getCache(`profile:${uid}`) - if (cacheObj) { - return cacheObj - } - this.uid = uid - return this._cache() - } - - getProfileData () { - - } - - static create (uid) { - let profile = new Profile(uid) - return profile - } - - static get (uid, id) { - let profile = Profile.create(uid) - return profile.getProfileData(id) - } -} diff --git a/models/ProfileData.js b/models/ProfileData.js index f086f849..1ddb0152 100644 --- a/models/ProfileData.js +++ b/models/ProfileData.js @@ -6,7 +6,7 @@ import { Character, ProfileArtis, ProfileDmg } from './index.js' import AttrCalc from './profile-lib/AttrCalc.js' export default class ProfileData extends Base { - constructor (ds = {}, uid, attrCalc = true) { + constructor (ds = {}) { super() let char = Character.get({ id: ds.id, elem: ds.elem }) if (!char) { @@ -14,20 +14,16 @@ export default class ProfileData extends Base { } this.id = char.id this.char = char - this.uid = uid || '' this.setBasic(ds) - ds.attr && this.setAttr(ds.attr) ds.weapon && this.setWeapon(ds.weapon) ds.talent && this.setTalent(ds.talent) this.artis = new ProfileArtis(this.id, this.elem) ds.artis && this.setArtis(ds.artis) - if (attrCalc && this.hasData) { - this.calcAttr() - } + this.calcAttr() } - static create (ds, uid) { - let profile = new ProfileData(ds, uid) + static create (ds) { + let profile = new ProfileData(ds) if (!profile) { return false } @@ -50,16 +46,6 @@ export default class ProfileData extends Base { this._time = ds._time || ds.updateTime || new Date() * 1 } - setAttr (ds) { - this.attr = lodash.extend(Data.getData(ds, 'atk,atkBase,def,defBase,hp,hpBase,mastery,recharge'), { - heal: ds.heal || ds.hInc || 0, - cpct: ds.cpct || ds.cRate, - cdmg: ds.cdmg || ds.cDmg, - dmg: ds.dmg || ds.dmgBonus || 0, - phy: ds.phy || ds.phyBonus || 0 - }) - } - setWeapon (ds = {}) { this.weapon = { name: ds.name, @@ -75,7 +61,7 @@ export default class ProfileData extends Base { } setArtis (ds = false) { - this.artis.setProfile(this, ds) + this.artis.setProfile(this, ds.artis || ds) } setTalent (ds = {}, mode = 'original') { diff --git a/models/ProfileReq.js b/models/ProfileReq.js index 97f4e32e..07f2eb42 100644 --- a/models/ProfileReq.js +++ b/models/ProfileReq.js @@ -51,16 +51,16 @@ export default class ProfileReq extends Base { this.e.reply(msg) } - async request () { + async request (player) { let Serv = ProfileReq.getServ(this.uid) let reqParam = await Serv.getReqParam(this.uid) let cdTime = await this.inCd() if (cdTime) { - return this.err(`请求过快,请${cdTime}秒后重试..`) + // return this.err(`请求过快,请${cdTime}秒后重试..`) } await this.setCd(20) - this.msg(`开始获取uid:${this.uid}的数据,可能会需要一定时间~`) + // this.msg(`开始获取uid:${this.uid}的数据,可能会需要一定时间~`) await sleep(100) // 发起请求 let data = {} @@ -92,16 +92,12 @@ export default class ProfileReq extends Base { if (data === false) { return false } - let userData = Serv.getUserData(data) - let profiles = Serv.getProfileData(data) + Serv.updatePlayer(player, data) cdTime = Serv.getCdTime(data) if (cdTime) { await this.setCd(cdTime) } - return lodash.extend({ - uid: this.uid, - chars: profiles - }, userData) + return player } } diff --git a/models/ProfileServ.js b/models/ProfileServ.js index 18631c9a..7c3aff2c 100644 --- a/models/ProfileServ.js +++ b/models/ProfileServ.js @@ -75,12 +75,8 @@ export default class ProfileServ extends Base { return Math.max(cdTime, this.execFn('cdTime', [data], 60)) } - getUserData (data) { - return this.execFn('userData', [data], {}) - } - - getProfileData (data) { - return this.execFn('profileData', [data], {}) + updatePlayer (player, data) { + return this.execFn('updatePlayer', [player, data], {}) } } diff --git a/models/index.js b/models/index.js index 7da128a4..f76ec989 100644 --- a/models/index.js +++ b/models/index.js @@ -3,8 +3,11 @@ import Character from './Character.js' import Artifact from './Artifact.js' import ArtifactSet from './ArtifactSet.js' import Avatar from './Avatar.js' +import AvatarData from './AvatarData.js' +import AvatarArtis from './AvatarArtis.js' import AvatarList from './AvatarList.js' import Abyss from './Abyss.js' +import Player from './Player.js' import ProfileServ from './ProfileServ.js' import ProfileReq from './ProfileReq.js' import ProfileData from './ProfileData.js' @@ -24,7 +27,9 @@ export { Artifact, ArtifactSet, Avatar, + AvatarData, AvatarList, + AvatarArtis, ProfileServ, ProfileReq, ProfileData, @@ -35,5 +40,6 @@ export { Material, Weapon, User, - MysApi + MysApi, + Player } diff --git a/models/player-lib/MysAvatar.js b/models/player-lib/MysAvatar.js new file mode 100644 index 00000000..76d9bb2a --- /dev/null +++ b/models/player-lib/MysAvatar.js @@ -0,0 +1,123 @@ +import lodash from 'lodash' +import { Common, Data } from '../../components/index.js' + +const MysAvatar = { + /** + * 更新米游社角色信息 + * @param player + * @param mys + * @param force + * @returns {Promise} + */ + async refreshMys (player, force = false) { + let mys = player?.e?._mys + if (!mys) { + return false + } + // 不必要更新 + if ((new Date() * 1 - player._mys < 10 * 60 * 1000) && !force) { + return false + } + let charData = await mys.getCharacter() + if (!charData || !charData.avatars) { + return false + } + MysAvatar.setMysCharData(player, charData) + }, + + /** + * 根据已有Mys CharData更新player + * @param player + * @param charData + */ + setMysCharData (player, charData) { + let role = charData.role + player.setBasicData({ + level: role.level, + name: role.nickname + }) + lodash.forEach(charData.avatars, (ds) => { + let avatar = Data.getData(ds, 'id,level,cons:actived_constellation_num,fetter') + avatar.elem = ds.element.toLowerCase() + // 处理实装数据 + let costume = (ds?.costumes || [])[0] + if (costume && costume.id) { + avatar.costume = costume.id + } + avatar.weapon = Data.getData(ds.weapon, 'name,star:rarity,level,promote:promote_level,affix:affix_level') + // 处理圣遗物数据 + let artis = {} + lodash.forEach(ds.reliquaries, (re) => { + const posIdx = { 生之花: 1, 死之羽: 2, 时之沙: 3, 空之杯: 4, 理之冠: 5 } + if (re && re.name && posIdx[re.pos_name]) { + artis[posIdx[re.pos_name]] = { + name: re.name, + level: re.level + } + } + }) + avatar.artis = artis + player.setAvatar(avatar, 'mys') + }) + player._mys = new Date() * 1 + player.save() + }, + + /** + * 获取当前角色需要更新天赋的角色ID + * @param player + * @param ids 角色列表,若传入则查询指定角色列表,不传入查询全部 + * @returns {*[]} + */ + getNeedRefreshIds (player, ids) { + let ret = [] + if (!ids) { + ids = lodash.keys(player._avatars) + } else if (!lodash.isArray(ids)) { + ids = [ids] + } + lodash.forEach(ids, (id) => { + let avatar = player.getAvatar(id) + if (avatar.needRefreshTalent()) { + ret.push(avatar.id) + } + }) + return ret + }, + + /** + * 使用MysApi刷新指定角色的天赋信息 + * @param player + * @param ids + * @param force + * @returns {Promise} + */ + async refreshTalent (player, ids, force) { + let e = player?.e + let mys = e?._mys + if (!e || !mys) { + return false + } + let needReqIds = MysAvatar.getNeedRefreshIds(player, ids) + if (needReqIds.length > 0) { + if (needReqIds.length > 8) { + e && e.reply('正在获取角色信息,请稍候...') + } + let num = 10 + let ms = 100 + let skillRet = [] + let avatarArr = lodash.chunk(needReqIds, num) + for (let val of avatarArr) { + for (let id of val) { + let avatar = player.getAvatar(id) + skillRet.push(await avatar.refreshTalent(mys)) + } + skillRet = await Promise.all(skillRet) + skillRet = skillRet.filter(item => item.id) + await Common.sleep(ms) + } + } + player.save() + } +} +export default MysAvatar diff --git a/components/profile-data/enka-data.js b/models/player-lib/enka-data.js similarity index 98% rename from components/profile-data/enka-data.js rename to models/player-lib/enka-data.js index 2f9be073..6944ee75 100644 --- a/components/profile-data/enka-data.js +++ b/models/player-lib/enka-data.js @@ -1,6 +1,6 @@ import lodash from 'lodash' import enkaMeta from './enka-meta.js' -import { Character, ArtifactSet, ProfileData } from '../../models/index.js' +import { Character, ArtifactSet, ProfileData } from '../index.js' const artiIdx = { EQUIP_BRACER: 1, diff --git a/components/profile-data/enka-meta.js b/models/player-lib/enka-meta.js similarity index 100% rename from components/profile-data/enka-meta.js rename to models/player-lib/enka-meta.js diff --git a/components/profile-data/enka.js b/models/player-lib/enka.js similarity index 94% rename from components/profile-data/enka.js rename to models/player-lib/enka.js index bab155b0..adda6986 100644 --- a/components/profile-data/enka.js +++ b/models/player-lib/enka.js @@ -1,6 +1,6 @@ import lodash from 'lodash' -import { Data } from '../index.js' -import { ProfileServ } from '../../models/index.js' +import { Data } from '../../components/index.js' +import { ProfileServ } from '../index.js' import EnkaData from './enka-data.js' let HttpsProxyAgent = '' diff --git a/components/profile-data/miao-data.js b/models/player-lib/miao-data.js similarity index 58% rename from components/profile-data/miao-data.js rename to models/player-lib/miao-data.js index 4784a9d7..282c49b8 100644 --- a/components/profile-data/miao-data.js +++ b/models/player-lib/miao-data.js @@ -1,6 +1,28 @@ -import { Character, ProfileData } from '../../models/index.js' +import { Character, Artifact } from '../index.js' import lodash from 'lodash' -import { artiIdx, artiSetMap, attrMap } from './miao-meta.js' + +const attrMap = { + HP: 'hpPlus', + HP_PERCENT: 'hp', + ATTACK: 'atkPlus', + ATTACK_PERCENT: 'atk', + DEFENSE: 'defPlus', + DEFENSE_PERCENT: 'def', + FIRE_ADD_HURT: '', + ICE_ADD_HURT: 'cryo', + ROCK_ADD_HURT: 'geo', + ELEC_ADD_HURT: 'electro', + WIND_ADD_HURT: 'anemo', + WATER_ADD_HURT: 'hydro', + PHYSICAL_ADD_HURT: 'phy', + GRASS_ADD_HURT: 'dendro', + HEAL_ADD: 'heal', + ELEMENT_MASTERY: 'mastery', + CRITICAL: 'cpct', + CRITICAL_HURT: 'cdmg', + CHARGE_EFFICIENCY: 'recharge' +} + let MiaoData = { key: 'miao', @@ -27,70 +49,21 @@ let MiaoData = { level: ds.level } }, - getProfile (ds) { + setAvatar (player, ds) { let char = Character.get(ds.id) - let profile = new ProfileData({ id: char.id }) - profile.setBasic({ + let avatar = player.getAvatar(ds.id) + let talentRet = MiaoData.getTalent(char.id, ds.skill) + avatar.setAvatar({ level: ds.level, cons: ds.constellationNum || 0, fetter: ds.fetterLevel, costume: char.checkCostume(ds.costumeID) ? ds.costumeID : 0, - dataSource: 'miao' - }) - profile.setAttr(MiaoData.getAttr(ds.combatValue)) - profile.setWeapon(MiaoData.getWeapon(ds.weapon)) - profile.setArtis(MiaoData.getArtifact(ds.reliquary)) - let talentRet = MiaoData.getTalent(char.id, ds.skill) - profile.setTalent(talentRet.talent, 'level') - if (talentRet.elem) { - profile.elem = talentRet.elem - } - return profile - }, - getAttr (data) { - let ret = {} - lodash.forEach({ - atk: 'attack', - atkBase: 'baseATK', - hp: 'health', - hpBase: 'baseHP', - def: 'defense', - defBase: 'baseDEF', - mastery: 'elementMastery', - cpct: { - src: 'critRate', - pct: true - }, - cdmg: { - src: 'critDamage', - pct: true - }, - heal: { - src: 'heal', - pct: true - }, - recharge: { - src: 'recharge', - pct: true - } - }, (cfg, key) => { - if (!lodash.isObject(cfg)) { - cfg = { src: cfg } - } - let val = data[cfg.src] || 0 - if (cfg.pct) { - val = val * 100 - } - ret[key] = val - }) - let maxDmg = 0 - let hurt = data.addHurt || {} - lodash.forEach('fire,elec,water,grass,wind,rock,ice'.split(','), (key) => { - maxDmg = Math.max(hurt[key] * 100, maxDmg) - }) - ret.dmg = maxDmg - ret.phy = hurt.physical * 100 - return ret + elem: talentRet.elem, + weapon: MiaoData.getWeapon(ds.weapon), + talent: talentRet.talent, + artis: MiaoData.getArtifact(ds.reliquary) + }, 'miao') + return avatar }, getWeapon (weapon) { return { @@ -116,18 +89,23 @@ let MiaoData = { if (value && value < 1) { value = value * 100 } - return [attrMap[name], value] + return { key: attrMap[name], value } } - lodash.forEach(data, (ds) => { let sub = ds.appendAffix || [] - let idx = artiIdx[ds.type] + let idx = { + 生之花: 1, + 死之羽: 2, + 时之沙: 3, + 空之杯: 4, + 理之冠: 5 + }[ds.type] if (!idx) { return } - ret[`arti${idx}`] = { + ret[idx] = { name: ds.name, - set: artiSetMap[ds.name] || '', + set: Artifact.getSetNameByArti(ds.name) || '', level: ds.level, main: get(ds.mainAffix), attrs: [ @@ -162,7 +140,6 @@ let MiaoData = { } } }) - return { talent: ret, elem diff --git a/components/profile-data/miao.js b/models/player-lib/miao.js similarity index 66% rename from components/profile-data/miao.js rename to models/player-lib/miao.js index 1160a74b..f60ad8c7 100644 --- a/components/profile-data/miao.js +++ b/models/player-lib/miao.js @@ -1,6 +1,6 @@ import lodash from 'lodash' -import { Data } from '../index.js' -import { ProfileServ } from '../../models/index.js' +import { Data } from '../../components/index.js' +import { ProfileServ } from '../index.js' import MiaoData from './miao-data.js' export default new ProfileServ({ @@ -18,19 +18,14 @@ export default new ProfileServ({ return data }, - userData (data) { - return Data.getData(data, 'name:nickname,avatar:profilePicture.avatarID,level,signature') - }, - - profileData (data) { - let ret = {} + updatePlayer (player, data) { + player.setBasicData(Data.getData(data, 'name:nickname,face:profilePicture.avatarID,card:nameCardID,level,word:worldLevel,sign:signature')) lodash.forEach(data.showAvatarInfoList, (ds) => { - let profile = MiaoData.getProfile(ds) - if (profile && profile.id) { - ret[profile.id] = profile + let ret = MiaoData.setAvatar(player, ds) + if (ret) { + player._update.push(ret.id) } }) - return ret }, // 获取冷却时间 diff --git a/models/profile-lib/AttrCalc.js b/models/profile-lib/AttrCalc.js index 7c3df43f..f831b7a0 100644 --- a/models/profile-lib/AttrCalc.js +++ b/models/profile-lib/AttrCalc.js @@ -103,7 +103,7 @@ class AttrCalc { * 计算武器属性 */ setWeaponAttr () { - let wData = this.profile?.weapon + let wData = this.profile?.weapon || {} let weapon = Weapon.get(wData?.name) let level = wData.level let promote = lodash.isUndefined(wData.promote) ? -1 : wData.promote diff --git a/models/profile-lib/ProfileFile.js b/models/profile-lib/ProfileFile.js deleted file mode 100644 index 1f158009..00000000 --- a/models/profile-lib/ProfileFile.js +++ /dev/null @@ -1,38 +0,0 @@ -import fs from 'node:fs' -import { Data } from '../../components/index.js' -import lodash from 'lodash' - -const _path = process.cwd() -const userPath = `${_path}/data/UserData/` -if (!fs.existsSync(userPath)) { - fs.mkdirSync(userPath) -} - -let ProfileFile = { - getData (uid) { - let data = Data.readJSON('/data/UserData', 'root') - if (data && data.chars) { - return data - } else { - return { - uid, - chars: {} - } - } - }, - saveData (profile) { - let userData = {} - const userFile = `${userPath}/${uid}.json` - if (fs.existsSync(userFile)) { - userData = JSON.parse(fs.readFileSync(userFile, 'utf8')) || {} - } - lodash.assignIn(userData, lodash.pick(data, 'uid,name,lv,avatar'.split(','))) - userData.chars = userData.chars || {} - lodash.forEach(data.chars, (char, charId) => { - userData.chars[charId] = char - }) - fs.writeFileSync(userFile, JSON.stringify(userData), '', ' ') - return data - } -} -export default ProfileFile \ No newline at end of file diff --git a/resources/character/character-card.html b/resources/character/character-card.html index 722ee765..7f2b59d3 100644 --- a/resources/character/character-card.html +++ b/resources/character/character-card.html @@ -78,7 +78,7 @@ {{else}} {{if custom}} diff --git a/tools/profile-calc-test.js b/tools/profile-calc-test.js deleted file mode 100644 index 5e54c08f..00000000 --- a/tools/profile-calc-test.js +++ /dev/null @@ -1,117 +0,0 @@ -import fs from 'fs' -import { Profile } from '../components/index.js' -import AttrCalc from '../models/profile-lib/AttrCalc.js' -import lodash from 'lodash' - -let _path = process.cwd() - -function testCalcAttr (profile) { - if (profile.hasData) { - let attrCalc = AttrCalc.create(profile) - let attr2 = attrCalc.calc() - let char = profile.char - let ret = {} - lodash.forEach(profile.attr, (val, key) => { - let diff = val - (attr2[key] || 0) - if (Math.abs(diff / val) > 0.005 && Math.abs(diff) > 0.99) { - ret[key] = [val, attr2[key]] - } - }) - if (!lodash.isEmpty(ret)) { - let retKeys = lodash.keys(ret) - let retKeyStr = lodash.keys(ret).join(',') - let ret2 = lodash.extend({}, ret) - if (retKeyStr === 'hp') { - let [s, d] = ret.hp - let hpBase = profile.attr?.hpBase - let pct = Math.round((s - d) / hpBase * 100) - if ([6, 12, 18, 30, 25, 31, 37, 43, 55].includes(pct)) { - delete ret.hp - } - } - if ((ret.atkBase) || (retKeys.length === 2 && ret.atkBase && ret.atk)) { - - if ([1, 20, 40, 50, 60, 70, 80, 90].includes(profile.weapon.level)) { - delete ret.atkBase - delete ret.atk - } - } - if (ret.def && ret.defBase && ret.hp && ret.hpBase) { - let [s, d] = ret.defBase - if (s > d && [1, 20, 40, 50, 60, 70, 80, 90].includes(profile.level)) { - delete ret.def - delete ret.defBase - delete ret.hp - delete ret.hpBase - delete ret[char.detail?.attr?.keys[3]] - } - } - if (retKeyStr === 'recharge') { - if (char.isTraveler && char.isElem('风')) { - delete ret.recharge - } - } - if (retKeyStr === 'dmg') { - let [s, d] = ret.dmg - let dmg = Math.round(Math.abs(s - d - 46.6)) - console.log(dmg) - if ([0, 15].includes(dmg) || char.name === '莫娜') { - delete ret.dmg - } - } - let cmd = `#${profile.name}面板${profile.uid}` - if (lodash.isEmpty(ret)) { - console.log(`Calc IGNORE: ${cmd}`) - return true - } else { - console.log(`Calc Diff: ${cmd}`, ret2) - } - return false - } else { - console.log(`Calc OK:${profile.uid}:${profile.id}`) - return true - } - } else { - console.log('!has data') - return true - } -} - -async function test (ignore) { - let files = fs.readdirSync(`${_path}/data/UserData`) - let count = 0 - let total = 0 - for (let file of files) { - if (count > 0) { - break - } - let testRet = /(\d{9}).json/.exec(file) - if (testRet && testRet[1]) { - let uid = testRet[1] - if (ignore.includes(uid * 1)) { - continue - } - Profile.forEach(uid, (profile) => { - if (count > 0) { - return false - } - let cmd = `#${profile.name}面板${profile.uid}` - if (ignore.includes(cmd)) { - return true - } - console.log(profile.id) - let ret = testCalcAttr(profile) - if (ret === false) { - count++ - } - total++ - }) - } - } - console.log(`calc test done total:${total}`) - return true -} - -const ignore = ['#荧面板100000023', '#班尼特面板100009630', '#荧面板100147429', '#八重神子面板100160080', '#纳西妲面板100181800', '#荧面板100211780', - '#九条裟罗面板100248492', '#砂糖面板100270260'] -await test(ignore)