From c9f14545fffd7c751018b020ff6e84cfb4f345fe Mon Sep 17 00:00:00 2001
From: wangjiahao <1522128093@qq.com>
Date: Tue, 29 Jul 2025 15:55:32 +0800
Subject: [PATCH 1/3] refactor: add view question
---
frontend/src/i18n/en.json | 2 +
frontend/src/i18n/zh-CN.json | 2 +
.../src/views/chat/chat-block/ChartBlock.vue | 22 ++++++++--
.../dashboard/common/AddViewDashboard.vue | 43 +++++++++++++------
4 files changed, 52 insertions(+), 17 deletions(-)
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index ddbe077a..cdb426ab 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -36,6 +36,8 @@
"password_reset_successful": "Password reset successful"
},
"dashboard": {
+ "add_dashboard_name_tips": "Please Input Dashboard Name",
+ "existing_dashboard": "Existing Dashboard",
"add_success": "Add Success",
"no_data": "No Relevant Content Found",
"new_tab": "New Tab",
diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json
index 8d5014db..3ed9c7af 100644
--- a/frontend/src/i18n/zh-CN.json
+++ b/frontend/src/i18n/zh-CN.json
@@ -39,6 +39,8 @@
"or": "或者"
},
"dashboard": {
+ "add_dashboard_name_tips": "请输入仪表板名称",
+ "existing_dashboard": "存量仪表板",
"add_success": "添加成功",
"no_data": "没找到相关内容",
"new_tab": "新建Tab",
diff --git a/frontend/src/views/chat/chat-block/ChartBlock.vue b/frontend/src/views/chat/chat-block/ChartBlock.vue
index 32de5d61..bcac8a82 100644
--- a/frontend/src/views/chat/chat-block/ChartBlock.vue
+++ b/frontend/src/views/chat/chat-block/ChartBlock.vue
@@ -192,9 +192,25 @@ function showSql() {
}
function addToDashboard() {
- const viewInfo = chartRef.value?.getViewInfo()
+ const recordeInfo = {
+ id: '1-1',
+ data: {
+ data: data.value,
+ },
+ chart: {},
+ }
// @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
- addViewRef.value?.optInit(viewInfo)
+ const chartBaseInfo = JSON.parse(props.message?.record?.chart)
+ recordeInfo['chart'] = {
+ type: chartBaseInfo.type,
+ title: chartBaseInfo.title,
+ columns: chartBaseInfo.columns,
+ xAxis: chartBaseInfo.axis?.x ? [chartBaseInfo.axis.x] : [],
+ yAxis: chartBaseInfo.axis?.y ? [chartBaseInfo.axis.y] : [],
+ series: chartBaseInfo.axis?.series ? [chartBaseInfo.axis.series] : [],
+ }
+ // @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ addViewRef.value?.optInit(recordeInfo)
}
function copy() {
@@ -264,7 +280,7 @@ function copy() {
-
+
diff --git a/frontend/src/views/dashboard/common/AddViewDashboard.vue b/frontend/src/views/dashboard/common/AddViewDashboard.vue
index 975850c9..47dc7e00 100644
--- a/frontend/src/views/dashboard/common/AddViewDashboard.vue
+++ b/frontend/src/views/dashboard/common/AddViewDashboard.vue
@@ -68,6 +68,10 @@ const saveResourcePrepare = () => {
if (result) {
const component = cloneDeep(findNewComponentFromList('SQView'))
const newComponentId = guid()
+ // @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ state.viewInfo.chart['id'] = newComponentId
+ // @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ state.viewInfo['id'] = newComponentId
if (resourceForm.addType === 'history' && component) {
findNextComponentIndex({ id: resourceForm.dashboardId }, (result: any) => {
const {
@@ -84,10 +88,8 @@ const saveResourcePrepare = () => {
name: dashboardInfo.name,
}
component['id'] = newComponentId
- component['y'] = bottomPosition + 1
+ component['y'] = bottomPosition
canvasDataResult.push(component)
- // @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
- state.viewInfo.chart['id'] = newComponentId
canvasViewInfoPreview[newComponentId] = state.viewInfo
const commonParams = {
componentData: canvasDataResult,
@@ -97,12 +99,22 @@ const saveResourcePrepare = () => {
saveResource(params, commonParams)
})
} else if (resourceForm.addType === 'new' && component) {
- const params = { opt: 'newLeaf', pid: 'root', name: resourceForm.dashboardName }
+ const params = {
+ opt: 'newLeaf',
+ pid: 'root',
+ name: resourceForm.dashboardName,
+ level: 1,
+ node_type: 'leaf',
+ type: 'dashboard',
+ }
component['id'] = newComponentId
+ const canvasViewInfo = {}
+ // @ts-expect-error eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ canvasViewInfo[newComponentId] = state.viewInfo
const commonParams = {
componentData: [component],
canvasStyleData: {},
- canvasViewInfo: { newComponentId: state.viewInfo },
+ canvasViewInfo: canvasViewInfo,
}
saveResource(params, commonParams)
}
@@ -112,7 +124,7 @@ const saveResourcePrepare = () => {
const saveResource = (params: any, commonParams: any) => {
saveDashboardResourceTarget(params, commonParams, function () {
- const messageTips = t('common.save_success')
+ const messageTips = t('dashboard.add_success')
ElMessage({
type: 'success',
message: messageTips,
@@ -142,7 +154,7 @@ defineExpose({
-
+
- 存量仪表板
- 新建仪表板
+ {{ t('dashboard.existing_dashboard') }}
+ {{ t('dashboard.new_dashboard') }}
-
+
Date: Tue, 29 Jul 2025 16:09:43 +0800
Subject: [PATCH 2/3] perf: Login api entrypt password
---
backend/apps/system/api/login.py | 7 +++++--
backend/common/utils/crypto.py | 4 ++++
backend/main.py | 1 +
backend/pyproject.toml | 2 +-
frontend/auto-imports.d.ts | 1 +
frontend/src/api/login.ts | 14 +++++++++-----
frontend/src/router/watch.ts | 4 +---
frontend/src/utils/request.ts | 5 +----
frontend/src/views/system/user/User.vue | 9 +++++++--
9 files changed, 30 insertions(+), 17 deletions(-)
create mode 100644 backend/common/utils/crypto.py
diff --git a/backend/apps/system/api/login.py b/backend/apps/system/api/login.py
index 8e360e08..70d85146 100644
--- a/backend/apps/system/api/login.py
+++ b/backend/apps/system/api/login.py
@@ -3,6 +3,7 @@ from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordRequestForm
from apps.system.schemas.system_schema import BaseUserDTO
from common.core.deps import SessionDep, Trans
+from common.utils.crypto import sqlbot_decrypt
from ..crud.user import authenticate
from common.core.security import create_access_token
from datetime import timedelta
@@ -11,12 +12,14 @@ from common.core.schemas import Token
router = APIRouter(tags=["login"], prefix="/login")
@router.post("/access-token")
-def local_login(
+async def local_login(
session: SessionDep,
trans: Trans,
form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
) -> Token:
- user: BaseUserDTO = authenticate(session=session, account=form_data.username, password=form_data.password)
+ origin_account = await sqlbot_decrypt(form_data.username)
+ origin_pwd = await sqlbot_decrypt(form_data.password)
+ user: BaseUserDTO = authenticate(session=session, account=origin_account, password=origin_pwd)
if not user:
raise HTTPException(status_code=400, detail=trans('i18n_login.account_pwd_error'))
if not user.oid or user.oid == 0:
diff --git a/backend/common/utils/crypto.py b/backend/common/utils/crypto.py
new file mode 100644
index 00000000..ce5d7b95
--- /dev/null
+++ b/backend/common/utils/crypto.py
@@ -0,0 +1,4 @@
+from sqlbot_xpack.core import sqlbot_decrypt as xpack_sqlbot_decrypt
+
+async def sqlbot_decrypt(text: str) -> str:
+ return await xpack_sqlbot_decrypt(text)
\ No newline at end of file
diff --git a/backend/main.py b/backend/main.py
index c4571893..9024658c 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -29,6 +29,7 @@ async def lifespan(app: FastAPI):
init_sqlbot_cache()
init_dynamic_cors(app)
SQLBotLogUtil.info("✅ SQLBot 初始化完成")
+ await sqlbot_xpack.core.clean_xpack_cache()
yield
SQLBotLogUtil.info("SQLBot 应用关闭")
diff --git a/backend/pyproject.toml b/backend/pyproject.toml
index 3e4a7c71..ea6d490a 100644
--- a/backend/pyproject.toml
+++ b/backend/pyproject.toml
@@ -36,7 +36,7 @@ dependencies = [
"pyyaml (>=6.0.2,<7.0.0)",
"fastapi-mcp (>=0.3.4,<0.4.0)",
"tabulate>=0.9.0",
- "sqlbot-xpack==0.0.3.8",
+ "sqlbot-xpack==0.0.3.9",
"fastapi-cache2>=0.2.2",
"sqlparse>=0.5.3",
"redis>=6.2.0",
diff --git a/frontend/auto-imports.d.ts b/frontend/auto-imports.d.ts
index 56d36587..f66cb83b 100644
--- a/frontend/auto-imports.d.ts
+++ b/frontend/auto-imports.d.ts
@@ -8,4 +8,5 @@ export {}
declare global {
const ElMessage: typeof import('element-plus-secondary/es')['ElMessage']
const ElMessageBox: typeof import('element-plus-secondary/es')['ElMessageBox']
+ const LicenseGenerator: any
}
diff --git a/frontend/src/api/login.ts b/frontend/src/api/login.ts
index 6fc486b9..efe894e2 100644
--- a/frontend/src/api/login.ts
+++ b/frontend/src/api/login.ts
@@ -1,15 +1,19 @@
import { request } from '@/utils/request'
-
export const AuthApi = {
- login: (credentials: { username: string; password: string }) =>
- request.post<{
+ login: (credentials: { username: string; password: string }) => {
+ const entryCredentials = {
+ username: LicenseGenerator.sqlbotEncrypt(credentials.username),
+ password: LicenseGenerator.sqlbotEncrypt(credentials.password),
+ }
+ return request.post<{
data: any
token: string
- }>('/login/access-token', credentials, {
+ }>('/login/access-token', entryCredentials, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
- }),
+ })
+ },
logout: () => request.post('/auth/logout'),
info: () => request.get('/user/info'),
}
diff --git a/frontend/src/router/watch.ts b/frontend/src/router/watch.ts
index d91cf605..a5fc9c41 100644
--- a/frontend/src/router/watch.ts
+++ b/frontend/src/router/watch.ts
@@ -50,12 +50,10 @@ const loadXpackStatic = () => {
if (document.getElementById('sqlbot_xpack_static')) {
return Promise.resolve()
}
- const url = '/xpack_static/license-generator.umd.js'
+ const url = `/xpack_static/license-generator.umd.js?t=${Date.now()}`
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)
})
diff --git a/frontend/src/utils/request.ts b/frontend/src/utils/request.ts
index 6e22a9da..5cbdc90d 100644
--- a/frontend/src/utils/request.ts
+++ b/frontend/src/utils/request.ts
@@ -99,8 +99,7 @@ class HttpService {
// Skip auth for xpack_static requests
return config
}
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
+
const request_key = LicenseGenerator.generate()
config.headers['X-SQLBOT-KEY'] = request_key
@@ -266,8 +265,6 @@ class HttpService {
heads['X-SQLBOT-ASSISTANT-ONLINE'] = assistantStore.getOnline
}
}
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
const request_key = LicenseGenerator.generate()
heads['X-SQLBOT-KEY'] = request_key
diff --git a/frontend/src/views/system/user/User.vue b/frontend/src/views/system/user/User.vue
index 466d4eb5..9c140a70 100644
--- a/frontend/src/views/system/user/User.vue
+++ b/frontend/src/views/system/user/User.vue
@@ -51,8 +51,13 @@
@selection-change="handleSelectionChange"
>
-
-
+
+
From 5449db3e91cdcf39bd575bf435b3ad1dc8b7b26d Mon Sep 17 00:00:00 2001
From: junjun
Date: Tue, 29 Jul 2025 16:17:25 +0800
Subject: [PATCH 3/3] feat: field lower
---
backend/apps/db/db.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/backend/apps/db/db.py b/backend/apps/db/db.py
index 607d7cb0..f27194a2 100644
--- a/backend/apps/db/db.py
+++ b/backend/apps/db/db.py
@@ -253,7 +253,7 @@ def exec_sql(ds: CoreDatasource | AssistantOutDsSchema, sql: str):
with get_session(ds) as session:
with session.execute(text(sql)) as result:
try:
- columns = result.keys()._keys
+ columns = [item.lower() for item in result.keys()._keys]
res = result.fetchall()
result_list = [
{columns[i]: float(value) if isinstance(value, Decimal) else value for i, value in