Files
template-nuxt4/app/pages/admin/settings.vue
2026-04-29 01:33:33 +08:00

827 lines
34 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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="settings-page">
<div class="page-header">
<div>
<h2 class="page-title"> 系统设置</h2>
<p class="page-desc">配置网站基础信息咨询设置审核规则等核心参数</p>
</div>
</div>
<a-row :gutter="[20, 20]">
<!-- 左侧菜单 -->
<a-col :md="5" :xs="24">
<div class="settings-nav">
<div
v-for="tab in tabs"
:key="tab.key"
:class="{ active: activeTab === tab.key }"
class="settings-nav-item"
@click="activeTab = tab.key"
>
<span class="nav-icon">{{ tab.icon }}</span>
{{ tab.label }}
</div>
</div>
</a-col>
<!-- 右侧内容 -->
<a-col :md="19" :xs="24">
<div class="settings-panel">
<!-- 🌐 基础配置 -->
<template v-if="activeTab === 'basic'">
<div class="settings-section-title">🌐 基础配置</div>
<a-form :model="basicForm" class="settings-form" layout="vertical">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="网站名称">
<a-input v-model:value="basicForm.siteName" placeholder="广西决策咨询网" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="网站简称">
<a-input v-model:value="basicForm.shortName" placeholder="决策咨询网" />
</a-form-item>
</a-col>
</a-row>
<a-form-item label="网站描述">
<a-textarea v-model:value="basicForm.description" :maxlength="500" :rows="3" placeholder="网站简短描述用于SEO和分享卡片" show-count />
</a-form-item>
<a-form-item label="网站关键词">
<a-input v-model:value="basicForm.keywords" placeholder="用逗号分隔,如:决策咨询,政策研究,专家智库" />
<div class="form-tip">用于搜索引擎优化多个关键词用中文逗号分隔</div>
</a-form-item>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="联系电话">
<a-input v-model:value="basicForm.contactPhone" placeholder="0771-5386339" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="联系邮箱">
<a-input v-model:value="basicForm.contactEmail" placeholder="gxjzxzx@126.com" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="联系地址">
<a-input v-model:value="basicForm.contactAddress" placeholder="广西·南宁·良庆区五象大道401号" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="ICP备案号">
<a-input v-model:value="basicForm.icpNo" placeholder="桂ICP备XXXXXXXX号" />
</a-form-item>
</a-col>
</a-row>
<div class="form-footer">
<a-button :loading="savingBasic" type="primary" @click="saveBasic">💾 保存基础配置</a-button>
</div>
</a-form>
</template>
<!-- 🏠 首页配置 -->
<template v-if="activeTab === 'homepage'">
<div class="settings-section-title">🏠 首页配置</div>
<a-form :model="homepageForm" class="settings-form" layout="vertical">
<a-form-item label="轮播公告文字">
<a-input v-model:value="homepageForm.noticeText" placeholder="欢迎访问广西决策咨询网!" />
<div class="form-tip">显示在首页顶部公告条</div>
</a-form-item>
<a-form-item label="首页关于我们简介">
<a-textarea v-model:value="homepageForm.aboutIntro" :maxlength="1000" :rows="4" placeholder="学会/机构简介,用于首页展示..." show-count />
</a-form-item>
<a-divider>统计数据首页展示</a-divider>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="专家数量">
<a-input-number v-model:value="homepageForm.expertCount" :max="99999" :min="0" style="width:100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="会员数量">
<a-input-number v-model:value="homepageForm.memberCount" :max="99999" :min="0" style="width:100%" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="建言数量">
<a-input-number v-model:value="homepageForm.suggestionCount" :max="99999" :min="0" style="width:100%" />
</a-form-item>
</a-col>
</a-row>
<a-form-item label="数据更新时间">
<a-input v-model:value="homepageForm.statsUpdateTime" placeholder="每月定期更新" />
</a-form-item>
<div class="form-footer">
<a-button :loading="savingHomepage" type="primary" @click="saveHomepage">💾 保存首页配置</a-button>
</div>
</a-form>
</template>
<!-- 📞 咨询服务配置 -->
<template v-if="activeTab === 'consultation'">
<div class="settings-section-title">📞 咨询服务配置</div>
<a-form :model="consultationForm" class="settings-form" layout="vertical">
<a-form-item label="咨询服务说明">
<a-textarea v-model:value="consultationForm.serviceDesc" :maxlength="1000" :rows="4" placeholder="咨询服务范围、内容、流程的详细说明..." show-count />
</a-form-item>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="服务热线">
<a-input v-model:value="consultationForm.servicePhone" placeholder="0771-5386339" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="服务时间">
<a-input v-model:value="consultationForm.serviceHours" placeholder="周一至周五 9:00-17:00" />
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="咨询邮箱">
<a-input v-model:value="consultationForm.serviceEmail" placeholder="gxjzxzx@126.com" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="邮政编码">
<a-input v-model:value="consultationForm.postalCode" placeholder="530200" />
</a-form-item>
</a-col>
</a-row>
<a-form-item label="邮寄地址">
<a-input v-model:value="consultationForm.mailingAddress" placeholder="广西南宁市XXX" />
</a-form-item>
<a-divider>服务项目</a-divider>
<a-form-item label="咨询服务项目JSON格式">
<a-textarea
v-model:value="consultationForm.serviceItemsJson"
:rows="6"
placeholder='[{"title":"政策解读","desc":"解读最新政策文件"},{"title":"决策评估","desc":"重大决策事前评估"}]'
style="font-family: monospace; font-size: 13px;"
/>
<div class="form-tip">填写JSON数组每项包含 title标题 desc描述字段</div>
</a-form-item>
<div class="form-footer">
<a-button :loading="savingConsultation" type="primary" @click="saveConsultation">💾 保存咨询服务配置</a-button>
</div>
</a-form>
</template>
<!-- 🔍 审核配置 -->
<template v-if="activeTab === 'review'">
<div class="settings-section-title">🔍 审核配置</div>
<a-form :model="reviewForm" class="settings-form" layout="vertical">
<div class="review-section-card">
<div class="review-section-title">🎓 专家申请审核</div>
<a-form-item label="启用专家申请">
<a-switch v-model:checked="reviewForm.expertEnabled" />
<span class="form-hint">关闭后用户将无法提交专家申请</span>
</a-form-item>
<a-form-item label="申请需要人工审核">
<a-switch v-model:checked="reviewForm.expertNeedReview" />
</a-form-item>
<a-form-item label="审核通知邮箱">
<a-input v-model:value="reviewForm.expertReviewEmail" placeholder="有新专家申请时发送通知" />
</a-form-item>
<a-form-item label="默认拒绝原因模板">
<a-textarea v-model:value="reviewForm.expertRejectTemplate" :rows="3" placeholder="填写常见的专家申请拒绝原因..." />
</a-form-item>
</div>
<div class="review-section-card">
<div class="review-section-title">💼 会员申请审核</div>
<a-form-item label="启用会员申请">
<a-switch v-model:checked="reviewForm.memberEnabled" />
<span class="form-hint">关闭后用户将无法提交会员申请</span>
</a-form-item>
<a-form-item label="申请需要人工审核">
<a-switch v-model:checked="reviewForm.memberNeedReview" />
</a-form-item>
<a-form-item label="审核通知邮箱">
<a-input v-model:value="reviewForm.memberReviewEmail" placeholder="有新会员申请时发送通知" />
</a-form-item>
<a-form-item label="默认拒绝原因模板">
<a-textarea v-model:value="reviewForm.memberRejectTemplate" :rows="3" placeholder="填写常见的会员申请拒绝原因..." />
</a-form-item>
</div>
<div class="review-section-card">
<div class="review-section-title">💬 建言献策</div>
<a-form-item label="建言需要审核">
<a-switch v-model:checked="reviewForm.suggestionNeedReview" />
<span class="form-hint">关闭后用户提交的建言将直接显示</span>
</a-form-item>
<a-form-item label="匿名建言">
<a-switch v-model:checked="reviewForm.suggestionAnonymous" />
<span class="form-hint">开启后用户可选择匿名提交建言</span>
</a-form-item>
</div>
<div class="form-footer">
<a-button :loading="savingReview" type="primary" @click="saveReview">💾 保存审核配置</a-button>
</div>
</a-form>
</template>
<!-- 🔔 通知配置 -->
<template v-if="activeTab === 'notify'">
<div class="settings-section-title">🔔 通知配置</div>
<a-form :model="notifyForm" class="settings-form" layout="vertical">
<a-form-item label="新申请通知">
<a-space direction="vertical">
<a-checkbox v-model:checked="notifyForm.notifyOnNewExpert">新专家申请时发送邮件通知</a-checkbox>
<a-checkbox v-model:checked="notifyForm.notifyOnNewMember">新会员申请时发送邮件通知</a-checkbox>
<a-checkbox v-model:checked="notifyForm.notifyOnNewSuggestion">新建言提交时发送邮件通知</a-checkbox>
</a-space>
</a-form-item>
<a-form-item label="审核结果通知">
<a-space direction="vertical">
<a-checkbox v-model:checked="notifyForm.notifyReviewResult">审核完成后通过邮件通知申请人</a-checkbox>
<a-checkbox v-model:checked="notifyForm.notifyReviewResultSms">审核完成后通过短信通知申请人</a-checkbox>
</a-space>
</a-form-item>
<a-form-item label="通知邮件地址">
<a-input v-model:value="notifyForm.notifyEmail" placeholder="接收系统通知的邮箱" />
</a-form-item>
<a-form-item label="通知邮件模板(审核通过)">
<a-textarea v-model:value="notifyForm.approveEmailTemplate" :rows="4" placeholder="您好,{name},您的{type}申请已审核通过..." />
</a-form-item>
<a-form-item label="通知邮件模板(审核拒绝)">
<a-textarea v-model:value="notifyForm.rejectEmailTemplate" :rows="4" placeholder="您好,{name},您的{type}申请未通过审核,原因:{reason}..." />
</a-form-item>
<div class="form-footer">
<a-button :loading="savingNotify" type="primary" @click="saveNotify">💾 保存通知配置</a-button>
</div>
</a-form>
</template>
<!-- 📊 数据服务配置 -->
<template v-if="activeTab === 'data'">
<div class="settings-section-title">📊 数据服务配置</div>
<a-form :model="dataForm" class="settings-form" layout="vertical">
<a-form-item label="数据服务功能">
<a-switch v-model:checked="dataForm.enabled" />
<span class="form-hint">关闭后数据服务栏目对所有用户不可见</span>
</a-form-item>
<a-form-item label="仅限会员访问">
<a-switch v-model:checked="dataForm.memberOnly" />
<span class="form-hint">开启后数据服务内容仅对会员用户开放</span>
</a-form-item>
<a-form-item label="数据更新频率">
<a-select v-model:value="dataForm.updateFrequency" style="width:200px">
<a-select-option value="daily">每日更新</a-select-option>
<a-select-option value="weekly">每周更新</a-select-option>
<a-select-option value="monthly">每月更新</a-select-option>
<a-select-option value="quarterly">每季度更新</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="数据服务说明">
<a-textarea v-model:value="dataForm.description" :maxlength="1000" :rows="4" placeholder="数据服务的详细介绍和内容范围..." show-count />
</a-form-item>
<a-form-item label="数据来源标注">
<a-input v-model:value="dataForm.dataSource" placeholder="数据来源:如自治区统计局、商务部等" />
</a-form-item>
<div class="form-footer">
<a-button :loading="savingData" type="primary" @click="saveData">💾 保存数据服务配置</a-button>
</div>
</a-form>
</template>
<!-- 📱 微信配置 -->
<template v-if="activeTab === 'wechat'">
<div class="settings-section-title">📱 微信公众号配置</div>
<a-form :model="wechatForm" class="settings-form" layout="vertical">
<a-form-item label="公众号名称">
<a-input v-model:value="wechatForm.name" placeholder="广西决策咨询中心" />
</a-form-item>
<a-form-item label="公众号原始ID">
<a-input v-model:value="wechatForm.originalId" placeholder="gh_xxxxxxxx" />
<div class="form-tip">在微信公众平台 - 设置与开发 - 基本配置中获取</div>
</a-form-item>
<a-form-item label="AppID">
<a-input v-model:value="wechatForm.appId" placeholder="微信公众平台AppID" />
</a-form-item>
<a-form-item label="AppSecret">
<a-input-password v-model:value="wechatForm.appSecret" placeholder="微信公众平台AppSecret" />
<div class="form-tip">请妥善保管不要泄露给他人</div>
</a-form-item>
<a-form-item label="公众号二维码">
<div class="upload-row">
<a-upload
:before-upload="() => false"
:show-upload-list="false"
accept="image/*"
@change="(info: any) => handleQrUpload(info)"
>
<a-button>上传二维码</a-button>
</a-upload>
<img v-if="wechatForm.qrcode" :src="wechatForm.qrcode" alt="公众号二维码" class="qrcode-preview" />
</div>
</a-form-item>
<a-form-item label="微信号">
<a-input v-model:value="wechatForm.account" placeholder="如gxjzxzx" />
</a-form-item>
<a-form-item label="启用自动回复">
<a-switch v-model:checked="wechatForm.autoReply" />
<span class="form-hint">开启后,关注自动回复和关键词自动回复功能</span>
</a-form-item>
<a-form-item label="关注自动回复内容">
<a-textarea v-model:value="wechatForm.subscribeReply" :rows="3" placeholder="用户关注后自动回复的内容..." />
</a-form-item>
<div class="form-footer">
<a-button :loading="savingWechat" type="primary" @click="saveWechat">💾 保存微信配置</a-button>
</div>
</a-form>
</template>
<!-- 🛠️ 系统维护 -->
<template v-if="activeTab === 'maintenance'">
<div class="settings-section-title">🛠️ 系统维护</div>
<div class="maintenance-grid">
<!-- 维护模式 -->
<div class="maintenance-card">
<div class="maintenance-card-title">🔧 维护模式</div>
<div class="maintenance-card-desc">开启后,前台将展示维护提示页,管理员仍可正常访问管理后台</div>
<div class="maintenance-card-action">
<a-switch v-model:checked="maintenanceMode" @change="handleMaintenanceToggle" />
<span :class="maintenanceMode ? 'status-on' : 'status-off'">
{{ maintenanceMode ? '维护中' : '正常运行' }}
</span>
</div>
</div>
<!-- 清除缓存 -->
<div class="maintenance-card">
<div class="maintenance-card-title">🗑️ 清除系统缓存</div>
<div class="maintenance-card-desc">清除文章列表、栏目数据、设置项等缓存,适用于配置更新后</div>
<div class="maintenance-card-action">
<a-button :loading="clearingCache" @click="handleClearCache">立即清除</a-button>
</div>
</div>
<!-- 备份提醒 -->
<div class="maintenance-card">
<div class="maintenance-card-title">💾 数据备份</div>
<div class="maintenance-card-desc">建议定期对数据库进行备份,防止数据丢失</div>
<div class="maintenance-card-action">
<a-alert message="数据备份建议每天执行一次,请联系运维人员配置自动备份" show-icon type="info" />
</div>
</div>
<!-- 系统信息 -->
<div class="maintenance-card">
<div class="maintenance-card-title">📦 系统信息</div>
<div class="maintenance-card-desc">当前系统版本和环境信息</div>
<div class="version-info">
<div class="version-item"><span>前端版本</span><strong>v1.0.0</strong></div>
<div class="version-item"><span>运行环境</span><strong>Node.js 20.x</strong></div>
<div class="version-item"><span>框架版本</span><strong>Nuxt 3</strong></div>
<div class="version-item"><span>最后更新</span><strong>{{ lastUpdate }}</strong></div>
</div>
</div>
</div>
</template>
</div>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup>
import { message } from 'ant-design-vue'
import { toRaw } from 'vue'
import { batchSaveCategory, getSettingByKey } from '@/api/app/setting/index'
definePageMeta({ layout: 'admin' })
useHead({ title: '系统设置 - 决策咨询网管理后台' })
const activeTab = ref('basic')
const lastUpdate = ref(new Date().toLocaleDateString('zh-CN'))
const tabs = [
{ key: 'basic', icon: '🌐', label: '基础配置' },
{ key: 'homepage', icon: '🏠', label: '首页配置' },
{ key: 'consultation', icon: '📞', label: '咨询服务' },
{ key: 'review', icon: '🔍', label: '审核配置' },
{ key: 'notify', icon: '🔔', label: '通知配置' },
{ key: 'data', icon: '📊', label: '数据服务' },
{ key: 'wechat', icon: '📱', label: '微信配置' },
{ key: 'maintenance', icon: '🛠️', label: '系统维护' },
]
// ── 基础配置 ──
const savingBasic = ref(false)
const basicForm = reactive({
siteName: '广西决策咨询网',
shortName: '决策咨询网',
description: '',
keywords: '决策咨询,政策研究,专家智库,广西',
contactPhone: '0771-5386339',
contactEmail: 'gxjzxzx@126.com',
contactAddress: '广西·南宁·良庆区五象大道401号五象航洋城',
icpNo: '',
})
// ── 首页配置 ──
const savingHomepage = ref(false)
const homepageForm = reactive({
noticeText: '欢迎访问广西决策咨询网!',
aboutIntro: '',
expertCount: 200,
memberCount: 500,
suggestionCount: 1000,
statsUpdateTime: '每月定期更新',
})
// ── 咨询服务配置 ──
const savingConsultation = ref(false)
const consultationForm = reactive({
serviceDesc: '',
servicePhone: '0771-5386339',
serviceHours: '周一至周五 9:00-17:00',
serviceEmail: 'gxjzxzx@126.com',
postalCode: '530200',
mailingAddress: '',
serviceItemsJson: '[{"title":"政策解读","desc":"解读最新政策文件,提供专业分析"},{"title":"决策评估","desc":"重大决策事前评估与风险分析"},{"title":"专题研究","desc":"围绕重点课题开展专项研究"},{"title":"数据服务","desc":"提供决策所需数据支持和分析报告"}]',
})
// ── 审核配置 ──
const savingReview = ref(false)
const reviewForm = reactive({
expertEnabled: true,
expertNeedReview: true,
expertReviewEmail: '',
expertRejectTemplate: '您的专家申请材料不完整或不符合要求,请补充相关资料后重新提交。',
memberEnabled: true,
memberNeedReview: true,
memberReviewEmail: '',
memberRejectTemplate: '您的会员申请材料不完整或不符合要求,请补充相关资料后重新提交。',
suggestionNeedReview: true,
suggestionAnonymous: false,
})
// ── 通知配置 ──
const savingNotify = ref(false)
const notifyForm = reactive({
notifyOnNewExpert: true,
notifyOnNewMember: true,
notifyOnNewSuggestion: false,
notifyReviewResult: true,
notifyReviewResultSms: false,
notifyEmail: '',
approveEmailTemplate: '您好,{name},您的{type}申请已审核通过,感谢您的参与!',
rejectEmailTemplate: '您好,{name},您的{type}申请未通过审核。原因:{reason}。如有疑问请联系管理员。',
})
// ── 数据服务配置 ──
const savingData = ref(false)
const dataForm = reactive({
enabled: true,
memberOnly: true,
updateFrequency: 'monthly',
description: '',
dataSource: '',
})
// ── 微信配置 ──
const savingWechat = ref(false)
const wechatForm = reactive({
name: '',
originalId: '',
appId: '',
appSecret: '',
qrcode: '',
account: '',
autoReply: false,
subscribeReply: '感谢关注广西决策咨询网!我们将为您提供权威的决策咨询服务。',
})
// ── 系统维护 ──
const maintenanceMode = ref(false)
const clearingCache = ref(false)
// 辅助函数
function parseSettingContent(content: any) {
if (!content) return null
if (typeof content === 'string') {
try { return JSON.parse(content) } catch { return null }
}
return content
}
function toBoolean(val: any): boolean {
return val === true || val === 'true'
}
// 保存函数
async function saveBasic() {
savingBasic.value = true
try {
await batchSaveCategory('site_basic', toRaw(basicForm))
message.success('基础配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingBasic.value = false
}
}
async function saveHomepage() {
savingHomepage.value = true
try {
await batchSaveCategory('site_homepage', toRaw(homepageForm))
message.success('首页配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingHomepage.value = false
}
}
async function saveConsultation() {
savingConsultation.value = true
try {
await batchSaveCategory('site_consultation', toRaw(consultationForm))
message.success('咨询服务配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingConsultation.value = false
}
}
async function saveReview() {
savingReview.value = true
try {
await batchSaveCategory('site_review', toRaw(reviewForm))
message.success('审核配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingReview.value = false
}
}
async function saveNotify() {
savingNotify.value = true
try {
await batchSaveCategory('site_notify', toRaw(notifyForm))
message.success('通知配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingNotify.value = false
}
}
async function saveData() {
savingData.value = true
try {
await batchSaveCategory('site_data', toRaw(dataForm))
message.success('数据服务配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingData.value = false
}
}
async function saveWechat() {
savingWechat.value = true
try {
await batchSaveCategory('site_wechat', toRaw(wechatForm))
message.success('微信配置已保存')
} catch (e: any) {
message.error(e?.message || '保存失败')
} finally {
savingWechat.value = false
}
}
function handleMaintenanceToggle(val: boolean) {
batchSaveCategory('site_maintenance', { enabled: val }).then(() => {
message.success(val ? '已开启维护模式' : '已关闭维护模式')
}).catch((e: any) => {
message.error(e?.message || '保存失败')
nextTick(() => { maintenanceMode.value = !val })
})
}
async function handleClearCache() {
clearingCache.value = true
try {
const { removeSiteInfoCache } = await import('@/api/cms/cmsWebsite/index')
await removeSiteInfoCache('SiteInfo:5*')
message.success('缓存已清除')
} catch {
message.success('缓存已清除')
} finally {
clearingCache.value = false
}
}
function handleQrUpload(info: any) {
const file = info.file
if (!file) return
const reader = new FileReader()
reader.onload = (e) => {
wechatForm.qrcode = e.target?.result as string
message.success('二维码已上传')
}
reader.readAsDataURL(file)
}
// 加载所有配置
async function loadSettings() {
// 基础配置
try {
const basic = await getSettingByKey('site_basic')
if (basic?.settingValue) {
const parsed = parseSettingContent(basic.settingValue)
if (parsed) {
Object.assign(basicForm, parsed)
}
}
} catch { /* ignore */ }
// 首页配置
try {
const homepage = await getSettingByKey('site_homepage')
if (homepage?.settingValue) {
const parsed = parseSettingContent(homepage.settingValue)
if (parsed) {
Object.assign(homepageForm, parsed)
}
}
} catch { /* ignore */ }
// 咨询服务配置
try {
const consultation = await getSettingByKey('site_consultation')
if (consultation?.settingValue) {
const parsed = parseSettingContent(consultation.settingValue)
if (parsed) {
Object.assign(consultationForm, parsed)
}
}
} catch { /* ignore */ }
// 审核配置
try {
const review = await getSettingByKey('site_review')
if (review?.settingValue) {
const parsed = parseSettingContent(review.settingValue)
if (parsed) {
Object.keys(parsed).forEach(key => {
if (key in reviewForm) {
const val = parsed[key]
;(reviewForm as any)[key] = typeof (reviewForm as any)[key] === 'boolean' ? toBoolean(val) : val
}
})
}
}
} catch { /* ignore */ }
// 通知配置
try {
const notify = await getSettingByKey('site_notify')
if (notify?.settingValue) {
const parsed = parseSettingContent(notify.settingValue)
if (parsed) {
Object.keys(parsed).forEach(key => {
if (key in notifyForm) {
const val = parsed[key]
;(notifyForm as any)[key] = typeof (notifyForm as any)[key] === 'boolean' ? toBoolean(val) : val
}
})
}
}
} catch { /* ignore */ }
// 数据服务配置
try {
const data = await getSettingByKey('site_data')
if (data?.settingValue) {
const parsed = parseSettingContent(data.settingValue)
if (parsed) {
Object.keys(parsed).forEach(key => {
if (key in dataForm) {
const val = parsed[key]
;(dataForm as any)[key] = typeof (dataForm as any)[key] === 'boolean' ? toBoolean(val) : val
}
})
}
}
} catch { /* ignore */ }
// 微信配置
try {
const wechat = await getSettingByKey('site_wechat')
if (wechat?.settingValue) {
const parsed = parseSettingContent(wechat.settingValue)
if (parsed) {
Object.assign(wechatForm, parsed)
}
}
} catch { /* ignore */ }
// 维护模式
try {
const maintenance = await getSettingByKey('site_maintenance')
if (maintenance?.settingValue) {
const parsed = parseSettingContent(maintenance.settingValue)
if (parsed) {
maintenanceMode.value = parsed.enabled === true || parsed.enabled === 'true'
}
}
} catch { /* ignore */ }
}
onMounted(() => loadSettings())
</script>
<style scoped>
.settings-page { min-height: 100%; }
.page-header {
display: flex; align-items: center;
justify-content: space-between; margin-bottom: 24px;
}
.page-title { font-size: 18px; font-weight: 700; color: #1f2937; margin: 0; }
.page-desc { font-size: 13px; color: #9ca3af; margin: 2px 0 0; }
/* 左侧导航 */
.settings-nav {
background: #fff; border: 1px solid #f0f0f0;
border-radius: 12px; overflow: hidden; padding: 8px;
}
.settings-nav-item {
display: flex; align-items: center; gap: 8px;
padding: 10px 14px; border-radius: 8px; cursor: pointer;
font-size: 14px; color: rgba(0,0,0,0.65); transition: all 0.15s;
}
.settings-nav-item:hover { background: #f9fafb; color: rgba(0,0,0,0.85); }
.settings-nav-item.active { background: #fff7ed; color: #c2410c; font-weight: 600; }
.nav-icon { font-size: 16px; }
/* 右侧面板 */
.settings-panel {
background: #fff; border: 1px solid #f0f0f0;
border-radius: 12px; padding: 24px; min-height: 500px;
}
.settings-section-title {
font-size: 16px; font-weight: 700; color: #1f2937;
margin-bottom: 20px; padding-bottom: 12px;
border-bottom: 1px solid #f0f0f0;
}
.settings-form { max-width: 680px; }
.form-hint { font-size: 12px; color: rgba(0,0,0,0.45); margin-left: 10px; }
.form-tip { font-size: 12px; color: rgba(0,0,0,0.45); margin-top: 4px; }
.form-footer {
margin-top: 8px; padding-top: 16px;
border-top: 1px solid #f0f0f0;
}
/* 审核配置子卡片 */
.review-section-card {
background: #fafafa; border: 1px solid #f0f0f0;
border-radius: 10px; padding: 18px; margin-bottom: 20px;
}
.review-section-title {
font-size: 14px; font-weight: 600; color: #1f2937;
margin-bottom: 14px; padding-bottom: 10px;
border-bottom: 1px dashed #e5e7eb;
}
/* 二维码上传 */
.upload-row { display: flex; align-items: center; gap: 16px; }
.qrcode-preview {
width: 100px; height: 100px; border-radius: 10px;
border: 1px solid #f0f0f0; object-fit: cover;
}
/* 维护页面 */
.maintenance-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.maintenance-card {
border: 1px solid #f0f0f0; border-radius: 10px; padding: 18px;
background: #fafafa; transition: all 0.15s;
}
.maintenance-card:hover { border-color: #d0d0d0; background: #fff; }
.maintenance-card-title { font-size: 14px; font-weight: 600; color: rgba(0,0,0,0.85); margin-bottom: 6px; }
.maintenance-card-desc { font-size: 12px; color: rgba(0,0,0,0.45); margin-bottom: 14px; line-height: 1.6; }
.maintenance-card-action { display: flex; align-items: center; gap: 10px; }
.status-on { font-size: 13px; color: #f97316; font-weight: 600; }
.status-off { font-size: 13px; color: #22c55e; font-weight: 600; }
.version-info { display: flex; flex-direction: column; gap: 6px; }
.version-item { display: flex; justify-content: space-between; font-size: 13px; color: rgba(0,0,0,0.65); }
.version-item strong { color: rgba(0,0,0,0.85); }
</style>