markdown渲染

This commit is contained in:
2025-10-23 18:07:39 +08:00
parent 7dbb8a3a08
commit 229eded27f
3 changed files with 121 additions and 32 deletions

View File

@@ -19,12 +19,16 @@
"@ant-design/icons-vue": "^7.0.1",
"ant-design-vue": "~4.2.6",
"ant-design-x-vue": "^1.3.2",
"highlight.js": "^11.11.1",
"markdown-it": "^14.1.0",
"markdown-it-highlightjs": "^4.2.0",
"pinia": "^3.0.3",
"vue": "^3.5.22",
"vue-router": "^4.6.3"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.2",
"@types/markdown-it": "^14.1.2",
"@types/node": "^22.18.11",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/eslint-config-prettier": "^10.2.0",

79
pnpm-lock.yaml generated
View File

@@ -17,6 +17,15 @@ importers:
ant-design-x-vue:
specifier: ^1.3.2
version: 1.3.2(ant-design-vue@4.2.6(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3))
highlight.js:
specifier: ^11.11.1
version: 11.11.1
markdown-it:
specifier: ^14.1.0
version: 14.1.0
markdown-it-highlightjs:
specifier: ^4.2.0
version: 4.2.0
pinia:
specifier: ^3.0.3
version: 3.0.3(typescript@5.9.3)(vue@3.5.22(typescript@5.9.3))
@@ -30,6 +39,9 @@ importers:
'@tsconfig/node22':
specifier: ^22.0.2
version: 22.0.2
'@types/markdown-it':
specifier: ^14.1.2
version: 14.1.2
'@types/node':
specifier: ^22.18.11
version: 22.18.12
@@ -617,6 +629,15 @@ packages:
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
'@types/linkify-it@5.0.0':
resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==}
'@types/markdown-it@14.1.2':
resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==}
'@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/node@22.18.12':
resolution: {integrity: sha512-BICHQ67iqxQGFSzfCFTT7MRQ5XcBjG5aeKh5Ok38UBbPe5fxTyE+aHFxwVrGyr8GNlqFMLKD1D3P2K/1ks8tog==}
@@ -1155,6 +1176,10 @@ packages:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
@@ -1259,6 +1284,9 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@@ -1282,6 +1310,16 @@ packages:
magic-string@0.30.19:
resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
markdown-it-highlightjs@4.2.0:
resolution: {integrity: sha512-NC7pXE8KkOl6xWJVRNt8p6wgJVznXKsE0HgYGdk6DD2tn1l4L9f0ALf3VIoGVkotNU1uGQatSxfBF1zZPUMmuQ==}
markdown-it@14.1.0:
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
hasBin: true
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
memorystream@0.3.1:
resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
engines: {node: '>= 0.10.0'}
@@ -1434,6 +1472,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -1567,6 +1609,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
uc.micro@2.1.0:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -2191,6 +2236,15 @@ snapshots:
'@types/json-schema@7.0.15': {}
'@types/linkify-it@5.0.0': {}
'@types/markdown-it@14.1.2':
dependencies:
'@types/linkify-it': 5.0.0
'@types/mdurl': 2.0.0
'@types/mdurl@2.0.0': {}
'@types/node@22.18.12':
dependencies:
undici-types: 6.21.0
@@ -2847,6 +2901,8 @@ snapshots:
has-flag@4.0.0: {}
highlight.js@11.11.1: {}
hookable@5.5.3: {}
ignore@5.3.2: {}
@@ -2917,6 +2973,10 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
linkify-it@5.0.0:
dependencies:
uc.micro: 2.1.0
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
@@ -2939,6 +2999,21 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
markdown-it-highlightjs@4.2.0:
dependencies:
highlight.js: 11.11.1
markdown-it@14.1.0:
dependencies:
argparse: 2.0.1
entities: 4.5.0
linkify-it: 5.0.0
mdurl: 2.0.0
punycode.js: 2.3.1
uc.micro: 2.1.0
mdurl@2.0.0: {}
memorystream@0.3.1: {}
merge2@1.4.1: {}
@@ -3067,6 +3142,8 @@ snapshots:
prettier@3.6.2: {}
punycode.js@2.3.1: {}
punycode@2.3.1: {}
queue-microtask@1.2.3: {}
@@ -3196,6 +3273,8 @@ snapshots:
typescript@5.9.3: {}
uc.micro@2.1.0: {}
undici-types@6.21.0: {}
unplugin-utils@0.3.1:

View File

@@ -19,18 +19,14 @@ import {
SmileOutlined,
} from '@ant-design/icons-vue'
import { Badge, Button, Flex, Space, theme } from 'ant-design-vue'
import {
Attachments,
Bubble,
Conversations,
Prompts,
Sender,
Welcome,
} from 'ant-design-x-vue'
import { Attachments, Bubble, Conversations, Prompts, Sender, Welcome } from 'ant-design-x-vue'
import markdownit from 'markdown-it'
import { computed, h, ref, watch } from 'vue'
const { token } = theme.useToken()
const md = markdownit({ html: true, breaks: true })
const styles = computed(() => {
return {
layout: {
@@ -185,6 +181,9 @@ const roles: BubbleListProps['roles'] = {
borderRadius: '16px',
},
},
messageRender: (content) => {
return h('div', { innerHTML: md.render(content) })
},
},
local: {
placement: 'end',
@@ -299,7 +298,8 @@ async function sendMessage(userMessage: string) {
const data = block.substring(5).trim()
console.log('[Parse] 接收到数据:', data)
if (data) { // 若响应数据不为空
if (data) {
// 若响应数据不为空
// 解析 JSON
const response = JSON.parse(data)
console.log('[Parse] 解析后的内容:', JSON.stringify(response))
@@ -381,27 +381,35 @@ const handleFileChange: AttachmentsProps['onChange'] = (info) =>
// ==================== Nodes ====================
const placeholderNode = computed(() =>
h(Space, { direction: 'vertical', size: 16, style: styles.value.placeholder }, () => [
h(Welcome as Component, {
variant: 'borderless',
icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
description: '基于Ant DesignAGI产品界面解决方案创造更美好的智能愿景~',
extra: h(Space, {}, () => [
h(Button, { icon: h(ShareAltOutlined) }),
h(Button, { icon: h(EllipsisOutlined) }),
]),
}, () => "Hello, I'm Ant Design X"),
h(Prompts as Component, {
items: placeholderPromptsItems,
styles: {
list: {
width: '100%',
},
item: {
flex: 1,
},
h(
Welcome as Component,
{
variant: 'borderless',
icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
description: '基于Ant DesignAGI产品界面解决方案创造更美好的智能愿景~',
extra: h(Space, {}, () => [
h(Button, { icon: h(ShareAltOutlined) }),
h(Button, { icon: h(EllipsisOutlined) }),
]),
},
onItemClick: onPromptsItemClick,
}, () => '想要了是吧?'),
() => "Hello, I'm Ant Design X",
),
h(
Prompts as Component,
{
items: placeholderPromptsItems,
styles: {
list: {
width: '100%',
},
item: {
flex: 1,
},
},
onItemClick: onPromptsItemClick,
},
() => '想要了是吧?',
),
]),
)
@@ -512,9 +520,7 @@ const items = computed<BubbleListProps['items']>(() => {
Click or drag files to this area to upload
</div>
</Flex>
<div v-if="type && type.type === 'drop'">
Drop file here
</div>
<div v-if="type && type.type === 'drop'">Drop file here</div>
</template>
</Attachments>
</Sender.Header>