mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-19 04:29:45 +08:00
✨ 重构真境剧诗页面UI,优化组件结构与样式
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @file assets/themes/dark.css
|
||||
* @description 主题样式文件-深色主题
|
||||
* @since Beta v0.7.2
|
||||
* 主题样式文件-深色主题
|
||||
* @since v0.8.9
|
||||
*/
|
||||
|
||||
/* dark mode */
|
||||
@@ -30,6 +29,7 @@ html.dark {
|
||||
--box-text-4: var(--tgc-white-4);
|
||||
--box-text-5: var(--tgc-red-1);
|
||||
--box-text-7: var(--tgc-white-5);
|
||||
--box-text-8: var(--tgc-yellow-1);
|
||||
|
||||
/* button */
|
||||
--btn-text: var(--tgc-yellow-1);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @file assets/themes/default.css
|
||||
* @description 主题样式文件-默认(浅色)主题
|
||||
* @since Beta v0.7.2
|
||||
* 主题样式文件-默认(浅色)主题
|
||||
* @since v0.8.9
|
||||
*/
|
||||
|
||||
/* default(light) theme */
|
||||
@@ -30,6 +29,7 @@ html.default {
|
||||
--box-text-4: var(--tgc-blue-3); /* subtitle */
|
||||
--box-text-5: var(--tgc-pink-1); /* tag */
|
||||
--box-text-7: var(--tgc-dark-7); /* quote */
|
||||
--box-text-8: var(--tgc-od-orange); /* sth hint */
|
||||
|
||||
/* button */
|
||||
--btn-text: var(--tgc-yellow-2); /* with tgc-btn-1 */
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<!-- 标题栏组件 -->
|
||||
<template>
|
||||
<div class="tsl-box">
|
||||
<img src="@/assets/icons/arrow-right.svg" alt="right" />
|
||||
<slot name="icon">
|
||||
<img alt="right" class="tsl-icon" src="@/assets/icons/arrow-right.svg" />
|
||||
</slot>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
@@ -18,7 +21,7 @@
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.tsl-box :first-child {
|
||||
.tsl-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
box-sizing: border-box;
|
||||
@@ -26,7 +29,7 @@
|
||||
filter: invert(0.75);
|
||||
}
|
||||
|
||||
.dark .tsl-box :first-child {
|
||||
.dark .tsl-icon {
|
||||
filter: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
173
src/components/userCombat/tuc-ae-box.vue
Normal file
173
src/components/userCombat/tuc-ae-box.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<!-- 剧诗,角色&敌人 -->
|
||||
<template>
|
||||
<div class="tuc-ae-box">
|
||||
<div class="tuc-avatars">
|
||||
<div class="tuc-ae-title">上场角色</div>
|
||||
<div class="tuc-ae-grid">
|
||||
<TItembox
|
||||
v-for="(avatar, idx) in props.avatars"
|
||||
:key="idx"
|
||||
:model-value="getAvatarBox(avatar)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tuc-enemies">
|
||||
<div class="tuc-ae-title">讨伐列表</div>
|
||||
<div class="tuc-ae-flex">
|
||||
<div v-for="(enemy, idx) in props.enemies" :key="idx" class="tuc-enemy">
|
||||
<div class="tuc-enemy-icon">
|
||||
<img :src="enemy.icon" alt="icon" />
|
||||
</div>
|
||||
<div class="tuc-enemy-info">
|
||||
<span>{{ enemy.name }}</span>
|
||||
<span>Lv.{{ enemy.level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TItembox, { type TItemBoxData } from "@comp/app/t-itemBox.vue";
|
||||
import { getWikiBrief, getZhElement } from "@utils/toolFunc.js";
|
||||
|
||||
type TucAeBoxProps = {
|
||||
/* 上场角色数据 */
|
||||
avatars: Array<TGApp.Game.Combat.Avatar>;
|
||||
/* 敌人数据 */
|
||||
enemies: Array<TGApp.Game.Combat.Enemy>;
|
||||
};
|
||||
|
||||
const props = defineProps<TucAeBoxProps>();
|
||||
|
||||
function getAvatarBox(item: TGApp.Game.Combat.Avatar): TItemBoxData {
|
||||
const findAvatar = getWikiBrief(item.avatar_id);
|
||||
let innerText = item.avatar_type === 2 ? "试用角色" : item.avatar_type === 3 ? "助演角色" : "";
|
||||
let findWeapon;
|
||||
if (findAvatar) {
|
||||
findWeapon = findAvatar.weapon;
|
||||
if (innerText === "") innerText = findAvatar.name;
|
||||
}
|
||||
return {
|
||||
bg: `/icon/bg/${item.rarity === 105 ? 5 : item.rarity}-BGC.webp`,
|
||||
clickable: false,
|
||||
display: "inner",
|
||||
height: "80px",
|
||||
icon: `/WIKI/character/${item.avatar_id}.webp`,
|
||||
innerHeight: innerText === "" ? 0 : 20,
|
||||
innerText: innerText,
|
||||
lt:
|
||||
item.element === "None"
|
||||
? findWeapon
|
||||
? `/icon/weapon/${findWeapon}.webp`
|
||||
: ""
|
||||
: `/icon/element/${getZhElement(item.element)}元素.webp`,
|
||||
ltSize: "20px",
|
||||
innerBlur: "5px",
|
||||
rt: "",
|
||||
rtSize: "",
|
||||
size: "80px",
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tuc-ae-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
align-items: stretch;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-2);
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-avatars {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.tuc-ae-title {
|
||||
color: var(--box-text-2);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tuc-ae-grid {
|
||||
position: relative;
|
||||
display: grid;
|
||||
margin: 0 auto;
|
||||
gap: 8px;
|
||||
grid-template-columns: repeat(4, 80px);
|
||||
}
|
||||
|
||||
.tuc-enemies {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.tuc-ae-flex {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-wrap: wrap-reverse;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px 8px;
|
||||
}
|
||||
|
||||
.tuc-enemy {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px 8px 4px 4px;
|
||||
border-radius: 40px;
|
||||
background: var(--box-bg-3);
|
||||
column-gap: 4px;
|
||||
}
|
||||
|
||||
.tuc-enemy-icon {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: var(--box-bg-4);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.tuc-enemy-info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
|
||||
span {
|
||||
line-height: 16px;
|
||||
|
||||
&:first-child {
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<!-- 剧诗角色列表 -->
|
||||
<template>
|
||||
<div class="tuca-box" :class="{ grid: props.detail }">
|
||||
<div :class="{ grid: props.detail }" class="tuca-box">
|
||||
<TItemBox v-for="(item, idx) in props.modelValue" :key="idx" :model-value="getItemBox(item)" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -52,7 +53,7 @@ function getItemBox(item: TGApp.Game.Combat.Avatar): TItemBoxData {
|
||||
&.grid {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-gap: 4px;
|
||||
gap: 4px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
151
src/components/userCombat/tuc-buff-box.vue
Normal file
151
src/components/userCombat/tuc-buff-box.vue
Normal file
@@ -0,0 +1,151 @@
|
||||
<!-- 剧诗,辉彩祝福 -->
|
||||
<template>
|
||||
<div class="tuc-buff-box">
|
||||
<div class="tuc-buff-item">
|
||||
<div class="tuc-buff-summary">
|
||||
<div class="tuc-buff-icon">
|
||||
<img alt="total" class="summary" src="/source/UI/combatCrown.webp" />
|
||||
</div>
|
||||
<div class="tuc-buff-desc">
|
||||
<span>辉彩祝福</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tuc-buff-total" v-html="parseHtmlText(props.modelValue.summary.desc)" />
|
||||
</div>
|
||||
<template v-for="(buff, idx) in props.modelValue.buffs" :key="idx">
|
||||
<div v-if="buff.level > 1" class="tuc-buff-item">
|
||||
<div class="tuc-buff-summary">
|
||||
<div class="tuc-buff-icon">
|
||||
<img :alt="buff.name" :src="buff.icon" />
|
||||
</div>
|
||||
<div class="tuc-buff-desc">
|
||||
<span>{{ buff.name }}</span>
|
||||
<span>Lv.{{ buff.level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tuc-buff-detail" @click="console.log(buff)">
|
||||
<div v-for="(effect, idx) in buff.level_effect" :key="idx" class="tuc-effect-item">
|
||||
<div class="tuc-effect-title">
|
||||
<img :src="effect.icon" alt="icon" />
|
||||
<span v-html="parseHtmlText(effect.name)" />
|
||||
</div>
|
||||
<span class="tuc-effect-desc" v-html="parseHtmlText(effect.desc)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { parseHtmlText } from "@utils/toolFunc.js";
|
||||
|
||||
type TucBuffBoxProps = {
|
||||
/* 辉彩祝福数据 */
|
||||
modelValue: TGApp.Game.Combat.SplendourBuff;
|
||||
};
|
||||
|
||||
const props = defineProps<TucBuffBoxProps>();
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-buff-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-2);
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-buff-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
column-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-buff-summary {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
.tuc-buff-icon {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--box-bg-3);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.tuc-buff-desc {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: var(--font-title);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.dark .tuc-buff-summary .tuc-buff-icon img.summary {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
.tuc-buff-detail {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tuc-buff-total {
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.tuc-effect-title {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
column-gap: 4px;
|
||||
font-family: var(--font-title);
|
||||
font-size: 12px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
filter: invert(0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.dark .tuc-effect-title img {
|
||||
filter: unset;
|
||||
}
|
||||
|
||||
.tuc-effect-desc {
|
||||
position: relative;
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<div class="tuc-buff-box">
|
||||
<div class="tuc-buff-item">
|
||||
<img alt="total" src="/source/UI/combatCrown.webp" />
|
||||
<span>{{ props.modelValue.summary.total_level }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="tuc-buff-item"
|
||||
v-for="(item, idx) in props.modelValue.buffs"
|
||||
:key="idx"
|
||||
:title="item.name"
|
||||
>
|
||||
<img :alt="item.name" :src="item.icon" />
|
||||
<span>{{ item.level }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
type TucBuffProps = { modelValue: TGApp.Game.Combat.SplendourBuff };
|
||||
|
||||
const props = defineProps<TucBuffProps>();
|
||||
const columnCnt = computed<number>(() => {
|
||||
const len = props.modelValue.buffs.length;
|
||||
if ((len + 1) % 2 === 1) return len / 2 + 1;
|
||||
return (len + 1) / 2;
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-buff-box {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-gap: 4px;
|
||||
/* stylelint-disable value-keyword-case */
|
||||
grid-template-columns: repeat(v-bind(columnCnt), 1fr);
|
||||
/* stylelint-enable value-keyword-case */
|
||||
}
|
||||
|
||||
.tuc-buff-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--box-bg-3);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 0 4px;
|
||||
background: var(--common-shadow-2);
|
||||
border-bottom-right-radius: 4px;
|
||||
border-top-left-radius: 4px;
|
||||
color: var(--tgc-white-2);
|
||||
font-family: var(--font-title);
|
||||
font-size: 14px;
|
||||
text-shadow: 0 0 4px #00000033;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
100
src/components/userCombat/tuc-card-box.vue
Normal file
100
src/components/userCombat/tuc-card-box.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<!-- 剧诗,神秘收获 -->
|
||||
<template>
|
||||
<div v-if="props.modelValue.length > 0" class="tuc-card-box">
|
||||
<div class="tuc-card-title">神秘收获 {{ props.modelValue.length }}</div>
|
||||
<div class="tuc-card-list">
|
||||
<div v-for="(card, idx) in props.modelValue" :key="idx" class="tuc-card-item">
|
||||
<div class="tuc-ci-icon">
|
||||
<img :src="card.icon" alt="icon" />
|
||||
</div>
|
||||
<div class="tuc-ci-info">
|
||||
<div class="tuc-ci-title">{{ card.name }}</div>
|
||||
<div class="tuc-ci-desc" v-html="parseHtmlText(card.desc)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { parseHtmlText } from "@utils/toolFunc.js";
|
||||
|
||||
type TucCardBoxProps = {
|
||||
/* 神秘收获数据 */
|
||||
modelValue: Array<TGApp.Game.Combat.Card>;
|
||||
};
|
||||
|
||||
const props = defineProps<TucCardBoxProps>();
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.tuc-card-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-2);
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-card-title {
|
||||
color: var(--box-text-2);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tuc-card-list {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-card-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
column-gap: 8px;
|
||||
}
|
||||
|
||||
.tuc-ci-icon {
|
||||
position: relative;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background-color: var(--box-bg-3);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
filter: invert(1);
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.dark .tuc-ci-icon img {
|
||||
filter: unset;
|
||||
}
|
||||
|
||||
.tuc-ci-title {
|
||||
position: relative;
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tuc-ci-desc {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,41 +0,0 @@
|
||||
<template>
|
||||
<div class="tuc-cards-box">
|
||||
<div class="tuc-cards-item" v-for="(card, idx) in modelValue" :key="idx" :title="card.name">
|
||||
<img :src="card.icon" :alt="card.name" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ modelValue: Array<TGApp.Game.Combat.Card> }>();
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-cards-box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.tuc-cards-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 50px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
aspect-ratio: 1;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
filter: invert(1);
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.dark .tuc-cards-item {
|
||||
img {
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -9,7 +9,7 @@
|
||||
<div v-else-if="!Array.isArray(props.data)" class="tucfi-data">
|
||||
<TItemBox :model-value="getBox(props.data)" />
|
||||
</div>
|
||||
<div class="tucfi-icons" v-else>
|
||||
<div v-else class="tucfi-icons">
|
||||
<div v-for="(item, idx) in props.data" :key="idx" class="tucfi-icon">
|
||||
<TItemBox :model-value="getBox2(item)" />
|
||||
</div>
|
||||
@@ -68,17 +68,16 @@ function getBox2(item: TGApp.Game.Combat.AvatarMini): TItemBoxData {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background: var(--box-bg-1);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tucfi-label {
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tucfi-data {
|
||||
color: var(--tgc-yellow-1);
|
||||
font-family: var(--font-text);
|
||||
color: var(--box-text-8);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
<!-- 剧诗数据概览 -->
|
||||
<template>
|
||||
<div class="tuco-box">
|
||||
<TucTile title="最佳记录" :val="getBestVal()" />
|
||||
<TucTile :title="`获得星章-${props.data.medal_num}`" :val="props.data.get_medal_round_list" />
|
||||
<TucTile :title="getRoundTitle()" :val="getRoundVal()" />
|
||||
<TucTile title="消耗幻剧之花" :val="props.data.coin_num" />
|
||||
<TucFight label="最快完成演出" :data="props.fights.shortest_avatar_list" />
|
||||
<TucTile title="总耗时" :val="getTime()" />
|
||||
<!-- <TucTile title="助演角色支援" :val="`${props.data.rent_cnt}次`" />-->
|
||||
<!-- <TucTile title="场外声援" :val="`${props.data.avatar_bonus_num}次`" />-->
|
||||
<TucFight label="击败最多敌人" :data="props.fights.max_defeat_avatar" />
|
||||
<TucFight label="最高伤害输出" :data="props.fights.max_damage_avatar" />
|
||||
<TucFight label="最高承受伤害" :data="props.fights.max_take_damage_avatar" />
|
||||
<div class="tuco-line1">
|
||||
<TucTile :val="getBestVal()" title="最佳记录" />
|
||||
<TucTile :val="props.data.coin_num" title="消耗幻剧之花" />
|
||||
<TucTile :val="getTime()" title="总耗时" />
|
||||
<TucTile :title="getRoundTitle()" :val="getRoundVal()" />
|
||||
</div>
|
||||
<div class="tuco-line2">
|
||||
<TucFight :data="props.fights.max_defeat_avatar" label="击败最多敌人" />
|
||||
<TucFight :data="props.fights.max_take_damage_avatar" label="最高承受伤害" />
|
||||
<TucFight :data="props.fights.shortest_avatar_list" label="最快完成演出" />
|
||||
<TucFight :data="props.fights.max_damage_avatar" label="最高伤害输出" />
|
||||
</div>
|
||||
<div class="tuco-line3">
|
||||
<TucTile :val="`${props.data.rent_cnt}次`" title="助演角色支援" />
|
||||
<TucTile :title="`获得星章-${props.data.medal_num}`" :val="props.data.get_medal_round_list" />
|
||||
<TucTile :val="`${props.data.avatar_bonus_num}次`" title="场外声援" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -58,9 +65,36 @@ function getTime(): string {
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuco-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tuco-line1 {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
column-gap: 8px;
|
||||
grid-template-columns: 1fr 2fr 2fr 1fr;
|
||||
}
|
||||
|
||||
.tuco-line2 {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
column-gap: 8px;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.tuco-line3 {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
column-gap: 8px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
<!-- 真境剧诗,单轮次卡片组件 -->
|
||||
<!-- 剧诗单幕 -->
|
||||
<template>
|
||||
<div class="tucr-box">
|
||||
<div class="tucr-title">
|
||||
<img :src="`/icon/combat/${getIcon()}.webp`" alt="combat" />
|
||||
<span class="main" v-if="props.round.is_tarot">
|
||||
<img
|
||||
:class="`stat_${props.round.is_get_medal}`"
|
||||
:src="`/icon/combat/${getIcon()}.webp`"
|
||||
alt="combat"
|
||||
/>
|
||||
<span v-if="props.round.is_tarot" class="main">
|
||||
圣牌挑战·{{ props.round.tarot_serial_no }}
|
||||
</span>
|
||||
<span class="main" v-else>第{{ props.round.round_id }}幕</span>
|
||||
<span v-else class="main">第{{ props.round.round_id }}幕</span>
|
||||
<span class="sub">{{ timestampToDate(Number(props.round.finish_time) * 1000) }}</span>
|
||||
</div>
|
||||
<TucAeBox :avatars="props.round.avatars" :enemies="props.round.enemies" />
|
||||
<div class="tucr-content">
|
||||
<TucSub title="出演角色" class="main">
|
||||
<TucAvatars :model-value="props.round.avatars" :detail="true" />
|
||||
</TucSub>
|
||||
<TucSub title="辉彩祝福" class="main">
|
||||
<TucBuffs :model-value="props.round.splendour_buff" />
|
||||
</TucSub>
|
||||
<TucSub :title="`神秘收获(${props.round.choice_cards.length})`" class="sub">
|
||||
<TucCards :model-value="props.round.choice_cards" />
|
||||
</TucSub>
|
||||
<TucBuffBox :model-value="props.round.splendour_buff" />
|
||||
<TucCardBox :model-value="props.round.choice_cards" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { timestampToDate } from "@utils/toolFunc.js";
|
||||
|
||||
import TucAvatars from "./tuc-avatars.vue";
|
||||
import TucBuffs from "./tuc-buffs.vue";
|
||||
import TucCards from "./tuc-cards.vue";
|
||||
import TucSub from "./tuc-sub.vue";
|
||||
import TucAeBox from "./tuc-ae-box.vue";
|
||||
import TucBuffBox from "./tuc-buff-box.vue";
|
||||
import TucCardBox from "./tuc-card-box.vue";
|
||||
|
||||
type TucRoundProps = { round: TGApp.Game.Combat.RoundData };
|
||||
const props = defineProps<TucRoundProps>();
|
||||
@@ -37,7 +34,7 @@ function getIcon(): string {
|
||||
return `${props.round.is_tarot ? "tarot" : "star"}_${props.round.is_get_medal ? "1" : "0"}`;
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
<style lang="scss" scoped>
|
||||
.tucr-box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@@ -47,7 +44,7 @@ function getIcon(): string {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-1);
|
||||
row-gap: 4px;
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
.tucr-title {
|
||||
@@ -60,6 +57,10 @@ function getIcon(): string {
|
||||
img {
|
||||
height: 30px;
|
||||
object-fit: contain;
|
||||
|
||||
&.stat_false {
|
||||
filter: invert(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
@@ -74,15 +75,11 @@ function getIcon(): string {
|
||||
}
|
||||
|
||||
.tucr-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
align-items: flex-start;
|
||||
align-items: stretch;
|
||||
justify-content: flex-start;
|
||||
column-gap: 8px;
|
||||
|
||||
.sub {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<div class="tuc-sub-box">
|
||||
<div class="tuc-sub-title">{{ title }}</div>
|
||||
<slot name="default" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps<{ title: string }>();
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tuc-sub-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 205px;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--common-shadow-1);
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-2);
|
||||
}
|
||||
|
||||
.tuc-sub-title {
|
||||
margin-right: auto;
|
||||
color: var(--box-text-2);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
</style>
|
||||
@@ -1,21 +1,28 @@
|
||||
<!-- 真境剧诗概况卡片组件 -->
|
||||
<!-- 真境剧诗概况卡片 -->
|
||||
<template>
|
||||
<div class="tuct-box">
|
||||
<div class="tuct-title">
|
||||
<slot name="title">{{ props.title }}</slot>
|
||||
</div>
|
||||
<div class="tuct-text" v-if="!Array.isArray(props.val)">
|
||||
<div v-if="!Array.isArray(props.val)" class="tuct-text">
|
||||
<slot name="text">{{ props.val }}</slot>
|
||||
</div>
|
||||
<div class="tuct-icons" v-else>
|
||||
<div v-else class="tuct-icons">
|
||||
<template v-for="(v, idx) in props.val" :key="idx">
|
||||
<img
|
||||
v-if="idx < 10"
|
||||
:src="`/icon/combat/star_${v}.webp`"
|
||||
:alt="`${v}`"
|
||||
:class="`stat${v}`"
|
||||
:src="`/icon/combat/star_${v}.webp`"
|
||||
:title="`第${idx + 1}幕`"
|
||||
/>
|
||||
<img v-else :src="`/icon/combat/tarot_${v}.webp`" :alt="`${v}`" :title="`圣牌${idx - 9}`" />
|
||||
<img
|
||||
v-else
|
||||
:alt="`${v}`"
|
||||
:class="`stat${v}`"
|
||||
:src="`/icon/combat/tarot_${v}.webp`"
|
||||
:title="`圣牌${idx - 9}`"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,19 +43,17 @@ const props = defineProps<TucTileProps>();
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background: var(--box-bg-1);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
|
||||
.tuct-title {
|
||||
color: var(--box-text-4);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tuct-text {
|
||||
color: var(--tgc-yellow-1);
|
||||
font-family: var(--font-text);
|
||||
color: var(--box-text-8);
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tuct-icons {
|
||||
@@ -59,6 +64,14 @@ const props = defineProps<TucTileProps>();
|
||||
img {
|
||||
height: 30px;
|
||||
object-fit: contain;
|
||||
|
||||
&.stat0 {
|
||||
filter: invert(0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark .tuct-icons img.stat0 {
|
||||
filter: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- 真境剧诗页面 TODO: 重构UI -->
|
||||
<!-- 真境剧诗页面 -->
|
||||
<template>
|
||||
<v-app-bar>
|
||||
<template #prepend>
|
||||
@@ -6,19 +6,19 @@
|
||||
<img alt="icon" src="/source/UI/userCombat.webp" />
|
||||
<span>幻想真境剧诗</span>
|
||||
<v-select
|
||||
density="compact"
|
||||
variant="outlined"
|
||||
v-model="uidCur"
|
||||
:items="uidList"
|
||||
:hide-details="true"
|
||||
:items="uidList"
|
||||
density="compact"
|
||||
label="游戏UID"
|
||||
variant="outlined"
|
||||
/>
|
||||
<v-btn :rounded="true" class="uc-btn" @click="toAbyss()">
|
||||
<img src="/source/UI/userAbyss.webp" alt="abyss" />
|
||||
<img alt="abyss" src="/source/UI/userAbyss.webp" />
|
||||
<span>深境螺旋</span>
|
||||
</v-btn>
|
||||
<v-btn :rounded="true" class="uc-btn" @click="toChallenge()">
|
||||
<img src="/source/UI/userChallenge.webp" alt="challenge" />
|
||||
<img alt="challenge" src="/source/UI/userChallenge.webp" />
|
||||
<span>幽境危战</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
@@ -26,28 +26,28 @@
|
||||
<template #append>
|
||||
<div class="uct-right">
|
||||
<v-btn
|
||||
class="uc-btn"
|
||||
@click="shareCombat()"
|
||||
:rounded="true"
|
||||
:disabled="localCombat.length === 0"
|
||||
:rounded="true"
|
||||
class="uc-btn"
|
||||
prepend-icon="mdi-share"
|
||||
@click="shareCombat()"
|
||||
>
|
||||
分享
|
||||
</v-btn>
|
||||
<v-btn class="uc-btn" @click="refreshCombat()" :rounded="true" prepend-icon="mdi-refresh">
|
||||
<v-btn :rounded="true" class="uc-btn" prepend-icon="mdi-refresh" @click="refreshCombat()">
|
||||
刷新
|
||||
</v-btn>
|
||||
<v-btn class="uc-btn" @click="tryReadCombat()" :rounded="true" prepend-icon="mdi-download">
|
||||
<v-btn :rounded="true" class="uc-btn" prepend-icon="mdi-download" @click="tryReadCombat()">
|
||||
导入
|
||||
</v-btn>
|
||||
<v-btn class="uc-btn" @click="deleteCombat()" :rounded="true" prepend-icon="mdi-delete">
|
||||
<v-btn :rounded="true" class="uc-btn" prepend-icon="mdi-delete" @click="deleteCombat()">
|
||||
删除
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="uc-box">
|
||||
<v-tabs v-model="userTab" direction="vertical" class="uc-tabs-box" center-active>
|
||||
<v-tabs v-model="userTab" center-active class="uc-tabs-box" direction="vertical">
|
||||
<v-tab v-for="item in localCombat" :key="item.id" :value="item.id"> 第{{ item.id }}期</v-tab>
|
||||
</v-tabs>
|
||||
<v-window v-model="userTab" class="uc-window">
|
||||
@@ -64,15 +64,18 @@
|
||||
<span>{{ item.id }}</span>
|
||||
<span>期 UID</span>
|
||||
<span>{{ uidCur }}</span>
|
||||
<span>更新于</span>
|
||||
<span>{{ item.updated }}</span>
|
||||
</div>
|
||||
<div class="ucw-share">真境剧诗 | Render by TeyvatGuide v{{ version }}</div>
|
||||
</div>
|
||||
<TSubLine>统计周期 {{ item.startTime }} ~ {{ item.endTime }}</TSubLine>
|
||||
<TSubLine>
|
||||
<div class="ucw-subtitle">
|
||||
<span>统计周期 {{ item.startTime }} ~ {{ item.endTime }}</span>
|
||||
<span>{{ item.updated }}更新</span>
|
||||
</div>
|
||||
</TSubLine>
|
||||
<TucOverview :data="item.stat" :fights="item.detail.fight_statisic" />
|
||||
<TSubLine>使用角色({{ item.detail.backup_avatars.length }}名)</TSubLine>
|
||||
<TucAvatars :model-value="item.detail.backup_avatars" :detail="false" />
|
||||
<TucAvatars :detail="false" :model-value="item.detail.backup_avatars" />
|
||||
<div class="ucw-rounds">
|
||||
<TucRound v-for="(round, idx) in item.detail.rounds_data" :key="idx" :round="round" />
|
||||
</div>
|
||||
@@ -80,7 +83,7 @@
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
<div v-show="localCombat.length === 0" class="user-empty">
|
||||
<img src="/source/UI/empty.webp" alt="empty" />
|
||||
<img alt="empty" src="/source/UI/empty.webp" />
|
||||
<span>暂无数据,请尝试刷新</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -210,7 +213,7 @@ async function shareCombat(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
await showLoading.start("正在生成图片", fileName);
|
||||
await generateShareImg(fileName, shareDom);
|
||||
await generateShareImg(fileName, shareDom, 2.0);
|
||||
await showLoading.end();
|
||||
await TGLogger.Info(`[UserCombat][shareCombat][${userTab.value}] 生成剧诗数据分享图片成功`);
|
||||
}
|
||||
@@ -374,12 +377,12 @@ async function tryReadCombat(): Promise<void> {
|
||||
align-items: center;
|
||||
color: var(--common-text-title);
|
||||
column-gap: 4px;
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
font-size: 18px;
|
||||
|
||||
.ucw-title :nth-child(2n) {
|
||||
color: var(--tgc-yellow-1);
|
||||
:nth-child(2n) {
|
||||
color: var(--tgc-od-orange);
|
||||
font-family: var(--font-title);
|
||||
}
|
||||
}
|
||||
|
||||
.ucw-share {
|
||||
@@ -388,6 +391,16 @@ async function tryReadCombat(): Promise<void> {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.ucw-subtitle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 8px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.user-empty {
|
||||
position: absolute;
|
||||
top: calc(50vh - 200px);
|
||||
@@ -406,8 +419,11 @@ async function tryReadCombat(): Promise<void> {
|
||||
}
|
||||
|
||||
.ucw-rounds {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
row-gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -115,7 +115,6 @@ export async function generateShareImg(
|
||||
canvas,
|
||||
x: -15,
|
||||
y: -15,
|
||||
dpi: 350,
|
||||
};
|
||||
let canvasData;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user