1、文档新增批量删除
2、文档新增点击文件名预览
This commit is contained in:
@@ -8,8 +8,8 @@ import { MODULES_API_URL } from '@/config/setting';
|
|||||||
*/
|
*/
|
||||||
export async function pageAiCloudFile(params: AiCloudFileParam) {
|
export async function pageAiCloudFile(params: AiCloudFileParam) {
|
||||||
const res = await request.get<ApiResult<PageResult<AiCloudFile>>>(
|
const res = await request.get<ApiResult<PageResult<AiCloudFile>>>(
|
||||||
MODULES_API_URL + '/ai/file/page',
|
MODULES_API_URL + '/ai/file/page',
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -22,8 +22,8 @@ export async function pageAiCloudFile(params: AiCloudFileParam) {
|
|||||||
*/
|
*/
|
||||||
export async function listAiCloudFile(params?: AiCloudFileParam) {
|
export async function listAiCloudFile(params?: AiCloudFileParam) {
|
||||||
const res = await request.get<ApiResult<AiCloudFile[]>>(
|
const res = await request.get<ApiResult<AiCloudFile[]>>(
|
||||||
MODULES_API_URL + '/ai/file',
|
MODULES_API_URL + '/ai/file',
|
||||||
{ params }
|
{ params }
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -34,22 +34,28 @@ export async function listAiCloudFile(params?: AiCloudFileParam) {
|
|||||||
/**
|
/**
|
||||||
* 上传文件到云中心
|
* 上传文件到云中心
|
||||||
*/
|
*/
|
||||||
export async function uploadFiles(docId: number, categoryId: string, files: File[]) {
|
export async function uploadFiles(
|
||||||
|
docId: number,
|
||||||
|
categoryId: string,
|
||||||
|
files: File[],
|
||||||
|
onUploadProgress?: (event: ProgressEvent) => void
|
||||||
|
) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('docId', docId);
|
formData.append('docId', docId);
|
||||||
formData.append('categoryId', categoryId);
|
formData.append('categoryId', categoryId);
|
||||||
files.forEach(file => {
|
files.forEach((file) => {
|
||||||
formData.append('files', file);
|
formData.append('files', file);
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await request.post<ApiResult<unknown>>(
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
MODULES_API_URL + '/ai/file/uploadFiles',
|
MODULES_API_URL + '/ai/file/uploadFiles',
|
||||||
formData,
|
formData,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'multipart/form-data'
|
'Content-Type': 'multipart/form-data'
|
||||||
}
|
},
|
||||||
}
|
onUploadProgress
|
||||||
|
}
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
return res.data.message;
|
return res.data.message;
|
||||||
@@ -62,7 +68,7 @@ export async function uploadFiles(docId: number, categoryId: string, files: File
|
|||||||
*/
|
*/
|
||||||
export async function removeAiCloudFile(id?: number) {
|
export async function removeAiCloudFile(id?: number) {
|
||||||
const res = await request.delete<ApiResult<unknown>>(
|
const res = await request.delete<ApiResult<unknown>>(
|
||||||
MODULES_API_URL + '/ai/file/' + id
|
MODULES_API_URL + '/ai/file/' + id
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
return res.data.message;
|
return res.data.message;
|
||||||
@@ -75,7 +81,7 @@ export async function removeAiCloudFile(id?: number) {
|
|||||||
*/
|
*/
|
||||||
export async function getAiCloudFile(id: number) {
|
export async function getAiCloudFile(id: number) {
|
||||||
const res = await request.get<ApiResult<AiCloudFile>>(
|
const res = await request.get<ApiResult<AiCloudFile>>(
|
||||||
MODULES_API_URL + '/ai/file/' + id
|
MODULES_API_URL + '/ai/file/' + id
|
||||||
);
|
);
|
||||||
if (res.data.code === 0 && res.data.data) {
|
if (res.data.code === 0 && res.data.data) {
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
@@ -88,8 +94,8 @@ export async function getAiCloudFile(id: number) {
|
|||||||
*/
|
*/
|
||||||
export async function updateAiCloudFile(data: AiCloudFile) {
|
export async function updateAiCloudFile(data: AiCloudFile) {
|
||||||
const res = await request.put<ApiResult<unknown>>(
|
const res = await request.put<ApiResult<unknown>>(
|
||||||
MODULES_API_URL + '/ai/file',
|
MODULES_API_URL + '/ai/file',
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
return res.data.message;
|
return res.data.message;
|
||||||
|
|||||||
@@ -1,114 +1,197 @@
|
|||||||
<!-- 文档导入弹窗 -->
|
<!-- 文档导入弹窗 -->
|
||||||
<template>
|
<template>
|
||||||
<ele-modal
|
<ele-modal
|
||||||
:width="520"
|
:width="520"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
:title="`批量导入文档`"
|
:title="`批量导入文档`"
|
||||||
:visible="visible"
|
:visible="visible"
|
||||||
@update:visible="updateVisible"
|
@update:visible="updateVisible"
|
||||||
>
|
>
|
||||||
<a-spin :spinning="loading">
|
<a-spin :spinning="loading">
|
||||||
|
<div v-if="queuedFileNames.length" class="upload-queue-info">
|
||||||
|
已加入 {{ queuedFileNames.length }} 个文件
|
||||||
|
</div>
|
||||||
<a-upload-dragger
|
<a-upload-dragger
|
||||||
accept=".pdf,.doc,.docx,.txt,.md,.xls,.xlsx"
|
accept=".pdf,.doc,.docx,.txt,.md,.xls,.xlsx"
|
||||||
:show-upload-list="false"
|
:show-upload-list="false"
|
||||||
:customRequest="doUpload"
|
:customRequest="doUpload"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
style="padding: 24px 0; margin-bottom: 16px"
|
style="padding: 24px 0; margin-bottom: 16px"
|
||||||
>
|
>
|
||||||
<p class="ant-upload-drag-icon">
|
<p class="ant-upload-drag-icon">
|
||||||
<cloud-upload-outlined />
|
<cloud-upload-outlined />
|
||||||
</p>
|
</p>
|
||||||
<p class="ant-upload-hint">将文件拖到此处,或点击上传</p>
|
<p class="ant-upload-hint">将文件拖到此处,或点击上传</p>
|
||||||
<p class="ant-upload-hint" style="font-size: 12px; color: #999;">
|
<p class="ant-upload-hint" style="font-size: 12px; color: #999">
|
||||||
支持格式:PDF、Word、Excel、TXT、MD 等文档格式
|
支持格式:PDF、Word、Excel、TXT、MD 等文档格式
|
||||||
</p>
|
</p>
|
||||||
</a-upload-dragger>
|
</a-upload-dragger>
|
||||||
|
<div v-if="loading || uploadProgress > 0" class="upload-progress-wrapper">
|
||||||
|
<div class="upload-progress-header">
|
||||||
|
<span>{{ progressText }}</span>
|
||||||
|
<span>{{ uploadProgress }}%</span>
|
||||||
|
</div>
|
||||||
|
<a-progress
|
||||||
|
:percent="uploadProgress"
|
||||||
|
:status="uploadProgress === 100 ? 'success' : 'active'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</ele-modal>
|
</ele-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { message } from 'ant-design-vue/es';
|
import { message } from 'ant-design-vue/es';
|
||||||
import { CloudUploadOutlined } from '@ant-design/icons-vue';
|
import { CloudUploadOutlined } from '@ant-design/icons-vue';
|
||||||
import { debounce } from 'lodash-es';
|
import { debounce } from 'lodash-es';
|
||||||
import { uploadFiles } from '@/api/ai/aiCloudFile';
|
import { uploadFiles } from '@/api/ai/aiCloudFile';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'done'): void;
|
(e: 'done'): void;
|
||||||
(e: 'update:visible', visible: boolean): void;
|
(e: 'update:visible', visible: boolean): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// 在顶层定义 props - 修改为接收 doc 对象
|
// 在顶层定义 props - 修改为接收 doc 对象
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
doc: { // 改为接收完整的 doc 对象
|
doc: {
|
||||||
id: number;
|
// 改为接收完整的 doc 对象
|
||||||
categoryId: string;
|
id: number;
|
||||||
|
categoryId: string;
|
||||||
|
};
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const uploadProgress = ref(0);
|
||||||
|
const queuedFileNames = ref<string[]>([]);
|
||||||
|
|
||||||
|
const progressText = computed(() => {
|
||||||
|
if (loading.value) {
|
||||||
|
return queuedFileNames.value.length
|
||||||
|
? `正在上传 ${queuedFileNames.value.length} 个文件`
|
||||||
|
: '正在上传文件';
|
||||||
|
}
|
||||||
|
if (uploadProgress.value === 100) {
|
||||||
|
return '上传完成';
|
||||||
|
}
|
||||||
|
return '等待上传';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 新增批量上传方法 - 修改调用参数
|
||||||
|
const handleBatchUpload = debounce(async () => {
|
||||||
|
if (uploadQueue.length === 0) return;
|
||||||
|
|
||||||
|
const files = [...uploadQueue];
|
||||||
|
queuedFileNames.value = files.map((file) => file.name);
|
||||||
|
uploadQueue.length = 0; // 清空队列
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
uploadProgress.value = 0;
|
||||||
|
try {
|
||||||
|
// 修改:传入 doc.id 和 doc.categoryId
|
||||||
|
const msg = await uploadFiles(
|
||||||
|
props.doc.id,
|
||||||
|
props.doc.categoryId,
|
||||||
|
files,
|
||||||
|
(event) => {
|
||||||
|
if (!event.total) return;
|
||||||
|
uploadProgress.value = Math.min(
|
||||||
|
100,
|
||||||
|
Math.max(0, Math.round((event.loaded / event.total) * 100))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
uploadProgress.value = 100;
|
||||||
|
message.success(msg || '上传成功');
|
||||||
|
updateVisible(false);
|
||||||
|
emit('done');
|
||||||
|
} catch (e: any) {
|
||||||
|
message.error(e.message || '上传失败');
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
window.setTimeout(() => {
|
||||||
|
uploadProgress.value = 0;
|
||||||
|
queuedFileNames.value = [];
|
||||||
|
}, 600);
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
// 修改后的上传方法
|
||||||
|
const doUpload = ({ file }: { file: File }) => {
|
||||||
|
// 检查文件类型
|
||||||
|
const allowedTypes = [
|
||||||
|
'application/pdf',
|
||||||
|
'application/msword',
|
||||||
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||||
|
'text/plain',
|
||||||
|
'text/markdown',
|
||||||
|
'application/vnd.ms-excel',
|
||||||
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||||||
|
];
|
||||||
|
|
||||||
|
const allowedExtensions = [
|
||||||
|
'.pdf',
|
||||||
|
'.doc',
|
||||||
|
'.docx',
|
||||||
|
'.txt',
|
||||||
|
'.md',
|
||||||
|
'.xls',
|
||||||
|
'.xlsx'
|
||||||
|
];
|
||||||
|
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
||||||
|
|
||||||
|
if (
|
||||||
|
!allowedTypes.includes(file.type) &&
|
||||||
|
!allowedExtensions.includes(fileExtension)
|
||||||
|
) {
|
||||||
|
message.error('只能上传文档文件(PDF、Word、Excel、TXT、MD)');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size / 1024 / 1024 > 100) {
|
||||||
|
message.error('文件大小不能超过 100MB');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将文件加入队列并触发防抖上传
|
||||||
|
uploadQueue.push(file);
|
||||||
|
handleBatchUpload();
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
}>();
|
|
||||||
|
|
||||||
const loading = ref(false);
|
// 新增文件队列
|
||||||
|
const uploadQueue: File[] = [];
|
||||||
|
|
||||||
// 新增批量上传方法 - 修改调用参数
|
/* 更新 visible */
|
||||||
const handleBatchUpload = debounce(async () => {
|
const updateVisible = (value: boolean) => {
|
||||||
if (uploadQueue.length === 0) return;
|
if (!value && !loading.value) {
|
||||||
|
uploadProgress.value = 0;
|
||||||
|
queuedFileNames.value = [];
|
||||||
|
uploadQueue.length = 0;
|
||||||
|
}
|
||||||
|
emit('update:visible', value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
const files = [...uploadQueue];
|
<style lang="less" scoped>
|
||||||
uploadQueue.length = 0; // 清空队列
|
.upload-queue-info {
|
||||||
|
margin-bottom: 12px;
|
||||||
loading.value = true;
|
color: #666;
|
||||||
try {
|
font-size: 12px;
|
||||||
// 修改:传入 doc.id 和 doc.categoryId
|
|
||||||
const msg = await uploadFiles(props.doc.id, props.doc.categoryId, files);
|
|
||||||
message.success(msg || '上传成功');
|
|
||||||
updateVisible(false);
|
|
||||||
emit('done');
|
|
||||||
} catch (e: any) {
|
|
||||||
message.error(e.message || '上传失败');
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
// 修改后的上传方法
|
|
||||||
const doUpload = ({ file }: { file: File }) => {
|
|
||||||
// 检查文件类型
|
|
||||||
const allowedTypes = [
|
|
||||||
'application/pdf',
|
|
||||||
'application/msword',
|
|
||||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
||||||
'text/plain',
|
|
||||||
'text/markdown',
|
|
||||||
'application/vnd.ms-excel',
|
|
||||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
||||||
];
|
|
||||||
|
|
||||||
const allowedExtensions = ['.pdf', '.doc', '.docx', '.txt', '.md', '.xls', '.xlsx'];
|
|
||||||
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
||||||
|
|
||||||
if (!allowedTypes.includes(file.type) && !allowedExtensions.includes(fileExtension)) {
|
|
||||||
message.error('只能上传文档文件(PDF、Word、Excel、TXT、MD)');
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.size / 1024 / 1024 > 100) {
|
.upload-progress-wrapper {
|
||||||
message.error('文件大小不能超过 100MB');
|
margin-top: 12px;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将文件加入队列并触发防抖上传
|
.upload-progress-header {
|
||||||
uploadQueue.push(file);
|
display: flex;
|
||||||
handleBatchUpload();
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
return false;
|
margin-bottom: 8px;
|
||||||
};
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
// 新增文件队列
|
}
|
||||||
const uploadQueue: File[] = [];
|
</style>
|
||||||
|
|
||||||
/* 更新 visible */
|
|
||||||
const updateVisible = (value: boolean) => {
|
|
||||||
emit('update:visible', value);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|||||||
@@ -44,13 +44,13 @@
|
|||||||
<a @click="openEdit(record)">修改</a>
|
<a @click="openEdit(record)">修改</a>
|
||||||
<a-divider type="vertical" />
|
<a-divider type="vertical" />
|
||||||
<!-- 文档管理按钮 -->
|
<!-- 文档管理按钮 -->
|
||||||
<a
|
<!-- <a-->
|
||||||
:class="{ 'disabled-text': !record.kbId }"
|
<!-- :class="{ 'disabled-text': !record.kbId }"-->
|
||||||
:style="!record.kbId ? 'cursor: not-allowed; color: #999' : ''"
|
<!-- :style="!record.kbId ? 'cursor: not-allowed; color: #999' : ''"-->
|
||||||
@click="record.kbId && openDocManage(record)"
|
<!-- @click="record.kbId && openDocManage(record)"-->
|
||||||
>文档管理</a
|
<!-- >文档管理</a-->
|
||||||
>
|
<!-- >-->
|
||||||
<a-divider type="vertical" />
|
<!-- <a-divider type="vertical" />-->
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
title="确定要删除此记录吗?"
|
title="确定要删除此记录吗?"
|
||||||
@confirm="remove(record)"
|
@confirm="remove(record)"
|
||||||
|
|||||||
@@ -24,12 +24,14 @@
|
|||||||
:tabBarStyle="{ margin: 0 }"
|
:tabBarStyle="{ margin: 0 }"
|
||||||
@change="handleSourceChange"
|
@change="handleSourceChange"
|
||||||
>
|
>
|
||||||
<a-tab-pane key="company" tab="公司文档" />
|
<a-tab-pane key="company" tab="项目文档" />
|
||||||
<a-tab-pane key="public" tab="公共库" />
|
<a-tab-pane key="public" tab="公共库" />
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div class="dir-header">
|
<div class="dir-header">
|
||||||
<span>{{ activeSource === 'company' ? '公司文档目录' : '公共库目录' }}</span>
|
<span>{{
|
||||||
|
activeSource === 'company' ? '项目文档目录' : '公共库目录'
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tree-container">
|
<div class="tree-container">
|
||||||
<a-tree
|
<a-tree
|
||||||
@@ -62,7 +64,10 @@
|
|||||||
<span class="doc-tips"
|
<span class="doc-tips"
|
||||||
>当前已选择 {{ checkedDirKeys.length }} 个目录,
|
>当前已选择 {{ checkedDirKeys.length }} 个目录,
|
||||||
{{ selectedFileList.length }} 个文件;合计
|
{{ selectedFileList.length }} 个文件;合计
|
||||||
{{ mergedDirKeys.length }} 个目录,{{ mergedFileKeys.length }} 个文件</span
|
{{ mergedDirKeys.length }} 个目录,{{
|
||||||
|
mergedFileKeys.length
|
||||||
|
}}
|
||||||
|
个文件</span
|
||||||
>
|
>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button @click="clearSelection">清空当前</a-button>
|
<a-button @click="clearSelection">清空当前</a-button>
|
||||||
@@ -79,9 +84,7 @@
|
|||||||
:loading="docLoading"
|
:loading="docLoading"
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
:scroll="
|
:scroll="
|
||||||
activeSource === 'public'
|
activeSource === 'public' ? { x: 2300, y: 400 } : { y: 400 }
|
||||||
? { x: 2300, y: 400 }
|
|
||||||
: { y: 400 }
|
|
||||||
"
|
"
|
||||||
:pagination="pagination"
|
:pagination="pagination"
|
||||||
@change="handleTableChange"
|
@change="handleTableChange"
|
||||||
@@ -307,7 +310,8 @@
|
|||||||
width: 160,
|
width: 160,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: ({ record, text }: { record: AiCloudFile; text: any }) =>
|
customRender: ({ record, text }: { record: AiCloudFile; text: any }) =>
|
||||||
text || renderDocText(record, ['version', 'versionNumber', 'versionName'])
|
text ||
|
||||||
|
renderDocText(record, ['version', 'versionNumber', 'versionName'])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '成文日期',
|
title: '成文日期',
|
||||||
@@ -352,7 +356,12 @@
|
|||||||
width: 220,
|
width: 220,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
customRender: ({ record, text }: { record: AiCloudFile; text: any }) =>
|
customRender: ({ record, text }: { record: AiCloudFile; text: any }) =>
|
||||||
text || renderDocText(record, ['relatedDocuments', 'relatedDoc', 'relatedFiles'])
|
text ||
|
||||||
|
renderDocText(record, [
|
||||||
|
'relatedDocuments',
|
||||||
|
'relatedDoc',
|
||||||
|
'relatedFiles'
|
||||||
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '适用区域',
|
title: '适用区域',
|
||||||
@@ -382,7 +391,9 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
const currentDocColumns = computed(() => {
|
const currentDocColumns = computed(() => {
|
||||||
return activeSource.value === 'public' ? publicDocColumns : companyDocColumns;
|
return activeSource.value === 'public'
|
||||||
|
? publicDocColumns
|
||||||
|
: companyDocColumns;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 计算树形数据
|
// 计算树形数据
|
||||||
@@ -406,12 +417,7 @@
|
|||||||
return buildTree(0);
|
return buildTree(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectionStateMap = ref<
|
const selectionStateMap = ref<Record<string, FileSelectionStatePayload>>({});
|
||||||
Record<
|
|
||||||
string,
|
|
||||||
FileSelectionStatePayload
|
|
||||||
>
|
|
||||||
>({});
|
|
||||||
const selectedDocList = ref<string[]>([]);
|
const selectedDocList = ref<string[]>([]);
|
||||||
const selectedFileList = ref<string[]>([]);
|
const selectedFileList = ref<string[]>([]);
|
||||||
const selectedFileKeys = ref<SelectionKey[]>([]);
|
const selectedFileKeys = ref<SelectionKey[]>([]);
|
||||||
@@ -491,7 +497,8 @@
|
|||||||
sourceState.fileKeys = [...getAllSelectedFileKeys(sourceState)];
|
sourceState.fileKeys = [...getAllSelectedFileKeys(sourceState)];
|
||||||
sourceState.currentDirKey =
|
sourceState.currentDirKey =
|
||||||
selectedKeys.value[0] !== undefined ? selectedKeys.value[0] : undefined;
|
selectedKeys.value[0] !== undefined ? selectedKeys.value[0] : undefined;
|
||||||
selectionStateMap.value[getSelectionStorageKey()] = getMergedSelectionPayload();
|
selectionStateMap.value[getSelectionStorageKey()] =
|
||||||
|
getMergedSelectionPayload();
|
||||||
};
|
};
|
||||||
|
|
||||||
const restoreSelectionState = () => {
|
const restoreSelectionState = () => {
|
||||||
@@ -528,9 +535,13 @@
|
|||||||
|
|
||||||
const loadAllCloudDocs = async () => {
|
const loadAllCloudDocs = async () => {
|
||||||
try {
|
try {
|
||||||
const params = activeSource.value === 'public'
|
const params =
|
||||||
|
activeSource.value === 'public'
|
||||||
? { companyId: 0 }
|
? { companyId: 0 }
|
||||||
: { companyId: props.currentCompanyId, projectId: props.currentProjectId };
|
: {
|
||||||
|
companyId: props.currentCompanyId,
|
||||||
|
projectId: props.currentProjectId
|
||||||
|
};
|
||||||
const result = await listAiCloudDoc(params);
|
const result = await listAiCloudDoc(params);
|
||||||
allDirs.value = result || [];
|
allDirs.value = result || [];
|
||||||
|
|
||||||
@@ -541,10 +552,14 @@
|
|||||||
sourceState.dirFileSelections || {}
|
sourceState.dirFileSelections || {}
|
||||||
).find((key) => {
|
).find((key) => {
|
||||||
const dirId = Number(key);
|
const dirId = Number(key);
|
||||||
return sourceState.dirFileSelections[key]?.length > 0 && availableIds.has(dirId);
|
return (
|
||||||
|
sourceState.dirFileSelections[key]?.length > 0 &&
|
||||||
|
availableIds.has(dirId)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
const preferredSelectedKey =
|
const preferredSelectedKey =
|
||||||
(selectedKeys.value[0] && availableIds.has(selectedKeys.value[0] as number)
|
(selectedKeys.value[0] &&
|
||||||
|
availableIds.has(selectedKeys.value[0] as number)
|
||||||
? selectedKeys.value[0]
|
? selectedKeys.value[0]
|
||||||
: undefined) ||
|
: undefined) ||
|
||||||
(sourceState.currentDirKey !== undefined &&
|
(sourceState.currentDirKey !== undefined &&
|
||||||
@@ -640,7 +655,9 @@
|
|||||||
addedKeys.map((key) => getDirFileKeys(key))
|
addedKeys.map((key) => getDirFileKeys(key))
|
||||||
);
|
);
|
||||||
addedKeys.forEach((key, index) => {
|
addedKeys.forEach((key, index) => {
|
||||||
sourceState.dirFileSelections[String(key)] = [...addedFileGroups[index]];
|
sourceState.dirFileSelections[String(key)] = [
|
||||||
|
...addedFileGroups[index]
|
||||||
|
];
|
||||||
});
|
});
|
||||||
removedKeys.forEach((key) => {
|
removedKeys.forEach((key) => {
|
||||||
delete sourceState.dirFileSelections[String(key)];
|
delete sourceState.dirFileSelections[String(key)];
|
||||||
@@ -679,9 +696,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 文件选择变化
|
// 文件选择变化
|
||||||
const onFileSelectionChange = (
|
const onFileSelectionChange = (selectedRowKeys: SelectionKey[]) => {
|
||||||
selectedRowKeys: SelectionKey[]
|
|
||||||
) => {
|
|
||||||
const currentDirKey = getCurrentDirKey();
|
const currentDirKey = getCurrentDirKey();
|
||||||
if (!currentDirKey) return;
|
if (!currentDirKey) return;
|
||||||
|
|
||||||
@@ -689,9 +704,7 @@
|
|||||||
sourceState.dirFileSelections[currentDirKey] = [...selectedRowKeys];
|
sourceState.dirFileSelections[currentDirKey] = [...selectedRowKeys];
|
||||||
sourceState.fileKeys = getAllSelectedFileKeys(sourceState);
|
sourceState.fileKeys = getAllSelectedFileKeys(sourceState);
|
||||||
selectedFileKeys.value = selectedRowKeys;
|
selectedFileKeys.value = selectedRowKeys;
|
||||||
selectedFileList.value = sourceState.fileKeys.map((key) =>
|
selectedFileList.value = sourceState.fileKeys.map((key) => key.toString());
|
||||||
key.toString()
|
|
||||||
);
|
|
||||||
saveSelectionState();
|
saveSelectionState();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -766,5 +779,4 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -268,11 +268,7 @@
|
|||||||
>
|
>
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'fileName'">
|
<template v-if="column.key === 'fileName'">
|
||||||
<a
|
<a @click="openDocPreview(record)">{{ record.fileName }}</a>
|
||||||
:href="`http://view.officeapps.live.com/op/view.aspx?src=${record.fileUrl}`"
|
|
||||||
target="_blank"
|
|
||||||
>{{ record.fileName }}</a
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'action'">
|
<template v-if="column.key === 'action'">
|
||||||
<a-space>
|
<a-space>
|
||||||
@@ -629,6 +625,56 @@
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDocFileUrl = (record: AiCloudFile) => {
|
||||||
|
const value = getDocFieldValue(
|
||||||
|
record,
|
||||||
|
['fileUrl', 'downloadUrl', 'url'],
|
||||||
|
''
|
||||||
|
);
|
||||||
|
return value === '-' ? '' : String(value).trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDocFileExt = (record: AiCloudFile) => {
|
||||||
|
const candidates = [
|
||||||
|
record.fileExt,
|
||||||
|
record.fileType,
|
||||||
|
record.fileName,
|
||||||
|
getDocFileUrl(record)
|
||||||
|
].filter(Boolean) as string[];
|
||||||
|
|
||||||
|
for (const item of candidates) {
|
||||||
|
const cleanValue = item.split('?')[0];
|
||||||
|
const ext = cleanValue.includes('.')
|
||||||
|
? cleanValue.split('.').pop()
|
||||||
|
: cleanValue;
|
||||||
|
if (ext) {
|
||||||
|
return ext.toLowerCase().replace(/^\./, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const openDocPreview = (record: AiCloudFile) => {
|
||||||
|
const fileUrl = getDocFileUrl(record);
|
||||||
|
if (!fileUrl) {
|
||||||
|
message.warning('该文件暂无可预览地址');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext = getDocFileExt(record);
|
||||||
|
const officePreviewExts = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'];
|
||||||
|
const previewUrl =
|
||||||
|
ext === 'pdf'
|
||||||
|
? fileUrl
|
||||||
|
: officePreviewExts.includes(ext)
|
||||||
|
? `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(
|
||||||
|
fileUrl
|
||||||
|
)}`
|
||||||
|
: fileUrl;
|
||||||
|
|
||||||
|
window.open(previewUrl, '_blank', 'noopener,noreferrer');
|
||||||
|
};
|
||||||
|
|
||||||
const resetDocSelection = () => {
|
const resetDocSelection = () => {
|
||||||
selectedDocRowKeys.value = [];
|
selectedDocRowKeys.value = [];
|
||||||
selectedDocRows.value = [];
|
selectedDocRows.value = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user