Files
VitPress-CMS/src/components/SystemSettingsPanel.vue
T
2026-06-08 22:50:18 +08:00

133 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, reactive, watch } from "vue";
import type { SystemSetting } from "../types";
const props = defineProps<{
settings: SystemSetting[];
saveState: "idle" | "saving" | "saved" | "error";
}>();
defineEmits<{
saveSettings: [settings: SystemSetting[]];
}>();
const draft = reactive<Record<string, SystemSetting>>({});
const groups = [
{
title: "基础",
eyebrow: "general",
keys: ["site.title"],
},
{
title: "认证",
eyebrow: "auth",
keys: ["auth.allow_email_login", "auth.allow_github_login", "auth.allow_registration"],
},
{
title: "SMTP",
eyebrow: "mail",
keys: ["smtp.host", "smtp.port", "smtp.username", "smtp.password", "smtp.sender_email"],
},
{
title: "GitHub",
eyebrow: "github",
keys: ["github.api_base_url", "github.web_base_url", "github.oauth_client_id", "github.oauth_client_secret"],
},
];
const labels: Record<string, string> = {
"site.title": "CMS 标题",
"auth.allow_email_login": "允许邮箱登录",
"auth.allow_github_login": "允许 GitHub 登录",
"auth.allow_registration": "开放注册",
"smtp.host": "SMTP 地址",
"smtp.port": "SMTP 端口",
"smtp.username": "SMTP 用户名",
"smtp.password": "SMTP 密码",
"smtp.sender_email": "发件人邮箱",
"github.api_base_url": "GitHub API 地址",
"github.web_base_url": "GitHub Web 地址",
"github.oauth_client_id": "OAuth Client ID",
"github.oauth_client_secret": "OAuth Client Secret",
};
const booleanKeys = new Set([
"auth.allow_email_login",
"auth.allow_github_login",
"auth.allow_registration",
]);
watch(
() => props.settings,
(settings) => {
Object.keys(draft).forEach((key) => delete draft[key]);
settings.forEach((setting) => {
draft[setting.key] = { ...setting };
});
},
{ immediate: true },
);
const draftSettings = computed(() => Object.values(draft));
function getSetting(key: string) {
if (!draft[key]) {
draft[key] = {
key,
value: "",
encrypted: key.includes("password") || key.includes("secret"),
updatedAt: "",
};
}
return draft[key];
}
function isBooleanKey(key: string) {
return booleanKeys.has(key);
}
</script>
<template>
<section class="panel is-visible">
<div class="settings-toolbar">
<p class="save-status" :class="`is-${saveState}`">
<template v-if="saveState === 'saved'">系统设置已保存</template>
<template v-else-if="saveState === 'error'">保存失败请查看日志</template>
<template v-else-if="saveState === 'saving'">正在保存系统设置</template>
<template v-else>系统设置保存到 SQLite 数据库</template>
</p>
<button class="primary-button" type="button" @click="$emit('saveSettings', draftSettings)">
{{ saveState === "saving" ? "保存中" : "保存设置" }}
</button>
</div>
<div class="settings-grid">
<section v-for="group in groups" :key="group.title" class="management-card">
<p class="eyebrow">{{ group.eyebrow }}</p>
<h3>{{ group.title }}</h3>
<label
v-for="key in group.keys"
:key="key"
:class="{ 'toggle-row': isBooleanKey(key) }"
>
<span>{{ labels[key] || key }}</span>
<input
v-if="isBooleanKey(key)"
:checked="getSetting(key).value === 'true'"
type="checkbox"
@change="getSetting(key).value = ($event.target as HTMLInputElement).checked ? 'true' : 'false'"
/>
<input
v-else
v-model="getSetting(key).value"
:placeholder="getSetting(key).encrypted ? '留空表示不修改敏感值' : ''"
:type="getSetting(key).encrypted ? 'password' : 'text'"
/>
</label>
</section>
</div>
</section>
</template>