发信改为事务内每 300 人分批写入,避免全校群发一次插入过大;数据库异常现在返回明确的 503,不再只显示模糊 500。
校级、学院级管理员支持按学院、身份、行政班、教学班、姓名/学号/工号筛选,也可指定最多 500 名收件人。所有结果均由服务端重新校验权限。 接入 CKEditor 5,支持标题、列表、引用和链接;正文扩展为 MySQL longtext。 富文本在收件箱、详情弹窗和已发送记录中统一经 DOMPurify 净化后展示。 页面改用系统现有的冷白、靛蓝、青绿色令牌,新增“选择收件人 → 编辑内容”工作台和移动端适配。
This commit is contained in:
Vendored
+1
@@ -49,6 +49,7 @@ declare module 'vue' {
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTimeSelect: typeof import('element-plus/es')['ElTimeSelect']
|
||||
RichMessageContent: typeof import('./components/RichMessageContent.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import DOMPurify from 'dompurify'
|
||||
|
||||
const props = defineProps<{
|
||||
content: string
|
||||
rich?: boolean
|
||||
}>()
|
||||
|
||||
const safeHtml = computed(() => DOMPurify.sanitize(props.content, {
|
||||
ALLOWED_TAGS: [
|
||||
'p', 'br', 'strong', 'b', 'em', 'i', 'u', 's',
|
||||
'h2', 'h3', 'h4', 'ul', 'ol', 'li', 'blockquote', 'a',
|
||||
],
|
||||
ALLOWED_ATTR: ['href', 'target', 'rel'],
|
||||
ALLOW_DATA_ATTR: false,
|
||||
}))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="rich" class="rich-message-content" v-html="safeHtml" />
|
||||
<p v-else class="plain-message-content">{{ content }}</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.plain-message-content {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.rich-message-content {
|
||||
overflow-wrap: anywhere;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(p),
|
||||
.rich-message-content :deep(ul),
|
||||
.rich-message-content :deep(ol),
|
||||
.rich-message-content :deep(blockquote) {
|
||||
margin: 0 0 .65em;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(p:last-child),
|
||||
.rich-message-content :deep(ul:last-child),
|
||||
.rich-message-content :deep(ol:last-child),
|
||||
.rich-message-content :deep(blockquote:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(h2),
|
||||
.rich-message-content :deep(h3),
|
||||
.rich-message-content :deep(h4) {
|
||||
margin: .8em 0 .35em;
|
||||
color: var(--ink);
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(h2) { font-size: 1.25em; }
|
||||
.rich-message-content :deep(h3) { font-size: 1.12em; }
|
||||
.rich-message-content :deep(h4) { font-size: 1em; }
|
||||
|
||||
.rich-message-content :deep(ul),
|
||||
.rich-message-content :deep(ol) {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(blockquote) {
|
||||
padding: .55em .9em;
|
||||
border-left: 3px solid var(--teal);
|
||||
background: #f3f8f7;
|
||||
}
|
||||
|
||||
.rich-message-content :deep(a) {
|
||||
color: var(--indigo);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user