118 行
4.2 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<div style="max-width: 1100px">
<n-space justify="space-between" align="center" style="margin-bottom: 20px">
<div>
<h1 style="margin: 0 0 4px; font-size: 20px; font-weight: 600; color: #111827">页面副标题</h1>
<p style="margin: 0; font-size: 13px; color: #9ca3af">统一管理各页面顶部 Hero 区域的副标题文案</p>
</div>
<n-space>
<n-button type="primary" :loading="saving" @click="save">保存</n-button>
</n-space>
</n-space>
<n-spin :show="!loaded">
<n-space vertical :size="12">
<n-card
v-for="item in entries"
:key="item.key"
size="small"
>
<template #header>
<n-space align="center" :size="12">
<span style="font-size: 14px; font-weight: 600; color: #111827">{{ item.label }}</span>
<n-button
size="tiny"
tag="a"
:href="item.preview"
target="_blank"
quaternary
style="color: #6b7280"
>
查看前台
</n-button>
</n-space>
</template>
<n-input
v-model:value="data[item.key]"
type="textarea"
:autosize="{ minRows: 1, maxRows: 4 }"
:placeholder="`${item.label} 的副标题`"
/>
</n-card>
</n-space>
</n-spin>
</div>
</template>
<script setup>
import { NButton, NCard, NSpace, NInput, NSpin } from 'naive-ui'
import { useMessage } from 'naive-ui'
definePageMeta({ layout: 'admin', middleware: 'admin' })
const { adminFetch } = useAdmin()
const message = useMessage()
// 23 个页面的元信息key对应 heroes.json 的字段)、显示名、前台路径
const entries = [
{ key: 'about', label: '关于我们', preview: '/about' },
{ key: 'reviews', label: '客户评价', preview: '/reviews' },
{ key: 'guides', label: '出行指南', preview: '/guides' },
{ key: 'guide-custom', label: '定制游怎么选', preview: '/guide-custom' },
{ key: 'youji', label: '客户游记列表', preview: '/youji' },
{ key: 'xiaohongshu', label: '小红书游记列表', preview: '/xiaohongshu' },
{ key: 'stories', label: '客户故事列表', preview: '/stories' },
{ key: 'winter-camp', label: '冬令营', preview: '/winter-camp' },
{ key: 'summer-camp', label: '夏令营', preview: '/summer-camp' },
{ key: 'calendar', label: '旅行日历', preview: '/calendar' },
{ key: 'customize', label: '定制入口', preview: '/customize' },
{ key: 'blog', label: '博客列表', preview: '/blog' },
{ key: 'courses', label: '亲子研学课程', preview: '/courses' },
{ key: 'partners', label: '合作伙伴', preview: '/partners' },
{ key: 'contact', label: '联系我们', preview: '/contact' },
{ key: 'destinations', label: '目的地列表', preview: '/destinations' },
{ key: 'news', label: '最新动态', preview: '/news' },
{ key: 'products', label: '产品总览', preview: '/products' },
{ key: 'products-winter', label: '冬季产品', preview: '/products/winter' },
{ key: 'qualifications', label: '资质荣誉', preview: '/qualifications' },
{ key: 'selector', label: '产品选择器', preview: '/selector' },
{ key: 'pricing', label: '价格公开', preview: '/pricing' },
{ key: 'gallery', label: '呼籁旅拍', preview: '/gallery' },
]
const data = ref({})
const loaded = ref(false)
const saving = ref(false)
async function load() {
try {
const res = await adminFetch('/api/admin/site-content?key=heroes')
data.value = res.data || {}
} catch (e) {
data.value = {}
} finally {
// 保证 23 个 key 都存在,避免 v-model 报错
for (const item of entries) {
if (typeof data.value[item.key] !== 'string') data.value[item.key] = ''
}
loaded.value = true
}
}
async function save() {
saving.value = true
try {
await adminFetch('/api/admin/site-content', {
method: 'PUT',
body: { key: 'heroes', data: data.value },
})
message.success('已保存')
} catch (e) {
message.error('保存失败:' + (e.data?.message || ''))
} finally {
saving.value = false
}
}
onMounted(load)
</script>