import base from './base.js' import lodash from 'lodash' import fs from 'node:fs' import gsCfg from './gsCfg.js' import moment from 'moment' import GachaLog from './gachaLog.js' export default class LogCount extends base { constructor (e) { super(e) this.model = 'logCount' this.urlKey = `${this.prefix}url:` /** 绑定的uid */ this.uidKey = `Yz:genshin:mys:qq-uid:${this.userId}` this.path = `./data/gachaJson/${this.e.user_id}/` this.pool = [ { type: 301, typeName: '角色' }, { type: 302, typeName: '武器' }, { type: 500, typeName: '集录' }, { type: 200, typeName: '常驻' } ] /** 五星角色 */ this.role5 = ['刻晴', '莫娜', '七七', '迪卢克', '琴', '提纳里', '迪希雅'] /** 五星武器 */ this.weapon5 = ['阿莫斯之弓', '天空之翼', '天空之卷', '天空之脊', '天空之傲', '天空之刃', '四风原典', '和璞鸢', '狼的末路', '风鹰剑'] if (e.isSr) { /** 绑定的uid */ this.uidKey = `Yz:srJson:mys:qq-uid:${this.userId}` this.path = `./data/srJson/${this.e.user_id}/` this.pool = [ { type: 11, typeName: '角色' }, { type: 12, typeName: '光锥' }, { type: 1, typeName: '常驻' }, { type: 2, typeName: '新手' } ] /** 五星角色 */ this.role5 = ['姬子', '杰帕德', '彦卿', '白露', '瓦尔特', '克拉拉', '布洛妮娅'] /** 五星武器 */ this.weapon5 = ['银河铁道之夜', '无可取代的东西', '但战斗还未结束', '以世界之名', '制胜的瞬间', '如泥酣眠', '时节不居'] } } // 读取本地json readJson () { let logJson = [] let ids = [] let file = `${this.path}/${this.uid}/${this.type}.json` if (fs.existsSync(file)) { // 获取本地数据 进行数据合并 logJson = JSON.parse(fs.readFileSync(file, 'utf8')) for (let val of logJson) { if (val.id) { ids.push(val.id) } } } return { list: logJson, ids } } /** #抽卡统计 */ async count () { /** 卡池 */ this.getPool() /** 判断uid */ await this.getUid() if (!this.uid) { await this.e.reply('当前绑定uid暂无抽卡记录') return false } /** 统计计算记录 */ let data = this.analyseHistory() if (!data) return false return { quality: 80, ...this.screenData, ...data } } getPool () { let msg = this.e.msg.replace(/#|抽卡|记录|祈愿|分析|池|原神|星铁|崩坏星穹铁道|铁道|抽卡|统计|池/g, '') this.type = this.e.isSr ? 11 : 301 this.typeName = '角色' switch (msg) { case 'up': case '抽卡': case '角色': case '抽奖': this.type = this.e.isSr ? 11 : 301 this.typeName = '角色' break case '常驻': this.type = this.e.isSr ? 1 : 200 this.typeName = '常驻' break case '集录': this.type = 500 this.typeName = '集录' break case '武器': this.type = this.e.isSr ? 12 : 302 this.typeName = this.e.isSr ? '光锥' : '武器' break case '光锥': this.type = 12 this.typeName = '光锥' break case '新手': this.type = this.e.isSr ? 2 : 100 this.typeName = '新手' break } } async getUid () { if (!fs.existsSync(this.path)) { this.e.reply(`暂无抽卡记录\n${this.e?.isSr ? '*' : '#'}记录帮助,查看配置说明`, false, { at: true }) return false } let logs = fs.readdirSync(this.path) if (lodash.isEmpty(logs)) { this.e.reply(`暂无抽卡记录\n${this.e?.isSr ? '*' : '#'}记录帮助,查看配置说明`, false, { at: true }) return false } if (!this.uid) { this.e.at = false this.uid = this?.e?.isSr ? this.e.user?._games?.sr?.uid : this.e.user?._games?.gs?.uid || await this.e.runtime.getUid(this.e) || await redis.get(this.uidKey) } /** 记录有绑定的uid */ if (this.uid && logs.includes(String(this.uid))) { return this.uid } /** 拿修改时间最后的uid */ let uidArr = [] for (let uid of logs) { let json = `${this.path}${uid}/301.json` if (!fs.existsSync(json)) { continue } let tmp = fs.statSync(json) uidArr.push({ uid, mtimeMs: tmp.mtimeMs }) } if (uidArr.length <= 0) { return false } uidArr = uidArr.sort(function (a, b) { return b.mtimeMs - a.mtimeMs }) this.uid = uidArr[0].uid return uidArr[0].uid } getPoolCfg () { let poolCfg = gsCfg.getdefSet('pool', this.type) poolCfg.forEach(v => { v.start = moment(v.from, 'YYYY-MM-DD HH:mm:ss').format('X') v.end = moment(v.to, 'YYYY-MM-DD HH:mm:ss').format('X') }) return poolCfg } /** 统计计算记录 */ analyseHistory () { let all = this.readJson().list let game = this.e?.game all = all.reverse() let poolCfg = [...this.getPoolCfg()].reverse() let sortName if (this.type == 301) { sortName = gsCfg.getdefSet('role', 'other').sortName } else { sortName = gsCfg.getdefSet('weapon', 'other').sortName } let pool = {} let fiveNum = 0 let fourNum = 0 for (let row of all) { // 判断属于卡池 let time = moment(row.time).format('X') /* eslint-disable no-labels */ b: for (let i in poolCfg) { if (time >= poolCfg[i].start && time <= poolCfg[i].end) { if (!pool[poolCfg[i].start]) { pool[poolCfg[i].start] = { count: 1, list: [], name: poolCfg[i].name, five: poolCfg[i].five, start: moment(poolCfg[i].from, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD'), end: moment(poolCfg[i].to, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD') } } else { pool[poolCfg[i].start].count++ } if (row.rank_type == 5) { if (row.name != '未知') { pool[poolCfg[i].start].list.push({ name: row.name, icon: GachaLog.getIcon(row.name, row.item_type, game), rank_type: row.rank_type, item_type: row.item_type, time, num: fiveNum + 1 }) } fiveNum = 0 fourNum++ } else if (row.rank_type == 4) { pool[poolCfg[i].start].list.push({ name: row.name, icon: GachaLog.getIcon(row.name, row.item_type, game), rank_type: row.rank_type, item_type: row.item_type, time, num: fourNum + 1 }) fourNum = 0 fiveNum++ } else { fiveNum++ fourNum++ } break b } else { delete poolCfg[i] } } } let tmp = [] for (let i in pool) { tmp.push(pool[i]) } pool = tmp.reverse() if (pool.length <= 0) { return false } let line = 0 let res = [] for (let i in pool) { line++ pool[i].role = {} pool[i].five = pool[i].five .map((v) => sortName[v] ?? v) .join('、') for (let val of pool[i].list) { if (!pool[i].role[val.name]) { pool[i].role[val.name] = { name: val.name, icon: GachaLog.getIcon(val.name, val.item_type, game), rank_type: val.rank_type, item_type: val.item_type, count: 1 } } else { pool[i].role[val.name].count++ } } delete pool[i].list // 排序 for (let j in pool[i].role) { let sort = (pool[i].role[j].rank_type - 3) * 1000 + pool[i].role[j].count if (this.role5.includes(pool[i].role[j].name)) { sort-- } if (this.weapon5.includes(pool[i].role[j].name)) { sort-- } if (pool[i].role[j].item_type == '角色' && pool[i].role[j].rank_type == 5) { sort += 1000 } pool[i].role[j].sort = sort } pool[i].roleNum = Object.keys(pool[i].role).length pool[i].role = lodash.orderBy(pool[i].role, ['sort'], ['desc']) res.push(pool[i]) line += Math.ceil(pool[i].roleNum / 6) if (this.e.isGroup && line >= 12) { break } } // if (line - pool.length <= 0) { // return false; // } return { saveId: this.uid, uid: this.uid, pool: res, typeName: this.typeName, isGroup: this.e.isGroup } } }