mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
✨ 祈愿历史
This commit is contained in:
278
src/components/gachaRecord/gro-history.vue
Normal file
278
src/components/gachaRecord/gro-history.vue
Normal file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<div class="gro-container">
|
||||
<v-tabs class="gro-tabs" v-model="historyTab" align-tabs="start" direction="vertical">
|
||||
<v-tab v-for="(item, index) in tabList" :key="index" :value="item.tab">
|
||||
v{{ item.tab }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<v-window v-model="historyTab" class="gro-window">
|
||||
<v-window-item
|
||||
v-for="(item, index) in tabList"
|
||||
:key="index"
|
||||
:value="item.tab"
|
||||
class="gro-pools"
|
||||
>
|
||||
<div v-for="pool in item.value" :key="pool.order" class="gro-pool">
|
||||
<!-- todo hover 效果 -->
|
||||
<img :src="pool.banner" alt="banner" />
|
||||
<div class="gro-pool-info">
|
||||
<div class="gro-pi-title">
|
||||
<span>{{ pool.name }}</span>
|
||||
<span class="gro-pi-tag">{{ pool.order === 1 ? "上半" : "下半" }}</span>
|
||||
<span class="gro-pi-tag">{{ getType(pool.type) }}</span>
|
||||
</div>
|
||||
<div class="gro-pi-time">{{ getTimeStr(pool) }}</div>
|
||||
<div class="gro-pi-sub">Up 五星</div>
|
||||
<div class="gro-pool-up">
|
||||
<TItembox
|
||||
v-for="i in pool.up5List"
|
||||
:key="i"
|
||||
:model-value="getBox(i)"
|
||||
@click="toWiki(i)"
|
||||
/>
|
||||
</div>
|
||||
<div class="gro-pi-sub">Up 四星</div>
|
||||
<div class="gro-pool-up">
|
||||
<TItembox
|
||||
v-for="i in pool.up4List"
|
||||
:key="i"
|
||||
:model-value="getBox(i)"
|
||||
@click="toWiki(i)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import { AppGachaData, AppCharacterData, AppWeaponData } from "../../data";
|
||||
import { timestampToDate } from "../../utils/toolFunc";
|
||||
import showConfirm from "../func/confirm";
|
||||
import showSnackbar from "../func/snackbar";
|
||||
import TItembox, { TItemBoxData } from "../main/t-itembox.vue";
|
||||
|
||||
interface GroHistoryMap {
|
||||
tab: string;
|
||||
value: TGApp.App.Gacha.PoolItem[];
|
||||
}
|
||||
|
||||
const historyTab = ref<string>("");
|
||||
const tabList = ref<GroHistoryMap[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
onMounted(() => {
|
||||
const res: GroHistoryMap[] = [];
|
||||
AppGachaData.forEach((pool) => {
|
||||
const index = res.findIndex((item) => item.tab === pool.version);
|
||||
if (index === -1) {
|
||||
res.push({
|
||||
tab: pool.version,
|
||||
value: [pool],
|
||||
});
|
||||
} else {
|
||||
res[index].value.push(pool);
|
||||
}
|
||||
});
|
||||
tabList.value = res.reverse();
|
||||
historyTab.value = res[0].tab;
|
||||
});
|
||||
|
||||
async function toWiki(id: number): Promise<void> {
|
||||
const cFind = AppCharacterData.find((item) => item.id === id);
|
||||
const wFind = AppWeaponData.find((item) => item.id === id);
|
||||
const confirm = await showConfirm({
|
||||
title: "是否跳转到对应图鉴界面?",
|
||||
});
|
||||
if (confirm === undefined || confirm === false) {
|
||||
showSnackbar({
|
||||
text: "已取消",
|
||||
color: "cancel",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (cFind) {
|
||||
await router.push({
|
||||
name: "角色图鉴",
|
||||
params: {
|
||||
id: id.toString(),
|
||||
},
|
||||
});
|
||||
} else if (wFind) {
|
||||
await router.push({
|
||||
name: "武器图鉴",
|
||||
params: {
|
||||
id: id.toString(),
|
||||
},
|
||||
});
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "未找到对应角色或武器",
|
||||
color: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getType(type: TGApp.App.Gacha.WishType): string {
|
||||
switch (type) {
|
||||
case 301:
|
||||
return "角色活动祈愿";
|
||||
case 400:
|
||||
return "角色活动祈愿2";
|
||||
case 302:
|
||||
return "武器活动祈愿";
|
||||
case 500:
|
||||
return "集录祈愿";
|
||||
default:
|
||||
return `未知类型 ${type}`;
|
||||
}
|
||||
}
|
||||
|
||||
function getTimeStr(pool: TGApp.App.Gacha.PoolItem): string {
|
||||
const startTime = timestampToDate(Date.parse(pool.from));
|
||||
const endTime = timestampToDate(Date.parse(pool.to));
|
||||
return `${startTime} ~ ${endTime}`;
|
||||
}
|
||||
|
||||
function getBox(id: number): TItemBoxData {
|
||||
const cFind = AppCharacterData.find((item) => item.id === id);
|
||||
const wFind = AppWeaponData.find((item) => item.id === id);
|
||||
if (cFind) {
|
||||
return {
|
||||
bg: `/icon/bg/${cFind.star}-Star.webp`,
|
||||
icon: `/WIKI/character/${cFind.id}.webp`,
|
||||
size: "100px",
|
||||
height: "100px",
|
||||
display: "inner",
|
||||
clickable: true,
|
||||
lt: `/icon/element/${cFind.element}元素.webp`,
|
||||
ltSize: "30px",
|
||||
innerHeight: 25,
|
||||
innerIcon: `/icon/weapon/${cFind.weapon}.webp`,
|
||||
innerText: cFind.name,
|
||||
};
|
||||
} else if (wFind) {
|
||||
return {
|
||||
bg: `/icon/bg/${wFind.star}-Star.webp`,
|
||||
icon: `/WIKI/weapon/${wFind.id}.webp`,
|
||||
size: "100px",
|
||||
height: "100px",
|
||||
display: "inner",
|
||||
clickable: true,
|
||||
lt: wFind.weaponIcon,
|
||||
ltSize: "30px",
|
||||
innerHeight: 25,
|
||||
innerText: wFind.name,
|
||||
};
|
||||
} else {
|
||||
throw new Error("未找到对应角色或武器");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.gro-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.gro-tabs {
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line selector-class-pattern */
|
||||
.v-tabs.v-slide-group--vertical {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gro-window {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 10px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.gro-pools {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.gro-pool {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
background: var(--box-bg-2);
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.gro-pool img {
|
||||
width: 50vw;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.gro-pool-info {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.gro-pi-title {
|
||||
display: flex;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.gro-pi-title :first-child {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.gro-pi-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 5px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-1);
|
||||
color: var(--box-text-5);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.gro-pi-sub {
|
||||
font-family: var(--font-title);
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.gro-pool-up {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
1718
src/data/app/gacha.json
Normal file
1718
src/data/app/gacha.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,14 @@
|
||||
/**
|
||||
* @file src/data/index.ts
|
||||
* @description 数据文件入口
|
||||
* @since Beta v0.4.2
|
||||
* @since Beta v0.4.4
|
||||
*/
|
||||
|
||||
import achievements from "./app/achievements.json";
|
||||
import achievementSeries from "./app/achievementSeries.json";
|
||||
import calendar from "./app/calendar.json";
|
||||
import character from "./app/character.json";
|
||||
import gacha from "./app/gacha.json";
|
||||
import GCG from "./app/GCG.json";
|
||||
import nameCards from "./app/namecard.json";
|
||||
import weapon from "./app/weapon.json";
|
||||
@@ -19,6 +20,7 @@ export const AppAchievementsData: TGApp.App.Achievement.Item[] = achievements;
|
||||
export const AppAchievementSeriesData: TGApp.App.Achievement.Series[] = achievementSeries;
|
||||
export const AppCalendarData: TGApp.App.Calendar.Item[] = calendar;
|
||||
export const AppCharacterData: TGApp.App.Character.WikiBriefInfo[] = character;
|
||||
export const AppGachaData: TGApp.App.Gacha.PoolItem[] = gacha;
|
||||
export const AppGCGData: TGApp.App.GCG.WikiBriefInfo[] = GCG;
|
||||
export const AppNameCardsData: TGApp.App.NameCard.Item[] = nameCards;
|
||||
export const AppWeaponData: TGApp.App.Weapon.WikiBriefInfo[] = weapon;
|
||||
|
||||
@@ -5,30 +5,22 @@
|
||||
<v-select v-model="uidCur" class="gacha-top-select" :items="selectItem" variant="outlined" />
|
||||
<div class="gacha-top-btns">
|
||||
<v-btn prepend-icon="mdi-refresh" class="gacha-top-btn" @click="confirmRefresh">刷新</v-btn>
|
||||
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn()">
|
||||
导入
|
||||
<v-btn prepend-icon="mdi-import" class="gacha-top-btn" @click="handleImportBtn()">导入</v-btn>
|
||||
<v-btn prepend-icon="mdi-export" class="gacha-top-btn" @click="handleExportBtn">导出</v-btn>
|
||||
<v-btn prepend-icon="mdi-cloud-download" class="gacha-top-btn" @click="backupGacha">
|
||||
备份
|
||||
</v-btn>
|
||||
<v-btn prepend-icon="mdi-delete" class="gacha-top-btn" @click="deleteGacha">删除</v-btn>
|
||||
<v-btn prepend-icon="mdi-cloud-upload" class="gacha-top-btn" @click="restoreGacha">
|
||||
恢复
|
||||
</v-btn>
|
||||
<v-btn prepend-icon="mdi-export" class="gacha-top-btn" @click="handleExportBtn"> 导出</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gacha-container">
|
||||
<v-tabs v-model="tab" align-tabs="start" class="gacha-tab" direction="vertical">
|
||||
<v-tabs v-model="tab" align-tabs="start" class="gacha-tab">
|
||||
<v-tab value="echarts">图表概览</v-tab>
|
||||
<v-tab value="overview">数据概览</v-tab>
|
||||
<div class="gacha-tab-bottom">
|
||||
<v-btn class="gacha-tab-btn" @click="backupGacha">
|
||||
<v-icon>mdi-cloud-download</v-icon>
|
||||
<span>备份</span>
|
||||
</v-btn>
|
||||
<v-btn class="gacha-tab-btn" @click="deleteGacha">
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
<span>删除</span>
|
||||
</v-btn>
|
||||
<v-btn class="gacha-tab-btn" @click="restoreGacha">
|
||||
<v-icon>mdi-cloud-upload</v-icon>
|
||||
<span>恢复</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-tab value="history">过往祈愿</v-tab>
|
||||
</v-tabs>
|
||||
<v-window v-model="tab" class="gacha-window">
|
||||
<v-window-item value="echarts" class="gacha-window-item">
|
||||
@@ -37,6 +29,9 @@
|
||||
<v-window-item value="overview" class="gacha-window-item">
|
||||
<gro-overview v-model="gachaListCur" />
|
||||
</v-window-item>
|
||||
<v-window-item value="history" class="gacha-window-item">
|
||||
<gro-history />
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
</div>
|
||||
</template>
|
||||
@@ -48,6 +43,7 @@ import { onMounted, ref, watch } from "vue";
|
||||
import showConfirm from "../../components/func/confirm";
|
||||
import showSnackbar from "../../components/func/snackbar";
|
||||
import GroEcharts from "../../components/gachaRecord/gro-echarts.vue";
|
||||
import GroHistory from "../../components/gachaRecord/gro-history.vue";
|
||||
import GroOverview from "../../components/gachaRecord/gro-overview.vue";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import { AppCharacterData, AppWeaponData } from "../../data";
|
||||
@@ -500,36 +496,20 @@ watch(uidCur, async (newUid) => {
|
||||
.gacha-container {
|
||||
display: flex;
|
||||
height: calc(100vh - 130px);
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-1);
|
||||
}
|
||||
|
||||
.gacha-tab {
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
height: 50px;
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.gacha-tab-bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.gacha-tab-btn {
|
||||
border-radius: 5px;
|
||||
background: var(--tgc-btn-1);
|
||||
color: var(--btn-text);
|
||||
}
|
||||
|
||||
.gacha-window {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -539,6 +519,5 @@ watch(uidCur, async (newUid) => {
|
||||
.gacha-window-item {
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
60
src/types/App/Gacha.d.ts
vendored
Normal file
60
src/types/App/Gacha.d.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file types/App/Gacha.d.ts
|
||||
* @description 本应用的祈愿相关类型定义
|
||||
* @since Beta v0.4.4
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 祈愿记录命名空间
|
||||
* @namespace Gacha
|
||||
* @since Beta v0.4.4
|
||||
* @memberof TGApp.App
|
||||
*/
|
||||
declare namespace TGApp.App.Gacha {
|
||||
/**
|
||||
* @description 祈愿类型枚举
|
||||
* @since Beta v0.4.4
|
||||
* @enum {number}
|
||||
* @property {number} Newbie 新手祈愿 = 100
|
||||
* @property {number} Normal 常驻祈愿 = 200
|
||||
* @property {number} CharacterUp 角色活动祈愿 = 301
|
||||
* @property {number} CharacterUp2 角色活动祈愿2 = 400
|
||||
* @property {number} WeaponUp 武器活动祈愿 = 302
|
||||
* @property {number} MixUp 集录祈愿 = 500
|
||||
* @return WishType
|
||||
*/
|
||||
const enum WishType {
|
||||
Newbie = 100,
|
||||
Normal = 200,
|
||||
CharacterUp = 301,
|
||||
CharacterUp2 = 400,
|
||||
WeaponUp = 302,
|
||||
MixUp = 500,
|
||||
}
|
||||
/**
|
||||
* @description 祈愿记录项
|
||||
* @interface PoolItem
|
||||
* @since Beta v0.4.4
|
||||
* @property {string} name 卡池名称
|
||||
* @property {string} version 卡池版本
|
||||
* @property {number} order 卡池排序
|
||||
* @property {string} banner 卡池横幅
|
||||
* @property {string} from 卡池开始时间 yyyy-MM-ddTHH:mm:ss+08:00
|
||||
* @property {string} to 卡池结束时间 yyyy-MM-ddTHH:mm:ss+08:00
|
||||
* @property {WishType} type 卡池类型
|
||||
* @property {number[]} up5List up五星
|
||||
* @property {number[]} up4List up四星
|
||||
* @return PoolItem
|
||||
*/
|
||||
interface PoolItem {
|
||||
name: string;
|
||||
version: string;
|
||||
order: number;
|
||||
banner: string;
|
||||
from: string;
|
||||
to: string;
|
||||
type: WishType;
|
||||
up5List: number[];
|
||||
up4List: number[];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user