152 lines
3.3 KiB
Vue
152 lines
3.3 KiB
Vue
<template>
|
|
<div class="settings-page">
|
|
<t-cell-group title="显示" theme="card">
|
|
<t-cell class="theme" title="显示模式">
|
|
<template #right-icon>
|
|
<segmented-slider
|
|
class="theme-slider"
|
|
:model-value="globalUIStore.themeMode"
|
|
:options="themeOptions"
|
|
@change="handleThemeChange"
|
|
/>
|
|
</template>
|
|
</t-cell>
|
|
</t-cell-group>
|
|
<t-cell-group title="声音" theme="card">
|
|
<t-cell title="扫码成功">
|
|
<template #right-icon>
|
|
<t-switch :model-value="settingStore.sound.scanSuccess" @change="value => handleScanSuccessChange(value === true)" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell title="登记成功">
|
|
<template #right-icon>
|
|
<t-switch :model-value="settingStore.sound.registerSuccess" @change="value => handleRegisterSuccessChange(value === true)" />
|
|
</template>
|
|
</t-cell>
|
|
<t-cell title="音量">
|
|
<template #right-icon>
|
|
<div class="volume-field">
|
|
<t-slider
|
|
:model-value="settingStore.sound.volume"
|
|
:min="0"
|
|
:max="100"
|
|
:step="1"
|
|
@change="handleVolumeChange"
|
|
/>
|
|
<span v-text="`${settingStore.sound.volume}%`" />
|
|
</div>
|
|
</template>
|
|
</t-cell>
|
|
</t-cell-group>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { ThemeMode } from "@/store/globalUI";
|
|
import { useGlobalUIStore } from "@/store/globalUI";
|
|
import SegmentedSlider from "@/components/SegmentedSlider.vue";
|
|
import { useSettingStore } from "@/store/settingStore";
|
|
|
|
defineOptions({
|
|
name: "AppSettings"
|
|
});
|
|
|
|
const globalUIStore = useGlobalUIStore();
|
|
const settingStore = useSettingStore();
|
|
|
|
// ---------- 主题 ----------
|
|
|
|
const themeOptions: Array<{ label: string; value: ThemeMode }> = [
|
|
{ label: "浅色", value: "light" },
|
|
{ label: "深色", value: "dark" },
|
|
{ label: "跟随系统", value: "system" }
|
|
];
|
|
|
|
function handleThemeChange(value: string): void {
|
|
globalUIStore.setThemeMode(value as ThemeMode);
|
|
}
|
|
|
|
// ---------- 声音 ----------
|
|
|
|
async function handleScanSuccessChange(value: boolean): Promise<void> {
|
|
settingStore.setSound({
|
|
scanSuccess: value
|
|
});
|
|
if (value) {
|
|
await playSettingSoundPreview("scanSuccess");
|
|
}
|
|
}
|
|
|
|
async function handleRegisterSuccessChange(value: boolean): Promise<void> {
|
|
settingStore.setSound({
|
|
registerSuccess: value
|
|
});
|
|
if (value) {
|
|
await playSettingSoundPreview("registerSuccess");
|
|
}
|
|
}
|
|
|
|
function handleVolumeChange(value: number | number[]): void {
|
|
settingStore.setSound({
|
|
volume: Array.isArray(value) ? value[0] : value
|
|
});
|
|
}
|
|
|
|
async function playSettingSoundPreview(type: "scanSuccess" | "registerSuccess"): Promise<void> {
|
|
await settingStore.unlockSoundPlayers();
|
|
if (type === "scanSuccess") {
|
|
await settingStore.playScanSuccessSound();
|
|
return;
|
|
}
|
|
|
|
await settingStore.playRegisterSuccessSound();
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.settings-page {
|
|
padding: calc(var(--app-nav-height) + 1rem) 0 1rem 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.theme {
|
|
|
|
:deep(.t-cell__title) {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.theme-slider {
|
|
width: 12rem;
|
|
flex: 0 0 12rem;
|
|
}
|
|
}
|
|
|
|
.volume-field {
|
|
gap: .5rem;
|
|
width: 16rem;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
:deep(.t-slider) {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
span {
|
|
color: #52607a;
|
|
font-size: .8125rem;
|
|
text-align: right;
|
|
}
|
|
}
|
|
}
|
|
|
|
:global(html.theme-dark) {
|
|
.settings-page {
|
|
.volume-field span {
|
|
color: #94a3b8;
|
|
}
|
|
}
|
|
}
|
|
</style>
|