Skip to content

Commit 32f0495

Browse files
feat: Assistant embedded
1 parent 08fe710 commit 32f0495

File tree

9 files changed

+298
-10
lines changed

9 files changed

+298
-10
lines changed

frontend/assistant.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite-sqlbot.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>SQLBot</title>
8+
</head>
9+
<body style="height: 100vh">
10+
<div id="sqlbot_embedded_app"></div>
11+
<script type="module" src="/src/main_assistant.ts"></script>
12+
</body>
13+
<style>
14+
#sqlbot_embedded_app {
15+
width: 100%;
16+
height: 100%;
17+
}
18+
</style>
19+
</html>
52.5 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading

frontend/src/main_assistant.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createApp } from 'vue'
2+
import './style.less'
3+
import App from './App.vue'
4+
import router from './router/assistant'
5+
import { i18n } from './i18n'
6+
7+
const app = createApp(App)
8+
9+
app.use(router)
10+
app.use(i18n)
11+
app.mount('#sqlbot_embedded_app')

frontend/src/router/assistant.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { createRouter, createWebHashHistory } from 'vue-router'
2+
3+
import assistant from '@/views/embedded/assistant.vue'
4+
import { watchRouter } from './watch_assistant'
5+
const router = createRouter({
6+
history: createWebHashHistory(),
7+
routes: [
8+
{
9+
path: '/',
10+
name: 'index',
11+
component: assistant,
12+
},
13+
{
14+
path: '/assistant',
15+
name: 'assistant',
16+
component: assistant,
17+
},
18+
],
19+
})
20+
watchRouter(router)
21+
export default router
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ElMessage } from 'element-plus-secondary'
2+
3+
import { request } from '@/utils/request'
4+
5+
export const watchRouter = (router: any) => {
6+
router.beforeEach(async (to: any, from: any, next: any) => {
7+
console.log(to, from)
8+
await loadXpackStatic()
9+
next()
10+
})
11+
}
12+
const loadXpackStatic = () => {
13+
if (document.getElementById('sqlbot_xpack_static')) {
14+
return Promise.resolve()
15+
}
16+
const url = '/xpack_static/license-generator.umd.js'
17+
return new Promise((resolve, reject) => {
18+
request
19+
.loadRemoteScript(url, 'sqlbot_xpack_static', () => {
20+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
21+
// @ts-ignore
22+
LicenseGenerator?.init(import.meta.env.VITE_API_BASE_URL).then(() => {
23+
resolve(true)
24+
})
25+
})
26+
.catch((error) => {
27+
console.error('Failed to load xpack_static script:', error)
28+
ElMessage.error('Failed to load license generator script')
29+
reject(error)
30+
})
31+
})
32+
}

frontend/src/views/chat/index.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,20 @@ const handleCtrlEnter = (e: KeyboardEvent) => {
645645
textarea.selectionStart = textarea.selectionEnd = start + 1
646646
})
647647
}
648+
649+
const getHistoryList = () => {
650+
return chatList.value
651+
}
652+
const getCurrentChatId = () => {
653+
return currentChatId.value
654+
}
655+
defineExpose({
656+
getHistoryList,
657+
onClickHistory,
658+
onChatDeleted,
659+
onChatRenamed,
660+
getCurrentChatId,
661+
})
648662
</script>
649663

650664
<style lang="less" scoped>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<template>
2+
<div class="sqlbot-assistant-container">
3+
<div class="head">
4+
<div class="flex align-center">
5+
<div class="head-img-div">
6+
<img :src="AssistantGif" />
7+
</div>
8+
<h4>SQLBot 小助手</h4>
9+
</div>
10+
</div>
11+
<chat-component ref="chatRef" class="sqlbot-chat-container" />
12+
</div>
13+
<div class="sqlbot-top-btn">
14+
<el-icon style="cursor: pointer" @click="openHistory">
15+
<history></history>
16+
</el-icon>
17+
</div>
18+
<div class="sqlbot-history-container">
19+
<el-drawer
20+
v-model="drawer"
21+
:append-to-body="false"
22+
class="sqlbot-history-drawer"
23+
modal-class="sqlbot-history-modal"
24+
title=""
25+
direction="ttb"
26+
:with-header="false"
27+
>
28+
<div class="sqlbot-history-title">
29+
<span>历史记录</span>
30+
</div>
31+
<div class="sqlbot-history-content">
32+
<div v-if="!chatList.length" class="history-empty">
33+
<span>暂无历史记录</span>
34+
</div>
35+
<div v-else class="sqlbot-chat-list-inner">
36+
<el-scrollbar max-height="350px" class="sqlbot-chat-scroller">
37+
<template v-for="chat in chatList" :key="chat.id">
38+
<div
39+
class="chat-list-item"
40+
:class="{ 'is-active-chat': currentId === chat.id }"
41+
@click="onClickHistory(chat)"
42+
>
43+
<span class="title">{{ chat.brief ?? 'Untitled' }}</span>
44+
<div class="history-operate">
45+
<el-icon @click="EditPen(chat)"><IconOpeEdit /></el-icon>
46+
<el-icon @click="Delete(chat)"><IconOpeDelete /></el-icon>
47+
</div>
48+
</div>
49+
</template>
50+
</el-scrollbar>
51+
</div>
52+
</div>
53+
</el-drawer>
54+
</div>
55+
</template>
56+
<script setup lang="ts">
57+
import { ref } from 'vue'
58+
import ChatComponent from '@/views/chat/index.vue'
59+
import AssistantGif from '@/assets/img/assistant.gif'
60+
import history from '@/assets/svg/chart/history.svg'
61+
import IconOpeEdit from '@/assets/svg/operate/ope-edit.svg'
62+
import IconOpeDelete from '@/assets/svg/operate/ope-delete.svg'
63+
64+
const chatRef = ref()
65+
const chatList = ref<Array<any>>([])
66+
const drawer = ref(false)
67+
const currentId = ref()
68+
69+
const openHistory = () => {
70+
chatList.value = chatRef.value?.getHistoryList()
71+
currentId.value = chatRef.value?.getCurrentChatId()
72+
drawer.value = true
73+
}
74+
const onClickHistory = (chat: any) => {
75+
chatRef.value?.onClickHistory(chat)
76+
}
77+
78+
const EditPen = (chat: any) => {
79+
chatRef.value?.onChatRenamed(chat)
80+
}
81+
const Delete = (chat: any) => {
82+
chatRef.value?.onChatDeleted(chat.id)
83+
}
84+
</script>
85+
86+
<style lang="less" scoped>
87+
.sqlbot-assistant-container {
88+
height: 100%;
89+
width: 100%;
90+
color: rgb(31, 35, 41);
91+
.flex {
92+
display: flex;
93+
}
94+
.head {
95+
background: linear-gradient(90deg, #ebf1ff 24.34%, #e5fbf8 56.18%, #f2ebfe 90.18%);
96+
position: fixed;
97+
width: 100%;
98+
left: 0;
99+
top: 0;
100+
z-index: 100;
101+
height: 56px;
102+
line-height: 56px;
103+
box-sizing: border-box;
104+
border-bottom: 1px solid #dee0e3;
105+
.align-center {
106+
align-items: center;
107+
.head-img-div {
108+
display: flex;
109+
margin-left: 24px;
110+
img {
111+
width: 32px;
112+
height: 32px;
113+
}
114+
}
115+
}
116+
}
117+
.sqlbot-chat-container {
118+
padding-top: 56px;
119+
:deep(.ed-aside) {
120+
display: none;
121+
}
122+
}
123+
}
124+
.sqlbot-top-btn {
125+
right: 85px;
126+
z-index: 2009;
127+
position: absolute;
128+
top: 16px;
129+
// right: 16px;
130+
font-size: 22px;
131+
}
132+
.sqlbot-history-container {
133+
width: 100%;
134+
:deep(.sqlbot-history-modal) {
135+
top: 56px !important;
136+
}
137+
:deep(.sqlbot-history-title) {
138+
border-bottom: 1px solid #dee0e3;
139+
padding: 16px 24px;
140+
font-size: 14px;
141+
font-weight: 500;
142+
color: #1f2329;
143+
}
144+
:deep(.ed-drawer__body) {
145+
padding: 0 !important;
146+
}
147+
:deep(.sqlbot-history-drawer) {
148+
height: fit-content !important;
149+
.sqlbot-history-content {
150+
padding: 16px;
151+
.history-empty {
152+
height: 60px;
153+
color: #8f959e !important;
154+
display: flex;
155+
align-items: center;
156+
justify-content: center;
157+
font-size: 14px;
158+
}
159+
.is-active-chat {
160+
background-color: #ebf1ff;
161+
color: #3370ff;
162+
font-weight: 500;
163+
}
164+
.chat-list-item {
165+
display: flex;
166+
align-items: center;
167+
padding: 10px 8px;
168+
font-size: 14px;
169+
color: #1f2329;
170+
justify-content: space-between;
171+
.history-operate {
172+
display: none;
173+
}
174+
&:hover {
175+
cursor: pointer;
176+
border-radius: 4px;
177+
background: rgba(31, 35, 41, 0.1);
178+
.history-operate {
179+
padding-right: 16px;
180+
display: flex;
181+
column-gap: 16px;
182+
align-items: center;
183+
font-size: 18px;
184+
i {
185+
color: #8f959e;
186+
&:hover {
187+
color: #8f959e99;
188+
}
189+
}
190+
}
191+
}
192+
}
193+
}
194+
}
195+
}
196+
</style>

frontend/vite.config.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,17 @@ export default defineConfig(({ mode }) => {
3939
build: {
4040
chunkSizeWarningLimit: 2000,
4141
rollupOptions: {
42+
input: {
43+
main: path.resolve(__dirname, 'index.html'),
44+
assistant: path.resolve(__dirname, 'assistant.html'),
45+
},
4246
output: {
4347
manualChunks: {
4448
'element-plus-secondary': ['element-plus-secondary'],
4549
},
4650
},
4751
},
4852
},
49-
// server: {
50-
// proxy: {
51-
// '/api': {
52-
// target: 'https://sqlbot.fit2cloud.cn',
53-
// changeOrigin: true,
54-
// rewrite: path => path.replace(/^\/api/, 'api')
55-
// }
56-
// },
57-
// port: 8080
58-
// },
5953
esbuild: {
6054
jsxFactory: 'h',
6155
jsxFragment: 'Fragment',

0 commit comments

Comments
 (0)