feat(navigation): hard-switch to Zibll navigation and Font Awesome 5

This commit is contained in:
kate522 committed 2026-08-18 20:46:21 +08:00
1 parent 3c3ddac8be
commit a0b84977a2
630 files changed
+101647 -11293

No files matched your search

@@ -11,7 +11,7 @@
<template #header>
<div class="aksrt-card-header-row">
<div class="aksrt-card-header-row__left">
<span class="header-icon"><i class="fas fa-cog"></i></span>
<span class="header-icon"><i class="fa fas fa-cog"></i></span>
<strong class="aksrt-card-header-row__title">基础设置</strong>
</div>
</div>
@@ -61,11 +61,11 @@
<template #header>
<div class="aksrt-card-header-row">
<div class="aksrt-card-header-row__left">
<span class="header-icon"><i class="fas fa-layer-group"></i></span>
<span class="header-icon"><i class="fa fas fa-clone"></i></span>
<strong class="aksrt-card-header-row__title">按钮列表 ({{ form.items.length }})</strong>
</div>
<n-button type="primary" size="small" @click="addItem">
<template #icon><i class="fas fa-plus"></i></template>
<template #icon><i class="fa fas fa-plus"></i></template>
添加按钮
</n-button>
</div>
@@ -87,7 +87,7 @@
<div class="float-btn-sort__item">
<div class="float-btn-sort__main">
<button type="button" class="float-btn-sort__handle" aria-label="拖拽排序">
<i class="fas fa-grip-vertical"></i>
<i class="fa fas fa-bars"></i>
</button>
<span class="float-btn-sort__icon">
<i v-if="element.icon" :class="element.icon"></i>
@@ -107,11 +107,11 @@
</div>
<div class="float-btn-sort__actions">
<n-button size="tiny" quaternary type="primary" @click="editItem(index)">
<template #icon><i class="fas fa-edit" style="font-size:12px;" /></template>
<template #icon><i class="fa fas fa-edit" style="font-size:12px;" /></template>
编辑
</n-button>
<n-button size="tiny" quaternary type="error" @click="deleteItem(index)">
<template #icon><i class="fas fa-trash-alt" style="font-size:12px;" /></template>
<template #icon><i class="fa fas fa-trash-alt" style="font-size:12px;" /></template>
删除
</n-button>
</div>
@@ -140,12 +140,12 @@
<n-select v-model:value="editingItem.type" :options="typeOptions" placeholder="选择按钮类型" @update:value="handleTypeChange" />
</n-form-item-gi>
<n-form-item-gi v-if="editingItem.type !== 'theme_mode'" label="主图标 (Font Awesome)">
<n-input v-model:value="editingItem.icon" placeholder="例如: fas fa-home" />
<n-input v-model:value="editingItem.icon" placeholder="例如: fa fas fa-home" />
</n-form-item-gi>
<n-form-item-gi v-else label="主题图标">
<div class="theme-icon-preview">
<span><i class="fas fa-sun"></i> 亮色固定显示太阳</span>
<span><i class="fas fa-moon"></i> 暗色固定显示月亮</span>
<span><i class="fa fas fa-sun"></i> 亮色固定显示太阳</span>
<span><i class="fa fas fa-moon"></i> 暗色固定显示月亮</span>
</div>
</n-form-item-gi>
</n-grid>
@@ -153,12 +153,12 @@
<div class="icon-preview-row">
<span>预览:</span>
<template v-if="editingItem.type === 'theme_mode'">
<span class="theme-icon-preview-inline"><i class="fas fa-sun"></i> / <i class="fas fa-moon"></i></span>
<span class="theme-icon-preview-inline"><i class="fa fas fa-sun"></i> / <i class="fa fas fa-moon"></i></span>
</template>
<i v-else-if="editingItem.icon" :class="editingItem.icon" style="font-size: 18px;"></i>
<span v-else class="muted-text">未设置图标</span>
<a href="https://fontawesome.com/search?m=free" target="_blank" rel="noopener">
<i class="fas fa-external-link-alt"></i>
<i class="fa fas fa-external-link-alt"></i>
Font Awesome
</a>
</div>
@@ -229,12 +229,12 @@
<div class="add-items-editor__head-actions">
<n-dropdown trigger="click" :options="addPresetOptions" @select="applyAddPreset">
<n-button size="small">
<template #icon><i class="fas fa-magic" /></template>
<template #icon><i class="fa fas fa-magic" /></template>
一键预设
</n-button>
</n-dropdown>
<n-button size="small" type="primary" @click="appendAddItem">
<template #icon><i class="fas fa-plus" /></template>
<template #icon><i class="fa fas fa-plus" /></template>
添加子项
</n-button>
</div>
@@ -251,13 +251,13 @@
<template #item="{ element, index: subIndex }">
<div class="add-items-editor__row">
<button type="button" class="add-items-editor__drag" aria-label="拖拽排序">
<i class="fas fa-grip-vertical"></i>
<i class="fa fas fa-bars"></i>
</button>
<n-input v-model:value="element.label" placeholder="名称,例如: 写文章" />
<n-input v-model:value="element.icon" placeholder="图标,例如: fas fa-pen" />
<n-input v-model:value="element.icon" placeholder="图标,例如: fa fas fa-pen" />
<n-input v-model:value="element.url" placeholder="链接,例如: /submit" />
<n-button quaternary type="error" @click="removeAddItem(subIndex)">
<template #icon><i class="fas fa-trash-alt" /></template>
<template #icon><i class="fa fas fa-trash-alt" /></template>
</n-button>
</div>
</template>
@@ -270,7 +270,7 @@
<div class="add-items-preview__panel add-items-preview__panel--light">
<div class="add-items-preview__mode">亮色</div>
<div class="add-items-preview__trigger">
<i :class="editingItem.icon || 'fas fa-plus'"></i>
<i :class="editingItem.icon || 'fa fas fa-plus'"></i>
</div>
<div class="add-items-preview__menu">
<div v-if="editingItem.add_items.length" class="add-items-preview__list">
@@ -280,7 +280,7 @@
href="javascript:void(0)"
class="add-items-preview__item"
>
<i :class="subItem.icon || 'fas fa-pen'"></i>
<i :class="subItem.icon || 'fa fas fa-pen'"></i>
<span>{{ subItem.label || '未命名子项' }}</span>
</a>
</div>
@@ -290,7 +290,7 @@
<div class="add-items-preview__panel add-items-preview__panel--dark">
<div class="add-items-preview__mode">暗色</div>
<div class="add-items-preview__trigger add-items-preview__trigger--dark">
<i :class="editingItem.icon || 'fas fa-plus'"></i>
<i :class="editingItem.icon || 'fa fas fa-plus'"></i>
</div>
<div class="add-items-preview__menu add-items-preview__menu--dark">
<div v-if="editingItem.add_items.length" class="add-items-preview__list">
@@ -300,7 +300,7 @@
href="javascript:void(0)"
class="add-items-preview__item add-items-preview__item--dark"
>
<i :class="subItem.icon || 'fas fa-pen'"></i>
<i :class="subItem.icon || 'fa fas fa-pen'"></i>
<span>{{ subItem.label || '未命名子项' }}</span>
</a>
</div>
@@ -410,7 +410,7 @@ function createDefaultItem() {
return {
id: '',
type: 'custom',
icon: 'fas fa-link',
icon: 'fa fas fa-link',
icon_dark: '',
icon_light: '',
text: '',
@@ -435,14 +435,14 @@ function createDefaultItem() {
function applyTypeDefaults(type) {
const map = {
custom: { icon: 'fas fa-link', icon_dark: '', icon_light: '', text: '链接', desc: '', link: '', hover: '', action_mode: 'link', qr_size: 120 },
back_top: { icon: 'fas fa-chevron-up', icon_dark: '', icon_light: '', text: '顶部', desc: '返回顶部', link: '', hover: '', action_mode: 'link', qr_size: 120 },
theme_mode: { icon: 'fas fa-sun', icon_dark: '', icon_light: '', text: '主题', desc: '切换主题', link: '', hover: '', action_mode: 'link', qr_size: 120 },
qrcode: { icon: 'fas fa-qrcode', icon_dark: '', icon_light: '', text: '二维码', desc: '扫码继续浏览', link: '', hover: '', action_mode: 'qrcode', qr_size: 120 },
service_qq: { icon: 'fab fa-qq', icon_dark: '', icon_light: '', text: 'QQ', desc: 'QQ 联系', link: '', hover: '', action_mode: 'link', qr_size: 120 },
service_wechat: { icon: 'fab fa-weixin', icon_dark: '', icon_light: '', text: '微信', desc: '扫码添加微信', link: '', hover: '', action_mode: 'link', qr_size: 120 },
pay_vip: { icon: 'fas fa-gem', icon_dark: '', icon_light: '', text: '会员', desc: '开通/升级会员弹窗', link: '', hover: '', action_mode: 'link', qr_size: 120 },
add: { icon: 'fas fa-plus', icon_dark: '', icon_light: '', text: '发布', desc: '发布内容', link: '', hover: '', action_mode: 'link', qr_size: 120 },
custom: { icon: 'fa fas fa-link', icon_dark: '', icon_light: '', text: '链接', desc: '', link: '', hover: '', action_mode: 'link', qr_size: 120 },
back_top: { icon: 'fa fas fa-chevron-up', icon_dark: '', icon_light: '', text: '顶部', desc: '返回顶部', link: '', hover: '', action_mode: 'link', qr_size: 120 },
theme_mode: { icon: 'fa fas fa-sun', icon_dark: '', icon_light: '', text: '主题', desc: '切换主题', link: '', hover: '', action_mode: 'link', qr_size: 120 },
qrcode: { icon: 'fa fas fa-qrcode', icon_dark: '', icon_light: '', text: '二维码', desc: '扫码继续浏览', link: '', hover: '', action_mode: 'qrcode', qr_size: 120 },
service_qq: { icon: 'fa fab fa-qq', icon_dark: '', icon_light: '', text: 'QQ', desc: 'QQ 联系', link: '', hover: '', action_mode: 'link', qr_size: 120 },
service_wechat: { icon: 'fa fab fa-weixin', icon_dark: '', icon_light: '', text: '微信', desc: '扫码添加微信', link: '', hover: '', action_mode: 'link', qr_size: 120 },
pay_vip: { icon: 'fa fas fa-gem', icon_dark: '', icon_light: '', text: '会员', desc: '开通/升级会员弹窗', link: '', hover: '', action_mode: 'link', qr_size: 120 },
add: { icon: 'fa fas fa-plus', icon_dark: '', icon_light: '', text: '发布', desc: '发布内容', link: '', hover: '', action_mode: 'link', qr_size: 120 },
}
return map[type] || map.custom
}
@@ -465,8 +465,8 @@ function handleTypeChange(type) {
if (type === 'pay_vip') {
editingItem.link = ''
editingItem.hover = ''
if (!editingItem.icon || editingItem.icon.includes('fa-diamond')) {
editingItem.icon = 'fas fa-gem'
if (!editingItem.icon || editingItem.icon.includes('fa-gem')) {
editingItem.icon = 'fa fas fa-gem'
}
}
}
@@ -484,7 +484,7 @@ function appendAddItem() {
editingItem.add_items.push({
id: `add_${Date.now()}_${editingItem.add_items.length}`,
label: '',
icon: 'fas fa-pen',
icon: 'fa fas fa-pen',
url: '',
})
}
@@ -503,9 +503,9 @@ function applyAddPreset(key) {
}
const presetFactories = {
post: () => ({ label: '写文章', icon: 'fas fa-pen-nib', url: `${siteUrl}/submit/` }),
submit: () => ({ label: '投稿页', icon: 'fas fa-paper-plane', url: `${siteUrl}/submit/` }),
profile: () => ({ label: '创作中心', icon: 'fas fa-user-edit', url: `${siteUrl}/user/` }),
post: () => ({ label: '写文章', icon: 'fa fas fa-pen', url: `${siteUrl}/submit/` }),
submit: () => ({ label: '投稿页', icon: 'fa fas fa-paper-plane', url: `${siteUrl}/submit/` }),
profile: () => ({ label: '创作中心', icon: 'fa fas fa-user', url: `${siteUrl}/user/` }),
}
const factory = presetFactories[key]
@@ -531,9 +531,9 @@ function isAddPresetExists(key) {
function getAddPresetValue(key) {
const presetFactories = {
post: () => ({ label: '写文章', icon: 'fas fa-pen-nib', url: `${siteUrl}/submit/` }),
submit: () => ({ label: '投稿页', icon: 'fas fa-paper-plane', url: `${siteUrl}/submit/` }),
profile: () => ({ label: '创作中心', icon: 'fas fa-user-edit', url: `${siteUrl}/user/` }),
post: () => ({ label: '写文章', icon: 'fa fas fa-pen', url: `${siteUrl}/submit/` }),
submit: () => ({ label: '投稿页', icon: 'fa fas fa-paper-plane', url: `${siteUrl}/submit/` }),
profile: () => ({ label: '创作中心', icon: 'fa fas fa-user', url: `${siteUrl}/user/` }),
}
return presetFactories[key] ? presetFactories[key]() : null
@@ -602,7 +602,7 @@ function saveItem() {
const item = {
id: editingItem.id || `float_${Date.now()}`,
type: editingItem.type,
icon: editingItem.type === 'theme_mode' ? 'fas fa-sun' : (editingItem.type === 'pay_vip' ? (editingItem.icon || 'fas fa-gem') : editingItem.icon),
icon: editingItem.type === 'theme_mode' ? 'fa fas fa-sun' : (editingItem.type === 'pay_vip' ? (editingItem.icon || 'fa fas fa-gem') : editingItem.icon),
icon_dark: '',
icon_light: '',
text: editingItem.text,
@@ -618,7 +618,7 @@ function saveItem() {
add_items: editingItem.type === 'add' ? editingItem.add_items.filter(subItem => subItem.label || subItem.url).map((subItem, idx) => ({
id: subItem.id || `add_${idx}`,
label: subItem.label || '',
icon: subItem.icon || 'fas fa-pen',
icon: subItem.icon || 'fa fas fa-pen',
url: subItem.url || '',
})) : [],
hover: editingItem.type === 'pay_vip' ? '' : (supportsHover.value ? (editingItem.hover || '') : ''),
@@ -672,7 +672,7 @@ async function loadSettings() {
form.items = (data.items || []).map((item, index) => ({
...createDefaultItem(),
...item,
icon: item.type === 'theme_mode' ? 'fas fa-sun' : (item.icon || ''),
icon: item.type === 'theme_mode' ? 'fa fas fa-sun' : (item.icon || ''),
color: item.color || null,
bg: item.bg || null,
icon_dark: '',
@@ -705,7 +705,7 @@ async function handleSave() {
filter_blur: form.filter_blur,
items: form.items.map((item, index) => ({
...item,
icon: item.type === 'theme_mode' ? 'fas fa-sun' : (item.icon || ''),
icon: item.type === 'theme_mode' ? 'fa fas fa-sun' : (item.icon || ''),
icon_dark: '',
icon_light: '',
color: item.color || '',
@@ -409,7 +409,7 @@
<n-input v-model:value="editingContactMore.desc" placeholder="如:微信公众号" />
</n-form-item>
<n-form-item label="图标类名">
<n-input v-model:value="editingContactMore.icon" placeholder="如:fab fa-weixin" />
<n-input v-model:value="editingContactMore.icon" placeholder="如:fa fab fa-weixin" />
</n-form-item>
<n-form-item label="链接地址">
<n-input v-model:value="editingContactMore.link" placeholder="https://..." />
@@ -12,7 +12,7 @@
<template #header>
<div class="aksrt-card-header-row">
<div class="aksrt-card-header-row__left">
<span class="header-icon"><i class="fas fa-cog"></i></span>
<span class="header-icon"><i class="fa fas fa-cog"></i></span>
<strong class="aksrt-card-header-row__title">基础设置</strong>
</div>
</div>
@@ -46,11 +46,11 @@
<template #header>
<div class="aksrt-card-header-row">
<div class="aksrt-card-header-row__left">
<span class="header-icon"><i class="fas fa-list-ul"></i></span>
<span class="header-icon"><i class="fa fas fa-list-ul"></i></span>
<strong class="aksrt-card-header-row__title">Tab按钮配置 ({{ form.items.length }})</strong>
</div>
<n-button type="primary" size="small" @click="addItem">
<template #icon><i class="fas fa-plus"></i></template>
<template #icon><i class="fa fas fa-plus"></i></template>
添加按钮
</n-button>
</div>
@@ -72,7 +72,7 @@
<div class="tabbar-sort__item">
<div class="tabbar-sort__main">
<button type="button" class="tabbar-sort__handle" aria-label="拖拽排序">
<i class="fas fa-grip-vertical"></i>
<i class="fa fas fa-bars"></i>
</button>
<span class="tabbar-sort__icon">
<i v-if="element.icon" :class="element.icon"></i>
@@ -90,11 +90,11 @@
</div>
<div class="tabbar-sort__actions">
<n-button size="tiny" quaternary type="primary" @click="editItem(index)">
<template #icon><i class="fas fa-edit" style="font-size:12px;" /></template>
<template #icon><i class="fa fas fa-edit" style="font-size:12px;" /></template>
编辑
</n-button>
<n-button size="tiny" quaternary type="error" @click="deleteItem(index)">
<template #icon><i class="fas fa-trash-alt" style="font-size:12px;" /></template>
<template #icon><i class="fa fas fa-trash-alt" style="font-size:12px;" /></template>
删除
</n-button>
</div>
@@ -129,14 +129,14 @@
</n-form-item>
<n-form-item label="图标 (Font Awesome)">
<n-input v-model:value="editingItem.icon" placeholder="例如: fas fa-home" />
<n-input v-model:value="editingItem.icon" placeholder="例如: fa fas fa-home" />
<template #feedback>
<div class="icon-preview-row">
<span>预览:</span>
<i v-if="editingItem.icon" :class="editingItem.icon" style="font-size: 20px;"></i>
<span v-else class="muted-text">无图标</span>
<a href="https://fontawesome.com/search?m=free" target="_blank" rel="noopener" style="margin-left: 12px;">
<i class="fas fa-external-link-alt"></i> Font Awesome 图标库
<i class="fa fas fa-external-link-alt"></i> Font Awesome 图标库
</a>
</div>
</template>
@@ -198,7 +198,7 @@
<div class="add-items-editor__head">
<strong>发布菜单项</strong>
<n-button size="small" type="primary" @click="appendAddItem">
<template #icon><i class="fas fa-plus" /></template>
<template #icon><i class="fa fas fa-plus" /></template>
添加子项
</n-button>
</div>
@@ -227,13 +227,13 @@
<template #item="{ element, index: subIndex }">
<div class="add-items-editor__row">
<button type="button" class="add-items-editor__drag" aria-label="拖拽排序">
<i class="fas fa-grip-vertical"></i>
<i class="fa fas fa-bars"></i>
</button>
<n-input v-model:value="element.label" placeholder="名称,例如:写文章" />
<n-input v-model:value="element.icon" placeholder="图标,例如:fas fa-pen" />
<n-input v-model:value="element.icon" placeholder="图标,例如:fa fas fa-pen" />
<n-input v-model:value="element.url" placeholder="链接,例如:/wp-admin/post-new.php" />
<n-button quaternary type="error" @click="removeAddItem(subIndex)">
<template #icon><i class="fas fa-trash-alt" /></template>
<template #icon><i class="fa fas fa-trash-alt" /></template>
</n-button>
</div>
</template>
@@ -327,15 +327,15 @@ const typeLabelMap = {
}
const typeDefaults = {
home: { icon: 'fas fa-home', text: '首页' },
category: { icon: 'fas fa-th-large', text: '分类' },
link: { icon: 'fas fa-link', text: '链接' },
add: { icon: 'fas fa-plus', text: '发布' },
user: { icon: 'fas fa-user', text: '用户中心' },
auth: { icon: 'fas fa-user', text: '我的' },
search: { icon: 'fas fa-search', text: '搜索' },
msg: { icon: 'fas fa-bell', text: '消息' },
pay_vip: { icon: 'fas fa-crown', text: '会员' },
home: { icon: 'fa fas fa-home', text: '首页' },
category: { icon: 'fa fas fa-th-large', text: '分类' },
link: { icon: 'fa fas fa-link', text: '链接' },
add: { icon: 'fa fas fa-plus', text: '发布' },
user: { icon: 'fa fas fa-user', text: '用户中心' },
auth: { icon: 'fa fas fa-user', text: '我的' },
search: { icon: 'fa fas fa-search', text: '搜索' },
msg: { icon: 'fa fas fa-bell', text: '消息' },
pay_vip: { icon: 'fa fas fa-gem', text: '会员' },
}
const enabledPreviewItems = computed(() => form.items.filter((item) => item.enabled))
@@ -361,10 +361,10 @@ function getItemSummary(item) {
}
const addPresets = [
{ label: '写文章', icon: 'fas fa-pen-fancy', url: '/submit' },
{ label: '投稿页', icon: 'fas fa-file-alt', url: '/submit' },
{ label: '发布资源', icon: 'fas fa-cloud-upload-alt', url: '/resource-new' },
{ label: '创作中心', icon: 'fas fa-palette', url: '/creator' },
{ label: '写文章', icon: 'fa fas fa-pen', url: '/submit' },
{ label: '投稿页', icon: 'fa fas fa-file-alt', url: '/submit' },
{ label: '发布资源', icon: 'fa fas fa-cloud-upload-alt', url: '/resource-new' },
{ label: '创作中心', icon: 'fa fas fa-paint-brush', url: '/creator' },
]
function appendAddPreset(preset) {
@@ -381,7 +381,7 @@ function appendAddItem() {
editingItem.add_items.push({
id: `add_${Date.now()}_${editingItem.add_items.length}`,
label: '',
icon: 'fas fa-pen',
icon: 'fa fas fa-pen',
url: '',
})
}
@@ -421,7 +421,7 @@ function addItem() {
Object.assign(editingItem, {
id: `tab_${Date.now()}`,
type: 'link',
icon: 'fas fa-link',
icon: 'fa fas fa-link',
text: '链接',
link: '',
badge: '',
@@ -489,7 +489,7 @@ function saveItem() {
? editingItem.add_items.filter((sub) => sub.label && sub.url).map((sub) => ({
id: sub.id || `add_${Date.now()}`,
label: sub.label,
icon: sub.icon || 'fas fa-pen',
icon: sub.icon || 'fa fas fa-pen',
url: sub.url,
}))
: [],
@@ -1,518 +0,0 @@
<template>
<div class="aksrt-page-container content-page">
<PageHeader title="Hero 轮播管理" desc="管理首页 Hero 幻灯片内容(图片/视频、文案、图层、跳转)。标题、副标题可留空。" />
<n-card class="aksrt-section-card" style="margin-bottom:16px;">
<template #header>
<div class="aksrt-card-header-row">
<strong>显示范围</strong>
<n-button size="small" secondary @click="goHeaderComponents">顶部多功能组件(页面类型/搜索/卡片)</n-button>
</div>
</template>
<p class="aksrt-inline-setting__hint" style="margin:0;">
幻灯片内容在此维护。页面类型启用、设备规则、搜索覆盖层与图标卡片请到「顶部多功能组件」配置;全不选页面类型即为关闭。
</p>
</n-card>
<n-spin :show="loading" style="width:100%; min-height:200px;">
<n-card class="aksrt-section-card">
<template #header>
<div class="aksrt-card-header-row">
<div class="aksrt-card-header-row__left">
<span class="header-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:18px;height:18px" aria-hidden="true">
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"/>
<circle cx="9" cy="9" r="2"/>
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>
</svg>
</span>
<strong class="aksrt-card-header-row__title">Hero 列表 ({{ slides.length }})</strong>
</div>
<n-button type="primary" size="small" @click="openCreate">+ 添加 Hero</n-button>
</div>
</template>
<n-data-table
v-if="slides.length"
:columns="columns"
:data="slides"
:row-key="(row) => row.id"
:bordered="false"
size="small"
/>
<n-empty v-else description="暂无 Hero,添加后首页即可使用。" />
</n-card>
</n-spin>
<!-- 编辑/新增 弹窗 -->
<n-modal
v-model:show="modalShow"
:mask-closable="false"
preset="card"
:title="editing.id ? '编辑 Hero' : '添加 Hero'"
class="aksrt-modal-card"
>
<n-form :model="editing" label-placement="top" class="aksrt-form">
<n-form-item label="标题">
<n-input v-model:value="editing.title" placeholder="可选,主标题" />
</n-form-item>
<n-form-item label="副标题">
<n-input v-model:value="editing.subtitle" placeholder="可选,副标题" />
</n-form-item>
<n-form-item label="背景图 URL">
<n-input-group>
<n-input v-model:value="editing.image_url" placeholder="https://..." />
<n-button secondary @click="pickImage">媒体库</n-button>
</n-input-group>
</n-form-item>
<div v-if="editing.image_url" class="aksrt-modal-preview">
<n-image :src="editing.image_url" width="100%" height="160" object-fit="cover" :preview-src="editing.image_url" />
</div>
<n-form-item label="跳转链接">
<n-input v-model:value="editing.link_url" placeholder="点击后跳转地址,可留空" />
</n-form-item>
<n-form-item label="描述文字">
<n-input v-model:value="editing.description" type="textarea" :rows="2" placeholder="可选,显示在副标题下方" />
</n-form-item>
<n-form-item label="视频背景 URL">
<n-input v-model:value="editing.video_url" placeholder="可选,MP4 视频地址替代背景图" />
</n-form-item>
<div class="aksrt-modal-grid">
<n-form-item label="链接打开方式">
<n-radio-group v-model:value="editing.link_target">
<n-radio-button value="_self">当前窗口</n-radio-button>
<n-radio-button value="_blank">新窗口</n-radio-button>
</n-radio-group>
</n-form-item>
<n-form-item label="文字对齐">
<n-radio-group v-model:value="editing.text_align">
<n-radio-button value="left">左</n-radio-button>
<n-radio-button value="center">居中</n-radio-button>
<n-radio-button value="right">右</n-radio-button>
</n-radio-group>
</n-form-item>
<n-form-item label="设备可见性">
<n-radio-group v-model:value="editing.device_visibility">
<n-radio-button value="all">全部</n-radio-button>
<n-radio-button value="pc">仅电脑</n-radio-button>
<n-radio-button value="mobile">仅移动</n-radio-button>
</n-radio-group>
</n-form-item>
<n-form-item label="文字视差">
<n-switch v-model:value="editing.text_parallax" />
</n-form-item>
<n-form-item label="文字大小(PC)">
<n-input v-model:value="editing.text_size_pc" placeholder="如 48px,留空默认" />
</n-form-item>
<n-form-item label="文字大小(移动)">
<n-input v-model:value="editing.text_size_m" placeholder="如 28px,留空默认" />
</n-form-item>
</div>
<div class="aksrt-modal-grid">
<n-form-item label="显示文字">
<n-switch v-model:value="editing.show_text" />
</n-form-item>
<n-form-item label="排序">
<n-input-number v-model:value="editing.sort_order" :min="0" style="width:100%;" />
</n-form-item>
<n-form-item label="启用">
<n-switch v-model:value="editing.enabled" />
</n-form-item>
<n-form-item label="显示元信息">
<n-switch v-model:value="editing.show_meta" />
</n-form-item>
</div>
<!-- 图片图层 -->
<n-divider title-placement="left" style="margin:16px 0 12px;">
图片图层(视差叠加)
</n-divider>
<div v-for="(layer, idx) in editing.layers" :key="idx" class="aksrt-layer-item">
<div class="aksrt-layer-item__header">
<strong>图层 {{ idx + 1 }}</strong>
<n-button size="tiny" type="error" quaternary @click="removeLayer(idx)">删除</n-button>
</div>
<n-form-item label="图片">
<n-input-group>
<n-input v-model:value="layer.image" placeholder="图片 URL" />
<n-button secondary @click="pickLayerImage(idx)">媒体库</n-button>
</n-input-group>
</n-form-item>
<div class="aksrt-modal-grid">
<n-form-item label="原始尺寸">
<n-switch v-model:value="layer.free_size" />
</n-form-item>
<n-form-item label="对齐方式">
<n-select v-model:value="layer.align" :options="[
{ label: '居中', value: 'center' },
{ label: '左上', value: 'left top' },
{ label: '右上', value: 'right top' },
{ label: '左下', value: 'left bottom' },
{ label: '右下', value: 'right bottom' },
]" />
</n-form-item>
<n-form-item label="视差">
<n-switch v-model:value="layer.parallax" />
</n-form-item>
<n-form-item label="视差强度" v-if="layer.parallax">
<n-slider v-model:value="layer.parallax_scale" :min="0" :max="1" :step="0.05" />
</n-form-item>
<n-form-item label="视差透明度" v-if="layer.parallax">
<n-slider v-model:value="layer.parallax_opacity" :min="0" :max="1" :step="0.05" />
</n-form-item>
</div>
</div>
<n-button size="small" dashed block @click="addLayer" style="margin-top:8px;">+ 添加图层</n-button>
</n-form>
<template #footer>
<div class="aksrt-modal-footer">
<n-button @click="modalShow = false">取消</n-button>
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
</div>
</template>
</n-modal>
</div>
</template>
<script setup>
import { h, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { NButton, NImage, NTag, useDialog, useMessage } from 'naive-ui'
import api from '@/api'
import { openMediaPicker } from '@/utils/media'
import PageHeader from '@/components/PageHeader.vue'
const router = useRouter()
const message = useMessage()
const dialog = useDialog()
function goHeaderComponents() {
router.push('/page-display/header-components')
}
const loading = ref(true)
const saving = ref(false)
const slides = ref([])
const modalShow = ref(false)
const editing = ref(emptyForm())
function emptyForm() {
return {
id: 0,
title: '',
subtitle: '',
description: '',
image_url: '',
video_url: '',
link_url: '',
link_target: '_self',
text_align: 'left',
device_visibility: 'all',
enabled: true,
show_text: true,
show_meta: false,
sort_order: 0,
text_size_pc: '',
text_size_m: '',
text_parallax: false,
layers: [],
}
}
const columns = [
{
title: '预览',
key: 'image_url',
width: 90,
render(row) {
if (!row.image_url) {
return h('span', { style: 'color:#bbb;font-size:12px;' }, '无')
}
return h(NImage, {
src: row.image_url,
width: 64,
height: 36,
objectFit: 'cover',
previewSrc: row.image_url,
style: 'border-radius:4px;display:block;',
})
},
},
{
title: '标题',
key: 'title',
ellipsis: { tooltip: true },
render(row) {
return row.title || h('span', { style: 'color:#bbb;' }, '未命名')
},
},
{
title: '文字',
key: 'show_text',
width: 70,
className: 'aksrt-table-mobile-hide',
render(row) {
return h(NTag, { size: 'small', type: row.show_text ? 'info' : 'default' }, {
default: () => (row.show_text ? '显示' : '隐藏'),
})
},
},
{
title: '元信息',
key: 'show_meta',
width: 78,
className: 'aksrt-table-mobile-hide',
render(row) {
return h(NTag, { size: 'small', type: row.show_meta ? 'info' : 'default' }, {
default: () => (row.show_meta ? '显示' : '隐藏'),
})
},
},
{
title: '跳转',
key: 'link_url',
ellipsis: { tooltip: true },
className: 'aksrt-table-mobile-hide',
render(row) {
return row.link_url || h('span', { style: 'color:#bbb;font-size:12px;' }, '—')
},
},
{
title: '排序',
key: 'sort_order',
width: 64,
className: 'aksrt-table-mobile-hide',
},
{
title: '状态',
key: 'enabled',
width: 84,
render(row) {
return h(NTag, { size: 'small', type: row.enabled ? 'success' : 'default' }, {
default: () => (row.enabled ? '启用' : '禁用'),
})
},
},
{
title: '操作',
key: 'actions',
width: 130,
render(row) {
return h('div', { style: 'display:flex;gap:6px;' }, [
h(NButton, { size: 'tiny', onClick: () => openEdit(row) }, { default: () => '编辑' }),
h(NButton, { size: 'tiny', type: 'error', quaternary: true, onClick: () => handleDelete(row) }, { default: () => '删除' }),
])
},
},
]
async function loadSlides() {
try {
loading.value = true
const res = await api.getHeroes()
if (res.code === 'success') {
slides.value = res.data || []
}
} catch (e) {
message.error(e.message || '加载失败')
} finally {
loading.value = false
}
}
function openCreate() {
editing.value = emptyForm()
modalShow.value = true
}
function openEdit(row) {
editing.value = {
id: row.id,
title: row.title || '',
subtitle: row.subtitle || '',
description: row.description || '',
image_url: row.image_url || '',
video_url: row.video_url || '',
link_url: row.link_url || '',
link_target: row.link_target || '_self',
text_align: row.text_align || 'left',
device_visibility: row.device_visibility || 'all',
show_text: row.show_text !== false,
enabled: !!row.enabled,
show_meta: row.show_meta === true,
sort_order: Number(row.sort_order) || 0,
text_size_pc: row.text_size_pc || '',
text_size_m: row.text_size_m || '',
text_parallax: !!row.text_parallax,
layers: Array.isArray(row.layers) ? row.layers : [],
}
modalShow.value = true
}
async function pickImage() {
try {
const media = await openMediaPicker({
title: '选择 Hero 背景图',
buttonText: '使用这张 Hero 图',
})
if (media?.url) {
editing.value.image_url = media.url
}
} catch (e) {
message.error(e.message || '打开媒体库失败')
}
}
function addLayer() {
editing.value.layers.push({
image: '',
free_size: false,
align: 'center',
parallax: false,
parallax_scale: 0.3,
parallax_opacity: 0.6,
})
}
function removeLayer(idx) {
editing.value.layers.splice(idx, 1)
}
async function pickLayerImage(idx) {
try {
const media = await openMediaPicker({
title: '选择图层图片',
buttonText: '使用这张图',
})
if (media?.url) {
editing.value.layers[idx].image = media.url
}
} catch (e) {
message.error(e.message || '打开媒体库失败')
}
}
async function handleSave() {
if (!editing.value.image_url) {
message.warning('请填写 Hero 背景图')
return
}
saving.value = true
try {
if (editing.value.id) {
await api.updateHero(editing.value.id, editing.value)
message.success('已保存')
} else {
await api.createHero(editing.value)
message.success('已添加')
}
modalShow.value = false
await loadSlides()
} catch (e) {
message.error(e.message || '保存失败')
} finally {
saving.value = false
}
}
function handleDelete(row) {
dialog.warning({
title: '确认删除',
content: `确定删除 Hero「${row.title || '未命名'}」?`,
positiveText: '删除',
negativeText: '取消',
onPositiveClick: async () => {
try {
await api.deleteHero(row.id)
message.success('已删除')
await loadSlides()
} catch (e) {
message.error(e.message || '删除失败')
}
},
})
}
onMounted(() => {
loadSlides()
})
</script>
<style scoped>
.aksrt-inline-setting {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.aksrt-inline-setting__hint {
color: #7a7f8a;
font-size: 13px;
}
.aksrt-inline-setting__actions {
display: flex;
justify-content: flex-end;
}
.aksrt-modal-preview {
margin: -8px 0 18px;
border-radius: 8px;
overflow: hidden;
border: 1px solid #eef1f6;
}
.aksrt-modal-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.aksrt-layer-item {
border: 1px solid #eef1f6;
border-radius: 8px;
padding: 14px;
margin-bottom: 10px;
background: #fafbfc;
}
.aksrt-layer-item__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.aksrt-modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
@media (max-width: 768px) {
.aksrt-modal-grid {
grid-template-columns: 1fr;
}
}
</style>
@@ -164,13 +164,12 @@
<template #header><strong>固定骨架说明</strong></template>
<n-space vertical>
<n-alert type="warning" :show-icon="false">
Hero 与 Banner 已作为固定首页骨架的一部分维护,不再由旧版首页模块编排驱动。
顶部多功能组件与 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')">
顶部多功能组件
+11 -11
View File
@@ -7,7 +7,7 @@
<n-grid :cols="2" :x-gap="12" :y-gap="12">
<n-grid-item>
<div class="aksrt-docs__action">
<FaIcon icon="fas fa-palette" :size="16" />
<FaIcon icon="fa fas fa-paint-brush" :size="16" />
<div>
<strong>全局设置</strong>
<p>Logo、背景、菜单装饰、自定义代码</p>
@@ -17,7 +17,7 @@
</n-grid-item>
<n-grid-item>
<div class="aksrt-docs__action">
<FaIcon icon="fas fa-home" :size="16" />
<FaIcon icon="fa fas fa-home" :size="16" />
<div>
<strong>首页配置</strong>
<p>首页模块、布局、排序和预设模板</p>
@@ -27,7 +27,7 @@
</n-grid-item>
<n-grid-item>
<div class="aksrt-docs__action">
<FaIcon icon="fas fa-users" :size="16" />
<FaIcon icon="fa fas fa-users" :size="16" />
<div>
<strong>用户管理</strong>
<p>登录注册、OAuth、签到、积分</p>
@@ -37,7 +37,7 @@
</n-grid-item>
<n-grid-item>
<div class="aksrt-docs__action">
<FaIcon icon="fas fa-tools" :size="16" />
<FaIcon icon="fa fas fa-wrench" :size="16" />
<div>
<strong>系统工具</strong>
<p>导入导出、健康检查、迁移状态</p>
@@ -66,7 +66,7 @@
<h4 class="aksrt-docs__card-title">{{ doc.title }}</h4>
<p class="aksrt-docs__card-desc">{{ doc.description }}</p>
</div>
<FaIcon icon="fas fa-external-link-alt" :size="12" class="aksrt-docs__card-arrow" />
<FaIcon icon="fa fas fa-external-link-alt" :size="12" class="aksrt-docs__card-arrow" />
</div>
</n-card>
</div>
@@ -95,12 +95,12 @@ const themeVersion = ref(window.aksrtAdminData?.themeVersion || '3.4.0-dev')
const dbSchemaVersion = ref('—')
const docs = ref([
{ key: 'admin-ia-map', title: '后台 IA 蓝图', description: '完整的后台信息架构映射,12 个顶级分区及子页面清单。', icon: 'fas fa-sitemap', color: '#1890ff', file: 'admin-ia-map.md' },
{ key: 'zibll-gap-matrix', title: '对标差异矩阵', description: 'AKSRT 当前 → Zibll 参考 → AKSRT 目标三层对照表。', icon: 'fas fa-columns', color: '#722ed1', file: 'zibll-gap-matrix.md' },
{ key: 'frontend-page-matrix', title: '前端页面矩阵', description: '前端模板、CSS、JS 资产映射与覆盖范围。', icon: 'fas fa-desktop', color: '#13c2c2', file: 'frontend-page-matrix.md' },
{ key: 'manual-acceptance-baseline', title: '验收基线', description: '每个 Phase 的人工验收标准和检查清单。', icon: 'fas fa-clipboard-check', color: '#52c41a', file: 'manual-acceptance-baseline.md' },
{ key: 'feature-domain-map', title: '功能域地图', description: '业务域划分、依赖关系和模块边界说明。', icon: 'fas fa-map', color: '#fa8c16', file: 'feature-domain-map.md' },
{ key: 'migration-map', title: '迁移地图', description: '设置 key 迁移、旧选项兼容和 Schema 版本对照。', icon: 'fas fa-exchange-alt', color: '#eb2f96', file: 'migration-map.md' },
{ key: 'admin-ia-map', title: '后台 IA 蓝图', description: '完整的后台信息架构映射,12 个顶级分区及子页面清单。', icon: 'fa fas fa-sitemap', color: '#1890ff', file: 'admin-ia-map.md' },
{ key: 'zibll-gap-matrix', title: '对标差异矩阵', description: 'AKSRT 当前 → Zibll 参考 → AKSRT 目标三层对照表。', icon: 'fa fas fa-columns', color: '#722ed1', file: 'zibll-gap-matrix.md' },
{ key: 'frontend-page-matrix', title: '前端页面矩阵', description: '前端模板、CSS、JS 资产映射与覆盖范围。', icon: 'fa fas fa-desktop', color: '#13c2c2', file: 'frontend-page-matrix.md' },
{ key: 'manual-acceptance-baseline', title: '验收基线', description: '每个 Phase 的人工验收标准和检查清单。', icon: 'fa fas fa-clipboard', color: '#52c41a', file: 'manual-acceptance-baseline.md' },
{ key: 'feature-domain-map', title: '功能域地图', description: '业务域划分、依赖关系和模块边界说明。', icon: 'fa fas fa-map', color: '#fa8c16', file: 'feature-domain-map.md' },
{ key: 'migration-map', title: '迁移地图', description: '设置 key 迁移、旧选项兼容和 Schema 版本对照。', icon: 'fa fas fa-exchange-alt', color: '#eb2f96', file: 'migration-map.md' },
])
onMounted(async () => {
@@ -9,7 +9,7 @@
<div class="aksrt-ai__status">
<div class="aksrt-ai__status-card">
<div class="aksrt-ai__status-icon" :class="status.available ? 'aksrt-ai__status-icon--ok' : 'aksrt-ai__status-icon--off'">
<i class="fas fa-robot"></i>
<i class="fa fab fa-android"></i>
</div>
<div class="aksrt-ai__status-info">
<div class="aksrt-ai__status-label">可用状态</div>
@@ -18,7 +18,7 @@
</div>
<div class="aksrt-ai__status-card">
<div class="aksrt-ai__status-icon" :class="status.wp_ai_available ? 'aksrt-ai__status-icon--ok' : 'aksrt-ai__status-icon--warn'">
<i class="fas fa-plug"></i>
<i class="fa fas fa-plug"></i>
</div>
<div class="aksrt-ai__status-info">
<div class="aksrt-ai__status-label">WP AI Client</div>
@@ -27,7 +27,7 @@
</div>
<div class="aksrt-ai__status-card">
<div class="aksrt-ai__status-icon" :class="status.theme_available ? 'aksrt-ai__status-icon--ok' : 'aksrt-ai__status-icon--warn'">
<i class="fas fa-key"></i>
<i class="fa fas fa-key"></i>
</div>
<div class="aksrt-ai__status-info">
<div class="aksrt-ai__status-label">主题 Provider</div>
@@ -36,7 +36,7 @@
</div>
<div class="aksrt-ai__status-card">
<div class="aksrt-ai__status-icon aksrt-ai__status-icon--info">
<i class="fas fa-route"></i>
<i class="fa fas fa-road"></i>
</div>
<div class="aksrt-ai__status-info">
<div class="aksrt-ai__status-label">当前后端</div>
@@ -115,7 +115,7 @@
</div>
<div class="aksrt-ai__form-card aksrt-ai__notice">
<h3><i class="fas fa-exclamation-triangle"></i> 重要说明</h3>
<h3><i class="fa fas fa-exclamation-triangle"></i> 重要说明</h3>
<ul>
<li>AI 输出仅作为<strong>建议</strong>,不会自动写库;需用户点「更新/提交」才保存</li>
<li>主题 API Key 已配置时优先使用;否则回退 WordPress AI Connectors</li>
@@ -29,7 +29,7 @@
<strong>{{ tool.title }}</strong>
<p>{{ tool.desc }}</p>
</div>
<FaIcon icon="fas fa-chevron-right" :size="12" color="#c0c4cc" />
<FaIcon icon="fa fas fa-chevron-right" :size="12" color="#c0c4cc" />
</div>
</n-grid-item>
</n-grid>
@@ -57,15 +57,15 @@
<n-card title="手动维护" size="small" class="aksrt-tools__section">
<n-space>
<n-button @click="handleFlushCache">
<template #icon><FaIcon icon="fas fa-broom" :size="12" /></template>
<template #icon><FaIcon icon="fa fas fa-magic" :size="12" /></template>
清除缓存
</n-button>
<n-button @click="handleOptimizeDb">
<template #icon><FaIcon icon="fas fa-database" :size="12" /></template>
<template #icon><FaIcon icon="fa fas fa-database" :size="12" /></template>
优化数据表
</n-button>
<n-button @click="handleRebuildIndex">
<template #icon><FaIcon icon="fas fa-sync-alt" :size="12" /></template>
<template #icon><FaIcon icon="fa fas fa-sync-alt" :size="12" /></template>
重建索引
</n-button>
</n-space>
@@ -85,24 +85,24 @@ const router = useRouter()
const message = useMessage()
const healthItems = ref([
{ key: 'php', icon: 'fas fa-code', color: '#1890ff', value: '—', label: 'PHP 版本', status: 'ok' },
{ key: 'wp', icon: 'fab fa-wordpress', color: '#722ed1', value: '—', label: 'WordPress', status: 'ok' },
{ key: 'db', icon: 'fas fa-database', color: '#52c41a', value: '—', label: '数据库', status: 'ok' },
{ key: 'uploads', icon: 'fas fa-folder-open', color: '#fa8c16', value: '—', label: '上传目录', status: 'ok' },
{ key: 'php', icon: 'fa fas fa-code', color: '#1890ff', value: '—', label: 'PHP 版本', status: 'ok' },
{ key: 'wp', icon: 'fa fab fa-wordpress', color: '#722ed1', value: '—', label: 'WordPress', status: 'ok' },
{ key: 'db', icon: 'fa fas fa-database', color: '#52c41a', value: '—', label: '数据库', status: 'ok' },
{ key: 'uploads', icon: 'fa fas fa-folder-open', color: '#fa8c16', value: '—', label: '上传目录', status: 'ok' },
])
const tools = ref([
{ key: 'import-export', icon: 'fas fa-exchange-alt', bg: '#1890ff', title: '导入导出', desc: '设置导入、导出和重置', route: '/tools/import-export' },
{ key: 'health', icon: 'fas fa-heartbeat', bg: '#52c41a', title: '健康检查', desc: '系统状态检测和诊断', route: '/tools/health' },
{ key: 'email-rollback', icon: 'fas fa-undo', bg: '#fa8c16', title: '邮箱回滚', desc: '邮箱变更 14 天内回滚', route: '/tools/email-rollback' },
{ key: 'import-export', icon: 'fa fas fa-exchange-alt', bg: '#1890ff', title: '导入导出', desc: '设置导入、导出和重置', route: '/tools/import-export' },
{ key: 'health', icon: 'fa fas fa-heartbeat', bg: '#52c41a', title: '健康检查', desc: '系统状态检测和诊断', route: '/tools/health' },
{ key: 'email-rollback', icon: 'fa fas fa-undo', bg: '#fa8c16', title: '邮箱回滚', desc: '邮箱变更 14 天内回滚', route: '/tools/email-rollback' },
])
const services = ref([
{ key: 'sms', icon: 'fas fa-sms', color: '#1890ff', name: '短信服务', description: '验证码和通知短信', available: false },
{ key: 'wechat', icon: 'fab fa-weixin', color: '#52c41a', name: '微信通知', description: '微信模板消息和订阅通知', available: false },
{ key: 'captcha', icon: 'fas fa-shield-alt', color: '#722ed1', name: '验证码服务', description: '人机验证(极验/腾讯/阿里云)', available: false },
{ key: 'push', icon: 'fas fa-paper-plane', color: '#fa8c16', name: '搜索引擎推送', description: '百度/Google 主动推送', available: false },
{ key: 'audit', icon: 'fas fa-shield-virus', color: '#f5222d', name: '内容审核', description: '第三方内容安全审核 API', available: false },
{ key: 'sms', icon: 'fa fas fa-comment', color: '#1890ff', name: '短信服务', description: '验证码和通知短信', available: false },
{ key: 'wechat', icon: 'fa fab fa-weixin', color: '#52c41a', name: '微信通知', description: '微信模板消息和订阅通知', available: false },
{ key: 'captcha', icon: 'fa fas fa-shield-alt', color: '#722ed1', name: '验证码服务', description: '人机验证(极验/腾讯/阿里云)', available: false },
{ key: 'push', icon: 'fa fas fa-paper-plane', color: '#fa8c16', name: '搜索引擎推送', description: '百度/Google 主动推送', available: false },
{ key: 'audit', icon: 'fa fas fa-shield-alt', color: '#f5222d', name: '内容审核', description: '第三方内容安全审核 API', available: false },
])
onMounted(async () => {
@@ -51,12 +51,12 @@ const overview = ref({})
const loading = ref(false)
function iconFor(id) {
if (id === 'balance') return 'fas fa-wallet'
if (id === 'alipay' || id === 'epay_alipay') return 'fab fa-alipay'
if (id === 'wechatpay' || id === 'epay_wxpay') return 'fab fa-weixin'
if (id === 'paypal') return 'fab fa-paypal'
if (id === 'stripe') return 'fab fa-stripe-s'
return 'fas fa-credit-card'
if (id === 'balance') return 'fa fas fa-credit-card'
if (id === 'alipay' || id === 'epay_alipay') return 'fa fas fa-credit-card'
if (id === 'wechatpay' || id === 'epay_wxpay') return 'fa fab fa-weixin'
if (id === 'paypal') return 'fa fab fa-paypal'
if (id === 'stripe') return 'fa fab fa-cc-stripe'
return 'fa fas fa-credit-card'
}
onMounted(async () => {
@@ -99,10 +99,10 @@ const form = reactive({
})
const summaryItems = computed(() => [
{ key: 'profile', icon: 'fas fa-id-card', label: '资料卡图片', enabled: true },
{ key: 'submit', icon: 'fas fa-edit', label: '投稿图片', enabled: true },
{ key: 'comment', icon: 'fas fa-comment-dots', label: '评论图片', enabled: true },
{ key: 'resource', icon: 'fas fa-file-archive', label: '资源附件', enabled: true },
{ key: 'profile', icon: 'fa fas fa-id-card', label: '资料卡图片', enabled: true },
{ key: 'submit', icon: 'fa fas fa-edit', label: '投稿图片', enabled: true },
{ key: 'comment', icon: 'fa fas fa-comment-dots', label: '评论图片', enabled: true },
{ key: 'resource', icon: 'fa fas fa-file-archive', label: '资源附件', enabled: true },
])
function go(path) {
@@ -70,7 +70,7 @@
size="small"
class="aksrt-theme-info__module-tag"
>
<FaIcon :icon="mod.enabled ? 'fas fa-check-circle' : 'fas fa-circle'" :size="10" />
<FaIcon :icon="mod.enabled ? 'fa fas fa-check-circle' : 'fa fas fa-circle'" :size="10" />
{{ mod.label }}
</n-tag>
</div>
@@ -94,23 +94,23 @@
<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" />
<FaIcon icon="fa 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" />
<FaIcon icon="fa fas fa-cloud-download-alt" :size="16" />
<span>更新中心</span>
</router-link>
<router-link to="/tools/backup" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-box-archive" :size="16" />
<FaIcon icon="fa fas fa-archive" :size="16" />
<span>数据备份</span>
</router-link>
<router-link to="/tools/health" class="aksrt-theme-info__link">
<FaIcon icon="fas fa-heartbeat" :size="16" />
<FaIcon icon="fa 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" />
<FaIcon icon="fa fas fa-exchange-alt" :size="16" />
<span>导入导出</span>
</router-link>
</div>
@@ -6,7 +6,7 @@
<div class="aksrt-wechat__status">
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.configured ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.configured ? 'fas fa-check' : 'fas fa-exclamation'"></i>
<i :class="status.configured ? 'fa fas fa-check' : 'fa fas fa-exclamation'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">配置状态</div>
@@ -15,7 +15,7 @@
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.has_token ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.has_token ? 'fas fa-key' : 'fas fa-key'"></i>
<i :class="status.has_token ? 'fa fas fa-key' : 'fa fas fa-key'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">Access Token</div>
@@ -24,7 +24,7 @@
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.has_template ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.has_template ? 'fas fa-file-alt' : 'fas fa-file-alt'"></i>
<i :class="status.has_template ? 'fa fas fa-file-alt' : 'fa fas fa-file-alt'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">模板 ID</div>
@@ -33,7 +33,7 @@
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon aksrt-wechat__status-icon--info">
<i class="fas fa-users"></i>
<i class="fa fas fa-users"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">绑定用户</div>