55 v-model =" dialogVisible"
66 style =" width : 600px "
77 append-to-body
8+ :close-on-click-modal =" false"
9+ :close-on-press-escape =" false"
810 >
911 <div class =" generate-prompt-dialog-bg border-r-8" >
1012 <div class =" scrollbar-height" >
1113 <!-- 生成内容 -->
1214 <div class =" p-16 pb-0 lighter" >
13- <el-scrollbar >
14- <div v-if =" answer" class =" pre-wrap lighter" style =" max-height : calc (100vh - 400px )" >
15+ <el-scrollbar ref =" scrollDiv" >
16+ <div
17+ ref =" dialogScrollbar"
18+ v-if =" answer"
19+ class =" pre-wrap lighter"
20+ style =" max-height : calc (100vh - 400px )"
21+ >
1522 {{ answer }}
1623 </div >
1724 <p v-else-if =" loading" shadow =" always" style =" margin : 0.5rem 0 " >
3845 <div class =" text-center mb-8" v-if =" loading" >
3946 <el-button class =" border-primary video-stop-button" @click =" stopChat" >
4047 <app-icon iconName =" app-video-stop" class =" mr-8" ></app-icon >
41- {{ $t('chat.operation.stopChat') }}
48+ 停止生成
4249 </el-button >
4350 </div >
4451
5158 :placeholder =" $t('views.application.generateDialog.placeholder')"
5259 :maxlength =" 100000"
5360 class =" chat-operate-textarea"
61+ @keydown.enter =" handleSubmit($event)"
5462 />
5563
5664 <div class =" operate" >
7482</template >
7583
7684<script setup lang="ts">
77- import { computed , reactive , ref } from ' vue'
85+ import { computed , reactive , ref , nextTick , watch } from ' vue'
7886import { useRoute } from ' vue-router'
7987import systemGeneratePromptAPI from ' @/api/system-resource-management/application'
8088import generatePromptAPI from ' @/api/application/application'
@@ -108,7 +116,7 @@ const promptTemplates = {
108116
109117请按以下格式生成:
110118
111- # 角色:
119+ # 角色:
112120
113121
114122## 目标:
@@ -129,10 +137,10 @@ const promptTemplates = {
129137
130138
131139## 限制:
132- 1. **严格限制回答范围**:仅回答与角色设定相关的问题。
133- - 如果用户提问与角色无关,必须使用以下固定格式回复:
134- “对不起,我只能回答与【角色设定】相关的问题,您的问题不在服务范围内。”
135- - 不得提供任何与角色设定无关的回答。
140+ 1. **严格限制回答范围**:仅回答与角色设定相关的问题。
141+ - 如果用户提问与角色无关,必须使用以下固定格式回复:
142+ “对不起,我只能回答与【角色设定】相关的问题,您的问题不在服务范围内。”
143+ - 不得提供任何与角色设定无关的回答。
1361442. 描述角色在互动过程中需要遵循的限制条件2
1371453. 描述角色在互动过程中需要遵循的限制条件3
138146 ` ,
@@ -215,20 +223,33 @@ function generatePrompt(inputValue: any) {
215223 prompt: promptTemplates .INIT_TEMPLATE ,
216224 }
217225 if (apiType .value === ' workspace' ) {
218- generatePromptAPI .generate_prompt (workspaceId , modelID .value , applicationID .value ,requestData )
219- .then ((response ) => {
220- const reader = response .body .getReader ()
221- reader .read ().then (getWrite (reader ))
222- })
226+ generatePromptAPI
227+ .generate_prompt (workspaceId , modelID .value , applicationID .value , requestData )
228+ .then ((response ) => {
229+ nextTick (() => {
230+ if (dialogScrollbar .value ) {
231+ // 将滚动条滚动到最下面
232+ scrollDiv .value .setScrollTop (getMaxHeight ())
233+ }
234+ })
235+ const reader = response .body .getReader ()
236+ reader .read ().then (getWrite (reader ))
237+ })
223238 } else if (apiType .value === ' systemManage' ) {
224239 console .log (apiType .value )
225- systemGeneratePromptAPI .generate_prompt (applicationID .value , modelID .value , requestData )
226- .then ((response ) => {
227- const reader = response .body .getReader ()
228- reader .read ().then (getWrite (reader ))
229- })
240+ systemGeneratePromptAPI
241+ .generate_prompt (applicationID .value , modelID .value , requestData )
242+ .then ((response ) => {
243+ nextTick (() => {
244+ if (dialogScrollbar .value ) {
245+ // 将滚动条滚动到最下面
246+ scrollDiv .value .setScrollTop (getMaxHeight ())
247+ }
248+ })
249+ const reader = response .body .getReader ()
250+ reader .read ().then (getWrite (reader ))
251+ })
230252 }
231-
232253}
233254
234255// 重新生成点击
@@ -238,12 +259,35 @@ const reAnswerClick = () => {
238259 }
239260}
240261
241- const handleSubmit = () => {
242- if (! originalUserInput .value ) {
243- originalUserInput .value = inputValue .value
262+ const quickInputRef = ref ()
263+
264+ const handleSubmit = (event ? : any ) => {
265+ if (! event ?.ctrlKey && ! event ?.shiftKey && ! event ?.altKey && ! event ?.metaKey ) {
266+ // 如果没有按下组合键,则会阻止默认事件
267+ event ?.preventDefault ()
268+ if (! originalUserInput .value ) {
269+ originalUserInput .value = inputValue .value
270+ }
271+ generatePrompt (inputValue .value )
272+ inputValue .value = ' '
273+ } else {
274+ // 如果同时按下ctrl/shift/cmd/opt +enter,则会换行
275+ insertNewlineAtCursor (event )
244276 }
245- generatePrompt (inputValue .value )
246- inputValue .value = ' '
277+ }
278+ const insertNewlineAtCursor = (event ? : any ) => {
279+ const textarea = quickInputRef .value .$el .querySelector (
280+ ' .el-textarea__inner' ,
281+ ) as HTMLTextAreaElement
282+ const startPos = textarea .selectionStart
283+ const endPos = textarea .selectionEnd
284+ // 阻止默认行为(避免额外的换行符)
285+ event .preventDefault ()
286+ // 在光标处插入换行符
287+ inputValue .value = inputValue .value .slice (0 , startPos ) + ' \n ' + inputValue .value .slice (endPos )
288+ nextTick (() => {
289+ textarea .setSelectionRange (startPos + 1 , startPos + 1 ) // 光标定位到换行后位置
290+ })
247291}
248292
249293const stopChat = () => {
@@ -259,6 +303,34 @@ const open = (modelId: string, applicationId: string) => {
259303 chatMessages .value = []
260304}
261305
306+ const scrollDiv = ref ()
307+ const dialogScrollbar = ref ()
308+
309+ const getMaxHeight = () => {
310+ return dialogScrollbar .value ! .scrollHeight
311+ }
312+
313+ /**
314+ * 处理跟随滚动条
315+ */
316+ const handleScroll = () => {
317+ if (scrollDiv .value ) {
318+ // 内部高度小于外部高度 就需要出滚动条
319+ if (scrollDiv .value .wrapRef .offsetHeight < dialogScrollbar .value ?.scrollHeight ) {
320+ // 如果当前滚动条距离最下面的距离在 规定距离 滚动条就跟随
321+ scrollDiv .value .setScrollTop (getMaxHeight ())
322+ }
323+ }
324+ }
325+
326+ watch (
327+ answer ,
328+ () => {
329+ handleScroll ()
330+ },
331+ { deep: true , immediate: true },
332+ )
333+
262334defineExpose ({
263335 open ,
264336})
0 commit comments