增加公告图片编辑, 增加取消归档
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { Marked } from 'marked'
|
||||
|
||||
const announcementMarkdown = new Marked({
|
||||
breaks: true,
|
||||
gfm: true,
|
||||
renderer: {
|
||||
html() {
|
||||
return ''
|
||||
},
|
||||
link({ href, title, tokens }) {
|
||||
const text = this.parser.parseInline(tokens)
|
||||
if (!isSafeMarkdownURL(href)) return text
|
||||
const safeTitle = title ? ` title="${escapeHTMLAttribute(title)}"` : ''
|
||||
return `<a href="${escapeHTMLAttribute(href)}"${safeTitle} target="_blank" rel="noopener noreferrer">${text}</a>`
|
||||
},
|
||||
image({ href, title, text }) {
|
||||
if (!isSafeMarkdownURL(href)) return ''
|
||||
const imageText = parseImageText(text)
|
||||
const safeTitle = title ? ` title="${escapeHTMLAttribute(title)}"` : ''
|
||||
const widthStyle = imageText.width
|
||||
? ` style="width:${imageText.width}px;max-width:100%;height:auto;"`
|
||||
: ''
|
||||
return `<img src="${escapeHTMLAttribute(href)}" alt="${escapeHTMLAttribute(imageText.alt)}"${safeTitle}${widthStyle}>`
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export function renderAnnouncementMarkdown(content: string) {
|
||||
return announcementMarkdown.parse(content) as string
|
||||
}
|
||||
|
||||
function isSafeMarkdownURL(url: string) {
|
||||
const value = url.trim().toLowerCase()
|
||||
return (
|
||||
value.startsWith('/') ||
|
||||
value.startsWith('http://') ||
|
||||
value.startsWith('https://') ||
|
||||
value.startsWith('mailto:')
|
||||
)
|
||||
}
|
||||
|
||||
function escapeHTMLAttribute(value: string) {
|
||||
return value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
}
|
||||
|
||||
function parseImageText(text: string) {
|
||||
const matched = text.match(/^(.*?)(?:\|w=(\d{2,4}))$/)
|
||||
if (!matched) return { alt: text }
|
||||
|
||||
const width = Number(matched[2])
|
||||
if (!Number.isFinite(width) || width < 120 || width > 1200) return { alt: text }
|
||||
return {
|
||||
alt: matched[1] || '',
|
||||
width,
|
||||
}
|
||||
}
|
||||
@@ -11,25 +11,19 @@ import {
|
||||
Warning,
|
||||
} from '@element-plus/icons-vue'
|
||||
import { fetchAnnouncementDetail, type Announcement } from '@/features/announcement'
|
||||
import { renderAnnouncementMarkdown } from '@/features/announcement/utils/markdown'
|
||||
import { debugError } from '@/shared/utils/debug'
|
||||
import { formatDateTime } from '@/shared/utils/time'
|
||||
import { marked } from 'marked'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const announcement = ref<Announcement | null>(null)
|
||||
|
||||
// 配置 marked 选项
|
||||
marked.setOptions({
|
||||
breaks: true, // 支持换行
|
||||
gfm: true, // GitHub Flavored Markdown
|
||||
})
|
||||
|
||||
// 计算属性:将 Markdown 转换为 HTML
|
||||
const renderedContent = computed(() => {
|
||||
if (!announcement.value?.content) return ''
|
||||
return marked.parse(announcement.value.content)
|
||||
return renderAnnouncementMarkdown(announcement.value.content)
|
||||
})
|
||||
|
||||
const categories = [
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import { marked } from 'marked'
|
||||
import { fetchAnnouncementDetail, type Announcement } from '@/features/announcement'
|
||||
import { renderAnnouncementMarkdown } from '@/features/announcement/utils/markdown'
|
||||
import { formatDateTime } from '@/shared/utils/time'
|
||||
|
||||
const route = useRoute()
|
||||
@@ -11,11 +11,6 @@ const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const announcement = ref<Announcement | null>(null)
|
||||
|
||||
marked.setOptions({
|
||||
breaks: true,
|
||||
gfm: true,
|
||||
})
|
||||
|
||||
const categories = [
|
||||
{ value: 'notice', label: '通知公告' },
|
||||
{ value: 'tutorial', label: '使用教程' },
|
||||
@@ -25,7 +20,7 @@ const categories = [
|
||||
|
||||
const renderedContent = computed(() => {
|
||||
if (!announcement.value?.content) return ''
|
||||
return marked.parse(announcement.value.content)
|
||||
return renderAnnouncementMarkdown(announcement.value.content)
|
||||
})
|
||||
|
||||
onMounted(loadAnnouncement)
|
||||
|
||||
Reference in New Issue
Block a user