Files
wordpress-theme-aksrt/assets/admin/src/pages/content/HomepageSettings.vue
T

372 lines
15 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.
<template>
<div class="aksrt-page-container content-page">
<PageHeader
title="首页配置"
desc="配置首页主列表、分类 Tab 与基础交互。列表/卡片显示请在「文章列表」中设置。"
>
<template #actions>
<n-button type="primary" :loading="saving" @click="handleSave">保存设置</n-button>
</template>
</PageHeader>
<n-tabs v-model:value="activeTab" type="line" animated>
<n-tab-pane name="stream" tab="主列表 & Tab">
<n-spin :show="loading" style="width:100%; min-height:200px;">
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>首页说明</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="内容说明">
<n-alert type="info" :show-icon="false">
首页主列表只使用普通文章。下载/付费是文章能力(meta),不是第二种内容类型。当前为固定骨架模式,不再使用旧版自由模块画布。
</n-alert>
</n-form-item>
</n-form>
</n-card>
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>主列表</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="启用主列表">
<n-switch v-model:value="form.home_posts_list_s" />
<template #feedback><span class="aksrt-hint-text">首页主内容区保留 Zibll 式内容流,不建议关闭。</span></template>
</n-form-item>
<n-form-item label="显示标题">
<n-input v-model:value="form.index_list_title" placeholder="最新发布" />
</n-form-item>
<n-form-item label="主栏目默认排序">
<n-select v-model:value="form.home_list1_orderby_option.orderby" :options="allSortOptions" />
</n-form-item>
<n-form-item label="显示排序方式按钮">
<n-switch v-model:value="form.home_list1_orderby_s" />
</n-form-item>
<n-form-item v-if="form.home_list1_orderby_s" label="排序栏样式">
<n-radio-group v-model:value="form.home_list_sort_dropdown">
<n-space size="large">
<n-radio-button :value="false">内联链接</n-radio-button>
<n-radio-button :value="true">下拉菜单</n-radio-button>
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item v-if="form.home_list1_orderby_s" label="排序方式选项">
<n-select
v-model:value="form.home_list1_orderby_option.options"
:options="allSortOptions"
multiple
placeholder="选择排序选项"
/>
</n-form-item>
</n-form>
</n-card>
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>排除规则</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="排除文章">
<n-input
v-model:value="excludePostIdsText"
type="textarea"
placeholder="逗号分隔的文章 ID,如 12,34,56"
:rows="2"
/>
<template #feedback><span class="aksrt-hint-text">主列表和首页 Tab 查询均排除这些文章。</span></template>
</n-form-item>
<n-form-item label="排除分类">
<n-input
v-model:value="excludeCategoryIdsText"
type="textarea"
placeholder="逗号分隔的分类 ID,如 5,8"
:rows="2"
/>
<template #feedback><span class="aksrt-hint-text">主列表排除这些分类,首页 Tab 不能绑定已排除分类。</span></template>
</n-form-item>
</n-form>
</n-card>
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header>
<div style="display:flex; align-items:center; justify-content:space-between;">
<strong>更多栏目</strong>
<n-button size="small" @click="addTab">+ 添加栏目</n-button>
</div>
</template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form" style="margin-bottom:16px;">
<n-form-item label="Tab 数量上限">
<n-input-number v-model:value="form.homepage_tab_limit" :min="1" :max="12" />
</n-form-item>
<n-form-item label="每 Tab 文章数">
<n-input-number v-model:value="form.homepage_tab_posts_per_page" :min="1" :max="20" />
</n-form-item>
</n-form>
<div v-if="form.home_lists.length === 0" class="homepage-settings__empty-tabs">
<n-text depth="3">暂无更多栏目,点击“添加栏目”创建分类/专题 Tab。</n-text>
</div>
<div v-for="(tab, index) in form.home_lists" :key="index" class="homepage-settings__tab-row">
<div class="homepage-settings__tab-fields">
<n-select
:value="tab.term_id"
:options="categoryOptions"
placeholder="分类"
filterable
style="flex:2;"
@update:value="(val) => updateTab(index, 'term_id', val)"
/>
<n-input
:value="tab.title"
placeholder="自定义标题"
style="flex:1;"
@update:value="(val) => updateTab(index, 'title', val)"
/>
<n-select
:value="tab.orderby"
:options="allSortOptions"
style="flex:1;"
@update:value="(val) => updateTab(index, 'orderby', val)"
/>
<n-switch
:value="tab.enabled"
@update:value="(val) => updateTab(index, 'enabled', val)"
/>
<n-button size="small" quaternary type="error" @click="removeTab(index)">删除</n-button>
</div>
</div>
</n-card>
</n-spin>
</n-tab-pane>
<n-tab-pane name="cards" tab="卡片 & 交互">
<n-spin :show="loading" style="width:100%; min-height:200px;">
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>列表显示</strong></template>
<n-alert type="info" :show-icon="false">
首页文章列表/卡片模式、样式变体与缩略图比例已统一到「文章&amp;列表 → 文章列表」设置(对齐 Zibll 全局 list_type / list_card_home)。此处不再单独维护 homepage_card_style / 默认视图。
</n-alert>
</n-card>
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header><strong>交互设置</strong></template>
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
<n-form-item label="排序栏 AJAX">
<n-switch v-model:value="form.homepage_sort_ajax_enabled" />
<template #feedback><span class="aksrt-hint-text">关闭后排序链接使用整页跳转。</span></template>
</n-form-item>
<n-form-item label="Tab 吸顶">
<n-switch v-model:value="form.homepage_sticky_tabs_enabled" />
</n-form-item>
<n-form-item label="迷你侧栏列表">
<n-switch v-model:value="form.homepage_sidebar_mini_enabled" />
</n-form-item>
</n-form>
</n-card>
<n-card class="aksrt-section-card">
<template #header><strong>固定骨架说明</strong></template>
<n-space vertical>
<n-alert type="warning" :show-icon="false">
Hero 与 Banner 已作为固定首页骨架的一部分维护,不再由旧版首页模块编排驱动。
</n-alert>
<n-alert type="info" :show-icon="false">
如需调整首页首屏运营区,请前往对应管理页配置幻灯片内容或顶部组件参数。
</n-alert>
<n-space>
<n-button secondary type="primary" @click="router.push('/page-display/hero')">管理 Hero 轮播</n-button>
<n-button secondary type="primary" @click="router.push('/page-display/banner')">管理 Banner 轮播</n-button>
<n-button secondary @click="router.push('/page-display/header-components')">
顶部多功能组件
</n-button>
</n-space>
</n-space>
</n-card>
</n-spin>
</n-tab-pane>
</n-tabs>
<div class="aksrt-form-actions">
<n-button type="primary" :loading="saving" @click="handleSave">保存设置</n-button>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useMessage } from 'naive-ui'
import api from '@/api'
import PageHeader from '@/components/PageHeader.vue'
const router = useRouter()
const message = useMessage()
const loading = ref(true)
const saving = ref(false)
const activeTab = ref('stream')
const categoryOptions = ref([])
const allSortOptions = [
{ label: '最近更新', value: 'modified' },
{ label: '发布时间', value: 'date' },
{ label: '浏览量', value: 'views' },
{ label: '点赞数', value: 'likes' },
{ label: '评论数', value: 'comments' },
{ label: '收藏数', value: 'favorites' },
{ label: '下载量', value: 'downloads' },
{ label: '随机', value: 'rand' },
]
const form = reactive({
home_posts_list_s: true,
home_list1_orderby_s: true,
home_list1_orderby_option: {
orderby: 'modified',
options: ['modified', 'date', 'views', 'likes', 'comments'],
},
index_list_title: '最新发布',
home_exclude_posts: [],
home_exclude_cats: [],
home_lists: [],
homepage_card_style: 'default',
homepage_multi_thumb_enabled: true,
homepage_multi_thumb_min_images: 3,
homepage_sidebar_mini_enabled: true,
homepage_default_view: 'list',
homepage_sort_ajax_enabled: true,
homepage_sticky_tabs_enabled: true,
home_list_sort_dropdown: false,
homepage_tab_posts_per_page: 6,
homepage_tab_limit: 4,
})
const excludePostIdsText = computed({
get: () => (form.home_exclude_posts || []).join(','),
set: (val) => {
form.home_exclude_posts = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
},
})
const excludeCategoryIdsText = computed({
get: () => (form.home_exclude_cats || []).join(','),
set: (val) => {
form.home_exclude_cats = val.split(',').map(s => parseInt(s.trim(), 10)).filter(n => n > 0)
},
})
function addTab() {
form.home_lists.push({ term_id: 0, title: '', orderby: 'date', enabled: true })
}
function removeTab(index) {
form.home_lists.splice(index, 1)
}
function updateTab(index, field, value) {
form.home_lists[index][field] = value
}
async function loadCategories() {
try {
const res = await api.getHomepageCategories()
const cats = res?.data || []
categoryOptions.value = cats.map(c => ({
label: `${c.taxonomy === 'topics' ? '[专题] ' : ''}${c.name} (${c.count})`,
value: c.term_id || c.id,
}))
} catch {
// non-critical
}
}
async function loadSettings() {
loading.value = true
try {
const res = await api.getHomepageSettings()
const d = res?.data || {}
form.home_posts_list_s = d.home_posts_list_s !== false && d.home_posts_list_enabled !== false
form.home_list1_orderby_s = d.home_list1_orderby_s !== false && d.home_list_sort_enabled !== false
const orderOpt = d.home_list1_orderby_option && typeof d.home_list1_orderby_option === 'object' ? d.home_list1_orderby_option : {}
form.home_list1_orderby_option = {
orderby: orderOpt.orderby || d.homepage_default_sort || 'modified',
options: Array.isArray(orderOpt.options) && orderOpt.options.length
? orderOpt.options
: (Array.isArray(d.home_list_sort_options) && d.home_list_sort_options.length
? d.home_list_sort_options
: ['modified', 'date', 'views', 'likes', 'comments']),
}
form.index_list_title = d.index_list_title || d.home_list_title || '最新发布'
form.home_exclude_posts = Array.isArray(d.home_exclude_posts)
? d.home_exclude_posts
: (Array.isArray(d.home_exclude_post_ids) ? d.home_exclude_post_ids : [])
form.home_exclude_cats = Array.isArray(d.home_exclude_cats)
? d.home_exclude_cats
: (Array.isArray(d.home_exclude_category_ids) ? d.home_exclude_category_ids : [])
form.home_lists = Array.isArray(d.home_lists)
? d.home_lists
: (Array.isArray(d.homepage_tabs) ? d.homepage_tabs : [])
form.homepage_card_style = d.homepage_card_style || 'default'
form.homepage_multi_thumb_enabled = d.homepage_multi_thumb_enabled !== false
form.homepage_multi_thumb_min_images = d.homepage_multi_thumb_min_images || 3
form.homepage_sidebar_mini_enabled = d.homepage_sidebar_mini_enabled !== false
form.homepage_default_view = d.homepage_default_view || 'list'
form.homepage_sort_ajax_enabled = d.homepage_sort_ajax_enabled !== false
form.homepage_sticky_tabs_enabled = d.homepage_sticky_tabs_enabled !== false
form.home_list_sort_dropdown = !!d.home_list_sort_dropdown
form.homepage_tab_posts_per_page = d.homepage_tab_posts_per_page || 6
form.homepage_tab_limit = d.homepage_tab_limit || 4
} catch (error) {
message.error(error.message || '加载设置失败')
} finally {
loading.value = false
}
}
async function handleSave() {
saving.value = true
try {
const payload = {
...form,
}
const res = await api.saveHomepageSettings(payload)
if (res?.code === 'success') {
message.success('首页设置已保存')
return
}
throw new Error(res?.message || '保存失败')
} catch (error) {
message.error(error.message || '保存失败')
} finally {
saving.value = false
}
}
onMounted(() => {
loadCategories()
loadSettings()
})
</script>
<style scoped>
.homepage-settings__empty-tabs {
padding: 24px;
text-align: center;
border: 1px dashed var(--n-border-color);
border-radius: 4px;
margin-bottom: 12px;
}
.homepage-settings__tab-row {
margin-bottom: 8px;
}
.homepage-settings__tab-fields {
display: flex;
gap: 8px;
align-items: center;
}
.aksrt-form-actions {
margin-top: 16px;
text-align: right;
}
</style>