导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

+211
View File
@@ -0,0 +1,211 @@
<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.post_pagination_mode">
<n-space size="large">
<n-radio-button value="numbered">数字翻页</n-radio-button>
<n-radio-button value="load_more">加载更多</n-radio-button>
<n-radio-button value="infinite">无限滚动</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="numbered">数字翻页</n-radio-button>
<n-radio-button value="load_more">加载更多</n-radio-button>
<n-radio-button value="infinite">无限滚动</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)
// 基础设置(aksrt_basic_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: '',
post_pagination_mode: 'numbered',
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.post_pagination_mode = d.post_pagination_mode || 'numbered'
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,
post_pagination_mode: basic.post_pagination_mode,
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>