聊天室更新markdown

This commit is contained in:
2025-12-25 12:33:12 +08:00
parent 41bc41cfcd
commit 78db3fc9e4
9 changed files with 578 additions and 35 deletions

View File

@@ -66,7 +66,7 @@
</view>
<view class="message-content">
<view class="bubble other-bubble">
<text class="message-text">{{ msg.content }}</text>
<rich-text :nodes="renderMarkdown(msg.content || '')" class="message-rich-text"></rich-text>
</view>
<text class="message-time">{{ formatTime(msg.sendTime) }}</text>
</view>
@@ -396,6 +396,42 @@ function formatTime(time?: string): string {
return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
}
// Markdown渲染函数返回富文本HTML
function renderMarkdown(text: string): string {
if (!text) return ''
// 转义HTML特殊字符
let html = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
// 处理粗体(**语法)
html = html.replace(/\*\*([^\*]+)\*\*/g, '<strong>$1</strong>')
// 处理斜体(*语法,但要避免和粗体冲突)
html = html.replace(/(?<!\*)\*([^\*]+)\*(?!\*)/g, '<em>$1</em>')
// 处理行内代码(`语法)
html = html.replace(/`([^`]+)`/g, '<code style="background-color:#f5f5f5;padding:2px 6px;border-radius:3px;font-family:monospace;color:#e53e3e;">$1</code>')
// 处理链接([text](url)语法)
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" style="color:#0055AA;text-decoration:underline;">$1</a>')
// 处理标题(# ## ###等)
html = html.replace(/^### (.+)$/gm, '<div style="font-size:16px;font-weight:600;margin:8px 0 4px;">$1</div>')
html = html.replace(/^## (.+)$/gm, '<div style="font-size:18px;font-weight:600;margin:10px 0 6px;">$1</div>')
html = html.replace(/^# (.+)$/gm, '<div style="font-size:20px;font-weight:700;margin:12px 0 8px;">$1</div>')
// 处理无序列表(- 或 * 开头)
html = html.replace(/^[*-] (.+)$/gm, '<div style="margin-left:16px;">• $1</div>')
// 处理换行
html = html.replace(/\n/g, '<br/>')
return html
}
// 发送消息
async function sendMessage() {
const text = inputText.value.trim()

View File

@@ -24,7 +24,7 @@
<text class="room-time">{{ formatTime(room.lastMessageTime) }}</text>
</view>
<view class="room-footer">
<text class="last-message">{{ room.lastMessage || '暂无消息' }}</text>
<text class="last-message">{{ getPlainTextPreview(room.lastMessage) }}</text>
<view class="unread-badge" v-if="room.unreadCount && room.unreadCount > 0">
<text class="badge-text">{{ room.unreadCount > 99 ? '99+' : room.unreadCount }}</text>
</view>
@@ -136,18 +136,50 @@ function formatTime(time?: string): string {
const iosCompatibleTime = time.replace(' ', 'T')
const date = new Date(iosCompatibleTime)
if (isNaN(date.getTime())) return ''
const now = new Date()
const diff = now.getTime() - date.getTime()
if (diff < 60000) return '刚刚'
if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前'
if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前'
if (diff < 172800000) return '昨天'
return `${date.getMonth() + 1}/${date.getDate()}`
}
// 去除markdown语法并截取前10个字符
function getPlainTextPreview(text?: string): string {
if (!text) return '暂无消息'
// 去除markdown语法
let plainText = text
// 去除代码块
.replace(/```[\s\S]*?```/g, '[代码]')
// 去除行内代码
.replace(/`([^`]+)`/g, '$1')
// 去除粗体
.replace(/\*\*([^\*]+)\*\*/g, '$1')
// 去除斜体
.replace(/\*([^\*]+)\*/g, '$1')
// 去除链接
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
// 去除标题标记
.replace(/^#{1,6}\s+/gm, '')
// 去除列表标记
.replace(/^[*-]\s+/gm, '')
// 去除多余的空白字符
.replace(/\s+/g, ' ')
.trim()
// 截取前10个字符
if (plainText.length > 10) {
return plainText.substring(0, 10) + '...'
}
return plainText
}
// 获取状态样式类
function getStatusClass(status?: string): string {
switch (status) {

View File

@@ -71,7 +71,7 @@
<view class="typing-dot"></view>
<view class="typing-dot"></view>
</view>
<text class="message-text" v-else>{{item.content}}</text>
<rich-text v-else :nodes="renderMarkdown(item.content)" class="message-rich-text"></rich-text>
</view>
</view>
<text class="message-time">{{item.time}}</text>
@@ -503,6 +503,42 @@
await callAIChat(question)
}
// Markdown渲染函数返回富文本节点
function renderMarkdown(text : string) : string {
if (!text) return ''
// 转义HTML特殊字符
let html = text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
// 处理粗体(**语法)
html = html.replace(/\*\*([^\*]+)\*\*/g, '<strong>$1</strong>')
// 处理斜体(*语法,但要避免和粗体冲突)
html = html.replace(/(?<!\*)\*([^\*]+)\*(?!\*)/g, '<em>$1</em>')
// 处理行内代码(`语法)
html = html.replace(/`([^`]+)`/g, '<code style="background-color:#f5f5f5;padding:2px 6px;border-radius:3px;font-family:monospace;color:#e53e3e;">$1</code>')
// 处理链接([text](url)语法)
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" style="color:#0055AA;text-decoration:underline;">$1</a>')
// 处理标题(# ## ###等)
html = html.replace(/^### (.+)$/gm, '<div style="font-size:16px;font-weight:600;margin:8px 0 4px;">$1</div>')
html = html.replace(/^## (.+)$/gm, '<div style="font-size:18px;font-weight:600;margin:10px 0 6px;">$1</div>')
html = html.replace(/^# (.+)$/gm, '<div style="font-size:20px;font-weight:700;margin:12px 0 8px;">$1</div>')
// 处理无序列表(- 或 * 开头)
html = html.replace(/^[*-] (.+)$/gm, '<div style="margin-left:16px;">• $1</div>')
// 处理换行
html = html.replace(/\n/g, '<br/>')
return html
}
// 显示上传选项
function showUploadOptions() {
uni.showActionSheet({

View File

@@ -2,7 +2,7 @@
"libVersion": "3.12.1",
"projectname": "workcase_wechat",
"setting": {
"urlCheck": true,
"urlCheck": false,
"coverView": true,
"lazyloadPlaceholderEnable": false,
"skylineRenderEnable": false,