feat: Assistant embedded

This commit is contained in:
fit2cloud-chenyw
2025-07-09 15:03:20 +08:00
parent 08fe710b8c
commit 32f0495f91
9 changed files with 298 additions and 10 deletions
+19
View File
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite-sqlbot.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SQLBot</title>
</head>
<body style="height: 100vh">
<div id="sqlbot_embedded_app"></div>
<script type="module" src="/src/main_assistant.ts"></script>
</body>
<style>
#sqlbot_embedded_app {
width: 100%;
height: 100%;
}
</style>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1752032446737" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4503" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M974.754909 315.345455c108.613818 232.913455 7.842909 509.789091-225.093818 618.402909A465.454545 465.454545 0 0 1 230.4 847.546182a46.545455 46.545455 0 0 1 64.488727-67.118546 372.363636 372.363636 0 0 0 415.418182 68.957091c186.344727-86.877091 266.961455-308.363636 180.084364-494.708363C803.490909 168.331636 582.004364 87.738182 395.636364 174.615273a371.805091 371.805091 0 0 0-188.462546 199.377454l63.069091 5.306182a23.272727 23.272727 0 0 1 17.198546 36.468364l-123.857455 178.269091a46.312727 46.312727 0 0 1-41.588364 19.781818 41.634909 41.634909 0 0 1-35.770181-26.926546L12.893091 391.051636a23.272727 23.272727 0 0 1 23.738182-31.371636l74.472727 6.260364A464.896 464.896 0 0 1 356.305455 90.251636C589.265455-18.385455 866.141091 82.385455 974.754909 315.322182zM529.733818 232.727273a46.545455 46.545455 0 0 1 46.405818 43.054545l0.139637 3.490909v228.887273l139.473454 79.802182a46.545455 46.545455 0 0 1 18.967273 60.276363l-1.675636 3.258182a46.545455 46.545455 0 0 1-60.276364 18.944l-3.258182-1.675636-151.179636-86.481455a69.818182 69.818182 0 0 1-35.002182-55.924363l-0.139636-4.677818V279.272727a46.545455 46.545455 0 0 1 46.545454-46.545454z" fill="" p-id="4504"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+11
View File
@@ -0,0 +1,11 @@
import { createApp } from 'vue'
import './style.less'
import App from './App.vue'
import router from './router/assistant'
import { i18n } from './i18n'
const app = createApp(App)
app.use(router)
app.use(i18n)
app.mount('#sqlbot_embedded_app')
+21
View File
@@ -0,0 +1,21 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import assistant from '@/views/embedded/assistant.vue'
import { watchRouter } from './watch_assistant'
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
name: 'index',
component: assistant,
},
{
path: '/assistant',
name: 'assistant',
component: assistant,
},
],
})
watchRouter(router)
export default router
+32
View File
@@ -0,0 +1,32 @@
import { ElMessage } from 'element-plus-secondary'
import { request } from '@/utils/request'
export const watchRouter = (router: any) => {
router.beforeEach(async (to: any, from: any, next: any) => {
console.log(to, from)
await loadXpackStatic()
next()
})
}
const loadXpackStatic = () => {
if (document.getElementById('sqlbot_xpack_static')) {
return Promise.resolve()
}
const url = '/xpack_static/license-generator.umd.js'
return new Promise((resolve, reject) => {
request
.loadRemoteScript(url, 'sqlbot_xpack_static', () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
LicenseGenerator?.init(import.meta.env.VITE_API_BASE_URL).then(() => {
resolve(true)
})
})
.catch((error) => {
console.error('Failed to load xpack_static script:', error)
ElMessage.error('Failed to load license generator script')
reject(error)
})
})
}
+14
View File
@@ -645,6 +645,20 @@ const handleCtrlEnter = (e: KeyboardEvent) => {
textarea.selectionStart = textarea.selectionEnd = start + 1
})
}
const getHistoryList = () => {
return chatList.value
}
const getCurrentChatId = () => {
return currentChatId.value
}
defineExpose({
getHistoryList,
onClickHistory,
onChatDeleted,
onChatRenamed,
getCurrentChatId,
})
</script>
<style lang="less" scoped>
+196
View File
@@ -0,0 +1,196 @@
<template>
<div class="sqlbot-assistant-container">
<div class="head">
<div class="flex align-center">
<div class="head-img-div">
<img :src="AssistantGif" />
</div>
<h4>SQLBot 小助手</h4>
</div>
</div>
<chat-component ref="chatRef" class="sqlbot-chat-container" />
</div>
<div class="sqlbot-top-btn">
<el-icon style="cursor: pointer" @click="openHistory">
<history></history>
</el-icon>
</div>
<div class="sqlbot-history-container">
<el-drawer
v-model="drawer"
:append-to-body="false"
class="sqlbot-history-drawer"
modal-class="sqlbot-history-modal"
title=""
direction="ttb"
:with-header="false"
>
<div class="sqlbot-history-title">
<span>历史记录</span>
</div>
<div class="sqlbot-history-content">
<div v-if="!chatList.length" class="history-empty">
<span>暂无历史记录</span>
</div>
<div v-else class="sqlbot-chat-list-inner">
<el-scrollbar max-height="350px" class="sqlbot-chat-scroller">
<template v-for="chat in chatList" :key="chat.id">
<div
class="chat-list-item"
:class="{ 'is-active-chat': currentId === chat.id }"
@click="onClickHistory(chat)"
>
<span class="title">{{ chat.brief ?? 'Untitled' }}</span>
<div class="history-operate">
<el-icon @click="EditPen(chat)"><IconOpeEdit /></el-icon>
<el-icon @click="Delete(chat)"><IconOpeDelete /></el-icon>
</div>
</div>
</template>
</el-scrollbar>
</div>
</div>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import ChatComponent from '@/views/chat/index.vue'
import AssistantGif from '@/assets/img/assistant.gif'
import history from '@/assets/svg/chart/history.svg'
import IconOpeEdit from '@/assets/svg/operate/ope-edit.svg'
import IconOpeDelete from '@/assets/svg/operate/ope-delete.svg'
const chatRef = ref()
const chatList = ref<Array<any>>([])
const drawer = ref(false)
const currentId = ref()
const openHistory = () => {
chatList.value = chatRef.value?.getHistoryList()
currentId.value = chatRef.value?.getCurrentChatId()
drawer.value = true
}
const onClickHistory = (chat: any) => {
chatRef.value?.onClickHistory(chat)
}
const EditPen = (chat: any) => {
chatRef.value?.onChatRenamed(chat)
}
const Delete = (chat: any) => {
chatRef.value?.onChatDeleted(chat.id)
}
</script>
<style lang="less" scoped>
.sqlbot-assistant-container {
height: 100%;
width: 100%;
color: rgb(31, 35, 41);
.flex {
display: flex;
}
.head {
background: linear-gradient(90deg, #ebf1ff 24.34%, #e5fbf8 56.18%, #f2ebfe 90.18%);
position: fixed;
width: 100%;
left: 0;
top: 0;
z-index: 100;
height: 56px;
line-height: 56px;
box-sizing: border-box;
border-bottom: 1px solid #dee0e3;
.align-center {
align-items: center;
.head-img-div {
display: flex;
margin-left: 24px;
img {
width: 32px;
height: 32px;
}
}
}
}
.sqlbot-chat-container {
padding-top: 56px;
:deep(.ed-aside) {
display: none;
}
}
}
.sqlbot-top-btn {
right: 85px;
z-index: 2009;
position: absolute;
top: 16px;
// right: 16px;
font-size: 22px;
}
.sqlbot-history-container {
width: 100%;
:deep(.sqlbot-history-modal) {
top: 56px !important;
}
:deep(.sqlbot-history-title) {
border-bottom: 1px solid #dee0e3;
padding: 16px 24px;
font-size: 14px;
font-weight: 500;
color: #1f2329;
}
:deep(.ed-drawer__body) {
padding: 0 !important;
}
:deep(.sqlbot-history-drawer) {
height: fit-content !important;
.sqlbot-history-content {
padding: 16px;
.history-empty {
height: 60px;
color: #8f959e !important;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.is-active-chat {
background-color: #ebf1ff;
color: #3370ff;
font-weight: 500;
}
.chat-list-item {
display: flex;
align-items: center;
padding: 10px 8px;
font-size: 14px;
color: #1f2329;
justify-content: space-between;
.history-operate {
display: none;
}
&:hover {
cursor: pointer;
border-radius: 4px;
background: rgba(31, 35, 41, 0.1);
.history-operate {
padding-right: 16px;
display: flex;
column-gap: 16px;
align-items: center;
font-size: 18px;
i {
color: #8f959e;
&:hover {
color: #8f959e99;
}
}
}
}
}
}
}
}
</style>
+4 -10
View File
@@ -39,6 +39,10 @@ export default defineConfig(({ mode }) => {
build: {
chunkSizeWarningLimit: 2000,
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
assistant: path.resolve(__dirname, 'assistant.html'),
},
output: {
manualChunks: {
'element-plus-secondary': ['element-plus-secondary'],
@@ -46,16 +50,6 @@ export default defineConfig(({ mode }) => {
},
},
},
// server: {
// proxy: {
// '/api': {
// target: 'https://sqlbot.fit2cloud.cn',
// changeOrigin: true,
// rewrite: path => path.replace(/^\/api/, 'api')
// }
// },
// port: 8080
// },
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',