feat: gacha
|
|
@ -1,10 +1,9 @@
|
||||||
import { ZZZPlugin } from '../lib/plugin.js';
|
import { ZZZPlugin } from '../lib/plugin.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import render from '../lib/render.js';
|
import render from '../lib/render.js';
|
||||||
import { ZZZNoteResp } from '../model/note.js';
|
|
||||||
import { rulePrefix } from '../lib/common.js';
|
import { rulePrefix } from '../lib/common.js';
|
||||||
import { getAuthKey, getStoken } from '../lib/authkey.js';
|
import { getAuthKey } from '../lib/authkey.js';
|
||||||
import { updateGachaLog } from '../lib/gacha.js';
|
import { anaylizeGachaLog, updateGachaLog } from '../lib/gacha.js';
|
||||||
|
|
||||||
export class GachaLog extends ZZZPlugin {
|
export class GachaLog extends ZZZPlugin {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -26,6 +25,10 @@ export class GachaLog extends ZZZPlugin {
|
||||||
reg: `^${rulePrefix}抽卡帮助$`,
|
reg: `^${rulePrefix}抽卡帮助$`,
|
||||||
fnc: 'gachaHelp',
|
fnc: 'gachaHelp',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: `^${rulePrefix}抽卡分析$`,
|
||||||
|
fnc: 'gachaLogAnalysis',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -87,4 +90,21 @@ export class GachaLog extends ZZZPlugin {
|
||||||
await this.reply(msg);
|
await this.reply(msg);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async gachaLogAnalysis() {
|
||||||
|
const uid = await this.getUID();
|
||||||
|
if (!uid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
await this.getPlayerInfo();
|
||||||
|
const data = await anaylizeGachaLog(uid);
|
||||||
|
if (!data) {
|
||||||
|
await this.reply('未查询到抽卡记录,请先发送抽卡链接');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const result = {
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
await render(this.e, 'gachalog/index.html', result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import settings from '../settings.js';
|
import settings from '../settings.js';
|
||||||
import PartnerId2SpriteId from '../../resources/map/PartnerId2SpriteId.json';
|
import PartnerId2SpriteId from '../../resources/map/PartnerId2SpriteId.json?json';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {boolean} full 显示全称
|
* @param {boolean} full 显示全称
|
||||||
* @param {boolean} en 是否为英文
|
* @param {boolean} en 是否为英文
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const IDToCharName = (id, full = true, en = false) => {
|
export const IDToCharName = (id, full = true, en = false) => {
|
||||||
const data = PartnerId2SpriteId?.[id];
|
const data = PartnerId2SpriteId?.[id];
|
||||||
|
|
@ -19,7 +19,7 @@ export const IDToCharName = (id, full = true, en = false) => {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const IDToCharSprite = id => {
|
export const IDToCharSprite = id => {
|
||||||
const data = PartnerId2SpriteId?.[id];
|
const data = PartnerId2SpriteId?.[id];
|
||||||
|
|
@ -29,7 +29,7 @@ export const IDToCharSprite = id => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const charNameToID = name => {
|
export const charNameToID = name => {
|
||||||
for (const [id, data] of Object.entries(PartnerId2SpriteId)) {
|
for (const [id, data] of Object.entries(PartnerId2SpriteId)) {
|
||||||
|
|
@ -40,7 +40,7 @@ export const charNameToID = name => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const charNameToSprite = name => {
|
export const charNameToSprite = name => {
|
||||||
for (const [_id, data] of Object.entries(PartnerId2SpriteId)) {
|
for (const [_id, data] of Object.entries(PartnerId2SpriteId)) {
|
||||||
|
|
@ -51,19 +51,20 @@ export const charNameToSprite = name => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} atlas
|
* @param {string} atlas
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const atlasToName = atlas => {
|
export const atlasToName = _atlas => {
|
||||||
const atlas = settings.getConfig('atlas');
|
const atlas = settings.getConfig('atlas');
|
||||||
for (const [id, data] of Object.entries(atlas)) {
|
for (const [id, data] of Object.entries(atlas)) {
|
||||||
if (data.includes(atlas)) return id;
|
if (id === _atlas) return id;
|
||||||
|
if (data.includes(_atlas)) return id;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} atlas
|
* @param {string} atlas
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const atlasToSprite = atlas => {
|
export const atlasToSprite = atlas => {
|
||||||
const atlas = settings.getConfig('atlas');
|
const atlas = settings.getConfig('atlas');
|
||||||
|
|
@ -75,7 +76,7 @@ export const atlasToSprite = atlas => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @returns string
|
* @returns string | null
|
||||||
*/
|
*/
|
||||||
export const atlasToID = name => {
|
export const atlasToID = name => {
|
||||||
const atlas = settings.getConfig('atlas');
|
const atlas = settings.getConfig('atlas');
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import WeaponId2Sprite from '../../resources/map/WeaponId2Sprite.json';
|
import WeaponId2Sprite from '../../resources/map/WeaponId2Sprite.json?json';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
|
|
|
||||||
101
lib/gacha.js
|
|
@ -127,3 +127,104 @@ export async function updateGachaLog(authKey, uid) {
|
||||||
saveGachaLog(uid, previousLog);
|
saveGachaLog(uid, previousLog);
|
||||||
return previousLog;
|
return previousLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RANK_MAP = {
|
||||||
|
4: 'S',
|
||||||
|
3: 'A',
|
||||||
|
2: 'B',
|
||||||
|
};
|
||||||
|
const HOMO_TAG = ['非到极致', '运气不好', '平稳保底', '小欧一把', '欧狗在此'];
|
||||||
|
const NORMAL_LIST = [
|
||||||
|
'「11号」',
|
||||||
|
'猫又',
|
||||||
|
'莱卡恩',
|
||||||
|
'丽娜',
|
||||||
|
'格莉丝',
|
||||||
|
'珂蕾妲',
|
||||||
|
'拘缚者',
|
||||||
|
'燃狱齿轮',
|
||||||
|
'嵌合编译器',
|
||||||
|
'钢铁肉垫',
|
||||||
|
'硫磺石',
|
||||||
|
'啜泣摇篮',
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function anaylizeGachaLog(uid) {
|
||||||
|
const savedData = getGachaLog(uid);
|
||||||
|
if (!savedData) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const result = [];
|
||||||
|
for (const name in savedData) {
|
||||||
|
const data = savedData[name].map(
|
||||||
|
item =>
|
||||||
|
new SingleGachaLog(
|
||||||
|
item.uid,
|
||||||
|
item.gacha_id,
|
||||||
|
item.gacha_type,
|
||||||
|
item.item_id,
|
||||||
|
item.count,
|
||||||
|
item.time,
|
||||||
|
item.name,
|
||||||
|
item.lang,
|
||||||
|
item.item_type,
|
||||||
|
item.rank_type,
|
||||||
|
item.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const earliest = data[data.length - 1];
|
||||||
|
const latest = data[0];
|
||||||
|
const list = [];
|
||||||
|
let lastFive = `${data.length}`;
|
||||||
|
let preIndex = 0;
|
||||||
|
let luck = 0;
|
||||||
|
data.forEach((item, i) => {
|
||||||
|
let isUp = true;
|
||||||
|
if (item.rank_type === '4') {
|
||||||
|
if (NORMAL_LIST.includes(item.name)) {
|
||||||
|
isUp = false;
|
||||||
|
}
|
||||||
|
if (lastFive === `${data.length}`) {
|
||||||
|
lastFive = `${i + 1}`;
|
||||||
|
}
|
||||||
|
list.push({
|
||||||
|
...item,
|
||||||
|
rank_type_label: RANK_MAP[item.rank_type],
|
||||||
|
isUp: isUp,
|
||||||
|
});
|
||||||
|
if (list.length > 0) {
|
||||||
|
list[list.length - 1]['totalCount'] = i - preIndex;
|
||||||
|
}
|
||||||
|
preIndex = i;
|
||||||
|
}
|
||||||
|
if (i === data.length - 1 && list.length > 0) {
|
||||||
|
list[list.length - 1]['totalCount'] = i - preIndex;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const upCount = list.length;
|
||||||
|
const totalCount = data.length;
|
||||||
|
const fiveStars = list.length;
|
||||||
|
logger.mark('fiveStars', fiveStars);
|
||||||
|
logger.mark('totalCount', totalCount);
|
||||||
|
let timeRange = '还没有抽卡';
|
||||||
|
let avgFive = '-';
|
||||||
|
let avgUp = '-';
|
||||||
|
if (data.length > 0) {
|
||||||
|
timeRange = `${latest.time} ~ ${earliest.time}`;
|
||||||
|
if (fiveStars > 0) avgFive = (totalCount / fiveStars).toFixed(1);
|
||||||
|
if (upCount > 0) avgUp = (totalCount / upCount).toFixed(1);
|
||||||
|
}
|
||||||
|
result.push({
|
||||||
|
name,
|
||||||
|
timeRange,
|
||||||
|
list,
|
||||||
|
lastFive,
|
||||||
|
fiveStars,
|
||||||
|
upCount,
|
||||||
|
totalCount,
|
||||||
|
avgFive,
|
||||||
|
avgUp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export class SingleGachaLog {
|
||||||
equals(item) {
|
equals(item) {
|
||||||
return (
|
return (
|
||||||
this.uid === item.uid &&
|
this.uid === item.uid &&
|
||||||
this.gacha_id === item.gacha_id &&
|
this.id === item.id &&
|
||||||
this.gacha_type === this.gacha_type
|
this.gacha_type === this.gacha_type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
resources/gachalog/images/IconTabUP.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
resources/gachalog/images/RANK_A.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
resources/gachalog/images/RANK_B.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
resources/gachalog/images/RANK_S.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
resources/gachalog/images/bg1.png
Normal file
|
After Width: | Height: | Size: 266 KiB |
BIN
resources/gachalog/images/bg2.png
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
resources/gachalog/images/bg3.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
resources/gachalog/images/bg4.png
Normal file
|
After Width: | Height: | Size: 266 KiB |
BIN
resources/gachalog/images/emoji/1.png
Normal file
|
After Width: | Height: | Size: 400 KiB |
BIN
resources/gachalog/images/emoji/10.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
resources/gachalog/images/emoji/11.png
Normal file
|
After Width: | Height: | Size: 346 KiB |
BIN
resources/gachalog/images/emoji/12.png
Normal file
|
After Width: | Height: | Size: 345 KiB |
BIN
resources/gachalog/images/emoji/13.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
resources/gachalog/images/emoji/14.png
Normal file
|
After Width: | Height: | Size: 331 KiB |
BIN
resources/gachalog/images/emoji/15.png
Normal file
|
After Width: | Height: | Size: 276 KiB |
BIN
resources/gachalog/images/emoji/16.png
Normal file
|
After Width: | Height: | Size: 230 KiB |
BIN
resources/gachalog/images/emoji/2.png
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
resources/gachalog/images/emoji/3.png
Normal file
|
After Width: | Height: | Size: 322 KiB |
BIN
resources/gachalog/images/emoji/4.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
resources/gachalog/images/emoji/5.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
resources/gachalog/images/emoji/6.png
Normal file
|
After Width: | Height: | Size: 269 KiB |
BIN
resources/gachalog/images/emoji/7.png
Normal file
|
After Width: | Height: | Size: 335 KiB |
BIN
resources/gachalog/images/emoji/8.png
Normal file
|
After Width: | Height: | Size: 341 KiB |
BIN
resources/gachalog/images/emoji/9.png
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
resources/gachalog/images/role_square_avatar_1011.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
216
resources/gachalog/index.css
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
.card {
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
.card .user-info {
|
||||||
|
margin: 0 1em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
.card .title {
|
||||||
|
border-image-slice: 37 27 37 131 fill;
|
||||||
|
border-image-width: 1em 1em 1em 4.5em;
|
||||||
|
border-image-outset: 0em 0em 0em 0em;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
min-height: 7em;
|
||||||
|
padding: 0.7em 2.3em 0.7em 3.7em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.card .title.t1 {
|
||||||
|
border-image-source: url("./images/bg1.png");
|
||||||
|
}
|
||||||
|
.card .title.t2 {
|
||||||
|
border-image-source: url("./images/bg2.png");
|
||||||
|
}
|
||||||
|
.card .title.t3 {
|
||||||
|
border-image-source: url("./images/bg3.png");
|
||||||
|
}
|
||||||
|
.card .title.t4 {
|
||||||
|
border-image-source: url("./images/bg4.png");
|
||||||
|
}
|
||||||
|
.card .title .info {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.card .title .info .type {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 0.1em;
|
||||||
|
}
|
||||||
|
.card .title .info .type .label {
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-shadow: 0.05em 0.05em 0.03em rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
.card .title .info .type .status {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
padding: 0em 0.5em;
|
||||||
|
border-radius: 1em;
|
||||||
|
backdrop-filter: blur(0.3em);
|
||||||
|
}
|
||||||
|
.card .title .info .type .status .value {
|
||||||
|
color: rgb(128, 237, 84);
|
||||||
|
margin: 0 0.1em;
|
||||||
|
}
|
||||||
|
.card .title .info .time {
|
||||||
|
font-size: 0.6em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
}
|
||||||
|
.card .title .info .analysis {
|
||||||
|
width: 15em;
|
||||||
|
display: flex;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-top: 0.3em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
}
|
||||||
|
.card .title .info .analysis .item {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.card .title .info .analysis .item .value {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
.card .title .info .analysis .item .label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
}
|
||||||
|
.card .title .comment {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.card .title .comment .icon {
|
||||||
|
width: 4.5em;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.card .title .comment.e1 .icon {
|
||||||
|
background-image: url("./images/emoji/1.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e2 .icon {
|
||||||
|
background-image: url("./images/emoji/2.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e3 .icon {
|
||||||
|
background-image: url("./images/emoji/3.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e4 .icon {
|
||||||
|
background-image: url("./images/emoji/4.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e5 .icon {
|
||||||
|
background-image: url("./images/emoji/5.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e6 .icon {
|
||||||
|
background-image: url("./images/emoji/6.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e7 .icon {
|
||||||
|
background-image: url("./images/emoji/7.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e8 .icon {
|
||||||
|
background-image: url("./images/emoji/8.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e9 .icon {
|
||||||
|
background-image: url("./images/emoji/9.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e10 .icon {
|
||||||
|
background-image: url("./images/emoji/10.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e11 .icon {
|
||||||
|
background-image: url("./images/emoji/11.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e12 .icon {
|
||||||
|
background-image: url("./images/emoji/12.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e13 .icon {
|
||||||
|
background-image: url("./images/emoji/13.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e14 .icon {
|
||||||
|
background-image: url("./images/emoji/14.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e15 .icon {
|
||||||
|
background-image: url("./images/emoji/15.png");
|
||||||
|
}
|
||||||
|
.card .title .comment.e16 .icon {
|
||||||
|
background-image: url("./images/emoji/16.png");
|
||||||
|
}
|
||||||
|
.card .title .comment .label {
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.card .list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1em;
|
||||||
|
padding: 0.5em 1.7em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
.card .list .item {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0.2em solid #000000;
|
||||||
|
}
|
||||||
|
.card .list .item.up::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.1em;
|
||||||
|
left: 0.2em;
|
||||||
|
width: 1.7em;
|
||||||
|
height: 1.7em;
|
||||||
|
background: url("./images/IconTabUP.png") no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.card .list .item .rank {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.2em;
|
||||||
|
right: 0.2em;
|
||||||
|
width: 1.5em;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background: url("./images/RANK_A.png") no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
color: white;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.card .list .item.rankS .rank {
|
||||||
|
background-image: url("./images/RANK_S.png");
|
||||||
|
}
|
||||||
|
.card .list .item.rankB .rank {
|
||||||
|
background-image: url("./images/RANK_B.png");
|
||||||
|
}
|
||||||
|
.card .list .item .image {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1.5;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
}
|
||||||
|
.card .list .item .image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.card .list .item .count {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
backdrop-filter: blur(0.3em);
|
||||||
|
border-top-right-radius: 0.5em;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.3em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*# sourceMappingURL=index.css.map */
|
||||||
54
resources/gachalog/index.html
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
{{extend defaultLayout}}
|
||||||
|
|
||||||
|
{{block 'css'}}
|
||||||
|
<link rel="stylesheet" href="{{@sys.currentPath}}/index.css">
|
||||||
|
{{/block}}
|
||||||
|
|
||||||
|
{{block 'main'}}
|
||||||
|
<div class="card">
|
||||||
|
{{include sys.playerInfo}}
|
||||||
|
{{each data item i}}
|
||||||
|
<div class="title t{{i+1}}">
|
||||||
|
<div class="info">
|
||||||
|
<div class="type">
|
||||||
|
<div class="label">{{item.name}}</div>
|
||||||
|
<div class="status">已<span class="value">{{item.lastFive}}</span>抽未出S级</div>
|
||||||
|
</div>
|
||||||
|
<div class="time">{{item.timeRange}}</div>
|
||||||
|
<div class="analysis">
|
||||||
|
<div class="item">
|
||||||
|
<div class="value">{{item.avgFive}}</div>
|
||||||
|
<div class="label">平均出金</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="value">{{item.avgUp}}</div>
|
||||||
|
<div class="label">平均UP</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="value">{{item.totalCount}}</div>
|
||||||
|
<div class="label">抽卡总数</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="comment e1">
|
||||||
|
<div class="icon"></div>
|
||||||
|
<div class="label">平稳保底</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
<div class="list">
|
||||||
|
{{each item.list inv j}}
|
||||||
|
<div class="item rankS {{inv.isUp && 'up'}}">
|
||||||
|
<div class="rank rankS"></div>
|
||||||
|
<div class="image">
|
||||||
|
<img src="./images/role_square_avatar_1011.png" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="count">{{inv?.totalCount || '-'}}抽</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/block}}
|
||||||
172
resources/gachalog/index.scss
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
.card {
|
||||||
|
margin: 0 1em;
|
||||||
|
.user-info {
|
||||||
|
margin: 0 1em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
border-image-slice: 37 27 37 131 fill;
|
||||||
|
border-image-width: 1em 1em 1em 4.5em;
|
||||||
|
border-image-outset: 0em 0em 0em 0em;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
min-height: 7em;
|
||||||
|
padding: 0.7em 2.3em 0.7em 3.7em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
@for $i from 1 through 4 {
|
||||||
|
&.t#{$i} {
|
||||||
|
border-image-source: url('./images/bg#{$i}.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
.type {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 0.1em;
|
||||||
|
.label {
|
||||||
|
font-size: 1.5em;
|
||||||
|
text-shadow: 0.05em 0.05em 0.03em rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
padding: 0em 0.5em;
|
||||||
|
border-radius: 1em;
|
||||||
|
backdrop-filter: blur(0.3em);
|
||||||
|
.value {
|
||||||
|
color: rgb(128, 237, 84);
|
||||||
|
margin: 0 0.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.time {
|
||||||
|
font-size: 0.6em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
}
|
||||||
|
.analysis {
|
||||||
|
width: 15em;
|
||||||
|
display: flex;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-top: 0.3em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
border-radius: 2em;
|
||||||
|
padding: 0.1em 0.5em;
|
||||||
|
.item {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
.value {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #e4e4e4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment {
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
.icon {
|
||||||
|
width: 4.5em;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: contain;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
@for $i from 1 through 16 {
|
||||||
|
&.e#{$i} {
|
||||||
|
.icon {
|
||||||
|
background-image: url('./images/emoji/#{$i}.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 1em;
|
||||||
|
padding: 0.5em 1.7em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
.item {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 0.2em solid #000000;
|
||||||
|
&.up {
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.1em;
|
||||||
|
left: 0.2em;
|
||||||
|
width: 1.7em;
|
||||||
|
height: 1.7em;
|
||||||
|
background: url('./images/IconTabUP.png') no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rank {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.2em;
|
||||||
|
right: 0.2em;
|
||||||
|
width: 1.5em;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
background: url('./images/RANK_A.png') no-repeat center center;
|
||||||
|
background-size: contain;
|
||||||
|
color: white;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
&.rankS {
|
||||||
|
.rank {
|
||||||
|
background-image: url('./images/RANK_S.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.rankB {
|
||||||
|
.rank {
|
||||||
|
background-image: url('./images/RANK_B.png');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1.5;
|
||||||
|
background-color: #e2e2e2;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
backdrop-filter: blur(0.3em);
|
||||||
|
border-top-right-radius: 0.5em;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 0.3em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||