feat: 新增常规设置页面,支持关闭行为与语言切换
新增常规设置路由和页面,实现关闭行为(每次询问/保持选择)与应用语言的持久化配置;封装卡片式单选组组件复用在关闭弹窗和设置页;修改关闭逻辑,根据关闭行为决定是否显示确认弹窗,同步更新多语言文案和类型定义。
This commit is contained in:
@@ -2,29 +2,27 @@
|
||||
<a-modal
|
||||
:open="store.closeConfirmOpen"
|
||||
:title="t('closeDialog.title')"
|
||||
:width="380"
|
||||
:width="400"
|
||||
centered
|
||||
:mask-closable="false"
|
||||
:closable="!store.quitting"
|
||||
:keyboard="!store.quitting"
|
||||
@cancel="store.cancelClose()"
|
||||
>
|
||||
<a-radio-group v-model:value="store.closeChoice" class="close-choice">
|
||||
<a-radio value="tray" class="close-option">
|
||||
<span class="close-option-title">{{ t("closeDialog.tray") }}</span>
|
||||
<span class="close-option-desc">{{ t("closeDialog.trayDesc") }}</span>
|
||||
</a-radio>
|
||||
<a-radio value="exit" class="close-option">
|
||||
<span class="close-option-title">{{ t("closeDialog.exit") }}</span>
|
||||
<span class="close-option-desc">{{ t("closeDialog.exitDesc") }}</span>
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
<!-- 关闭方式:最小化到系统托盘 / 直接退出 -->
|
||||
<CardRadioGroup v-model="draftChoice" :options="choiceOptions" :disabled="store.quitting" />
|
||||
|
||||
<a-divider class="!my-3" />
|
||||
|
||||
<!-- 关闭行为:每次询问 / 保持以上选择 -->
|
||||
<div class="mb-2 text-xs opacity-60">{{ t("closeDialog.behavior") }}</div>
|
||||
<CardRadioGroup v-model="draftBehavior" :options="behaviorOptions" :disabled="store.quitting" />
|
||||
|
||||
<template #footer>
|
||||
<a-button :disabled="store.quitting" @click="store.cancelClose()">
|
||||
{{ t("common.cancel") }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="store.quitting" @click="store.confirmClose()">
|
||||
<a-button type="primary" :loading="store.quitting" @click="onConfirm">
|
||||
{{ t("common.confirm") }}
|
||||
</a-button>
|
||||
</template>
|
||||
@@ -33,68 +31,40 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from "vue-i18n"
|
||||
import { useWindowStore } from "@/stores/window"
|
||||
import { useWindowStore, type CloseBehavior, type CloseChoice } from "@/stores/window"
|
||||
|
||||
const { t } = useI18n()
|
||||
const store = useWindowStore()
|
||||
|
||||
/** 弹窗内的临时选择,点击「确定」后才写回设置(避免误触单选框又取消时被改掉) */
|
||||
const draftChoice = ref<CloseChoice>("tray")
|
||||
const draftBehavior = ref<CloseBehavior>("ask")
|
||||
|
||||
const choiceOptions = computed(() => [
|
||||
{ value: "tray" as const, label: t("closeDialog.tray"), description: t("closeDialog.trayDesc") },
|
||||
{ value: "exit" as const, label: t("closeDialog.exit"), description: t("closeDialog.exitDesc") },
|
||||
])
|
||||
|
||||
const behaviorOptions = computed(() => [
|
||||
{ value: "ask" as const, label: t("closeDialog.ask"), description: t("closeDialog.askDesc") },
|
||||
{
|
||||
value: "remember" as const,
|
||||
label: t("closeDialog.remember"),
|
||||
description: t("closeDialog.rememberDesc"),
|
||||
},
|
||||
])
|
||||
|
||||
// 每次打开弹窗时,用当前设置初始化临时选择
|
||||
watch(
|
||||
() => store.closeConfirmOpen,
|
||||
(open) => {
|
||||
if (!open) return
|
||||
draftChoice.value = store.closeChoice
|
||||
draftBehavior.value = store.closeBehavior
|
||||
},
|
||||
)
|
||||
|
||||
function onConfirm() {
|
||||
void store.confirmClose(draftChoice.value, draftBehavior.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.close-choice {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.close-option {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
margin-inline-end: 0;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(15, 23, 42, 0.1);
|
||||
transition: border-color 0.2s ease, background-color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: rgba(99, 102, 241, 0.5);
|
||||
}
|
||||
|
||||
// 选中态高亮
|
||||
&.ant-radio-wrapper-checked {
|
||||
border-color: #6366f1;
|
||||
background-color: rgba(99, 102, 241, 0.08);
|
||||
}
|
||||
|
||||
:deep(.ant-radio) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
:deep(> span:last-child) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dark .close-option {
|
||||
border-color: rgba(255, 255, 255, 0.12);
|
||||
|
||||
&.ant-radio-wrapper-checked {
|
||||
border-color: #6366f1;
|
||||
background-color: rgba(99, 102, 241, 0.16);
|
||||
}
|
||||
}
|
||||
|
||||
.close-option-title {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.close-option-desc {
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user