feat: import Sample SQL

This commit is contained in:
ulleo
2025-11-17 19:30:52 +08:00
committed by ulleo
parent 067406633a
commit 5b436c7b48
10 changed files with 528 additions and 19 deletions
+5
View File
@@ -15,4 +15,9 @@ export const trainingApi = {
responseType: 'blob',
requestOptions: { customError: true },
}),
downloadError: (path: any) =>
request.get(`/system/data-training/download-fail-info/${path}`, {
responseType: 'blob',
requestOptions: { customError: true },
}),
}
+3 -1
View File
@@ -44,7 +44,9 @@
"sql_statement": "SQL Statement",
"edit_training_data": "Edit SQL Sample",
"all_236_terms": "Export all {msg} sample SQL records?",
"sales_this_year": "Do you want to delete the SQL Sample: {msg}?"
"sales_this_year": "Do you want to delete the SQL Sample: {msg}?",
"upload_success": "Import Successful",
"upload_failed": "Import successful: {success} records. Failed: {fail} records. For details, see: {fail_info}"
},
"professional": {
"cannot_be_repeated": "Term name, synonyms cannot be repeated",
+3 -1
View File
@@ -44,7 +44,9 @@
"sql_statement": "SQL 문",
"edit_training_data": "예제 SQL 편집",
"all_236_terms": "모든 {msg}개의 예시 SQL 기록을 내보내시겠습니까?",
"sales_this_year": "예제 SQL을 삭제하시겠습니까: {msg}?"
"sales_this_year": "예제 SQL을 삭제하시겠습니까: {msg}?",
"upload_success": "가져오기 성공",
"upload_failed": "성공: {success}건, 실패: {fail}건. 자세한 내용은 다음을 참조하세요: {fail_info}"
},
"professional": {
"cannot_be_repeated": "용어 이름과 동의어는 중복될 수 없습니다",
+3 -1
View File
@@ -44,7 +44,9 @@
"sql_statement": "SQL 语句",
"edit_training_data": "编辑示例 SQL",
"all_236_terms": "是否导出全部 {msg} 条示例 SQL?",
"sales_this_year": "是否删除示例 SQL:{msg}?"
"sales_this_year": "是否删除示例 SQL:{msg}?",
"upload_success": "导入成功",
"upload_failed": "导入成功 {success} 条,失败 {fail} 条,失败信息详见:{fail_info}"
},
"professional": {
"cannot_be_repeated": "术语名称,同义词不能重复",
+129 -10
View File
@@ -16,6 +16,10 @@ import { useUserStore } from '@/stores/user'
import { useI18n } from 'vue-i18n'
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'
interface Form {
id?: string | null
@@ -33,7 +37,7 @@ 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 = () => {
@@ -86,6 +90,94 @@ const cancelDelete = () => {
isIndeterminate.value = false
}
const upload = () => {}
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,
})
)
trainingApi
.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 = `${t('training.data_training')}_error.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(() => {
uploadLoading.value = false
})
} else {
ElMessage.success(t('training.upload_success'))
uploadLoading.value = false
}
}
const onError = () => {
uploadLoading.value = false
uploadRef.value!.clearFiles()
}
const exportExcel = () => {
ElMessageBox.confirm(t('training.all_236_terms', { msg: pageInfo.total }), {
confirmButtonType: 'primary',
@@ -360,13 +452,13 @@ const onRowFormClose = () => {
</script>
<template>
<div v-loading="searchLoading" class="training">
<div v-loading="searchLoading || uploadLoading" class="training">
<div class="tool-left">
<span class="page-title">{{ $t('training.data_training') }}</span>
<div>
<div class="tool-row">
<el-input
v-model="keywords"
style="width: 240px; margin-right: 12px"
style="width: 240px"
:placeholder="$t('training.search_problem')"
clearable
@blur="search"
@@ -383,12 +475,26 @@ const onRowFormClose = () => {
</template>
{{ $t('professional.export_all') }}
</el-button>
<el-button v-if="false" secondary @click="editHandler(null)">
<template #icon>
<ccmUpload></ccmUpload>
</template>
{{ $t('user.batch_import') }}
</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 @click="upload()">
<template #icon>
<ccmUpload></ccmUpload>
</template>
{{ $t('user.batch_import') }}
</el-button>
</el-upload>
<el-button type="primary" @click="editHandler(null)">
<template #icon>
<icon_add_outlined></icon_add_outlined>
@@ -688,6 +794,13 @@ const onRowFormClose = () => {
}
}
.tool-row {
display: flex;
align-items: center;
flex-direction: row;
gap: 8px;
}
.pagination-container {
display: flex;
justify-content: end;
@@ -861,4 +974,10 @@ const onRowFormClose = () => {
line-height: 22px;
}
}
.upload-user {
height: 32px;
.ed-upload {
width: 100% !important;
}
}
</style>