mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat: add export terminologies
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
import asyncio
|
||||
import io
|
||||
from typing import Optional
|
||||
|
||||
import pandas as pd
|
||||
from fastapi import APIRouter, Query
|
||||
from fastapi.responses import StreamingResponse
|
||||
|
||||
from apps.chat.models.chat_model import AxisObj
|
||||
from apps.chat.task.llm import LLMService
|
||||
from apps.terminology.curd.terminology import page_terminology, create_terminology, update_terminology, \
|
||||
delete_terminology, enable_terminology
|
||||
delete_terminology, enable_terminology, get_all_terminology
|
||||
from apps.terminology.models.terminology_model import TerminologyInfo
|
||||
from common.core.deps import SessionDep, CurrentUser, Trans
|
||||
|
||||
@@ -42,3 +48,44 @@ async def delete(session: SessionDep, id_list: list[int]):
|
||||
@router.get("/{id}/enable/{enabled}")
|
||||
async def enable(session: SessionDep, id: int, enabled: bool, trans: Trans):
|
||||
enable_terminology(session, id, enabled, trans)
|
||||
|
||||
|
||||
@router.get("/export")
|
||||
async def export_excel(session: SessionDep, trans: Trans, current_user: CurrentUser,
|
||||
word: Optional[str] = Query(None, description="搜索术语(可选)")):
|
||||
def inner():
|
||||
_list = get_all_terminology(session, word, oid=current_user.oid)
|
||||
|
||||
data_list = []
|
||||
for obj in _list:
|
||||
_data = {
|
||||
"word": obj.word,
|
||||
"other_words": ', '.join(obj.other_words) if obj.other_words else '',
|
||||
"description": obj.description,
|
||||
"all_data_sources": 'Y' if obj.specific_ds else 'N',
|
||||
"datasource": ', '.join(obj.datasource_names) if obj.datasource_names else '',
|
||||
}
|
||||
data_list.append(_data)
|
||||
|
||||
fields = []
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.term_name'), value='word'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.synonyms'), value='other_words'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.term_description'), value='description'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.effective_data_sources'), value='datasource'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.all_data_sources'), value='all_data_sources'))
|
||||
|
||||
md_data, _fields_list = LLMService.convert_object_array_for_pandas(fields, data_list)
|
||||
|
||||
df = pd.DataFrame(md_data, columns=_fields_list)
|
||||
|
||||
buffer = io.BytesIO()
|
||||
|
||||
with pd.ExcelWriter(buffer, engine='xlsxwriter',
|
||||
engine_kwargs={'options': {'strings_to_numbers': False}}) as writer:
|
||||
df.to_excel(writer, sheet_name='Sheet1', index=False)
|
||||
|
||||
buffer.seek(0)
|
||||
return io.BytesIO(buffer.getvalue())
|
||||
|
||||
result = await asyncio.to_thread(inner)
|
||||
return StreamingResponse(result, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
|
||||
@@ -17,24 +17,18 @@ from common.core.deps import SessionDep, Trans
|
||||
from common.utils.embedding_threads import run_save_terminology_embeddings
|
||||
|
||||
|
||||
def page_terminology(session: SessionDep, current_page: int = 1, page_size: int = 10, name: Optional[str] = None,
|
||||
oid: Optional[int] = 1):
|
||||
_list: List[TerminologyInfo] = []
|
||||
|
||||
def get_terminology_base_query(oid: int, name: Optional[str] = None):
|
||||
"""
|
||||
获取术语查询的基础查询结构
|
||||
"""
|
||||
child = aliased(Terminology)
|
||||
|
||||
current_page = max(1, current_page)
|
||||
page_size = max(10, page_size)
|
||||
|
||||
total_count = 0
|
||||
total_pages = 0
|
||||
|
||||
if name and name.strip() != "":
|
||||
keyword_pattern = f"%{name.strip()}%"
|
||||
# 步骤1:先找到所有匹配的节点ID(无论是父节点还是子节点)
|
||||
matched_ids_subquery = (
|
||||
select(Terminology.id)
|
||||
.where(and_(Terminology.word.ilike(keyword_pattern), Terminology.oid == oid)) # LIKE查询条件
|
||||
.where(and_(Terminology.word.ilike(keyword_pattern), Terminology.oid == oid))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
@@ -51,94 +45,31 @@ def page_terminology(session: SessionDep, current_page: int = 1, page_size: int
|
||||
)
|
||||
.where(Terminology.pid.is_(None)) # 只取父节点
|
||||
)
|
||||
|
||||
count_stmt = select(func.count()).select_from(parent_ids_subquery.subquery())
|
||||
total_count = session.execute(count_stmt).scalar()
|
||||
total_pages = (total_count + page_size - 1) // page_size
|
||||
|
||||
if current_page > total_pages:
|
||||
current_page = 1
|
||||
|
||||
# 步骤3:获取分页后的父节点ID
|
||||
paginated_parent_ids = (
|
||||
parent_ids_subquery
|
||||
.order_by(Terminology.create_time.desc())
|
||||
.offset((current_page - 1) * page_size)
|
||||
.limit(page_size)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 步骤4:获取这些父节点的childrenNames
|
||||
children_subquery = (
|
||||
select(
|
||||
child.pid,
|
||||
func.jsonb_agg(child.word).filter(child.word.isnot(None)).label('other_words')
|
||||
)
|
||||
.where(child.pid.isnot(None))
|
||||
.group_by(child.pid)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 创建子查询来获取数据源名称,添加类型转换
|
||||
datasource_names_subquery = (
|
||||
select(
|
||||
func.jsonb_array_elements(Terminology.datasource_ids).cast(BigInteger).label('ds_id'),
|
||||
Terminology.id.label('term_id')
|
||||
)
|
||||
.where(Terminology.id.in_(paginated_parent_ids))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 主查询
|
||||
stmt = (
|
||||
select(
|
||||
Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
func.jsonb_agg(CoreDatasource.name).filter(CoreDatasource.id.isnot(None)).label('datasource_names'),
|
||||
Terminology.enabled
|
||||
)
|
||||
.outerjoin(
|
||||
children_subquery,
|
||||
Terminology.id == children_subquery.c.pid
|
||||
)
|
||||
# 关联数据源名称子查询和 CoreDatasource 表
|
||||
.outerjoin(
|
||||
datasource_names_subquery,
|
||||
datasource_names_subquery.c.term_id == Terminology.id
|
||||
)
|
||||
.outerjoin(
|
||||
CoreDatasource,
|
||||
CoreDatasource.id == datasource_names_subquery.c.ds_id
|
||||
)
|
||||
.where(and_(Terminology.id.in_(paginated_parent_ids), Terminology.oid == oid))
|
||||
.group_by(
|
||||
Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
Terminology.enabled
|
||||
)
|
||||
.order_by(Terminology.create_time.desc())
|
||||
)
|
||||
else:
|
||||
parent_ids_subquery = (
|
||||
select(Terminology.id)
|
||||
.where(and_(Terminology.pid.is_(None), Terminology.oid == oid)) # 只取父节点
|
||||
.where(and_(Terminology.pid.is_(None), Terminology.oid == oid))
|
||||
)
|
||||
count_stmt = select(func.count()).select_from(parent_ids_subquery.subquery())
|
||||
total_count = session.execute(count_stmt).scalar()
|
||||
total_pages = (total_count + page_size - 1) // page_size
|
||||
|
||||
if current_page > total_pages:
|
||||
current_page = 1
|
||||
return parent_ids_subquery, child
|
||||
|
||||
|
||||
def build_terminology_query(session: SessionDep, oid: int, name: Optional[str] = None,
|
||||
paginate: bool = True, current_page: int = 1, page_size: int = 10):
|
||||
"""
|
||||
构建术语查询的通用方法
|
||||
"""
|
||||
parent_ids_subquery, child = get_terminology_base_query(oid, name)
|
||||
|
||||
# 计算总数
|
||||
count_stmt = select(func.count()).select_from(parent_ids_subquery.subquery())
|
||||
total_count = session.execute(count_stmt).scalar()
|
||||
|
||||
if paginate:
|
||||
# 分页处理
|
||||
page_size = max(10, page_size)
|
||||
total_pages = (total_count + page_size - 1) // page_size
|
||||
current_page = max(1, min(current_page, total_pages)) if total_pages > 0 else 1
|
||||
|
||||
paginated_parent_ids = (
|
||||
parent_ids_subquery
|
||||
@@ -147,65 +78,85 @@ def page_terminology(session: SessionDep, current_page: int = 1, page_size: int
|
||||
.limit(page_size)
|
||||
.subquery()
|
||||
)
|
||||
else:
|
||||
# 不分页,获取所有数据
|
||||
total_pages = 1
|
||||
current_page = 1
|
||||
page_size = total_count if total_count > 0 else 1
|
||||
|
||||
children_subquery = (
|
||||
select(
|
||||
child.pid,
|
||||
func.jsonb_agg(child.word).filter(child.word.isnot(None)).label('other_words')
|
||||
)
|
||||
.where(child.pid.isnot(None))
|
||||
.group_by(child.pid)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 创建子查询来获取数据源名称
|
||||
datasource_names_subquery = (
|
||||
select(
|
||||
func.jsonb_array_elements(Terminology.datasource_ids).cast(BigInteger).label('ds_id'),
|
||||
Terminology.id.label('term_id')
|
||||
)
|
||||
.where(Terminology.id.in_(paginated_parent_ids))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
stmt = (
|
||||
select(
|
||||
Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
func.jsonb_agg(CoreDatasource.name).filter(CoreDatasource.id.isnot(None)).label('datasource_names'),
|
||||
Terminology.enabled
|
||||
)
|
||||
.outerjoin(
|
||||
children_subquery,
|
||||
Terminology.id == children_subquery.c.pid
|
||||
)
|
||||
# 关联数据源名称子查询和 CoreDatasource 表
|
||||
.outerjoin(
|
||||
datasource_names_subquery,
|
||||
datasource_names_subquery.c.term_id == Terminology.id
|
||||
)
|
||||
.outerjoin(
|
||||
CoreDatasource,
|
||||
CoreDatasource.id == datasource_names_subquery.c.ds_id
|
||||
)
|
||||
.where(and_(Terminology.id.in_(paginated_parent_ids), Terminology.oid == oid))
|
||||
.group_by(Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
Terminology.enabled
|
||||
)
|
||||
paginated_parent_ids = (
|
||||
parent_ids_subquery
|
||||
.order_by(Terminology.create_time.desc())
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 构建公共查询部分
|
||||
children_subquery = (
|
||||
select(
|
||||
child.pid,
|
||||
func.jsonb_agg(child.word).filter(child.word.isnot(None)).label('other_words')
|
||||
)
|
||||
.where(child.pid.isnot(None))
|
||||
.group_by(child.pid)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
# 创建子查询来获取数据源名称
|
||||
datasource_names_subquery = (
|
||||
select(
|
||||
func.jsonb_array_elements(Terminology.datasource_ids).cast(BigInteger).label('ds_id'),
|
||||
Terminology.id.label('term_id')
|
||||
)
|
||||
.where(Terminology.id.in_(paginated_parent_ids))
|
||||
.subquery()
|
||||
)
|
||||
|
||||
stmt = (
|
||||
select(
|
||||
Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
func.jsonb_agg(CoreDatasource.name).filter(CoreDatasource.id.isnot(None)).label('datasource_names'),
|
||||
Terminology.enabled
|
||||
)
|
||||
.outerjoin(
|
||||
children_subquery,
|
||||
Terminology.id == children_subquery.c.pid
|
||||
)
|
||||
.outerjoin(
|
||||
datasource_names_subquery,
|
||||
datasource_names_subquery.c.term_id == Terminology.id
|
||||
)
|
||||
.outerjoin(
|
||||
CoreDatasource,
|
||||
CoreDatasource.id == datasource_names_subquery.c.ds_id
|
||||
)
|
||||
.where(and_(Terminology.id.in_(paginated_parent_ids), Terminology.oid == oid))
|
||||
.group_by(
|
||||
Terminology.id,
|
||||
Terminology.word,
|
||||
Terminology.create_time,
|
||||
Terminology.description,
|
||||
Terminology.specific_ds,
|
||||
Terminology.datasource_ids,
|
||||
children_subquery.c.other_words,
|
||||
Terminology.enabled
|
||||
)
|
||||
.order_by(Terminology.create_time.desc())
|
||||
)
|
||||
|
||||
return stmt, total_count, total_pages, current_page, page_size
|
||||
|
||||
|
||||
def execute_terminology_query(session: SessionDep, stmt) -> List[TerminologyInfo]:
|
||||
"""
|
||||
执行查询并返回术语信息列表
|
||||
"""
|
||||
_list = []
|
||||
result = session.execute(stmt)
|
||||
|
||||
for row in result:
|
||||
@@ -221,9 +172,34 @@ def page_terminology(session: SessionDep, current_page: int = 1, page_size: int
|
||||
enabled=row.enabled if row.enabled is not None else False,
|
||||
))
|
||||
|
||||
return _list
|
||||
|
||||
|
||||
def page_terminology(session: SessionDep, current_page: int = 1, page_size: int = 10,
|
||||
name: Optional[str] = None, oid: Optional[int] = 1):
|
||||
"""
|
||||
分页查询术语(原方法保持不变)
|
||||
"""
|
||||
stmt, total_count, total_pages, current_page, page_size = build_terminology_query(
|
||||
session, oid, name, True, current_page, page_size
|
||||
)
|
||||
_list = execute_terminology_query(session, stmt)
|
||||
|
||||
return current_page, page_size, total_count, total_pages, _list
|
||||
|
||||
|
||||
def get_all_terminology(session: SessionDep, name: Optional[str] = None, oid: Optional[int] = 1):
|
||||
"""
|
||||
获取所有术语(不分页)
|
||||
"""
|
||||
stmt, total_count, total_pages, current_page, page_size = build_terminology_query(
|
||||
session, oid, name, False
|
||||
)
|
||||
_list = execute_terminology_query(session, stmt)
|
||||
|
||||
return _list
|
||||
|
||||
|
||||
def create_terminology(session: SessionDep, info: TerminologyInfo, oid: int, trans: Trans):
|
||||
create_time = datetime.datetime.now()
|
||||
|
||||
|
||||
+31
-26
@@ -1,60 +1,65 @@
|
||||
{
|
||||
"i18n_default_workspace": "Default workspace",
|
||||
"i18n_default_workspace": "Default Workspace",
|
||||
"i18n_ds_name_exist": "Name already exists",
|
||||
"i18n_concat_admin": "Please contact administrator!",
|
||||
"i18n_concat_admin": "Please contact the administrator!",
|
||||
"i18n_exist": "{msg} already exists!",
|
||||
"i18n_name": "Name",
|
||||
"i18n_not_exist": "{msg} not exists",
|
||||
"i18n_not_exist": "{msg} does not exist!",
|
||||
"i18n_error": "{key} error!",
|
||||
"i18n_miss_args": "Missing {key} parameter!",
|
||||
"i18n_format_invalid": "{key} format is incorrect!",
|
||||
"i18n_login": {
|
||||
"account_pwd_error": "Account or password error!",
|
||||
"account_pwd_error": "Incorrect account or password!",
|
||||
"no_associated_ws": "No associated workspace, {msg}",
|
||||
"user_disable": "Account disabled, {msg}"
|
||||
"user_disable": "Account is disabled, {msg}"
|
||||
},
|
||||
"i18n_user": {
|
||||
"account": "Account",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"language_not_support": "System does not support [{key}] language!",
|
||||
"ws_miss": "The current user is not in the workspace [{ws}]!"
|
||||
"language_not_support": "The system does not support [{key}] language!",
|
||||
"ws_miss": "Current user is not in the workspace [{ws}]!"
|
||||
},
|
||||
"i18n_ws": {
|
||||
"title": "Workspace"
|
||||
},
|
||||
"i18n_permission": {
|
||||
"only_admin": "Only administrators can call this!",
|
||||
"no_permission": "No permission to access {url}{msg}",
|
||||
"authenticate_invalid": "Authenticate invalid [{msg}]",
|
||||
"token_expired": "Token has expired"
|
||||
"only_admin": "Only administrators are allowed to call!",
|
||||
"no_permission": "No permission to call {url}{msg}",
|
||||
"authenticate_invalid": "Authentication invalid【{msg}】",
|
||||
"token_expired": "Token expired"
|
||||
},
|
||||
"i18n_llm": {
|
||||
"validate_error": "Validation failed [{msg}]",
|
||||
"delete_default_error": "Cannot delete default model [{key}]!",
|
||||
"miss_default": "The default large language model has not been configured"
|
||||
"delete_default_error": "Cannot delete the default model [{key}]!",
|
||||
"miss_default": "Default large language model has not been configured"
|
||||
},
|
||||
"i18n_ds_invalid": "Datasource Invalid",
|
||||
"i18n_ds_invalid": "Datasource connection is invalid",
|
||||
"i18n_embedded": {
|
||||
"invalid_origin": "Domain verification failed [{origin}]"
|
||||
"invalid_origin": "Domain name validation failed【{origin}】"
|
||||
},
|
||||
"i18n_terminology": {
|
||||
"terminology_not_exists": "Terminology does not exists",
|
||||
"datasource_cannot_be_none": "Datasource cannot be none or empty",
|
||||
"cannot_be_repeated": "Term name, synonyms cannot be repeated",
|
||||
"exists_in_db": "Term name, synonyms exists"
|
||||
"terminology_not_exists": "This terminology does not exist",
|
||||
"datasource_cannot_be_none": "Datasource cannot be empty",
|
||||
"cannot_be_repeated": "Terminology name and synonyms cannot be repeated",
|
||||
"exists_in_db": "Terminology name and synonyms already exist",
|
||||
"term_name": "Terminology Name",
|
||||
"term_description": "Terminology Description",
|
||||
"effective_data_sources": "Effective Data Sources",
|
||||
"all_data_sources": "All Data Sources",
|
||||
"synonyms": "Synonyms"
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "Datasource cannot be none or empty",
|
||||
"datasource_assistant_cannot_be_none": "Datasource or Advanced application cannot be all none",
|
||||
"data_training_not_exists": "Example does not exists",
|
||||
"exists_in_db": "Question exists"
|
||||
"datasource_cannot_be_none": "Datasource cannot be empty",
|
||||
"datasource_assistant_cannot_be_none": "Datasource or advanced application cannot both be empty",
|
||||
"data_training_not_exists": "This example does not exist",
|
||||
"exists_in_db": "This question already exists"
|
||||
},
|
||||
"i18n_custom_prompt": {
|
||||
"exists_in_db": "Prompt name exists",
|
||||
"not_exists": "Prompt does not exists"
|
||||
"exists_in_db": "Template name already exists",
|
||||
"not_exists": "This template does not exist"
|
||||
},
|
||||
"i18n_excel_export": {
|
||||
"data_is_empty": "The form data is empty, cannot export data"
|
||||
"data_is_empty": "Form data is empty, unable to export data"
|
||||
}
|
||||
}
|
||||
+37
-28
@@ -1,56 +1,65 @@
|
||||
{
|
||||
"i18n_default_workspace": "기본 워크스페이스",
|
||||
"i18n_ds_name_exist": "이미 존재하는 이름입니다",
|
||||
"i18n_concat_admin": "관리자에게 문의해 주세요!",
|
||||
"i18n_default_workspace": "기본 작업 공간",
|
||||
"i18n_ds_name_exist": "이름이 이미 존재합니다",
|
||||
"i18n_concat_admin": "관리자에게 문의하세요!",
|
||||
"i18n_exist": "{msg}이(가) 이미 존재합니다!",
|
||||
"i18n_name": "이름",
|
||||
"i18n_not_exist": "{msg}을(를) 찾을 수 없습니다",
|
||||
"i18n_not_exist": "{msg}이(가) 존재하지 않습니다!",
|
||||
"i18n_error": "{key} 오류!",
|
||||
"i18n_miss_args": "{key} 매개변수가 없습니다!",
|
||||
"i18n_miss_args": "{key} 매개변수가 누락되었습니다!",
|
||||
"i18n_format_invalid": "{key} 형식이 올바르지 않습니다!",
|
||||
"i18n_login": {
|
||||
"account_pwd_error": "계정 또는 비밀번호가 올바르지 않습니다!",
|
||||
"no_associated_ws": "연결된 워크스페이스가 없습니다. {msg}",
|
||||
"user_disable": "계정이 비활성화되었습니다. {msg}"
|
||||
"account_pwd_error": "계정 또는 비밀번호가 잘못되었습니다!",
|
||||
"no_associated_ws": "연결된 작업 공간이 없습니다, {msg}",
|
||||
"user_disable": "계정이 비활성화되었습니다, {msg}"
|
||||
},
|
||||
"i18n_user": {
|
||||
"account": "계정",
|
||||
"email": "이메일",
|
||||
"password": "비밀번호",
|
||||
"language_not_support": "[{key}] 언어는 지원하지 않습니다!",
|
||||
"ws_miss": "현재 사용자는 워크스페이스 [{ws}]에 속해 있지 않습니다!"
|
||||
"language_not_support": "시스템이 [{key}] 언어를 지원하지 않습니다!",
|
||||
"ws_miss": "현재 사용자가 [{ws}] 작업 공간에 속해 있지 않습니다!"
|
||||
},
|
||||
"i18n_ws": {
|
||||
"title": "워크스페이스"
|
||||
"title": "작업 공간"
|
||||
},
|
||||
"i18n_permission": {
|
||||
"only_admin": "관리자만 호출할 수 있습니다!",
|
||||
"no_permission": "{url}{msg}에 접근 권한이 없습니다",
|
||||
"authenticate_invalid": "인증이 실패했습니다 [{msg}]",
|
||||
"token_expired": "토큰이 만료되었습니다"
|
||||
"no_permission": "{url}{msg} 호출 권한이 없습니다",
|
||||
"authenticate_invalid": "인증 무효 【{msg}】",
|
||||
"token_expired": "토큰이 만료됨"
|
||||
},
|
||||
"i18n_llm": {
|
||||
"validate_error": "검증에 실패했습니다 [{msg}]",
|
||||
"delete_default_error": "기본 모델 [{key}]은 삭제할 수 없습니다!",
|
||||
"miss_default": "기본 LLM이 아직 설정되지 않았습니다"
|
||||
"validate_error": "검증 실패 [{msg}]",
|
||||
"delete_default_error": "기본 모델 [{key}]을(를) 삭제할 수 없습니다!",
|
||||
"miss_default": "기본 대형 언어 모델이 구성되지 않았습니다"
|
||||
},
|
||||
"i18n_ds_invalid": "데이터 소스가 유효하지 않습니다",
|
||||
"i18n_ds_invalid": "데이터 소스 연결이 무효합니다",
|
||||
"i18n_embedded": {
|
||||
"invalid_origin": "도메인 검증에 실패했습니다 [{origin}]"
|
||||
"invalid_origin": "도메인 이름 검증 실패 【{origin}】"
|
||||
},
|
||||
"i18n_terminology": {
|
||||
"terminology_not_exists": "용어를 찾을 수 없습니다",
|
||||
"datasource_cannot_be_none": "데이터 소스를 선택해 주세요",
|
||||
"cannot_be_repeated": "용어 이름과 동의어는 중복될 수 없습니다",
|
||||
"exists_in_db": "용어 이름 또는 동의어가 이미 존재합니다"
|
||||
"terminology_not_exists": "이 용어가 존재하지 않습니다",
|
||||
"datasource_cannot_be_none": "데이터 소스는 비울 수 없습니다",
|
||||
"cannot_be_repeated": "용어 이름과 동의어는 반복될 수 없습니다",
|
||||
"exists_in_db": "용어 이름과 동의어가 이미 존재합니다",
|
||||
"term_name": "용어 이름",
|
||||
"term_description": "용어 설명",
|
||||
"effective_data_sources": "유효 데이터 소스",
|
||||
"all_data_sources": "모든 데이터 소스",
|
||||
"synonyms": "동의어"
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "데이터 소스를 선택해 주세요",
|
||||
"datasource_assistant_cannot_be_none": "데이터 소스와 고급 애플리케이션이 모두 비어 있을 수는 없습니다.",
|
||||
"data_training_not_exists": "예제가 존재하지 않습니다",
|
||||
"exists_in_db": "질문이 이미 존재합니다"
|
||||
"datasource_cannot_be_none": "데이터 소스는 비울 수 없습니다",
|
||||
"datasource_assistant_cannot_be_none": "데이터 소스와 고급 애플리케이션을 모두 비울 수 없습니다",
|
||||
"data_training_not_exists": "이 예시가 존재하지 않습니다",
|
||||
"exists_in_db": "이 질문이 이미 존재합니다"
|
||||
},
|
||||
"i18n_custom_prompt": {
|
||||
"exists_in_db": "템플릿 이름이 이미 존재합니다",
|
||||
"not_exists": "이 템플릿이 존재하지 않습니다"
|
||||
},
|
||||
"i18n_excel_export": {
|
||||
"data_is_empty": "양식 데이터가 없어 내보낼 수 없습니다"
|
||||
"data_is_empty": "폼 데이터가 비어 있어 데이터를 내보낼 수 없습니다"
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,12 @@
|
||||
"terminology_not_exists": "该术语不存在",
|
||||
"datasource_cannot_be_none": "数据源不能为空",
|
||||
"cannot_be_repeated": "术语名称,同义词不能重复",
|
||||
"exists_in_db": "术语名称,同义词已存在"
|
||||
"exists_in_db": "术语名称,同义词已存在",
|
||||
"term_name": "术语名称",
|
||||
"term_description": "术语描述",
|
||||
"effective_data_sources": "生效数据源",
|
||||
"all_data_sources": "所有数据源",
|
||||
"synonyms": "同义词"
|
||||
},
|
||||
"i18n_data_training": {
|
||||
"datasource_cannot_be_none": "数据源不能为空",
|
||||
|
||||
@@ -10,4 +10,10 @@ export const professionalApi = {
|
||||
deleteEmbedded: (params: any) => request.delete('/system/terminology', { data: params }),
|
||||
getOne: (id: any) => request.get(`/system/terminology/${id}`),
|
||||
enable: (id: any, enabled: any) => request.get(`/system/terminology/${id}/enable/${enabled}`),
|
||||
export2Excel: (params: any) =>
|
||||
request.get(`/system/terminology/export`, {
|
||||
params,
|
||||
responseType: 'blob',
|
||||
requestOptions: { customError: true },
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -59,16 +59,16 @@ const showSysmenu = computed(() => {
|
||||
<div class="system-layout">
|
||||
<div class="left-side" :class="collapse && 'left-side-collapse'">
|
||||
<template v-if="showSysmenu">
|
||||
<div @click="toUserIndex" class="sys-management">
|
||||
<div class="sys-management" @click="toUserIndex">
|
||||
<img
|
||||
v-if="loginBg"
|
||||
:style="{ marginLeft: collapse ? '5px' : 0 }"
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
v-if="loginBg"
|
||||
:src="loginBg"
|
||||
:class="!collapse && 'collapse-icon'"
|
||||
alt=""
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<custom_small
|
||||
v-else-if="appearanceStore.themeColor !== 'default'"
|
||||
@@ -80,28 +80,28 @@ const showSysmenu = computed(() => {
|
||||
:style="{ marginLeft: collapse ? '5px' : 0 }"
|
||||
:class="!collapse && 'collapse-icon'"
|
||||
></LOGO_fold>
|
||||
<span v-if="!collapse">{{ $t('training.system_anagement') }}</span>
|
||||
<span v-if="!collapse">{{ $t('training.system_management') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="appearanceStore.isBlue">
|
||||
<img
|
||||
v-if="loginBg && collapse"
|
||||
style="margin: 0 0 6px 5px; cursor: pointer"
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
v-if="loginBg && collapse"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<div v-else-if="loginBg && !collapse" class="default-sqlbot">
|
||||
<img
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
class="collapse-icon"
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<span style="max-width: 150px" :title="appearanceStore.name" class="ellipsis">{{
|
||||
appearanceStore.name
|
||||
@@ -122,22 +122,22 @@ const showSysmenu = computed(() => {
|
||||
</template>
|
||||
<template v-else-if="appearanceStore.themeColor === 'custom'">
|
||||
<img
|
||||
v-if="loginBg && collapse"
|
||||
style="margin: 0 0 6px 5px; cursor: pointer"
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
v-if="loginBg && collapse"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<div v-else-if="loginBg && !collapse" class="default-sqlbot">
|
||||
<img
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
class="collapse-icon"
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<span style="max-width: 150px" :title="appearanceStore.name" class="ellipsis">{{
|
||||
appearanceStore.name
|
||||
@@ -157,22 +157,22 @@ const showSysmenu = computed(() => {
|
||||
</template>
|
||||
<template v-else>
|
||||
<img
|
||||
v-if="loginBg && collapse"
|
||||
style="margin: 0 0 6px 5px; cursor: pointer"
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
v-if="loginBg && collapse"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<div v-else-if="loginBg && !collapse" class="default-sqlbot">
|
||||
<img
|
||||
@click="toChatIndex"
|
||||
height="30"
|
||||
width="30"
|
||||
:src="loginBg"
|
||||
alt=""
|
||||
class="collapse-icon"
|
||||
@click="toChatIndex"
|
||||
/>
|
||||
<span style="max-width: 150px" :title="appearanceStore.name" class="ellipsis">{{
|
||||
appearanceStore.name
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"partial_data_sources": "Partial data sources",
|
||||
"add_it_here": "Drag the table name on the left to add it here",
|
||||
"table_relationship_management": "Table relationship management",
|
||||
"system_anagement": "System Management",
|
||||
"system_management": "System Management",
|
||||
"data_training": "SQL Sample Lib",
|
||||
"problem_description": "Problem Description",
|
||||
"sample_sql": "Sample SQL",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"partial_data_sources": "일부 데이터 소스",
|
||||
"add_it_here": "왼쪽 테이블 이름을 드래그하여 여기에 추가",
|
||||
"table_relationship_management": "테이블 관계 관리",
|
||||
"system_anagement": "시스템 관리",
|
||||
"system_management": "시스템 관리",
|
||||
"data_training": "SQL 예제 라이브러리",
|
||||
"problem_description": "문제 설명",
|
||||
"sample_sql": "예제 SQL",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"partial_data_sources": "部分数据源",
|
||||
"add_it_here": "拖拽左侧表名,添加到这里",
|
||||
"table_relationship_management": "表关系管理",
|
||||
"system_anagement": "系统管理",
|
||||
"system_management": "系统管理",
|
||||
"data_training": "SQL 示例库",
|
||||
"problem_description": "问题描述",
|
||||
"sample_sql": "示例 SQL",
|
||||
|
||||
@@ -66,29 +66,10 @@ const cancelDelete = () => {
|
||||
checkAll.value = false
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
const exportBatchUser = () => {
|
||||
ElMessageBox.confirm(
|
||||
t('professional.selected_2_terms_de', { msg: multipleSelectionAll.value.length }),
|
||||
{
|
||||
confirmButtonType: 'primary',
|
||||
confirmButtonText: t('professional.export'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
customClass: 'confirm-no_icon',
|
||||
autofocus: false,
|
||||
}
|
||||
).then(() => {
|
||||
professionalApi.deleteEmbedded(multipleSelectionAll.value.map((ele) => ele.id)).then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
})
|
||||
multipleSelectionAll.value = []
|
||||
search()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const exportAllUser = () => {
|
||||
const uploadExcel = () => {}
|
||||
|
||||
const exportExcel = () => {
|
||||
ElMessageBox.confirm(t('professional.all_236_terms', { msg: pageInfo.total }), {
|
||||
confirmButtonType: 'primary',
|
||||
confirmButtonText: t('professional.export'),
|
||||
@@ -96,17 +77,52 @@ const exportAllUser = () => {
|
||||
customClass: 'confirm-no_icon',
|
||||
autofocus: false,
|
||||
}).then(() => {
|
||||
professionalApi.deleteEmbedded(multipleSelectionAll.value.map((ele) => ele.id)).then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
searchLoading.value = true
|
||||
professionalApi
|
||||
.export2Excel(keywords.value ? { word: keywords.value } : {})
|
||||
.then((res) => {
|
||||
const blob = new Blob([res], {
|
||||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
})
|
||||
const link = document.createElement('a')
|
||||
link.href = URL.createObjectURL(blob)
|
||||
link.download = `${t('professional.professional_terminology')}.xlsx`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
})
|
||||
.catch(async (error) => {
|
||||
if (error.response) {
|
||||
try {
|
||||
let text = await error.response.data.text()
|
||||
try {
|
||||
text = JSON.parse(text)
|
||||
} finally {
|
||||
ElMessage({
|
||||
message: text,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error processing error response:', e)
|
||||
}
|
||||
} else {
|
||||
console.error('Other error:', error)
|
||||
ElMessage({
|
||||
message: error,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
searchLoading.value = false
|
||||
})
|
||||
multipleSelectionAll.value = []
|
||||
search()
|
||||
})
|
||||
})
|
||||
}
|
||||
const deleteBatchUser = () => {
|
||||
|
||||
const deleteBatch = () => {
|
||||
ElMessageBox.confirm(
|
||||
t('professional.selected_2_terms', { msg: multipleSelectionAll.value.length }),
|
||||
{
|
||||
@@ -355,20 +371,18 @@ const changeStatus = (id: any, val: any) => {
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<template v-if="false">
|
||||
<el-button secondary @click="exportAllUser">
|
||||
<template #icon>
|
||||
<icon_export_outlined />
|
||||
</template>
|
||||
{{ $t('professional.export_all') }}
|
||||
</el-button>
|
||||
<el-button secondary @click="editHandler(null)">
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button secondary @click="exportExcel">
|
||||
<template #icon>
|
||||
<icon_export_outlined />
|
||||
</template>
|
||||
{{ $t('professional.export_all') }}
|
||||
</el-button>
|
||||
<el-button v-if="false" secondary @click="uploadExcel()">
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="editHandler(null)">
|
||||
<template #icon>
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
@@ -423,7 +437,7 @@ const changeStatus = (id: any, val: any) => {
|
||||
</el-table-column>
|
||||
<el-table-column :label="t('ds.status')" width="180">
|
||||
<template #default="scope">
|
||||
<div @click.stop style="display: flex; align-items: center">
|
||||
<div style="display: flex; align-items: center" @click.stop>
|
||||
<el-switch
|
||||
v-model="scope.row.enabled"
|
||||
size="small"
|
||||
@@ -505,11 +519,8 @@ const changeStatus = (id: any, val: any) => {
|
||||
>
|
||||
{{ $t('datasource.select_all') }}
|
||||
</el-checkbox>
|
||||
<button v-if="false" class="primary-button" @click="exportBatchUser">
|
||||
{{ $t('professional.export') }}
|
||||
</button>
|
||||
|
||||
<button class="danger-button" @click="deleteBatchUser">{{ $t('dashboard.delete') }}</button>
|
||||
<button class="danger-button" @click="deleteBatch">{{ $t('dashboard.delete') }}</button>
|
||||
|
||||
<span class="selected">{{
|
||||
$t('user.selected_2_items', { msg: multipleSelectionAll.length })
|
||||
@@ -568,13 +579,13 @@ const changeStatus = (id: any, val: any) => {
|
||||
<el-radio :value="true">{{ $t('training.partial_data_sources') }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-select
|
||||
v-if="pageForm.specific_ds"
|
||||
v-model="pageForm.datasource_ids"
|
||||
multiple
|
||||
v-if="pageForm.specific_ds"
|
||||
filterable
|
||||
@change="handleChange"
|
||||
:placeholder="$t('datasource.Please_select') + $t('common.empty') + $t('ds.title')"
|
||||
style="width: 100%; margin-top: 8px"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-option v-for="item in allDsList" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
|
||||
Reference in New Issue
Block a user