🌱 卡片视图适配,2/3

#121
This commit is contained in:
目棃
2024-08-24 20:00:23 +08:00
parent 1fe33ba4fd
commit 4dd14a9d93
11 changed files with 319 additions and 336 deletions

View File

@@ -1,225 +0,0 @@
<template>
<TOverlay v-model="visible" hide :to-click="onOverlayCancel" blur-val="20px">
<div class="duc-do-box">
<!-- 左侧箭头 -->
<div class="duc-arrow-left" @click="handleClick('left')">
<img src="../../assets/icons/arrow-right.svg" alt="left" />
</div>
<!-- 中间内容 -->
<div class="duc-do-container">
<img :src="nameCard" class="duc-doc-bg" v-if="nameCard !== false" alt="bg" />
<div class="duc-doc-bgc" />
<!-- 左上角色跟武器 -->
<div class="duc-doc-lt">
<DucDetailOlt :data="props.dataVal" mode="avatar" />
<DucDetailOlt :data="JSON.parse(props.dataVal.weapon)" mode="weapon" />
<DucDetailRelics :data="props.dataVal.reliquary" />
</div>
<v-btn
class="duc-doc-btn"
@click="share"
variant="outlined"
:loading="loading"
data-html2canvas-ignore
>
<v-icon>mdi-share-variant</v-icon>
<span>分享</span>
</v-btn>
<!-- 右侧天赋 -->
<div class="duc-doc-rt">
<DucDetailOrt :model-value="JSON.parse(props.dataVal.talent)" />
</div>
<!-- 左下命座 -->
<div class="duc-doc-lb">
<DucDetailOlb :model-value="JSON.parse(props.dataVal.constellation)" />
</div>
<!-- 底部水印信息 -->
<div class="duc-doc-bt">
UID: {{ props.dataVal.uid }} Updated: {{ props.dataVal.updated }} | Rendered by
TeyvatGuide v{{ version }}
</div>
</div>
<!-- 右侧箭头 -->
<div class="duc-arrow-right" @click="handleClick('right')">
<img src="../../assets/icons/arrow-right.svg" alt="right" />
</div>
</div>
</TOverlay>
</template>
<script lang="ts" setup>
import { app } from "@tauri-apps/api";
import { computed, onMounted, onUpdated, ref } from "vue";
import TGSqlite from "../../plugins/Sqlite/index.js";
import { generateShareImg } from "../../utils/TGShare.js";
import TOverlay from "../main/t-overlay.vue";
import DucDetailOlb from "./duc-detail-olb.vue";
import DucDetailOlt from "./duc-detail-olt.vue";
import DucDetailOrt from "./duc-detail-ort.vue";
import DucDetailRelics from "./duc-detail-relics.vue";
interface DucDetailOverlayProps {
modelValue: boolean;
dataVal: TGApp.Sqlite.Character.UserRole;
}
type DucDetailOverlayEmits = {
(e: "update:modelValue", value: boolean): void;
(e: "clickL"): void;
(e: "clickR"): void;
};
const props = defineProps<DucDetailOverlayProps>();
const emits = defineEmits<DucDetailOverlayEmits>();
const version = await app.getVersion();
const visible = computed({
get: () => props.modelValue,
set: (value) => {
emits("update:modelValue", value);
},
});
// share
const loading = ref<boolean>(false);
// 渲染数据
const nameCard = ref<string | false>(false);
function onOverlayCancel() {
visible.value = false;
emits("update:modelValue", false);
}
function handleClick(pos: "left" | "right") {
pos === "left" ? emits("clickL") : emits("clickR");
}
onMounted(async () => {
await loadData();
});
onUpdated(async () => {
await loadData();
console.log("updated, loadData");
console.log(props.dataVal);
});
async function loadData(): Promise<void> {
if (!props.modelValue) return;
if (props.dataVal.cid !== 10000005 && props.dataVal.cid !== 10000007) {
const role = await TGSqlite.getAppCharacter(props.dataVal.cid);
nameCard.value = `/source/nameCard/profile/${role.nameCard}.webp`;
} else {
nameCard.value = "/source/nameCard/profile/原神·印象.webp";
}
}
async function share(): Promise<void> {
const detailBox = <HTMLElement>document.querySelector(".duc-do-container");
const fileName = `【角色详情】-${props.dataVal.name}`;
loading.value = true;
await generateShareImg(fileName, detailBox);
loading.value = false;
}
</script>
<style lang="css" scoped>
.duc-do-box {
display: flex;
align-items: center;
justify-content: space-between;
column-gap: 10px;
}
.duc-arrow-left,
.duc-arrow-right {
position: relative;
display: flex;
width: 30px;
height: 30px;
align-items: center;
justify-content: center;
cursor: pointer;
}
.dark .duc-arrow-left,
.dark .duc-arrow-right {
filter: invert(11%) sepia(73%) saturate(11%) hue-rotate(139deg) brightness(97%) contrast(81%);
}
.duc-arrow-left img {
width: 100%;
height: 100%;
transform: rotate(180deg);
}
.duc-arrow-right img {
width: 100%;
height: 100%;
}
.duc-do-container {
position: relative;
overflow: hidden;
width: 800px;
border-radius: 5px;
aspect-ratio: 21 / 10;
background: var(--box-bg-1);
}
.duc-doc-bg {
position: absolute;
right: 0;
left: 0;
width: 100%;
height: 100%;
}
.duc-doc-bgc {
position: absolute;
right: 0;
left: 0;
width: 100%;
height: 100%;
background: rgb(0 0 0 / 20%);
}
.duc-doc-lt {
position: absolute;
top: 10px;
left: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5px;
row-gap: 10px;
}
.duc-doc-btn {
position: absolute;
bottom: 90px;
left: 370px;
color: var(--tgc-white-1);
}
.duc-doc-rt {
position: absolute;
top: 10px;
right: 10px;
padding: 5px;
}
.duc-doc-lb {
position: absolute;
bottom: 10px;
left: 10px;
padding: 5px;
}
.duc-doc-bt {
position: absolute;
right: 10px;
bottom: -1px;
color: var(--tgc-white-1);
font-size: 12px;
text-shadow: 0 0 2px var(--tgc-dark-2);
}
</style>

View File

@@ -1,45 +0,0 @@
<template>
<div class="ddr-box">
<DucDetailRelic
v-for="(relic, index) in transData"
:key="index"
:model-value="relic"
:pos="index + 1"
/>
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
import DucDetailRelic from "./duc-detail-relic.vue";
interface DucDetailRelicsProps {
data: string;
}
const props = defineProps<DucDetailRelicsProps>();
const transData = computed<Array<TGApp.Sqlite.Character.RoleReliquary | false>>(() => {
if (!props.data || props.data === "") return [false, false, false, false, false];
try {
const parsedData: TGApp.Sqlite.Character.RoleReliquary[] = JSON.parse(props.data);
let relics: Array<TGApp.Sqlite.Character.RoleReliquary | false> = [];
for (let i = 0; i < 5; i++) {
const relic = parsedData.find((relic) => relic.pos === i + 1);
if (relic) relics.push(relic);
else relics.push(false);
}
return relics;
} catch (e) {
console.error(e);
return [false, false, false, false, false];
}
});
</script>
<style lang="css" scoped>
.ddr-box {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 10px;
}
</style>

View File

@@ -1,12 +1,13 @@
<template>
<TOverlay v-model="visible" hide :to-click="onCancel" blur-val="20px">
<TOverlay v-model="visible" hide blur-val="20px">
<div class="tdo-box">
<div class="tdo-tabs-container">
<v-tabs v-model="modeTab" class="tdo-tabs" :rounded="true">
<v-tabs v-model="modeTab" class="tdo-tabs">
<v-tab value="classic">经典视图</v-tab>
<v-tab value="card">卡片视图简略</v-tab>
<v-tab value="dev">卡片视图详细</v-tab>
</v-tabs>
<v-btn @click="onCancel" icon="mdi-close" size="28" variant="outlined" />
</div>
<div class="tdo-container">
<div class="tdo-box-arrow left" @click="handleClick('left')">
@@ -14,10 +15,12 @@
</div>
<v-window class="tdo-box-container" v-model="modeTab">
<v-window-item value="classic">
<TucDetailCard :data-val="avatar" />
<TucDetailOld :model-value="avatar" />
</v-window-item>
<v-window-item value="card"> </v-window-item>
<v-window-item value="dev"> </v-window-item>
<v-window-item value="card">
<TucDetailCard :model-value="avatar" />
</v-window-item>
<v-window-item value="dev"></v-window-item>
</v-window>
<div class="tdo-box-arrow right" @click="handleClick('right')">
<img alt="right" src="../../assets/icons/arrow-right.svg" />
@@ -30,7 +33,8 @@
import { computed } from "vue";
import TOverlay from "../main/t-overlay.vue";
import TucDetailCard from "../userAvatarOld/tuc-detail-card.vue";
import TucDetailCard from "../userAvatarCard/tuc-detail-card.vue";
import TucDetailOld from "../userAvatarOld/tuc-detail-old.vue";
interface TuaDetailOverlayProps {
modelValue: boolean;
@@ -78,9 +82,15 @@ function handleClick(pos: "left" | "right"): void {
}
.tdo-tabs-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
border-radius: 10px;
background: var(--box-bg-1);
box-shadow: 0 0 10px var(--common-shadow-2);
box-shadow: 0 0 5px var(--common-shadow-2);
color: var(--box-text-1);
column-gap: 10px;
}
.tdo-container {
@@ -117,5 +127,6 @@ function handleClick(pos: "left" | "right"): void {
.tdo-box-container {
position: relative;
transition: all 1s ease-in-out;
}
</style>

View File

@@ -6,7 +6,7 @@
:title="constellation.name"
class="duc-dolb-item"
>
<div v-if="!constellation.active" class="duc-dolb-lock">
<div v-if="!constellation.is_actived" class="duc-dolb-lock">
<v-icon color="white">mdi-lock</v-icon>
</div>
<img class="duc-dolb-icon" :src="constellation.icon" alt="constellation" />
@@ -14,19 +14,19 @@
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUpdated, ref } from "vue";
import { onMounted, ref, watch, onUnmounted } from "vue";
import { saveImgLocal } from "../../utils/TGShare.js";
interface DucDetailOlbProps {
modelValue: TGApp.Sqlite.Character.RoleConstellation[];
modelValue: TGApp.Game.Avatar.Constellation[];
}
const props = defineProps<DucDetailOlbProps>();
const constellations = ref<TGApp.Sqlite.Character.RoleConstellation[]>([]);
const constellations = ref<TGApp.Game.Avatar.Constellation[]>([]);
async function loadData() {
const tempConstellations = props.modelValue;
const tempConstellations = JSON.parse(JSON.stringify(props.modelValue));
for (const constellation of tempConstellations) {
if (constellation.icon.startsWith("blob:")) return;
constellation.icon = await saveImgLocal(constellation.icon);
@@ -37,9 +37,23 @@ async function loadData() {
onMounted(async () => {
await loadData();
});
onUpdated(async () => {
await loadData();
watch(
() => props.modelValue,
async () => {
for (const constellation of constellations.value) {
if (constellation.icon.startsWith("blob:")) {
URL.revokeObjectURL(constellation.icon);
}
}
await loadData();
},
);
onUnmounted(() => {
for (const constellation of constellations.value) {
if (constellation.icon.startsWith("blob:")) {
URL.revokeObjectURL(constellation.icon);
}
}
});
</script>
<style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="ddo-lt-box">
<div class="ddo-ltb-icon" :title="getTitle">
<div class="ddo-ltb-icon" :title="props.data.name">
<TItemBox :model-value="boxData" />
</div>
<div class="ddo-ltb-info">
@@ -13,67 +13,58 @@
<script lang="ts" setup>
import { computed } from "vue";
import { getZhElement } from "../../utils/toolFunc.js";
import TItemBox, { TItemBoxData } from "../main/t-itembox.vue";
type DucDetailOltProps =
| {
data: TGApp.Sqlite.Character.UserRole;
data: TGApp.Game.Avatar.Avatar;
mode: "avatar";
}
| {
data: TGApp.Sqlite.Character.RoleWeapon;
data: TGApp.Game.Avatar.WeaponDetail;
mode: "weapon";
};
const props = defineProps<DucDetailOltProps>();
const getTitle = computed(() => {
if (props.mode === "avatar") {
return `${props.data.name}`;
} else {
const descriptionList = props.data.description.split("");
return descriptionList.reduce((prev: string, cur: string, index: number) => {
if (index % 10 === 0) {
return `${prev}\n${cur}`;
} else {
return `${prev}${cur}`;
}
}, "");
}
});
const boxData = computed<TItemBoxData>(() => {
if (props.mode === "avatar") {
const avatar = <TGApp.Game.Avatar.Avatar>props.data;
return {
bg: `/icon/bg/${props.data.star}-Star.webp`,
icon: `/WIKI/character/${props.data.cid}.webp`,
bg: `/icon/bg/${avatar.rarity}-Star.webp`,
icon: `/WIKI/character/${avatar.id}.webp`,
size: "100px",
height: "100px",
display: "inner",
innerHeight: 0,
innerText: "",
clickable: false,
lt: `/icon/element/${props.data.element}.webp`,
lt: `/icon/element/${getZhElement(avatar.element)}元素.webp`,
ltSize: "30px",
};
} else {
const weapon = <TGApp.Game.Avatar.WeaponDetail>props.data;
return {
bg: `/icon/bg/${props.data.star}-Star.webp`,
icon: `/WIKI/weapon/${props.data.id}.webp`,
bg: `/icon/bg/${weapon.rarity}-Star.webp`,
icon: `/WIKI/weapon/${weapon.id}.webp`,
size: "100px",
height: "100px",
display: "inner",
innerHeight: 0,
innerText: "",
clickable: false,
lt: `/icon/weapon/${props.data.type}.webp`,
lt: `/icon/weapon/${weapon.type_name}.webp`,
ltSize: "30px",
};
}
});
const info = computed(() => {
if (props.mode === "avatar") {
return `好感 ${props.data.fetter}`;
const avatar = <TGApp.Game.Avatar.Avatar>props.data;
return `好感 ${avatar.fetter}`;
} else {
return `精炼 ${props.data.affix}`;
const weapon = <TGApp.Game.Avatar.WeaponDetail>props.data;
return `精炼 ${weapon.affix_level}`;
}
});
</script>

View File

@@ -1,6 +1,11 @@
<template>
<div class="duc-dort-box">
<div :title="talent.name" v-for="talent in talents" :key="talent.pos" class="duc-dort-item">
<div
:title="talent.name"
v-for="talent in talents"
:key="talent.skill_id"
class="duc-dort-item"
>
<span>{{ talent.name }}</span>
<img :src="talent.icon" alt="talent" />
<span>Lv.{{ talent.level === 0 ? 1 : talent.level }}</span>
@@ -8,19 +13,19 @@
</div>
</template>
<script lang="ts" setup>
import { onMounted, onUpdated, ref } from "vue";
import { onMounted, watch, ref, onUnmounted } from "vue";
import { saveImgLocal } from "../../utils/TGShare.js";
interface DucDetailOrtProps {
modelValue: TGApp.Sqlite.Character.RoleTalent[];
modelValue: TGApp.Game.Avatar.Skill[];
}
const props = defineProps<DucDetailOrtProps>();
const talents = ref<TGApp.Sqlite.Character.RoleTalent[]>([]);
const talents = ref<TGApp.Game.Avatar.Skill[]>([]);
async function loadData(): Promise<void> {
const tempTalent = props.modelValue;
const tempTalent = JSON.parse(JSON.stringify(props.modelValue));
for (const talent of tempTalent) {
if (talent.icon.startsWith("blob:")) return;
talent.icon = await saveImgLocal(talent.icon);
@@ -31,9 +36,23 @@ async function loadData(): Promise<void> {
onMounted(async () => {
await loadData();
});
onUpdated(async () => {
await loadData();
watch(
() => props.modelValue,
async () => {
for (const talent of talents.value) {
if (talent.icon.startsWith("blob:")) {
URL.revokeObjectURL(talent.icon);
}
}
await loadData();
},
);
onUnmounted(() => {
for (const talent of talents.value) {
if (talent.icon.startsWith("blob:")) {
URL.revokeObjectURL(talent.icon);
}
}
});
</script>
<style lang="css" scoped>

View File

@@ -4,7 +4,7 @@
<img :src="`/icon/relic/${props.pos}.webp`" alt="relic" />
</div>
<div v-if="props.modelValue" class="duc-dr-bg">
<img :src="`/icon/bg/${props.modelValue.star}-Star.webp`" alt="bg" />
<img :src="`/icon/bg/${props.modelValue.rarity}-Star.webp`" alt="bg" />
</div>
<div v-if="props.modelValue" class="duc-dr-icon">
<img :src="props.modelValue.icon" alt="relic" />
@@ -15,12 +15,23 @@
</div>
</template>
<script lang="ts" setup>
import { computed } from "vue";
interface ducDetailRelicProps {
modelValue: TGApp.Sqlite.Character.RoleReliquary | false;
modelValue: TGApp.Game.Avatar.Relic | false;
pos: number;
}
const props = defineProps<ducDetailRelicProps>();
const relicBg = computed<string>(() => {
if (props.modelValue === false) return "transparent";
if (props.modelValue.rarity === 0 || props.modelValue.rarity === 1) return "var(--tgc-od-white)";
if (props.modelValue.rarity === 2) return "var(--tgc-od-green)";
if (props.modelValue.rarity === 3) return "var(--tgc-od-blue)";
if (props.modelValue.rarity === 4) return "var(--tgc-od-purple)";
if (props.modelValue.rarity === 5) return "var(--tgc-od-orange)";
return "var(--tgc-od-red)";
});
</script>
<style lang="css" scoped>
.duc-dr-box {
@@ -72,8 +83,9 @@ const props = defineProps<ducDetailRelicProps>();
height: 24px;
align-items: center;
justify-content: center;
border: 2px solid var(--tgc-od-red);
border-radius: 50%;
background: var(--tgc-yellow-3);
background: v-bind(relicBg);
color: var(--tgc-white-1);
font-family: var(--font-title);
font-size: 12px;

View File

@@ -0,0 +1,184 @@
<template>
<div class="duc-do-container">
<img :src="nameCard" class="duc-doc-bg" v-if="nameCard !== false" alt="bg" />
<div class="duc-doc-bgc" />
<!-- 左上角色跟武器 -->
<div class="duc-doc-lt">
<DucDetailOlt :data="props.modelValue.avatar" mode="avatar" />
<DucDetailOlt :data="props.modelValue.weapon" mode="weapon" />
<div class="duc-relic">
<DucDetailRelic
v-for="(relic, index) in relicList"
:key="index"
:model-value="relic"
:pos="index + 1"
/>
</div>
</div>
<v-btn
class="duc-doc-btn"
@click="share"
variant="outlined"
:loading="loading"
data-html2canvas-ignore
>
<v-icon>mdi-share-variant</v-icon>
<span>分享</span>
</v-btn>
<!-- 右侧天赋 -->
<div class="duc-doc-rt">
<DucDetailOrt :model-value="props.modelValue.skills" />
</div>
<!-- 左下命座 -->
<div class="duc-doc-lb">
<DucDetailOlb :model-value="props.modelValue.constellations" />
</div>
<!-- 底部水印信息 -->
<div class="duc-doc-bt">
UID: {{ props.modelValue.uid }} Updated: {{ props.modelValue.updated }} | Rendered by
TeyvatGuide v{{ version }}
</div>
</div>
</template>
<script lang="ts" setup>
import { app } from "@tauri-apps/api";
import { computed, ref, watch, onMounted } from "vue";
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
import { generateShareImg } from "../../utils/TGShare.js";
import DucDetailOlb from "./duc-detail-olb.vue";
import DucDetailOlt from "./duc-detail-olt.vue";
import DucDetailOrt from "./duc-detail-ort.vue";
import DucDetailRelic from "./duc-detail-relic.vue";
interface DucDetailOverlayProps {
modelValue: TGApp.Sqlite.Character.UserRole;
}
type fixedLenArray<T, N extends number> = [T, ...T[]] & { length: N };
type RelicList = fixedLenArray<TGApp.Game.Avatar.Relic | false, 5>;
const props = defineProps<DucDetailOverlayProps>();
const version = await app.getVersion();
const loading = ref<boolean>(false);
const relicList = computed<RelicList>(() => {
return [
props.modelValue.relics.find((item) => item.pos === 1) || false,
props.modelValue.relics.find((item) => item.pos === 2) || false,
props.modelValue.relics.find((item) => item.pos === 3) || false,
props.modelValue.relics.find((item) => item.pos === 4) || false,
props.modelValue.relics.find((item) => item.pos === 5) || false,
];
});
const nameCard = ref<string | false>(false);
onMounted(async () => {
await loadData();
});
watch(
() => props.modelValue,
async () => {
await loadData();
},
);
async function loadData(): Promise<void> {
if (props.modelValue.cid === 10000005 || props.modelValue.cid === 10000007) {
nameCard.value = "/source/nameCard/profile/原神·印象.webp";
} else {
const card = await TSUserAvatar.getAvatarCard(props.modelValue.cid);
if (card !== false) {
nameCard.value = `/source/nameCard/profile/${card}.webp`;
} else {
nameCard.value = false;
}
}
}
async function share(): Promise<void> {
const detailBox = <HTMLElement>document.querySelector(".duc-do-container");
const fileName = `【角色详情】-${props.modelValue.avatar.name}`;
loading.value = true;
await generateShareImg(fileName, detailBox);
loading.value = false;
}
</script>
<style lang="css" scoped>
.duc-do-container {
position: relative;
overflow: hidden;
width: 800px;
border-radius: 5px;
aspect-ratio: 21 / 10;
background: var(--box-bg-1);
}
.duc-doc-bg {
position: absolute;
right: 0;
left: 0;
width: 100%;
height: 100%;
}
.duc-doc-bgc {
position: absolute;
right: 0;
left: 0;
width: 100%;
height: 100%;
background: rgb(0 0 0 / 20%);
}
.duc-doc-lt {
position: absolute;
top: 10px;
left: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5px;
row-gap: 10px;
}
.duc-relic {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 10px;
}
.duc-doc-btn {
position: absolute;
bottom: 90px;
left: 370px;
color: var(--tgc-white-1);
}
.duc-doc-rt {
position: absolute;
top: 10px;
right: 10px;
padding: 5px;
}
.duc-doc-lb {
position: absolute;
bottom: 10px;
left: 10px;
padding: 5px;
}
.duc-doc-bt {
position: absolute;
right: 10px;
bottom: -1px;
color: var(--tgc-white-1);
font-size: 12px;
text-shadow: 0 0 2px var(--tgc-dark-2);
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="tuc-do-box">
<img :src="bg" alt="role" class="tuc-do-bg" />
<div v-if="props.dataVal.costumes.length > 0" class="tuc-do-costume">
<div v-if="props.modelValue.costumes.length > 0" class="tuc-do-costume">
<v-switch v-model="showCostumeSwitch" color="#fb7299" @click="switchBg">
<template #label>
<v-icon>mdi-tshirt-crew-outline</v-icon>
@@ -9,7 +9,7 @@
</v-switch>
</div>
<div v-if="showCostumeSwitch" class="tuc-do-costume-name">
{{ props.dataVal.costumes[0].name }}
{{ props.modelValue.costumes[0].name }}
</div>
<div class="tuc-do-show">
<div class="tuc-do-main">
@@ -17,7 +17,7 @@
<div
class="tuc-dol-item"
:style="`opacity: ${selected.pos === 0 ? '1' : '0.5'}`"
@click="showDetail(props.dataVal.weapon, '武器', 0)"
@click="showDetail(props.modelValue.weapon, '武器', 0)"
>
<TucDetailItemBox :model-value="weaponBox" />
</div>
@@ -38,7 +38,7 @@
<div class="tuc-do-right">
<div class="tuc-dor-box">
<TucDetailConstellation
v-for="item in props.dataVal.constellations"
v-for="item in props.modelValue.constellations"
:key="item.pos"
class="tuc-dor-item"
:model-value="item"
@@ -52,7 +52,10 @@
</div>
<!-- 底部说明 -->
<div class="tuc-do-bottom">
<TucDetailDescWeapon v-if="selected.type === '武器'" :model-value="props.dataVal.weapon" />
<TucDetailDescWeapon
v-if="selected.type === '武器'"
:model-value="props.modelValue.weapon"
/>
<TucDetailDescConstellation
v-if="selected.type === '命座' && selectConstellation"
:model-value="selectConstellation"
@@ -77,7 +80,7 @@ import TucDetailItemBox from "./tuc-detail-itembox.vue";
import TucDetailRelic from "./tuc-detail-relic.vue";
interface ToUcDetailProps {
dataVal: TGApp.Sqlite.Character.UserRole;
modelValue: TGApp.Sqlite.Character.UserRole;
}
interface ToUcDetailSelect {
@@ -91,15 +94,15 @@ type RelicList = fixedLenArray<TGApp.Game.Avatar.Relic | false, 5>;
const props = defineProps<ToUcDetailProps>();
const relicList = computed<RelicList>(() => {
return [
props.dataVal.relics.find((item) => item.pos === 1) || false,
props.dataVal.relics.find((item) => item.pos === 2) || false,
props.dataVal.relics.find((item) => item.pos === 3) || false,
props.dataVal.relics.find((item) => item.pos === 4) || false,
props.dataVal.relics.find((item) => item.pos === 5) || false,
props.modelValue.relics.find((item) => item.pos === 1) || false,
props.modelValue.relics.find((item) => item.pos === 2) || false,
props.modelValue.relics.find((item) => item.pos === 3) || false,
props.modelValue.relics.find((item) => item.pos === 4) || false,
props.modelValue.relics.find((item) => item.pos === 5) || false,
];
});
const weaponBox = computed(() => {
const weapon = props.dataVal.weapon;
const weapon = props.modelValue.weapon;
return {
icon: `/WIKI/weapon/${weapon.id}.webp`,
bg: `/icon/bg/${weapon.rarity}-Star.webp`,
@@ -110,7 +113,9 @@ const selectConstellation = ref<TGApp.Game.Avatar.Constellation>();
const selectRelic = ref<TGApp.Game.Avatar.Relic>();
const selected = ref<ToUcDetailSelect>({ type: "武器", pos: 0 });
const bg = computed<string>(() => {
return showCostumeSwitch.value ? props.dataVal.costumes[0].icon : props.dataVal.avatar.image;
return showCostumeSwitch.value
? props.modelValue.costumes[0].icon
: props.modelValue.avatar.image;
});
const bgTransY = computed<string>(() => {
return showCostumeSwitch.value ? "0" : "10px";
@@ -131,7 +136,7 @@ onMounted(() => {
loadData();
});
watch(
() => props.dataVal,
() => props.modelValue,
() => {
loadData();
},

View File

@@ -113,7 +113,7 @@ const showOverlay = ref<boolean>(false);
const selectIndex = ref<number>(0);
const showSelect = ref<boolean>(false);
const showMode = ref<"classic" | "card" | "dev">("classic");
const showMode = ref<"classic" | "card" | "dev">("card");
const resetSelect = ref<boolean>(false);
const modeList = [
{ label: "经典视图", value: "classic" },

View File

@@ -61,10 +61,27 @@ async function saveAvatars(uid: string, data: TGApp.Game.Avatar.DetailList[]): P
await db.execute(sql);
}
/**
* @description 获取角色名片
* @since Beta v0.5.3
* @param {number} id 角色 id
* @returns {Promise<string|false>}
*/
async function getAvatarCard(id: number): Promise<string | false> {
const db = await TGSqlite.getDB();
type resType = Array<{ card: string }>;
const res = await db.select<resType>("SELECT nameCard as card FROM AppCharacters WHERE id = ?;", [
id,
]);
if (res.length === 0) return false;
return res[0].card;
}
const TSUserAvatar = {
getAllAvatarId,
getAvatars,
saveAvatars,
getAvatarCard,
};
export default TSUserAvatar;