mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-12 09:18:14 +08:00
🚸 支持配置图像质量
This commit is contained in:
@@ -142,7 +142,7 @@ function getPostCover(item: TGApp.Plugins.Mys.Post.FullData): string {
|
|||||||
else if (item.post.images.length > 0) cover = item.post.images[0];
|
else if (item.post.images.length > 0) cover = item.post.images[0];
|
||||||
if (cover === undefined) return "";
|
if (cover === undefined) return "";
|
||||||
if (cover.endsWith(".gif")) return cover;
|
if (cover.endsWith(".gif")) return cover;
|
||||||
// 裁剪图片格式为 png,比例为 36:13,进行缩放但是不拉伸
|
// return `${cover}?x-oss-process=image/resize,m_fill,w_360,h_130,limit_0/format,jpg/quality,Q_${imageQualityPercent.value}`;
|
||||||
return `${cover}?x-oss-process=image/resize,m_fill,w_360,h_130,limit_0/format,png`;
|
return `${cover}?x-oss-process=image/resize,m_fill,w_360,h_130,limit_0/format,png`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type GroTableProps = { modelValue: Array<TGApp.Sqlite.GachaRecords.SingleTable>
|
|||||||
|
|
||||||
const props = defineProps<GroTableProps>();
|
const props = defineProps<GroTableProps>();
|
||||||
|
|
||||||
const headers = [
|
const headers = <const>[
|
||||||
{ title: "时间", align: "center", key: "time" },
|
{ title: "时间", align: "center", key: "time" },
|
||||||
{ title: "卡池", align: "center", key: "uigfType" },
|
{ title: "卡池", align: "center", key: "uigfType" },
|
||||||
{ title: "类型", align: "center", key: "type" },
|
{ title: "类型", align: "center", key: "type" },
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="tp-image-box" @click="showOverlay = true" v-if="localUrl !== undefined">
|
<div class="tp-image-box" @click="showOverlay = true" v-if="localUrl !== undefined">
|
||||||
<img :src="localUrl" :alt="props.data.insert.image" :title="getImageTitle()" />
|
<img :src="localUrl" :alt="props.data.insert.image" :title="getImageTitle()" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="tp-image-load" :title="getImageUrl()">
|
<div v-else class="tp-image-load" :title="props.data.insert.image">
|
||||||
<v-progress-circular :indeterminate="true" color="primary" size="small" />
|
<v-progress-circular :indeterminate="true" color="primary" size="small" />
|
||||||
<span>加载中...</span>
|
<span>加载中...</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -13,6 +13,7 @@ import { computed, onMounted, onUnmounted, ref } from "vue";
|
|||||||
|
|
||||||
import VpOverlayImage from "./vp-overlay-image.vue";
|
import VpOverlayImage from "./vp-overlay-image.vue";
|
||||||
|
|
||||||
|
import { useAppStore } from "@/store/modules/app.js";
|
||||||
import { saveImgLocal } from "@/utils/TGShare.js";
|
import { saveImgLocal } from "@/utils/TGShare.js";
|
||||||
import { bytesToSize } from "@/utils/toolFunc.js";
|
import { bytesToSize } from "@/utils/toolFunc.js";
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ export type TpImage = {
|
|||||||
};
|
};
|
||||||
type TpImageProps = { data: TpImage };
|
type TpImageProps = { data: TpImage };
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
const props = defineProps<TpImageProps>();
|
const props = defineProps<TpImageProps>();
|
||||||
const showOverlay = ref<boolean>(false);
|
const showOverlay = ref<boolean>(false);
|
||||||
const localUrl = ref<string>();
|
const localUrl = ref<string>();
|
||||||
@@ -41,7 +43,7 @@ const imgWidth = computed<string>(() => {
|
|||||||
console.log("tp-image", props.data.insert.image, props.data.attributes);
|
console.log("tp-image", props.data.insert.image, props.data.attributes);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const link = getImageUrl();
|
const link = appStore.getImageUrl(props.data.insert.image);
|
||||||
localUrl.value = await saveImgLocal(link);
|
localUrl.value = await saveImgLocal(link);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,13 +65,6 @@ function getImageTitle(): string {
|
|||||||
}
|
}
|
||||||
return res.join("\n");
|
return res.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImageUrl(): string {
|
|
||||||
const img = props.data.insert.image;
|
|
||||||
const append = "?x-oss-process=image/format,png";
|
|
||||||
if (img.endsWith(".gif")) return img;
|
|
||||||
return img + append;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.tp-image-box {
|
.tp-image-box {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tp-link-card-box">
|
<div class="tp-link-card-box">
|
||||||
<img :src="cover" alt="cover" @click="toLink()" />
|
<img :src="cover" alt="cover" @click="toLink()" v-if="cover" />
|
||||||
<div class="tp-link-card-content">
|
<div class="tp-link-card-content">
|
||||||
<span>{{ props.data.insert.link_card.title }}</span>
|
<span>{{ props.data.insert.link_card.title }}</span>
|
||||||
<div v-if="props.data.insert.link_card.price" class="tp-link-card-price">
|
<div v-if="props.data.insert.link_card.price" class="tp-link-card-price">
|
||||||
@@ -15,6 +15,7 @@ import showSnackbar from "@comp/func/snackbar.js";
|
|||||||
import { computed, onMounted, onUnmounted, ref, toRaw } from "vue";
|
import { computed, onMounted, onUnmounted, ref, toRaw } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import { useAppStore } from "@/store/modules/app.js";
|
||||||
import { parseLink, parsePost } from "@/utils/linkParser.js";
|
import { parseLink, parsePost } from "@/utils/linkParser.js";
|
||||||
import { saveImgLocal } from "@/utils/TGShare.js";
|
import { saveImgLocal } from "@/utils/TGShare.js";
|
||||||
|
|
||||||
@@ -39,8 +40,9 @@ type TpLinkCardProps = { data: TpLinkCard };
|
|||||||
|
|
||||||
const props = defineProps<TpLinkCardProps>();
|
const props = defineProps<TpLinkCardProps>();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
const cover = ref<string>(props.data.insert.link_card.cover);
|
const cover = ref<string>();
|
||||||
const btnText = computed<string>(() => {
|
const btnText = computed<string>(() => {
|
||||||
if (!props.data.insert.link_card.button_text || props.data.insert.link_card.button_text === "") {
|
if (!props.data.insert.link_card.button_text || props.data.insert.link_card.button_text === "") {
|
||||||
return "详情";
|
return "详情";
|
||||||
@@ -49,15 +51,12 @@ const btnText = computed<string>(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!cover.value.startsWith("blob:")) {
|
const coverLink = appStore.getImageUrl(props.data.insert.link_card.cover);
|
||||||
cover.value = await saveImgLocal(props.data.insert.link_card.cover);
|
cover.value = await saveImgLocal(coverLink);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (cover.value.startsWith("blob:")) {
|
if (cover.value) URL.revokeObjectURL(cover.value);
|
||||||
URL.revokeObjectURL(cover.value);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("tpLinkCard", props.data.insert.link_card.card_id, toRaw(props.data).insert.link_card);
|
console.log("tpLinkCard", props.data.insert.link_card.card_id, toRaw(props.data).insert.link_card);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import Bili from "@Bili/index.js";
|
|||||||
import showSnackbar from "@comp/func/snackbar.js";
|
import showSnackbar from "@comp/func/snackbar.js";
|
||||||
import { onMounted, onUnmounted, ref, shallowRef } from "vue";
|
import { onMounted, onUnmounted, ref, shallowRef } from "vue";
|
||||||
|
|
||||||
import { getImageBuffer } from "@/utils/TGShare.js";
|
import { saveImgLocal } from "@/utils/TGShare.js";
|
||||||
import { getVideoDuration, timestampToDate } from "@/utils/toolFunc.js";
|
import { getVideoDuration, timestampToDate } from "@/utils/toolFunc.js";
|
||||||
|
|
||||||
type TpVideo = { insert: { video: string } };
|
type TpVideo = { insert: { video: string } };
|
||||||
@@ -42,7 +42,6 @@ const props = defineProps<TpVideoProps>();
|
|||||||
const videoAspectRatio = ref<number>(16 / 9);
|
const videoAspectRatio = ref<number>(16 / 9);
|
||||||
const videoCover = ref<string>();
|
const videoCover = ref<string>();
|
||||||
const videoData = shallowRef<TGApp.Plugins.Bili.Video.ViewData>();
|
const videoData = shallowRef<TGApp.Plugins.Bili.Video.ViewData>();
|
||||||
const coverBuffer = shallowRef<Uint8Array | null>(null);
|
|
||||||
|
|
||||||
console.log("tpVideo", props.data.insert.video);
|
console.log("tpVideo", props.data.insert.video);
|
||||||
|
|
||||||
@@ -58,8 +57,7 @@ onMounted(async () => {
|
|||||||
const meta = videoData.value.dimension;
|
const meta = videoData.value.dimension;
|
||||||
if (meta.width > meta.height) videoAspectRatio.value = meta.width / meta.height;
|
if (meta.width > meta.height) videoAspectRatio.value = meta.width / meta.height;
|
||||||
else videoAspectRatio.value = meta.height / meta.width;
|
else videoAspectRatio.value = meta.height / meta.width;
|
||||||
coverBuffer.value = await getImageBuffer(videoData.value.pic);
|
videoCover.value = await saveImgLocal(videoData.value.pic);
|
||||||
videoCover.value = URL.createObjectURL(new Blob([coverBuffer.value], { type: "image/png" }));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@@ -23,9 +23,10 @@
|
|||||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
import Artplayer from "artplayer";
|
import Artplayer from "artplayer";
|
||||||
import type { Option } from "artplayer/types/option.js";
|
import type { Option } from "artplayer/types/option.js";
|
||||||
import { onMounted, ref, shallowRef, toRaw } from "vue";
|
import { onMounted, onUnmounted, ref, shallowRef, toRaw } from "vue";
|
||||||
|
|
||||||
import { getImageBuffer, saveCanvasImg } from "@/utils/TGShare.js";
|
import { useAppStore } from "@/store/modules/app.js";
|
||||||
|
import { getImageBuffer, saveCanvasImg, saveImgLocal } from "@/utils/TGShare.js";
|
||||||
import { getVideoDuration } from "@/utils/toolFunc.js";
|
import { getVideoDuration } from "@/utils/toolFunc.js";
|
||||||
|
|
||||||
type TpVod = {
|
type TpVod = {
|
||||||
@@ -52,10 +53,12 @@ type TpVod = {
|
|||||||
};
|
};
|
||||||
type TpVodProps = { data: TpVod };
|
type TpVodProps = { data: TpVod };
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
const props = defineProps<TpVodProps>();
|
const props = defineProps<TpVodProps>();
|
||||||
const container = shallowRef<Artplayer | null>(null);
|
const coverUrl = ref<string>();
|
||||||
const vodAspectRatio = ref<number>(16 / 9);
|
const vodAspectRatio = ref<number>(16 / 9);
|
||||||
const coverBuffer = shallowRef<Uint8Array | null>(null);
|
const coverBuffer = shallowRef<Uint8Array | null>(null);
|
||||||
|
const container = shallowRef<Artplayer | null>(null);
|
||||||
|
|
||||||
console.log("tpVod", props.data.insert.vod.id, toRaw(props.data).insert.vod);
|
console.log("tpVod", props.data.insert.vod.id, toRaw(props.data).insert.vod);
|
||||||
|
|
||||||
@@ -70,6 +73,8 @@ onMounted(async () => {
|
|||||||
if (width > height) vodAspectRatio.value = width / height;
|
if (width > height) vodAspectRatio.value = width / height;
|
||||||
else vodAspectRatio.value = height / width;
|
else vodAspectRatio.value = height / width;
|
||||||
}
|
}
|
||||||
|
const localUrl = appStore.getImageUrl(props.data.insert.vod.cover);
|
||||||
|
coverUrl.value = await saveImgLocal(localUrl);
|
||||||
const option: Option = {
|
const option: Option = {
|
||||||
id: props.data.insert.vod.id,
|
id: props.data.insert.vod.id,
|
||||||
container: `#tp-vod-${props.data.insert.vod.id}`,
|
container: `#tp-vod-${props.data.insert.vod.id}`,
|
||||||
@@ -116,6 +121,16 @@ onMounted(async () => {
|
|||||||
container.value = new Artplayer(option);
|
container.value = new Artplayer(option);
|
||||||
container.value?.on("fullscreen", async (s) => await getCurrentWindow().setFullscreen(s));
|
container.value?.on("fullscreen", async (s) => await getCurrentWindow().setFullscreen(s));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
container.value?.destroy();
|
||||||
|
if (coverBuffer.value) {
|
||||||
|
coverBuffer.value = null;
|
||||||
|
}
|
||||||
|
if (coverUrl.value) {
|
||||||
|
URL.revokeObjectURL(coverUrl.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.tp-vod-box {
|
.tp-vod-box {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<TOverlay v-model="visible" blur-val="10px">
|
<TOverlay v-model="visible" blur-val="10px">
|
||||||
<div class="tpoi-box">
|
<div class="tpoi-box">
|
||||||
<div :class="{ 'tpoi-top-ori': isOriSize, 'tpoi-top': !isOriSize }">
|
<div :class="{ 'tpoi-top-ori': isOriSize, 'tpoi-top': !isOriSize }">
|
||||||
<img :src="props.image.insert.image" alt="图片" @click="isOriSize = !isOriSize" />
|
<img :src="localCover" alt="图片" @click="isOriSize = !isOriSize" v-if="localCover" />
|
||||||
</div>
|
</div>
|
||||||
<div class="tpoi-bottom">
|
<div class="tpoi-bottom">
|
||||||
<div class="tpoi-info" v-if="props.image.attributes">
|
<div class="tpoi-info" v-if="props.image.attributes">
|
||||||
@@ -25,19 +25,22 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import TOverlay from "@comp/app/t-overlay.vue";
|
import TOverlay from "@comp/app/t-overlay.vue";
|
||||||
import showSnackbar from "@comp/func/snackbar.js";
|
import showSnackbar from "@comp/func/snackbar.js";
|
||||||
import { computed, ref, shallowRef } from "vue";
|
import { computed, onMounted, onUnmounted, ref, shallowRef } from "vue";
|
||||||
|
|
||||||
import type { TpImage } from "./tp-image.vue";
|
import type { TpImage } from "./tp-image.vue";
|
||||||
|
|
||||||
import { copyToClipboard, getImageBuffer, saveCanvasImg } from "@/utils/TGShare.js";
|
import { useAppStore } from "@/store/modules/app.js";
|
||||||
|
import { copyToClipboard, getImageBuffer, saveCanvasImg, saveImgLocal } from "@/utils/TGShare.js";
|
||||||
import { bytesToSize } from "@/utils/toolFunc.js";
|
import { bytesToSize } from "@/utils/toolFunc.js";
|
||||||
|
|
||||||
type TpoImageProps = { image: TpImage };
|
type TpoImageProps = { image: TpImage };
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
const props = defineProps<TpoImageProps>();
|
const props = defineProps<TpoImageProps>();
|
||||||
const visible = defineModel<boolean>();
|
const visible = defineModel<boolean>();
|
||||||
const bgMode = ref<number>(0); // 0: transparent, 1: black, 2: white
|
const bgMode = ref<number>(0); // 0: transparent, 1: black, 2: white
|
||||||
const isOriSize = ref<boolean>(false);
|
const isOriSize = ref<boolean>(false);
|
||||||
|
const localCover = ref<string>();
|
||||||
const buffer = shallowRef<Uint8Array | null>(null);
|
const buffer = shallowRef<Uint8Array | null>(null);
|
||||||
const format = computed<string>(() => {
|
const format = computed<string>(() => {
|
||||||
if (props.image.attributes?.ext) return props.image.attributes.ext;
|
if (props.image.attributes?.ext) return props.image.attributes.ext;
|
||||||
@@ -46,6 +49,16 @@ const format = computed<string>(() => {
|
|||||||
return "png";
|
return "png";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const link = appStore.getImageUrl(props.image.insert.image);
|
||||||
|
localCover.value = await saveImgLocal(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (localCover.value) URL.revokeObjectURL(localCover.value);
|
||||||
|
buffer.value = null;
|
||||||
|
});
|
||||||
|
|
||||||
function setBlackBg(): void {
|
function setBlackBg(): void {
|
||||||
bgMode.value = (bgMode.value + 1) % 3;
|
bgMode.value = (bgMode.value + 1) % 3;
|
||||||
const bgLabelList = ["透明", "黑色", "白色"];
|
const bgLabelList = ["透明", "黑色", "白色"];
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="config-box">
|
<div class="config-box">
|
||||||
<TcInfo />
|
<TcInfo />
|
||||||
<v-list class="config-list">
|
<v-list class="config-list">
|
||||||
<v-list-subheader :inset="true" class="config-header" title="设置" />
|
<v-list-subheader :inset="true" class="config-header" title="数据相关" />
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
<v-divider :inset="true" class="border-opacity-75" />
|
||||||
<v-list-item title="数据备份" @click="confirmBackup()">
|
<v-list-item title="数据备份" @click="confirmBackup()">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
@@ -25,6 +25,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item>
|
||||||
|
<template #prepend>
|
||||||
|
<div class="config-icon">
|
||||||
|
<v-icon>mdi-refresh</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title @click="confirmUpdateDevice()">刷新设备信息</v-list-item-title>
|
||||||
|
<v-list-item-subtitle>
|
||||||
|
<!-- @ts-expect-error eslint-disable-next-line Deprecated symbol used -->
|
||||||
|
{{ deviceInfo.device_name }}({{ deviceInfo.product }}) - {{ deviceInfo.device_fp }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
<template #append>
|
||||||
|
<v-icon @click="confirmUpdateDevice(true)">mdi-bug</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="清除缓存" @click="confirmDelCache">
|
||||||
|
<template #prepend>
|
||||||
|
<div class="config-icon">
|
||||||
|
<v-icon>mdi-database-remove</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #append>{{ bytesToSize(cacheSize) }}</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item v-show="showReset" title="重置数据库" @click="confirmResetDB()">
|
||||||
|
<template #prepend>
|
||||||
|
<div class="config-icon">
|
||||||
|
<v-icon>mdi-database-settings</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="恢复默认设置" @click="confirmResetApp">
|
||||||
|
<template #prepend>
|
||||||
|
<div class="config-icon">
|
||||||
|
<v-icon>mdi-cog-sync</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
<v-list-subheader :inset="true" class="config-header" title="调试" @click="tryShowReset" />
|
<v-list-subheader :inset="true" class="config-header" title="调试" @click="tryShowReset" />
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
<v-divider :inset="true" class="border-opacity-75" />
|
||||||
<v-list-item v-if="isDevEnv" title="调试模式" subtitle="开启后将显示调试信息">
|
<v-list-item v-if="isDevEnv" title="调试模式" subtitle="开启后将显示调试信息">
|
||||||
@@ -70,41 +107,15 @@
|
|||||||
<v-icon @click="confirmShare()">mdi-cog</v-icon>
|
<v-icon @click="confirmShare()">mdi-cog</v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item>
|
<v-list-item title="图片质量调整">
|
||||||
|
<template #subtitle>当前图像质量:{{ imageQualityPercent }}%</template>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<div class="config-icon">
|
<div class="config-icon">
|
||||||
<v-icon>mdi-refresh</v-icon>
|
<v-icon>mdi-image-filter-vintage</v-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title @click="confirmUpdateDevice()">刷新设备信息</v-list-item-title>
|
|
||||||
<v-list-item-subtitle>
|
|
||||||
<!-- @ts-expect-error eslint-disable-next-line Deprecated symbol used -->
|
|
||||||
{{ deviceInfo.device_name }}({{ deviceInfo.product }}) - {{ deviceInfo.device_fp }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-icon @click="confirmUpdateDevice(true)">mdi-bug</v-icon>
|
<v-icon @click="confirmImgQuality()">mdi-cog</v-icon>
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="清除缓存" @click="confirmDelCache">
|
|
||||||
<template #prepend>
|
|
||||||
<div class="config-icon">
|
|
||||||
<v-icon>mdi-database-remove</v-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #append>{{ bytesToSize(cacheSize) }}</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item v-show="showReset" title="重置数据库" @click="confirmResetDB()">
|
|
||||||
<template #prepend>
|
|
||||||
<div class="config-icon">
|
|
||||||
<v-icon>mdi-database-settings</v-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="恢复默认设置" @click="confirmResetApp">
|
|
||||||
<template #prepend>
|
|
||||||
<div class="config-icon">
|
|
||||||
<v-icon>mdi-cog-sync</v-icon>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
@@ -143,8 +154,15 @@ import TGLogger from "@/utils/TGLogger.js";
|
|||||||
import { bytesToSize, getCacheDir, getDeviceInfo, getRandomString } from "@/utils/toolFunc.js";
|
import { bytesToSize, getCacheDir, getDeviceInfo, getRandomString } from "@/utils/toolFunc.js";
|
||||||
import OtherApi from "@/web/request/otherReq.js";
|
import OtherApi from "@/web/request/otherReq.js";
|
||||||
|
|
||||||
const { needResize, devMode, deviceInfo, shareDefaultFile, userDir, buildTime } =
|
const {
|
||||||
storeToRefs(useAppStore());
|
needResize,
|
||||||
|
devMode,
|
||||||
|
deviceInfo,
|
||||||
|
shareDefaultFile,
|
||||||
|
userDir,
|
||||||
|
buildTime,
|
||||||
|
imageQualityPercent,
|
||||||
|
} = storeToRefs(useAppStore());
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const homeStore = useHomeStore();
|
const homeStore = useHomeStore();
|
||||||
|
|
||||||
@@ -281,6 +299,42 @@ async function confirmShare(): Promise<void> {
|
|||||||
showSnackbar.success(`成功修改分享设置!新阈值为${input}MB`);
|
showSnackbar.success(`成功修改分享设置!新阈值为${input}MB`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 图片质量调整
|
||||||
|
async function confirmImgQuality(): Promise<void> {
|
||||||
|
const input = await showDialog.input(
|
||||||
|
"请输入图片质量(1-100)",
|
||||||
|
"质量:",
|
||||||
|
imageQualityPercent.value.toString(),
|
||||||
|
);
|
||||||
|
if (input === undefined) {
|
||||||
|
showSnackbar.cancel("已取消修改图片质量");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (input === "") {
|
||||||
|
showSnackbar.error("质量不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(Number(input))) {
|
||||||
|
showSnackbar.error("质量必须为数字!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Number(input) === imageQualityPercent.value) {
|
||||||
|
showSnackbar.cancel("未修改图片质量");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Number(input) > 100 || Number(input) < 1) {
|
||||||
|
showSnackbar.error("质量必须在1-100之间!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const check = await showDialog.check("确认修改图片质量吗?", `新质量为${input}`);
|
||||||
|
if (!check) {
|
||||||
|
showSnackbar.cancel("已取消修改图片质量");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageQualityPercent.value = Number(input);
|
||||||
|
showSnackbar.success(`成功修改图片质量!新质量为${input}`);
|
||||||
|
}
|
||||||
|
|
||||||
// 更新设备信息
|
// 更新设备信息
|
||||||
async function confirmUpdateDevice(force?: boolean): Promise<void> {
|
async function confirmUpdateDevice(force?: boolean): Promise<void> {
|
||||||
if (force !== undefined && force) {
|
if (force !== undefined && force) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file store/modules/app.ts
|
* @file store/modules/app.ts
|
||||||
* @description App store module
|
* @description App store module
|
||||||
* @since Beta v0.6.4
|
* @since Beta v0.6.8
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { path } from "@tauri-apps/api";
|
import { path } from "@tauri-apps/api";
|
||||||
@@ -59,6 +59,8 @@ export const useAppStore = defineStore(
|
|||||||
const needResize = ref<string>("true");
|
const needResize = ref<string>("true");
|
||||||
// 分享图生成默认设置,为0表示默认保存到文件,为数字表示当大小超过xMB时保存到文件,否则保存到剪贴板
|
// 分享图生成默认设置,为0表示默认保存到文件,为数字表示当大小超过xMB时保存到文件,否则保存到剪贴板
|
||||||
const shareDefaultFile = ref<number>(10);
|
const shareDefaultFile = ref<number>(10);
|
||||||
|
// 图像压缩质量
|
||||||
|
const imageQualityPercent = ref<number>(80);
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
function init(): void {
|
function init(): void {
|
||||||
@@ -72,6 +74,7 @@ export const useAppStore = defineStore(
|
|||||||
needResize.value = "true";
|
needResize.value = "true";
|
||||||
gameDir.value = "未设置";
|
gameDir.value = "未设置";
|
||||||
shareDefaultFile.value = 10;
|
shareDefaultFile.value = 10;
|
||||||
|
imageQualityPercent.value = 10;
|
||||||
initDevice();
|
initDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +87,11 @@ export const useAppStore = defineStore(
|
|||||||
deviceInfo.value = getInitDeviceInfo();
|
deviceInfo.value = getInitDeviceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getImageUrl(url: string): string {
|
||||||
|
if (url.endsWith(".gif")) return url;
|
||||||
|
return `${url}?x-oss-process=image/format,jpg/quality,Q_${imageQualityPercent.value}`;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme,
|
theme,
|
||||||
buildTime,
|
buildTime,
|
||||||
@@ -100,8 +108,10 @@ export const useAppStore = defineStore(
|
|||||||
needResize,
|
needResize,
|
||||||
gameDir,
|
gameDir,
|
||||||
shareDefaultFile,
|
shareDefaultFile,
|
||||||
|
imageQualityPercent,
|
||||||
init,
|
init,
|
||||||
changeTheme,
|
changeTheme,
|
||||||
|
getImageUrl,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -114,7 +124,15 @@ export const useAppStore = defineStore(
|
|||||||
{
|
{
|
||||||
key: "app",
|
key: "app",
|
||||||
storage: window.localStorage,
|
storage: window.localStorage,
|
||||||
pick: ["devMode", "loading", "buildTime", "isLogin", "needResize", "shareDefaultFile"],
|
pick: [
|
||||||
|
"devMode",
|
||||||
|
"loading",
|
||||||
|
"buildTime",
|
||||||
|
"isLogin",
|
||||||
|
"needResize",
|
||||||
|
"shareDefaultFile",
|
||||||
|
"imageQualityPercent",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "sidebar",
|
key: "sidebar",
|
||||||
|
|||||||
Reference in New Issue
Block a user