导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

@@ -0,0 +1,283 @@
<template>
<div class="aksrt-page-container">
<PageHeader
title="附件治理"
desc="统一管理全站上传行为:头像、封面、投稿图片、评论图片、背景图和资源附件。"
>
<template #actions>
<n-space>
<n-button quaternary @click="go('/permissions/download')">下载权限</n-button>
<n-button quaternary @click="goModeration">审核策略</n-button>
</n-space>
</template>
</PageHeader>
<n-spin :show="loading" style="width:100%; min-height:200px;">
<!-- Summary -->
<n-card class="aksrt-section-card">
<div class="aksrt-section-header">
<h3>上传策略总览</h3>
</div>
<n-grid :cols="3" :x-gap="12" :y-gap="12">
<n-grid-item v-for="item in summaryItems" :key="item.key">
<div class="aksrt-attach__summary">
<FaIcon :icon="item.icon" :size="16" :color="item.enabled ? '#52c41a' : '#8a909c'" />
<div>
<strong>{{ item.label }}</strong>
<p>{{ item.enabled ? '已启用' : '已关闭' }}</p>
</div>
</div>
</n-grid-item>
</n-grid>
</n-card>
<!-- Avatar & Cover -->
<n-card class="aksrt-section-card">
<div class="aksrt-section-header">
<h3>头像与封面</h3>
</div>
<n-form :model="form" label-placement="left" label-width="200" class="aksrt-form">
<n-form-item label="允许用户上传头像">
<n-switch v-model:value="form.allow_avatar_upload" />
<template #feedback>
<span class="aksrt-hint-text">关闭后用户只能使用 Gravatar/Cravatar 自动头像。</span>
</template>
</n-form-item>
<n-form-item label="允许用户上传封面图">
<n-switch v-model:value="form.allow_cover_upload" />
<template #feedback>
<span class="aksrt-hint-text">控制用户中心公开主页封面图上传入口。</span>
</template>
</n-form-item>
<n-form-item label="允许用户上传背景图">
<n-switch v-model:value="form.allow_background_upload" />
<template #feedback>
<span class="aksrt-hint-text">控制用户中心公开可用的背景图上传入口。</span>
</template>
</n-form-item>
<n-form-item label="头像/封面大小上限 (MB)">
<n-input-number v-model:value="form.avatar_max_size" :min="1" :max="10" style="max-width:160px;" />
</n-form-item>
</n-form>
</n-card>
<!-- Content uploads -->
<n-card class="aksrt-section-card">
<div class="aksrt-section-header">
<h3>内容上传</h3>
</div>
<n-form :model="form" label-placement="left" label-width="200" class="aksrt-form">
<n-form-item label="允许投稿插入图片">
<n-switch v-model:value="form.allow_submit_images" />
<template #feedback>
<span class="aksrt-hint-text">前台投稿编辑器中允许插入图片。</span>
</template>
</n-form-item>
<n-form-item label="投稿图片大小上限 (MB)">
<n-input-number v-model:value="form.submit_image_max_size" :min="1" :max="20" style="max-width:160px;" />
</n-form-item>
<n-form-item label="允许评论插入图片">
<n-switch v-model:value="form.allow_comment_images" />
<template #feedback>
<span class="aksrt-hint-text">评论工具栏中允许插入图片链接或上传图片。</span>
</template>
</n-form-item>
<n-form-item label="评论图片大小上限 (MB)">
<n-input-number v-model:value="form.comment_image_max_size" :min="1" :max="10" style="max-width:160px;" />
</n-form-item>
</n-form>
</n-card>
<!-- Resource attachments -->
<n-card class="aksrt-section-card">
<div class="aksrt-section-header">
<h3>资源附件</h3>
</div>
<n-form :model="form" label-placement="left" label-width="200" class="aksrt-form">
<n-form-item label="允许资源附件上传">
<n-switch v-model:value="form.allow_resource_upload" />
<template #feedback>
<span class="aksrt-hint-text">后台资源编辑器中允许上传附件文件。</span>
</template>
</n-form-item>
<n-form-item label="资源附件大小上限 (MB)">
<n-input-number v-model:value="form.resource_max_size" :min="1" :max="200" style="max-width:160px;" />
</n-form-item>
</n-form>
</n-card>
<!-- AI Moderation -->
<n-card class="aksrt-section-card">
<div class="aksrt-section-header">
<h3>审核联动</h3>
</div>
<n-form :model="form" label-placement="left" label-width="200" class="aksrt-form">
<n-form-item label="背景图接入 AI 审核">
<n-switch v-model:value="form.ai_moderate_background" />
<template #feedback>
<span class="aksrt-hint-text">命中高风险时会阻断上传,并保留上一次背景图。</span>
</template>
</n-form-item>
<n-form-item label="投稿图片接入 AI 审核">
<n-switch v-model:value="form.ai_moderate_submit" />
<template #feedback>
<span class="aksrt-hint-text">投稿中插入的图片也会经过内容安全审核。</span>
</template>
</n-form-item>
</n-form>
</n-card>
<div class="aksrt-form-actions">
<n-button type="primary" :loading="saving" @click="handleSave">保存配置</n-button>
</div>
</n-spin>
</div>
</template>
<script setup>
import { onMounted, reactive, ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useMessage } from 'naive-ui'
import api from '@/api'
import PageHeader from '@/components/PageHeader.vue'
import FaIcon from '@/components/form/FaIcon.vue'
const router = useRouter()
const message = useMessage()
const loading = ref(true)
const saving = ref(false)
const moderationSnapshot = ref({})
const form = reactive({
allow_avatar_upload: true,
allow_cover_upload: true,
allow_background_upload: false,
avatar_max_size: 2,
allow_submit_images: true,
submit_image_max_size: 5,
allow_comment_images: false,
comment_image_max_size: 2,
allow_resource_upload: true,
resource_max_size: 50,
ai_moderate_background: true,
ai_moderate_submit: false,
})
const summaryItems = computed(() => [
{ key: 'avatar', icon: 'fas fa-user-circle', label: '头像上传', enabled: form.allow_avatar_upload },
{ key: 'cover', icon: 'fas fa-image', label: '封面上传', enabled: form.allow_cover_upload },
{ key: 'background', icon: 'fas fa-photo-video', label: '背景图上传', enabled: form.allow_background_upload },
{ key: 'submit', icon: 'fas fa-edit', label: '投稿图片', enabled: form.allow_submit_images },
{ key: 'comment', icon: 'fas fa-comment-dots', label: '评论图片', enabled: form.allow_comment_images },
{ key: 'resource', icon: 'fas fa-file-archive', label: '资源附件', enabled: form.allow_resource_upload },
])
function go(path) {
router.push(path)
}
function goModeration() { router.push('/permissions/moderation') }
async function load() {
loading.value = true
try {
const [permissionRes, moderationRes] = await Promise.all([
api.getPermissionsAttachmentSettings(),
api.getPermissionsModerationSettings(),
])
const permission = permissionRes?.data ?? permissionRes ?? {}
const moderation = moderationRes?.data ?? moderationRes ?? {}
// Map permission fields
form.allow_avatar_upload = permission.allow_avatar_upload !== false
form.allow_cover_upload = permission.allow_cover_upload !== false
form.allow_background_upload = !!permission.allow_background_upload
form.avatar_max_size = Number(permission.avatar_max_size || 2)
form.allow_submit_images = permission.allow_submit_images !== false
form.submit_image_max_size = Number(permission.submit_image_max_size || 5)
form.allow_comment_images = !!permission.allow_comment_images
form.comment_image_max_size = Number(permission.comment_image_max_size || 2)
form.allow_resource_upload = permission.allow_resource_upload !== false
form.resource_max_size = Number(permission.resource_max_size || 50)
form.ai_moderate_background = moderation.ai_moderate_background !== false
form.ai_moderate_submit = !!moderation.ai_moderate_submit
moderationSnapshot.value = { ...moderation }
} catch (error) {
message.error(error.message || '加载附件权限失败')
} finally {
loading.value = false
}
}
async function handleSave() {
saving.value = true
try {
await Promise.all([
api.savePermissionsAttachmentSettings({
allow_avatar_upload: form.allow_avatar_upload,
allow_cover_upload: form.allow_cover_upload,
allow_background_upload: form.allow_background_upload,
avatar_max_size: form.avatar_max_size,
allow_submit_images: form.allow_submit_images,
submit_image_max_size: form.submit_image_max_size,
allow_comment_images: form.allow_comment_images,
comment_image_max_size: form.comment_image_max_size,
allow_resource_upload: form.allow_resource_upload,
resource_max_size: form.resource_max_size,
}),
api.savePermissionsModerationSettings({
...moderationSnapshot.value,
ai_moderate_background: form.ai_moderate_background,
ai_moderate_submit: form.ai_moderate_submit,
}),
])
moderationSnapshot.value = {
...moderationSnapshot.value,
ai_moderate_background: form.ai_moderate_background,
ai_moderate_submit: form.ai_moderate_submit,
}
message.success('附件治理配置已保存')
} catch (error) {
message.error(error.message || '保存失败')
} finally {
saving.value = false
}
}
onMounted(load)
</script>
<style scoped>
.aksrt-attach__summary {
display: flex;
align-items: center;
gap: 10px;
padding: 12px;
border-radius: 6px;
background: #fafafa;
}
.aksrt-attach__summary strong {
display: block;
font-size: 13px;
color: #1a1a2e;
}
.aksrt-attach__summary p {
margin: 2px 0 0;
font-size: 12px;
color: #8a909c;
}
</style>