Files
wordpress-theme-aksrt/assets/admin/src/pages/theme/ThemeInfoPage.vue
T
kate522 91b083b2b0 refactor(settings): collapse get_all to aksrt_settings and drop migration UI
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.
2026-07-11 16:55:27 +08:00

266 lines
8.0 KiB
Vue

<template>
<div class="aksrt-page-container">
<PageHeader title="主题信息" desc="主题版本、运行环境、已启用模块和关键系统信息。" />
<div v-if="loading" class="aksrt-theme-info__loading">
<n-spin size="medium" />
</div>
<template v-else>
<!-- Version Card -->
<n-card class="aksrt-theme-info__card" title="版本信息" size="small">
<n-descriptions :column="2" bordered label-placement="left" size="small">
<n-descriptions-item label="主题版本">
<n-tag type="success" size="small">{{ info.themeVersion }}</n-tag>
</n-descriptions-item>
<n-descriptions-item label="WordPress 版本">
{{ info.wpVersion }}
</n-descriptions-item>
<n-descriptions-item label="PHP 版本">
<n-tag :type="info.phpVersion >= '8.1' ? 'success' : 'warning'" size="small">
{{ info.phpVersion }}
</n-tag>
</n-descriptions-item>
<n-descriptions-item label="数据库 Schema">
<n-tag type="info" size="small">{{ info.dbSchemaVersion }}</n-tag>
</n-descriptions-item>
<n-descriptions-item label="邮箱验证回填">
<n-tag :type="info.emailBackfillDone ? 'success' : 'default'" size="small">
{{ info.emailBackfillDone ? '已完成' : '未触发' }}
</n-tag>
</n-descriptions-item>
</n-descriptions>
</n-card>
<!-- Environment Card -->
<n-card class="aksrt-theme-info__card" title="运行环境" size="small">
<n-descriptions :column="2" bordered label-placement="left" size="small">
<n-descriptions-item label="站点地址">
<n-text code>{{ info.siteUrl }}</n-text>
</n-descriptions-item>
<n-descriptions-item label="REST API">
<n-text code>{{ info.apiUrl }}</n-text>
</n-descriptions-item>
<n-descriptions-item label="主题目录">
<n-text code>{{ info.themeDir }}</n-text>
</n-descriptions-item>
<n-descriptions-item label="上传目录">
<n-text code>{{ info.uploadDir }}</n-text>
</n-descriptions-item>
<n-descriptions-item label="多站点">
<n-tag :type="info.isMultisite ? 'warning' : 'default'" size="small">
{{ info.isMultisite ? '是' : '否' }}
</n-tag>
</n-descriptions-item>
<n-descriptions-item label="调试模式">
<n-tag :type="info.debugMode ? 'warning' : 'default'" size="small">
{{ info.debugMode ? '开启' : '关闭' }}
</n-tag>
</n-descriptions-item>
</n-descriptions>
</n-card>
<!-- Modules Card -->
<n-card class="aksrt-theme-info__card" title="已启用模块" size="small">
<div class="aksrt-theme-info__modules">
<n-tag
v-for="mod in info.modules"
:key="mod.key"
:type="mod.enabled ? 'success' : 'default'"
size="small"
class="aksrt-theme-info__module-tag"
>
<FaIcon :icon="mod.enabled ? 'fas fa-check-circle' : 'fas fa-circle'" :size="10" />
{{ mod.label }}
</n-tag>
</div>
<n-text v-if="!info.modules.length" depth="3" style="font-size: 13px;">
暂无模块信息
</n-text>
</n-card>
<!-- Data Tables Card -->
<n-card class="aksrt-theme-info__card" title="数据表状态" size="small">
<n-data-table
:columns="tableColumns"
:data="info.tables"
:bordered="true"
size="small"
:max-height="300"
/>
</n-card>
<!-- Docs Links Card -->
<n-card class="aksrt-theme-info__card" title="快速入口" size="small">
<div class="aksrt-theme-info__links">
<router-link to="/docs" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-book" :size="16" />
<span>文档中心</span>
</router-link>
<router-link to="/tools/update" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-cloud-arrow-down" :size="16" />
<span>更新中心</span>
</router-link>
<router-link to="/tools/backup" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-box-archive" :size="16" />
<span>数据备份</span>
</router-link>
<router-link to="/tools/health" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-heartbeat" :size="16" />
<span>健康检查</span>
</router-link>
<router-link to="/tools/import-export" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-exchange-alt" :size="16" />
<span>导入导出</span>
</router-link>
</div>
</n-card>
</template>
</div>
</template>
<script setup>
import { ref, onMounted, h } from 'vue'
import { NTag, NText } from 'naive-ui'
import PageHeader from '@/components/PageHeader.vue'
import FaIcon from '@/components/form/FaIcon.vue'
import api from '@/api/index.js'
const loading = ref(true)
const info = ref({
themeVersion: '',
wpVersion: '',
phpVersion: '',
dbSchemaVersion: '',
emailBackfillDone: false,
siteUrl: '',
apiUrl: '',
themeDir: '',
uploadDir: '',
isMultisite: false,
debugMode: false,
modules: [],
tables: [],
})
const tableColumns = [
{ title: '数据表', key: 'name', width: 220 },
{
title: '状态',
key: 'exists',
width: 100,
render(row) {
return h(NTag, {
type: row.exists ? 'success' : 'error',
size: 'small',
bordered: false,
}, { default: () => row.exists ? '正常' : '缺失' })
},
},
{
title: '行数',
key: 'rows',
width: 100,
render(row) {
return row.exists ? row.rows.toLocaleString() : '—'
},
},
]
onMounted(async () => {
try {
const res = await api.getHealthCheck()
const data = res?.data || res || {}
info.value = {
themeVersion: window.aksrtAdminData?.themeVersion || data.theme_version || '3.4.0-dev',
wpVersion: data.wp_version || '',
phpVersion: data.php_version || '',
dbSchemaVersion: data.db_schema_version || '',
emailBackfillDone: !!data.email_backfill_done,
siteUrl: data.site_url || window.aksrtAdminData?.siteUrl || '',
apiUrl: data.api_url || window.aksrtAdminData?.apiUrl || '',
themeDir: data.theme_dir || '',
uploadDir: data.upload_dir || '',
isMultisite: !!data.is_multisite,
debugMode: !!data.debug_mode,
modules: normalizeModules(data.modules || []),
tables: normalizeTables(data.tables || []),
}
} catch (err) {
console.error('[ThemeInfo] Failed to load health data:', err)
// Fallback with minimal info
info.value.themeVersion = '3.4.0-dev'
info.value.siteUrl = window.aksrtAdminData?.siteUrl || ''
info.value.apiUrl = window.aksrtAdminData?.apiUrl || ''
} finally {
loading.value = false
}
})
function normalizeModules(raw) {
if (!Array.isArray(raw)) return []
return raw.map(m => ({
key: m.key || m.name || '',
label: m.label || m.name || m.key || '',
enabled: !!m.enabled,
}))
}
function normalizeTables(raw) {
if (!Array.isArray(raw)) return []
return raw.map(t => ({
name: t.name || '',
exists: !!t.exists,
rows: t.rows || 0,
}))
}
</script>
<style scoped>
.aksrt-theme-info__loading {
display: flex;
justify-content: center;
padding: 60px 0;
}
.aksrt-theme-info__card {
margin-bottom: 16px;
}
.aksrt-theme-info__modules {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.aksrt-theme-info__module-tag {
display: inline-flex;
align-items: center;
gap: 5px;
}
.aksrt-theme-info__links {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.aksrt-theme-info__link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border-radius: 6px;
background: #f5f7fa;
color: #333;
text-decoration: none;
font-size: 13px;
transition: background 0.2s;
}
.aksrt-theme-info__link:hover {
background: #e8eaed;
}
</style>