mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat: import Sample SQL / Terminologies
This commit is contained in:
@@ -74,8 +74,8 @@ async def export_excel(session: SessionDep, trans: Trans, current_user: CurrentU
|
||||
data_list.append(_data)
|
||||
|
||||
fields = []
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.data_training'), value='question'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.problem_description'), value='description'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.problem_description'), value='question'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.sample_sql'), value='description'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.effective_data_sources'), value='datasource_name'))
|
||||
if current_user.oid == 1:
|
||||
fields.append(
|
||||
@@ -98,6 +98,43 @@ async def export_excel(session: SessionDep, trans: Trans, current_user: CurrentU
|
||||
return StreamingResponse(result, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
|
||||
|
||||
@router.get("/template")
|
||||
async def excel_template(trans: Trans, current_user: CurrentUser):
|
||||
def inner():
|
||||
data_list = []
|
||||
_data1 = {
|
||||
"question": '查询TEST表内所有ID',
|
||||
"description": 'SELECT id FROM TEST',
|
||||
"datasource_name": '生效数据源1',
|
||||
"advanced_application_name": '生效高级应用名称',
|
||||
}
|
||||
data_list.append(_data1)
|
||||
|
||||
fields = []
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.problem_description_template'), value='question'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.sample_sql_template'), value='description'))
|
||||
fields.append(AxisObj(name=trans('i18n_data_training.effective_data_sources_template'), value='datasource_name'))
|
||||
if current_user.oid == 1:
|
||||
fields.append(
|
||||
AxisObj(name=trans('i18n_data_training.advanced_application_template'), value='advanced_application_name'))
|
||||
|
||||
md_data, _fields_list = DataFormat.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")
|
||||
|
||||
|
||||
path = settings.EXCEL_PATH
|
||||
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
|
||||
@@ -98,6 +98,51 @@ async def export_excel(session: SessionDep, trans: Trans, current_user: CurrentU
|
||||
return StreamingResponse(result, media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
|
||||
|
||||
@router.get("/template")
|
||||
async def excel_template(trans: Trans):
|
||||
def inner():
|
||||
data_list = []
|
||||
_data1 = {
|
||||
"word": trans('i18n_terminology.term_name_template_example_1'),
|
||||
"other_words": trans('i18n_terminology.synonyms_template_example_1'),
|
||||
"description": trans('i18n_terminology.term_description_template_example_1'),
|
||||
"all_data_sources": 'N',
|
||||
"datasource": trans('i18n_terminology.effective_data_sources_template_example_1'),
|
||||
}
|
||||
data_list.append(_data1)
|
||||
_data2 = {
|
||||
"word": trans('i18n_terminology.term_name_template_example_2'),
|
||||
"other_words": trans('i18n_terminology.synonyms_template_example_2'),
|
||||
"description": trans('i18n_terminology.term_description_template_example_2'),
|
||||
"all_data_sources": 'Y',
|
||||
"datasource": '',
|
||||
}
|
||||
data_list.append(_data2)
|
||||
|
||||
fields = []
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.term_name_template'), value='word'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.synonyms_template'), value='other_words'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.term_description_template'), value='description'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.effective_data_sources_template'), value='datasource'))
|
||||
fields.append(AxisObj(name=trans('i18n_terminology.all_data_sources_template'), value='all_data_sources'))
|
||||
|
||||
md_data, _fields_list = DataFormat.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")
|
||||
|
||||
|
||||
path = settings.EXCEL_PATH
|
||||
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
|
||||
@@ -48,6 +48,18 @@
|
||||
"effective_data_sources": "Effective Data Sources",
|
||||
"all_data_sources": "All Data Sources",
|
||||
"synonyms": "Synonyms",
|
||||
"term_name_template": "Terminology Name (Required)",
|
||||
"term_description_template": "Terminology Description (Required)",
|
||||
"effective_data_sources_template": "Effective Data Sources (Multiple supported, separated by \",\")",
|
||||
"all_data_sources_template": "All Data Sources (Y: Apply to all data sources, N: Apply to specified data sources)",
|
||||
"synonyms_template": "Synonyms (Multiple supported, separated by \",\")",
|
||||
"term_name_template_example_1": "Term1",
|
||||
"term_description_template_example_1": "Term1 Description",
|
||||
"effective_data_sources_template_example_1": "Datasource1, Datasource2",
|
||||
"synonyms_template_example_1": "Synonym1, Synonym2",
|
||||
"term_name_template_example_2": "Term2",
|
||||
"term_description_template_example_2": "Term2 Description",
|
||||
"synonyms_template_example_2": "Synonym3",
|
||||
"word_cannot_be_empty": "Term cannot be empty",
|
||||
"description_cannot_be_empty": "Term description cannot be empty",
|
||||
"datasource_not_found": "Datasource not found"
|
||||
@@ -62,6 +74,13 @@
|
||||
"sample_sql": "Sample SQL",
|
||||
"effective_data_sources": "Effective Data Sources",
|
||||
"advanced_application": "Advanced Application",
|
||||
"problem_description_template": "Problem Description (Required)",
|
||||
"sample_sql_template": "Sample SQL (Required)",
|
||||
"effective_data_sources_template": "Effective Data Sources",
|
||||
"advanced_application_template": "Advanced Application",
|
||||
"problem_description_template_example": "Query all IDs in the TEST table",
|
||||
"effective_data_sources_template_example": "Effective Datasource 1",
|
||||
"advanced_application_template_example": "Effective Advanced Application Name",
|
||||
"error_info": "Error Information",
|
||||
"question_cannot_be_empty": "Question cannot be empty",
|
||||
"description_cannot_be_empty": "Sample SQL cannot be empty",
|
||||
@@ -75,6 +94,15 @@
|
||||
"prompt_word_content": "Prompt word content",
|
||||
"effective_data_sources": "Effective Data Sources",
|
||||
"all_data_sources": "All Data Sources",
|
||||
"prompt_word_name_template": "Prompt Name (Required)",
|
||||
"prompt_word_content_template": "Prompt Content (Required)",
|
||||
"effective_data_sources_template": "Effective Data Sources (Multiple supported, separated by \",\")",
|
||||
"all_data_sources_template": "All Data Sources (Y: Apply to all data sources, N: Apply to specified data sources)",
|
||||
"prompt_word_name_template_example1": "Prompt1",
|
||||
"prompt_word_content_template_example1": "Describe your prompt in detail",
|
||||
"effective_data_sources_template_example1": "Datasource1, Datasource2",
|
||||
"prompt_word_name_template_example2": "Prompt2",
|
||||
"prompt_word_content_template_example2": "Describe your prompt in detail",
|
||||
"name_cannot_be_empty": "Name cannot be empty",
|
||||
"prompt_cannot_be_empty": "Prompt content cannot be empty",
|
||||
"type_cannot_be_empty": "Type cannot be empty",
|
||||
|
||||
@@ -48,6 +48,18 @@
|
||||
"effective_data_sources": "유효 데이터 소스",
|
||||
"all_data_sources": "모든 데이터 소스",
|
||||
"synonyms": "동의어",
|
||||
"term_name_template": "용어 이름 (필수)",
|
||||
"term_description_template": "용어 설명 (필수)",
|
||||
"effective_data_sources_template": "유효 데이터 소스 (여러 개 지원, \",\"로 구분)",
|
||||
"all_data_sources_template": "모든 데이터 소스 (Y: 모든 데이터 소스에 적용, N: 지정된 데이터 소스에 적용)",
|
||||
"synonyms_template": "동의어 (여러 개 지원, \",\"로 구분)",
|
||||
"term_name_template_example_1": "용어1",
|
||||
"term_description_template_example_1": "용어1 설명",
|
||||
"effective_data_sources_template_example_1": "데이터소스1, 데이터소스2",
|
||||
"synonyms_template_example_1": "동의어1, 동의어2",
|
||||
"term_name_template_example_2": "용어2",
|
||||
"term_description_template_example_2": "용어2 설명",
|
||||
"synonyms_template_example_2": "동의어3",
|
||||
"word_cannot_be_empty": "용어는 비울 수 없습니다",
|
||||
"description_cannot_be_empty": "용어 설명은 비울 수 없습니다",
|
||||
"datasource_not_found": "데이터 소스를 찾을 수 없음"
|
||||
@@ -62,6 +74,13 @@
|
||||
"sample_sql": "예시 SQL",
|
||||
"effective_data_sources": "유효 데이터 소스",
|
||||
"advanced_application": "고급 애플리케이션",
|
||||
"problem_description_template": "문제 설명 (필수)",
|
||||
"sample_sql_template": "예시 SQL (필수)",
|
||||
"effective_data_sources_template": "유효 데이터 소스",
|
||||
"advanced_application_template": "고급 애플리케이션",
|
||||
"problem_description_template_example": "TEST 테이블 내 모든 ID 조회",
|
||||
"effective_data_sources_template_example": "유효 데이터소스1",
|
||||
"advanced_application_template_example": "유효 고급 애플리케이션 이름",
|
||||
"error_info": "오류 정보",
|
||||
"question_cannot_be_empty": "질문은 비울 수 없습니다",
|
||||
"description_cannot_be_empty": "예시 SQL은 비울 수 없습니다",
|
||||
@@ -75,6 +94,15 @@
|
||||
"prompt_word_content": "프롬프트 내용",
|
||||
"effective_data_sources": "유효 데이터 소스",
|
||||
"all_data_sources": "모든 데이터 소스",
|
||||
"prompt_word_name_template": "프롬프트 이름 (필수)",
|
||||
"prompt_word_content_template": "프롬프트 내용 (필수)",
|
||||
"effective_data_sources_template": "유효 데이터 소스 (여러 개 지원, \",\"로 구분)",
|
||||
"all_data_sources_template": "모든 데이터 소스 (Y: 모든 데이터 소스에 적용, N: 지정된 데이터 소스에 적용)",
|
||||
"prompt_word_name_template_example1": "프롬프트1",
|
||||
"prompt_word_content_template_example1": "프롬프트를 상세히 설명해 주세요",
|
||||
"effective_data_sources_template_example1": "데이터소스1, 데이터소스2",
|
||||
"prompt_word_name_template_example2": "프롬프트2",
|
||||
"prompt_word_content_template_example2": "프롬프트를 상세히 설명해 주세요",
|
||||
"name_cannot_be_empty": "이름은 비울 수 없습니다",
|
||||
"prompt_cannot_be_empty": "프롬프트 내용은 비울 수 없습니다",
|
||||
"type_cannot_be_empty": "유형은 비울 수 없습니다",
|
||||
|
||||
@@ -48,6 +48,18 @@
|
||||
"effective_data_sources": "生效数据源",
|
||||
"all_data_sources": "所有数据源",
|
||||
"synonyms": "同义词",
|
||||
"term_name_template": "术语名称(必填)",
|
||||
"term_description_template": "术语描述(必填)",
|
||||
"effective_data_sources_template": "生效数据源(支持多个,用\",\"分割)",
|
||||
"all_data_sources_template": "所有数据源(Y:应用到全部数据源,N:应用到指定数据源)",
|
||||
"synonyms_template": "同义词(支持多个,用\",\"分割)",
|
||||
"term_name_template_example_1": "术语1",
|
||||
"term_description_template_example_1": "术语1描述",
|
||||
"effective_data_sources_template_example_1": "生效数据源1, 生效数据源2",
|
||||
"synonyms_template_example_1": "同义词1, 同义词2",
|
||||
"term_name_template_example_2": "术语2",
|
||||
"term_description_template_example_2": "术语2描述",
|
||||
"synonyms_template_example_2": "同义词3",
|
||||
"word_cannot_be_empty": "术语不能为空",
|
||||
"description_cannot_be_empty": "术语描述不能为空",
|
||||
"datasource_not_found": "找不到数据源"
|
||||
@@ -62,6 +74,13 @@
|
||||
"sample_sql": "示例 SQL",
|
||||
"effective_data_sources": "生效数据源",
|
||||
"advanced_application": "高级应用",
|
||||
"problem_description_template": "问题描述(必填)",
|
||||
"sample_sql_template": "示例 SQL(必填)",
|
||||
"effective_data_sources_template": "生效数据源",
|
||||
"advanced_application_template": "高级应用",
|
||||
"problem_description_template_example": "查询TEST表内所有ID",
|
||||
"effective_data_sources_template_example": "生效数据源1",
|
||||
"advanced_application_template_example": "生效高级应用名称",
|
||||
"error_info": "错误信息",
|
||||
"question_cannot_be_empty": "问题不能为空",
|
||||
"description_cannot_be_empty": "示例 SQL 不能为空",
|
||||
@@ -75,6 +94,15 @@
|
||||
"prompt_word_content": "提示词内容",
|
||||
"effective_data_sources": "生效数据源",
|
||||
"all_data_sources": "所有数据源",
|
||||
"prompt_word_name_template": "提示词名称(必填)",
|
||||
"prompt_word_content_template": "提示词内容(必填)",
|
||||
"effective_data_sources_template": "生效数据源(支持多个,用\",\"分割)",
|
||||
"all_data_sources_template": "所有数据源(Y:应用到全部数据源,N:应用到指定数据源)",
|
||||
"prompt_word_name_template_example1": "提示词1",
|
||||
"prompt_word_content_template_example1": "详细描述你的提示词",
|
||||
"effective_data_sources_template_example1": "生效数据源1, 生效数据源2",
|
||||
"prompt_word_name_template_example2": "提示词2",
|
||||
"prompt_word_content_template_example2": "详细描述你的提示词",
|
||||
"name_cannot_be_empty": "名称不能为空",
|
||||
"prompt_cannot_be_empty": "提示词内容不能为空",
|
||||
"type_cannot_be_empty": "类型不能为空",
|
||||
|
||||
@@ -39,7 +39,7 @@ dependencies = [
|
||||
"pyyaml (>=6.0.2,<7.0.0)",
|
||||
"fastapi-mcp (>=0.3.4,<0.4.0)",
|
||||
"tabulate>=0.9.0",
|
||||
"sqlbot-xpack>=0.0.3.47,<1.0.0",
|
||||
"sqlbot-xpack>=0.0.3.53,<1.0.0",
|
||||
"fastapi-cache2>=0.2.2",
|
||||
"sqlparse>=0.5.3",
|
||||
"redis>=6.2.0",
|
||||
|
||||
@@ -17,4 +17,10 @@ export const settingsApi = {
|
||||
requestOptions: { customError: true },
|
||||
}
|
||||
),
|
||||
|
||||
downloadTemplate: (url: any) =>
|
||||
request.get(url, {
|
||||
responseType: 'blob',
|
||||
requestOptions: { customError: true },
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -117,6 +117,12 @@
|
||||
"english": "English",
|
||||
"re_upload": "Re-upload",
|
||||
"not_exceed_50mb": "Supports XLS, XLSX, CSV formats, file size does not exceed 50MB",
|
||||
"excel_file_type_limit": "Only XLS and XLSX formats are supported",
|
||||
"click_to_select_file": "Click to select file",
|
||||
"upload_hint_first": "Please ",
|
||||
"upload_hint_download_template": "download the template",
|
||||
"upload_hint_end": " first, then upload after filling it out as required",
|
||||
"continue_to_upload": "Continue to import",
|
||||
"reset_password": "Reset password",
|
||||
"password_reset_successful": "Password reset successful",
|
||||
"or": "Or",
|
||||
|
||||
@@ -117,6 +117,12 @@
|
||||
"english": "English",
|
||||
"re_upload": "다시 업로드",
|
||||
"not_exceed_50mb": "XLS, XLSX, CSV 형식을 지원하며, 파일 크기는 50MB를 초과할 수 없습니다",
|
||||
"excel_file_type_limit": "XLS 및 XLSX 형식만 지원됩니다",
|
||||
"click_to_select_file": "파일 선택을 클릭하세요",
|
||||
"upload_hint_first": "먼저 ",
|
||||
"upload_hint_download_template": "템플릿을 다운로드",
|
||||
"upload_hint_end": ", 한 후 요구사항에 따라 작성하여 업로드하세요",
|
||||
"continue_to_upload": "계속 가져오기",
|
||||
"reset_password": "비밀번호 재설정",
|
||||
"password_reset_successful": "비밀번호 재설정 성공",
|
||||
"or": "또는",
|
||||
|
||||
@@ -117,6 +117,12 @@
|
||||
"english": "English",
|
||||
"re_upload": "重新上传",
|
||||
"not_exceed_50mb": "支持 XLS、XLSX、CSV 格式,文件大小不超过 50MB",
|
||||
"excel_file_type_limit": "仅支持 XLS、XLSX 格式",
|
||||
"click_to_select_file": "点击选择文件",
|
||||
"upload_hint_first": "先",
|
||||
"upload_hint_download_template": "下载模板",
|
||||
"upload_hint_end": ",按要求填写后上传",
|
||||
"continue_to_upload": "继续导入",
|
||||
"reset_password": "重置密码",
|
||||
"password_reset_successful": "重置密码成功",
|
||||
"or": "或者",
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { endsWith, startsWith } from 'lodash-es'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import icon_warning_filled from '@/assets/svg/icon_warning_filled.svg'
|
||||
import icon_upload_outlined from '@/assets/svg/icon_upload_outlined.svg'
|
||||
import icon_fileExcel_colorful from '@/assets/datasource/icon_excel.png'
|
||||
import { genFileId, type UploadInstance, type UploadProps, type UploadRawFile } from 'element-plus'
|
||||
import { useCache } from '@/utils/useCache.ts'
|
||||
import { settingsApi } from '@/api/setting.ts'
|
||||
import ccmUpload from '@/assets/svg/icon_ccm-upload_outlined.svg'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
|
||||
const emits = defineEmits(['upload-finished'])
|
||||
|
||||
const props = defineProps<{
|
||||
uploadPath: string
|
||||
templatePath: string
|
||||
templateName: string
|
||||
}>()
|
||||
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadLoading = ref(false)
|
||||
|
||||
const token = wsCache.get('user.token')
|
||||
const headers = ref<any>({ 'X-SQLBOT-TOKEN': `Bearer ${token}` })
|
||||
const getUploadURL = () => {
|
||||
return import.meta.env.VITE_API_BASE_URL + props.uploadPath
|
||||
}
|
||||
|
||||
function downloadTemplate() {
|
||||
settingsApi
|
||||
.downloadTemplate(props.templatePath)
|
||||
.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 = props.templateName
|
||||
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,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
uploadRef.value!.handleStart(file)
|
||||
}
|
||||
const fileList = ref<Array<any>>([])
|
||||
const fileName = computed(() => {
|
||||
if (fileList.value.length > 0) {
|
||||
return fileList.value[0].name
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
const beforeUpload = (rawFile: any) => {
|
||||
if (rawFile.size / 1024 / 1024 > 50) {
|
||||
ElMessage.error(t('common.not_exceed_50mb'))
|
||||
return false
|
||||
}
|
||||
uploadLoading.value = true
|
||||
return true
|
||||
}
|
||||
|
||||
const errorFileName = ref<string>('')
|
||||
|
||||
function downloadErrorFile() {
|
||||
settingsApi
|
||||
.downloadError(errorFileName.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 = errorFileName.value
|
||||
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,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const infoMessage = ref<string>('')
|
||||
const hasError = ref(false)
|
||||
|
||||
const onSuccess = (response: any) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
fileList.value = []
|
||||
hasError.value = false
|
||||
infoMessage.value = ''
|
||||
emits('upload-finished')
|
||||
if (response?.data?.failed_count > 0 && response?.data?.error_excel_filename) {
|
||||
infoMessage.value = t('training.upload_failed', {
|
||||
success: response.data.success_count,
|
||||
fail: response.data.failed_count,
|
||||
fail_info: '',
|
||||
})
|
||||
errorFileName.value = response.data.error_excel_filename
|
||||
hasError.value = true
|
||||
} else {
|
||||
infoMessage.value = t('training.upload_success')
|
||||
hasError.value = false
|
||||
}
|
||||
uploadLoading.value = false
|
||||
close()
|
||||
showResult()
|
||||
}
|
||||
|
||||
const onError = (err: Error) => {
|
||||
uploadLoading.value = false
|
||||
uploadRef.value!.clearFiles()
|
||||
fileList.value = []
|
||||
let msg = err.message
|
||||
if (startsWith(msg, '"') && endsWith(msg, '"')) {
|
||||
msg = msg.slice(1, msg.length - 1)
|
||||
}
|
||||
errorFileName.value = ''
|
||||
infoMessage.value = msg
|
||||
hasError.value = true
|
||||
close()
|
||||
showResult()
|
||||
}
|
||||
|
||||
const dialogShow = ref<boolean>(false)
|
||||
|
||||
const resultShow = ref(false)
|
||||
|
||||
function showResult() {
|
||||
resultShow.value = true
|
||||
}
|
||||
function closeResult() {
|
||||
resultShow.value = false
|
||||
}
|
||||
function backToUpload() {
|
||||
closeResult()
|
||||
open()
|
||||
}
|
||||
|
||||
function open() {
|
||||
dialogShow.value = true
|
||||
errorFileName.value = ''
|
||||
fileList.value = []
|
||||
hasError.value = false
|
||||
infoMessage.value = ''
|
||||
}
|
||||
|
||||
function close() {
|
||||
uploadRef.value!.clearFiles()
|
||||
fileList.value = []
|
||||
dialogShow.value = false
|
||||
}
|
||||
|
||||
const submitUpload = () => {
|
||||
uploadRef.value!.submit()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-button class="no-margin" secondary @click="open">
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
<el-dialog
|
||||
v-if="dialogShow"
|
||||
v-model="dialogShow"
|
||||
:title="t('user.batch_import')"
|
||||
width="600px"
|
||||
class="user-import-class"
|
||||
@close="close"
|
||||
>
|
||||
<div class="import-container">
|
||||
<div class="down-template">
|
||||
<span class="icon-span">
|
||||
<el-icon>
|
||||
<Icon name="icon_warning_filled"><icon_warning_filled class="svg-icon" /></Icon>
|
||||
</el-icon>
|
||||
</span>
|
||||
<div class="down-template-content">
|
||||
<span>{{ t('common.upload_hint_first') }}</span>
|
||||
<el-button type="primary" link class="down-button" @click="downloadTemplate">
|
||||
{{ t('common.upload_hint_download_template') }}
|
||||
</el-button>
|
||||
<span>{{ t('common.upload_hint_end') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 100%">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
style="width: 100%"
|
||||
:multiple="false"
|
||||
accept=".xlsx,.xls"
|
||||
:action="getUploadURL()"
|
||||
:before-upload="beforeUpload"
|
||||
:headers="headers"
|
||||
:on-success="onSuccess"
|
||||
:on-error="onError"
|
||||
:show-file-list="false"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
<el-input
|
||||
v-model="fileName"
|
||||
style="width: 100%"
|
||||
:placeholder="t('common.click_to_select_file')"
|
||||
readonly
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon>
|
||||
<Icon name="icon_upload_outlined">
|
||||
<icon_upload_outlined class="svg-icon" />
|
||||
</Icon>
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #prefix>
|
||||
<img v-if="!!fileName" :src="icon_fileExcel_colorful" width="16px" height="16px" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-upload>
|
||||
|
||||
<div>
|
||||
<el-link class="font12" type="info" disabled>
|
||||
{{ t('common.excel_file_type_limit') }}
|
||||
</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="close">{{ t('common.cancel') }}</el-button>
|
||||
<el-button
|
||||
:type="fileName ? 'primary' : 'info'"
|
||||
:disabled="!fileName"
|
||||
@click="submitUpload"
|
||||
>
|
||||
{{ t('common.continue_to_upload') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-if="resultShow"
|
||||
v-model="resultShow"
|
||||
:title="hasError ? t('user.data_import_failed') : t('user.data_import_completed')"
|
||||
width="600px"
|
||||
class="user-import-class"
|
||||
@close="closeResult"
|
||||
>
|
||||
<div class="down-template-content">
|
||||
{{ infoMessage }}
|
||||
<el-button
|
||||
v-if="hasError && errorFileName.length > 0"
|
||||
type="primary"
|
||||
link
|
||||
class="down-button"
|
||||
@click="downloadErrorFile"
|
||||
>
|
||||
{{ errorFileName }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="closeResult">{{ t('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="backToUpload">
|
||||
{{ t('common.continue_to_upload') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
.down-template-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
line-height: 24px;
|
||||
height: 24px;
|
||||
|
||||
.down-button {
|
||||
padding: 0;
|
||||
height: unset !important;
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="less">
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
.import-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
:deep(.ed-upload) {
|
||||
width: 100%;
|
||||
}
|
||||
.down-template {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.font12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,20 +4,17 @@ import icon_export_outlined from '@/assets/svg/icon_export_outlined.svg'
|
||||
import { professionalApi } from '@/api/professional'
|
||||
import { formatTimestamp } from '@/utils/date'
|
||||
import { datasourceApi } from '@/api/datasource'
|
||||
import ccmUpload from '@/assets/svg/icon_ccm-upload_outlined.svg'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
import IconOpeEdit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import IconOpeDelete from '@/assets/svg/icon_delete.svg'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { cloneDeep, endsWith, startsWith } from 'lodash-es'
|
||||
import { genFileId, type UploadInstance, type UploadProps, type UploadRawFile } from 'element-plus'
|
||||
import { useCache } from '@/utils/useCache.ts'
|
||||
import { settingsApi } from '@/api/setting.ts'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { convertFilterText, FilterText } from '@/components/filter-text'
|
||||
import { DrawerMain } from '@/components/drawer-main'
|
||||
import iconFilter from '@/assets/svg/icon-filter_outlined.svg'
|
||||
import Uploader from '@/views/system/excel-upload/Uploader.vue'
|
||||
|
||||
interface Form {
|
||||
id?: string | null
|
||||
@@ -30,7 +27,6 @@ interface Form {
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
const multipleSelectionAll = ref<any[]>([])
|
||||
const allDsList = ref<any[]>([])
|
||||
const keywords = ref('')
|
||||
@@ -83,101 +79,6 @@ const cancelDelete = () => {
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadLoading = ref(false)
|
||||
|
||||
const token = wsCache.get('user.token')
|
||||
const headers = ref<any>({ 'X-SQLBOT-TOKEN': `Bearer ${token}` })
|
||||
const getUploadURL = import.meta.env.VITE_API_BASE_URL + '/system/terminology/uploadExcel'
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
uploadRef.value!.handleStart(file)
|
||||
}
|
||||
|
||||
const beforeUpload = (rawFile: any) => {
|
||||
if (rawFile.size / 1024 / 1024 > 50) {
|
||||
ElMessage.error(t('common.not_exceed_50mb'))
|
||||
return false
|
||||
}
|
||||
uploadLoading.value = true
|
||||
return true
|
||||
}
|
||||
const onSuccess = (response: any) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
search()
|
||||
|
||||
if (response?.data?.failed_count > 0 && response?.data?.error_excel_filename) {
|
||||
ElMessage.error(
|
||||
t('training.upload_failed', {
|
||||
success: response.data.success_count,
|
||||
fail: response.data.failed_count,
|
||||
fail_info: response.data.error_excel_filename,
|
||||
})
|
||||
)
|
||||
settingsApi
|
||||
.downloadError(response.data.error_excel_filename)
|
||||
.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 = response.data.error_excel_filename
|
||||
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(() => {
|
||||
uploadLoading.value = false
|
||||
})
|
||||
} else {
|
||||
ElMessage.success(t('training.upload_success'))
|
||||
uploadLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onError = (err: Error) => {
|
||||
uploadLoading.value = false
|
||||
uploadRef.value!.clearFiles()
|
||||
let msg = err.message
|
||||
if (startsWith(msg, '"') && endsWith(msg, '"')) {
|
||||
msg = msg.slice(1, msg.length - 1)
|
||||
}
|
||||
ElMessage({
|
||||
message: msg,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
ElMessageBox.confirm(t('professional.export_hint', { msg: pageInfo.total }), {
|
||||
confirmButtonType: 'primary',
|
||||
@@ -543,33 +444,19 @@ const changeStatus = (id: any, val: any) => {
|
||||
</template>
|
||||
{{ $t('professional.export_all') }}
|
||||
</el-button>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:multiple="false"
|
||||
accept=".xlsx,.xls"
|
||||
:action="getUploadURL"
|
||||
:before-upload="beforeUpload"
|
||||
:headers="headers"
|
||||
:on-success="onSuccess"
|
||||
:on-error="onError"
|
||||
:show-file-list="false"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
<el-button secondary>
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button secondary @click="drawerMainOpen">
|
||||
<Uploader
|
||||
upload-path="/system/terminology/uploadExcel"
|
||||
template-path="/system/terminology/template"
|
||||
:template-name="`${t('professional.professional_terminology')}.xlsx`"
|
||||
@upload-finished="search"
|
||||
/>
|
||||
<el-button class="no-margin" secondary @click="drawerMainOpen">
|
||||
<template #icon>
|
||||
<iconFilter></iconFilter>
|
||||
</template>
|
||||
{{ $t('user.filter') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="editHandler(null)">
|
||||
<el-button class="no-margin" type="primary" @click="editHandler(null)">
|
||||
<template #icon>
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</template>
|
||||
@@ -878,6 +765,9 @@ const changeStatus = (id: any, val: any) => {
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
.professional {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
@@ -4,7 +4,6 @@ import icon_export_outlined from '@/assets/svg/icon_export_outlined.svg'
|
||||
import { promptApi } from '@/api/prompt'
|
||||
import { formatTimestamp } from '@/utils/date'
|
||||
import { datasourceApi } from '@/api/datasource'
|
||||
import ccmUpload from '@/assets/svg/icon_ccm-upload_outlined.svg'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
import IconOpeEdit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import icon_copy_outlined from '@/assets/embedded/icon_copy_outlined.svg'
|
||||
@@ -13,13 +12,12 @@ import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlin
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { cloneDeep, endsWith, startsWith } from 'lodash-es'
|
||||
import { genFileId, type UploadInstance, type UploadProps, type UploadRawFile } from 'element-plus'
|
||||
import { settingsApi } from '@/api/setting.ts'
|
||||
import { useCache } from '@/utils/useCache.ts'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { convertFilterText, FilterText } from '@/components/filter-text'
|
||||
import { DrawerMain } from '@/components/drawer-main'
|
||||
import iconFilter from '@/assets/svg/icon-filter_outlined.svg'
|
||||
import Uploader from '@/views/system/excel-upload/Uploader.vue'
|
||||
|
||||
interface Form {
|
||||
id?: string | null
|
||||
type: string | null
|
||||
@@ -94,102 +92,18 @@ const cancelDelete = () => {
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadLoading = ref(false)
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const token = wsCache.get('user.token')
|
||||
const headers = ref<any>({ 'X-SQLBOT-TOKEN': `Bearer ${token}` })
|
||||
const getUploadURL = (type: string) => {
|
||||
return import.meta.env.VITE_API_BASE_URL + `/system/custom_prompt/${type}/uploadExcel`
|
||||
}
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
uploadRef.value!.handleStart(file)
|
||||
}
|
||||
|
||||
const beforeUpload = (rawFile: any) => {
|
||||
if (rawFile.size / 1024 / 1024 > 50) {
|
||||
ElMessage.error(t('common.not_exceed_50mb'))
|
||||
return false
|
||||
const getFileName = () => {
|
||||
let title = ''
|
||||
if (currentType.value === 'GENERATE_SQL') {
|
||||
title = t('prompt.ask_sql')
|
||||
}
|
||||
uploadLoading.value = true
|
||||
return true
|
||||
}
|
||||
const onSuccess = (response: any) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
search()
|
||||
|
||||
if (response?.data?.failed_count > 0 && response?.data?.error_excel_filename) {
|
||||
ElMessage.error(
|
||||
t('training.upload_failed', {
|
||||
success: response.data.success_count,
|
||||
fail: response.data.failed_count,
|
||||
fail_info: response.data.error_excel_filename,
|
||||
})
|
||||
)
|
||||
settingsApi
|
||||
.downloadError(response.data.error_excel_filename)
|
||||
.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 = response.data.error_excel_filename
|
||||
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(() => {
|
||||
uploadLoading.value = false
|
||||
})
|
||||
} else {
|
||||
ElMessage.success(t('training.upload_success'))
|
||||
uploadLoading.value = false
|
||||
if (currentType.value === 'ANALYSIS') {
|
||||
title = t('prompt.data_analysis')
|
||||
}
|
||||
}
|
||||
|
||||
const onError = (err: Error) => {
|
||||
uploadLoading.value = false
|
||||
uploadRef.value!.clearFiles()
|
||||
let msg = err.message
|
||||
if (startsWith(msg, '"') && endsWith(msg, '"')) {
|
||||
msg = msg.slice(1, msg.length - 1)
|
||||
if (currentType.value === 'PREDICT_DATA') {
|
||||
title = t('prompt.data_prediction')
|
||||
}
|
||||
ElMessage({
|
||||
message: msg,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
return `${title}.xlsx`
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
@@ -566,33 +480,19 @@ const drawerMainClose = () => {
|
||||
</template>
|
||||
{{ $t('professional.export_all') }}
|
||||
</el-button>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:multiple="false"
|
||||
accept=".xlsx,.xls"
|
||||
:action="getUploadURL(currentType)"
|
||||
:before-upload="beforeUpload"
|
||||
:headers="headers"
|
||||
:on-success="onSuccess"
|
||||
:on-error="onError"
|
||||
:show-file-list="false"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
<el-button secondary>
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button secondary @click="drawerMainOpen">
|
||||
<Uploader
|
||||
:upload-path="`/system/custom_prompt/${currentType}/uploadExcel`"
|
||||
:template-path="`/system/custom_prompt/template`"
|
||||
:template-name="getFileName()"
|
||||
@upload-finished="search"
|
||||
/>
|
||||
<el-button class="no-margin" secondary @click="drawerMainOpen">
|
||||
<template #icon>
|
||||
<iconFilter></iconFilter>
|
||||
</template>
|
||||
{{ $t('user.filter') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="editHandler(null)">
|
||||
<el-button class="no-margin" type="primary" @click="editHandler(null)">
|
||||
<template #icon>
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</template>
|
||||
@@ -851,6 +751,9 @@ const drawerMainClose = () => {
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
.prompt {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
import { computed, nextTick, onMounted, reactive, ref, unref } from 'vue'
|
||||
import icon_export_outlined from '@/assets/svg/icon_export_outlined.svg'
|
||||
import { trainingApi } from '@/api/training'
|
||||
import { settingsApi } from '@/api/setting.ts'
|
||||
import { formatTimestamp } from '@/utils/date'
|
||||
import { datasourceApi } from '@/api/datasource'
|
||||
import ccmUpload from '@/assets/svg/icon_ccm-upload_outlined.svg'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
import IconOpeEdit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import icon_copy_outlined from '@/assets/embedded/icon_copy_outlined.svg'
|
||||
@@ -15,12 +13,9 @@ import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { cloneDeep, endsWith, startsWith } from 'lodash-es'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { getAdvancedApplicationList } from '@/api/embedded.ts'
|
||||
import { genFileId } from 'element-plus'
|
||||
|
||||
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
|
||||
import { useCache } from '@/utils/useCache.ts'
|
||||
import Uploader from '@/views/system/excel-upload/Uploader.vue'
|
||||
|
||||
interface Form {
|
||||
id?: string | null
|
||||
@@ -38,7 +33,6 @@ const keywords = ref('')
|
||||
const oldKeywords = ref('')
|
||||
const searchLoading = ref(false)
|
||||
const { copy } = useClipboard({ legacy: true })
|
||||
const { wsCache } = useCache()
|
||||
const options = ref<any[]>([])
|
||||
const adv_options = ref<any[]>([])
|
||||
const selectable = () => {
|
||||
@@ -91,101 +85,6 @@ const cancelDelete = () => {
|
||||
isIndeterminate.value = false
|
||||
}
|
||||
|
||||
const uploadRef = ref<UploadInstance>()
|
||||
const uploadLoading = ref(false)
|
||||
|
||||
const token = wsCache.get('user.token')
|
||||
const headers = ref<any>({ 'X-SQLBOT-TOKEN': `Bearer ${token}` })
|
||||
const getUploadURL = import.meta.env.VITE_API_BASE_URL + '/system/data-training/uploadExcel'
|
||||
|
||||
const handleExceed: UploadProps['onExceed'] = (files) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
const file = files[0] as UploadRawFile
|
||||
file.uid = genFileId()
|
||||
uploadRef.value!.handleStart(file)
|
||||
}
|
||||
|
||||
const beforeUpload = (rawFile: any) => {
|
||||
if (rawFile.size / 1024 / 1024 > 50) {
|
||||
ElMessage.error(t('common.not_exceed_50mb'))
|
||||
return false
|
||||
}
|
||||
uploadLoading.value = true
|
||||
return true
|
||||
}
|
||||
const onSuccess = (response: any) => {
|
||||
uploadRef.value!.clearFiles()
|
||||
search()
|
||||
|
||||
if (response?.data?.failed_count > 0 && response?.data?.error_excel_filename) {
|
||||
ElMessage.error(
|
||||
t('training.upload_failed', {
|
||||
success: response.data.success_count,
|
||||
fail: response.data.failed_count,
|
||||
fail_info: response.data.error_excel_filename,
|
||||
})
|
||||
)
|
||||
settingsApi
|
||||
.downloadError(response.data.error_excel_filename)
|
||||
.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 = response.data.error_excel_filename
|
||||
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(() => {
|
||||
uploadLoading.value = false
|
||||
})
|
||||
} else {
|
||||
ElMessage.success(t('training.upload_success'))
|
||||
uploadLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onError = (err: Error) => {
|
||||
uploadLoading.value = false
|
||||
uploadRef.value!.clearFiles()
|
||||
let msg = err.message
|
||||
if (startsWith(msg, '"') && endsWith(msg, '"')) {
|
||||
msg = msg.slice(1, msg.length - 1)
|
||||
}
|
||||
ElMessage({
|
||||
message: msg,
|
||||
type: 'error',
|
||||
showClose: true,
|
||||
})
|
||||
}
|
||||
|
||||
const exportExcel = () => {
|
||||
ElMessageBox.confirm(t('training.export_hint', { msg: pageInfo.total }), {
|
||||
confirmButtonType: 'primary',
|
||||
@@ -460,7 +359,7 @@ const onRowFormClose = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-loading="searchLoading || uploadLoading" class="training">
|
||||
<div v-loading="searchLoading" class="training">
|
||||
<div class="tool-left">
|
||||
<span class="page-title">{{ $t('training.data_training') }}</span>
|
||||
<div class="tool-row">
|
||||
@@ -483,27 +382,13 @@ const onRowFormClose = () => {
|
||||
</template>
|
||||
{{ $t('professional.export_all') }}
|
||||
</el-button>
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
:multiple="false"
|
||||
accept=".xlsx,.xls"
|
||||
:action="getUploadURL"
|
||||
:before-upload="beforeUpload"
|
||||
:headers="headers"
|
||||
:on-success="onSuccess"
|
||||
:on-error="onError"
|
||||
:show-file-list="false"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
<el-button secondary>
|
||||
<template #icon>
|
||||
<ccmUpload></ccmUpload>
|
||||
</template>
|
||||
{{ $t('user.batch_import') }}
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<el-button type="primary" @click="editHandler(null)">
|
||||
<Uploader
|
||||
upload-path="/system/data-training/uploadExcel"
|
||||
template-path="/system/data-training/template"
|
||||
:template-name="`${t('training.data_training')}.xlsx`"
|
||||
@upload-finished="search"
|
||||
/>
|
||||
<el-button class="no-margin" type="primary" @click="editHandler(null)">
|
||||
<template #icon>
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</template>
|
||||
@@ -775,6 +660,9 @@ const onRowFormClose = () => {
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
.training {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
Reference in New Issue
Block a user