2023-02-26 15:42:56 +00:00
|
|
|
import lodash from 'lodash'
|
2023-03-07 17:52:11 +00:00
|
|
|
import { Data } from '#miao'
|
|
|
|
import { Character, Weapon } from '#miao.models'
|
2024-04-03 16:33:14 +00:00
|
|
|
import { poolDetail, mixPoolDetail } from '../../resources/meta-gs/info/index.js'
|
2023-02-26 15:42:56 +00:00
|
|
|
import moment from 'moment'
|
|
|
|
|
|
|
|
let poolVersion = []
|
|
|
|
lodash.forEach(poolDetail, (ds) => {
|
|
|
|
poolVersion.push({
|
|
|
|
...ds,
|
|
|
|
start: new Date(ds.from),
|
|
|
|
end: new Date(ds.to)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
let last = poolVersion[poolVersion.length - 1]
|
|
|
|
// 为未知卡池做兼容
|
|
|
|
poolVersion.push({
|
2023-02-28 17:59:13 +00:00
|
|
|
version: '新版本',
|
2023-02-26 15:42:56 +00:00
|
|
|
half: '?',
|
|
|
|
from: last.to,
|
|
|
|
to: '2025-12-31 23:59:59',
|
|
|
|
start: last.end,
|
|
|
|
end: new Date('2025-12-31 23:59:59')
|
|
|
|
})
|
|
|
|
|
2024-04-03 16:33:14 +00:00
|
|
|
let mixPoolVersion = []
|
|
|
|
lodash.forEach(mixPoolDetail, (ds) => {
|
|
|
|
mixPoolVersion.push({
|
|
|
|
...ds,
|
|
|
|
start: new Date(ds.from),
|
|
|
|
end: new Date(ds.to)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
let mixLast = mixPoolVersion[mixPoolVersion.length - 1]
|
|
|
|
mixPoolVersion.push({
|
|
|
|
version: '新版本',
|
|
|
|
half: '?',
|
|
|
|
from: mixLast.to,
|
|
|
|
to: '2025-12-31 23:59:59',
|
|
|
|
start: mixLast.end,
|
|
|
|
end: new Date('2025-12-31 23:59:59')
|
|
|
|
})
|
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
let GachaData = {
|
2023-02-26 19:30:26 +00:00
|
|
|
|
|
|
|
// 获取JSON数据
|
2023-02-26 15:42:56 +00:00
|
|
|
readJSON (qq, uid, type) {
|
|
|
|
let logJson = []
|
|
|
|
// 获取本地数据 进行数据合并
|
2023-02-28 17:59:13 +00:00
|
|
|
logJson = Data.readJSON(`/data/gachaJson/${qq}/${uid}/${type}.json`, 'root')
|
2023-02-26 15:42:56 +00:00
|
|
|
let itemMap = {}
|
|
|
|
let nameMap = {}
|
|
|
|
let items = []
|
|
|
|
let ids = {}
|
|
|
|
lodash.forEach(logJson, (ds) => {
|
|
|
|
if (!nameMap[ds.name]) {
|
|
|
|
if (ds.item_type === '武器') {
|
|
|
|
let weapon = Weapon.get(ds.name)
|
2023-02-26 19:30:26 +00:00
|
|
|
if (weapon) {
|
|
|
|
nameMap[ds.name] = weapon.id
|
|
|
|
itemMap[weapon.id] = {
|
|
|
|
type: 'weapon',
|
|
|
|
count: 0,
|
|
|
|
...weapon.getData('star,name,abbr,img')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nameMap[ds.name] = 403
|
|
|
|
itemMap[403] = {
|
|
|
|
type: 'weapon',
|
|
|
|
count: 0,
|
|
|
|
star: 3,
|
|
|
|
name: '未知',
|
|
|
|
abbr: '未知',
|
|
|
|
img: ''
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
}
|
|
|
|
} else if (ds.item_type === '角色') {
|
|
|
|
let char = Character.get(ds.name)
|
2023-02-26 19:30:26 +00:00
|
|
|
if (char) {
|
|
|
|
nameMap[ds.name] = char.id
|
|
|
|
itemMap[char.id] = {
|
|
|
|
type: 'char',
|
|
|
|
count: 0,
|
|
|
|
...char.getData('star,name,abbr,img:face')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nameMap[ds.name] = 404
|
|
|
|
itemMap[404] = {
|
|
|
|
type: 'char',
|
|
|
|
count: 0,
|
|
|
|
star: 4,
|
|
|
|
name: '未知',
|
|
|
|
abbr: '未知',
|
|
|
|
img: ''
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let id = nameMap[ds.name]
|
2023-03-01 01:54:08 +00:00
|
|
|
if (!id || !itemMap[id] || (ds.id && ids[ds.id])) {
|
2023-02-26 15:42:56 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
ids[ds.id] = true
|
|
|
|
items.push({
|
|
|
|
id,
|
|
|
|
logId: ds.id,
|
|
|
|
time: new Date(ds.time)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
items = items.sort((a, b) => b.time - a.time)
|
|
|
|
return { items, itemMap }
|
|
|
|
},
|
2023-02-26 19:30:26 +00:00
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
// 卡池分析
|
|
|
|
analyse (qq, uid, type) {
|
|
|
|
let logData = GachaData.readJSON(qq, uid, type)
|
|
|
|
let fiveLog = []
|
|
|
|
let fourLog = []
|
|
|
|
let fiveNum = 0
|
|
|
|
let fourNum = 0
|
|
|
|
let fiveLogNum = 0
|
|
|
|
let fourLogNum = 0
|
|
|
|
let noFiveNum = 0
|
|
|
|
let noFourNum = 0
|
|
|
|
let wai = 0 // 歪
|
|
|
|
let weaponNum = 0
|
|
|
|
let weaponFourNum = 0
|
|
|
|
let bigNum = 0
|
|
|
|
let allNum = 0
|
2024-04-03 16:33:14 +00:00
|
|
|
let isMix = false
|
|
|
|
if (type === 500) {
|
|
|
|
isMix = true
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
|
|
|
|
let itemMap = logData.itemMap
|
2023-02-27 13:31:10 +00:00
|
|
|
if (logData.items.length === 0) {
|
|
|
|
return false
|
|
|
|
}
|
2023-02-28 17:59:13 +00:00
|
|
|
let currVersion
|
2023-02-26 15:42:56 +00:00
|
|
|
lodash.forEach(logData.items, (item) => {
|
2023-02-28 17:59:13 +00:00
|
|
|
if (!currVersion || (item.time < currVersion.start)) {
|
2024-04-03 16:33:14 +00:00
|
|
|
currVersion = GachaData.getVersion(item.time, true, isMix)
|
2023-02-28 17:59:13 +00:00
|
|
|
}
|
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
allNum++
|
|
|
|
let ds = itemMap[item.id]
|
|
|
|
let { star, type } = ds
|
|
|
|
ds.count++
|
|
|
|
if (star === 4) {
|
|
|
|
fourNum++
|
|
|
|
if (noFourNum === 0) {
|
|
|
|
noFourNum = fourLogNum
|
|
|
|
}
|
|
|
|
fourLogNum = 0
|
|
|
|
if (fourLog[ds.name]) {
|
|
|
|
fourLog[ds.name]++
|
|
|
|
} else {
|
|
|
|
fourLog[ds.name] = 1
|
|
|
|
}
|
|
|
|
if (type === 'weapon') {
|
|
|
|
weaponFourNum++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fourLogNum++
|
|
|
|
|
|
|
|
if (star === 5) {
|
|
|
|
fiveNum++
|
|
|
|
if (fiveLog.length > 0) {
|
|
|
|
fiveLog[fiveLog.length - 1].count = fiveLogNum
|
|
|
|
} else {
|
|
|
|
noFiveNum = fiveLogNum
|
|
|
|
}
|
|
|
|
fiveLogNum = 0
|
|
|
|
let isUp = false
|
|
|
|
// 歪了多少个
|
|
|
|
if (type === 'char') {
|
2024-01-09 13:37:34 +00:00
|
|
|
if (currVersion.char5?.includes(ds.name)) {
|
2023-02-26 15:42:56 +00:00
|
|
|
isUp = true
|
|
|
|
} else {
|
|
|
|
wai++
|
|
|
|
}
|
|
|
|
} else {
|
2024-01-09 13:37:34 +00:00
|
|
|
if (currVersion.weapon5?.includes(ds.name)) {
|
2023-02-28 17:59:13 +00:00
|
|
|
isUp = true
|
|
|
|
} else {
|
|
|
|
wai++
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fiveLog.push({
|
|
|
|
id: item.id,
|
|
|
|
isUp,
|
|
|
|
date: moment(item.time).format('MM-DD')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
fiveLogNum++
|
|
|
|
})
|
|
|
|
|
|
|
|
if (fiveLog.length > 0) {
|
|
|
|
fiveLog[fiveLog.length - 1].count = fiveLogNum
|
|
|
|
} else {
|
|
|
|
// 没有五星
|
|
|
|
noFiveNum = allNum
|
|
|
|
}
|
|
|
|
|
|
|
|
// 四星最多
|
|
|
|
let fourItem = lodash.filter(lodash.values(itemMap), (ds) => ds.star === 4)
|
|
|
|
fourItem.push({ name: '无', count: 0 })
|
|
|
|
fourItem = fourItem.sort((a, b) => b.count - a.count)
|
|
|
|
|
|
|
|
// 平均5星
|
|
|
|
let fiveAvg = 0
|
|
|
|
let fourAvg = 0
|
|
|
|
if (fiveNum > 0) {
|
|
|
|
fiveAvg = ((allNum - noFiveNum) / fiveNum).toFixed(2)
|
|
|
|
}
|
|
|
|
// 平均四星
|
|
|
|
if (fourNum > 0) {
|
|
|
|
fourAvg = ((allNum - noFourNum) / fourNum).toFixed(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 有效抽卡
|
|
|
|
let isvalidNum = 0
|
|
|
|
if (fiveNum > 0 && fiveNum > wai) {
|
|
|
|
if (fiveLog.length > 0 && !fiveLog[0].isUp) {
|
|
|
|
isvalidNum = (allNum - noFiveNum - fiveLog[0].count) / (fiveNum - wai)
|
|
|
|
} else {
|
|
|
|
isvalidNum = (allNum - noFiveNum) / (fiveNum - wai)
|
|
|
|
}
|
|
|
|
isvalidNum = isvalidNum.toFixed(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
let upYs = isvalidNum * 160
|
|
|
|
if (upYs >= 10000) {
|
|
|
|
upYs = (upYs / 10000).toFixed(2) + 'w'
|
|
|
|
} else {
|
|
|
|
upYs = upYs.toFixed(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 小保底不歪概率
|
|
|
|
let noWaiRate = 0
|
|
|
|
if (fiveNum > 0) {
|
|
|
|
noWaiRate = (fiveNum - bigNum - wai) / (fiveNum - bigNum)
|
|
|
|
noWaiRate = (noWaiRate * 100).toFixed(1)
|
|
|
|
}
|
|
|
|
|
2023-02-28 17:59:13 +00:00
|
|
|
if (noFiveNum > 0) {
|
|
|
|
fiveLog.unshift({
|
|
|
|
id: 888,
|
|
|
|
isUp: true,
|
|
|
|
count: noFiveNum,
|
|
|
|
date: moment().format('MM-DD')
|
|
|
|
})
|
|
|
|
itemMap['888'] = {
|
|
|
|
name: '已抽',
|
|
|
|
star: 5,
|
|
|
|
abbr: '已抽',
|
|
|
|
img: 'gacha/imgs/no-avatar.webp'
|
|
|
|
}
|
2023-02-27 21:16:42 +00:00
|
|
|
}
|
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
return {
|
|
|
|
stat: {
|
|
|
|
allNum,
|
|
|
|
noFiveNum,
|
|
|
|
noFourNum,
|
|
|
|
fiveNum,
|
|
|
|
fourNum,
|
|
|
|
fiveAvg,
|
|
|
|
fourAvg,
|
|
|
|
wai,
|
|
|
|
isvalidNum,
|
|
|
|
weaponNum,
|
|
|
|
weaponFourNum,
|
|
|
|
upYs
|
|
|
|
},
|
|
|
|
maxFour: fourItem[0],
|
|
|
|
fiveLog,
|
|
|
|
noWaiRate,
|
|
|
|
items: itemMap
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// 卡池统计
|
|
|
|
stat (qq, uid, type) {
|
2023-02-26 19:30:26 +00:00
|
|
|
let items = []
|
|
|
|
let itemMap = {}
|
|
|
|
let hasVersion = true
|
2024-04-03 16:33:14 +00:00
|
|
|
let isMix = false
|
2023-02-26 19:30:26 +00:00
|
|
|
let loadData = function (poolId) {
|
|
|
|
let gachaData = GachaData.readJSON(qq, uid, poolId)
|
|
|
|
items = items.concat(gachaData.items)
|
|
|
|
lodash.extend(itemMap, gachaData.itemMap || {})
|
|
|
|
}
|
|
|
|
if (['up', 'char', 'all'].includes(type)) {
|
|
|
|
loadData(301)
|
|
|
|
}
|
|
|
|
if (['up', 'weapon', 'all'].includes(type)) {
|
|
|
|
loadData(302)
|
|
|
|
}
|
|
|
|
if (['all', 'normal'].includes(type)) {
|
|
|
|
hasVersion = false
|
|
|
|
loadData(200)
|
|
|
|
}
|
2024-04-03 16:33:14 +00:00
|
|
|
if (['mix'].includes(type)) {
|
|
|
|
isMix = true
|
|
|
|
loadData(500)
|
|
|
|
}
|
|
|
|
if (['all'].includes(type)) {
|
|
|
|
loadData(500)
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
|
|
|
|
items = items.sort((a, b) => b.time - a.time)
|
|
|
|
|
|
|
|
let versionData = []
|
|
|
|
let currVersion
|
|
|
|
|
2023-02-27 13:31:10 +00:00
|
|
|
if (lodash.isEmpty(items)) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
let getCurr = function () {
|
|
|
|
if (currVersion && !lodash.isEmpty(currVersion)) {
|
|
|
|
let cv = currVersion
|
|
|
|
let temp = {
|
|
|
|
version: cv.version,
|
|
|
|
half: cv.half,
|
2023-02-26 19:30:26 +00:00
|
|
|
from: hasVersion ? moment(new Date(cv.from)).format('YY-MM-DD') : '',
|
|
|
|
to: hasVersion ? moment(new Date(cv.to)).format('YY-MM-DD') : '',
|
2023-02-26 15:42:56 +00:00
|
|
|
upIds: {}
|
|
|
|
}
|
|
|
|
let upName = {}
|
|
|
|
let items = []
|
|
|
|
let poolNames = []
|
|
|
|
lodash.forEach(cv.char5, (name) => {
|
|
|
|
upName[name] = true
|
|
|
|
let char = Character.get(name)
|
|
|
|
poolNames.push(char.abbr)
|
|
|
|
})
|
|
|
|
lodash.forEach(cv.weapon5, (name) => {
|
|
|
|
upName[name] = true
|
|
|
|
})
|
|
|
|
let w5Num = 0
|
|
|
|
let w5UpNum = 0
|
|
|
|
let c5Num = 0
|
|
|
|
let c5UpNum = 0
|
|
|
|
let c4Num = 0
|
|
|
|
let w4Num = 0
|
|
|
|
let w3Num = 0
|
|
|
|
lodash.forEach(cv.items, (num, id) => {
|
|
|
|
let item = itemMap[id]
|
|
|
|
let isUp = upName[item.name]
|
|
|
|
let star = item.star
|
|
|
|
if (isUp) {
|
|
|
|
temp.upIds[id] = item.name
|
|
|
|
}
|
|
|
|
items.push({ id, num, star: item.star, isUp: temp.upIds[id] ? 1 : 0 })
|
|
|
|
if (item.type === 'char') {
|
|
|
|
if (star === 5) {
|
|
|
|
c5Num += num
|
|
|
|
isUp && (c5UpNum += num)
|
|
|
|
} else {
|
|
|
|
c4Num += num
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (item.type === 'weapon') {
|
|
|
|
if (star === 5) {
|
|
|
|
w5Num += num
|
|
|
|
isUp && (w5UpNum += num)
|
|
|
|
} else {
|
|
|
|
star === 4 ? (w4Num += num) : (w3Num += num)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
temp.name = poolNames.join(' / ')
|
|
|
|
temp.items = lodash.sortBy(items, ['star', 'num', 'isUp']).reverse()
|
|
|
|
temp.stats = {
|
|
|
|
w5Num,
|
|
|
|
w5UpNum,
|
|
|
|
c5Num,
|
|
|
|
c5UpNum,
|
|
|
|
c4Num,
|
|
|
|
w4Num,
|
|
|
|
w3Num,
|
|
|
|
upNum: w5UpNum + c5UpNum,
|
|
|
|
star5Num: w5Num + c5Num,
|
|
|
|
star4Num: w4Num + c4Num,
|
|
|
|
totalNum: w5Num + w4Num + w3Num + c5Num + c4Num
|
|
|
|
}
|
|
|
|
return temp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lodash.forEach(items, (ds) => {
|
2023-02-26 19:30:26 +00:00
|
|
|
if (!currVersion || (ds.time < currVersion.start && hasVersion)) {
|
2023-02-26 15:42:56 +00:00
|
|
|
if (currVersion) {
|
|
|
|
versionData.push(getCurr())
|
|
|
|
}
|
2024-04-03 16:33:14 +00:00
|
|
|
let v = GachaData.getVersion(ds.time, hasVersion, isMix)
|
2023-02-26 19:30:26 +00:00
|
|
|
if (!hasVersion) {
|
|
|
|
v.version = type === 'all' ? '全部统计' : '常驻池'
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
if (!v) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
currVersion = {
|
|
|
|
...v,
|
|
|
|
items: {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!currVersion.items[ds.id]) {
|
|
|
|
currVersion.items[ds.id] = 1
|
|
|
|
} else {
|
|
|
|
currVersion.items[ds.id]++
|
|
|
|
}
|
|
|
|
})
|
|
|
|
versionData.push(getCurr())
|
|
|
|
|
2023-02-27 21:16:42 +00:00
|
|
|
let stat = {}
|
|
|
|
lodash.forEach(versionData, (ds) => {
|
|
|
|
lodash.forEach(ds.stats, (num, key) => {
|
|
|
|
if (!stat[key]) {
|
|
|
|
stat[key] = num
|
|
|
|
} else {
|
|
|
|
stat[key] += num
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
stat.avgUpNum = stat.upNum === 0 ? 0 : ((stat.totalNum / stat.upNum).toFixed(1))
|
|
|
|
|
2023-02-26 15:42:56 +00:00
|
|
|
return {
|
|
|
|
versionData,
|
2023-02-27 21:16:42 +00:00
|
|
|
itemMap,
|
2024-04-03 16:33:14 +00:00
|
|
|
totalStat: stat,
|
|
|
|
isMix
|
2023-02-26 15:42:56 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2024-04-03 16:33:14 +00:00
|
|
|
getVersion (time, hasVersion = true, isMix = false) {
|
|
|
|
if (isMix) {
|
|
|
|
for (let ds of mixPoolVersion) {
|
|
|
|
if (time > ds.start && time < ds.end) {
|
|
|
|
return ds
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-26 19:30:26 +00:00
|
|
|
if (hasVersion) {
|
|
|
|
for (let ds of poolVersion) {
|
|
|
|
if (time > ds.start && time < ds.end) {
|
|
|
|
return ds
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-26 19:30:26 +00:00
|
|
|
return {
|
|
|
|
version: hasVersion === false ? '全部' : '未知',
|
|
|
|
half: '',
|
|
|
|
char5: [],
|
|
|
|
char4: [],
|
|
|
|
weapon5: [],
|
|
|
|
weapon4: []
|
|
|
|
}
|
2023-02-26 15:42:56 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
getItem (ds) {
|
|
|
|
if (ds.item_type === '武器') {
|
|
|
|
let weapon = Weapon.get(ds.name)
|
|
|
|
return {
|
|
|
|
type: 'weapon',
|
|
|
|
count: 0,
|
|
|
|
...weapon.getData('id,star,name,abbr,img')
|
|
|
|
}
|
|
|
|
} else if (ds.item_type === '角色') {
|
|
|
|
let char = Character.get(ds.name)
|
|
|
|
return {
|
|
|
|
type: 'char',
|
|
|
|
count: 0,
|
|
|
|
...char.getData('id,star,name,abbr,face')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export default GachaData
|