Skip to content

Commit 19fabbc

Browse files
shaohuzhang1wxg0103
authored andcommitted
feat: AI dialog box, left mouse button menu (#2005)
1 parent 6147719 commit 19fabbc

File tree

6 files changed

+119
-2
lines changed

6 files changed

+119
-2
lines changed

ui/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
"vue-clipboard3": "^2.0.0",
4848
"vue-codemirror": "^6.1.1",
4949
"vue-i18n": "^9.13.1",
50-
"vue-router": "^4.2.4"
50+
"vue-router": "^4.2.4",
51+
"vue3-menus": "^1.1.2"
5152
},
5253
"devDependencies": {
5354
"@rushstack/eslint-patch": "^1.3.2",

ui/src/components/ai-chat/component/answer-content/index.vue

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<img v-if="application.avatar" :src="application.avatar" height="32px" width="32px" />
66
<LogoIcon v-else height="32px" width="32px" />
77
</div>
8-
<div class="content">
8+
<div class="content" @click.stop @mouseup="openControl">
99
<el-card shadow="always" class="dialog-card mb-8">
1010
<MdRenderer
1111
v-if="
@@ -56,6 +56,7 @@ import MdRenderer from '@/components/markdown/MdRenderer.vue'
5656
import OperationButton from '@/components/ai-chat/component/operation-button/index.vue'
5757
import { type chatType } from '@/api/type/application'
5858
import { computed } from 'vue'
59+
import bus from '@/bus'
5960
const props = defineProps<{
6061
chatRecord: chatType
6162
application: any
@@ -79,6 +80,13 @@ const chatMessage = (question: string, type: 'old' | 'new', other_params_data?:
7980
const add_answer_text_list = (answer_text_list: Array<any>) => {
8081
answer_text_list.push({ content: '' })
8182
}
83+
84+
const openControl = (event: any) => {
85+
if (props.type !== 'log') {
86+
bus.emit('open-control', event)
87+
}
88+
}
89+
8290
const answer_text_list = computed(() => {
8391
return props.chatRecord.answer_text_list.map((item) => {
8492
if (typeof item == 'string') {

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

+4
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ import { MsgAlert } from '@/utils/message'
182182
import { type chatType } from '@/api/type/application'
183183
import { useRoute, useRouter } from 'vue-router'
184184
import { getImgUrl } from '@/utils/utils'
185+
import bus from '@/bus'
185186
import 'recorder-core/src/engine/mp3'
186187
187188
import 'recorder-core/src/engine/mp3-engine'
@@ -542,6 +543,9 @@ function mouseleave() {
542543
}
543544
544545
onMounted(() => {
546+
bus.on('chat-input', (message: string) => {
547+
inputValue.value = message
548+
})
545549
if (question) {
546550
inputValue.value = decodeURIComponent(question.trim())
547551
sendChatHandle()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<template>
2+
<div>
3+
<vue3-menus v-model:open="isOpen" :event="eventVal" :menus="menus" hasIcon>
4+
<template #icon="{ menu }"
5+
><AppIcon v-if="menu.icon" :iconName="menu.icon"></AppIcon
6+
></template>
7+
<template #label="{ menu }"> {{ menu.label }}</template>
8+
</vue3-menus>
9+
</div>
10+
</template>
11+
<script setup lang="ts">
12+
import { Vue3Menus } from 'vue3-menus'
13+
import { MsgSuccess } from '@/utils/message'
14+
import AppIcon from '@/components/icons/AppIcon.vue'
15+
import bus from '@/bus'
16+
import { ref, nextTick, onMounted } from 'vue'
17+
const isOpen = ref<boolean>(false)
18+
const eventVal = ref({})
19+
function getSelection() {
20+
const selection = window.getSelection()
21+
if (selection && selection.anchorNode == null) {
22+
return null
23+
}
24+
const text = selection?.anchorNode?.textContent
25+
return text && text.substring(selection.anchorOffset, selection.focusOffset)
26+
}
27+
/**
28+
* 打开控制台
29+
* @param event
30+
*/
31+
const openControl = (event: any) => {
32+
const c = getSelection()
33+
isOpen.value = false
34+
if (c) {
35+
nextTick(() => {
36+
eventVal.value = event
37+
isOpen.value = true
38+
})
39+
event.preventDefault()
40+
}
41+
}
42+
43+
const menus = ref([
44+
{
45+
label: '复制',
46+
icon: 'app-copy',
47+
click: () => {
48+
const selectionText = getSelection()
49+
if (selectionText) {
50+
clearSelectedText()
51+
navigator.clipboard.writeText(selectionText).then(() => {
52+
MsgSuccess('复制成功')
53+
})
54+
}
55+
}
56+
},
57+
{
58+
label: '引用',
59+
icon: 'app-quote',
60+
click: () => {
61+
bus.emit('chat-input', getSelection())
62+
clearSelectedText()
63+
}
64+
}
65+
])
66+
/**
67+
* 清除选中文本
68+
*/
69+
const clearSelectedText = () => {
70+
if (window.getSelection) {
71+
var selection = window.getSelection()
72+
if (selection) {
73+
selection.removeAllRanges()
74+
}
75+
}
76+
}
77+
onMounted(() => {
78+
bus.on('open-control', openControl)
79+
})
80+
</script>
81+
<style lang="scss"></style>

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

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
>
4747
<template #operateBefore> <slot name="operateBefore" /> </template>
4848
</ChatInputOperate>
49+
<Control></Control>
4950
</div>
5051
</template>
5152
<script setup lang="ts">
@@ -63,6 +64,7 @@ import QuestionContent from '@/components/ai-chat/component/question-content/ind
6364
import ChatInputOperate from '@/components/ai-chat/component/chat-input-operate/index.vue'
6465
import PrologueContent from '@/components/ai-chat/component/prologue-content/index.vue'
6566
import UserForm from '@/components/ai-chat/component/user-form/index.vue'
67+
import Control from '@/components/ai-chat/component/control/index.vue'
6668
defineOptions({ name: 'AiChat' })
6769
const route = useRoute()
6870
const {

ui/src/components/icons/index.ts

+21
Original file line numberDiff line numberDiff line change
@@ -1374,4 +1374,25 @@ export const iconMap: any = {
13741374
])
13751375
}
13761376
},
1377+
'app-quote': {
1378+
iconReader: () => {
1379+
return h('i', [
1380+
h(
1381+
'svg',
1382+
{
1383+
style: { height: '100%', width: '100%' },
1384+
viewBox: '0 0 1024 1024',
1385+
version: '1.1',
1386+
xmlns: 'http://www.w3.org/2000/svg'
1387+
},
1388+
[
1389+
h('path', {
1390+
d: 'M800.768 477.184c-14.336 0-30.72 2.048-45.056 4.096 18.432-51.2 77.824-188.416 237.568-315.392 36.864-28.672-20.48-86.016-59.392-57.344-155.648 116.736-356.352 317.44-356.352 573.44v20.48c0 122.88 100.352 223.232 223.232 223.232S1024 825.344 1024 702.464c0-124.928-100.352-225.28-223.232-225.28zM223.232 477.184c-14.336 0-30.72 2.048-45.056 4.096 18.432-51.2 77.824-188.416 237.568-315.392 36.864-28.672-20.48-86.016-59.392-57.344C200.704 225.28 0 425.984 0 681.984v20.48c0 122.88 100.352 223.232 223.232 223.232s223.232-100.352 223.232-223.232c0-124.928-100.352-225.28-223.232-225.28z',
1391+
fill: 'currentColor'
1392+
})
1393+
]
1394+
)
1395+
])
1396+
}
1397+
}
13771398
}

0 commit comments

Comments
 (0)