mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -96,7 +96,7 @@ async def start_chat(session: SessionDep, current_user: CurrentUser):
|
||||
@router.post("/recommend_questions/{chat_record_id}")
|
||||
async def recommend_questions(session: SessionDep, current_user: CurrentUser, chat_record_id: int, current_assistant: CurrentAssistant):
|
||||
try:
|
||||
record = session.query(ChatRecord).get(chat_record_id)
|
||||
record = session.get(ChatRecord, chat_record_id)
|
||||
if not record:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
||||
@@ -151,8 +151,6 @@ class AiModelQuestion(BaseModel):
|
||||
class ChatQuestion(AiModelQuestion):
|
||||
question: str = ''
|
||||
chat_id: int = 0
|
||||
assistant_certificate: Optional[str] = None
|
||||
|
||||
|
||||
class ChatMcp(ChatQuestion):
|
||||
token: str = ''
|
||||
|
||||
@@ -53,7 +53,6 @@ class LLMService:
|
||||
session: SessionDep
|
||||
current_user: CurrentUser
|
||||
current_assistant: Optional[CurrentAssistant] = None
|
||||
assistant_certificate: str
|
||||
out_ds_instance: Optional[AssistantOutDs] = None
|
||||
change_title: bool = False
|
||||
|
||||
@@ -63,8 +62,6 @@ class LLMService:
|
||||
self.session = session
|
||||
self.current_user = current_user
|
||||
self.current_assistant = current_assistant
|
||||
if chat_question.assistant_certificate:
|
||||
self.assistant_certificate = chat_question.assistant_certificate
|
||||
# chat = self.session.query(Chat).filter(Chat.id == chat_question.chat_id).first()
|
||||
chat_id = chat_question.chat_id
|
||||
chat: Chat = self.session.get(Chat, chat_id)
|
||||
|
||||
@@ -10,7 +10,7 @@ from apps.datasource.models.datasource import CoreDatasource, DatasourceConf
|
||||
|
||||
from apps.system.models.system_model import AssistantModel
|
||||
from apps.system.schemas.auth import CacheName, CacheNamespace
|
||||
from apps.system.schemas.system_schema import AssistantOutDsSchema, UserInfoDTO
|
||||
from apps.system.schemas.system_schema import AssistantHeader, AssistantOutDsSchema, UserInfoDTO
|
||||
from common.core.sqlbot_cache import cache
|
||||
from common.core.db import engine
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
@@ -24,9 +24,8 @@ async def get_assistant_info(*, session: Session, assistant_id: int) -> Assistan
|
||||
def get_assistant_user(*, id: int):
|
||||
return UserInfoDTO(id=id, account="sqlbot-inner-assistant", oid=1, name="sqlbot-inner-assistant", email="[email protected]")
|
||||
|
||||
# def get_assistant_ds(*, session: Session, assistant: AssistantModel):
|
||||
def get_assistant_ds(llm_service) -> list[dict]:
|
||||
assistant: AssistantModel = llm_service.current_assistant
|
||||
assistant: AssistantHeader = llm_service.current_assistant
|
||||
session: Session = llm_service.session
|
||||
type = assistant.type
|
||||
if type == 0:
|
||||
@@ -51,7 +50,7 @@ def get_assistant_ds(llm_service) -> list[dict]:
|
||||
|
||||
# filter private ds if offline
|
||||
return result_list
|
||||
out_ds_instance: AssistantOutDs = AssistantOutDsFactory.get_instance(assistant, llm_service.assistant_certificate)
|
||||
out_ds_instance: AssistantOutDs = AssistantOutDsFactory.get_instance(assistant)
|
||||
llm_service.out_ds_instance = out_ds_instance
|
||||
dslist = out_ds_instance.get_simple_ds_list()
|
||||
# format?
|
||||
@@ -84,20 +83,20 @@ def init_dynamic_cors(app: FastAPI):
|
||||
|
||||
|
||||
class AssistantOutDs:
|
||||
assistant: AssistantModel
|
||||
assistant: AssistantHeader
|
||||
ds_list: Optional[list[AssistantOutDsSchema]] = None
|
||||
certificate: Optional[str] = None
|
||||
def __init__(self, assistant: AssistantModel, certificate: Optional[str] = None):
|
||||
def __init__(self, assistant: AssistantHeader):
|
||||
self.assistant = assistant
|
||||
self.ds_list = None
|
||||
self.certificate = certificate
|
||||
self.get_ds_from_api(certificate)
|
||||
self.certificate = assistant.certificate
|
||||
self.get_ds_from_api()
|
||||
|
||||
#@cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_DS, keyExpression="current_user.id")
|
||||
def get_ds_from_api(self, certificate: Optional[str] = None):
|
||||
def get_ds_from_api(self):
|
||||
config: dict[any] = json.loads(self.assistant.configuration)
|
||||
endpoint: str = config['endpoint']
|
||||
certificateList: list[any] = json.loads(certificate)
|
||||
certificateList: list[any] = json.loads(self.certificate)
|
||||
header = {}
|
||||
cookies = {}
|
||||
for item in certificateList:
|
||||
@@ -155,8 +154,8 @@ class AssistantOutDs:
|
||||
|
||||
class AssistantOutDsFactory:
|
||||
@staticmethod
|
||||
def get_instance(assistant: AssistantModel, certificate: Optional[str] = None) -> AssistantOutDs:
|
||||
return AssistantOutDs(assistant, certificate)
|
||||
def get_instance(assistant: AssistantHeader) -> AssistantOutDs:
|
||||
return AssistantOutDs(assistant)
|
||||
|
||||
def get_ds_engine(ds: AssistantOutDsSchema) -> Engine:
|
||||
timeout: int = 30
|
||||
|
||||
@@ -9,7 +9,7 @@ from apps.system.models.system_model import AssistantModel
|
||||
from common.core.db import engine
|
||||
from apps.system.crud.assistant import get_assistant_info, get_assistant_user
|
||||
from apps.system.crud.user import get_user_info
|
||||
from apps.system.schemas.system_schema import UserInfoDTO
|
||||
from apps.system.schemas.system_schema import AssistantHeader, UserInfoDTO
|
||||
from common.core import security
|
||||
from common.core.config import settings
|
||||
from common.core.schemas import TokenPayload
|
||||
@@ -92,6 +92,7 @@ class TokenMiddleware(BaseHTTPMiddleware):
|
||||
session_user = get_assistant_user(id = token_data.id)
|
||||
assistant_info = await get_assistant_info(session=session, assistant_id=payload['assistant_id'])
|
||||
assistant_info = AssistantModel.model_validate(assistant_info)
|
||||
assistant_info = AssistantHeader.model_validate(assistant_info.model_dump(exclude_unset=True))
|
||||
return True, session_user, assistant_info
|
||||
except Exception as e:
|
||||
return False, e
|
||||
@@ -71,6 +71,12 @@ class AssistantBase(BaseModel):
|
||||
class AssistantDTO(AssistantBase, BaseCreatorDTO):
|
||||
pass
|
||||
|
||||
class AssistantHeader(AssistantDTO):
|
||||
unique: Optional[str] = None
|
||||
certificate: Optional[str] = None
|
||||
online: bool = False
|
||||
|
||||
|
||||
class AssistantValidator(BaseModel):
|
||||
valid: bool = False
|
||||
id_match: bool = False
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import base64
|
||||
from typing import Annotated
|
||||
from urllib.parse import unquote
|
||||
|
||||
from fastapi import Depends, Request
|
||||
from sqlmodel import Session
|
||||
from apps.system.models.system_model import AssistantModel
|
||||
from apps.system.schemas.system_schema import UserInfoDTO
|
||||
from apps.system.schemas.system_schema import AssistantHeader, UserInfoDTO
|
||||
from common.core.db import get_session
|
||||
from common.utils.locale import I18n
|
||||
|
||||
@@ -19,10 +20,14 @@ async def get_current_user(request: Request) -> UserInfoDTO:
|
||||
|
||||
CurrentUser = Annotated[UserInfoDTO, Depends(get_current_user)]
|
||||
|
||||
async def get_current_assistant(request: Request) -> AssistantModel | None:
|
||||
return request.state.assistant if hasattr(request.state, "assistant") else None
|
||||
async def get_current_assistant(request: Request) -> AssistantHeader | None:
|
||||
base_assistant = request.state.assistant if hasattr(request.state, "assistant") else None
|
||||
if request.headers.get("X-SQLBOT-ASSISTANT-CERTIFICATE"):
|
||||
entry_certificate = request.headers['X-SQLBOT-ASSISTANT-CERTIFICATE']
|
||||
base_assistant.certificate = unquote(base64.b64decode(entry_certificate).decode('utf-8'))
|
||||
return base_assistant
|
||||
|
||||
CurrentAssistant = Annotated[AssistantModel, Depends(get_current_assistant)]
|
||||
CurrentAssistant = Annotated[AssistantHeader, Depends(get_current_assistant)]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -74,5 +74,9 @@ const routerList = computed(() => {
|
||||
color: #1cba90 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ed-sub-menu .ed-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -76,7 +76,9 @@ onMounted(async () => {
|
||||
<el-icon size="16">
|
||||
<icon_moments_categories_outlined></icon_moments_categories_outlined>
|
||||
</el-icon>
|
||||
<span v-if="!collapse" class="name">{{ currentWorkspace.name }}</span>
|
||||
<span v-if="!collapse" :title="currentWorkspace.name" class="name ellipsis">{{
|
||||
currentWorkspace.name
|
||||
}}</span>
|
||||
<el-icon v-if="!collapse" style="transform: scale(0.5)" class="expand" size="24">
|
||||
<icon_expand_down_filled></icon_expand_down_filled>
|
||||
</el-icon></button
|
||||
@@ -105,13 +107,17 @@ onMounted(async () => {
|
||||
<el-icon size="16">
|
||||
<icon_moments_categories_outlined></icon_moments_categories_outlined>
|
||||
</el-icon>
|
||||
<div class="datasource-name" v-html="formatKeywords(ele.name)"></div>
|
||||
<div
|
||||
:title="ele.name"
|
||||
class="datasource-name ellipsis"
|
||||
v-html="formatKeywords(ele.name)"
|
||||
></div>
|
||||
<el-icon size="16" class="done">
|
||||
<icon_done_outlined></icon_done_outlined>
|
||||
</el-icon>
|
||||
</div>
|
||||
<div v-if="!defaultWorkspaceListWithSearch.length" class="popover-item empty">
|
||||
没有找到相关结果
|
||||
{{ $t('model.relevant_results_found') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,6 +148,7 @@ onMounted(async () => {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
margin-left: 8px;
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
.expand {
|
||||
@@ -203,6 +210,7 @@ onMounted(async () => {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
max-width: 180px;
|
||||
}
|
||||
|
||||
.done {
|
||||
|
||||
@@ -312,6 +312,7 @@
|
||||
"old_password": "Old password"
|
||||
},
|
||||
"workspace": {
|
||||
"relevant_content_found": "No relevant content found",
|
||||
"add_workspace": "Add workspace",
|
||||
"administrator": "Administrator",
|
||||
"ordinary_member": "Ordinary member",
|
||||
|
||||
@@ -325,6 +325,7 @@
|
||||
}
|
||||
},
|
||||
"workspace": {
|
||||
"relevant_content_found": "找不到相关内容",
|
||||
"add_workspace": "添加工作空间",
|
||||
"administrator": "管理员",
|
||||
"ordinary_member": "普通成员",
|
||||
|
||||
@@ -75,6 +75,11 @@ class HttpService {
|
||||
if (assistantStore.getToken) {
|
||||
config.headers['X-SQLBOT-ASSISTANT-TOKEN'] = `Assistant ${assistantStore.getToken}`
|
||||
if (config.headers['X-SQLBOT-TOKEN']) config.headers.delete('X-SQLBOT-TOKEN')
|
||||
if (assistantStore.getType && assistantStore.getCertificate) {
|
||||
config.headers['X-SQLBOT-ASSISTANT-CERTIFICATE'] = btoa(
|
||||
encodeURIComponent(assistantStore.getCertificate)
|
||||
)
|
||||
}
|
||||
}
|
||||
const locale = getLocale()
|
||||
if (locale) {
|
||||
@@ -239,6 +244,11 @@ class HttpService {
|
||||
if (assistantStore.getToken) {
|
||||
heads['X-SQLBOT-ASSISTANT-TOKEN'] = `Assistant ${assistantStore.getToken}`
|
||||
if (heads['X-SQLBOT-TOKEN']) delete heads['X-SQLBOT-TOKEN']
|
||||
if (assistantStore.getType && assistantStore.getCertificate) {
|
||||
heads['X-SQLBOT-ASSISTANT-CERTIFICATE'] = btoa(
|
||||
encodeURIComponent(assistantStore.getCertificate)
|
||||
)
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
|
||||
@@ -103,54 +103,61 @@ function onChatCreated(chat: ChatInfo) {
|
||||
|
||||
const chatCreatorRef = ref()
|
||||
|
||||
function goEmpty() {
|
||||
function goEmpty(func?: (...p: any[]) => void, ...params: any[]) {
|
||||
_currentChat.value = new ChatInfo()
|
||||
_currentChatId.value = undefined
|
||||
emits('goEmpty')
|
||||
emits('goEmpty', func, ...params)
|
||||
}
|
||||
|
||||
const createNewChat = async () => {
|
||||
if (!_loading.value) {
|
||||
goEmpty()
|
||||
if (isAssistant.value) {
|
||||
const assistantChat = await assistantStore.setChat()
|
||||
if (assistantChat) {
|
||||
onChatCreated(assistantChat)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
chatCreatorRef.value?.showDs()
|
||||
goEmpty(doCreateNewChat)
|
||||
}
|
||||
|
||||
async function doCreateNewChat() {
|
||||
if (isAssistant.value) {
|
||||
const assistantChat = await assistantStore.setChat()
|
||||
if (assistantChat) {
|
||||
onChatCreated(assistantChat)
|
||||
}
|
||||
return
|
||||
} else {
|
||||
chatCreatorRef.value?.showDs()
|
||||
}
|
||||
}
|
||||
|
||||
function onClickHistory(chat: Chat) {
|
||||
if (chat !== undefined && chat.id !== undefined && !_loading.value) {
|
||||
goEmpty()
|
||||
nextTick(() => {
|
||||
if (chat !== undefined && chat.id !== undefined) {
|
||||
_currentChat.value = new ChatInfo(chat)
|
||||
_currentChatId.value = chat.id
|
||||
_loading.value = true
|
||||
chatApi
|
||||
.get(chat.id)
|
||||
.then((res) => {
|
||||
const info = chatApi.toChatInfo(res)
|
||||
if (info) {
|
||||
_currentChat.value = info
|
||||
|
||||
// scrollToBottom()
|
||||
emits('onClickHistory', info)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
_loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
if (chat !== undefined && chat.id !== undefined) {
|
||||
if (_currentChatId.value === chat.id) {
|
||||
return
|
||||
}
|
||||
goEmpty(goHistory, chat)
|
||||
}
|
||||
}
|
||||
|
||||
function goHistory(chat: Chat) {
|
||||
nextTick(() => {
|
||||
if (chat !== undefined && chat.id !== undefined) {
|
||||
_currentChat.value = new ChatInfo(chat)
|
||||
_currentChatId.value = chat.id
|
||||
_loading.value = true
|
||||
chatApi
|
||||
.get(chat.id)
|
||||
.then((res) => {
|
||||
const info = chatApi.toChatInfo(res)
|
||||
if (info && info.id === _currentChatId.value) {
|
||||
_currentChat.value = info
|
||||
|
||||
// scrollToBottom()
|
||||
emits('onClickHistory', info)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
_loading.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onChatDeleted(id: number) {
|
||||
for (let i = 0; i < _chatList.value.length; i++) {
|
||||
if (_chatList.value[i].id === id) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import { endsWith, startsWith } from 'lodash-es'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { chatApi, ChatInfo } from '@/api/chat.ts'
|
||||
@@ -19,7 +19,7 @@ const props = withDefaults(
|
||||
}
|
||||
)
|
||||
|
||||
const emits = defineEmits(['clickQuestion', 'update:currentChat'])
|
||||
const emits = defineEmits(['clickQuestion', 'update:currentChat', 'stop'])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
@@ -57,7 +57,7 @@ async function getRecommendQuestions() {
|
||||
loading.value = true
|
||||
try {
|
||||
const controller: AbortController = new AbortController()
|
||||
const response = await chatApi.recommendQuestions(props.recordId)
|
||||
const response = await chatApi.recommendQuestions(props.recordId, controller)
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
@@ -138,8 +138,13 @@ async function getRecommendQuestions() {
|
||||
function stop() {
|
||||
stopFlag.value = true
|
||||
loading.value = false
|
||||
emits('stop')
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop()
|
||||
})
|
||||
|
||||
defineExpose({ getRecommendQuestions, id: () => props.recordId, stop })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import BaseAnswer from './BaseAnswer.vue'
|
||||
import { chatApi, ChatInfo, type ChatMessage, ChatRecord } from '@/api/chat.ts'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import MdComponent from '@/views/chat/component/MdComponent.vue'
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -23,6 +23,7 @@ const props = withDefaults(
|
||||
const emits = defineEmits([
|
||||
'finish',
|
||||
'error',
|
||||
'stop',
|
||||
'update:loading',
|
||||
'update:chatList',
|
||||
'update:currentChat',
|
||||
@@ -192,7 +193,12 @@ const sendMessage = async () => {
|
||||
function stop() {
|
||||
stopFlag.value = true
|
||||
_loading.value = false
|
||||
emits('stop')
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop()
|
||||
})
|
||||
defineExpose({ sendMessage, index: () => index.value, chatList: () => _chatList.value, stop })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import BaseAnswer from './BaseAnswer.vue'
|
||||
import { Chat, chatApi, ChatInfo, type ChatMessage, ChatRecord, questionApi } from '@/api/chat.ts'
|
||||
import { useAssistantStore } from '@/stores/assistant'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
const assistantStore = useAssistantStore()
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
chatList?: Array<ChatInfo>
|
||||
@@ -25,6 +23,7 @@ const props = withDefaults(
|
||||
const emits = defineEmits([
|
||||
'finish',
|
||||
'error',
|
||||
'stop',
|
||||
'update:loading',
|
||||
'update:chatList',
|
||||
'update:currentChat',
|
||||
@@ -101,12 +100,8 @@ const sendMessage = async () => {
|
||||
const param = {
|
||||
question: currentRecord.question,
|
||||
chat_id: _currentChatId.value,
|
||||
assistant_certificate: assistantStore.getCertificate,
|
||||
controller,
|
||||
}
|
||||
console.log(assistantStore.getCertificate)
|
||||
console.log(param)
|
||||
const response = await questionApi.add(param)
|
||||
const response = await questionApi.add(param, controller)
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
@@ -235,7 +230,13 @@ function getChatData(recordId?: number) {
|
||||
function stop() {
|
||||
stopFlag.value = true
|
||||
_loading.value = false
|
||||
emits('stop')
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop()
|
||||
})
|
||||
|
||||
defineExpose({ sendMessage, index: () => index.value, stop })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import BaseAnswer from './BaseAnswer.vue'
|
||||
import { chatApi, ChatInfo, type ChatMessage, ChatRecord } from '@/api/chat.ts'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
import { computed, nextTick, onBeforeUnmount, ref } from 'vue'
|
||||
import MdComponent from '@/views/chat/component/MdComponent.vue'
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -23,6 +23,7 @@ const props = withDefaults(
|
||||
const emits = defineEmits([
|
||||
'finish',
|
||||
'error',
|
||||
'stop',
|
||||
'update:loading',
|
||||
'update:chatList',
|
||||
'update:currentChat',
|
||||
@@ -95,7 +96,7 @@ const sendMessage = async () => {
|
||||
|
||||
try {
|
||||
const controller: AbortController = new AbortController()
|
||||
const response = await chatApi.predict(currentRecord.predict_record_id)
|
||||
const response = await chatApi.predict(currentRecord.predict_record_id, controller)
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
@@ -195,10 +196,17 @@ const sendMessage = async () => {
|
||||
_loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function stop() {
|
||||
stopFlag.value = true
|
||||
_loading.value = false
|
||||
emits('stop')
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stop()
|
||||
})
|
||||
|
||||
defineExpose({ sendMessage, index: () => index.value, chatList: () => _chatList, stop })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
:questions="message.recommended_question"
|
||||
:first-chat="message.first_chat"
|
||||
@click-question="quickAsk"
|
||||
@stop="onChatStop"
|
||||
/>
|
||||
<UserChat v-if="message.role === 'user'" :message="message" />
|
||||
<template v-if="message.role === 'assistant' && !message.first_chat">
|
||||
@@ -118,6 +119,7 @@
|
||||
:reasoning-name="['sql_answer', 'chart_answer']"
|
||||
@finish="onChartAnswerFinish"
|
||||
@error="onChartAnswerError"
|
||||
@stop="onChatStop"
|
||||
>
|
||||
<ChartBlock style="margin-top: 12px" :message="message" />
|
||||
<div
|
||||
@@ -190,6 +192,7 @@
|
||||
:questions="message.recommended_question"
|
||||
:first-chat="message.first_chat"
|
||||
@click-question="quickAsk"
|
||||
@stop="onChatStop"
|
||||
/>
|
||||
</template>
|
||||
</ChartAnswer>
|
||||
@@ -206,6 +209,7 @@
|
||||
:message="message"
|
||||
@finish="onAnalysisAnswerFinish"
|
||||
@error="onAnalysisAnswerError"
|
||||
@stop="onChatStop"
|
||||
>
|
||||
<div
|
||||
v-if="message.record?.error && message.record?.error?.trim().length > 0"
|
||||
@@ -230,6 +234,7 @@
|
||||
:message="message"
|
||||
@finish="onPredictAnswerFinish"
|
||||
@error="onPredictAnswerError"
|
||||
@stop="onChatStop"
|
||||
>
|
||||
<ChartBlock style="margin-top: 12px" :message="message" is-predict />
|
||||
<div
|
||||
@@ -382,9 +387,9 @@ const computedMessages = computed<Array<ChatMessage>>(() => {
|
||||
return messages
|
||||
})
|
||||
|
||||
const goEmpty = () => {
|
||||
const goEmpty = (func?: (...p: any[]) => void, ...param: any[]) => {
|
||||
inputMessage.value = ''
|
||||
stop()
|
||||
stop(func, ...param)
|
||||
}
|
||||
|
||||
const createNewChatSimple = async () => {
|
||||
@@ -418,8 +423,8 @@ function getChatList() {
|
||||
}
|
||||
|
||||
function onClickHistory(chat: Chat) {
|
||||
console.log('click history', chat)
|
||||
scrollToBottom()
|
||||
console.debug('click history', chat)
|
||||
}
|
||||
|
||||
function toAssistantHistory(chat: Chat) {
|
||||
@@ -510,6 +515,13 @@ async function onChartAnswerFinish(id: number) {
|
||||
function onChartAnswerError() {
|
||||
loading.value = false
|
||||
isTyping.value = false
|
||||
console.debug('onChartAnswerError')
|
||||
}
|
||||
|
||||
function onChatStop() {
|
||||
loading.value = false
|
||||
isTyping.value = false
|
||||
console.debug('onChatStop')
|
||||
}
|
||||
|
||||
const sendMessage = async () => {
|
||||
@@ -698,7 +710,7 @@ function clickInput() {
|
||||
inputRef.value?.focus()
|
||||
}
|
||||
|
||||
function stop() {
|
||||
function stop(func?: (...p: any[]) => void, ...param: any[]) {
|
||||
if (recommendQuestionRef.value) {
|
||||
if (recommendQuestionRef.value instanceof Array) {
|
||||
for (let i = 0; i < recommendQuestionRef.value.length; i++) {
|
||||
@@ -735,6 +747,9 @@ function stop() {
|
||||
predictAnswerRef.value.stop()
|
||||
}
|
||||
}
|
||||
if (func && typeof func === 'function') {
|
||||
func(...param)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
@@ -8,7 +8,6 @@ import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import edit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ParamsForm from './ParamsForm.vue'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
|
||||
interface Table {
|
||||
name: string
|
||||
|
||||
@@ -275,6 +275,7 @@ const back = () => {
|
||||
<EmptyBackground
|
||||
v-if="!!keywords && !datasourceListWithSearch.length"
|
||||
:description="$t('datasource.relevant_content_found')"
|
||||
class="datasource-yet"
|
||||
img-type="tree"
|
||||
/>
|
||||
|
||||
|
||||
@@ -463,10 +463,7 @@ defineExpose({
|
||||
>
|
||||
<div v-if="isCreate && activeStep !== 2" class="model-name">
|
||||
{{ activeName }}
|
||||
<span
|
||||
v-if="form.type !== 'excel'"
|
||||
style="margin-left: 8px; color: #8f959e; font-size: 12px; margin-top: 7px"
|
||||
>
|
||||
<span v-if="form.type !== 'excel'" style="margin-left: 8px; color: #8f959e; font-size: 12px">
|
||||
<span>{{ t('ds.form.support_version') }}: </span>
|
||||
<span v-if="form.type === 'sqlServer'">2012+</span>
|
||||
<span v-else-if="form.type === 'oracle'">12+</span>
|
||||
|
||||
@@ -109,7 +109,6 @@ const communicationCb = async (event: any) => {
|
||||
}
|
||||
if (event.data?.busi == 'certificate') {
|
||||
const certificate = event.data['certificate']
|
||||
console.log(certificate)
|
||||
assistantStore.setType(1)
|
||||
assistantStore.setCertificate(certificate)
|
||||
// store certificate to pinia
|
||||
|
||||
@@ -440,8 +440,11 @@ const handleCurrentChange = (val: number) => {
|
||||
bottom: 0;
|
||||
border-top: 1px solid #1f232926;
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
align-items: center;
|
||||
padding-left: 24px;
|
||||
background-color: #fff;
|
||||
z-index: 10;
|
||||
|
||||
.danger-button {
|
||||
border: 1px solid var(--ed-color-danger);
|
||||
|
||||
@@ -442,9 +442,10 @@ const savePermission = () => {
|
||||
id,
|
||||
name,
|
||||
permissions: permissionsObj,
|
||||
users: isCreate.value
|
||||
? selectPermissionRef.value.checkedWorkspace.map((ele: any) => ele.id)
|
||||
: users,
|
||||
users:
|
||||
isCreate.value || activeStep.value === 1
|
||||
? selectPermissionRef.value.checkedWorkspace.map((ele: any) => ele.id)
|
||||
: users,
|
||||
}
|
||||
if (!id) {
|
||||
delete obj.id
|
||||
@@ -764,6 +765,7 @@ const columnRules = {
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('permission.set_rule')">
|
||||
<el-input
|
||||
v-if="ruleType !== 1"
|
||||
v-model="searchColumn"
|
||||
:placeholder="$t('permission.search_rule_group')"
|
||||
autocomplete="off"
|
||||
@@ -775,7 +777,9 @@ const columnRules = {
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<AuthTree v-if="ruleType === 1" ref="authTreeRef" @save="saveAuthTree"></AuthTree>
|
||||
<div v-if="ruleType === 1" class="auth-tree_content">
|
||||
<AuthTree ref="authTreeRef" @save="saveAuthTree"></AuthTree>
|
||||
</div>
|
||||
<div v-else class="table-content">
|
||||
<el-table
|
||||
:empty-text="$t('permission.no_fields_yet')"
|
||||
@@ -931,6 +935,17 @@ const columnRules = {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-tree_content {
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #dee0e3;
|
||||
min-height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow-y: auto;
|
||||
margin-top: -16px;
|
||||
}
|
||||
}
|
||||
|
||||
.system-permission_user.system-permission_user {
|
||||
|
||||
@@ -131,19 +131,18 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="state.pageInfo.currentPage"
|
||||
v-model:page-size="state.pageInfo.pageSize"
|
||||
:page-sizes="[10, 20, 30]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="state.pageInfo.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="state.pageInfo.currentPage"
|
||||
v-model:page-size="state.pageInfo.pageSize"
|
||||
:page-sizes="[10, 20, 30]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="state.pageInfo.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="multipleSelectionAll.length" class="bottom-select">
|
||||
@@ -193,6 +192,7 @@
|
||||
<el-form-item prop="account" :label="t('user.account')">
|
||||
<el-input
|
||||
v-model="state.form.account"
|
||||
:disabled="!!state.form.id"
|
||||
:placeholder="$t('datasource.please_enter') + $t('common.empty') + $t('user.account')"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -316,6 +316,7 @@ const dialogVisiblePassword = ref(false)
|
||||
const isIndeterminate = ref(true)
|
||||
const drawerMainRef = ref()
|
||||
const userImportRef = ref()
|
||||
const selectionLoading = ref(false)
|
||||
const filterOption = ref<any[]>([
|
||||
{
|
||||
type: 'enum',
|
||||
@@ -359,7 +360,7 @@ const defaultForm = {
|
||||
account: '',
|
||||
oid: 0,
|
||||
email: '',
|
||||
status: '',
|
||||
status: 1,
|
||||
phoneNumber: '',
|
||||
oid_list: [],
|
||||
}
|
||||
@@ -451,7 +452,9 @@ const handleConfirmPassword = () => {
|
||||
})
|
||||
dialogVisiblePassword.value = false
|
||||
}
|
||||
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
if (selectionLoading.value) return
|
||||
const ids = state.tableData.map((ele: any) => ele.id)
|
||||
multipleSelectionAll.value = [
|
||||
...multipleSelectionAll.value.filter((ele) => !ids.includes(ele.id)),
|
||||
@@ -481,6 +484,7 @@ const handleToggleRowSelection = (check: boolean = true) => {
|
||||
}
|
||||
checkAll.value = i === state.tableData.length
|
||||
isIndeterminate.value = !(i === 0 || i === state.tableData.length)
|
||||
selectionLoading.value = false
|
||||
}
|
||||
const handleSearch = () => {
|
||||
search()
|
||||
@@ -541,6 +545,7 @@ const deleteBatchUser = () => {
|
||||
autofocus: false,
|
||||
}).then(() => {
|
||||
userApi.deleteBatch(multipleSelectionAll.value.map((ele) => ele.id)).then(() => {
|
||||
multipleSelectionAll.value = []
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
@@ -557,13 +562,20 @@ const deleteHandler = (row: any) => {
|
||||
customClass: 'confirm-no_icon',
|
||||
autofocus: false,
|
||||
}).then(() => {
|
||||
userApi.delete(row.id).then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
})
|
||||
search()
|
||||
multipleSelectionAll.value = multipleSelectionAll.value.filter((ele) => ele.id !== row.id)
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
})
|
||||
search()
|
||||
// userApi.delete(row.id).then(() => {
|
||||
// multipleSelectionAll.value = multipleSelectionAll.value.filter((ele) => ele.id !== row.id)
|
||||
// ElMessage({
|
||||
// type: 'success',
|
||||
// message: t('dashboard.delete_success'),
|
||||
// })
|
||||
// search()
|
||||
// })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -613,7 +625,7 @@ const search = () => {
|
||||
.then((res: any) => {
|
||||
state.tableData = res.items
|
||||
state.pageInfo.total = res.total
|
||||
|
||||
selectionLoading.value = true
|
||||
nextTick(() => {
|
||||
handleToggleRowSelection()
|
||||
})
|
||||
@@ -692,11 +704,13 @@ onMounted(() => {
|
||||
height: 64px;
|
||||
width: calc(100% + 48px);
|
||||
left: -24px;
|
||||
background-color: #fff;
|
||||
bottom: 0;
|
||||
border-top: 1px solid #1f232926;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 24px;
|
||||
z-index: 10;
|
||||
|
||||
.danger-button {
|
||||
border: 1px solid var(--ed-color-danger);
|
||||
@@ -734,12 +748,8 @@ onMounted(() => {
|
||||
.sqlbot-table {
|
||||
border-radius: 6px;
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 100px);
|
||||
max-height: calc(100vh - 150px);
|
||||
overflow-y: auto;
|
||||
|
||||
&.is-filter {
|
||||
max-height: calc(100vh - 256px);
|
||||
}
|
||||
:deep(.ed-table) {
|
||||
--el-table-header-bg-color: #f5f7fa;
|
||||
--el-table-border-color: #ebeef5;
|
||||
@@ -795,12 +805,13 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ const open = async (id: any) => {
|
||||
checkAll.value = false
|
||||
isIndeterminate.value = false
|
||||
const systemWorkspaceList = await workspaceOptionUserList({ oid }, 1, 1000)
|
||||
workspace.value = systemWorkspaceList.items as any
|
||||
workspace.value = systemWorkspaceList.items.filter((ele: any) => +ele.id !== 1) as any
|
||||
loading.value = false
|
||||
centerDialogVisible.value = true
|
||||
}
|
||||
@@ -203,7 +203,8 @@ defineExpose({
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
overflow-y: auto;
|
||||
|
||||
.flex-between {
|
||||
@@ -239,6 +240,8 @@ defineExpose({
|
||||
|
||||
.border-r {
|
||||
border-right: 1px solid #dee0e3;
|
||||
width: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,6 +30,7 @@ const multipleSelectionAll = ref<any[]>([])
|
||||
const tableList = ref([] as any[])
|
||||
const keyword = ref('')
|
||||
const keywordsMember = ref('')
|
||||
const oldKeywordsMember = ref('')
|
||||
const workspaceFormRef = ref()
|
||||
const authorizedWorkspaceDialog = ref()
|
||||
const tableListWithSearch = computed(() => {
|
||||
@@ -210,8 +211,9 @@ const search = () => {
|
||||
pageInfo.currentPage,
|
||||
pageInfo.pageSize
|
||||
).then((res) => {
|
||||
fieldList.value = res.items
|
||||
fieldList.value = res.items.sort((a: any, b: any) => b.weight - a.weight)
|
||||
pageInfo.total = res.total
|
||||
oldKeywordsMember.value = keywordsMember.value
|
||||
})
|
||||
}
|
||||
|
||||
@@ -342,7 +344,7 @@ const handleCurrentChange = (val: number) => {
|
||||
</el-popover>
|
||||
</div>
|
||||
<div v-if="!!keyword && !tableListWithSearch.length" class="no-result">
|
||||
{{ $t('workspace.historical_dialogue') }}
|
||||
{{ $t('workspace.relevant_content_found') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -463,31 +465,31 @@ const handleCurrentChange = (val: number) => {
|
||||
</el-table-column>
|
||||
<template #empty>
|
||||
<EmptyBackground
|
||||
v-if="!keywordsMember && !fieldListWithSearch.length"
|
||||
v-if="!oldKeywordsMember && !fieldListWithSearch.length"
|
||||
:description="$t('workspace.no_user')"
|
||||
img-type="noneWhite"
|
||||
/>
|
||||
|
||||
<EmptyBackground
|
||||
v-if="!!keywordsMember && !fieldListWithSearch.length"
|
||||
v-if="!!oldKeywordsMember && !fieldListWithSearch.length"
|
||||
:description="$t('datasource.relevant_content_found')"
|
||||
img-type="tree"
|
||||
/>
|
||||
</template>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pageInfo.currentPage"
|
||||
v-model:page-size="pageInfo.pageSize"
|
||||
:page-sizes="[10, 20, 30]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pageInfo.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pageInfo.currentPage"
|
||||
v-model:page-size="pageInfo.pageSize"
|
||||
:page-sizes="[10, 20, 30]"
|
||||
:background="true"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pageInfo.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="multipleSelectionAll.length" class="bottom-select">
|
||||
<el-checkbox
|
||||
@@ -700,16 +702,17 @@ const handleCurrentChange = (val: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.table-content {
|
||||
padding: 0 24px 16px 24px;
|
||||
height: calc(100% - 104px);
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
margin-top: 16px;
|
||||
}
|
||||
height: calc(100% - 168px);
|
||||
overflow-y: auto;
|
||||
|
||||
.preview-or-schema {
|
||||
:deep(.user-source) {
|
||||
@@ -779,7 +782,9 @@ const handleCurrentChange = (val: number) => {
|
||||
border-top: 1px solid #1f232926;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
padding-left: 24px;
|
||||
z-index: 10;
|
||||
|
||||
.danger-button {
|
||||
border: 1px solid var(--ed-color-danger);
|
||||
|
||||
Reference in New Issue
Block a user