mirror of
https://github.com/ZZZure/ZZZ-Plugin.git
synced 2025-12-16 13:17:32 +00:00
feat: 月报统计(总);查询的月报数据自动保存
This commit is contained in:
parent
9f8d5dc1f6
commit
dcf04636c2
12 changed files with 739 additions and 62 deletions
17
apps/help.js
17
apps/help.js
|
|
@ -41,8 +41,8 @@ const helpData = [
|
||||||
commands: ['note', '便签', '便笺', '体力', '每日'],
|
commands: ['note', '便签', '便笺', '体力', '每日'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '月报/菲林/邦布券/母带统计',
|
title: '单月月报/菲林/邦布券/母带统计',
|
||||||
desc: '查看菲林、邦布券、加密/原装母带的收入情况。其中,参数可以为空(默认为本月),也可以为年份月份或者月份,例如:2024年9月、9月、上月',
|
desc: '查看单月菲林、邦布券、加密/原装母带的收入情况(查询结果也会写入数据库)。其中,参数可以为空(默认为本月),也可以为年份月份或者月份,例如:2024年9月、9月、上月',
|
||||||
needCK: true,
|
needCK: true,
|
||||||
needSK: false,
|
needSK: false,
|
||||||
commands: [
|
commands: [
|
||||||
|
|
@ -53,6 +53,19 @@ const helpData = [
|
||||||
'月报+[参数]',
|
'月报+[参数]',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '查看全部月报/菲林/邦布券/母带统计',
|
||||||
|
desc: '查看菲林、邦布券、加密/原装母带的收入总情况(会查询全部可查询月份+已保存数据,新旧数据会进行合并)。',
|
||||||
|
needCK: true,
|
||||||
|
needSK: false,
|
||||||
|
commands: [
|
||||||
|
'monthly统计',
|
||||||
|
'菲林统计',
|
||||||
|
'邦布券统计',
|
||||||
|
'收入统计',
|
||||||
|
'月报统计',
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { Monthly } from '../model/monthly.js';
|
||||||
import settings from '../lib/settings.js';
|
import settings from '../lib/settings.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { rulePrefix } from '../lib/common.js';
|
import { rulePrefix } from '../lib/common.js';
|
||||||
|
import { getMonthly, getMonthlyCollect } from '../lib/monthly.js';
|
||||||
|
|
||||||
export class Note extends ZZZPlugin {
|
export class Note extends ZZZPlugin {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
@ -16,6 +17,10 @@ export class Note extends ZZZPlugin {
|
||||||
reg: `${rulePrefix}(monthly|菲林|邦布券|收入|月报)((\\d{4})年)?((\\d{1,2}|上)月)?$`,
|
reg: `${rulePrefix}(monthly|菲林|邦布券|收入|月报)((\\d{4})年)?((\\d{1,2}|上)月)?$`,
|
||||||
fnc: 'monthly',
|
fnc: 'monthly',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
reg: `${rulePrefix}(monthly|菲林|邦布券|收入|月报)统计$`,
|
||||||
|
fnc: 'monthlyCollect',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -30,19 +35,15 @@ export class Note extends ZZZPlugin {
|
||||||
}
|
}
|
||||||
let year = match[3];
|
let year = match[3];
|
||||||
let month = match[5];
|
let month = match[5];
|
||||||
logger.debug(this.getDateString(year, month));
|
|
||||||
const { api } = await this.getAPI();
|
const { api } = await this.getAPI();
|
||||||
await this.getPlayerInfo();
|
await this.getPlayerInfo();
|
||||||
const monthlyResponse = await api
|
const monthlyResponse = await getMonthly(
|
||||||
.getFinalData('zzzMonthly', {
|
api,
|
||||||
query: {
|
this.getDateString(year, month)
|
||||||
month: this.getDateString(year, month),
|
).catch(e => {
|
||||||
},
|
this.reply(e.message);
|
||||||
})
|
throw e;
|
||||||
.catch(e => {
|
});
|
||||||
this.reply(e.message);
|
|
||||||
throw e;
|
|
||||||
});
|
|
||||||
if (!monthlyResponse) {
|
if (!monthlyResponse) {
|
||||||
await this.reply('获取月报数据失败,请检查日期是否正确');
|
await this.reply('获取月报数据失败,请检查日期是否正确');
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -58,6 +59,49 @@ export class Note extends ZZZPlugin {
|
||||||
await this.render('monthly/index.html', finalData);
|
await this.render('monthly/index.html', finalData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async monthlyCollect() {
|
||||||
|
const { api } = await this.getAPI();
|
||||||
|
await this.getPlayerInfo();
|
||||||
|
const collect = await getMonthlyCollect(api).catch(e => {
|
||||||
|
this.reply(e.message);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!collect) {
|
||||||
|
await this.reply('获取月报数据失败');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const collectData = collect.map(item => new Monthly(item));
|
||||||
|
|
||||||
|
const start = collectData[collectData.length - 1]?.query_full_date;
|
||||||
|
|
||||||
|
const end = collectData[0]?.query_full_date;
|
||||||
|
|
||||||
|
const total = {
|
||||||
|
poly: collectData.reduce(
|
||||||
|
(acc, cur) => acc + cur.month_data.overview.poly,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
tape: collectData.reduce(
|
||||||
|
(acc, cur) => acc + cur.month_data.overview.tape,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
boopon: collectData.reduce(
|
||||||
|
(acc, cur) => acc + cur.month_data.overview.boopon,
|
||||||
|
0
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const finalData = {
|
||||||
|
collect: collectData,
|
||||||
|
range: `${start}~${end}`,
|
||||||
|
total,
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.render('monthly/collect.html', finalData);
|
||||||
|
}
|
||||||
|
|
||||||
getDateString(year, month) {
|
getDateString(year, month) {
|
||||||
let _year = +year,
|
let _year = +year,
|
||||||
_month = +month;
|
_month = +month;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
import { ZZZPlugin } from '../lib/plugin.js';
|
import { ZZZPlugin } from '../lib/plugin.js';
|
||||||
import { getPanelList, refreshPanel, getPanel } from '../lib/avatar.js';
|
import {
|
||||||
|
getPanelList,
|
||||||
|
refreshPanel as refreshPanelFunction,
|
||||||
|
getPanel,
|
||||||
|
} from '../lib/avatar.js';
|
||||||
import settings from '../lib/settings.js';
|
import settings from '../lib/settings.js';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { rulePrefix } from '../lib/common.js';
|
import { rulePrefix } from '../lib/common.js';
|
||||||
|
|
@ -53,7 +57,7 @@ export class Panel extends ZZZPlugin {
|
||||||
await redis.set(`ZZZ:PANEL:${uid}:LASTTIME`, Date.now());
|
await redis.set(`ZZZ:PANEL:${uid}:LASTTIME`, Date.now());
|
||||||
await this.reply('正在刷新面板列表,请稍候...');
|
await this.reply('正在刷新面板列表,请稍候...');
|
||||||
await this.getPlayerInfo();
|
await this.getPlayerInfo();
|
||||||
const result = await refreshPanel(api, uid).catch(e => {
|
const result = await refreshPanelFunction(api).catch(e => {
|
||||||
this.reply(e.message);
|
this.reply(e.message);
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,11 @@ export const getAvatarInfoList = async (api, origin = false) => {
|
||||||
/**
|
/**
|
||||||
* 刷新面板
|
* 刷新面板
|
||||||
* @param {MysZZZApi} api
|
* @param {MysZZZApi} api
|
||||||
* @param {string} uid
|
|
||||||
* @returns {Promise<ZZZAvatarInfo[] | null>}
|
* @returns {Promise<ZZZAvatarInfo[] | null>}
|
||||||
*/
|
*/
|
||||||
export const refreshPanel = async (api, uid) => {
|
export const refreshPanel = async api => {
|
||||||
// 获取已保存数据
|
// 获取已保存数据
|
||||||
const originData = getPanelData(uid);
|
const originData = getPanelData(api.uid);
|
||||||
// 获取新数据
|
// 获取新数据
|
||||||
const newData = await getAvatarInfoList(api, true);
|
const newData = await getAvatarInfoList(api, true);
|
||||||
if (!newData) return null;
|
if (!newData) return null;
|
||||||
|
|
@ -73,7 +72,7 @@ export const refreshPanel = async (api, uid) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 保存数据
|
// 保存数据
|
||||||
savePanelData(uid, finalData);
|
savePanelData(api.uid, finalData);
|
||||||
// 格式化数据
|
// 格式化数据
|
||||||
finalData.forEach(item => {
|
finalData.forEach(item => {
|
||||||
item.isNew = !!newData.find(i => i.id === item.id);
|
item.isNew = !!newData.find(i => i.id === item.id);
|
||||||
|
|
|
||||||
16
lib/db.js
16
lib/db.js
|
|
@ -31,3 +31,19 @@ export function getPanelData(uid) {
|
||||||
export function savePanelData(uid, data) {
|
export function savePanelData(uid, data) {
|
||||||
setDB('panel', uid, data);
|
setDB('panel', uid, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} uid
|
||||||
|
* @returns {Array<object>}
|
||||||
|
*/
|
||||||
|
export function getMonthlyData(uid) {
|
||||||
|
return getDB('monthly', uid) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} uid
|
||||||
|
* @param {Array<object>} data
|
||||||
|
*/
|
||||||
|
export function saveMonthlyData(uid, data) {
|
||||||
|
setDB('monthly', uid, data);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { dataPath } from '../path.js';
|
||||||
export const dbPath = {
|
export const dbPath = {
|
||||||
gacha: 'gacha',
|
gacha: 'gacha',
|
||||||
panel: 'panel',
|
panel: 'panel',
|
||||||
|
monthly: 'monthly',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
63
lib/monthly.js
Normal file
63
lib/monthly.js
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { getMonthlyData, saveMonthlyData } from './db.js';
|
||||||
|
import MysZZZApi from './mysapi.js';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存月度数据
|
||||||
|
* @param {string} uid
|
||||||
|
* @param {object} newData
|
||||||
|
*/
|
||||||
|
export const saveMonthlyNewData = (uid, ...newDatas) => {
|
||||||
|
// 获取先前月度数据
|
||||||
|
const savedData = getMonthlyData(uid);
|
||||||
|
// 合并新旧数据
|
||||||
|
const mergedData = _.unionBy(newDatas, savedData, 'data_month').sort(
|
||||||
|
(a, b) => a.data_month - b.data_month
|
||||||
|
);
|
||||||
|
// 保存数据
|
||||||
|
saveMonthlyData(uid, mergedData);
|
||||||
|
return mergedData.reverse();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取月度数据
|
||||||
|
* @param {MysZZZApi} api
|
||||||
|
* @param {string} month
|
||||||
|
* @returns {Promise<object | null>}
|
||||||
|
*/
|
||||||
|
export const getMonthly = async (api, month) => {
|
||||||
|
// 获取月度数据
|
||||||
|
const data = await api.getFinalData('zzzMonthly', {
|
||||||
|
query: { month },
|
||||||
|
});
|
||||||
|
saveMonthlyNewData(api.uid, data);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 月度数据(统计)
|
||||||
|
* @param {MysZZZApi} api
|
||||||
|
* @returns {Promise<object | null>}
|
||||||
|
*/
|
||||||
|
export const getMonthlyCollect = async api => {
|
||||||
|
// 获取当前月度数据
|
||||||
|
const currentData = await getMonthly(api, '');
|
||||||
|
|
||||||
|
if (!currentData) return null;
|
||||||
|
|
||||||
|
const newDatas = [currentData];
|
||||||
|
// 获取所有可查询月份
|
||||||
|
const availableData = currentData.optional_month.filter(
|
||||||
|
month => month !== currentData.data_month
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const month of availableData) {
|
||||||
|
const data = await getMonthly(api, month);
|
||||||
|
if (data) newDatas.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并新旧数据
|
||||||
|
const mergedData = saveMonthlyNewData(api.uid, ...newDatas);
|
||||||
|
|
||||||
|
return mergedData;
|
||||||
|
};
|
||||||
|
|
@ -155,4 +155,8 @@ export class Monthly {
|
||||||
const month = +this.data_month.slice(-2);
|
const month = +this.data_month.slice(-2);
|
||||||
return `${month}月`;
|
return `${month}月`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get query_full_date() {
|
||||||
|
return `${this.data_month.slice(0, 4)}年${this.query_month}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
224
resources/monthly/collect.css
Normal file
224
resources/monthly/collect.css
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
.container {
|
||||||
|
background: url("./images/bg.png") no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
|
padding-top: 0.1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.container .lh {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 0 0 0.5em 0.5em;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
min-width: 10em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-align: center;
|
||||||
|
color: #d3d3d3;
|
||||||
|
filter: drop-shadow(0 0 0.3em #0d0d0d);
|
||||||
|
}
|
||||||
|
.container .lh::before, .container .lh::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
}
|
||||||
|
.container .lh::before {
|
||||||
|
left: -0.5em;
|
||||||
|
background: radial-gradient(circle at 0 100%, transparent 0, transparent 70%, #000 70%);
|
||||||
|
}
|
||||||
|
.container .lh::after {
|
||||||
|
right: -0.5em;
|
||||||
|
background: radial-gradient(circle at 100% 100%, transparent 0, transparent 70%, #000 70%);
|
||||||
|
}
|
||||||
|
.container .box {
|
||||||
|
margin: 5em 1em 0em 1em;
|
||||||
|
border-image-source: url("./images/container.png");
|
||||||
|
border-image-slice: 210 40 40 40 fill;
|
||||||
|
border-image-width: 6.3em 1.2em 1.2em 1.2em;
|
||||||
|
border-image-outset: 0 0 0 0;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
position: relative;
|
||||||
|
filter: drop-shadow(0.5em 0.5em 0 #000);
|
||||||
|
}
|
||||||
|
.container .box .user-info {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 2.8em 2em 1em 7em;
|
||||||
|
}
|
||||||
|
.container .box .bangboo {
|
||||||
|
position: absolute;
|
||||||
|
background: url("./images/bamboo.png") no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
width: 10.5em;
|
||||||
|
height: 10.5em;
|
||||||
|
right: 0.3em;
|
||||||
|
top: -2.5em;
|
||||||
|
}
|
||||||
|
.container .box .content {
|
||||||
|
padding: 1em 2em;
|
||||||
|
}
|
||||||
|
.container .box .content .title {
|
||||||
|
text-shadow: 1px 1px 0px #000;
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
.container .box .content .title.with-icon::after {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
background: url("./images/icon-title-deco.png") no-repeat left center;
|
||||||
|
background-size: contain;
|
||||||
|
width: 2em;
|
||||||
|
height: 1.1em;
|
||||||
|
margin-bottom: -0.05em;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox {
|
||||||
|
background: url("./images/itembox.png") no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
aspect-ratio: 2.2;
|
||||||
|
padding: 2em 1.4em 1.2em 1.4em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item {
|
||||||
|
width: 31%;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item .icon {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
margin: 1.5em;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item .icon.feilin {
|
||||||
|
background: url("./images/icon-feilin.png") no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item .icon.tape {
|
||||||
|
background: url("./images/icon-matser.png") no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item .icon.boopon {
|
||||||
|
background: url("./images/icon-bangboo.png") no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
.container .box .content .itembox .item .count {
|
||||||
|
font-size: 1.3em;
|
||||||
|
text-align: center;
|
||||||
|
color: #000;
|
||||||
|
margin-top: -0.1em;
|
||||||
|
}
|
||||||
|
.container .box .content .list {
|
||||||
|
border-image-source: url("./images/list.png");
|
||||||
|
border-image-slice: 550 30 30 30 fill;
|
||||||
|
border-image-width: 22em 1.2em 1.2em 1.2em;
|
||||||
|
border-image-outset: 0 0 0 0;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
margin: 1em 0;
|
||||||
|
padding-bottom: 1.3em;
|
||||||
|
min-height: 25em;
|
||||||
|
}
|
||||||
|
.container .box .content .list .title {
|
||||||
|
font-size: 1.3em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item {
|
||||||
|
padding: 0.6em 1em;
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .month {
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-shadow: 1px 1px 0px #000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffcf32;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .month::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
background-color: #ffcf32;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 0.2em;
|
||||||
|
box-shadow: 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail {
|
||||||
|
display: flex;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .overview {
|
||||||
|
width: 10em;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .overview .itembox {
|
||||||
|
font-size: 0.35em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .overview .itembox .item .count {
|
||||||
|
font-size: 1.8em;
|
||||||
|
margin-top: -0.2em;
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
font-size: 0.6em;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components .item {
|
||||||
|
padding: 0.4em 0.6em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
box-shadow: 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components .item .name {
|
||||||
|
color: #e3e3e3;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components .item .value {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components .item .value .percent {
|
||||||
|
color: #989898;
|
||||||
|
}
|
||||||
|
.container .box .content .list > .item .detail .components .item .value .count {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips {
|
||||||
|
padding: 1em;
|
||||||
|
color: #dfdfdf;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
.tips ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.tips ul li {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
.tips ul li::before {
|
||||||
|
content: "*";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copyright {
|
||||||
|
background: url("./images/bottom-deco.gif") no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
|
text-shadow: 1px 1px 1px #000;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*# sourceMappingURL=collect.css.map */
|
||||||
78
resources/monthly/collect.html
Normal file
78
resources/monthly/collect.html
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
{{extend defaultLayout}}
|
||||||
|
|
||||||
|
{{block 'css'}}
|
||||||
|
<link rel="stylesheet" href="{{@sys.currentPath}}/collect.css">
|
||||||
|
{{/block}}
|
||||||
|
|
||||||
|
{{block 'main'}}
|
||||||
|
<div class="lh">
|
||||||
|
{{range}}
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
{{include sys.playerInfo}}
|
||||||
|
<div class="bangboo"></div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="title with-icon">
|
||||||
|
收入一览
|
||||||
|
</div>
|
||||||
|
<div class="itembox">
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon feilin"></div>
|
||||||
|
<div class="count">{{total.poly}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon tape"></div>
|
||||||
|
<div class="count">{{total.tape}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon boopon"></div>
|
||||||
|
<div class="count">{{total.boopon}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="list">
|
||||||
|
<div class="title">每月细则</div>
|
||||||
|
{{each collect item}}
|
||||||
|
<div class="item">
|
||||||
|
<div class="month">{{item.query_full_date}}</div>
|
||||||
|
<div class="detail">
|
||||||
|
<div class="overview">
|
||||||
|
<div class="itembox">
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon feilin"></div>
|
||||||
|
<div class="count">{{item.month_data.overview.poly}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon tape"></div>
|
||||||
|
<div class="count">{{item.month_data.overview.tape}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon boopon"></div>
|
||||||
|
<div class="count">{{item.month_data.overview.boopon}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="components">
|
||||||
|
{{each item.month_data.income_components item_comp}}
|
||||||
|
<div class="item">
|
||||||
|
<div class="name">{{item_comp.name}}</div>
|
||||||
|
<div class="value">
|
||||||
|
<div class="percent">{{item_comp.percent}}%</div>
|
||||||
|
<div class="count">{{item_comp.num}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tips">
|
||||||
|
<ul>
|
||||||
|
<li>最新数据统计存在2小时左右延迟,请绳匠知悉</li>
|
||||||
|
<li>菲林收入不含充值获得菲林底片所兑换的菲林数量</li>
|
||||||
|
<li>若先前没有查询过数据(或者被删除)并且米游社也无法查询,那么上面将没有对应日期的数据</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/block}}
|
||||||
233
resources/monthly/collect.scss
Normal file
233
resources/monthly/collect.scss
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
.container {
|
||||||
|
background: url('./images/bg.png') no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
|
padding-top: 0.1em;
|
||||||
|
position: relative;
|
||||||
|
.lh {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 0 0 0.5em 0.5em;
|
||||||
|
padding: 0.3em 0.5em;
|
||||||
|
min-width: 10em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-align: center;
|
||||||
|
color: #d3d3d3;
|
||||||
|
filter: drop-shadow(0 0 0.3em #0d0d0d);
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
left: -0.5em;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at 0 100%,
|
||||||
|
transparent 0,
|
||||||
|
transparent 70%,
|
||||||
|
#000 70%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
right: -0.5em;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle at 100% 100%,
|
||||||
|
transparent 0,
|
||||||
|
transparent 70%,
|
||||||
|
#000 70%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
margin: 5em 1em 0em 1em;
|
||||||
|
border-image-source: url('./images/container.png');
|
||||||
|
border-image-slice: 210 40 40 40 fill;
|
||||||
|
border-image-width: 6.3em 1.2em 1.2em 1.2em;
|
||||||
|
border-image-outset: 0 0 0 0;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
position: relative;
|
||||||
|
filter: drop-shadow(0.5em 0.5em 0 #000);
|
||||||
|
.user-info {
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 2.8em 2em 1em 7em;
|
||||||
|
}
|
||||||
|
.bangboo {
|
||||||
|
position: absolute;
|
||||||
|
background: url('./images/bamboo.png') no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
width: 10.5em;
|
||||||
|
height: 10.5em;
|
||||||
|
right: 0.3em;
|
||||||
|
top: -2.5em;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 1em 2em;
|
||||||
|
.title {
|
||||||
|
text-shadow: 1px 1px 0px #000;
|
||||||
|
font-size: 1.5em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
&.with-icon::after {
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
background: url('./images/icon-title-deco.png') no-repeat left center;
|
||||||
|
background-size: contain;
|
||||||
|
width: 2em;
|
||||||
|
height: 1.1em;
|
||||||
|
margin-bottom: -0.05em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.itembox {
|
||||||
|
background: url('./images/itembox.png') no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
aspect-ratio: 2.2;
|
||||||
|
padding: 2em 1.4em 1.2em 1.4em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.item {
|
||||||
|
width: 31%;
|
||||||
|
.icon {
|
||||||
|
aspect-ratio: 1;
|
||||||
|
margin: 1.5em;
|
||||||
|
&.feilin {
|
||||||
|
background: url('./images/icon-feilin.png') no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
&.tape {
|
||||||
|
background: url('./images/icon-matser.png') no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
&.boopon {
|
||||||
|
background: url('./images/icon-bangboo.png') no-repeat center;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
font-size: 1.3em;
|
||||||
|
text-align: center;
|
||||||
|
color: #000;
|
||||||
|
margin-top: -0.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list {
|
||||||
|
border-image-source: url('./images/list.png');
|
||||||
|
border-image-slice: 550 30 30 30 fill;
|
||||||
|
border-image-width: 22em 1.2em 1.2em 1.2em;
|
||||||
|
border-image-outset: 0 0 0 0;
|
||||||
|
border-image-repeat: stretch stretch;
|
||||||
|
margin: 1em 0;
|
||||||
|
padding-bottom: 1.3em;
|
||||||
|
min-height: 25em;
|
||||||
|
.title {
|
||||||
|
font-size: 1.3em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
> .item {
|
||||||
|
padding: 0.6em 1em;
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
.month {
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-shadow: 1px 1px 0px #000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffcf32;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
background-color: #ffcf32;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 0.2em;
|
||||||
|
box-shadow: 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.detail {
|
||||||
|
display: flex;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
gap: 0.5em;
|
||||||
|
.overview {
|
||||||
|
width: 10em;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
.itembox {
|
||||||
|
font-size: 0.35em;
|
||||||
|
.item {
|
||||||
|
.count {
|
||||||
|
font-size: 1.8em;
|
||||||
|
margin-top: -0.2em;
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.components {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
font-size: 0.6em;
|
||||||
|
gap: 0.5em;
|
||||||
|
.item {
|
||||||
|
padding: 0.4em 0.6em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
box-shadow: 1px 1px 0 #000;
|
||||||
|
.name {
|
||||||
|
color: #e3e3e3;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.value {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 0.2em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
.percent {
|
||||||
|
color: #989898;
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tips {
|
||||||
|
padding: 1em;
|
||||||
|
color: #dfdfdf;
|
||||||
|
font-size: 0.8em;
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
&::before {
|
||||||
|
content: '*';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.copyright {
|
||||||
|
background: url('./images/bottom-deco.gif') no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
|
text-shadow: 1px 1px 1px #000;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
@ -5,54 +5,52 @@
|
||||||
{{/block}}
|
{{/block}}
|
||||||
|
|
||||||
{{block 'main'}}
|
{{block 'main'}}
|
||||||
<div class="card">
|
<div class="lh">
|
||||||
<div class="lh">
|
{{monthly.query_month}}
|
||||||
{{monthly.query_month}}
|
</div>
|
||||||
</div>
|
<div class="box">
|
||||||
<div class="box">
|
{{include sys.playerInfo}}
|
||||||
{{include sys.playerInfo}}
|
<div class="bangboo"></div>
|
||||||
<div class="bangboo"></div>
|
<div class="content">
|
||||||
<div class="content">
|
<div class="title with-icon">
|
||||||
<div class="title with-icon">
|
收入一览
|
||||||
收入一览
|
</div>
|
||||||
|
<div class="itembox">
|
||||||
|
<div class="item">
|
||||||
|
<div class="icon feilin"></div>
|
||||||
|
<div class="count">{{monthly.month_data.overview.poly}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="itembox">
|
<div class="item">
|
||||||
<div class="item">
|
<div class="icon tape"></div>
|
||||||
<div class="icon feilin"></div>
|
<div class="count">{{monthly.month_data.overview.tape}}</div>
|
||||||
<div class="count">{{monthly.month_data.overview.poly}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<div class="icon tape"></div>
|
|
||||||
<div class="count">{{monthly.month_data.overview.tape}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<div class="icon boopon"></div>
|
|
||||||
<div class="count">{{monthly.month_data.overview.boopon}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="item">
|
||||||
<div class="title">菲林收入组成</div>
|
<div class="icon boopon"></div>
|
||||||
{{each monthly.month_data.income_components item}}
|
<div class="count">{{monthly.month_data.overview.boopon}}</div>
|
||||||
<div class="item">
|
|
||||||
<div class="info-line">
|
|
||||||
<div class="name">{{item.name}}</div>
|
|
||||||
<div class="percent">{{item.percent}}%</div>
|
|
||||||
<div class="value">{{item.num}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="progress">
|
|
||||||
<div class="bar" style="width: {{item.percent}}%;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="list">
|
||||||
|
<div class="title">菲林收入组成</div>
|
||||||
|
{{each monthly.month_data.income_components item}}
|
||||||
|
<div class="item">
|
||||||
|
<div class="info-line">
|
||||||
|
<div class="name">{{item.name}}</div>
|
||||||
|
<div class="percent">{{item.percent}}%</div>
|
||||||
|
<div class="value">{{item.num}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="progress">
|
||||||
|
<div class="bar" style="width: {{item.percent}}%;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tips">
|
</div>
|
||||||
<ul>
|
<div class="tips">
|
||||||
<li>数据统计存在2小时左右延迟,请绳匠知悉</li>
|
<ul>
|
||||||
<li>菲林收入不含充值获得菲林底片所兑换的菲林数量</li>
|
<li>数据统计存在2小时左右延迟,请绳匠知悉</li>
|
||||||
</ul>
|
<li>菲林收入不含充值获得菲林底片所兑换的菲林数量</li>
|
||||||
</div>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{/block}}
|
{{/block}}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue