Files
urldb/web/components/Admin/AnnouncementConfig.vue
2025-10-20 23:57:27 +08:00

203 lines
6.7 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="space-y-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-2">
<label class="text-lg font-semibold text-gray-800 dark:text-gray-200">公告配置</label>
<span class="text-xs text-gray-500 dark:text-gray-400">开启后可在网站显示公告信息</span>
</div>
<n-button v-if="modelValue.enable_announcements" @click="addAnnouncement" type="primary" size="small">
<template #icon>
<i class="fas fa-plus"></i>
</template>
添加公告
</n-button>
</div>
<n-switch v-model:value="enableAnnouncements" />
<!-- 公告列表 -->
<div v-if="modelValue.enable_announcements && modelValue.announcements && modelValue.announcements.length > 0" class="announcement-list space-y-3">
<div v-for="(announcement, index) in modelValue.announcements" :key="index" class="announcement-item border rounded-lg p-3 bg-gray-50 dark:bg-gray-800">
<div class="flex items-center justify-between mb-2">
<div class="flex items-center space-x-3">
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100">公告 {{ index + 1 }}</h4>
<n-switch :value="announcement.enabled" @update:value="handleEnabledChange(index, $event)" size="small" />
</div>
<div class="flex items-center space-x-1">
<n-button text @click="moveAnnouncementUp(index)" :disabled="index === 0" size="small">
<template #icon>
<i class="fas fa-arrow-up"></i>
</template>
</n-button>
<n-button text @click="moveAnnouncementDown(index)" :disabled="index === modelValue.announcements.length - 1" size="small">
<template #icon>
<i class="fas fa-arrow-down"></i>
</template>
</n-button>
<n-button text @click="removeAnnouncement(index)" type="error" size="small">
<template #icon>
<i class="fas fa-trash"></i>
</template>
</n-button>
</div>
</div>
<div class="space-y-2">
<n-input
:value="announcement.content"
@update:value="handleContentChange(index, $event)"
placeholder="公告内容支持HTML标签"
type="textarea"
:rows="2"
size="small"
/>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
// 公告接口
interface Announcement {
content: string
enabled: boolean
}
// 配置数据接口
interface ConfigData {
enable_announcements: boolean
announcements: Announcement[]
}
// Props
const props = defineProps<{
modelValue: ConfigData
}>()
// Emits
const emit = defineEmits<{
'update:modelValue': [value: ConfigData]
}>()
// 计算属性用于双向绑定
const enableAnnouncements = computed({
get: () => props.modelValue.enable_announcements,
set: (value: boolean) => {
emit('update:modelValue', {
enable_announcements: value,
announcements: props.modelValue.announcements
})
}
})
// 更新数据
const updateValue = (newValue: ConfigData) => {
emit('update:modelValue', newValue)
}
// 监听单个公告内容变化
const handleContentChange = (index: number, content: string) => {
const newAnnouncements = [...props.modelValue.announcements]
newAnnouncements[index] = { ...newAnnouncements[index], content }
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
// 监听单个公告启用状态变化
const handleEnabledChange = (index: number, enabled: boolean) => {
const newAnnouncements = [...props.modelValue.announcements]
newAnnouncements[index] = { ...newAnnouncements[index], enabled }
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
// 计算属性用于公告内容双向绑定
const announcementContent = (index: number) => computed({
get: () => props.modelValue.announcements[index]?.content || '',
set: (value: string) => {
const newAnnouncements = [...props.modelValue.announcements]
newAnnouncements[index] = { ...newAnnouncements[index], content: value }
updateValue({
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
})
// 计算属性用于公告启用状态双向绑定
const announcementEnabled = (index: number) => computed({
get: () => props.modelValue.announcements[index]?.enabled || false,
set: (value: boolean) => {
const newAnnouncements = [...props.modelValue.announcements]
newAnnouncements[index] = { ...newAnnouncements[index], enabled: value }
updateValue({
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
})
// 添加公告
const addAnnouncement = () => {
const newAnnouncements = [...props.modelValue.announcements, {
content: '',
enabled: true
}]
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
// 删除公告
const removeAnnouncement = (index: number) => {
const currentAnnouncements = Array.isArray(props.modelValue.announcements) ? props.modelValue.announcements : []
const newAnnouncements = currentAnnouncements.filter((_, i) => i !== index)
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
// 上移公告
const moveAnnouncementUp = (index: number) => {
if (index > 0) {
const currentAnnouncements = Array.isArray(props.modelValue.announcements) ? props.modelValue.announcements : []
const newAnnouncements = [...currentAnnouncements]
const temp = newAnnouncements[index]
newAnnouncements[index] = newAnnouncements[index - 1]
newAnnouncements[index - 1] = temp
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
}
// 下移公告
const moveAnnouncementDown = (index: number) => {
const currentAnnouncements = Array.isArray(props.modelValue.announcements) ? props.modelValue.announcements : []
if (index < currentAnnouncements.length - 1) {
const newAnnouncements = [...currentAnnouncements]
const temp = newAnnouncements[index]
newAnnouncements[index] = newAnnouncements[index + 1]
newAnnouncements[index + 1] = temp
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
}
}
</script>
<style scoped>
.announcement-list {
max-height: 400px;
overflow-y: auto;
}
</style>