Skip to content

Commit 7b51d08

Browse files
feat: Add mobile mode to the conversation, support ctrl/shift/cmd/opt+enter for new line (#2615)
1 parent 9e62e81 commit 7b51d08

File tree

13 files changed

+486
-26
lines changed

13 files changed

+486
-26
lines changed

ui/src/assets/window3.png

9.13 KB
Loading

ui/src/components/ai-chat/component/chat-input-operate/index.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -525,23 +525,25 @@ function autoSendMessage() {
525525
}
526526
527527
function sendChatHandle(event?: any) {
528-
if (!event?.ctrlKey) {
529-
// 如果没有按下组合键ctrl,则会阻止默认事件
528+
if (!event?.ctrlKey && !event?.shiftKey && !event?.altKey && !event?.metaKey) {
529+
// 如果没有按下组合键,则会阻止默认事件
530530
event?.preventDefault()
531531
if (!isDisabledChat.value && !props.loading && !event?.isComposing) {
532532
if (inputValue.value.trim()) {
533533
autoSendMessage()
534534
}
535535
}
536536
} else {
537-
// 如果同时按下ctrl+回车键,则会换行
538-
insertNewlineAtCursor()
537+
// 如果同时按下ctrl/shift/cmd/opt +enter,则会换行
538+
insertNewlineAtCursor(event)
539539
}
540540
}
541-
const insertNewlineAtCursor = () => {
541+
const insertNewlineAtCursor = (event?: any) => {
542542
const textarea = document.querySelector('.el-textarea__inner') as HTMLTextAreaElement
543543
const startPos = textarea.selectionStart
544544
const endPos = textarea.selectionEnd
545+
// 阻止默认行为(避免额外的换行符)
546+
event.preventDefault()
545547
// 在光标处插入换行符
546548
inputValue.value = inputValue.value.slice(0, startPos) + '\n' + inputValue.value.slice(endPos)
547549
nextTick(() => {

ui/src/components/ai-chat/index.vue

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<template>
22
<div ref="aiChatRef" class="ai-chat" :class="type">
33
<div
4-
v-show="(isUserInput && firsUserInput) || showUserInput"
4+
v-show="showUserInputContent"
55
:class="firsUserInput ? 'firstUserInput' : 'popperUserInput'"
66
>
77
<UserForm
@@ -15,7 +15,7 @@
1515
ref="userFormRef"
1616
></UserForm>
1717
</div>
18-
<template v-if="!isUserInput || !firsUserInput">
18+
<template v-if="!isUserInput || !firsUserInput || type === 'log'">
1919
<el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
2020
<div ref="dialogScrollbar" class="ai-chat__content p-24">
2121
<PrologueContent
@@ -62,7 +62,13 @@
6262
<slot name="operateBefore">
6363
<span></span>
6464
</slot>
65-
<el-button class="user-input-button mb-8" type="primary" text @click="toggleUserInput">
65+
<el-button
66+
v-if="isUserInput"
67+
class="user-input-button mb-8"
68+
type="primary"
69+
text
70+
@click="toggleUserInput"
71+
>
6672
<AppIcon iconName="app-user-input"></AppIcon>
6773
</el-button>
6874
</div>
@@ -114,7 +120,7 @@ const props = withDefaults(
114120
const emit = defineEmits(['refresh', 'scroll'])
115121
const { application, common } = useStore()
116122
const isMobile = computed(() => {
117-
return common.isMobile() || mode === 'embed'
123+
return common.isMobile() || mode === 'embed' || mode === 'mobile'
118124
})
119125
const aiChatRef = ref()
120126
const scrollDiv = ref()
@@ -135,7 +141,9 @@ const isUserInput = computed(
135141
props.applicationDetails.work_flow?.nodes?.filter((v: any) => v.id === 'base-node')[0]
136142
.properties.user_input_field_list.length > 0
137143
)
138-
144+
const showUserInputContent = computed(() => {
145+
return ((isUserInput.value && firsUserInput.value) || showUserInput.value) && props.type !== 'log'
146+
})
139147
watch(
140148
() => props.chatId,
141149
(val) => {

ui/src/locales/lang/en-US/ai-chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default {
4848
inputPlaceholder: {
4949
speaking: 'Speaking...',
5050
recorderLoading: 'Transcribing...',
51-
default: 'Type your question, Ctrl+Enter for a new line'
51+
default: 'Type your question'
5252
},
5353
uploadFile: {
5454
label: 'Upload File',

ui/src/locales/lang/en-US/views/application-overview.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ export default {
4141
EmbedDialog: {
4242
fullscreenModeTitle: 'Fullscreen Mode',
4343
copyInstructions: 'Copy the code below to embed',
44-
floatingModeTitle: 'Floating Mode'
44+
floatingModeTitle: 'Floating Mode',
45+
mobileModeTitle: 'Mobile Mode'
4546
},
4647
LimitDialog: {
4748
dialogTitle: 'Access Restrictions',

ui/src/locales/lang/zh-CN/ai-chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default {
4848
inputPlaceholder: {
4949
speaking: '说话中',
5050
recorderLoading: '转文字中',
51-
default: '请输入问题,Ctrl+Enter 换行'
51+
default: '请输入问题'
5252
},
5353
uploadFile: {
5454
label: '上传文件',

ui/src/locales/lang/zh-CN/views/application-overview.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ export default {
4040
EmbedDialog: {
4141
fullscreenModeTitle: '全屏模式',
4242
copyInstructions: '复制以下代码进行嵌入',
43-
floatingModeTitle: '浮窗模式'
43+
floatingModeTitle: '浮窗模式',
44+
mobileModeTitle: '移动端模式'
4445
},
4546
LimitDialog: {
4647
showSourceLabel: '显示知识来源',

ui/src/locales/lang/zh-Hant/ai-chat.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default {
4848
inputPlaceholder: {
4949
speaking: '說話中',
5050
recorderLoading: '轉文字中',
51-
default: '請輸入問題,Ctrl+Enter 換行'
51+
default: '請輸入問題'
5252
},
5353
uploadFile: {
5454
label: '上傳文件',

ui/src/locales/lang/zh-Hant/views/application-overview.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ export default {
3939
EmbedDialog: {
4040
fullscreenModeTitle: '全螢幕模式',
4141
copyInstructions: '複製以下程式碼進行嵌入',
42-
floatingModeTitle: '浮窗模式'
42+
floatingModeTitle: '浮窗模式',
43+
mobileModeTitle: '移動端模式'
4344
},
4445
LimitDialog: {
4546
dialogTitle: '訪問限制',

ui/src/views/application-overview/component/EmbedDialog.vue

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
:close-on-click-modal="false"
88
:close-on-press-escape="false"
99
>
10+
1011
<el-row :gutter="12">
11-
<el-col :span="12">
12+
<el-col :span="8">
1213
<div class="border">
1314
<p class="title p-16 bold">
1415
{{ $t('views.applicationOverview.appInfo.EmbedDialog.fullscreenModeTitle') }}
@@ -31,7 +32,30 @@
3132
</div>
3233
</div>
3334
</el-col>
34-
<el-col :span="12">
35+
<el-col :span="8">
36+
<div class="border">
37+
<p class="title p-16 bold">
38+
{{ $t('views.applicationOverview.appInfo.EmbedDialog.mobileModeTitle') }}
39+
</p>
40+
<img src="@/assets/window3.png" alt="" class="ml-8" height="150" />
41+
<div class="code layout-bg border-t p-8">
42+
<div class="flex-between p-8">
43+
<span class="bold">{{
44+
$t('views.applicationOverview.appInfo.EmbedDialog.copyInstructions')
45+
}}</span>
46+
<el-button text @click="copyClick(source3)">
47+
<AppIcon iconName="app-copy"></AppIcon>
48+
</el-button>
49+
</div>
50+
<el-scrollbar height="150" always>
51+
<div class="pre-wrap p-8 pt-0">
52+
{{ source3 }}
53+
</div>
54+
</el-scrollbar>
55+
</div>
56+
</div>
57+
</el-col>
58+
<el-col :span="8">
3559
<div class="border">
3660
<p class="title p-16 bold">
3761
{{ $t('views.applicationOverview.appInfo.EmbedDialog.floatingModeTitle') }}
@@ -76,6 +100,7 @@ const dialogVisible = ref<boolean>(false)
76100
const source1 = ref('')
77101
78102
const source2 = ref('')
103+
const source3 = ref('')
79104
80105
const urlParams1 = computed(() => (props.apiInputParams ? '?' + props.apiInputParams : ''))
81106
const urlParams2 = computed(() => (props.apiInputParams ? '&' + props.apiInputParams : ''))
@@ -84,6 +109,7 @@ watch(dialogVisible, (bool) => {
84109
if (!bool) {
85110
source1.value = ''
86111
source2.value = ''
112+
source3.value = ''
87113
}
88114
})
89115
@@ -105,6 +131,14 @@ src="${window.location.origin}/api/application/embed?protocol=${window.location.
105131
)}&host=${window.location.host}&token=${val}${urlParams2.value}">
106132
<\/script>
107133
`
134+
source3.value = `<iframe
135+
src="${application.location + val + urlParams1.value}&mode=mobile"
136+
style="width: 100%; height: 100%;"
137+
frameborder="0"
138+
allow="microphone">
139+
</iframe>
140+
`
141+
108142
dialogVisible.value = true
109143
}
110144

ui/src/views/chat/index.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ const {
4141
const is_auth = ref<boolean>(false)
4242
const currentTemplate = computed(() => {
4343
let modeName = ''
44-
if (mode && mode === 'embed') {
45-
modeName = 'embed'
46-
} else {
44+
if (!mode || mode === 'pc') {
4745
modeName = show_history.value || !user.isEnterprise() ? 'pc' : 'base'
46+
} else {
47+
modeName = mode
4848
}
4949
const name = `/src/views/chat/${modeName}/index.vue`
5050
return components[name].default

0 commit comments

Comments
 (0)