diff --git a/backend/apps/api.py b/backend/apps/api.py index 06dd11b59..23ca0175a 100644 --- a/backend/apps/api.py +++ b/backend/apps/api.py @@ -9,6 +9,7 @@ from apps.terminology.api import terminology from apps.settings.api import base + api_router = APIRouter() api_router.include_router(login.router) api_router.include_router(user.router) diff --git a/backend/apps/chat/api/chat.py b/backend/apps/chat/api/chat.py index 211b95349..6dfe495f2 100644 --- a/backend/apps/chat/api/chat.py +++ b/backend/apps/chat/api/chat.py @@ -81,14 +81,15 @@ async def rename(session: SessionDep, chat: RenameChat): ) -@router.delete("/{chart_id}", response_model=str, summary=f"{PLACEHOLDER_PREFIX}delete_chat") +@router.delete("/{chart_id}/{brief}", response_model=str, summary=f"{PLACEHOLDER_PREFIX}delete_chat") @system_log(LogConfig( operation_type=OperationType.DELETE_QA, operation_detail=OperationDetails.DELETE_QA_DETAILS, module=OperationModules.QA, - resource_id_expr="chart_id" + resource_id_expr="chart_id", + remark_expr="brief" )) -async def delete(session: SessionDep, chart_id: int): +async def delete(session: SessionDep, chart_id: int, brief: str): try: return delete_chat(session=session, chart_id=chart_id) except Exception as e: @@ -158,7 +159,7 @@ def _err(_e: Exception): @router.get("/recent_questions/{datasource_id}", response_model=List[str], summary=f"{PLACEHOLDER_PREFIX}get_recommend_questions") -@require_permissions(permission=SqlbotPermission(type='ds', keyExpression="datasource_id")) +#@require_permissions(permission=SqlbotPermission(type='ds', keyExpression="datasource_id")) async def recommend_questions(session: SessionDep, current_user: CurrentUser, datasource_id: int = Path(..., description=f"{PLACEHOLDER_PREFIX}ds_id")): return list_recent_questions(session=session, current_user=current_user, datasource_id=datasource_id) diff --git a/backend/apps/dashboard/api/dashboard_api.py b/backend/apps/dashboard/api/dashboard_api.py index 7af75d76c..f93d1af7c 100644 --- a/backend/apps/dashboard/api/dashboard_api.py +++ b/backend/apps/dashboard/api/dashboard_api.py @@ -30,14 +30,15 @@ async def update_resource_api(session: SessionDep, user: CurrentUser, dashboard: return update_resource(session=session, user=user, dashboard=dashboard) -@router.delete("/delete_resource/{resource_id}") +@router.delete("/delete_resource/{resource_id}/{name}") @system_log(LogConfig( operation_type=OperationType.DELETE_DASHBOARD, operation_detail=OperationDetails.DELETE_DASHBOARD_DETAILS, module=OperationModules.DASHBOARD, - resource_id_expr="resource_id" + resource_id_expr="resource_id", + remark_expr="name" )) -async def delete_resource_api(session: SessionDep, resource_id: str): +async def delete_resource_api(session: SessionDep, resource_id: str, name: str): return delete_resource(session, resource_id) diff --git a/backend/apps/datasource/api/datasource.py b/backend/apps/datasource/api/datasource.py index 096abb3fd..bbfd996bf 100644 --- a/backend/apps/datasource/api/datasource.py +++ b/backend/apps/datasource/api/datasource.py @@ -30,6 +30,7 @@ TableSchemaResponse, ColumnSchemaResponse, PreviewResponse from sqlbot_xpack.audit.models.log_model import OperationType, OperationDetails, OperationModules from sqlbot_xpack.audit.schemas.logger_decorator import system_log, LogConfig + router = APIRouter(tags=["Datasource"], prefix="/datasource") path = settings.EXCEL_PATH @@ -107,15 +108,16 @@ def inner(): return await asyncio.to_thread(inner) -@router.post("/delete/{id}", response_model=None, summary=f"{PLACEHOLDER_PREFIX}ds_delete") +@router.post("/delete/{id}/{name}", response_model=None, summary=f"{PLACEHOLDER_PREFIX}ds_delete") @require_permissions(permission=SqlbotPermission(type='ds', keyExpression="id")) @system_log(LogConfig( operation_type=OperationType.DELETE_DATASOURCE, operation_detail=OperationDetails.DELETE_DATASOURCE_DETAILS, module=OperationModules.DATASOURCE, - resource_id_expr="id" + resource_id_expr="id", + remark_expr="name" )) -async def delete(session: SessionDep, id: int = Path(..., description=f"{PLACEHOLDER_PREFIX}ds_id")): +async def delete(session: SessionDep, id: int = Path(..., description=f"{PLACEHOLDER_PREFIX}ds_id"), name: str = None): return delete_ds(session, id) @@ -385,6 +387,7 @@ def insert_pg(df, tableName, engine): t_sheet = "数据表列表" +t_s_col = "Sheet名称" t_n_col = "表名" t_c_col = "表备注" f_n_col = "字段名" @@ -404,7 +407,8 @@ def inner(): if id == 0: # download template file_name = '批量上传备注' df_list = [ - {'sheet': t_sheet, 'c1_h': t_n_col, 'c2_h': t_c_col, 'c1': ["user", "score"], + {'sheet': t_sheet, 'c0_h': t_s_col, 'c1_h': t_n_col, 'c2_h': t_c_col, 'c0': ["数据表1", "数据表2"], + 'c1': ["user", "score"], 'c2': ["用来存放用户信息的数据表", "用来存放用户课程信息的数据表"]}, {'sheet': '数据表1', 'c1_h': f_n_col, 'c2_h': f_c_col, 'c1': ["id", "name"], 'c2': ["用户id", "用户姓名"]}, @@ -419,14 +423,15 @@ def inner(): raise HTTPException(400, "No tables") df_list = [] - df1 = {'sheet': t_sheet, 'c1_h': t_n_col, 'c2_h': t_c_col, 'c1': [], 'c2': []} + df1 = {'sheet': t_sheet, 'c0_h': t_s_col,'c1_h': t_n_col, 'c2_h': t_c_col,'c0': [], 'c1': [], 'c2': []} df_list.append(df1) - for table in tables: + for index, table in enumerate(tables): + df1['c0'].append(f"Sheet{index}") df1['c1'].append(table.table_name) df1['c2'].append(table.custom_comment) fields = session.query(CoreField).filter(CoreField.table_id == table.id).all() - df_fields = {'sheet': table.table_name, 'c1_h': f_n_col, 'c2_h': f_c_col, 'c1': [], 'c2': []} + df_fields = {'sheet': f"Sheet{index}", 'c1_h': f_n_col, 'c2_h': f_c_col, 'c1': [], 'c2': []} for field in fields: df_fields['c1'].append(field.field_name) df_fields['c2'].append(field.custom_comment) @@ -435,10 +440,14 @@ def inner(): # build dataframe and export output = io.BytesIO() - with pd.ExcelWriter(output, engine='xlsxwriter') as writer: - for df in df_list: - pd.DataFrame({df['c1_h']: df['c1'], df['c2_h']: df['c2']}).to_excel(writer, sheet_name=df['sheet'], - index=False) + with (pd.ExcelWriter(output, engine='xlsxwriter') as writer): + for index, df in enumerate(df_list): + if index == 0: + pd.DataFrame({df['c0_h']: df['c0'], df['c1_h']: df['c1'], df['c2_h']: df['c2']} + ).to_excel(writer, sheet_name=df['sheet'], index=False) + else: + pd.DataFrame({df['c1_h']: df['c1'], df['c2_h']: df['c2']}).to_excel(writer, sheet_name=df['sheet'], + index=False) output.seek(0) @@ -484,10 +493,14 @@ async def upload_ds_schema(session: SessionDep, id: int = Path(..., description= # print(field_sheets) + # sheet table mapping + sheet_table_map = {} + # get data and update # update table comment if table_sheet and len(table_sheet) > 0: for table in table_sheet: + sheet_table_map[table[t_s_col]] = table[t_n_col] session.query(CoreTable).filter( and_(CoreTable.ds_id == id, CoreTable.table_name == table[t_n_col])).update( {'custom_comment': table[t_c_col]}) @@ -497,8 +510,9 @@ async def upload_ds_schema(session: SessionDep, id: int = Path(..., description= for fields in field_sheets: if len(fields['data']) > 0: # get table id + table_name = sheet_table_map[fields['sheet_name']] table = session.query(CoreTable).filter( - and_(CoreTable.ds_id == id, CoreTable.table_name == fields['sheet_name'])).first() + and_(CoreTable.ds_id == id, CoreTable.table_name == table_name)).first() if table: for field in fields['data']: session.query(CoreField).filter( @@ -510,4 +524,4 @@ async def upload_ds_schema(session: SessionDep, id: int = Path(..., description= return True except Exception as e: - raise HTTPException(status_code=500, detail=f"解析 Excel 失败: {str(e)}") + raise HTTPException(status_code=500, detail=f"Parse Excel Failed: {str(e)}") diff --git a/backend/apps/system/api/aimodel.py b/backend/apps/system/api/aimodel.py index 8f01a4190..defa3b20b 100644 --- a/backend/apps/system/api/aimodel.py +++ b/backend/apps/system/api/aimodel.py @@ -18,6 +18,7 @@ router = APIRouter(tags=["system_model"], prefix="/system/aimodel") @router.post("/status", include_in_schema=False) +@require_permissions(permission=SqlbotPermission(role=['admin'])) async def check_llm(info: AiModelCreator, trans: Trans): async def generate(): try: @@ -92,6 +93,7 @@ async def query( return items @router.get("/{id}", response_model=AiModelEditor, summary=f"{PLACEHOLDER_PREFIX}system_model_query", description=f"{PLACEHOLDER_PREFIX}system_model_query") +@require_permissions(permission=SqlbotPermission(role=['admin'])) async def get_model_by_id( session: SessionDep, id: int = Path(description="ID") @@ -107,10 +109,13 @@ async def get_model_by_id( config_list = [AiModelConfigItem(**item) for item in raw] except Exception: pass - if db_model.api_key: - db_model.api_key = await sqlbot_decrypt(db_model.api_key) - if db_model.api_domain: - db_model.api_domain = await sqlbot_decrypt(db_model.api_domain) + try: + if db_model.api_key: + db_model.api_key = await sqlbot_decrypt(db_model.api_key) + if db_model.api_domain: + db_model.api_domain = await sqlbot_decrypt(db_model.api_domain) + except Exception: + pass data = AiModelDetail.model_validate(db_model).model_dump(exclude_unset=True) data.pop("config", None) data["config_list"] = config_list diff --git a/backend/apps/system/middleware/auth.py b/backend/apps/system/middleware/auth.py index bdf887118..e76741525 100644 --- a/backend/apps/system/middleware/auth.py +++ b/backend/apps/system/middleware/auth.py @@ -205,6 +205,12 @@ async def validateEmbedded(self, param: str, trans: I18n) -> tuple[any]: return False, f"Miss account payload error!" account = payload['account'] with Session(engine) as session: + assistant_info = await get_assistant_info(session=session, assistant_id=embeddedId) + assistant_info = AssistantModel.model_validate(assistant_info) + payload = jwt.decode( + param, assistant_info.app_secret, algorithms=[security.ALGORITHM] + ) + assistant_info = AssistantHeader.model_validate(assistant_info.model_dump(exclude_unset=True)) """ session_user = await get_user_info(session = session, user_id = token_data.id) session_user = UserInfoDTO.model_validate(session_user) """ session_user = get_user_by_account(session = session, account=account) @@ -220,12 +226,7 @@ async def validateEmbedded(self, param: str, trans: I18n) -> tuple[any]: if not session_user.oid or session_user.oid == 0: message = trans('i18n_login.no_associated_ws', msg = trans('i18n_concat_admin')) raise Exception(message) - assistant_info = await get_assistant_info(session=session, assistant_id=embeddedId) - assistant_info = AssistantModel.model_validate(assistant_info) - payload = jwt.decode( - param, assistant_info.app_secret, algorithms=[security.ALGORITHM] - ) - assistant_info = AssistantHeader.model_validate(assistant_info.model_dump(exclude_unset=True)) + return True, session_user, assistant_info except Exception as e: SQLBotLogUtil.exception(f"Embedded validation error: {str(e)}") diff --git a/backend/locales/en.json b/backend/locales/en.json index b70548660..3c9aed5d4 100644 --- a/backend/locales/en.json +++ b/backend/locales/en.json @@ -121,5 +121,48 @@ }, "i18n_authentication": { "record_not_exist": "{msg} record does not exist. Please save it first!" + }, + "i18n_audit": { + "success": "Success", + "failed": "Failed", + "create_qa": "Create Q&A", + "delete_qa": "Delete Q&A", + "create_datasource": "Create Datasource", + "update_datasource": "Edit Datasource", + "delete_datasource": "Delete Datasource", + "create_dashboard": "Create Dashboard", + "update_dashboard": "Edit Dashboard", + "delete_dashboard": "Delete Dashboard", + "setting_create_user": "Add Member", + "setting_delete_user": "Remove Member", + "setting_create_rule": "Add Rule Group", + "setting_delete_rule": "Remove Rule Group", + "setting_update_rule": "Configure Rules", + "setting_update_rule_user": "Configure Users", + "setting_create_terminology": "Create Terminology", + "create_qa_details": "Create Q&A【{resource_name}】", + "delete_qa_details": "Delete Q&A【{resource_name}】", + "create_datasource_details": "Create Datasource【{resource_name}】", + "update_datasource_details": "Edit Datasource【{resource_name}】", + "delete_datasource_details": "Delete Datasource【{resource_name}】", + "create_dashboard_details": "Create Dashboard【{resource_name}】", + "update_dashboard_details": "Edit Dashboard【{resource_name}】", + "delete_dashboard_details": "Delete Dashboard【{resource_name}】", + "setting_create_user_details": "Add Member【{resource_name}】", + "setting_delete_user_details": "Remove Member【{resource_name}】", + "setting_create_rule_details": "Add Rule Group【{resource_name}】", + "setting_delete_rule_details": "Remove Rule Group【{resource_name}】", + "setting_update_rule_details": "Configure Rules【{resource_name}】", + "setting_update_rule_user_details": "Configure Users【{resource_name}】", + "setting_create_terminology_details": "Create Terminology【{resource_name}】", + "system_log": "System Log", + "operation_type_name": "Operation Type", + "operation_detail_info": "Operation Details", + "user_name": "Operating User", + "oid_name": "Workspace", + "operation_status_name": "Operation Status", + "error_message": "Error Message", + "ip_address": "IP Address", + "create_time": "Operation Time" } } \ No newline at end of file diff --git a/backend/locales/ko-KR.json b/backend/locales/ko-KR.json index 786cc5498..2b7258280 100644 --- a/backend/locales/ko-KR.json +++ b/backend/locales/ko-KR.json @@ -121,5 +121,48 @@ }, "i18n_authentication": { "record_not_exist": "{msg} 기록이 존재하지 않습니다. 먼저 저장해 주세요!" + }, + "i18n_audit": { + "success": "성공", + "failed": "실패", + "create_qa": "Q&A 생성", + "delete_qa": "Q&A 삭제", + "create_datasource": "데이터 소스 생성", + "update_datasource": "데이터 소스 편집", + "delete_datasource": "데이터 소스 삭제", + "create_dashboard": "대시보드 생성", + "update_dashboard": "대시보드 편집", + "delete_dashboard": "대시보드 삭제", + "setting_create_user": "멤버 추가", + "setting_delete_user": "멤버 제거", + "setting_create_rule": "규칙 그룹 추가", + "setting_delete_rule": "규칙 그룹 제거", + "setting_update_rule": "규칙 설정", + "setting_update_rule_user": "사용자 설정", + "setting_create_terminology": "용어 생성", + "create_qa_details": "Q&A 생성【{resource_name}】", + "delete_qa_details": "Q&A 삭제【{resource_name}】", + "create_datasource_details": "데이터 소스 생성【{resource_name}】", + "update_datasource_details": "데이터 소스 편집【{resource_name}】", + "delete_datasource_details": "데이터 소스 삭제【{resource_name}】", + "create_dashboard_details": "대시보드 생성【{resource_name}】", + "update_dashboard_details": "대시보드 편집【{resource_name}】", + "delete_dashboard_details": "대시보드 삭제【{resource_name}】", + "setting_create_user_details": "멤버 추가【{resource_name}】", + "setting_delete_user_details": "멤버 제거【{resource_name}】", + "setting_create_rule_details": "규칙 그룹 추가【{resource_name}】", + "setting_delete_rule_details": "규칙 그룹 제거【{resource_name}】", + "setting_update_rule_details": "규칙 설정【{resource_name}】", + "setting_update_rule_user_details": "사용자 설정【{resource_name}】", + "setting_create_terminology_details": "용어 생성【{resource_name}】", + "system_log": "시스템 로그", + "operation_type_name": "작업 유형", + "operation_detail_info": "작업 상세 정보", + "user_name": "작업 사용자", + "oid_name": "작업 공간", + "operation_status_name": "작업 상태", + "error_message": "오류 메시지", + "ip_address": "IP 주소", + "create_time": "작업 시간" } } \ No newline at end of file diff --git a/backend/locales/zh-CN.json b/backend/locales/zh-CN.json index 9154c424e..84236f342 100644 --- a/backend/locales/zh-CN.json +++ b/backend/locales/zh-CN.json @@ -121,5 +121,48 @@ }, "i18n_authentication": { "record_not_exist": "{msg} 记录不存在,请先保存!" + }, + "i18n_audit": { + "success": "成功", + "failed": "失败", + "create_qa": "新建问数", + "delete_qa": "删除问数", + "create_datasource": "新建数据源", + "update_datasource": "编辑数据源", + "delete_datasource": "删除数据源", + "create_dashboard": "新建仪表板", + "update_dashboard": "编辑仪表板", + "delete_dashboard": "删除仪表板", + "setting_create_user": "添加成员", + "setting_delete_user": "移除成员", + "setting_create_rule": "添加规则组", + "setting_delete_rule": "移除规则组", + "setting_update_rule": "设置规则", + "setting_update_rule_user": "设置用户", + "setting_create_terminology": "新建术语", + "create_qa_details": "新建问数【{resource_name}】", + "delete_qa_details": "删除问数【{resource_name}】", + "create_datasource_details": "新建数据源【{resource_name}】", + "update_datasource_details": "编辑数据源【{resource_name}】", + "delete_datasource_details": "删除数据源【{resource_name}】", + "create_dashboard_details": "新建仪表板【{resource_name}】", + "update_dashboard_details": "编辑仪表板【{resource_name}】", + "delete_dashboard_details": "删除仪表板【{resource_name}】", + "setting_create_user_details": "添加成员【{resource_name}】", + "setting_delete_user_details": "移除成员【{resource_name}】", + "setting_create_rule_details": "添加规则组【{resource_name}】", + "setting_delete_rule_details": "移除规则组【{resource_name}】", + "setting_update_rule_details": "设置规则【{resource_name}】", + "setting_update_rule_user_details": "设置用户【{resource_name}】", + "setting_create_terminology_details": "新建术语【{resource_name}】", + "system_log": "操作日志", + "operation_type_name": "操作类型", + "operation_detail_info": "操作详情", + "user_name": "操作用户", + "oid_name": "工作空间", + "operation_status_name": "操作状态", + "error_message": "错误信息", + "ip_address": "IP 地址", + "create_time": "操作时间" } -} \ No newline at end of file +} diff --git a/frontend/src/api/audit.ts b/frontend/src/api/audit.ts new file mode 100644 index 000000000..7c19e90a9 --- /dev/null +++ b/frontend/src/api/audit.ts @@ -0,0 +1,12 @@ +import { request } from '@/utils/request' + +export const audit = { + getList: (pageNum: any, pageSize: any, params: any) => + request.get(`/system/audit/page/${pageNum}/${pageSize}${params}`), + export2Excel: (params: any) => + request.get(`/system/audit/export`, { + params, + responseType: 'blob', + requestOptions: { customError: true }, + }), +} diff --git a/frontend/src/api/chat.ts b/frontend/src/api/chat.ts index 42a7199c8..d64fee6d3 100644 --- a/frontend/src/api/chat.ts +++ b/frontend/src/api/chat.ts @@ -324,8 +324,8 @@ export const chatApi = { renameChat: (chat_id: number | undefined, brief: string): Promise => { return request.post('/chat/rename', { id: chat_id, brief: brief }) }, - deleteChat: (id: number | undefined): Promise => { - return request.delete(`/chat/${id}`) + deleteChat: (id: number | undefined, brief: any): Promise => { + return request.delete(`/chat/${id}/${brief}`) }, analysis: (record_id: number | undefined, controller?: AbortController) => { return request.fetchStream(`/chat/record/${record_id}/analysis`, {}, controller) diff --git a/frontend/src/api/dashboard.ts b/frontend/src/api/dashboard.ts index f19ae1b84..7c5dc27e7 100644 --- a/frontend/src/api/dashboard.ts +++ b/frontend/src/api/dashboard.ts @@ -9,6 +9,6 @@ export const dashboardApi = { update_canvas: (params: any) => request.post('/dashboard/update_canvas', params), check_name: (params: any) => request.post('/dashboard/check_name', params), delete_resource: (params: any) => - request.delete(`/dashboard/delete_resource/${params.id}`, params), + request.delete(`/dashboard/delete_resource/${params.id}/${params.name}`, params), move_resource: (params: any) => request.delete(`/dashboard/move_resource/${params.id}`, params), } diff --git a/frontend/src/api/datasource.ts b/frontend/src/api/datasource.ts index c349c85e8..7f2fb782b 100644 --- a/frontend/src/api/datasource.ts +++ b/frontend/src/api/datasource.ts @@ -8,7 +8,7 @@ export const datasourceApi = { add: (data: any) => request.post('/datasource/add', data), list: () => request.get('/datasource/list'), update: (data: any) => request.post('/datasource/update', data), - delete: (id: number) => request.post(`/datasource/delete/${id}`), + delete: (id: number, name: string) => request.post(`/datasource/delete/${id}/${name}`), getTables: (id: number) => request.post(`/datasource/getTables/${id}`), getTablesByConf: (data: any) => request.post('/datasource/getTablesByConf', data), getFields: (id: number, table_name: string) => diff --git a/frontend/src/assets/svg/icon_error.svg b/frontend/src/assets/svg/icon_error.svg new file mode 100644 index 000000000..5777bd1b7 --- /dev/null +++ b/frontend/src/assets/svg/icon_error.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_issue.svg b/frontend/src/assets/svg/icon_issue.svg new file mode 100644 index 000000000..663e919b6 --- /dev/null +++ b/frontend/src/assets/svg/icon_issue.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_success.svg b/frontend/src/assets/svg/icon_success.svg new file mode 100644 index 000000000..2303d6f93 --- /dev/null +++ b/frontend/src/assets/svg/icon_success.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/components/layout/Menu.vue b/frontend/src/components/layout/Menu.vue index dd1fbcd23..a7514096f 100644 --- a/frontend/src/components/layout/Menu.vue +++ b/frontend/src/components/layout/Menu.vue @@ -55,6 +55,7 @@ const routerList = computed(() => { !route.path.includes('prompt') && !route.path.includes('permission') && !route.path.includes('preview') && + !route.path.includes('audit') && route.path !== '/login' && route.path !== '/admin-login' && !route.path.includes('/system') && diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 7d0622465..62058a304 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -822,6 +822,40 @@ "modelType": { "llm": "Large Language Model" }, + "audit": { + "system_log": "System Log", + "search_log": "Search Log", + "operation_type": "Operation Type", + "operation_details": "Operation Details", + "operation_user_name": "Operating User", + "operation_status": "Operation Status", + "user_name": "User Name", + "oid_name": "Workspace", + "ip_address": "IP Address", + "create_time": "Creation Time", + "no_log": "No Logs Available", + "all_236_terms": "Export all {msg} log entries?", + "export_hint": "Export all logs?", + "export": "Export", + "success": "Success", + "failed": "Failed", + "failed_info": "Operation Failure Details", + "create_qa": "Create Q&A", + "delete_qa": "Delete Q&A", + "create_datasource": "Create Datasource", + "update_datasource": "Edit Datasource", + "delete_datasource": "Delete Datasource", + "create_dashboard": "Create Dashboard", + "update_dashboard": "Edit Dashboard", + "delete_dashboard": "Delete Dashboard", + "setting_create_user": "Add Member", + "setting_delete_user": "Remove Member", + "setting_create_rule": "Add Rule Group", + "setting_delete_rule": "Remove Rule Group", + "setting_update_rule": "Configure Rules", + "setting_update_rule_user": "Configure Users", + "setting_create_terminology": "Create Terminology" + }, "api_key": { "info_tips": "The API Key is your credential for accessing the SQLBot API, with full permissions for your account. Please keep it secure! Do not disclose the API Key in any public channels to avoid security risks from unauthorized use.", "create": "Create", diff --git a/frontend/src/i18n/ko-KR.json b/frontend/src/i18n/ko-KR.json index ca764db42..f5d978fb2 100644 --- a/frontend/src/i18n/ko-KR.json +++ b/frontend/src/i18n/ko-KR.json @@ -822,10 +822,44 @@ "modelType": { "llm": "대형 언어 모델" }, + "audit": { + "system_log": "시스템 로그", + "search_log": "검색 로그", + "operation_type": "작업 유형", + "operation_details": "작업 상세", + "operation_user_name": "작업 사용자", + "operation_status": "작업 상태", + "user_name": "사용자 이름", + "oid_name": "작업 공간", + "ip_address": "IP 주소", + "create_time": "생성 시간", + "no_log": "로그 없음", + "all_236_terms": "전체 {msg}개의 로그를 내보내시겠습니까?", + "export_hint": "모든 로그를 내보내시겠습니까?", + "export": "내보내기", + "success": "성공", + "failed": "실패", + "failed_info": "작업 실패 상세", + "create_qa": "Q&A 생성", + "delete_qa": "Q&A 삭제", + "create_datasource": "데이터 소스 생성", + "update_datasource": "데이터 소스 편집", + "delete_datasource": "데이터 소스 삭제", + "create_dashboard": "대시보드 생성", + "update_dashboard": "대시보드 편집", + "delete_dashboard": "대시보드 삭제", + "setting_create_user": "멤버 추가", + "setting_delete_user": "멤버 제거", + "setting_create_rule": "규칙 그룹 추가", + "setting_delete_rule": "규칙 그룹 제거", + "setting_update_rule": "규칙 설정", + "setting_update_rule_user": "사용자 설정", + "setting_create_terminology": "용어 생성" + }, "api_key": { "info_tips": "API 키는 SQLBot API에 액세스하는 비밀키로 계정의 모든 권한을 갖고 있습니다. 꼭 안전하게 보관하세요! 외부 채널에 어떠한 방식으로도 API 키를 공개하지 마시고, 타인이 악용하여 보안 위협이 발생하는 것을 방지하세요.", "create": "생성", "to_doc": "API 보기", "trigger_limit": "최대 {0}개의 API 키 생성 지원" } -} \ No newline at end of file +} diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json index 91464287f..a0f368088 100644 --- a/frontend/src/i18n/zh-CN.json +++ b/frontend/src/i18n/zh-CN.json @@ -823,10 +823,44 @@ "modelType": { "llm": "大语言模型" }, + "audit": { + "system_log": "操作日志", + "search_log": "搜索日志", + "operation_type": "操作类型", + "operation_details": "操作详情", + "operation_user_name": "操作用户", + "operation_status": "操作状态", + "user_name": "操作日志", + "oid_name": "工作空间", + "ip_address": "IP 地址", + "create_time": "创建时间", + "no_log": "暂无日志", + "all_236_terms": "是否导出全部 {msg} 条日志?", + "export_hint": "是否导出全部日志?", + "export": "导出", + "success": "成功", + "failed": "失败", + "failed_info": "操作失败详情", + "create_qa": "新建问数", + "delete_qa": "删除问数", + "create_datasource": "新建数据源", + "update_datasource": "编辑数据源", + "delete_datasource": "删除数据源", + "create_dashboard": "新建仪表板", + "update_dashboard": "编辑仪表板", + "delete_dashboard": "删除仪表板", + "setting_create_user": "添加成员", + "setting_delete_user": "移除成员", + "setting_create_rule": "添加规则组", + "setting_delete_rule": "移除规则组", + "setting_update_rule": "设置规则", + "setting_update_rule_user": "设置用户", + "setting_create_terminology": "新建术语" + }, "api_key": { "info_tips": "API Key 是您访问 SQLBot API 的密钥,具有账户的完全权限,请您务必妥善保管!不要以任何方式公开 API Key 到外部渠道,避免被他人利用造成安全威胁。", "create": "创建", "to_doc": "查看 API", "trigger_limit": "最多支持创建 {0} 个 API Key" } -} \ No newline at end of file +} diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 51f8aba45..ca3f1d099 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -18,6 +18,7 @@ import Member from '@/views/system/member/index.vue' import Professional from '@/views/system/professional/index.vue' import Training from '@/views/system/training/index.vue' import Prompt from '@/views/system/prompt/index.vue' +import Audit from '@/views/system/audit/index.vue' import Appearance from '@/views/system/appearance/index.vue' import Parameter from '@/views/system/parameter/index.vue' import Authentication from '@/views/system/authentication/index.vue' @@ -130,6 +131,12 @@ export const routes = [ component: Prompt, meta: { title: t('prompt.customize_prompt_words') }, }, + { + path: '/set/audit', + name: 'audit', + component: Audit, + meta: { title: t('audit.system_log') }, + }, ], }, { diff --git a/frontend/src/views/chat/ChatList.vue b/frontend/src/views/chat/ChatList.vue index 36cc985c6..c2a98aa3b 100644 --- a/frontend/src/views/chat/ChatList.vue +++ b/frontend/src/views/chat/ChatList.vue @@ -122,7 +122,7 @@ function handleCommand(command: string | number | object, chat: Chat) { }).then(() => { _loading.value = true chatApi - .deleteChat(chat.id) + .deleteChat(chat.id, chat.brief) .then(() => { ElMessage({ type: 'success', diff --git a/frontend/src/views/dashboard/common/ResourceTree.vue b/frontend/src/views/dashboard/common/ResourceTree.vue index bce90f438..a6496ee40 100644 --- a/frontend/src/views/dashboard/common/ResourceTree.vue +++ b/frontend/src/views/dashboard/common/ResourceTree.vue @@ -230,7 +230,7 @@ const operation = (opt: string, data: SQTreeNode) => { autofocus: false, showClose: false, }).then(() => { - dashboardApi.delete_resource({ id: data.id }).then(() => { + dashboardApi.delete_resource({ id: data.id, name: data.name }).then(() => { ElMessage.success(t('dashboard.delete_success')) getTree() dashboardStore.canvasDataInit() diff --git a/frontend/src/views/ds/Datasource.vue b/frontend/src/views/ds/Datasource.vue index 3a9fcb282..6fb08ec11 100644 --- a/frontend/src/views/ds/Datasource.vue +++ b/frontend/src/views/ds/Datasource.vue @@ -159,7 +159,7 @@ const deleteHandler = (item: any) => { '' ), }).then(() => { - datasourceApi.delete(item.id).then(() => { + datasourceApi.delete(item.id, item.name).then(() => { ElMessage({ type: 'success', message: t('dashboard.delete_success'), diff --git a/frontend/src/views/ds/index.vue b/frontend/src/views/ds/index.vue index 41563894d..7acacfeeb 100644 --- a/frontend/src/views/ds/index.vue +++ b/frontend/src/views/ds/index.vue @@ -109,7 +109,7 @@ const deleteDs = (item: any) => { type: 'warning', }) .then(() => { - datasourceApi.delete(item.id).then(() => { + datasourceApi.delete(item.id, item.name).then(() => { refresh() }) }) diff --git a/frontend/src/views/system/audit/index.vue b/frontend/src/views/system/audit/index.vue new file mode 100644 index 000000000..65434e724 --- /dev/null +++ b/frontend/src/views/system/audit/index.vue @@ -0,0 +1,627 @@ + + + + + +