From dcf04636c2c4fcf418e49bd6d7c7313cc4b89ecc Mon Sep 17 00:00:00 2001 From: bietiaop <1527109126@qq.com> Date: Fri, 4 Oct 2024 11:23:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9C=88=E6=8A=A5=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=EF=BC=88=E6=80=BB=EF=BC=89;=E6=9F=A5=E8=AF=A2=E7=9A=84?= =?UTF-8?q?=E6=9C=88=E6=8A=A5=E6=95=B0=E6=8D=AE=E8=87=AA=E5=8A=A8=E4=BF=9D?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/help.js | 17 ++- apps/monthly.js | 66 ++++++++-- apps/panel.js | 8 +- lib/avatar.js | 7 +- lib/db.js | 16 +++ lib/db/core.js | 1 + lib/monthly.js | 63 +++++++++ model/monthly.js | 4 + resources/monthly/collect.css | 224 +++++++++++++++++++++++++++++++ resources/monthly/collect.html | 78 +++++++++++ resources/monthly/collect.scss | 233 +++++++++++++++++++++++++++++++++ resources/monthly/index.html | 84 ++++++------ 12 files changed, 739 insertions(+), 62 deletions(-) create mode 100644 lib/monthly.js create mode 100644 resources/monthly/collect.css create mode 100644 resources/monthly/collect.html create mode 100644 resources/monthly/collect.scss diff --git a/apps/help.js b/apps/help.js index 2779cd5..0e3c567 100644 --- a/apps/help.js +++ b/apps/help.js @@ -41,8 +41,8 @@ const helpData = [ commands: ['note', '便签', '便笺', '体力', '每日'], }, { - title: '月报/菲林/邦布券/母带统计', - desc: '查看菲林、邦布券、加密/原装母带的收入情况。其中,参数可以为空(默认为本月),也可以为年份月份或者月份,例如:2024年9月、9月、上月', + title: '单月月报/菲林/邦布券/母带统计', + desc: '查看单月菲林、邦布券、加密/原装母带的收入情况(查询结果也会写入数据库)。其中,参数可以为空(默认为本月),也可以为年份月份或者月份,例如:2024年9月、9月、上月', needCK: true, needSK: false, commands: [ @@ -53,6 +53,19 @@ const helpData = [ '月报+[参数]', ], }, + { + title: '查看全部月报/菲林/邦布券/母带统计', + desc: '查看菲林、邦布券、加密/原装母带的收入总情况(会查询全部可查询月份+已保存数据,新旧数据会进行合并)。', + needCK: true, + needSK: false, + commands: [ + 'monthly统计', + '菲林统计', + '邦布券统计', + '收入统计', + '月报统计', + ], + }, ], }, { diff --git a/apps/monthly.js b/apps/monthly.js index b9c2e91..4e92cb8 100644 --- a/apps/monthly.js +++ b/apps/monthly.js @@ -3,6 +3,7 @@ import { Monthly } from '../model/monthly.js'; import settings from '../lib/settings.js'; import _ from 'lodash'; import { rulePrefix } from '../lib/common.js'; +import { getMonthly, getMonthlyCollect } from '../lib/monthly.js'; export class Note extends ZZZPlugin { constructor() { @@ -16,6 +17,10 @@ export class Note extends ZZZPlugin { reg: `${rulePrefix}(monthly|菲林|邦布券|收入|月报)((\\d{4})年)?((\\d{1,2}|上)月)?$`, fnc: 'monthly', }, + { + reg: `${rulePrefix}(monthly|菲林|邦布券|收入|月报)统计$`, + fnc: 'monthlyCollect', + }, ], }); } @@ -30,19 +35,15 @@ export class Note extends ZZZPlugin { } let year = match[3]; let month = match[5]; - logger.debug(this.getDateString(year, month)); const { api } = await this.getAPI(); await this.getPlayerInfo(); - const monthlyResponse = await api - .getFinalData('zzzMonthly', { - query: { - month: this.getDateString(year, month), - }, - }) - .catch(e => { - this.reply(e.message); - throw e; - }); + const monthlyResponse = await getMonthly( + api, + this.getDateString(year, month) + ).catch(e => { + this.reply(e.message); + throw e; + }); if (!monthlyResponse) { await this.reply('获取月报数据失败,请检查日期是否正确'); return false; @@ -58,6 +59,49 @@ export class Note extends ZZZPlugin { 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) { let _year = +year, _month = +month; diff --git a/apps/panel.js b/apps/panel.js index d4a357d..ed4d3c7 100644 --- a/apps/panel.js +++ b/apps/panel.js @@ -1,5 +1,9 @@ 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 _ from 'lodash'; 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 this.reply('正在刷新面板列表,请稍候...'); await this.getPlayerInfo(); - const result = await refreshPanel(api, uid).catch(e => { + const result = await refreshPanelFunction(api).catch(e => { this.reply(e.message); throw e; }); diff --git a/lib/avatar.js b/lib/avatar.js index b131b4b..38b11a5 100644 --- a/lib/avatar.js +++ b/lib/avatar.js @@ -51,12 +51,11 @@ export const getAvatarInfoList = async (api, origin = false) => { /** * 刷新面板 * @param {MysZZZApi} api - * @param {string} uid * @returns {Promise} */ -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); if (!newData) return null; @@ -73,7 +72,7 @@ export const refreshPanel = async (api, uid) => { } } // 保存数据 - savePanelData(uid, finalData); + savePanelData(api.uid, finalData); // 格式化数据 finalData.forEach(item => { item.isNew = !!newData.find(i => i.id === item.id); diff --git a/lib/db.js b/lib/db.js index 9e76214..4c8a97d 100644 --- a/lib/db.js +++ b/lib/db.js @@ -31,3 +31,19 @@ export function getPanelData(uid) { export function savePanelData(uid, data) { setDB('panel', uid, data); } + +/** + * @param {string} uid + * @returns {Array} + */ +export function getMonthlyData(uid) { + return getDB('monthly', uid) || []; +} + +/** + * @param {string} uid + * @param {Array} data + */ +export function saveMonthlyData(uid, data) { + setDB('monthly', uid, data); +} diff --git a/lib/db/core.js b/lib/db/core.js index 1ee5b93..7054158 100644 --- a/lib/db/core.js +++ b/lib/db/core.js @@ -5,6 +5,7 @@ import { dataPath } from '../path.js'; export const dbPath = { gacha: 'gacha', panel: 'panel', + monthly: 'monthly', }; /** diff --git a/lib/monthly.js b/lib/monthly.js new file mode 100644 index 0000000..a1a258a --- /dev/null +++ b/lib/monthly.js @@ -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} + */ +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} + */ +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; +}; diff --git a/model/monthly.js b/model/monthly.js index 155eeac..1cf553a 100644 --- a/model/monthly.js +++ b/model/monthly.js @@ -155,4 +155,8 @@ export class Monthly { const month = +this.data_month.slice(-2); return `${month}月`; } + + get query_full_date() { + return `${this.data_month.slice(0, 4)}年${this.query_month}`; + } } diff --git a/resources/monthly/collect.css b/resources/monthly/collect.css new file mode 100644 index 0000000..d015b04 --- /dev/null +++ b/resources/monthly/collect.css @@ -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 */ diff --git a/resources/monthly/collect.html b/resources/monthly/collect.html new file mode 100644 index 0000000..f1e53cf --- /dev/null +++ b/resources/monthly/collect.html @@ -0,0 +1,78 @@ +{{extend defaultLayout}} + +{{block 'css'}} + +{{/block}} + +{{block 'main'}} +
+ {{range}} +
+
+ {{include sys.playerInfo}} +
+
+
+ 收入一览 +
+
+
+
+
{{total.poly}}
+
+
+
+
{{total.tape}}
+
+
+
+
{{total.boopon}}
+
+
+
+
每月细则
+ {{each collect item}} +
+
{{item.query_full_date}}
+
+
+
+
+
+
{{item.month_data.overview.poly}}
+
+
+
+
{{item.month_data.overview.tape}}
+
+
+
+
{{item.month_data.overview.boopon}}
+
+
+
+
+ {{each item.month_data.income_components item_comp}} +
+
{{item_comp.name}}
+
+
{{item_comp.percent}}%
+
{{item_comp.num}}
+
+
+ {{/each}} +
+
+
+ {{/each}} +
+
+
+
+
    +
  • 最新数据统计存在2小时左右延迟,请绳匠知悉
  • +
  • 菲林收入不含充值获得菲林底片所兑换的菲林数量
  • +
  • 若先前没有查询过数据(或者被删除)并且米游社也无法查询,那么上面将没有对应日期的数据
  • +
+
+{{/block}} \ No newline at end of file diff --git a/resources/monthly/collect.scss b/resources/monthly/collect.scss new file mode 100644 index 0000000..999fc4f --- /dev/null +++ b/resources/monthly/collect.scss @@ -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; +} diff --git a/resources/monthly/index.html b/resources/monthly/index.html index 81fe1d0..2e2fad8 100644 --- a/resources/monthly/index.html +++ b/resources/monthly/index.html @@ -5,54 +5,52 @@ {{/block}} {{block 'main'}} -
-
- {{monthly.query_month}} -
-
- {{include sys.playerInfo}} -
-
-
- 收入一览 +
+ {{monthly.query_month}} +
+
+ {{include sys.playerInfo}} +
+
+
+ 收入一览 +
+
+
+
+
{{monthly.month_data.overview.poly}}
-
-
-
-
{{monthly.month_data.overview.poly}}
-
-
-
-
{{monthly.month_data.overview.tape}}
-
-
-
-
{{monthly.month_data.overview.boopon}}
-
+
+
+
{{monthly.month_data.overview.tape}}
-
-
菲林收入组成
- {{each monthly.month_data.income_components item}} -
-
-
{{item.name}}
-
{{item.percent}}%
-
{{item.num}}
-
-
-
-
-
- {{/each}} +
+
+
{{monthly.month_data.overview.boopon}}
+
+
菲林收入组成
+ {{each monthly.month_data.income_components item}} +
+
+
{{item.name}}
+
{{item.percent}}%
+
{{item.num}}
+
+
+
+
+
+ {{/each}} +
-
-
    -
  • 数据统计存在2小时左右延迟,请绳匠知悉
  • -
  • 菲林收入不含充值获得菲林底片所兑换的菲林数量
  • -
-
+
+
+
    +
  • 数据统计存在2小时左右延迟,请绳匠知悉
  • +
  • 菲林收入不含充值获得菲林底片所兑换的菲林数量
  • +
{{/block}} \ No newline at end of file