💄 修正类型,调整UI

This commit is contained in:
目棃
2024-08-21 19:54:32 +08:00
parent 8ab998e089
commit 3a320ed95b
5 changed files with 221 additions and 111 deletions

View File

@@ -62,7 +62,7 @@ html {
/* /*
* @description 侧边滚动条样式 * @description 侧边滚动条样式
* @since Beta v0.3.0 * @since Beta v0.5.3
*/ */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;
@@ -76,9 +76,9 @@ html {
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
border-radius: 5px; border-radius: 5px;
background: var(--common-shadow-2); background: var(--tgc-od-white);
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: var(--common-shadow-4); background: var(--tgc-od-orange);
} }

View File

@@ -1,23 +1,19 @@
<template> <template>
<div class="tua-ab-box"> <div class="tua-ab-box">
<!-- 左侧角色武器天赋好感衣装名片 -->
<div class="tua-ab-top"> <div class="tua-ab-top">
<TItembox v-model="avatarBox" /> <TItembox v-model="avatarBox" />
<div class="tua-abt-right"> <div class="tua-abt-right">
<TItembox v-model="weaponBox" /> <div class="tua-abt-rt">
<div v-for="(relic, index) in relicsBox" :key="index" class="tua-relic-box"> <TItembox v-model="weaponBox" :title="getWeaponTitle()" />
<div class="tua-relic-bg"> <div class="tua-abt-rtr">
<img :src="`/icon/bg/${relic.rarity}-Star.webp`" alt="bg" v-if="relic !== false" /> <TuaRelicBox :model-value="relicsBox[0]" :position="1" />
<TuaRelicBox :model-value="relicsBox[1]" :position="2" />
</div> </div>
<div class="tua-relic-icon">
<img
:src="`/icon/relic/${index + 1}.webp`"
:alt="`relic${index + 1}`"
v-if="relic === false"
class="empty"
/>
<img :src="relic.icon" :alt="relic.name" v-else />
</div> </div>
<div class="tua-abt-rb">
<TuaRelicBox :model-value="relicsBox[2]" :position="3" />
<TuaRelicBox :model-value="relicsBox[3]" :position="4" />
<TuaRelicBox :model-value="relicsBox[4]" :position="5" />
</div> </div>
</div> </div>
</div> </div>
@@ -52,14 +48,18 @@
import { computed, onMounted, ref } from "vue"; import { computed, onMounted, ref } from "vue";
import TGSqlite from "../../plugins/Sqlite/index.js"; import TGSqlite from "../../plugins/Sqlite/index.js";
import { useUserStore } from "../../store/modules/user.js";
import { getZhElement } from "../../utils/toolFunc.js"; import { getZhElement } from "../../utils/toolFunc.js";
import TItembox, { TItemBoxData } from "../main/t-itembox.vue"; import TItembox, { TItemBoxData } from "../main/t-itembox.vue";
import TuaRelicBox from "./tua-relic-box.vue";
interface TuaAvatarBoxProps { interface TuaAvatarBoxProps {
modelValue: TGApp.Sqlite.Character.UserRole; modelValue: TGApp.Sqlite.Character.UserRole;
} }
const props = defineProps<TuaAvatarBoxProps>(); const props = defineProps<TuaAvatarBoxProps>();
const userStore = useUserStore();
type FixedLenArr<T, N extends number> = [T, ...T[]] & { length: N }; type FixedLenArr<T, N extends number> = [T, ...T[]] & { length: N };
type AvatarRelics = FixedLenArr<TGApp.Game.Avatar.Relic | false, 5>; type AvatarRelics = FixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
@@ -67,8 +67,8 @@ type AvatarRelics = FixedLenArr<TGApp.Game.Avatar.Relic | false, 5>;
const avatarBox = computed<TItemBoxData>(() => { const avatarBox = computed<TItemBoxData>(() => {
const avatar = props.modelValue.avatar; const avatar = props.modelValue.avatar;
return { return {
size: "130px", size: "100px",
height: "130px", height: "100px",
bg: `/icon/bg/${avatar.rarity}-Star.webp`, bg: `/icon/bg/${avatar.rarity}-Star.webp`,
icon: `/WIKI/character/${avatar.id}.webp`, icon: `/WIKI/character/${avatar.id}.webp`,
lt: `/icon/element/${getZhElement(avatar.element)}元素.webp`, lt: `/icon/element/${getZhElement(avatar.element)}元素.webp`,
@@ -78,22 +78,24 @@ const avatarBox = computed<TItemBoxData>(() => {
innerText: avatar.name, innerText: avatar.name,
innerHeight: 30, innerHeight: 30,
display: "inner", display: "inner",
clickable: true, clickable: false,
}; };
}); });
const weaponBox = computed<TItemBoxData>(() => { const weaponBox = computed<TItemBoxData>(() => {
const weapon = props.modelValue.weapon; const weapon = props.modelValue.weapon;
return { return {
size: "40px", size: "65px",
height: "40px", height: "65px",
bg: `/icon/bg/${weapon.rarity}-Star.webp`, bg: `/icon/bg/${weapon.rarity}-Star.webp`,
icon: `/WIKI/weapon/${weapon.id}.webp`, icon: `/WIKI/weapon/${weapon.id}.webp`,
lt: `/icon/weapon/${weapon.type_name}.webp`, lt: `/icon/weapon/${weapon.type_name}.webp`,
ltSize: "15px", ltSize: "20px",
innerText: "", rt: weapon.affix_level.toString(),
innerHeight: 0, rtSize: "20px",
innerText: weapon.name,
innerHeight: 20,
display: "inner", display: "inner",
clickable: true, clickable: false,
}; };
}); });
const relicsBox = computed<AvatarRelics>(() => { const relicsBox = computed<AvatarRelics>(() => {
@@ -127,6 +129,18 @@ onMounted(async () => {
nameCard.value = "/source/nameCard/profile/原神·印象.webp"; nameCard.value = "/source/nameCard/profile/原神·印象.webp";
} }
}); });
function getWeaponTitle(): string {
const weapon = props.modelValue.weapon;
const title: string[] = [];
title.push(`${weapon.type_name} - ${weapon.name}`);
title.push(`${weapon.rarity}星 精炼${weapon.affix_level} Lv.${weapon.level}`);
const propMain = userStore.getProp(weapon.main_property.property_type);
title.push(`${propMain !== false ? propMain.name : "未知属性"} - ${weapon.main_property.final}`);
const propSub = userStore.getProp(weapon.sub_property.property_type);
title.push(`${propSub !== false ? propSub.name : "未知属性"} - ${weapon.sub_property.final}`);
return title.join("\n");
}
</script> </script>
<style lang="css" scoped> <style lang="css" scoped>
.tua-ab-box { .tua-ab-box {
@@ -144,59 +158,38 @@ onMounted(async () => {
display: flex; display: flex;
width: 100%; width: 100%;
align-items: center; align-items: center;
justify-content: space-between; justify-content: center;
column-gap: 10px;
} }
.tua-abt-right { .tua-abt-right {
display: grid;
padding: 5px;
gap: 5px;
grid-template-columns: repeat(2, 40px);
}
.tua-relic-box {
position: relative;
width: 40px;
height: 40px;
border-radius: 5px;
}
.tua-relic-icon {
position: relative;
width: 40px;
height: 40px;
border-radius: 5px;
img {
width: 100%;
height: 100%;
border-radius: 5px;
object-fit: cover;
}
.empty {
padding: 5px;
}
}
.tua-relic-bg {
position: absolute;
top: 0;
left: 0;
display: flex; display: flex;
width: 100%; flex-direction: column;
height: 100%;
align-items: center; align-items: center;
justify-content: center; justify-content: space-between;
border-radius: 5px; row-gap: 5px;
background: var(--box-bg-3);
img {
width: 100%;
height: 100%;
border-radius: 5px;
object-fit: cover;
} }
.tua-abt-rt {
display: flex;
align-items: center;
justify-content: space-between;
column-gap: 5px;
}
.tua-abt-rtr {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
row-gap: 5px;
}
.tua-abt-rb {
display: flex;
align-items: center;
justify-content: space-between;
column-gap: 5px;
} }
.tua-abl-bottom { .tua-abl-bottom {

View File

@@ -0,0 +1,110 @@
<template>
<div class="tua-relic-box" :title="getRelicTitle()">
<div class="tua-relic-bg">
<img
:src="`/icon/bg/${props.modelValue.rarity}-Star.webp`"
v-if="props.modelValue !== false"
:alt="`relic${props.position}`"
/>
</div>
<div class="tua-relic-icon">
<img
:src="`/icon/relic/${props.position}.webp`"
:alt="`relic${props.position}`"
v-if="props.modelValue === false"
class="empty"
/>
<img :src="props.modelValue.icon" :alt="props.modelValue.name" v-else />
</div>
</div>
</template>
<script lang="ts" setup>
import { useUserStore } from "../../store/modules/user.js";
interface TuaRelicBoxProps {
modelValue: TGApp.Game.Avatar.Relic | false;
position: number;
}
const props = defineProps<TuaRelicBoxProps>();
const userStore = useUserStore();
function getRelicPosName(): string {
switch (props.position) {
case 1:
return "生之花";
case 2:
return "死之羽";
case 3:
return "时之沙";
case 4:
return "空之杯";
case 5:
return "理之冠";
default:
return "未知";
}
}
function getRelicTitle(): string {
const posName = getRelicPosName();
if (props.modelValue === false) return `${posName}:未装备`;
const relicProps: string[] = [];
const mainProp = userStore.getProp(props.modelValue.main_property.property_type);
relicProps.push(
`主词条:${mainProp === false ? "未知属性" : mainProp.name} ${props.modelValue.main_property.value}`,
);
relicProps.push("副词条:");
for (const relicProp of props.modelValue.sub_property_list) {
const subProp = userStore.getProp(relicProp.property_type);
relicProps.push(
` ${subProp === false ? "未知属性" : subProp.name} ${relicProp.value}(+${relicProp.times})`,
);
}
return `${posName}\n${props.modelValue.name} Lv.${props.modelValue.level}\n${relicProps.join("\n")}`;
}
</script>
<style lang="css" scoped>
.tua-relic-box {
position: relative;
width: 30px;
height: 30px;
border-radius: 5px;
}
.tua-relic-icon {
position: relative;
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
.empty {
padding: 5px;
}
}
.tua-relic-bg {
position: absolute;
top: 0;
left: 0;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
border-radius: 5px;
background: var(--box-bg-3);
img {
width: 100%;
height: 100%;
border-radius: 5px;
object-fit: cover;
}
}
</style>

View File

@@ -1,5 +1,27 @@
<template> <template>
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" /> <ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
<v-app-bar>
<template #title>
<span v-if="user"> {{ user.nickname }}({{ user.gameUid }})</span>
<span v-else> 暂无数据 </span>
</template>
<template #append>
<div class="uc-top-btns">
<v-btn @click="refresh()" rounded variant="outlined" v-model:loading="loadData">
<template #prepend>
<v-icon>mdi-refresh</v-icon>
</template>
刷新
</v-btn>
<v-btn @click="share()" rounded variant="outlined" v-model:loading="loadShare">
<template #prepend>
<v-icon>mdi-share</v-icon>
</template>
分享
</v-btn>
</div>
</template>
</v-app-bar>
<div class="uc-box"> <div class="uc-box">
<div class="uc-top"> <div class="uc-top">
<div class="uc-top-title" @click="switchOld"> <div class="uc-top-title" @click="switchOld">
@@ -8,24 +30,7 @@
</span> </span>
<span v-else> 暂无数据 </span> <span v-else> 暂无数据 </span>
</div> </div>
<div class="uc-top-btns" data-html2canvas-ignore>
<v-btn class="uc-top-btn" @click="refresh()">
<template #prepend>
<v-icon>mdi-refresh</v-icon>
</template>
刷新
</v-btn>
<v-btn class="uc-top-btn" @click="share()">
<template #prepend>
<v-icon>mdi-share</v-icon>
</template>
分享
</v-btn>
</div> </div>
</div>
<div class="uc-content">
<div class="uc-left">
<div class="ucl-top"></div>
<div class="uc-grid"> <div class="uc-grid">
<TuaAvatarBox <TuaAvatarBox
v-for="(role, index) in roleList" v-for="(role, index) in roleList"
@@ -35,8 +40,6 @@
/> />
</div> </div>
</div> </div>
</div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
@@ -57,6 +60,8 @@ const user = ref<TGApp.Sqlite.Account.Game>();
// loading // loading
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const loadData = ref<boolean>(false);
const loadShare = ref<boolean>(false);
const loadingTitle = ref<string>(); const loadingTitle = ref<string>();
const loadingSub = ref<string>(); const loadingSub = ref<string>();
@@ -80,8 +85,10 @@ onMounted(async () => {
await TGLogger.Info("[Character][onMounted] 进入角色页面"); await TGLogger.Info("[Character][onMounted] 进入角色页面");
loadingTitle.value = "正在获取角色数据"; loadingTitle.value = "正在获取角色数据";
loading.value = true; loading.value = true;
loadData.value = true;
await load(); await load();
loading.value = false; loading.value = false;
loadData.value = false;
}); });
function switchOld(): void { function switchOld(): void {
@@ -114,12 +121,14 @@ async function refresh(): Promise<void> {
await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 正在更新角色数据`); await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 正在更新角色数据`);
loadingTitle.value = "正在获取角色列表"; loadingTitle.value = "正在获取角色列表";
loading.value = true; loading.value = true;
loadData.value = true;
if (!userStore.cookie.value) { if (!userStore.cookie.value) {
showSnackbar({ showSnackbar({
text: "请先登录", text: "请先登录",
color: "error", color: "error",
}); });
loading.value = false; loading.value = false;
loadData.value = false;
return; return;
} }
const cookie = { const cookie = {
@@ -137,6 +146,7 @@ async function refresh(): Promise<void> {
`[Character][refreshRoles][${user.value.gameUid}] ${listRes.retcode} ${listRes.message}`, `[Character][refreshRoles][${user.value.gameUid}] ${listRes.retcode} ${listRes.message}`,
); );
loading.value = false; loading.value = false;
loadData.value = false;
return; return;
} }
const idList = listRes.map((i) => i.id.toString()); const idList = listRes.map((i) => i.id.toString());
@@ -153,6 +163,7 @@ async function refresh(): Promise<void> {
`[Character][refreshRoles][${user.value.gameUid}] ${res.retcode} ${res.message}`, `[Character][refreshRoles][${user.value.gameUid}] ${res.retcode} ${res.message}`,
); );
loading.value = false; loading.value = false;
loadData.value = false;
return; return;
} }
userStore.propMap.value = res.property_map; userStore.propMap.value = res.property_map;
@@ -164,6 +175,7 @@ async function refresh(): Promise<void> {
); );
await load(); await load();
loading.value = false; loading.value = false;
loadData.value = false;
} }
async function share(): Promise<void> { async function share(): Promise<void> {
@@ -174,9 +186,11 @@ async function share(): Promise<void> {
loadingTitle.value = "正在生成图片"; loadingTitle.value = "正在生成图片";
loadingSub.value = `${fileName}.png`; loadingSub.value = `${fileName}.png`;
loading.value = true; loading.value = true;
loadShare.value = true;
await generateShareImg(fileName, rolesBox); await generateShareImg(fileName, rolesBox);
loadingSub.value = ""; loadingSub.value = "";
loading.value = false; loading.value = false;
loadShare.value = false;
await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 生成分享图片成功`); await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 生成分享图片成功`);
} }
@@ -226,20 +240,13 @@ function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
.uc-top-btns { .uc-top-btns {
display: flex; display: flex;
align-items: center; align-content: center;
gap: 15px; column-gap: 10px;
}
.uc-top-btn {
border-radius: 5px;
background: var(--tgc-btn-1);
color: var(--btn-text);
font-family: var(--font-text);
} }
.uc-grid { .uc-grid {
display: grid; display: grid;
grid-gap: 10px; grid-gap: 15px;
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
} }
</style> </style>

View File

@@ -208,7 +208,7 @@ declare namespace TGApp.Game.Avatar {
* @property {RelicSet} set - 圣遗物套装 * @property {RelicSet} set - 圣遗物套装
* @property {string} pos_name - 圣遗物位置名称 * @property {string} pos_name - 圣遗物位置名称
* @property {RelicProp} main_property - 圣遗物主属性 * @property {RelicProp} main_property - 圣遗物主属性
* @property {RelicProp[]} sub_properties - 圣遗物副属性 * @property {RelicProp[]} sub_property_list - 圣遗物副属性
* @return Relic * @return Relic
*/ */
interface Relic { interface Relic {
@@ -221,7 +221,7 @@ declare namespace TGApp.Game.Avatar {
set: RelicSet; set: RelicSet;
pos_name: string; pos_name: string;
main_property: RelicProp; main_property: RelicProp;
sub_properties: RelicProp[]; sub_property_list: RelicProp[];
} }
/** /**