支持手动更新背包记录

This commit is contained in:
BTMuli
2025-12-18 01:34:45 +08:00
parent 66006bb0f9
commit 8879dfd912
6 changed files with 185 additions and 23 deletions

View File

@@ -11,12 +11,19 @@
</div>
</template>
<script lang="ts" setup>
import { shallowRef } from "vue";
import { shallowRef, watch } from "vue";
import type { MaterialInfo } from "@/pages/common/PageBagMaterial.vue";
/** 组件参数 */
type PbMaterialItemProps = MaterialInfo;
type PbMaterialItemProps = {
/** 数据库数据 */
tb: TGApp.Sqlite.UserBag.TableMaterial;
/** WIKI 数据 */
info: TGApp.App.Material.WikiItem;
/** 当前选中材料 */
cur?: MaterialInfo;
};
/** 组件事件 */
type PbMaterialItemEmits = (e: "select", v: MaterialInfo) => void;
@@ -25,10 +32,18 @@ const emits = defineEmits<PbMaterialItemEmits>();
const item = shallowRef<TGApp.Sqlite.UserBag.TableMaterial>(props.tb);
// TODO: 点击修改数量/查看更改历史
function toMaterial(): void {
emits("select", { tb: item.value, info: props.info });
}
watch(
() => props.cur,
() => {
if (props.cur && props.cur.info.id === props.info.id) {
item.value = props.cur.tb;
}
},
);
</script>
<style lang="scss" scoped>
@use "@styles/github.styles.scss" as github-styles;

View File

@@ -1,22 +1,22 @@
<!-- 背包材料物品浮窗 TODO:更新记录图表 -->
<!-- 背包材料物品浮窗 -->
<template>
<TOverlay v-model="visible">
<div v-if="props.data" class="pbom-container">
<slot name="left"></slot>
<div class="pbom-box">
<div class="pbom-share">
{{ props.data.tb.updated }} | UID {{ props.uid }} | TeyvatGuide v{{ version }}
{{ dbInfo.updated }} | UID {{ props.uid }} | TeyvatGuide v{{ version }}
</div>
<div class="pbom-top">
<div class="pbom-icon">
<img :src="`/icon/bg/${props.data.info.star}-BGC.webp`" alt="bg" class="bg" />
<img :src="`/icon/material/${props.data.info.id}.webp`" alt="icon" class="icon" />
<span class="cnt">{{ props.data.tb.count }}</span>
<span class="cnt">{{ dbInfo.count }}</span>
</div>
<div class="pbom-name" @click="shareMaterial()">{{ props.data.info.name }}</div>
<div class="pbom-type">{{ props.data.info.type }}</div>
</div>
<div class="pbom-bottom">
<div class="pbom-mid">
<div class="pbom-desc" v-html="parseHtmlText(props.data.info.description)" />
<div v-if="props.data.info.source.length > 0" class="pbom-source">
<TwoSource v-for="(item, index) in props.data.info.source" :key="index" :data="item" />
@@ -29,6 +29,20 @@
/>
</div>
</div>
<div class="pbom-bottom">
<div class="pbom-bt-title">
<v-icon color="var(--tgc-od-white)" size="16">mdi-clock-edit-outline</v-icon>
<span>更新记录</span>
<span class="edit" @click="tryEdit()">手动更新</span>
</div>
<div class="pbom-bt-records">
<div v-for="record in dbInfo.records" :key="record.time" class="pbom-record">
<span class="time">[{{ timestampToDate(record.time * 1000) }}]</span>
<span class="cnt">{{ record.count }}</span>
<span class="type">{{ record.manual ? "手动更新" : "自动导入" }}</span>
</div>
</div>
</div>
</div>
<slot name="right"></slot>
</div>
@@ -36,34 +50,77 @@
</template>
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showDialog from "@comp/func/dialog.js";
import showSnackbar from "@comp/func/snackbar.js";
import TwoConvert from "@comp/pageWiki/two-convert.vue";
import TwoSource from "@comp/pageWiki/two-source.vue";
import TSUserBagMaterial from "@Sqlm/userBagMaterial.js";
import { getVersion } from "@tauri-apps/api/app";
import { generateShareImg } from "@utils/TGShare.js";
import { parseHtmlText } from "@utils/toolFunc.js";
import { onMounted, ref } from "vue";
import { parseHtmlText, timestampToDate } from "@utils/toolFunc.js";
import { onMounted, ref, shallowRef, watch } from "vue";
import type { MaterialInfo } from "@/pages/common/PageBagMaterial.vue";
type PboMaterialProps = { data: MaterialInfo; uid: string };
type PboMaterialEmits = (e: "updateDB", v: MaterialInfo) => void;
const props = defineProps<PboMaterialProps>();
const emits = defineEmits<PboMaterialEmits>();
const visible = defineModel<boolean>();
const version = ref<string>();
onMounted(async () => (version.value = await getVersion()));
const dbInfo = shallowRef<TGApp.Sqlite.UserBag.TableMaterial>(props.data.tb);
watch(
() => props.data.info,
async () => await refreshDb(),
);
async function refreshDb(): Promise<void> {
const list = await TSUserBagMaterial.getMaterial(Number(props.uid), props.data.info.id);
dbInfo.value = list[0];
}
async function shareMaterial(): Promise<void> {
const element = document.querySelector<HTMLElement>(".pbom-box");
if (element === null) {
showSnackbar.error("未获取到分享内容");
return;
}
const fileName = `materialBag_${props.data.info.id}_${props.data.tb.count}`;
const fileName = `materialBag_${props.data.info.id}_${dbInfo.value.count}`;
const zoom = window.outerWidth / window.innerWidth;
await generateShareImg(fileName, element, zoom, true);
}
async function tryEdit(): Promise<void> {
const input = await showDialog.input("请输入更新值", `物品:${props.data.info.name}`);
if (!input) {
showSnackbar.cancel(`已取消对${props.data.info.name}的数量编辑`);
return;
}
if (input === "" || isNaN(Number(input)) || Number(input) < 0) {
showSnackbar.warn("请输入有效正整数");
return;
}
const check = await showDialog.check("确定更新?", `物品:${props.data.info.name},数量:${input}`);
if (!check) {
showSnackbar.cancel(`已取消对${props.data.info.name}的数量编辑`);
return;
}
await TSUserBagMaterial.insertMaterial(
Number(props.uid),
props.data.info.id,
Number(input),
dbInfo.value.records,
true,
);
await refreshDb();
emits("updateDB", { info: props.data.info, tb: dbInfo.value });
showSnackbar.success("成功更新记录");
}
</script>
<style lang="scss" scoped>
@use "@styles/github.styles.scss" as github-styles;
@@ -165,17 +222,17 @@ async function shareMaterial(): Promise<void> {
opacity: 0.8;
}
.pbom-bottom {
.pbom-mid {
display: flex;
flex-direction: column;
row-gap: 10px;
row-gap: 8px;
}
.pbom-desc,
.pbom-source,
.pbom-convert {
padding: 10px;
border-radius: 10px;
padding: 8px;
border-radius: 4px;
background: var(--box-bg-2);
color: var(--box-text-2);
}
@@ -201,4 +258,65 @@ async function shareMaterial(): Promise<void> {
padding: 10px;
row-gap: 5px;
}
.pbom-bottom {
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
padding: 8px;
border-radius: 4px;
background: var(--box-bg-2);
row-gap: 8px;
}
.pbom-bt-title {
position: relative;
display: flex;
width: 100%;
align-items: center;
justify-content: flex-start;
column-gap: 4px;
font-family: var(--font-title);
font-size: 16px;
.edit {
margin-left: auto;
color: var(--tgc-od-red);
cursor: pointer;
}
}
.pbom-bt-records {
position: relative;
display: flex;
width: 100%;
max-height: 120px;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
overflow-y: auto;
}
.pbom-record {
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 4px;
.time {
color: var(--tgc-od-white);
}
.cnt {
color: var(--tgc-od-red);
font-style: var(--font-title);
}
.type {
font-style: italic;
}
}
</style>

View File

@@ -91,8 +91,8 @@ async function loadUserPosition(forceReload: boolean = false): Promise<void> {
console.log(resp);
if (isInit.value) await showLoading.end();
if ("retcode" in resp) {
showSnackbar.error(`获取近期活动失败:[${resp.retcode}-${resp.message}`);
await TGLogger.Error(`获取近期活动失败:[${resp.retcode}-${resp.message}`);
showSnackbar.error(`获取近期活动失败:[${resp.retcode}]-${resp.message}`);
await TGLogger.Error(`获取近期活动失败:[${resp.retcode}]-${resp.message}`);
return;
}
userPos.value = [...resp.act_list, ...resp.fixed_act_list].filter(
@@ -109,8 +109,8 @@ async function loadWikiPosition(): Promise<void> {
obsPos.value = resp;
if (resp.length === 0) showSnackbar.warn("暂无近期活动");
} else {
showSnackbar.error(`获取近期活动失败:[${resp.retcode}-${resp.message}`);
await TGLogger.Error(`获取近期活动失败:[${resp.retcode}-${resp.message}`);
showSnackbar.error(`获取近期活动失败:[${resp.retcode}]-${resp.message}`);
await TGLogger.Error(`获取近期活动失败:[${resp.retcode}]-${resp.message}`);
}
}