diff --git a/frontend/assistant.html b/frontend/assistant.html
deleted file mode 100644
index c65334fd..00000000
--- a/frontend/assistant.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
+
+
+`
+ }
+ /**
+ * 初始化引导
+ * @param {*} root
+ */
+ const initGuide = (root) => {
+ root.insertAdjacentHTML('beforeend', guideHtml)
+ const button = root.querySelector('.sqlbot-assistant-button')
+ const close_icon = root.querySelector('.sqlbot-assistant-close')
+ const close_func = () => {
+ root.removeChild(root.querySelector('.sqlbot-assistant-tips'))
+ root.removeChild(root.querySelector('.sqlbot-assistant-mask'))
+ localStorage.setItem('sqlbot_assistant_mask_tip', true)
+ }
+ button.onclick = close_func
+ close_icon.onclick = close_func
+ }
+ const initChat = (root, data) => {
+ // 添加对话icon
+ root.insertAdjacentHTML('beforeend', chatButtonHtml(data))
+ // 添加对话框
+ root.insertAdjacentHTML('beforeend', getChatContainerHtml(data))
+ // 按钮元素
+ const chat_button = root.querySelector('.sqlbot-assistant-chat-button')
+ const chat_button_img = root.querySelector('.sqlbot-assistant-chat-button > img')
+ // 对话框元素
+ const chat_container = root.querySelector('#sqlbot-assistant-chat-container')
+ // 引导层
+ const mask_content = root.querySelector('.sqlbot-assistant-mask > .sqlbot-assistant-content')
+ const mask_tips = root.querySelector('.sqlbot-assistant-tips')
+ chat_button_img.onload = (event) => {
+ if (mask_content) {
+ mask_content.style.width = chat_button_img.width + 'px'
+ mask_content.style.height = chat_button_img.height + 'px'
+ if (data.x_type == 'left') {
+ mask_tips.style.marginLeft =
+ (chat_button_img.naturalWidth > 500 ? 500 : chat_button_img.naturalWidth) - 64 + 'px'
+ } else {
+ mask_tips.style.marginRight =
+ (chat_button_img.naturalWidth > 500 ? 500 : chat_button_img.naturalWidth) - 64 + 'px'
+ }
+ }
+ }
+
+ const viewport = root.querySelector('.sqlbot-assistant-openviewport')
+ const closeviewport = root.querySelector('.sqlbot-assistant-closeviewport')
+ const close_func = () => {
+ chat_container.style['display'] =
+ chat_container.style['display'] == 'block' ? 'none' : 'block'
+ chat_button.style['display'] = chat_container.style['display'] == 'block' ? 'none' : 'block'
+ }
+ close_icon = chat_container.querySelector('.sqlbot-assistant-chat-close')
+ chat_button.onclick = close_func
+ close_icon.onclick = close_func
+ const viewport_func = () => {
+ if (chat_container.classList.contains('sqlbot-assistant-enlarge')) {
+ chat_container.classList.remove('sqlbot-assistant-enlarge')
+ viewport.classList.remove('sqlbot-assistant-viewportnone')
+ closeviewport.classList.add('sqlbot-assistant-viewportnone')
+ } else {
+ chat_container.classList.add('sqlbot-assistant-enlarge')
+ viewport.classList.add('sqlbot-assistant-viewportnone')
+ closeviewport.classList.remove('sqlbot-assistant-viewportnone')
+ }
+ }
+ const drag = (e) => {
+ if (['touchmove', 'touchstart'].includes(e.type)) {
+ chat_button.style.top = e.touches[0].clientY - chat_button_img.naturalHeight / 2 + 'px'
+ chat_button.style.left = e.touches[0].clientX - chat_button_img.naturalWidth / 2 + 'px'
+ } else {
+ chat_button.style.top = e.y - chat_button_img.naturalHeight / 2 + 'px'
+ chat_button.style.left = e.x - chat_button_img.naturalWidth / 2 + 'px'
+ }
+ chat_button.style.width = chat_button_img.naturalWidth + 'px'
+ chat_button.style.height = chat_button_img.naturalHeight + 'px'
+ }
+ if (data.is_draggable) {
+ chat_button.addEventListener('drag', drag)
+ chat_button.addEventListener('dragover', (e) => {
+ e.preventDefault()
+ })
+ chat_button.addEventListener('dragend', drag)
+ chat_button.addEventListener('touchstart', drag)
+ chat_button.addEventListener('touchmove', drag)
+ }
+ viewport.onclick = viewport_func
+ closeviewport.onclick = viewport_func
+ }
+ /**
+ * 第一次进来的引导提示
+ */
+ function initsqlbot_assistant(data) {
+ const sqlbot_div = document.createElement('div')
+ const root = document.createElement('div')
+ const sqlbot_root_id = 'sqlbot-assistant-root-' + data.id
+ root.id = sqlbot_root_id
+ initsqlbot_assistantStyle(sqlbot_div, sqlbot_root_id, data)
+ sqlbot_div.appendChild(root)
+ document.body.appendChild(sqlbot_div)
+ const sqlbot_assistant_mask_tip = localStorage.getItem('sqlbot_assistant_mask_tip')
+ if (sqlbot_assistant_mask_tip == null && data.show_guide) {
+ initGuide(root)
+ }
+ initChat(root, data)
+ }
+
+ // 初始化全局样式
+ function initsqlbot_assistantStyle(root, sqlbot_assistantId, data) {
+ style = document.createElement('style')
+ style.type = 'text/css'
+ style.innerText = `
+ /* 放大 */
+ #sqlbot-assistant .sqlbot-assistant-enlarge {
+ width: 50%!important;
+ height: 100%!important;
+ bottom: 0!important;
+ right: 0 !important;
+ }
+ @media only screen and (max-width: 768px){
+ #sqlbot-assistant .sqlbot-assistant-enlarge {
+ width: 100%!important;
+ height: 100%!important;
+ right: 0 !important;
+ bottom: 0!important;
+ }
+ }
+
+ /* 引导 */
+
+ #sqlbot-assistant .sqlbot-assistant-mask {
+ position: fixed;
+ z-index: 10001;
+ background-color: transparent;
+ height: 100%;
+ width: 100%;
+ top: 0;
+ left: 0;
+ }
+ #sqlbot-assistant .sqlbot-assistant-mask .sqlbot-assistant-content {
+ width: 64px;
+ height: 64px;
+ box-shadow: 1px 1px 1px 9999px rgba(0,0,0,.6);
+ position: absolute;
+ ${data.x_type}: ${data.x_value}px;
+ ${data.y_type}: ${data.y_value}px;
+ z-index: 10001;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips {
+ position: fixed;
+ ${data.x_type}:calc(${data.x_value}px + 75px);
+ ${data.y_type}: calc(${data.y_value}px + 0px);
+ padding: 22px 24px 24px;
+ border-radius: 6px;
+ color: #ffffff;
+ font-size: 14px;
+ background: #3370FF;
+ z-index: 10001;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-arrow {
+ position: absolute;
+ background: #3370FF;
+ width: 10px;
+ height: 10px;
+ pointer-events: none;
+ transform: rotate(45deg);
+ box-sizing: border-box;
+ /* left */
+ ${data.x_type}: -5px;
+ ${data.y_type}: 33px;
+ border-left-color: transparent;
+ border-bottom-color: transparent
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-title {
+ font-size: 20px;
+ font-weight: 500;
+ margin-bottom: 8px;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button {
+ text-align: right;
+ margin-top: 24px;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button button {
+ border-radius: 4px;
+ background: #FFF;
+ padding: 3px 12px;
+ color: #3370FF;
+ cursor: pointer;
+ outline: none;
+ border: none;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-button button::after{
+ border: none;
+ }
+ #sqlbot-assistant .sqlbot-assistant-tips .sqlbot-assistant-close {
+ position: absolute;
+ right: 20px;
+ top: 20px;
+ cursor: pointer;
+
+ }
+ #sqlbot-assistant-chat-container {
+ width: 450px;
+ height: 600px;
+ display:none;
+ }
+ @media only screen and (max-width: 768px) {
+ #sqlbot-assistant-chat-container {
+ width: 100%;
+ height: 70%;
+ right: 0 !important;
+ }
+ }
+
+ #sqlbot-assistant .sqlbot-assistant-chat-button{
+ position: fixed;
+ ${data.x_type}: ${data.x_value}px;
+ ${data.y_type}: ${data.y_value}px;
+ cursor: pointer;
+ z-index:10000;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container{
+ z-index:10000;position: relative;
+ border-radius: 8px;
+ border: 1px solid #ffffff;
+ background: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1;
+ box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.10);
+ position: fixed;bottom: 16px;right: 16px;overflow: hidden;
+ }
+
+ #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate{
+ top: 18px;
+ right: 15px;
+ position: absolute;
+ display: flex;
+ align-items: center;
+ line-height: 18px;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-chat-close{
+ margin-left:15px;
+ cursor: pointer;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-openviewport{
+
+ cursor: pointer;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-operate .sqlbot-assistant-closeviewport{
+
+ cursor: pointer;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container .sqlbot-assistant-viewportnone{
+ display:none;
+ }
+ #sqlbot-assistant #sqlbot-assistant-chat-container #sqlbot-assistant-chat{
+ height:100%;
+ width:100%;
+ border: none;
+}
+ #sqlbot-assistant #sqlbot-assistant-chat-container {
+ animation: appear .4s ease-in-out;
+ }
+ @keyframes appear {
+ from {
+ height: 0;;
+ }
+
+ to {
+ height: 600px;
+ }
+ }`.replaceAll('#sqlbot-assistant ', `#${sqlbot_assistantId} `)
+ root.appendChild(style)
+ }
+ function getParam(src, key) {
+ const url = new URL(src)
+ return url.searchParams.get(key)
+ }
+
+ function loadScript(src, id) {
+ const domain_url = getDomain(src)
+ // const url = `${domain_url}api/v1/system/assistant/validator/${id}`
+ /* const url = `http://localhost:8000/api/v1/system/assistant/validator/${id}`
+ fetch(url)
+ .then((response) => response.json())
+ .then((data) => {
+ console.log(data)
+ const tempData = Object.assign(defaultData, data)
+ initsqlbot_assistant(tempData)
+ }) */
+ initsqlbot_assistant(defaultData)
+ }
+ function getDomain(src) {
+ return src.substring(0, src.indexOf('assistant.js'))
+ }
+ function init() {
+ const sqlbotScripts = document.querySelectorAll(`script[id^="${script_id_prefix}"]`)
+ const scriptsArray = Array.from(sqlbotScripts)
+ const src_list = scriptsArray.map((script) => script.src)
+ src_list.forEach((src) => {
+ const id = getParam(src, 'id')
+ const propName = script_id_prefix + id + '-state'
+ if (window[propName]) {
+ return true
+ }
+ window[propName] = true
+ loadScript(src, id)
+ })
+ }
+ window.addEventListener('load', init)
+})()
diff --git a/frontend/src/main_assistant.ts b/frontend/src/main_assistant.ts
deleted file mode 100644
index b458a6c6..00000000
--- a/frontend/src/main_assistant.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-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')
diff --git a/frontend/src/router/assistant.ts b/frontend/src/router/assistant.ts
deleted file mode 100644
index fec2ddc4..00000000
--- a/frontend/src/router/assistant.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-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: '/:id',
- name: 'index',
- component: assistant,
- },
- {
- path: '/assistant:id',
- name: 'assistant',
- component: assistant,
- },
- ],
-})
-watchRouter(router)
-export default router
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index c647d9f9..7a56a075 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -10,6 +10,7 @@ import DashboardEditor from '@/views/dashboard/editor/index.vue'
import DashboardPreview from '@//views/dashboard/preview/SQPreviewSingle.vue'
import Dashboard from '@/views/dashboard/index.vue'
import Model from '@/views/system/model/Model.vue'
+import assistant from '@/views/embedded/assistant.vue'
// import User from "@/views/system/user/index.vue";
import { watchRouter } from './watch'
const router = createRouter({
@@ -128,6 +129,11 @@ const router = createRouter({
},
],
},
+ {
+ path: '/assistant',
+ name: 'assistant',
+ component: assistant,
+ },
],
})
watchRouter(router)
diff --git a/frontend/src/router/watch.ts b/frontend/src/router/watch.ts
index b359c2ef..14bf2ad9 100644
--- a/frontend/src/router/watch.ts
+++ b/frontend/src/router/watch.ts
@@ -5,9 +5,14 @@ import { request } from '@/utils/request'
const userStore = useUserStore()
const { wsCache } = useCache()
const whiteList = ['/login']
+const assistantWhiteList = ['/assistant']
export const watchRouter = (router: any) => {
router.beforeEach(async (to: any, from: any, next: any) => {
await loadXpackStatic()
+ if (assistantWhiteList.includes(to.path)) {
+ next()
+ return
+ }
const token = wsCache.get('user.token')
if (whiteList.includes(to.path)) {
next()
diff --git a/frontend/src/router/watch_assistant.ts b/frontend/src/router/watch_assistant.ts
deleted file mode 100644
index 1e0fcbcb..00000000
--- a/frontend/src/router/watch_assistant.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-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)
- })
- })
-}
diff --git a/frontend/src/views/embedded/assistant.vue b/frontend/src/views/embedded/assistant.vue
index 199940db..bede90c7 100644
--- a/frontend/src/views/embedded/assistant.vue
+++ b/frontend/src/views/embedded/assistant.vue
@@ -95,7 +95,9 @@ const validator = ref({
})
const loading = ref(true)
onBeforeMount(async () => {
- const assistantId = route.params.id
+ const assistantId = route.query.id
+ const online = route.query.online
+ console.log(online)
const now = Date.now()
assistantStore.setFlag(now)
const id = `${assistantId}-${assistantStore.getFlag}`
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index 8e88d435..4749a7e2 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -39,10 +39,6 @@ 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'],