update: 公告支持html

This commit is contained in:
ctwj
2025-10-20 23:57:27 +08:00
parent 921bdc43cb
commit 40ad48f5cf
4 changed files with 109 additions and 23 deletions

View File

@@ -20,7 +20,7 @@
<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 v-model:value="announcement.enabled" size="small" />
<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">
@@ -43,7 +43,8 @@
<div class="space-y-2">
<n-input
v-model:value="announcement.content"
:value="announcement.content"
@update:value="handleContentChange(index, $event)"
placeholder="公告内容支持HTML标签"
type="textarea"
:rows="2"
@@ -89,20 +90,65 @@ const enableAnnouncements = computed({
}
})
console.log(props.modelValue)
// 更新数据
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
}]
updateValue({
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
@@ -112,7 +158,7 @@ const addAnnouncement = () => {
const removeAnnouncement = (index: number) => {
const currentAnnouncements = Array.isArray(props.modelValue.announcements) ? props.modelValue.announcements : []
const newAnnouncements = currentAnnouncements.filter((_, i) => i !== index)
updateValue({
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
@@ -126,7 +172,7 @@ const moveAnnouncementUp = (index: number) => {
const temp = newAnnouncements[index]
newAnnouncements[index] = newAnnouncements[index - 1]
newAnnouncements[index - 1] = temp
updateValue({
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})
@@ -141,7 +187,7 @@ const moveAnnouncementDown = (index: number) => {
const temp = newAnnouncements[index]
newAnnouncements[index] = newAnnouncements[index + 1]
newAnnouncements[index + 1] = temp
updateValue({
emit('update:modelValue', {
enable_announcements: props.modelValue.enable_announcements,
announcements: newAnnouncements
})

View File

@@ -5,7 +5,7 @@
<i class="fas fa-bullhorn text-blue-600 dark:text-blue-400 text-sm flex-shrink-0"></i>
<div class="announcement-content overflow-hidden">
<div class="announcement-item active">
<span class="text-sm text-gray-700 dark:text-gray-300 truncate">{{ validAnnouncements[currentIndex].content }}</span>
<span class="text-sm text-gray-700 dark:text-gray-300 truncate" v-html="validAnnouncements[currentIndex].content"></span>
</div>
</div>
</div>

View File

@@ -71,26 +71,26 @@ export const useConfigChangeDetection = <T extends Record<string, any>>(
}
const changedConfig: Partial<T> = {}
// 遍历所有配置项
for (const key in currentConfig.value) {
const currentValue = currentConfig.value[key]
const originalValue = originalConfig.value[key]
// 使用自定义比较函数或默认比较
const hasChanged = customCompare
const hasChanged = customCompare
? customCompare(key, currentValue, originalValue)
: currentValue !== originalValue
if (hasChanged) {
changedConfig[key as keyof T] = currentValue
}
}
if (debug) {
console.log('useConfigChangeDetection - 检测到的改动:', changedConfig)
}
return changedConfig
}

View File

@@ -318,6 +318,15 @@ const {
saveConfig: saveConfigWithDetection
} = useConfigChangeDetection<SiteConfigForm>({
debug: true,
// 自定义比较函数,处理数组深层比较
customCompare: (key: string, currentValue: any, originalValue: any) => {
// 对于数组类型使用JSON字符串比较
if (Array.isArray(currentValue) && Array.isArray(originalValue)) {
return JSON.stringify(currentValue) !== JSON.stringify(originalValue)
}
// 其他类型使用默认比较
return currentValue !== originalValue
},
// 字段映射:前端字段名 -> 后端字段名
fieldMapping: {
site_title: 'site_title',
@@ -470,37 +479,68 @@ const openLogoSelector = () => {
}
const clearLogo = () => {
configForm.value.site_logo = ''
configForm.value = {
...configForm.value,
site_logo: ''
}
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
// 子组件更新处理方法
const handleAnnouncementUpdate = (newValue: any) => {
configForm.value.enable_announcements = newValue.enable_announcements
configForm.value.announcements = newValue.announcements
// 直接更新整个表单
configForm.value = {
...configForm.value,
enable_announcements: newValue.enable_announcements,
announcements: newValue.announcements
}
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
const handleFloatButtonsUpdate = (newValue: any) => {
configForm.value.enable_float_buttons = newValue.enable_float_buttons
configForm.value.wechat_search_image = newValue.wechat_search_image
configForm.value.telegram_qr_image = newValue.telegram_qr_image
configForm.value = {
...configForm.value,
enable_float_buttons: newValue.enable_float_buttons,
wechat_search_image: newValue.wechat_search_image,
telegram_qr_image: newValue.telegram_qr_image
}
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
// Logo选择处理
const handleLogoSelect = (file: any) => {
configForm.value.site_logo = file.access_url
configForm.value = {
...configForm.value,
site_logo: file.access_url
}
showLogoSelector.value = false
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
// 微信图片选择处理
const handleWechatImageSelect = (file: any) => {
configForm.value.wechat_search_image = file.access_url
configForm.value = {
...configForm.value,
wechat_search_image: file.access_url
}
showWechatSelector.value = false
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
// Telegram图片选择处理
const handleTelegramImageSelect = (file: any) => {
configForm.value.telegram_qr_image = file.access_url
configForm.value = {
...configForm.value,
telegram_qr_image: file.access_url
}
showTelegramSelector.value = false
// 强制触发更新
updateCurrentConfig({ ...configForm.value })
}
// 页面加载时获取配置