3636 <icon-new-session />
3737 </button >
3838 </template >
39- <div v-if =" activeMessages.length === 0" >
40- <tr-welcome title =" AI助手" description =" 您好,我是您的开发小助手" :icon =" welcomeIcon" class =" robot-welcome" >
41- </tr-welcome >
42- <tr-prompts
43- :items =" promptItems"
44- :wrap =" true"
45- item-class =" prompt-item"
46- class =" tiny-prompts"
47- @item-click =" handlePromptItemClick"
48- ></tr-prompts >
39+ <div class =" robot-chat-container-content" ref =" chatContainerRef" >
40+ <div v-if =" activeMessages.length === 0" >
41+ <tr-welcome
42+ title =" AI助手"
43+ description =" 您好,我是您的开发小助手"
44+ :icon =" welcomeIcon"
45+ class =" robot-welcome"
46+ >
47+ </tr-welcome >
48+ <tr-prompts
49+ :items =" promptItems"
50+ :wrap =" true"
51+ item-class =" prompt-item"
52+ class =" tiny-prompts"
53+ @item-click =" handlePromptItemClick"
54+ ></tr-prompts >
55+ </div >
56+ <tr-bubble-provider :content-renderers =" { markdown: MarkdownRenderer }" v-else >
57+ <tr-bubble-list :items =" activeMessages" :roles =" roles" autoScroll ></tr-bubble-list >
58+ </tr-bubble-provider >
4959 </div >
50- <tr-bubble-provider :message-renderers =" { markdown: MarkdownRenderer }" v-else >
51- <tr-bubble-list :items =" activeMessages" :roles =" roles" autoScroll ></tr-bubble-list >
52- </tr-bubble-provider >
5360 <template #footer >
5461 <tr-sender
5562 :maxlength =" 4000"
6168 @submit =" sendContent(inputContent, false)"
6269 >
6370 <template #footer-left >
64- <mcp-server ></mcp-server >
71+ <mcp-server :position = " mcpDrawerPosition " ></mcp-server >
6572 </template >
6673 </tr-sender >
6774 </template >
7380
7481<script lang="ts">
7582/* metaService: engine.plugins.robot.Main */
76- import { ref , onMounted , watchEffect , type CSSProperties , h , resolveComponent } from ' vue'
83+ import { ref , onMounted , watchEffect , type CSSProperties , h , resolveComponent , computed , watch } from ' vue'
7784import { Notify , Loading , TinyPopover } from ' @opentiny/vue'
7885import { useCanvas , useHistory , usePage , useModal , getMetaApi , META_SERVICE } from ' @opentiny/tiny-engine-meta-register'
7986import { extend } from ' @opentiny/vue-renderless/common/object'
@@ -118,6 +125,8 @@ export default {
118125 const tokenValue = ref (' ' )
119126 const showPopover = ref (false )
120127
128+ const chatContainerRef = ref (null )
129+
121130 const { pageSettingState, getDefaultPage } = usePage ()
122131 const ROOT_ID = pageSettingState .ROOT_ID
123132 const sleep = (delay ) => new Promise ((resolve ) => setTimeout (resolve , delay ))
@@ -188,8 +197,7 @@ export default {
188197
189198 const getAiRespMessage = (role = ' assistant' , content ) => ({
190199 role ,
191- content ,
192- name: ' AI'
200+ content
193201 })
194202
195203 const requestLoading = ref (false )
@@ -198,6 +206,7 @@ export default {
198206 if (useMcpServer ().isToolsEnabled ) {
199207 try {
200208 requestLoading .value = true
209+ await scrollContent () // eslint-disable-line
201210 await sendMcpRequest (messages .value , {
202211 model: selectedModel .value .value ,
203212 headers: {
@@ -209,6 +218,7 @@ export default {
209218 } finally {
210219 inProcesing .value = false
211220 requestLoading .value = false
221+ await scrollContent () // eslint-disable-line
212222 }
213223 return
214224 }
@@ -237,10 +247,8 @@ export default {
237247 }
238248
239249 const scrollContent = async () => {
240- await sleep (100 )
241- const scrollElement = document .getElementById (' chatgpt-window' )
242- if (scrollElement ) {
243- scrollElement .scrollTop = scrollElement .scrollHeight
250+ if (chatContainerRef .value ) {
251+ chatContainerRef .value .scrollTop = chatContainerRef .value .scrollHeight
244252 }
245253 }
246254
@@ -257,8 +265,7 @@ export default {
257265
258266 const getMessage = (content ) => ({
259267 role: ' user' ,
260- content ,
261- name: ' John'
268+ content
262269 })
263270
264271 const sendContent = async (content , isModel ) => {
@@ -412,11 +419,33 @@ export default {
412419
413420 // 对话角色配置
414421 const roles: Record <string , BubbleRoleConfig > = {
415- assistant: { placement: ' start' , avatar: aiAvatar , maxWidth: ' 90%' , contentRenderer: MarkdownRenderer },
422+ assistant: {
423+ placement: ' start' ,
424+ avatar: aiAvatar ,
425+ maxWidth: ' 90%' ,
426+ contentRenderer: MarkdownRenderer ,
427+ customContentField: ' renderContent'
428+ },
416429 user: { placement: ' end' , avatar: userAvatar , maxWidth: ' 90%' , contentRenderer: MarkdownRenderer }
417430 }
418431
432+ watch ([activeMessages .value .length , activeMessages .value .at (- 1 )?.renderContent ?.length ], async () => {
433+ await scrollContent ()
434+ })
435+
436+ const mcpDrawerPosition = computed (() => {
437+ return {
438+ type: ' fixed' ,
439+ position: {
440+ top: ' var(--base-top-panel-height)' ,
441+ bottom: 0 ,
442+ ... (fullscreen .value ? { left: 0 } : { right: ' var(--tr-container-width)' })
443+ }
444+ }
445+ })
446+
419447 return {
448+ chatContainerRef ,
420449 robotVisible ,
421450 avatarUrl ,
422451 chatWindowOpened ,
@@ -440,7 +469,8 @@ export default {
440469 welcomeIcon ,
441470 roles ,
442471 MarkdownRenderer ,
443- requestLoading
472+ requestLoading ,
473+ mcpDrawerPosition
444474 }
445475 }
446476}
@@ -486,10 +516,38 @@ export default {
486516 }
487517
488518 .tr-bubble-list {
519+ font-size : 14px ;
489520 flex : 1 ;
490521 .tr-bubble {
491522 word-break : break-word ;
492523 }
524+ ul ,
525+ ol {
526+ padding-left : 10px ;
527+ }
528+ ul > li {
529+ list-style : disc ;
530+ }
531+ ol > li {
532+ list-style : decimal ;
533+ }
534+ table {
535+ border-collapse : collapse ; // 合并边框
536+ border : 1px solid #ccc ;
537+ width : 100% ;
538+ margin : 1rem 0 ;
539+ th ,
540+ td {
541+ border : 1px solid #ccc ; /* 单元格边框 */
542+ padding : 8px ;
543+ }
544+ tr :nth- child(even) {
545+ background-color : #f2f2f2 ;
546+ }
547+ tr :hover {
548+ background-color : #e6f7ff ;
549+ }
550+ }
493551 }
494552
495553 .robot-welcome > div {
0 commit comments