Make aksrt_settings the sole theme settings store for get_all(), remove aksrt_seo_settings/aksrt_basic_settings merge paths, point global.logo schema at aksrt_settings, and delete the retired settings migration page, route, REST endpoint, and related SPA surface.
211 lines
9.1 KiB
Vue
211 lines
9.1 KiB
Vue
<template>
|
||
<div class="aksrt-page-container">
|
||
<PageHeader title="站点设置" desc="集中管理评论、分页、懒加载、头像源与备案信息。">
|
||
<template #actions>
|
||
<n-button type="primary" :loading="saving" @click="handleSave">保存全部</n-button>
|
||
</template>
|
||
</PageHeader>
|
||
|
||
<n-spin :show="loading" style="width:100%; min-height:200px;">
|
||
<!-- 1. 评论 -->
|
||
<n-card class="aksrt-section-card">
|
||
<div class="aksrt-section-header">
|
||
<span class="section-icon"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></span>
|
||
<h3>评论设置</h3>
|
||
</div>
|
||
<n-form :model="basic" label-placement="left" label-width="140" class="aksrt-form">
|
||
<n-form-item label="全局评论开关">
|
||
<n-switch v-model:value="basic.comment_enabled">
|
||
<template #checked>已开启</template>
|
||
<template #unchecked>已关闭</template>
|
||
</n-switch>
|
||
<template #feedback>
|
||
<span class="aksrt-hint-text">关闭后全站禁用评论功能。</span>
|
||
</template>
|
||
</n-form-item>
|
||
|
||
<n-form-item v-if="basic.comment_enabled" label="必须注册才能评论">
|
||
<n-switch v-model:value="basic.comment_requires_registration">
|
||
<template #checked>是</template>
|
||
<template #unchecked>否</template>
|
||
</n-switch>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<!-- 2. 分页 -->
|
||
<n-card class="aksrt-section-card">
|
||
<div class="aksrt-section-header">
|
||
<span class="section-icon"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg></span>
|
||
<h3>分页设置</h3>
|
||
</div>
|
||
<n-form :model="basic" label-placement="left" label-width="140" class="aksrt-form">
|
||
<n-form-item label="文章列表分页">
|
||
<n-radio-group v-model:value="basic.paging_ajax_s">
|
||
<n-space size="large">
|
||
<n-radio-button value="0">数字翻页</n-radio-button>
|
||
<n-radio-button value="1">加载更多</n-radio-button>
|
||
<n-radio-button value="1">无限滚动</n-radio-button>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
|
||
<n-form-item label="评论列表分页">
|
||
<n-radio-group v-model:value="basic.comment_pagination_mode">
|
||
<n-space size="large">
|
||
<n-radio-button value="0">数字翻页</n-radio-button>
|
||
<n-radio-button value="1">加载更多</n-radio-button>
|
||
<n-radio-button value="1">无限滚动</n-radio-button>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<!-- 3. 懒加载 -->
|
||
<n-card class="aksrt-section-card">
|
||
<div class="aksrt-section-header">
|
||
<span class="section-icon"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg></span>
|
||
<h3>图片懒加载</h3>
|
||
</div>
|
||
<n-form :model="basic" label-placement="left" label-width="140" class="aksrt-form">
|
||
<n-form-item label="启用懒加载">
|
||
<n-switch v-model:value="basic.lazyload_enabled">
|
||
<template #checked>已开启</template>
|
||
<template #unchecked>已关闭</template>
|
||
</n-switch>
|
||
<template #feedback>
|
||
<span class="aksrt-hint-text">开启后图片在进入视口时才加载,可显著提升页面加载速度。</span>
|
||
</template>
|
||
</n-form-item>
|
||
|
||
<n-form-item v-if="basic.lazyload_enabled" label="自定义占位图 URL">
|
||
<n-input v-model:value="basic.lazyload_placeholder_url" placeholder="留空使用默认占位图" />
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<!-- 4. 头像 -->
|
||
<n-card class="aksrt-section-card">
|
||
<div class="aksrt-section-header">
|
||
<span class="section-icon"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
|
||
<h3>Gravatar 头像源</h3>
|
||
</div>
|
||
<n-form :model="basic" label-placement="left" label-width="130" class="aksrt-form">
|
||
<n-form-item label="头像服务源">
|
||
<n-select v-model:value="basic.avatar_source" :options="avatarSourceOptions" placeholder="选择头像镜像源" />
|
||
<template #feedback>
|
||
<span class="aksrt-hint-text">国内站点建议优先选 Cravatar。</span>
|
||
</template>
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<!-- 5. 备案 -->
|
||
<n-card class="aksrt-section-card">
|
||
<div class="aksrt-section-header">
|
||
<span class="section-icon"><svg xmlns="http://www.w3.org/2000/svg" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg></span>
|
||
<h3>备案信息</h3>
|
||
</div>
|
||
<n-form :model="basic" label-placement="left" label-width="120" class="aksrt-form">
|
||
<n-form-item label="ICP 备案号">
|
||
<n-input v-model:value="basic.icp_number" placeholder="例如:ICP 备 xxxxxxxx 号" />
|
||
</n-form-item>
|
||
|
||
<n-form-item label="公安备案号">
|
||
<n-input v-model:value="basic.police_number" placeholder="例如:公网安备 xxxxxx 号" />
|
||
</n-form-item>
|
||
</n-form>
|
||
</n-card>
|
||
|
||
<div class="aksrt-form-actions">
|
||
<n-button type="primary" :loading="saving" @click="handleSave">保存全部</n-button>
|
||
</div>
|
||
</n-spin>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onMounted, reactive, ref } from 'vue'
|
||
import { useMessage } from 'naive-ui'
|
||
import api from '@/api'
|
||
import PageHeader from '@/components/PageHeader.vue'
|
||
|
||
const message = useMessage()
|
||
const loading = ref(true)
|
||
const saving = ref(false)
|
||
|
||
// 基础设置(canonical: aksrt_settings)
|
||
// 后端 /settings/basic 返回基础字段;auth 相关字段由 /settings/auth 独立维护。
|
||
const basic = reactive({
|
||
comment_enabled: true,
|
||
comment_requires_registration: false,
|
||
avatar_source: 'cn.cravatar.com',
|
||
icp_number: '',
|
||
police_number: '',
|
||
lazyload_enabled: true,
|
||
lazyload_placeholder_url: '',
|
||
paging_ajax_s: '1',
|
||
comment_pagination_mode: 'numbered',
|
||
})
|
||
|
||
const avatarSourceOptions = [
|
||
{ label: 'Cravatar (国内推荐)', value: 'cn.cravatar.com' },
|
||
{ label: 'Gravatar 国内镜像', value: 'cn.gravatar.com' },
|
||
{ label: 'Gravatar 官方', value: 'gravatar.com' },
|
||
]
|
||
|
||
async function loadAll() {
|
||
loading.value = true
|
||
try {
|
||
const basicRes = await api.getBasicSettings()
|
||
if (basicRes?.code === 'success' && basicRes.data) {
|
||
const d = basicRes.data
|
||
basic.comment_enabled = d.comment_enabled !== false
|
||
basic.comment_requires_registration = !!d.comment_requires_registration
|
||
basic.avatar_source = d.avatar_source || 'cn.cravatar.com'
|
||
basic.icp_number = d.icp_number || ''
|
||
basic.police_number = d.police_number || ''
|
||
basic.lazyload_enabled = d.lazyload_enabled !== false
|
||
basic.lazyload_placeholder_url = d.lazyload_placeholder_url || ''
|
||
basic.paging_ajax_s = d.paging_ajax_s ?? '1'
|
||
basic.comment_pagination_mode = d.comment_pagination_mode || 'numbered'
|
||
}
|
||
} catch (e) {
|
||
message.error(e.message || '加载失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleSave() {
|
||
saving.value = true
|
||
try {
|
||
const basicPayload = {
|
||
comment_enabled: basic.comment_enabled,
|
||
comment_requires_registration: basic.comment_requires_registration,
|
||
avatar_source: basic.avatar_source,
|
||
icp_number: basic.icp_number,
|
||
police_number: basic.police_number,
|
||
lazyload_enabled: basic.lazyload_enabled,
|
||
lazyload_placeholder_url: basic.lazyload_placeholder_url,
|
||
paging_ajax_s: basic.paging_ajax_s,
|
||
comment_pagination_mode: basic.comment_pagination_mode,
|
||
}
|
||
|
||
const res = await api.saveBasicSettings(basicPayload)
|
||
if (res?.code === 'success') {
|
||
message.success('已保存')
|
||
} else {
|
||
throw new Error(res?.message || '保存失败')
|
||
}
|
||
} catch (e) {
|
||
message.error(e.message || '保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(loadAll)
|
||
</script>
|