|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
BIN
public/icon/challenge/bling.webp
Normal file
|
After Width: | Height: | Size: 418 B |
BIN
public/icon/challenge/buff.webp
Normal file
|
After Width: | Height: | Size: 516 B |
@@ -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> {
|
||||
|
||||
99
src/components/userChallenge/tuc-bling-item.vue
Normal 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>
|
||||
49
src/components/userChallenge/tuc-blings.vue
Normal 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>
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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%;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||