Merge pull request #293 from Rrrrrrray/master

优化抽卡记录导入及导出
This commit is contained in:
Ca(HCO₃)₂ 2023-10-25 19:34:36 +08:00 committed by GitHub
commit cdf8ac4a02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 106 deletions

View File

@ -8,7 +8,7 @@ import LogCount from '../model/logCount.js'
const _path = process.cwd() + '/plugins/genshin' const _path = process.cwd() + '/plugins/genshin'
export class gcLog extends plugin { export class gcLog extends plugin {
constructor() { constructor () {
super({ super({
name: '抽卡记录', name: '抽卡记录',
dsc: '抽卡记录数据统计', dsc: '抽卡记录数据统计',
@ -20,15 +20,15 @@ export class gcLog extends plugin {
fnc: 'logUrl' fnc: 'logUrl'
}, },
{ {
reg: '^#txt(日志)?(文件)?导入记录$', reg: '^#txt日志文件导入记录$',
fnc: 'logFile' fnc: 'logFile'
}, },
{ {
reg: '^#*(原神|星铁)?(xlsx|excel)(文件)?导入记录$', reg: '^#xlsx文件导入记录$',
fnc: 'logXlsx' fnc: 'logXlsx'
}, },
{ {
reg: '^#*(原神|星铁)?json(文件)?导入记录$', reg: '^#json文件导入记录$',
fnc: 'logJson' fnc: 'logJson'
}, },
{ {
@ -57,8 +57,8 @@ export class gcLog extends plugin {
this.androidUrl = 'https://docs.qq.com/doc/DUWpYaXlvSklmVXlX' this.androidUrl = 'https://docs.qq.com/doc/DUWpYaXlvSklmVXlX'
} }
async init() { async init () {
let file = ['./data/gachaJson', './data/srJson', './temp/html/StarRail'] let file = ['./data/gachaJson', './data/srJson', './temp/html/StarRail', './temp/uigf']
for (let i of file) { for (let i of file) {
if (!fs.existsSync(i)) { if (!fs.existsSync(i)) {
fs.mkdirSync(i) fs.mkdirSync(i)
@ -66,7 +66,7 @@ export class gcLog extends plugin {
} }
} }
accept() { accept () {
if (this.e.file && this.e.isPrivate) { if (this.e.file && this.e.isPrivate) {
let name = this.e.file?.name let name = this.e.file?.name
if (name.includes('txt')) { if (name.includes('txt')) {
@ -89,7 +89,7 @@ export class gcLog extends plugin {
} }
/** 抽卡记录链接 */ /** 抽卡记录链接 */
async logUrl() { async logUrl () {
if (!this.e.isPrivate) { if (!this.e.isPrivate) {
this.e.reply('请私聊发送链接', false, { at: true }) this.e.reply('请私聊发送链接', false, { at: true })
return true return true
@ -103,7 +103,7 @@ export class gcLog extends plugin {
} }
/** 发送output_log.txt日志文件 */ /** 发送output_log.txt日志文件 */
async logFile() { async logFile () {
if (!this.e.isPrivate) { if (!this.e.isPrivate) {
await this.e.reply('请私聊发送日志文件', false, { at: true }) await this.e.reply('请私聊发送日志文件', false, { at: true })
return true return true
@ -126,7 +126,7 @@ export class gcLog extends plugin {
} }
/** #抽卡记录 */ /** #抽卡记录 */
async getLog() { async getLog () {
this.e.isAll = !!(this.e.msg.includes('全部')) this.e.isAll = !!(this.e.msg.includes('全部'))
let data = await new GachaLog(this.e).getLogData() let data = await new GachaLog(this.e).getLogData()
if (!data) return if (!data) return
@ -139,7 +139,7 @@ export class gcLog extends plugin {
} }
/** 导出记录 */ /** 导出记录 */
async exportLog() { async exportLog () {
if (this.e.isGroup) { if (this.e.isGroup) {
await this.reply('请私聊导出', false, { at: true }) await this.reply('请私聊导出', false, { at: true })
return return
@ -150,63 +150,44 @@ export class gcLog extends plugin {
if (this.e.msg.includes('json')) { if (this.e.msg.includes('json')) {
return await exportLog.exportJson() return await exportLog.exportJson()
} else { } else {
await this.e.reply('如需要将此记录导入到其他平台请导出json格式文件')
return await exportLog.exportXlsx() return await exportLog.exportXlsx()
} }
} }
async logXlsx() { async logXlsx () {
if (!this.e.isPrivate) { if (!this.e.isPrivate) {
await this.e.reply('请私聊发送日志文件', false, { at: true }) await this.e.reply('请私聊发送日志文件', false, { at: true })
return true return true
} }
const gsTips = `不支持https://github.com/biuuu/genshin-wish-export项目导出的excel文件,如果是该项目的文件请发送任意消息取消excel导入后使用【#json导入记录】`;
const srTips = `注:适配https://github.com/biuuu/star-rail-warp-export项目导出的excel文件`;
await this.e.reply(`请发送xlsx文件该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名100000000.xlsx\n否则可能无法正确识别,如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`);
this.setContext('importLogXlsx');
}
async importLogXlsx() {
if (!this.e.file) { if (!this.e.file) {
await this.e.reply(`未检测到excel文件操作已取消请重新发送【${this.e?.isSr ? '*' : '#'}excel导入记录】`); await this.e.reply('请发送xlsx文件')
return true
} }
else { await this.e.reply('如果是星铁记录请在【原始数据】工作表复制【gacha_type】列粘贴并把此标题重命名为【srgf_gacha_type】否则可能无法正确识别')
this.e.isSr = this.getContext()?.importLogXlsx.isSr; await new ExportLog(this.e).logXlsx()
await new ExportLog(this.e).logXlsx();
}
this.finish('importLogXlsx');
} }
async logJson() { async logJson () {
if (!this.e.isPrivate) { if (!this.e.isPrivate) {
await this.e.reply('请私聊发送日志文件', false, { at: true }) await this.e.reply('请私聊发送Json文件', false, { at: true })
return true return true
} }
const gsTips = `适配https://github.com/biuuu/genshin-wish-export项目导出的json文件`;
const srTips = `注:适配https://github.com/biuuu/star-rail-warp-export项目导出的json文件`;
await this.e.reply(`请发送json文件该文件需要以${this.e?.isSr ? '*' : '#'}的uid命名\n100000000.json否则可能无法正确识别如果误触可发送任意消息取消导入\n${this.e?.isSr ? srTips : gsTips}`);
this.setContext('importLogJson');
}
async importLogJson() {
this.e.isSr = this.getContext()?.importLogJson.isSr;
if (!this.e.file) { if (!this.e.file) {
await this.e.reply(`未检测到json文件操作已取消请重新发送【${this.e?.isSr ? '*' : '#'}json导入记录】`); await this.e.reply('请发送Json文件')
return true
} }
else {
await new ExportLog(this.e).logJson(); await new ExportLog(this.e).logJson()
}
this.finish('importLogJson');
} }
async help() { async help () {
await this.e.reply(segment.image(`file://${_path}/resources/logHelp/记录帮助.png`)) await this.e.reply(segment.image(`file://${_path}/resources/logHelp/记录帮助.png`))
} }
async helpPort() { async helpPort () {
let msg = this.e.msg.replace(/#|帮助/g, '') let msg = this.e.msg.replace(/#|帮助/g, '')
if (['电脑', 'pc'].includes(msg)) { if (['电脑', 'pc'].includes(msg)) {
@ -218,7 +199,7 @@ export class gcLog extends plugin {
} }
} }
async logCount() { async logCount () {
let data = await new LogCount(this.e).count() let data = await new LogCount(this.e).count()
if (!data) return if (!data) return
let img = await puppeteer.screenshot(`${data.srtempFile}logCount`, data) let img = await puppeteer.screenshot(`${data.srtempFile}logCount`, data)

View File

@ -19,35 +19,41 @@ export default class ExportLog extends base {
this.path = this.e.isSr ? `./data/srJson/${this.e.user_id}/` : `./data/gachaJson/${this.e.user_id}/` this.path = this.e.isSr ? `./data/srJson/${this.e.user_id}/` : `./data/gachaJson/${this.e.user_id}/`
const gsPool = [ this.game = this.e.game || this.e.isSr ? 'sr' : 'gs'
{ type: 301, typeName: '角色活动' },
{ type: 302, typeName: '武器活动' },
{ type: 200, typeName: '常驻' }
];
const srPool = [ this.pool = (game = 'gs') => {
{ type: 11, typeName: '角色活动' }, let pool = {
{ type: 12, typeName: '武器活动' }, gs: [
{ type: 2, typeName: '新手活动' }, { type: 301, typeName: '角色活动' },
{ type: 1, typeName: '常驻' } { type: 302, typeName: '武器活动' },
]; { type: 200, typeName: '常驻' }
],
sr: [
{ type: 11, typeName: '角色活动' },
{ type: 12, typeName: '武器活动' },
{ type: 2, typeName: '新手活动' },
{ type: 1, typeName: '常驻' }
]
}
return pool[game]
}
this.pool = this.e.isSr ? srPool : gsPool; this.typeName = (game = 'gs') => {
let type = {
const gsTypeName = { gs: {
301: '角色', 301: '角色',
302: '武器', 302: '武器',
200: '常驻' 200: '常驻'
}; },
sr: {
const srTypeName = { 11: '角色',
11: '角色', 12: '武器',
12: '武器', 2: '新手',
2: '新手', 1: '常驻'
1: '常驻' }
}; }
return type[game]
this.typeName = this.e.isSr ? srTypeName : gsTypeName; }
} }
async initXlsx() { async initXlsx() {
@ -57,6 +63,9 @@ export default class ExportLog extends base {
} }
async exportJson() { async exportJson() {
if (!this.e.isSr) {
await common.downFile('https://api.uigf.org/dict/genshin/chs.json', './temp/uigf/genshin.json')
}
await this.getUid() await this.getUid()
if (!this.uid) return false if (!this.uid) return false
@ -71,11 +80,17 @@ export default class ExportLog extends base {
export_timestamp: moment().format('X'), export_timestamp: moment().format('X'),
export_app: 'Miao-Yunzai', export_app: 'Miao-Yunzai',
export_app_version: cfg.package.version, export_app_version: cfg.package.version,
uigf_version: 'v2.2'
}, },
list list
} }
if (this.e.isSr) {
data.info.srgf_version = 'v1.0'
data.info.region_time_zone = moment(list[0].time).utcOffset() / 60
} else {
data.info.uigf_version = 'v2.3'
}
let saveFile = `${this.path}${this.uid}/${this.uid}.json` let saveFile = `${this.path}${this.uid}/${this.uid}.json`
fs.writeFileSync(saveFile, JSON.stringify(data, '', '\t')) fs.writeFileSync(saveFile, JSON.stringify(data, '', '\t'))
@ -141,11 +156,12 @@ export default class ExportLog extends base {
} }
getAllList() { getAllList() {
let uigf = JSON.parse(fs.readFileSync('./temp/uigf/genshin.json', 'utf8'))
let res = { let res = {
list: [] list: []
} }
let tmpId = {} let tmpId = {}
for (let v of this.pool) { for (let v of this.pool(this.game)) {
let json = `${this.path}${this.uid}/${v.type}.json` let json = `${this.path}${this.uid}/${v.type}.json`
if (fs.existsSync(json)) { if (fs.existsSync(json)) {
json = JSON.parse(fs.readFileSync(json, 'utf8')) json = JSON.parse(fs.readFileSync(json, 'utf8'))
@ -155,10 +171,16 @@ export default class ExportLog extends base {
} }
res[v.type] = json res[v.type] = json
for (let v of json) { for (let v of json) {
if (v.gacha_type == 301 || v.gacha_type == 400) { // item_id必要字段
v.uigf_gacha_type = '301' if (!v.item_id) {
} else { v.item_id = String(uigf[v.name])
v.uigf_gacha_type = v.gacha_type }
if (!this.e.isSr) {
if (v.gacha_type == 301 || v.gacha_type == 400) {
v.uigf_gacha_type = '301'
} else {
v.uigf_gacha_type = v.gacha_type
}
} }
let id = v.id let id = v.id
if (!id) { if (!id) {
@ -192,7 +214,7 @@ export default class ExportLog extends base {
xlsxDataPool(data) { xlsxDataPool(data) {
let xlsxData = [] let xlsxData = []
for (let v of this.pool) { for (let v of this.pool(this.game)) {
let poolData = [ let poolData = [
[ [
'时间', '名称', '物品类型', '星级', '祈愿类型' '时间', '名称', '物品类型', '星级', '祈愿类型'
@ -214,15 +236,17 @@ export default class ExportLog extends base {
} }
xlsxDataAll(data) { xlsxDataAll(data) {
let ui = this.e.isSr ? 'sr' : 'ui'
let list = [ let list = [
[ [
'count', 'gacha_type', 'id', 'item_id', 'item_type', 'lang', 'name', 'rank_type', 'time', 'uid', 'uigf_gacha_type' 'count', 'gacha_type', 'id', 'item_id', 'item_type', 'lang', 'name', 'rank_type', 'time', 'uid', `${ui}gf_gacha_type`
] ]
] ]
for (let v of data.list) { for (let v of data.list) {
let tmp = [] let tmp = []
if (this.e.isSr) v.srgf_gacha_type = v.gacha_type
for (let i of list[0]) { for (let i of list[0]) {
if (i == 'id' || i == 'uigf_gacha_type') v[i] = String(v[i]) if (i == 'id' || i == `${ui}gf_gacha_type`) v[i] = String(v[i])
tmp.push(v[i]) tmp.push(v[i])
} }
list.push(tmp) list.push(tmp)
@ -280,6 +304,10 @@ export default class ExportLog extends base {
return false return false
} }
if (rawData.data[0].includes('srgf_gacha_type')) {
this.e.isSr = true
this.game = 'sr'
}
/** 处理xlsx数据 */ /** 处理xlsx数据 */
let data = this.dealXlsx(rawData.data); let data = this.dealXlsx(rawData.data);
if (!data) return false if (!data) return false
@ -287,24 +315,26 @@ export default class ExportLog extends base {
/** 保存json */ /** 保存json */
let msg = [] let msg = []
for (let type in data) { for (let type in data) {
if (!this.typeName[type]) continue let typeName = this.typeName(this.game)
if (!typeName[type]) continue
let gachLog = new GachaLog(this.e) let gachLog = new GachaLog(this.e)
gachLog.uid = uid gachLog.uid = uid
gachLog.type = type gachLog.type = type
gachLog.writeJson(data[type]) gachLog.writeJson(data[type])
msg.push(`${this.typeName[type]}记录:${data[type].length}`) msg.push(`${typeName[type]}记录:${data[type].length}`)
} }
/** 删除文件 */ /** 删除文件 */
fs.unlink(textPath, () => { }) fs.unlink(textPath, () => { })
await this.e.reply(`${this.e.file.name}导入成功\n${msg.join('\n')}`) await this.e.reply(`${this.e.file.name}${this.e.isSr ? '星铁' : '原神'}记录导入成功\n${msg.join('\n')}`)
} }
dealXlsx(list) { dealXlsx(list) {
let ui = this.e.isSr ? 'sr' : 'ui'
/** 必要字段 */ /** 必要字段 */
let reqField = ['uigf_gacha_type', 'gacha_type', 'item_type', 'name', 'time'] let reqField = ['gacha_type', 'item_type', 'name', 'time', `${ui}gf_gacha_type`]
/** 不是必要字段 */ /** 不是必要字段 */
let noReqField = ['id', 'uid', 'count', 'item_id', 'lang', 'rank_type'] let noReqField = ['id', 'uid', 'count', 'item_id', 'lang', 'rank_type']
@ -313,15 +343,11 @@ export default class ExportLog extends base {
field[list[0][i]] = i field[list[0][i]] = i
} }
// 适配StarRailExport导出的xlsx该xlsx没有uigf_gacha_type字段.
if (!field['uigf_gacha_type'] && field['gacha_type']) {
field['uigf_gacha_type'] = field['gacha_type']
}
/** 判断字段 */ /** 判断字段 */
for (let v of reqField) { for (let v of reqField) {
if (!field[v]) { if (!field[v]) {
this.e.reply(`xlsx文件内容错误缺少必要字段${v}`) let tips = v === 'srgf_gacha_type' ? '\n请在【原始数据】工作表复制【gacha_type】列粘贴并把此标题重命名为【srgf_gacha_type】' : ''
this.e.reply(`xlsx文件内容错误缺少必要字段${v}${tips}`)
return return
} }
} }
@ -334,7 +360,7 @@ export default class ExportLog extends base {
let data = {} let data = {}
for (let v of list) { for (let v of list) {
if (v[field.name] == 'name') continue if (v[field.name] == 'name') continue
if (!data[v[field.uigf_gacha_type]]) data[v[field.uigf_gacha_type]] = [] if (!data[v[field[`${ui}gf_gacha_type`]]]) data[v[field[`${ui}gf_gacha_type`]]] = []
let tmp = {} let tmp = {}
/** 加入必要字段 */ /** 加入必要字段 */
@ -351,7 +377,7 @@ export default class ExportLog extends base {
} }
} }
data[v[field.uigf_gacha_type]].push(tmp) data[v[field[`${ui}gf_gacha_type`]]].push(tmp)
} }
return data return data
@ -382,25 +408,31 @@ export default class ExportLog extends base {
return false return false
} }
if (json.info.srgf_version) {
this.e.isSr = true
this.game = 'sr'
}
let data = this.dealJson(json.list) let data = this.dealJson(json.list)
if (!data) return false if (!data) return false
/** 保存json */ /** 保存json */
let msg = [] let msg = []
for (let type in data) { for (let type in data) {
if (!this.typeName[type]) continue let typeName = this.typeName(this.game)
if (!typeName[type]) continue
let gachLog = new GachaLog(this.e) let gachLog = new GachaLog(this.e)
gachLog.uid = uid gachLog.uid = uid
gachLog.type = type gachLog.type = type
gachLog.writeJson(data[type]) gachLog.writeJson(data[type])
msg.push(`${this.typeName[type]}记录:${data[type].length}`) msg.push(`${typeName[type]}记录:${data[type].length}`)
} }
/** 删除文件 */ /** 删除文件 */
fs.unlink(textPath, () => { }) fs.unlink(textPath, () => { })
await this.e.reply(`${this.e.file.name}导入成功\n${msg.join('\n')}`) await this.e.reply(`${this.e.file.name}${this.e.isSr ? '星铁' : '原神'}记录导入成功\n${msg.join('\n')}`)
} }
dealJson(list) { dealJson(list) {
@ -416,22 +448,13 @@ export default class ExportLog extends base {
} }
} }
// 对json进行排序按照time字段
list.sort((a, b) => {
return moment(a.time).format('x') - moment(b.time).format('x');
});
/** 倒序 */ /** 倒序 */
if (moment(list[0].time).format('x') < moment(list[list.length - 1].time).format('x')) { if (moment(list[0].time).format('x') < moment(list[list.length - 1].time).format('x')) {
list = list.reverse() list = list.reverse()
} }
for (let v of list) { for (let v of list) {
// 适配StarRailExport导出的json该json没有uigf_gacha_type字段. if (this.game === 'sr') v.uigf_gacha_type = v.gacha_type
if (!v['uigf_gacha_type'] && v['gacha_type']) {
v['uigf_gacha_type'] = v['gacha_type']
}
if (!data[v.uigf_gacha_type]) data[v.uigf_gacha_type] = [] if (!data[v.uigf_gacha_type]) data[v.uigf_gacha_type] = []
data[v.uigf_gacha_type].push(v) data[v.uigf_gacha_type].push(v)
} }