初步增加#抽卡分析#抽卡统计,样式与功能尚未完全稳定

This commit is contained in:
Kokomi 2023-02-26 23:42:56 +08:00
parent 25a7103321
commit 347280f1b4
19 changed files with 1651 additions and 16 deletions

View File

@ -1,15 +1,16 @@
# 2.3.2
# 2.3.3 Dev
* 初步增加`#抽卡分析``#抽卡统计`,样式与功能尚未完全稳定
# 2.3.1~2.3.2
* 面板服务增加国内专属面板服务 MiniGG-API
* 由小灰灰大佬**@MiniGrayGay**与Enka官方合作部署
* 国内节点免费开放请求速度会比Enka更快
* `#喵喵设置`中可区分国服、B服、外服分别设置面板服务器具体参见喵喵设置
# 2.3.1
* MiaoApi面板服务更新
* 使用新版接口获取面板,大幅提高响应速度
* 使用statsIds存储圣遗物数据能够更精确的计算角色属性
* `#喵喵设置`中可区分国服、B服、外服分别设置面板服务器具体参见喵喵设置
* `#面板`、`#角色`等页面使用Q版头像(@QuAn_、Misaaa),可在#喵喵设置 中关闭
* 部分已知问题调整或优化
* 圣遗物、天赋更新策略及更新逻辑优化

21
apps/gacha.js Normal file
View File

@ -0,0 +1,21 @@
import { App } from '../components/index.js'
import Gacha from './gacha/Gacha.js'
let app = App.init({
id: 'gacha',
name: '抽卡统计'
})
app.reg({
detail: {
name: '抽卡记录',
fn: Gacha.detail,
rule: /^#*(抽卡|抽奖|角色|武器|常驻|up)池*(记录|祈愿|分析)$/
},
stat: {
name: '抽卡统计',
fn: Gacha.stat,
rule: /^#*(抽卡|抽奖|角色|武器|常驻|up|版本)池*统计$/
}
})
export default app

68
apps/gacha/Gacha.js Normal file
View File

@ -0,0 +1,68 @@
import { Common } from '../../components/index.js'
import { getTargetUid } from '../profile/ProfileCommon.js'
import GachaData from './GachaData.js'
import { Character, Player } from '../../models/index.js'
let Gacha = {
async detail (e) {
let msg = e.msg.replace(/#|抽卡|记录|祈愿|分析|池/g, '')
let type = 301
switch (msg) {
case 'up':
case '抽卡':
case '角色':
case '抽奖':
type = 301
break
case '常驻':
type = 200
break
case '武器':
type = 302
break
}
let uid = e.uid || await getTargetUid(e)
let qq = e.user_id
if (!uid || !qq) {
return false
}
let gacha = GachaData.analyse(e.user_id, uid, type)
await Common.render('gacha/gacha-detail', {
save_id: uid,
uid,
gacha,
face: Gacha.getFace(uid)
}, { e, scale: 1.1, retMsgId: true })
},
async stat (e) {
let uid = e.uid || await getTargetUid(e)
let qq = e.user_id
if (!uid || !qq) {
return false
}
let gacha = GachaData.stat(e.user_id, uid)
await Common.render('gacha/gacha-stat', {
save_id: uid,
uid,
gacha,
face: Gacha.getFace(uid)
}, { e, scale: 1.1, retMsgId: true })
},
getFace (uid) {
let player = Player.create(uid)
let faceChar = Character.get(player.face || '100000003')
let imgs = faceChar.imgs
return {
banner: imgs?.banner,
face: imgs?.face,
qFace: imgs?.qFace,
name: player.name || `#${uid}`,
sign: player.sign,
level: player.level
}
}
}
export default Gacha

371
apps/gacha/GachaData.js Normal file
View File

@ -0,0 +1,371 @@
import lodash from 'lodash'
import { Data } from '../../components/index.js'
import { Character, Weapon } from '../../models/index.js'
import { poolName, poolDetail } from '../../resources/meta/info/index.js'
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({
version: '?',
half: '?',
from: last.to,
to: '2025-12-31 23:59:59',
start: last.end,
end: new Date('2025-12-31 23:59:59')
})
let GachaData = {
readJSON (qq, uid, type) {
let logJson = []
// 获取本地数据 进行数据合并
logJson = Data.readJSON(`/data/gachaJSON/${qq}/${uid}/${type}.json`, 'root')
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)
nameMap[ds.name] = weapon.id
itemMap[weapon.id] = {
type: 'weapon',
count: 0,
...weapon.getData('star,name,abbr,img')
}
} else if (ds.item_type === '角色') {
let char = Character.get(ds.name)
nameMap[ds.name] = char.id
itemMap[char.id] = {
type: 'char',
count: 0,
...char.getData('star,name,abbr,img:face')
}
}
}
let id = nameMap[ds.name]
if (!id || !itemMap[id] || ids[ds.id]) {
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 }
},
// 卡池分析
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
let itemMap = logData.itemMap
lodash.forEach(logData.items, (item) => {
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') {
if (GachaData.checkIsUp(item, ds)) {
isUp = true
} else {
wai++
}
} else {
weaponNum++
}
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)
}
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) {
let charData = GachaData.readJSON(qq, uid, 301)
let weaponData = GachaData.readJSON(qq, uid, 302)
let items = charData.items.concat(weaponData.items || [])
items = items.sort((a, b) => b.time - a.time)
let itemMap = lodash.extend({}, charData.itemMap, weaponData.itemMap)
let versionData = []
let currVersion
let getCurr = function () {
if (currVersion && !lodash.isEmpty(currVersion)) {
let cv = currVersion
let temp = {
version: cv.version,
half: cv.half,
from: moment(new Date(cv.from)).format('YY-MM-DD'),
to: moment(new Date(cv.to)).format('YY-MM-DD'),
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) => {
if (!currVersion || ds.time < currVersion.start) {
if (currVersion) {
versionData.push(getCurr())
}
let v = GachaData.getVersion(ds.time)
if (!v) {
console.log('no v')
return true
}
currVersion = {
...v,
items: {}
}
}
if (!currVersion.items[ds.id]) {
currVersion.items[ds.id] = 1
} else {
currVersion.items[ds.id]++
}
})
versionData.push(getCurr())
return {
versionData,
itemMap
}
},
getVersion (time) {
for (let ds of poolVersion) {
if (time > ds.start && time < ds.end) {
return ds
}
}
return false
},
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')
}
}
},
// 检查角色是否是Up角色
checkIsUp (ds, item) {
if (['莫娜', '七七', '迪卢克', '琴'].includes(item.name)) {
return false
}
let time = ds.time
if (item.name === '刻晴') {
let start = new Date('2021-02-17 18:00:00').getTime()
let end = new Date('2021-03-02 15:59:59').getTime()
return !(time < start || time > end)
}
if (item.name === '提纳里') {
let start = new Date('2022-08-24 06:00:00').getTime()
let end = new Date('2022-09-09 17:59:59').getTime()
return !(time < start || time > end)
}
return true
}
}
export default GachaData

View File

@ -5,6 +5,7 @@ import wiki from './wiki.js'
import poke from './poke.js'
import help from './help.js'
import admin from './admin.js'
import gacha from './gacha.js'
export const characterApp = character.v2App()
export const profileApp = profile.v2App()
@ -13,8 +14,9 @@ export const helpApp = help.v2App()
export const statApp = stat.v2App()
export const wikiApp = wiki.v2App()
export const pokeApp = poke.v2App()
export const gachaApp = gacha.v2App()
let apps = { character, poke, profile, stat, wiki, admin, help }
let apps = { character, poke, profile, stat, wiki, gacha, admin, help }
let rule = {} // v2
let rules = {} // v3
for (let key in apps) {

View File

@ -10,6 +10,10 @@ const Common = {
return new Promise((resolve) => setTimeout(resolve, ms))
},
async downFile () {
console.log('down file')
},
async getNoteQQUids (e) {
let ret = {}
if (Version.isV3) {

View File

@ -78,7 +78,7 @@ export default class ProfileReq extends Base {
if (self._isReq) {
this.msg(`开始获取uid:${uid}的数据,可能会需要一定时间~`)
}
}, 3000)
}, 2000)
// 发起请求
this.log(`${logger.yellow('开始请求数据')},面板服务:${serv.name}...`)
const startTime = new Date() * 1

View File

@ -14,6 +14,7 @@ class Weapon extends Base {
if (cache) {
return cache
}
this.id = meta.id
this.name = meta.name
this.meta = meta
this.type = meta.type

View File

@ -0,0 +1,117 @@
.avatar-cont {
background: rgba(0, 0, 0, 0.1);
}
.gacha-list .gacha-item {
height: 38px;
display: flex;
}
.gacha-list .gacha-item .date {
width: 97px;
line-height: 38px;
padding-left: 5px;
background: rgba(0, 0, 0, 0.8);
display: flex;
}
.gacha-list .gacha-item .date .dot {
width: 23.75px;
height: 38px;
background: url('./imgs/date-icon.webp') center -100%;
background-size: 100% auto;
}
.gacha-list .gacha-item .date .dot.first {
background-position: center 0;
}
.gacha-list .gacha-item .date .dot.last {
background-position: center -128px;
}
.gacha-list .gacha-item .date .txt {
text-align: center;
}
.gacha-list .gacha-item.no-date .date .dot {
background-position: center -71.25px;
}
.gacha-list .gacha-item.no-date .date .dot.last {
background-position: center -95px;
}
.gacha-list .gacha-item.no-date .date .txt {
opacity: 0;
}
.gacha-list .gacha-item.has-date {
margin-top: 5px;
}
.gacha-list .gacha-item .name {
width: 90px;
text-align: right;
line-height: 38px;
padding-right: 5px;
}
.gacha-list .gacha-item.wai .name {
color: #aaa;
}
.gacha-list .gacha-item.wai .name,
.gacha-list .gacha-item.wai .icon,
.gacha-list .gacha-item.wai .process {
background-color: rgba(85, 85, 85, 0.8);
}
.gacha-list .gacha-item.up .name {
background: rgba(0, 0, 0, 0.5);
color: #ffd484;
}
.gacha-list .gacha-item.up .process,
.gacha-list .gacha-item.up .icon {
background-color: rgba(0, 0, 0, 0.5);
}
.gacha-list .icon {
width: 32px;
height: 38px;
}
.gacha-list .icon .icon-bg {
width: 32px;
height: 32px;
margin: 3px 0;
border-radius: 5px;
}
.gacha-list .icon .icon-bg.star5 {
background: url('../common/item/bg5.png') 100% 100% no-repeat;
}
.gacha-list .icon span {
display: block;
width: 32px;
height: 32px;
background-size: auto 100%;
background-position: center;
background-repeat: no-repeat;
}
.gacha-list .process {
width: 490px;
padding-right: 15px;
}
.gacha-list .process .bar {
background: green;
border-radius: 0 5px 5px 0;
height: 26px;
line-height: 26px;
margin: 6px 0;
padding-left: 5px;
}
.gacha-list .process .bar.gold {
background: #ffeb73;
color: #6f4b00;
min-width: 18px;
}
.gacha-list .process .bar.good {
background: #6939b7;
color: #fff;
}
.gacha-list .process .bar.normal {
background: #168b2c;
color: #fff;
}
.gacha-list .process .bar.bad {
background: #9d3333;
color: #fff;
}
.avatar-card .name {
text-align: center;
}
/*# sourceMappingURL=gacha-detail.css.map */

View File

@ -0,0 +1,70 @@
{{extend elemLayout}}
{{block 'css'}}
<link rel="stylesheet" type="text/css" href="{{_res_path}}/common/tpl.css?v=1.0"/>
<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/avatar-list.css"/>
<link rel="stylesheet" type="text/css" href="{{_res_path}}/gacha/gacha-detail.css?v=1.0"/>
{{/block}}
{{ set statMap = { allNum:'抽卡总数', fiveNum:'金卡数', fiveAvg:'平均出金' } }}
{{block 'main'}}
<div class="basic">
<div class="user-banner" style="background-image:url({{_res_path}}{{face?.banner}})">
<div class="face">
<span style="background-image:url({{_res_path}}{{face?.qFace||face?.face}})"></span>
</div>
<div class="user-info">
<div class="name">
<strong>{{face.name}}</strong>
{{if face.level && face.level > 1}} Lv.{{face.level}}{{/if}}
</div>
<div class="uid">
{{if uid}}<span> #{{uid}}</span>{{/if}}
</div>
</div>
{{if gacha && gacha.stat }}
{{set stat = gacha.stat }}
<div class="stat">
{{each statMap title key}}
{{if stat[key] }}
<div class="stat-li">
<strong>{{stat[key]}}</strong>
<span>{{title}}</span>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
</div>
<div class="cont avatar-cont">
<div class="gacha-list">
{{each gacha.fiveLog ds idx}}
{{set item = gacha.items[ds.id]}}
{{set max = item.type === 'weapon'?80:90}}
{{set hasDate = (idx===0 || idx ===gacha.items.length-1 || (idx>0 && gacha.fiveLog[idx-1].date !== ds.date)) }}
<div class="gacha-item {{!hasDate?'no-date':'has-date'}} {{ds.isUp||item.type==='weapon' ?'up':'wai'}}">
<div class="date ">
<div class="dot {{idx===0?'first':''}} {{idx===gacha.items.length-1?'last':''}}"></div>
<div class="txt">{{ds.date}}</div>
</div>
<div class="name">{{item.abbr}}</div>
<div class="icon">
<div class="icon-bg star{{item.star}}">
<span class="img mini" style="background-image:url({{_res_path}}{{item.img}})"></span>
</div>
</div>
<div class="process">
{{set count = ds.count}}
<div class="bar {{count<=10?'gold': (count<max*0.4 ? 'good' : (count<max*0.8) ? 'normal': 'bad')}}"
style="width:{{count/max*100}}%">{{count}}
</div>
</div>
</div>
{{/each}}
</div>
</div>
</div>
{{/block}}

View File

@ -0,0 +1,165 @@
.avatar-cont {
background: rgba(0, 0, 0, .1);
}
.gacha-list {
@size: 32px;
@padding: 3px;
@height: @size + @padding * 2;
.gacha-item {
height: @height;
display: flex;
.date {
width: @size + 65px;
line-height: @height;
padding-left: 5px;
background: rgba(0, 0, 0, .8);
display: flex;
.dot {
width: @height * 0.625;
height: @height;
background: url('./imgs/date-icon.webp') center -100%;
background-size: 100% auto;
&.first {
background-position: center 0;
}
&.last {
background-position: center @size * -4
}
}
.txt {
text-align: center;
}
}
&.no-date {
.date {
.dot {
background-position: center @height * 0.625 * -3;
&.last {
background-position: center @height * 0.625 * -4
}
}
.txt {
opacity: 0;
}
}
}
&.has-date {
margin-top: 5px;
}
.name {
width: 90px;
text-align: right;
line-height: @height;
padding-right: 5px;
}
&.wai {
.name {
color: #aaa;
}
.name, .icon, .process {
background-color: rgba(85, 85, 85, 0.8);
}
}
&.up {
.name {
background: rgba(0, 0, 0, .5);
color: rgb(255, 212, 132);
}
.process, .icon {
background-color: rgba(0, 0, 0, .5);
}
}
}
.icon {
width: @size;
height: @height;
.icon-bg {
width: @size;
height: @size;
margin: @padding 0;
border-radius: 5px;
&.star5 {
background: url('../common/item/bg5.png') 100% 100% no-repeat;
}
}
span {
display: block;
width: @size;
height: @size;
background-size: auto 100%;
background-position: center;
background-repeat: no-repeat;
}
}
.process {
width: 490px;
padding-right: 15px;
@pd: 3px;
.bar {
background: green;
border-radius: 0 5px 5px 0;
height: @size - @pd * 2;
line-height: @size - @pd * 2;
margin: @padding + @pd 0;
padding-left: 5px;
&.gold {
background: #ffeb73;
color: #6f4b00;
min-width: 18px;
}
&.good {
background: #6939b7;
color: #fff;
}
&.normal {
background: #168b2c;
color: #fff;
}
&.bad {
background: #9d3333;
color: #fff;
}
}
}
}
.avatar-card {
.name {
text-align: center;
}
}

View File

@ -0,0 +1,117 @@
.cont-title {
padding: 0;
background: rgba(0, 0, 0, 0.6);
}
.gacha-pool {
display: flex;
text-align: center;
}
.gacha-pool > div {
padding: 10px;
height: 56px;
}
.gacha-pool .line {
padding-right: 15px;
position: relative;
}
.gacha-pool .line:after {
content: "";
display: block;
width: 1px;
height: 15px;
position: absolute;
top: 12px;
right: 7px;
background: #d3bc8e;
}
.gacha-pool .version {
text-align: center;
background: rgba(0, 0, 0, 0.8);
padding: 10px 0;
display: flex;
border-right: 1px solid rgba(255, 255, 255, 0.3);
}
.gacha-pool .version-name {
width: 100px;
line-height: 36px;
font-size: 20px;
font-weight: bold;
text-align: right;
}
.gacha-pool .pool-name {
width: 125px;
text-align: left;
}
.gacha-pool .pool-name .name {
height: 22px;
line-height: 22px;
}
.gacha-pool .pool-name .time {
font-size: 12px;
line-height: 14px;
height: 14px;
color: #888;
}
.gacha-pool .stat-info {
display: flex;
padding: 8px 20px 0;
}
.gacha-pool .stat-info .info {
min-width: 60px;
padding: 0 20px 0 10px;
}
.gacha-pool .stat-info .info .num {
height: 25px;
line-height: 25px;
font-size: 20px;
text-shadow: 0 0 2px #000;
}
.gacha-pool .stat-info .info .title {
font-size: 12px;
line-height: 14px;
height: 14px;
color: #888;
}
.gacha-pool .stat-info .info:last-child:after {
display: none;
}
.gacha-stat {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
background: rgba(0, 0, 0, 0.5);
padding: 5px 8px;
}
.gacha-stat .gacha-item {
text-align: center;
}
.gacha-stat .gacha-item .item-card {
width: 69px;
}
.gacha-stat .item-life {
top: initial;
left: initial;
right: 0;
bottom: 0;
border-radius: 5px 0 0 0;
font-size: 16px;
padding: 0 6px;
min-width: 20px;
height: 22px;
line-height: 22px;
text-align: center;
}
.gacha-stat .item-life.life5 {
background: #ffeb73;
color: #6f4b00;
box-shadow: 0 0 3px 0 #6f4b00;
}
.gacha-stat .item-life.life1 {
background: #333;
color: #fff;
}
.gacha-stat .item-name {
font-size: 15px;
line-height: 24px;
}
/*# sourceMappingURL=gacha-stat.css.map */

View File

@ -0,0 +1,88 @@
{{extend elemLayout}}
{{block 'css'}}
<link rel="stylesheet" type="text/css" href="{{_res_path}}/common/tpl.css?v=1.0"/>
<link rel="stylesheet" type="text/css" href="{{_res_path}}/character/avatar-list.css"/>
<link rel="stylesheet" type="text/css" href="{{_res_path}}/gacha/gacha-detail.css?v=1.0"/>
<link rel="stylesheet" type="text/css" href="{{_res_path}}/gacha/gacha-stat.css?v=1.0"/>
{{/block}}
{{ set statMap = { allNum:'抽卡总数', fiveNum:'金卡数', fiveAvg:'平均出金' } }}
{{block 'main'}}
<div class="basic">
<div class="user-banner" style="background-image:url({{_res_path}}{{face?.banner}})">
<div class="face">
<span style="background-image:url({{_res_path}}{{face?.qFace||face?.face}})"></span>
</div>
<div class="user-info">
<div class="name">
<strong>{{face.name}}</strong>
{{if face.level && face.level > 1}} Lv.{{face.level}}{{/if}}
</div>
<div class="uid">
{{if uid}}<span> #{{uid}}</span>{{/if}}
</div>
</div>
{{if gacha && gacha.stat }}
{{set stat = gacha.stat }}
<div class="stat">
{{each statMap title key}}
{{if stat[key] }}
<div class="stat-li">
<strong>{{stat[key]}}</strong>
<span>{{title}}</span>
</div>
{{/if}}
{{/each}}
</div>
{{/if}}
</div>
{{each gacha.versionData vData}}
{{set stats = vData.stats}}
<div class="cont avatar-cont">
<div class="cont-title">
<div class="gacha-pool">
<div class="version">
<div class="version-name line">
{{vData.version}}{{vData.half}}
</div>
<div class="pool-name">
<div class="name">{{vData.name}}</div>
<div class="time">{{vData.from}}~{{vData.to}}</div>
</div>
</div>
<div class="stat-info">
{{set keyMap = {totalNum:'总抽卡',star5Num:'金卡',upNum:'UP金卡', c4Num:'紫角色', w4Num:'紫武器'} }}
{{each keyMap title key}}
{{if stats[key] > 0}}
<div class="info line">
<div class="num">{{stats[key]}}</div>
<div class="title">{{title}}</div>
</div>
{{/if}}
{{/each}}
</div>
</div>
</div>
<div class="gacha-stat card-list">
{{each vData.items ds}}
{{set item = gacha.itemMap[ds.id]}}
{{if item.star === 4 || item.star === 5}}
<div class="gacha-item">
<div class="item-card">
<div class="item-icon star{{item.star}}">
<div class="item-bg" style="background-image:url({{_res_path}}{{item.img}})"></div>
<div class="item-life {{ds.isUp ? 'life5': 'life1'}}">{{ds.num}}</div>
</div>
<div class="item-name">{{item.name.length >4 ? item.abbr : item.name}}</div>
</div>
</div>
{{/if}}
{{/each}}
</div>
</div>
{{/each}}
</div>
{{/block}}

View File

@ -0,0 +1,138 @@
.cont-title {
padding: 0;
background: rgba(0, 0, 0, .6);
}
.gacha-pool {
display: flex;
text-align: center;
& > div {
padding: 10px;
height: 56px;
}
.line {
padding-right: 15px;
position: relative;
&:after {
content: "";
display: block;
width: 1px;
height: 15px;
position: absolute;
top: 12px;
right: 7px;
background: #d3bc8e;
}
}
.version {
text-align: center;
background: rgba(0, 0, 0, .8);
padding: 10px 0;
display: flex;
border-right: 1px solid rgba(255, 255, 255, .3);
}
.version-name {
width: 100px;
line-height: 36px;
font-size: 20px;
font-weight: bold;
text-align: right;
}
.pool-name {
width: 125px;
text-align: left;
.name {
height: 22px;
line-height: 22px;
}
.time {
font-size: 12px;
line-height: 14px;
height: 14px;
color: #888;
}
}
.stat-info {
display: flex;
padding: 8px 20px 0;
.info {
min-width: 60px;
padding: 0 20px 0 10px;
.num {
height: 25px;
line-height: 25px;
font-size: 20px;
text-shadow: 0 0 2px #000;
}
.title {
font-size: 12px;
line-height: 14px;
height: 14px;
color: #888;
}
&:last-child:after {
display: none;
}
}
}
}
.gacha-stat {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
background: rgba(0, 0, 0, .5);
padding: 5px 8px;
.gacha-item {
text-align: center;
.item-card {
width: 69px;
}
}
.item-life {
top: initial;
left: initial;
right: 0;
bottom: 0;
border-radius: 5px 0 0 0;
font-size: 16px;
padding: 0 6px;
min-width: 20px;
height: 22px;
line-height: 22px;
text-align: center;
&.life5 {
background: #ffeb73;
color: #6f4b00;
box-shadow: 0 0 3px 0 #6f4b00;
}
&.life1 {
background: #333;
color: #fff;
}
}
.item-name {
font-size: 15px;
line-height: 24px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,4 +1,6 @@
// 报箱数统计
export * from './pool.js'
// 宝箱数统计
export const chestInfo = {
common: {
title: '普通宝箱',

461
resources/meta/info/pool.js Normal file
View File

@ -0,0 +1,461 @@
export const poolName = {
温迪: '杯装之诗',
可莉: '闪焰的驻足',
达达利亚: '暂别冬都',
钟离: '陵薮市朝',
阿贝多: '深秘之息',
甘雨: '浮生孰来',
: '烟火之邀',
刻晴: '鱼龙灯昼',
胡桃: '赤团开时',
优菈: '浪涌之瞬',
枫原万叶: '叶落风随',
神里绫华: '白鹭之庭',
宵宫: '焰色天河',
雷电将军: '影寂天下人',
珊瑚宫心海: '浮岳虹珠',
荒泷一斗: '鬼门斗宴',
申鹤: '出尘入世',
八重神子: '华紫樱绯',
神里绫人: '苍流踏花',
夜兰: '素霓伣天',
提纳里: '巡御蘙荟',
赛诺: '雳裁冥昭',
妮露: '翩舞歈莲',
纳西妲: '月草的赐慧',
流浪者: '余火变相',
艾尔海森: '敕诫枢谋'
}
export const poolDetail = [
{
version: '1.0',
half: '上半',
from: '2020-09-28 06:00:00',
to: '2020-10-18 17:59:59',
char5: ['温迪'],
char4: ['芭芭拉', '菲谢尔', '香菱'],
weapon5: ['风鹰剑', '阿莫斯之弓'],
weapon4: ['笛剑', '流浪乐章', '钟剑', '绝弦', '西风长枪']
},
{
version: '1.0',
half: '下半',
from: '2020-10-20 18:00:00',
to: '2020-11-10 14:59:59',
char5: ['可莉'],
char4: ['行秋', '诺艾尔', '砂糖'],
weapon5: ['四风原典', '狼的末路'],
weapon4: ['祭礼剑', '祭礼残章', '祭礼大剑', '祭礼弓', '匣里灭辰']
},
{
version: '1.1',
half: '上半',
from: '2020-11-11 06:00:00',
to: '2020-12-01 15:59:59',
char5: ['达达利亚'],
char4: ['迪奥娜', '北斗', '凝光'],
weapon5: ['尘世之锁', '天空之翼'],
weapon4: ['笛剑', '昭心', '雨裁', '弓藏', '西风长枪']
},
{
version: '1.1',
half: '下半',
from: '2020-12-01 18:00:00',
to: '2020-12-22 14:59:59',
char5: ['钟离'],
char4: ['辛焱', '雷泽', '重云'],
weapon5: ['无工之剑', '贯虹之槊'],
weapon4: ['匣里龙吟', '西风秘典', '钟剑', '西风猎弓', '匣里灭辰']
},
{
version: '1.2',
half: '上半',
from: '2020-12-23 06:00:00',
to: '2021-01-12 15:59:59',
char5: ['阿贝多'],
char4: ['菲谢尔', '砂糖', '班尼特'],
weapon5: ['斫峰之刃', '天空之卷'],
weapon4: ['西风剑', '祭礼残章', '西风大剑', '绝弦', '西风长枪']
},
{
version: '1.2',
half: '下半',
from: '2021-01-12 18:00:00',
to: '2021-02-02 14:59:59',
char5: ['甘雨'],
char4: ['香菱', '行秋', '诺艾尔'],
weapon5: ['天空之傲', '阿莫斯之弓'],
weapon4: ['祭礼剑', '昭心', '钟剑', '西风猎弓', '匣里灭辰']
},
{
version: '1.3',
half: '上半',
from: '2021-02-03 06:00:00',
to: '2021-02-23 15:59:59',
char5: ['魈'],
char4: ['迪奥娜', '北斗', '辛焱'],
weapon5: ['磐岩结绿', '和璞鸢'],
weapon4: ['笛剑', '昭心', '祭礼大剑', '弓藏', '西风长枪']
},
{
version: '1.3',
half: '中场',
from: '2021-02-17 18:00:00',
to: '2021-03-02 15:59:59',
char5: ['刻晴'],
char4: ['凝光', '班尼特', '芭芭拉'],
weapon5: [],
weapon4: []
},
{
version: '1.3',
half: '下半',
from: '2021-03-02 18:00:00',
to: '2021-03-16 14:59:59',
char5: ['胡桃'],
char4: ['行秋', '香菱', '重云'],
weapon5: ['狼的末路', '护摩之杖'],
weapon4: ['匣里龙吟', '流浪乐章', '千岩古剑', '祭礼弓', '千岩长枪']
},
{
version: '1.4',
half: '上半',
from: '2021-03-17 06:00:00',
to: '2021-04-06 15:59:59',
char5: ['温迪'],
char4: ['砂糖', '雷泽', '诺艾尔'],
weapon5: ['天空之刃', '终末嗟叹之诗'],
weapon4: ['暗巷闪光', '暗巷的酒与诗', '西风大剑', '西风猎弓', '匣里灭辰']
},
{
version: '1.4',
half: '下半',
from: '2021-04-06 18:00:00',
to: '2021-04-27 14:59:59',
char5: ['达达利亚'],
char4: ['罗莎莉亚', '芭芭拉', '菲谢尔'],
weapon5: ['四风原典', '天空之翼'],
weapon4: ['西风剑', '西风秘典', '祭礼大剑', '暗巷猎手', '西风长枪']
},
{
version: '1.5',
half: '上半',
from: '2021-04-28 06:00:00',
to: '2021-05-18 17:59:59',
char5: ['钟离'],
char4: ['烟绯', '诺艾尔', '迪奥娜'],
weapon5: ['斫峰之刃', '尘世之锁'],
weapon4: ['笛剑', '昭心', '千岩古剑', '祭礼弓', '千岩长枪']
},
{
version: '1.5',
half: '下半',
from: '2021-05-18 18:00:00',
to: '2021-06-08 14:59:59',
char5: ['优菈'],
char4: ['辛焱', '行秋', '北斗'],
weapon5: ['风鹰剑', '松籁响起之时'],
weapon4: ['祭礼剑', '祭礼残章', '雨裁', '弓藏', '匣里灭辰']
},
{
version: '1.6',
half: '上半',
from: '2021-06-09 06:00:00',
to: '2021-06-29 17:59:59',
char5: ['可莉'],
char4: ['芭芭拉', '砂糖', '菲谢尔'],
weapon5: ['四风原典', '天空之傲'],
weapon4: ['匣里龙吟', '流浪乐章', '钟剑', '幽夜华尔兹', '西风长枪']
},
{
version: '1.6',
half: '下半',
from: '2021-06-29 18:00:00',
to: '2021-07-20 14:59:59',
char5: ['枫原万叶'],
char4: ['罗莎莉亚', '班尼特', '雷泽'],
weapon5: ['苍古自由之誓', '天空之卷'],
weapon4: ['暗巷闪光', '暗巷的酒与诗', '西风大剑', '暗巷猎手', '匣里灭辰']
},
{
version: '2.0',
half: '上半',
from: '2021-07-21 06:00:00',
to: '2021-08-10 17:59:59',
char5: ['神里绫华'],
char4: ['凝光', '重云', '烟绯'],
weapon5: ['雾切之回光', '天空之脊'],
weapon4: ['西风剑', '西风秘典', '祭礼大剑', '绝弦', '西风长枪']
},
{
version: '2.0',
half: '下半',
from: '2021-08-10 18:00:00',
to: '2021-08-31 14:59:59',
char5: ['宵宫'],
char4: ['早柚', '迪奥娜', '辛焱'],
weapon5: ['天空之刃', '飞雷之弦振'],
weapon4: ['祭礼剑', '祭礼残章', '雨裁', '西风猎弓', '匣里灭辰']
},
{
version: '2.1',
half: '上半',
from: '2021-09-01 06:00:00',
to: '2021-09-21 17:59:59',
char5: ['雷电将军'],
char4: ['九条裟罗', '香菱', '砂糖'],
weapon5: ['无工之剑', '薙草之稻光'],
weapon4: ['匣里龙吟', '流浪乐章', '钟剑', '祭礼弓', '西风长枪']
},
{
version: '2.1',
half: '下半',
from: '2021-09-21 18:00:00',
to: '2021-10-12 14:59:59',
char5: ['珊瑚宫心海'],
char4: ['罗莎莉亚', '北斗', '行秋'],
weapon5: ['磐岩结绿', '不灭月华'],
weapon4: ['笛剑', '西风秘典', '西风大剑', '绝弦', '匣里灭辰']
},
{
version: '2.2',
half: '上半',
from: '2021-10-13 06:00:00',
to: '2021-11-02 17:59:59',
char5: ['达达利亚'],
char4: ['凝光', '重云', '烟绯'],
weapon5: ['尘世之锁', '冬极白星'],
weapon4: ['西风剑', '昭心', '恶王丸', '弓藏', '西风长枪']
},
{
version: '2.2',
half: '下半',
from: '2021-11-02 18:00:00',
to: '2021-11-23 14:59:59',
char5: ['胡桃'],
char4: ['托马', '迪奥娜', '早柚'],
weapon5: ['终末嗟叹之诗', '护摩之杖'],
weapon4: ['祭礼剑', '流浪乐章', '雨裁', '曚云之月', '断浪长鳍']
},
{
version: '2.3',
half: '上半',
from: '2021-11-24 06:00:00',
to: '2021-12-14 17:59:59',
char5: ['阿贝多', '优菈'],
char4: ['班尼特', '诺艾尔', '罗莎莉亚'],
weapon5: ['苍古自由之誓', '松籁响起之时'],
weapon4: ['匣里龙吟', '暗巷的酒与诗', '祭礼大剑', '暗巷猎手', '匣里灭辰']
},
{
version: '2.3',
half: '下半',
from: '2021-12-14 18:00:00',
to: '2022-01-04 14:59:59',
char5: ['荒泷一斗'],
char4: ['五郎', '芭芭拉', '香菱'],
weapon5: ['赤角石溃杵', '天空之翼'],
weapon4: ['暗巷闪光', '祭礼残章', '钟剑', '幽夜华尔兹', '西风长枪']
},
{
version: '2.4',
half: '上半',
from: '2022-01-05 06:00:00',
to: '2022-01-25 17:59:59',
char5: ['申鹤', '魈'],
char4: ['云堇', '凝光', '重云'],
weapon5: ['息灾', '和璞鸢'],
weapon4: ['笛剑', '流浪乐章', '西风大剑', '西风猎弓', '千岩长枪']
},
{
version: '2.4',
half: '下半',
from: '2022-01-25 18:00:00',
to: '2022-02-15 14:59:59',
char5: ['钟离', '甘雨'],
char4: ['行秋', '北斗', '烟绯'],
weapon5: ['阿莫斯之弓', '贯虹之槊'],
weapon4: ['西风剑', '西风秘典', '千岩古剑', '祭礼弓', '匣里灭辰']
},
{
version: '2.5',
half: '上半',
from: '2022-02-16 06:00:00',
to: '2022-03-08 17:59:59',
char5: ['八重神子'],
char4: ['托马', '菲谢尔', '迪奥娜'],
weapon5: ['磐岩结绿', '神乐之真意'],
weapon4: ['祭礼剑', '昭心', '雨裁', '绝弦', '断浪长鳍']
},
{
version: '2.5',
half: '下半',
from: '2022-03-08 18:00:00',
to: '2022-03-29 14:59:59',
char5: ['雷电将军', '珊瑚宫心海'],
char4: ['班尼特', '辛焱', '九条裟罗'],
weapon5: ['不灭月华', '薙草之稻光'],
weapon4: ['匣里龙吟', '恶王丸', '祭礼残章', '曚云之月', '西风长枪']
},
{
version: '2.6',
half: '上半',
from: '2022-03-30 06:00:00',
to: '2022-04-19 17:59:59',
char5: ['神里绫人', '温迪'],
char4: ['砂糖', '香菱', '云堇'],
weapon5: ['波乱月白经津', '终末嗟叹之诗'],
weapon4: ['笛剑', '流浪乐章', '祭礼大剑', '弓藏', '匣里灭辰']
},
{
version: '2.6',
half: '下半',
from: '2022-04-19 18:00:00',
to: '2022-05-31 05:59:59',
char5: ['神里绫华'],
char4: ['早柚', '雷泽', '罗莎莉亚'],
weapon5: ['雾切之回光', '无工之剑'],
weapon4: ['西风剑', '西风秘典', '钟剑', '西风猎弓', '西风长枪']
},
{
version: '2.7',
half: '上半',
from: '2022-05-31 06:00:00',
to: '2022-06-21 17:59:59',
char5: ['夜兰', '魈'],
char4: ['诺艾尔', '芭芭拉', '烟绯'],
weapon5: ['若水', '和璞鸢'],
weapon4: ['祭礼剑', '昭心', '西风大剑', '祭礼弓', '千岩长枪']
},
{
version: '2.7',
half: '下半',
from: '2022-06-21 18:00:00',
to: '2022-07-12 14:59:59',
char5: ['荒泷一斗'],
char4: ['五郎', '久岐忍', '重云'],
weapon5: ['尘世之锁', '赤角石溃杵'],
weapon4: ['匣里龙吟', '祭礼残章', '千岩古剑', '绝弦', '匣里灭辰']
},
{
version: '2.8',
half: '上半',
from: '2022-07-13 06:00:00',
to: '2022-08-02 17:59:59',
char5: ['枫原万叶', '可莉'],
char4: ['鹿野院平藏', '托马', '凝光'],
weapon5: ['苍古自由之誓', '四风原典'],
weapon4: ['暗巷闪光', '流浪乐章', '雨裁', '幽夜华尔兹', '西风长枪']
},
{
version: '2.8',
half: '下半',
from: '2022-08-02 18:00:00',
to: '2022-08-23 14:59:59',
char5: ['宵宫'],
char4: ['云堇', '辛焱', '班尼特'],
weapon5: ['斫峰之刃', '飞雷之弦振'],
weapon4: ['笛剑', '暗巷的酒与诗', '祭礼大剑', '暗巷猎手', '匣里灭辰']
},
{
version: '3.0',
half: '上半',
from: '2022-08-24 06:00:00',
to: '2022-09-09 17:59:59',
char5: ['提纳里', '钟离'],
char4: ['柯莱', '迪奥娜', '菲谢尔'],
weapon5: ['猎人之径', '贯虹之槊'],
weapon4: ['西风剑', '西风秘典', '钟剑', '绝弦', '西风长枪']
},
{
version: '3.0',
half: '下半',
from: '2022-09-09 18:00:00',
to: '2022-09-27 14:59:59',
char5: ['甘雨', '珊瑚宫心海'],
char4: ['多莉', '砂糖', '行秋'],
weapon5: ['不灭月华', '阿莫斯之弓'],
weapon4: ['祭礼剑', '昭心', '西风大剑', '弓藏', '匣里灭辰']
},
{
version: '3.1',
half: '上半',
from: '2022-09-28 06:00:00',
to: '2022-10-14 17:59:59',
char5: ['赛诺', '温迪'],
char4: ['坎蒂丝', '久岐忍', '早柚'],
weapon5: ['终末嗟叹之诗', '赤沙之杖'],
weapon4: ['匣里龙吟', '祭礼残章', '玛海菈的水色', '西风猎弓', '西风长枪']
},
{
version: '3.1',
half: '下半',
from: '2022-10-14 18:00:00',
to: '2022-11-01 14:59:59',
char5: ['妮露', '阿贝多'],
char4: ['北斗', '芭芭拉', '香菱'],
weapon5: ['圣显之钥', '磐岩结绿'],
weapon4: ['西福斯的月光', '流浪的晚星', '雨裁', '祭礼弓', '匣里灭辰']
},
{
version: '3.2',
half: '上半',
from: '2022-11-02 06:00:00',
to: '2022-11-18 17:59:59',
char5: ['纳西妲', '宵宫'],
char4: ['雷泽', '诺艾尔', '班尼特'],
weapon5: ['千夜浮梦', '飞雷之弦振'],
weapon4: ['笛剑', '流浪乐章', '祭礼大剑', '弓藏', '西风长枪']
},
{
version: '3.2',
half: '下半',
from: '2022-11-18 18:00:00',
to: '2022-12-06 14:59:59',
char5: ['八重神子', '达达利亚'],
char4: ['莱依拉', '托马', '鹿野院平藏'],
weapon5: ['神乐之真意', '冬极白星'],
weapon4: ['西风剑', '西风秘典', '钟剑', '绝弦', '匣里灭辰']
},
{
version: '3.3',
half: '上半',
from: '2022-12-07 06:00:00',
to: '2022-12-27 17:59:59',
char5: ['流浪者', '荒泷一斗'],
char4: ['珐露珊', '五郎', '烟绯'],
weapon5: ['图莱杜拉的回忆', '赤角石溃杵'],
weapon4: ['祭礼剑', '昭心', '西风大剑', '西风猎弓', '断浪长鳍']
},
{
version: '3.3',
half: '下半',
from: '2022-12-27 18:00:00',
to: '2023-01-17 14:59:59',
char5: ['雷电将军', '神里绫人'],
char4: ['罗莎莉亚', '早柚', '九条裟罗'],
weapon5: ['波乱月白经津', '薙草之稻光'],
weapon4: ['匣里龙吟', '祭礼残章', '恶王丸', '曚云之月', '西风长枪']
},
{
version: '3.4',
half: '上半',
from: '2023-01-18 06:00:00',
to: '2023-02-07 17:59:59',
char5: ['艾尔海森', '魈'],
char4: ['瑶瑶', '云堇', '辛焱'],
weapon5: ['裁叶萃光', '和璞鸢'],
weapon4: ['笛剑', '流浪乐章', '雨裁', '祭礼弓', '千岩长枪']
},
{
version: '3.4',
half: '下半',
from: '2023-02-07 18:00:00',
to: '2023-02-28 14:59:59',
char5: ['胡桃', '夜兰'],
char4: ['行秋', '凝光', '北斗'],
weapon5: ['若水', '护摩之杖'],
weapon4: ['西风剑', '西风秘典', '千岩古剑', '弓藏', '匣里灭辰']
}
]

View File

@ -26,6 +26,8 @@ const attr = function (key, start, _step) {
}
}
let ids = {}
for (let type in weaponType) {
// calc
let typeCalc = await Data.importDefault(`resources/meta/weapon/${type}/calc.js`)
@ -35,7 +37,13 @@ for (let type in weaponType) {
// data
let typeData = await Data.readJSON(`resources/meta/weapon/${type}/data.json`)
lodash.forEach(typeData, (ds) => {
let id = ds.id.replace('n', '') * 1
if (ids[id]) {
console.log(ds.id, id)
}
ids[id] = true
data[ds.name] = {
id,
name: ds.name,
type,
star: ds.star

View File

@ -8,16 +8,16 @@ export const weaponType = {
export const abbr = {
磐岩结绿: '绿剑',
赤角石溃杵: '赤角',
终末嗟叹之诗: '终末',
松籁响起之时: '松籁',
苍古自由之誓: '苍古',
赤角石溃杵: '赤角',
终末嗟叹之诗: '终末之诗',
松籁响起之时: '松籁之时',
苍古自由之誓: '苍古之誓',
阿莫斯之弓: '阿莫斯',
雾切之回光: '雾切',
飞雷之弦振: '飞雷',
薙草之稻光: '薙刀',
神乐之真意: '神乐铃',
波乱月白经津: '波乱',
波乱月白经津: '波乱',
笼钓瓶一心: '妖刀',
幽夜华尔兹: '幽夜弓',
雪葬的星银: '雪葬星银',
@ -27,8 +27,8 @@ export const abbr = {
桂木斩长正: '桂木刀',
证誓之明瞳: '证誓明瞳',
嘟嘟可故事集: '嘟嘟可',
辰砂之纺锤: '辰砂',
讨龙英杰谭: '讨龙',
辰砂之纺锤: '辰砂纺锤',
讨龙英杰谭: '讨龙',
神射手之誓: '神射手',
'「渔获」': '渔获',
暗巷的酒与诗: '暗巷书',
@ -40,7 +40,8 @@ export const abbr = {
异世界行记: '异世行记',
西福斯的月光: '西福斯',
玛海菈的水色: '玛海菈',
图莱杜拉的回忆: '铃铛'
图莱杜拉的回忆: '图莱杜拉',
流浪的晚星: '流浪晚星'
}
export const alias = {