|
...
|
...
|
@@ -4,17 +4,11 @@ |
|
|
|
<template #tableTitle>
|
|
|
|
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined">新增</a-button>
|
|
|
|
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls">导出</a-button>
|
|
|
|
<a-button
|
|
|
|
type="primary"
|
|
|
|
preIcon="ant-design:import-outlined"
|
|
|
|
@click="handleOpenImportModal"
|
|
|
|
>导入ZIP</a-button>
|
|
|
|
<a-button type="primary" preIcon="ant-design:import-outlined" @click="handleOpenImportModal">导入ZIP</a-button>
|
|
|
|
<a-dropdown v-if="selectedRowKeys.length > 0">
|
|
|
|
<template #overlay>
|
|
|
|
<a-menu>
|
|
|
|
<a-menu-item key="1" @click="batchHandleDelete">
|
|
|
|
<Icon icon="ant-design:delete-outlined" />删除
|
|
|
|
</a-menu-item>
|
|
|
|
<a-menu-item key="1" @click="batchHandleDelete"> <Icon icon="ant-design:delete-outlined" />删除 </a-menu-item>
|
|
|
|
</a-menu>
|
|
|
|
</template>
|
|
|
|
<a-button>批量操作<Icon icon="mdi:chevron-down" /></a-button>
|
|
...
|
...
|
@@ -36,30 +30,13 @@ |
|
|
|
:okButtonProps="{ disabled: !selectedKnowledgeId || !currentFile }"
|
|
|
|
>
|
|
|
|
<BasicForm @register="registerImportForm" :showActionButtonGroup="false" />
|
|
|
|
<div style="margin-top: 20px;margin-left: 5%">
|
|
|
|
<input
|
|
|
|
type="file"
|
|
|
|
ref="fileInput"
|
|
|
|
accept=".zip"
|
|
|
|
@change="handleFileChange"
|
|
|
|
style="display: none"
|
|
|
|
>
|
|
|
|
<a-button
|
|
|
|
type="primary"
|
|
|
|
@click="triggerFileInput"
|
|
|
|
>
|
|
|
|
<UploadOutlined /> 选择ZIP文件
|
|
|
|
</a-button>
|
|
|
|
<div v-if="currentFile" style="margin-top: 8px;">
|
|
|
|
已选择文件: {{ currentFile.name }} ({{ formatFileSize(currentFile.size) }})
|
|
|
|
</div>
|
|
|
|
<div v-if="uploadProgress > 0" style="margin-top: 8px;">
|
|
|
|
<div style="margin-top: 20px; margin-left: 5%">
|
|
|
|
<input type="file" ref="fileInput" accept=".zip" @change="handleFileChange" style="display: none" />
|
|
|
|
<a-button type="primary" @click="triggerFileInput"> <UploadOutlined /> 选择ZIP文件 </a-button>
|
|
|
|
<div v-if="currentFile" style="margin-top: 8px"> 已选择文件: {{ currentFile.name }} ({{ formatFileSize(currentFile.size) }}) </div>
|
|
|
|
<div v-if="uploadProgress > 0" style="margin-top: 8px">
|
|
|
|
上传进度: {{ uploadProgress }}%
|
|
|
|
<a-progress
|
|
|
|
:percent="uploadProgress"
|
|
|
|
:stroke-color="progressColor"
|
|
|
|
:status="uploadStatus"
|
|
|
|
/>
|
|
|
|
<a-progress :percent="uploadProgress" :stroke-color="progressColor" :status="uploadStatus" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</BasicModal>
|
|
...
|
...
|
@@ -67,32 +44,32 @@ |
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
import { ref, reactive } from 'vue';
|
|
|
|
import { UploadOutlined } from '@ant-design/icons-vue';
|
|
|
|
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
|
|
|
import { BasicModal } from '/@/components/Modal';
|
|
|
|
import { BasicForm, useForm } from '/@/components/Form';
|
|
|
|
import { useModal } from '/@/components/Modal';
|
|
|
|
import { useListPage } from '/@/hooks/system/useListPage';
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
import QuestionEmbeddingModal from './components/QuestionEmbeddingModal.vue';
|
|
|
|
import { columns, searchFormSchema } from './QuestionEmbedding.data';
|
|
|
|
import { list, deleteOne, batchDelete, getImportZipUrl, getExportUrl, listKnowledge } from './QuestionEmbedding.api';
|
|
|
|
import { useUserStore } from '/@/store/modules/user';
|
|
|
|
import { getToken } from '/@/utils/auth';
|
|
|
|
import { ref, reactive } from 'vue';
|
|
|
|
import { UploadOutlined } from '@ant-design/icons-vue';
|
|
|
|
import { BasicTable, TableAction } from '/@/components/Table';
|
|
|
|
import { BasicModal } from '/@/components/Modal';
|
|
|
|
import { BasicForm, useForm } from '/@/components/Form';
|
|
|
|
import { useModal } from '/@/components/Modal';
|
|
|
|
import { useListPage } from '/@/hooks/system/useListPage';
|
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
import QuestionEmbeddingModal from './components/QuestionEmbeddingModal.vue';
|
|
|
|
import { columns, searchFormSchema } from './QuestionEmbedding.data';
|
|
|
|
import { list, deleteOne, batchDelete, getImportZipUrl, getExportUrl, listKnowledge } from './QuestionEmbedding.api';
|
|
|
|
import { useUserStore } from '/@/store/modules/user';
|
|
|
|
import { getToken } from '/@/utils/auth';
|
|
|
|
|
|
|
|
const queryParam = reactive<any>({});
|
|
|
|
const [registerModal, { openModal }] = useModal();
|
|
|
|
const importModalVisible = ref(false);
|
|
|
|
const selectedKnowledgeId = ref('');
|
|
|
|
const fileInput = ref<HTMLInputElement | null>(null);
|
|
|
|
const currentFile = ref<File | null>(null);
|
|
|
|
const uploadProgress = ref(0);
|
|
|
|
const progressColor = ref('#1890ff');
|
|
|
|
const uploadStatus = ref<'normal' | 'exception' | 'active' | 'success'>('normal');
|
|
|
|
const queryParam = reactive<any>({});
|
|
|
|
const [registerModal, { openModal }] = useModal();
|
|
|
|
const importModalVisible = ref(false);
|
|
|
|
const selectedKnowledgeId = ref('');
|
|
|
|
const fileInput = ref<HTMLInputElement | null>(null);
|
|
|
|
const currentFile = ref<File | null>(null);
|
|
|
|
const uploadProgress = ref(0);
|
|
|
|
const progressColor = ref('#1890ff');
|
|
|
|
const uploadStatus = ref<'normal' | 'exception' | 'active' | 'success'>('normal');
|
|
|
|
|
|
|
|
// 知识库选择表单
|
|
|
|
const [registerImportForm] = useForm({
|
|
|
|
// 知识库选择表单
|
|
|
|
const [registerImportForm] = useForm({
|
|
|
|
labelWidth: 100,
|
|
|
|
showActionButtonGroup: false,
|
|
|
|
schemas: [
|
|
...
|
...
|
@@ -108,13 +85,13 @@ const [registerImportForm] = useForm({ |
|
|
|
valueField: 'id',
|
|
|
|
onChange: (value: string) => {
|
|
|
|
selectedKnowledgeId.value = value;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
const { tableContext, onExportXls } = useListPage({
|
|
|
|
const { tableContext, onExportXls } = useListPage({
|
|
|
|
tableProps: {
|
|
|
|
title: '问答向量库',
|
|
|
|
api: list,
|
|
...
|
...
|
@@ -122,38 +99,38 @@ const { tableContext, onExportXls } = useListPage({ |
|
|
|
formConfig: {
|
|
|
|
schemas: searchFormSchema,
|
|
|
|
autoSubmitOnEnter: true,
|
|
|
|
showAdvancedButton: true
|
|
|
|
showAdvancedButton: true,
|
|
|
|
},
|
|
|
|
actionColumn: {
|
|
|
|
width: 120,
|
|
|
|
fixed: 'right'
|
|
|
|
fixed: 'right',
|
|
|
|
},
|
|
|
|
beforeFetch: (params) => Object.assign(params, queryParam)
|
|
|
|
beforeFetch: (params) => Object.assign(params, queryParam),
|
|
|
|
},
|
|
|
|
exportConfig: {
|
|
|
|
name: '问答向量库',
|
|
|
|
url: getExportUrl
|
|
|
|
}
|
|
|
|
});
|
|
|
|
url: getExportUrl,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
|
|
|
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
|
|
|
|
|
|
|
function handleOpenImportModal() {
|
|
|
|
function handleOpenImportModal() {
|
|
|
|
importModalVisible.value = true;
|
|
|
|
selectedKnowledgeId.value = '';
|
|
|
|
resetFileInput();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleImportCancel() {
|
|
|
|
function handleImportCancel() {
|
|
|
|
importModalVisible.value = false;
|
|
|
|
resetFileInput();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function triggerFileInput() {
|
|
|
|
function triggerFileInput() {
|
|
|
|
fileInput.value?.click();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleFileChange(e: Event) {
|
|
|
|
function handleFileChange(e: Event) {
|
|
|
|
const input = e.target as HTMLInputElement;
|
|
|
|
if (input.files && input.files.length > 0) {
|
|
|
|
currentFile.value = input.files[0];
|
|
...
|
...
|
@@ -162,35 +139,35 @@ function handleFileChange(e: Event) { |
|
|
|
console.log('文件选择成功:', {
|
|
|
|
name: currentFile.value.name,
|
|
|
|
size: currentFile.value.size,
|
|
|
|
type: currentFile.value.type
|
|
|
|
type: currentFile.value.type,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
currentFile.value = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function resetFileInput() {
|
|
|
|
function resetFileInput() {
|
|
|
|
if (fileInput.value) {
|
|
|
|
fileInput.value.value = '';
|
|
|
|
}
|
|
|
|
currentFile.value = null;
|
|
|
|
uploadProgress.value = 0;
|
|
|
|
uploadStatus.value = 'normal';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function formatFileSize(bytes: number): string {
|
|
|
|
function formatFileSize(bytes: number): string {
|
|
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
const k = 1024;
|
|
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 获取用户token
|
|
|
|
const userStore = useUserStore();
|
|
|
|
const token = getToken();
|
|
|
|
// 获取用户token
|
|
|
|
const userStore = useUserStore();
|
|
|
|
const token = getToken();
|
|
|
|
|
|
|
|
async function handleImportSubmit() {
|
|
|
|
async function handleImportSubmit() {
|
|
|
|
if (!selectedKnowledgeId.value || !currentFile.value) {
|
|
|
|
message.warning('请完整填写上传信息');
|
|
|
|
return;
|
|
...
|
...
|
@@ -205,14 +182,14 @@ async function handleImportSubmit() { |
|
|
|
uploadStatus.value = 'active';
|
|
|
|
|
|
|
|
// 使用fetch API并添加认证头
|
|
|
|
const response = await fetch("/jeecgboot" + getImportZipUrl, {
|
|
|
|
const response = await fetch('/jeecgboot' + getImportZipUrl, {
|
|
|
|
method: 'POST',
|
|
|
|
body: formData,
|
|
|
|
headers: {
|
|
|
|
'X-Access-Token': token, // JEECG标准认证头
|
|
|
|
'Authorization': `Bearer ${token}` // 备用认证头
|
|
|
|
Authorization: `Bearer ${token}`, // 备用认证头
|
|
|
|
},
|
|
|
|
credentials: 'include' // 携带cookie
|
|
|
|
credentials: 'include', // 携带cookie
|
|
|
|
});
|
|
|
|
|
|
|
|
if (response.status === 401) {
|
|
...
|
...
|
@@ -238,68 +215,66 @@ async function handleImportSubmit() { |
|
|
|
message.error(error.message || '上传失败');
|
|
|
|
console.error('上传错误:', error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleSuperQuery(params: any) {
|
|
|
|
function handleSuperQuery(params: any) {
|
|
|
|
Object.assign(queryParam, params);
|
|
|
|
reload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleAdd() {
|
|
|
|
function handleAdd() {
|
|
|
|
openModal(true, { isUpdate: false, showFooter: true });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleEdit(record: any) {
|
|
|
|
function handleEdit(record: any) {
|
|
|
|
openModal(true, { record, isUpdate: true, showFooter: true });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleDetail(record: any) {
|
|
|
|
function handleDetail(record: any) {
|
|
|
|
openModal(true, { record, isUpdate: true, showFooter: false });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function handleDelete(record: any) {
|
|
|
|
async function handleDelete(record: any) {
|
|
|
|
await deleteOne({ id: record.id }, handleSuccess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function batchHandleDelete() {
|
|
|
|
async function batchHandleDelete() {
|
|
|
|
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function handleSuccess() {
|
|
|
|
function handleSuccess() {
|
|
|
|
selectedRowKeys.value = [];
|
|
|
|
reload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTableAction(record: any) {
|
|
|
|
return [
|
|
|
|
{ label: '编辑', onClick: handleEdit.bind(null, record) }
|
|
|
|
];
|
|
|
|
}
|
|
|
|
function getTableAction(record: any) {
|
|
|
|
return [{ label: '编辑', onClick: handleEdit.bind(null, record) }];
|
|
|
|
}
|
|
|
|
|
|
|
|
function getDropDownAction(record: any) {
|
|
|
|
function getDropDownAction(record: any) {
|
|
|
|
return [
|
|
|
|
{ label: '详情', onClick: handleDetail.bind(null, record) },
|
|
|
|
{
|
|
|
|
label: '删除',
|
|
|
|
popConfirm: {
|
|
|
|
title: '确认删除此问答?',
|
|
|
|
confirm: handleDelete.bind(null, record)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
confirm: handleDelete.bind(null, record),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.upload-area {
|
|
|
|
.upload-area {
|
|
|
|
margin-top: 20px;
|
|
|
|
padding: 20px;
|
|
|
|
border: 1px dashed #d9d9d9;
|
|
|
|
border-radius: 4px;
|
|
|
|
text-align: center;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
.upload-area:hover {
|
|
|
|
}
|
|
|
|
.upload-area:hover {
|
|
|
|
border-color: #1890ff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style> |
...
|
...
|
|