fix(users): keep management inside center

This commit is contained in:
2026-08-12 20:59:31 +08:00
parent c3bfd12c69
commit ce2b266890
44 changed files with 194 additions and 2584 deletions
@@ -36,16 +36,6 @@ export const extensionsSection = {
canonicalDomain: 'extensions',
section: 'push',
}),
schemaPage({
key: 'extensions-docs-mode',
name: 'ExtensionsDocsMode',
label: '文档模式',
route: '/extensions/docs-mode',
title: '文档模式',
desc: '文档专题内容模式与页面增强。',
canonicalDomain: 'extensions',
section: 'docs-mode',
}),
customPage({
key: 'extensions-security',
name: 'ExtensionsSecurity',
-129
View File
@@ -2,43 +2,6 @@
<div class="aksrt-page-container">
<PageHeader title="文档中心" desc="主题使用文档、开发指南、迁移说明和更新日志。" />
<!-- Docs Mode Status -->
<n-card class="aksrt-docs__section" size="small">
<div class="aksrt-docs__mode-status">
<div class="aksrt-docs__mode-info">
<FaIcon :icon="docsModeEnabled ? 'fas fa-book-open' : 'fas fa-book'" :size="18" :color="docsModeEnabled ? '#52c41a' : '#8a909c'" />
<div>
<strong>{{ docsModeEnabled ? '文档模式已启用' : '文档模式未启用' }}</strong>
<p>{{ docsModeEnabled ? '文档导航页面和文档站式侧边栏已激活' : '启用后将激活文档导航页面模板和文档站式侧边栏' }}</p>
</div>
</div>
<n-space>
<router-link to="/extensions/docs-mode" class="aksrt-docs__mode-link">
<FaIcon icon="fas fa-cog" :size="12" />
{{ docsModeEnabled ? '管理文档模式' : '启用文档模式' }}
</router-link>
</n-space>
</div>
</n-card>
<!-- Doc Pages Overview -->
<n-card title="文档页面" size="small" class="aksrt-docs__section">
<n-alert v-if="docPageCount === 0" type="info" size="small">
尚未创建文档页面。在 WordPress 后台新建页面时,选择"文档导航页"或"专题聚合页"模板。
</n-alert>
<n-grid v-else :cols="3" :x-gap="12" :y-gap="12">
<n-grid-item v-for="stat in docPageStats" :key="stat.key">
<div class="aksrt-docs__stat">
<FaIcon :icon="stat.icon" :size="16" :color="stat.color" />
<div>
<strong>{{ stat.value }}</strong>
<p>{{ stat.label }}</p>
</div>
</div>
</n-grid-item>
</n-grid>
</n-card>
<!-- Quick Actions -->
<n-card title="常用操作" size="small" class="aksrt-docs__section">
<n-grid :cols="2" :x-gap="12" :y-gap="12">
@@ -130,13 +93,6 @@ import api from '@/api/index.js'
const themeVersion = ref(window.aksrtAdminData?.themeVersion || '3.4.0-dev')
const dbSchemaVersion = ref('—')
const docsModeEnabled = ref(false)
const docPageCount = ref(0)
const docPageStats = ref([
{ key: 'total', icon: 'fas fa-file-alt', color: '#1890ff', value: 0, label: '文档页面' },
{ key: 'nav', icon: 'fas fa-sitemap', color: '#722ed1', value: 0, label: '导航页' },
{ key: 'special', icon: 'fas fa-layer-group', color: '#fa8c16', value: 0, label: '专题页' },
])
const docs = ref([
{ key: 'admin-ia-map', title: '后台 IA 蓝图', description: '完整的后台信息架构映射,12 个顶级分区及子页面清单。', icon: 'fas fa-sitemap', color: '#1890ff', file: 'admin-ia-map.md' },
@@ -148,28 +104,6 @@ const docs = ref([
])
onMounted(async () => {
try {
const res = await api.getSchemaPage('extensions', 'docs-mode')
if (res?.data) {
docsModeEnabled.value = !!res.data.docs_mode_enabled
}
} catch {
// Schema endpoint may not exist yet
}
// Fetch doc page stats via REST if available
try {
const statsRes = await api.request('/docs/stats')
if (statsRes?.data) {
docPageCount.value = statsRes.data.total || 0
docPageStats.value[0].value = statsRes.data.total || 0
docPageStats.value[1].value = statsRes.data.nav_count || 0
docPageStats.value[2].value = statsRes.data.special_count || 0
}
} catch {
// Endpoint may not exist yet
}
// Fetch schema version from health
try {
const healthRes = await api.getHealthCheck()
@@ -189,69 +123,6 @@ function openDoc(doc) {
</script>
<style scoped>
.aksrt-docs__mode-status {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.aksrt-docs__mode-info {
display: flex;
align-items: center;
gap: 12px;
}
.aksrt-docs__mode-info strong {
display: block;
font-size: 14px;
color: #1a1a2e;
}
.aksrt-docs__mode-info p {
margin: 2px 0 0;
font-size: 12px;
color: #8a909c;
}
.aksrt-docs__mode-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 6px;
background: #f5f7fa;
color: #1890ff;
text-decoration: none;
font-size: 13px;
transition: background 0.2s;
}
.aksrt-docs__mode-link:hover {
background: #e6f4ff;
}
.aksrt-docs__stat {
display: flex;
align-items: center;
gap: 10px;
padding: 12px;
border-radius: 6px;
background: #fafafa;
}
.aksrt-docs__stat strong {
display: block;
font-size: 20px;
color: #1a1a2e;
}
.aksrt-docs__stat p {
margin: 0;
font-size: 12px;
color: #8a909c;
}
.aksrt-docs__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
@@ -1,311 +0,0 @@
<template>
<div class="aksrt-page-container">
<PageHeader title="文档模式" desc="启用文档专题内容模式,配置文档导航页面和文档站式体验。" />
<n-card class="aksrt-docs-mode__card" title="文档模式" size="small">
<n-form label-placement="left" label-width="160">
<n-form-item label="启用文档模式">
<n-switch v-model:value="formData.docs_mode_enabled" />
<n-text depth="3" style="margin-left: 12px; font-size: 12px;">
开启后将激活文档导航页面模板和文档站式侧边栏
</n-text>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="文档首页模板">
<n-select
v-model:value="formData.docs_mode_default_template"
:options="templateOptions"
placeholder="选择文档首页模板"
style="max-width: 360px;"
/>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="文档分类">
<n-select
v-model:value="formData.docs_mode_cats"
:options="categoryOptions"
:loading="categoriesLoading"
multiple
clearable
filterable
placeholder="选择用于文档模式的分类"
style="max-width: 520px;"
/>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="首页排除">
<n-switch v-model:value="formData.docs_mode_exclude" />
<n-text depth="3" style="margin-left: 12px; font-size: 12px;">
开启后,所选文档分类的内容不会出现在首页常规文章流中
</n-text>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="显示目录树">
<n-switch v-model:value="formData.docs_mode_toc_enabled" />
<n-text depth="3" style="margin-left: 12px; font-size: 12px;">
在文档页面侧边栏显示章节目录树
</n-text>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="显示章节导航">
<n-switch v-model:value="formData.docs_mode_chapter_nav_enabled" />
<n-text depth="3" style="margin-left: 12px; font-size: 12px;">
在文档底部显示上一章/下一章导航
</n-text>
</n-form-item>
<n-form-item v-if="formData.docs_mode_enabled" label="默认排序">
<n-radio-group v-model:value="formData.docs_mode_default_order">
<n-radio value="menu_order">按菜单顺序</n-radio>
<n-radio value="date">按发布时间</n-radio>
<n-radio value="title">按标题排序</n-radio>
</n-radio-group>
</n-form-item>
</n-form>
<template #action>
<n-space justify="end">
<n-button @click="handleReset">重置</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存设置</n-button>
</n-space>
</template>
</n-card>
<n-card title="文档页面统计" size="small" class="aksrt-docs-mode__card">
<n-grid :cols="3" :x-gap="12" :y-gap="12">
<n-grid-item>
<div class="aksrt-docs-mode__stat">
<strong>{{ docStats.total || 0 }}</strong>
<p>文档页面总数</p>
</div>
</n-grid-item>
<n-grid-item>
<div class="aksrt-docs-mode__stat">
<strong>{{ docStats.nav_count || 0 }}</strong>
<p>文档导航页</p>
</div>
</n-grid-item>
<n-grid-item>
<div class="aksrt-docs-mode__stat">
<strong>{{ docStats.special_count || 0 }}</strong>
<p>专题聚合页</p>
</div>
</n-grid-item>
</n-grid>
</n-card>
<n-card title="可用页面模板" size="small" class="aksrt-docs-mode__card">
<n-alert type="info" size="small" style="margin-bottom: 12px;">
以下页面模板可用于创建文档类页面。在 WordPress 后台新建页面时,从"页面属性 → 模板"中选择对应模板。
</n-alert>
<n-list bordered size="small">
<n-list-item v-for="tpl in availableTemplates" :key="tpl.file">
<n-thing :title="tpl.name" :description="tpl.description">
<template #avatar>
<FaIcon :icon="tpl.icon" :size="18" color="#1890ff" />
</template>
<template #header-extra>
<n-tag size="small" type="info">{{ tpl.file }}</n-tag>
</template>
</n-thing>
</n-list-item>
</n-list>
</n-card>
<n-card title="快速入口" size="small" class="aksrt-docs-mode__card">
<n-space>
<router-link to="/page-display/special" class="aksrt-docs-mode__link">
<FaIcon icon="fas fa-layer-group" :size="14" />
专题页面配置
</router-link>
</n-space>
</n-card>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useMessage } from 'naive-ui'
import PageHeader from '@/components/PageHeader.vue'
import FaIcon from '@/components/form/FaIcon.vue'
import api from '@/api/index.js'
const message = useMessage()
const saving = ref(false)
const docStats = ref({ total: 0, nav_count: 0, special_count: 0 })
const categoriesLoading = ref(false)
const categoryOptions = ref([])
const defaults = {
docs_mode_enabled: false,
docs_mode_default_template: 'documentnav',
docs_mode_toc_enabled: true,
docs_mode_chapter_nav_enabled: true,
docs_mode_default_order: 'menu_order',
docs_mode_cats: [],
docs_mode_exclude: true,
}
const formData = ref({ ...defaults })
const templateOptions = [
{ label: '文档导航页 (page-documentnav)', value: 'documentnav' },
{ label: '专题聚合页 (page-special)', value: 'special' },
]
const availableTemplates = [
{
file: 'page-documentnav.php',
name: '文档导航页',
description: '站式文档导航模板,支持侧边栏目录树、章节高亮和快速搜索。',
icon: 'fas fa-book',
},
{
file: 'page-special.php',
name: '专题聚合页',
description: '专题内容聚合模板,支持封面、摘要、多列布局和子页面矩阵。',
icon: 'fas fa-layer-group',
},
{
file: 'page-download.php',
name: '下载中心页',
description: '资源下载中心模板,支持资源类型筛选、权限说明和交易承接。',
icon: 'fas fa-download',
},
{
file: 'page-categories.php',
name: '分类导航页',
description: '全站分类导航模板,展示分类树和文章统计。',
icon: 'fas fa-folder-open',
},
{
file: 'page-friends.php',
name: '友情链接页',
description: '友情链接展示模板。',
icon: 'fas fa-link',
},
]
onMounted(async () => {
await Promise.all([loadSettings(), loadDocStats(), loadCategories()])
})
async function loadSettings() {
try {
const res = await api.getSchemaPage('extensions', 'docs-mode')
if (res?.data) {
formData.value = {
...defaults,
...res.data,
docs_mode_cats: normalizeCategoryIds(res.data.docs_mode_cats),
}
}
} catch {
// Schema endpoint may not exist yet; use defaults
}
}
async function loadDocStats() {
try {
const statsRes = await api.request('/docs/stats')
if (statsRes?.data) {
docStats.value = statsRes.data
}
} catch {
// Endpoint may not exist yet
}
}
async function loadCategories() {
categoriesLoading.value = true
try {
const res = await api.getCategories()
const items = res?.data || res || []
categoryOptions.value = (Array.isArray(items) ? items : []).map((item) => ({
label: item.name + (item.count ? ` (${item.count})` : ''),
value: Number(item.term_id),
}))
} catch {
categoryOptions.value = []
} finally {
categoriesLoading.value = false
}
}
function normalizeCategoryIds(value) {
if (Array.isArray(value)) {
return value.map((item) => Number(item)).filter((item) => Number.isFinite(item) && item > 0)
}
if (typeof value === 'string' && value.trim()) {
return value
.split(',')
.map((item) => Number(item.trim()))
.filter((item) => Number.isFinite(item) && item > 0)
}
return []
}
async function handleSave() {
saving.value = true
try {
await api.saveSchemaPage('extensions', 'docs-mode', {
...formData.value,
docs_mode_cats: normalizeCategoryIds(formData.value.docs_mode_cats),
})
message.success('文档模式设置已保存')
} catch (err) {
message.error('保存失败: ' + (err?.message || '未知错误'))
} finally {
saving.value = false
}
}
function handleReset() {
formData.value = { ...defaults }
message.info('已重置为默认值')
}
</script>
<style scoped>
.aksrt-docs-mode__card {
margin-bottom: 16px;
}
.aksrt-docs-mode__stat {
text-align: center;
padding: 12px;
border-radius: 6px;
background: #fafafa;
}
.aksrt-docs-mode__stat strong {
display: block;
font-size: 24px;
color: #1a1a2e;
}
.aksrt-docs-mode__stat p {
margin: 4px 0 0;
font-size: 12px;
color: #8a909c;
}
.aksrt-docs-mode__link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 14px;
border-radius: 6px;
background: #f5f7fa;
color: #1890ff;
text-decoration: none;
font-size: 13px;
transition: background 0.2s;
}
.aksrt-docs-mode__link:hover {
background: #e6f4ff;
}
</style>
@@ -84,7 +84,6 @@ const updateInfo = ref({
const guides = [
{ key: 'rewrite', title: '伪静态配置', desc: '检查固定链接与重写规则', url: '/wp-admin/options-permalink.php' },
{ key: 'docs-mode', title: '文档模式', desc: '配置文档分类与专题模板', url: '#/extensions/docs-mode' },
{ key: 'oauth', title: '第三方登录', desc: '检查 GitHub / Gitee / QQ / Google 登录', url: '#/users/oauth' },
{ key: 'backup', title: '设置快照', desc: '创建与恢复站点配置快照', url: '#/tools/backup' },
{ key: 'health', title: '健康检查', desc: '查看 PHP / WP / 数据表状态', url: '#/tools/health' },
@@ -1,125 +0,0 @@
export const docsModeSchema = {
key: 'extensions.docs-mode',
title: '文档模式',
icon: 'fas fa-book-open',
description: '启用文档专题内容模式,配置文档导航页面和文档站式体验。',
defaults: {
docs_mode_enabled: false,
docs_mode_default_template: 'documentnav',
docs_mode_toc_enabled: true,
docs_mode_chapter_nav_enabled: true,
docs_mode_default_order: 'menu_order',
docs_mode_cats: [],
docs_mode_exclude: true,
docs_mode_toc_depth: 3,
docs_mode_chapter_title: '',
docs_mode_style: 'default',
docs_mode_icon: true,
docs_mode_count: true,
},
groups: [
{
key: 'basic',
title: '基础配置',
icon: 'fas fa-cog',
fields: [
{ key: 'docs_mode_enabled', label: '启用文档模式', type: 'switch', default: false, help: '开启后将激活文档导航页面模板和文档站式侧边栏' },
{
key: 'docs_mode_default_template',
label: '文档首页模板',
type: 'select',
default: 'documentnav',
options: [
{ label: '文档导航页', value: 'documentnav' },
{ label: '专题聚合页', value: 'special' },
],
dependsOn: { key: 'docs_mode_enabled', value: true },
},
],
},
{
key: 'navigation',
title: '导航设置',
icon: 'fas fa-compass',
fields: [
{ key: 'docs_mode_toc_enabled', label: '显示目录树', type: 'switch', default: true, dependsOn: { key: 'docs_mode_enabled', value: true }, help: '在文档页面侧边栏显示章节目录树' },
{ key: 'docs_mode_chapter_nav_enabled', label: '显示章节导航', type: 'switch', default: true, dependsOn: { key: 'docs_mode_enabled', value: true }, help: '在文档底部显示上一章/下一章导航' },
{
key: 'docs_mode_default_order',
label: '默认排序',
type: 'radio',
default: 'menu_order',
options: [
{ label: '按菜单顺序', value: 'menu_order' },
{ label: '按发布时间', value: 'date' },
{ label: '按标题排序', value: 'title' },
],
dependsOn: { key: 'docs_mode_enabled', value: true },
},
{
key: 'docs_mode_toc_depth',
label: '目录深度',
type: 'number',
default: 3,
min: 1,
max: 6,
dependsOn: { key: 'docs_mode_enabled', value: true },
},
{
key: 'docs_mode_chapter_title',
label: '章节标题',
type: 'input',
default: '',
dependsOn: { key: 'docs_mode_enabled', value: true },
},
],
},
{
key: 'filter',
title: '筛选设置',
icon: 'fas fa-filter',
fields: [
{
key: 'docs_mode_cats',
label: '文档分类',
type: 'taxonomy_select',
taxonomy: 'category',
multiple: true,
clearable: true,
default: [],
placeholder: '选择用于文档模式的分类',
dependsOn: { key: 'docs_mode_enabled', value: true },
},
{
key: 'docs_mode_exclude',
label: '在首页排除此类内容',
type: 'switch',
default: true,
dependsOn: { key: 'docs_mode_enabled', value: true },
help: '开启后,所选文档分类的内容不会出现在首页常规文章流中。',
},
],
},
{
key: 'style',
title: '样式设置',
icon: 'fas fa-palette',
fields: [
{
key: 'docs_mode_style',
label: '文档样式',
type: 'select',
default: 'default',
options: [
{ label: '默认', value: 'default' },
{ label: '简洁', value: 'simple' },
{ label: '卡片', value: 'card' },
],
dependsOn: { key: 'docs_mode_enabled', value: true },
},
{ key: 'docs_mode_icon', label: '显示图标', type: 'switch', default: true, dependsOn: { key: 'docs_mode_enabled', value: true } },
{ key: 'docs_mode_count', label: '显示文章数', type: 'switch', default: true, dependsOn: { key: 'docs_mode_enabled', value: true } },
],
},
],
}
@@ -6,11 +6,9 @@
import { ipSchema } from './ip.js'
import { auditSchema } from './audit.js'
import { pushSchema } from './push.js'
import { docsModeSchema } from './docs-mode.js'
export const extensionsSchemas = {
ip: ipSchema,
audit: auditSchema,
push: pushSchema,
'docs-mode': docsModeSchema,
}