幽境危战

close #157
This commit is contained in:
BTMuli
2025-07-01 22:08:36 +08:00
parent aaf38e4526
commit 131fbe389c
18 changed files with 217 additions and 48 deletions

View File

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

View File

@@ -365,7 +365,7 @@ async function loadAccount(ac: string): Promise<void> {
return;
}
account.value = gameAccount;
showSnackbar.success(`成功切换到用户${uid}`);
showSnackbar.success(`成功切换到用户${uid.value}`);
}
async function confirmRefreshUser(ac: string): Promise<void> {

View File

@@ -0,0 +1,99 @@
<!-- 幽境危战赋光之人 -->
<template>
<div class="tuc-bling-item-comp" :title="props.bling.name">
<div class="bg">
<img :src="bg" alt="Avatar" />
</div>
<div class="icon">
<TMiImg :src="icon" :alt="props.bling.name" :ori="true" />
</div>
<div class="plus">
<img
src="/icon/challenge/bling.webp"
alt="Plus"
v-if="props.bling.is_plus"
title="恒昼辉光"
/>
<img src="/icon/challenge/buff.webp" alt="Buff" v-else title="辉光" />
</div>
</div>
</template>
<script lang="ts" setup>
import TMiImg from "@comp/app/t-mi-img.vue";
import { computed } from "vue";
import { AppCharacterData } from "@/data/index.js";
type TucblingItemProps = { bling: TGApp.Game.Challenge.ChallengeBling };
const props = defineProps<TucblingItemProps>();
const avatarR = computed<TGApp.App.Character.WikiBriefInfo | undefined>(() => {
const find = AppCharacterData.find((i) => i.id === props.bling.avatar_id);
if (find) return find;
return undefined;
});
const bg = computed<string>(() => {
if (avatarR.value) return `/icon/bg/${avatarR.value.star}-BGC.webp`;
return `/icon/bg/${props.bling.rarity > 5 ? 5 : props.bling.rarity}-BGC.webp`;
});
const icon = computed<string>(() => {
if (avatarR.value) return `/WIKI/character/${avatarR.value.id}.webp`;
return props.bling.image;
});
</script>
<style lang="scss" scoped>
.tuc-bling-item-comp {
position: relative;
display: flex;
width: 40px;
height: 40px;
align-items: flex-end;
justify-content: center;
border-radius: 50%;
}
.bg {
position: absolute;
z-index: 0;
overflow: hidden;
width: 100%;
height: 100%;
border-radius: 50%;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.icon {
position: relative;
z-index: 1;
overflow: hidden;
width: 36px;
height: 36px;
border-radius: 50%;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.plus {
position: absolute;
z-index: 2;
right: -2px;
bottom: -2px;
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
</style>

View File

@@ -0,0 +1,49 @@
<!-- 幽境危战玩家赋光之人 -->
<template>
<div class="tuc-blings-comp">
<div class="title">
<span>赋光之人</span>
<span>{{ plusLen }}/{{ props.data.length }}</span>
</div>
<div class="append">
<TucBlingItem :bling v-for="(bling, idx) in props.data" :key="idx" />
</div>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import TucBlingItem from "./tuc-bling-item.vue";
type TucBlingsProps = { data: TGApp.Game.Challenge.ChallengeBlings };
const props = defineProps<TucBlingsProps>();
const plusLen = computed<number>(() => props.data.filter((i) => i.is_plus).length);
</script>
<style lang="scss" scoped>
.tuc-blings-comp {
position: relative;
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
color: var(--box-text-1);
}
.title {
position: relative;
display: flex;
align-items: center;
justify-content: center;
column-gap: 8px;
font-family: var(--font-title);
font-size: 18px;
}
.append {
display: flex;
align-items: center;
gap: 8px;
}
</style>

View File

@@ -1,11 +1,9 @@
<!-- 幽境危战单个怪物挑战 -->
<template>
<div class="tuc-challenge-item-comp" @click="console.log(props.data)">
<div class="tuc-challenge-item-comp">
<div class="top-title">
<div class="name">{{ props.data.name }} Lv.{{ props.data.monster.level }}</div>
<div class="tags">
<TucMonsterTag v-for="(tag, idx) in props.data.monster.tags" :key="idx" :data="tag" />
</div>
<div class="append">
<span>战斗用时</span>
<span>{{ props.data.second }}</span>
@@ -45,9 +43,10 @@
<script lang="ts" setup>
import TItemBox, { type TItemBoxData } from "@comp/app/t-itemBox.vue";
import TMiImg from "@comp/app/t-mi-img.vue";
import TucMonsterTag from "@comp/userChallenge/tuc-monster-tag.vue";
import { getZhElement, parseHtmlText } from "@utils/toolFunc.js";
import TucMonsterTag from "./tuc-monster-tag.vue";
import { AppCharacterData } from "@/data/index.js";
type TucChallengeItemProps = { data: TGApp.Game.Challenge.ChallengeList };
@@ -114,28 +113,20 @@ function getTeamBox(avatar: TGApp.Game.Challenge.ChallengeTeam): TItemBoxData {
width: 100%;
align-items: center;
justify-content: flex-start;
column-gap: 12px;
column-gap: 8px;
.name {
font-family: var(--font-title);
font-size: 16px;
}
.tags {
position: relative;
display: flex;
align-items: center;
justify-content: center;
column-gap: 8px;
}
.append {
display: flex;
align-items: center;
margin-left: auto;
color: var(--box-text-2);
font-family: var(--font-title);
font-size: 14px;
font-size: 16px;
gap: 4px;
span {
@@ -226,16 +217,12 @@ function getTeamBox(avatar: TGApp.Game.Challenge.ChallengeTeam): TItemBoxData {
flex-direction: column;
align-items: flex-start;
justify-content: center;
row-gap: 8px;
row-gap: 12px;
span {
color: var(--box-text-1);
font-size: 14px;
line-height: 1.4;
font-size: 12px;
text-align: left;
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
:deep(span) {
font-weight: bold;

View File

@@ -45,7 +45,6 @@ function getElement(value: string): string {
}
function parseDesc(desc: string): Array<MonsterDesc> {
// {SPRITE_PRESET#11003}元素优势 => [{type: "element", value: "11003"}, {type: "text", value: "元素优势"}]
const regex = /{SPRITE_PRESET#(\d+)}([^{}]*)/g;
const result: Array<MonsterDesc> = [];
let match;
@@ -82,6 +81,7 @@ function parseDesc(desc: string): Array<MonsterDesc> {
color: var(--box-text-1);
font-family: var(--font-title);
font-size: 12px;
line-height: 16px;
}
&.buff-0 {

View File

@@ -1,6 +1,6 @@
<!-- 幽境危战单人/联机数据总览 -->
<template>
<div class="tuc-overview-comp" @click="onClick()">
<div class="tuc-overview-comp">
<div class="toc-top-title">
<div class="title">{{ props.title }}{{ props.data.has_data ? "" : " (无数据) " }}</div>
<div class="append" v-if="props.data.best">
@@ -8,7 +8,7 @@
<span>{{ props.data.best.second }}s</span>
<img
:title="getDiffTitle(props.data.best)"
:src="`/icon/medals/${props.data.best.icon}.webp`"
:src="`/icon/challenge/UI_LeyLineChallenge_Medal_${props.data.best.difficulty}.webp`"
alt="medal"
/>
</div>
@@ -21,19 +21,12 @@
</div>
</template>
<script lang="ts" setup>
import TucChallengeItem from "@comp/userChallenge/tuc-challenge-item.vue";
import TucChallengeItem from "./tuc-challenge-item.vue";
type TucOverviewProps = {
title: string;
data: TGApp.Game.Challenge.Challenge;
};
type TucOverviewProps = { title: string; data: TGApp.Game.Challenge.Challenge };
const props = defineProps<TucOverviewProps>();
function onClick(): void {
console.log(props.data);
}
function getDiffTitle(best: TGApp.Game.Challenge.ChallengeBest): string {
switch (best.difficulty) {
case 1:
@@ -73,8 +66,7 @@ function getDiffTitle(best: TGApp.Game.Challenge.ChallengeBest): string {
.title {
font-family: var(--font-title);
font-size: 16px;
font-weight: bold;
font-size: 18px;
}
.append {
@@ -85,11 +77,17 @@ function getDiffTitle(best: TGApp.Game.Challenge.ChallengeBest): string {
span {
font-size: 14px;
&:nth-child(2) {
color: var(--tgc-yellow-1);
font-family: var(--font-title);
font-size: 16px;
}
}
img {
width: 24px;
height: 24px;
width: 32px;
height: 32px;
object-fit: contain;
}
}

View File

@@ -7,6 +7,9 @@
<div class="icon">
<TMiImg :src="icon" :alt="props.avatar.name" :ori="true" />
</div>
<div class="buff" title="赋光之人">
<img src="/icon/challenge/buff.webp" alt="Buff" />
</div>
</div>
</template>
<script lang="ts" setup>
@@ -36,16 +39,11 @@ const icon = computed<string>(() => {
.tuc-pop-item-comp {
position: relative;
display: flex;
overflow: hidden;
width: 40px;
height: 40px;
align-items: flex-end;
justify-content: center;
border-radius: 50%;
&:hover {
filter: brightness(0.9);
}
}
.bg {
@@ -54,6 +52,7 @@ const icon = computed<string>(() => {
overflow: hidden;
width: 100%;
height: 100%;
border-radius: 50%;
img {
width: 100%;
@@ -65,8 +64,25 @@ const icon = computed<string>(() => {
.icon {
position: relative;
z-index: 1;
overflow: hidden;
width: 36px;
height: 36px;
border-radius: 50%;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.buff {
position: absolute;
z-index: 2;
right: 0;
bottom: 0;
width: 16px;
height: 16px;
img {
width: 100%;

View File

@@ -12,6 +12,7 @@
:items="uidList"
:hide-details="true"
label="游戏UID"
@update:model-value="switchUid"
/>
<v-btn :rounded="true" class="ucp-btn" @click="toAbyss()">
<img src="/source/UI/userAbyss.webp" alt="abyss" />
@@ -101,8 +102,11 @@
<span>{{ item.startTime }} ~ {{ item.endTime }}</span>
<span>更新于 {{ item.updated }}</span>
</div>
<div class="ucw-share">幽境危战 | Render by TeyvatGuide v{{ version }}</div>
<div class="ucw-share">
幽境危战 | UID-{{ item.uid }} | Render by TeyvatGuide v{{ version }}
</div>
</div>
<TucBlings :data="item.blings" v-if="item.blings.length > 0" />
<TucOverview title="单人模式" :data="item.single" />
<TucOverview title="联机模式" :data="item.mp" v-if="item.mp.has_data" />
</div>
@@ -118,6 +122,7 @@
import showDialog from "@comp/func/dialog.js";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TucBlings from "@comp/userChallenge/tuc-blings.vue";
import TucOverview from "@comp/userChallenge/tuc-overview.vue";
import TucPopItem from "@comp/userChallenge/tuc-pop-item.vue";
import { GameServerEnum, getGameServerDesc } from "@enum/game.js";
@@ -161,6 +166,7 @@ onMounted(async () => {
version.value = await getVersion();
await TGLogger.Info("[UserCombat][onMounted] 打开幽境危战页面");
await reloadChallenge();
if (uidCur.value?.startsWith("5")) server.value = GameServerEnum.CN_QD01;
await refreshPopList(false);
});
@@ -173,6 +179,17 @@ watch(
},
);
async function switchUid(): Promise<void> {
if (uidCur.value === undefined || uidCur.value === "") return;
await TGLogger.Info(`[UserChallenge][watch][uidCur] 切换UID: ${uidCur.value}`);
await showLoading.start(`正在加载UID ${uidCur.value} 的幽境危战数据`);
await loadChallenge();
await showLoading.end();
showSnackbar.success(
`已加载UID ${uidCur.value}${localChallenge.value.length} 条幽境危战数据`,
);
}
async function toAbyss(): Promise<void> {
await router.push({ name: "深境螺旋" });
}
@@ -208,19 +225,20 @@ async function shareChallenge(): Promise<void> {
async function reloadChallenge(): Promise<void> {
localChallenge.value = [];
uidList.value = [];
await showLoading.start("正在加载UID列表");
uidList.value = await TSUserChallenge.getAllUid();
if (uidList.value.length === 0) {
uidCur.value = "";
} else {
if (uidCur.value === undefined || uidCur.value === "") {
if (uidList.value.includes(account.value.gameUid)) uidCur.value = account.value.gameUid;
else uidCur.value = uidList.value[0];
}
await showLoading.update(`正在加载UID${uidCur.value}的幽境危战数据`);
await loadChallenge();
}
await showLoading.end();
if (uidCur.value?.length > 0) {
if (uidCur.value !== undefined && uidCur.value !== "") {
showSnackbar.success(
`已加载UID ${uidCur.value}${localChallenge.value.length} 条幽境危战数据`,
);
@@ -288,6 +306,7 @@ async function refreshChallenge(): Promise<void> {
}
isReq.value = false;
await showLoading.end();
uidCur.value = account.value.gameUid;
await reloadChallenge();
}
@@ -308,6 +327,7 @@ async function deleteChallenge(): Promise<void> {
await showLoading.start("正在删除幽境危战数据", `UID: ${uidCur.value}`);
await TSUserChallenge.delChallenge(uidCur.value);
showSnackbar.success(`已清除 ${uidCur.value} 的幽境危战数据`);
uidCur.value = "";
await reloadChallenge();
}