Miao-Yunzai/plugins/genshin/model/payLogData.js

336 lines
9.1 KiB
JavaScript
Raw Normal View History

2023-03-04 14:30:13 +08:00
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
import fetch from 'node-fetch'
import moment from 'moment'
import lodash from 'lodash'
import fs from 'fs'
import base from './base.js'
if (!fs.existsSync('./data/payLog/')) {
fs.mkdirSync('./data/payLog/')
}
export class PayData {
constructor (authKey = '') {
this.#authkey = encodeURIComponent(authKey)
}
#genShinId = ''
#oringinData = []
#authkey = ''
/** 获取原始支付数据 */
async getOringinalData (id = '') {
let res = await fetch(this.getUrl() + id, this.headers)
let ret = await res.json()
let check = this.checkResult(ret)
if (check?.errorMsg) return check
let list = ret?.data?.list
if (!Array.isArray(list)) {
console.error(ret)
return { errorMsg: '获取失败,错误码:' + ret?.retcode }
2023-03-04 14:30:13 +08:00
}
if (list.length === 20) {
this.#oringinData.push(...list)
await this.getOringinalData(list[19].id)
return true
} else {
this.#oringinData.push(...list)
return true
}
}
/** 获取大月卡数据 */
async getPrimogemLog (id = '') {
let res = await fetch(this.getUrl('getPrimogemLog') + id, this.headers)
let ret = await res.json()
let check = this.checkResult(ret)
if (check?.errorMsg) return check
let list = ret?.data?.list
if (!Array.isArray(list)) {
console.error(ret)
return { errorMsg: '获取失败,错误码:' + ret?.retcode }
}
2023-03-04 14:30:13 +08:00
if (list.length === 20) {
list.forEach(v => {
if (v.add_num === '680') this.#oringinData.push(v)
})
await this.getPrimogemLog(list[19].id)
return true
} else {
list.forEach(v => {
if (v.add_num === '680') this.#oringinData.push(v)
})
return true
}
}
async getUserInfo() {
let res = await fetch(this.getUrl('getUserInfo'), this.headers)
let ret = await res.json()
let check = this.checkResult(ret)
if (check?.errorMsg) return check
let data = ret?.data
if (data?.uid) {
return data
}
return {errorMsg: '获取失败,可能是链接已过期或不正确'}
}
checkResult(ret) {
if (ret?.retcode === -101 || ret?.retcode === -100) {
return ret.retcode === -101 ? {errorMsg: '您的链接过期,请重新获取'} : {errorMsg: '链接不正确,请重新获取'}
}
if (/unknown auth appid/.test(ret?.message)) {
return {errorMsg: '抽卡或其他链接现已无法获取充值记录,请发送客服页面的链接!'}
}
return {errorMsg: ''}
}
2023-03-04 14:30:13 +08:00
/** 对原始数据进行筛选,组合 */
async filtrateData () {
// 由于新接口不返回uid了所以先查询出用户信息
const userInfo = await this.getUserInfo()
if (userInfo?.errorMsg) return userInfo
this.#genShinId = userInfo.uid
2023-03-04 14:30:13 +08:00
// 获取数据
let isSucceed = await this.getOringinalData()
// 判断数据是否获取成功
if (isSucceed?.errorMsg) return isSucceed
await this.getPrimogemLog()
// 判断零氪党的情况
if (this.#oringinData.length === 0) {
return {errorMsg: '未获取到您的任何充值数据'}
2023-03-04 14:30:13 +08:00
}
// 将原始数据按id排序
this.#oringinData = this.#oringinData.sort((a, b) => {
let val1 = Number(a.id)
let val2 = Number(b.id)
if (val2 > val1) {
return -1
} else {
return 1
}
})
// 单双倍结晶数
const price = [680, 300, 8080, 3880, 2240, 1090, 330, 60]
const doublePrice = [0, 0, 12960, 6560, 3960, 1960, 600, 120]
let month = 0
let sum = 0
let i = -1
let listIndex = 0
let list = []
for (let index = 0; index < this.#oringinData.length; index++) {
// 如果小于零则返回
let num = Number(this.#oringinData[index].add_num)
if (num < 0) continue
// 获取月份
// let thisMonth = ++moment(this.#oringinData[index].time).toArray()[1]
// 新接口改名为datetime
let thisMonth = ++moment(this.#oringinData[index].datetime).toArray()[1]
2023-03-04 14:30:13 +08:00
if (thisMonth !== month) {
i++
month = thisMonth
list[listIndex++] = {
month: thisMonth + '月',
payNum: [0, 0, 0, 0, 0, 0, 0, 0]
}
} else if (!i) {
list[i] = {
month: thisMonth + '月',
payNum: [0, 0, 0, 0, 0, 0, 0, 0]
}
}
for (let index = 0; index < 8; index++) {
if (num === price[index] || num === doublePrice[index]) {
list[i].payNum[index]++
if (num !== 680) sum += num
break
}
}
}
return {
uid: this.#genShinId,
crystal: sum,
monthData: list
}
}
headers = {
headers: {
accept: 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site'
},
referrer: 'https://webstatic.mihoyo.com/',
referrerPolicy: 'strict-origin-when-cross-origin',
method: 'GET',
mode: 'cors',
credentials: 'include'
}
/**
* 获取url
* @param api 原石 getPrimogemLog // 结晶 getCrystalLog // 获取用户信息 getUserInfo
* @returns {string}
*/
getUrl(api = 'getCrystalLog') {
const baseUrl = 'https://hk4e-api.mihoyo.com/common/hk4e_self_help_query/User'
const isUserInfo = api === 'getUserInfo', isCrystalLog = api === 'getCrystalLog'
const url = isUserInfo ? '/GetUserInfo' : isCrystalLog ? '/GetCrystalLog' : '/GetPrimogemLog'
let params = ''
params += '?selfquery_type=1'
params += '&sign_type=2'
params += '&auth_appid=csc'
params += '&authkey_ver=1'
params += '&game_biz=hk4e_cn'
params += '&win_direction=portrait'
params += '&bbs_auth_required=true'
params += '&bbs_game_role_required=hk4e_cn'
params += '&app_client=bbs'
params += '&lang=zh-cn'
params += '&csc_authkey_required=true'
params += '&authkey=' + this.#authkey
params += '&page_id=1'
// 此条件限定只查询获取的
if (!isUserInfo) {
params += '&add_type=produce'
params += '&size=20'
// endId外部拼接
params += '&end_id='
}
return baseUrl + url + params
// 老API
// let type = api === 'getCrystalLog' ? 3 : 1
// return `https://hk4e-api.mihoyo.com/ysulog/api/${api}?selfquery_type=${type}&lang=zh-cn&sign_type=2&auth_appid=csc&authkey_ver=1&authkey=${this.#authkey}&game_biz=hk4e_cn&app_client=bbs&type=${type}&size=20&end_id=`
2023-03-04 14:30:13 +08:00
}
}
export class HtmlData extends base {
/**
* @param data 数据
* @param data.monthData 月份数据
* @param data.crystal 总结晶数
*/
constructor (data = {}) {
super()
this.monthData = data.monthData
this.crystal = data.crystal
this.uid = data.uid
this.model = 'payLog'
}
crystal = 0
uid = ''
monthData = []
// 价格
price = [68, 30, 648, 328, 198, 98, 30, 6]
/** 柱形图数据 */
getBarData () {
return this.monthData.map(v => {
return {
type: v.month,
sales: v.payNum.reduce((sum, val, index) => sum + val * this.price[index], 0)
}
})
}
/** 顶部数据 */
getTopData (crystal = 0) {
const maxMonth = this.maxcConsumption()
const sum = this.sumConsumption()
return [
{
title: '总消费',
value: '¥' + this.getBarData().reduce((sum, val) => sum + val.sales, 0)
},
{
title: '总结晶',
value: this.crystal
},
{
title: '消费最多',
value: maxMonth.type
},
{
title: maxMonth.type + '消费',
value: '¥' + maxMonth.sales
},
...sum
]
}
/** 饼图数据 */
getPieData () {
const data = this.sumConsumption()
let pieData = []
data.forEach((val, index) => {
let value = val.value * this.price[index]
if (value) {
pieData.push({
value,
name: val.title
})
}
})
return pieData
}
/** 消费最多月 */
maxcConsumption () {
return this.getBarData().sort((a, b) => {
if (a.sales < b.sales) {
return 1
} else {
return -1
}
})[0]
}
/** 每种消费的总数 */
sumConsumption () {
let sum = {
小月卡: 0,
大月卡: 0,
648: 0,
328: 0,
198: 0,
98: 0,
30: 0,
6: 0
}
// 循环sum,按照月份统计各个充值的类别总数
let k = Object.keys(sum).reverse()
this.monthData.forEach(val => {
val.payNum.forEach((v, i) => {
sum[k[i]] += v
})
})
// 返回title,value对象'648':123456
let value = Object.values(sum).reverse()
return k.map((val, index) => {
return {
title: val,
value: value[index]
}
})
}
}
export async function renderImg (data) {
const htmlData = new HtmlData(data)
const imgDatas = {
...htmlData.screenData,
topData: htmlData.getTopData(),
barData: JSON.stringify(htmlData.getBarData()),
pieData: JSON.stringify(htmlData.getPieData()),
saveId: htmlData.uid,
uid: htmlData.uid
}
let img = await puppeteer.screenshot('payLog', imgDatas)
return img
}