支持消息 Markdown 与欢迎语富文本

聊天/离线提示使用 Markdown 安全渲染;欢迎语改为 TipTap 富文本(颜色字号),DOMPurify 白名单清洗后展示。
This commit is contained in:
yml2213
2026-07-19 00:03:05 +08:00
parent 970bae16d1
commit fea5f4acf5
12 changed files with 3235 additions and 32 deletions
+25 -13
View File
@@ -16,6 +16,8 @@ import {
type Channel, type CustomerTag, type StaffUser, type TenantSettings, type WorkHours, type WelcomeSegment,
} from '@/services/api'
import { useAuth } from '@/stores/auth'
import MarkdownEditor from '@/components/common/MarkdownEditor'
import RichTextEditor from '@/components/common/RichTextEditor'
const tagColorPresets: { value: string; label: string; bg: string; color: string }[] = [
{ value: 'amber', label: '琥珀', bg: '#fef3c7', color: '#92400e' },
@@ -834,9 +836,12 @@ const Settings = () => {
}
for (let i = 0; i < welcomeSegments.length; i++) {
const seg = welcomeSegments[i]
if (seg.type === 'text' && !seg.content.trim()) {
message.error(`第 ${i + 1} 段文本不能为空`)
return
if (seg.type === 'text') {
const plain = seg.content.replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').trim()
if (!plain) {
message.error(`第 ${i + 1} 段文本不能为空`)
return
}
}
if (seg.type === 'image' && !seg.content.trim()) {
message.error(`第 ${i + 1} 段请上传图片`)
@@ -857,7 +862,8 @@ const Settings = () => {
<div>
<div className="text-sm font-medium text-neutral-800">欢迎语(多段)</div>
<p className="text-xs text-neutral-500 m-0 mt-0.5">
访客打开窗口且尚无消息时按顺序展示;可混排文本与图片,最多 {MAX_WELCOME_SEGMENTS} 段。
访客打开窗口且尚无消息时按顺序展示;可混排富文本与图片,最多 {MAX_WELCOME_SEGMENTS} 段。
选中文字可设置<strong className="font-medium text-neutral-600">颜色、字号、加粗</strong>等(仅欢迎语;正常聊天仍为 Markdown)。
</p>
</div>
</div>
@@ -913,14 +919,10 @@ const Settings = () => {
</div>
</div>
{seg.type === 'text' ? (
<Input.TextArea
rows={2}
maxLength={500}
showCount
<RichTextEditor
value={seg.content}
placeholder="访客打开窗口时展示的文案"
onChange={e => {
const v = e.target.value
placeholder="输入欢迎语,选中文字后设置颜色、字号…"
onChange={v => {
setWelcomeSegments(prev =>
prev.map((s, i) => (i === idx ? { ...s, content: v } : s)),
)
@@ -1006,8 +1008,18 @@ const Settings = () => {
</Button>
</div>
</div>
<Form.Item name="offline_prompt" label="离线留言提示" rules={[{ max: 500 }]}>
<Input.TextArea rows={3} maxLength={500} showCount placeholder="无客服在线时展示" />
<Form.Item
name="offline_prompt"
label="离线留言提示"
rules={[{ max: 500 }]}
extra="点工具栏设置加粗、列表、链接、表情;可点「预览」查看效果"
>
<MarkdownEditor
rows={3}
maxLength={500}
showCount
placeholder="无客服在线时展示…"
/>
</Form.Item>
<Form.Item className="!mb-0">
<Button type="primary" htmlType="submit" loading={saving}>保存</Button>