|
@@ -24,7 +24,6 @@
|
|
|
:icon="h(FolderAddOutlined)"
|
|
|
style="margin-left: 15px; height: 36px"
|
|
|
@click="openNewFolderModel = true"
|
|
|
- v-if="!clickFileDetail"
|
|
|
>新建文件夹</a-button
|
|
|
>
|
|
|
<a-button
|
|
@@ -46,11 +45,11 @@
|
|
|
v-model:value="searchValue"
|
|
|
placeholder="搜索文档"
|
|
|
style="width: 280px; height: 40px"
|
|
|
- @pressEnter="getDataSource({ searchKey: searchValue })"
|
|
|
+ @pressEnter="searchHandle"
|
|
|
>
|
|
|
<template #suffix>
|
|
|
<SearchOutlined
|
|
|
- @click="getDataSource({ searchKey: searchValue })"
|
|
|
+ @click="searchHandle"
|
|
|
style=""
|
|
|
class="search-icon"
|
|
|
/>
|
|
@@ -69,23 +68,23 @@
|
|
|
:pagination="false"
|
|
|
>
|
|
|
<template #bodyCell="{ column, record }">
|
|
|
- <template v-if="column.dataIndex === 'fileName'">
|
|
|
+ <template v-if="column.dataIndex === 'name'">
|
|
|
<div class="editable-cell">
|
|
|
- <div v-if="editableData[record.key]">
|
|
|
- <a-input v-model:value="editableData[record.key].fileName" @pressEnter="save(record.key)" />
|
|
|
+ <div v-if="editableData[record.id] && !record.type">
|
|
|
+ <a-input v-model:value="editableData[record.id].name" @pressEnter="updateHandle(record.id)" />
|
|
|
</div>
|
|
|
<div v-else class="editable-cell-text-wrapper">
|
|
|
<div
|
|
|
- v-if="record.sign == 'dir'"
|
|
|
+ v-if="!record.type"
|
|
|
class="name-box"
|
|
|
@click="jumpToFile(record)"
|
|
|
>
|
|
|
- <MyIcon :icon="iconTypeName.dir" size="18" />
|
|
|
- <span>{{ record.fileName }}</span>
|
|
|
+ <MyIcon icon="icon-wjj" size="18" />
|
|
|
+ <span>{{ record.name }}</span>
|
|
|
</div>
|
|
|
<div v-else class="name-box" @click="showFileDetail(record)">
|
|
|
- <MyIcon :icon="iconTypeName[record.fileType]" size="18" />
|
|
|
- <span>{{ record.fileName }}</span>
|
|
|
+ <MyIcon icon="icon-wenjianleixing-suolvetu-PDFwendang" size="18" />
|
|
|
+ <span>{{ record.name }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -101,7 +100,7 @@
|
|
|
:icon="h(DownloadOutlined)"
|
|
|
style="margin-right: 15px"
|
|
|
@click="
|
|
|
- record.sign !== 'dir'
|
|
|
+ record.type
|
|
|
? downloadFile(record)
|
|
|
: downloadFiles([record.id])
|
|
|
"
|
|
@@ -119,7 +118,7 @@
|
|
|
type="link"
|
|
|
:icon="h(DeleteOutlined)"
|
|
|
style="color: #000"
|
|
|
- @click="moveFiles([record.id])"
|
|
|
+ @click="deleteFiles(record.id)"
|
|
|
>刪除</a-button
|
|
|
>
|
|
|
</a-menu-item>
|
|
@@ -137,16 +136,17 @@
|
|
|
type="link"
|
|
|
:icon="h(VerticalAlignTopOutlined)"
|
|
|
style="color: #000"
|
|
|
- @click="topFile(record.id)"
|
|
|
+ @click="topFileHandle(record)"
|
|
|
>置顶</a-button
|
|
|
>
|
|
|
</a-menu-item>
|
|
|
<a-menu-item>
|
|
|
<a-button
|
|
|
type="link"
|
|
|
+ v-if="!record.type"
|
|
|
:icon="h(FormOutlined)"
|
|
|
style="color: #000"
|
|
|
- @click="editFolderName(record.key)"
|
|
|
+ @click="editFolderName(record.id)"
|
|
|
>编辑</a-button
|
|
|
>
|
|
|
</a-menu-item>
|
|
@@ -158,7 +158,7 @@
|
|
|
</a-table>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <a-modal v-model:open="openNewFolderModel" title="新建分组" @ok="newFolder">
|
|
|
+ <a-modal v-model:open="openNewFolderModel" title="新建分组" @ok="createFolder">
|
|
|
<a-input
|
|
|
style="margin-top: 15px; margin-bottom: 10px"
|
|
|
v-model:value="folderName"
|
|
@@ -170,7 +170,7 @@
|
|
|
:ids="moveFileIds"
|
|
|
:closeModel="closeMoveFileModel"
|
|
|
/>
|
|
|
- <FileUpload ref="userUploadFileRef" />
|
|
|
+ <FileUpload ref="userUploadFileRef" :pid="currentTabId" @close="closeHandle"/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
@@ -180,6 +180,7 @@
|
|
|
*/
|
|
|
import { cloneDeep } from 'lodash-es';
|
|
|
import { h, ref, reactive, onMounted } from "vue";
|
|
|
+import http from "@/utils/http";
|
|
|
import {
|
|
|
FormOutlined,
|
|
|
DeleteOutlined,
|
|
@@ -194,14 +195,8 @@ import HomeHeader from '@/views/home/components/HomeHeader.vue';
|
|
|
import { message } from "ant-design-vue";
|
|
|
import MyIcon from "@/components/myIcon/index.vue";
|
|
|
import {
|
|
|
- topDocs,
|
|
|
- getDocList,
|
|
|
- deleteDocs,
|
|
|
downloadDocs,
|
|
|
- madeNewFolder,
|
|
|
- isRepeatFolder
|
|
|
} from "./http";
|
|
|
-import { columns, iconTypeName } from "./config";
|
|
|
import MoveFileModel from "./MoveFiles.vue";
|
|
|
import FileUpload from "./FileUpload.vue";
|
|
|
import FileDetail from "./FileDetail.vue";
|
|
@@ -211,69 +206,104 @@ import dayjs from "dayjs";
|
|
|
onMounted(() => {
|
|
|
getDataSource();
|
|
|
});
|
|
|
-const menuList = ref<{
|
|
|
- name: string,
|
|
|
- id: string,
|
|
|
- checked: boolean
|
|
|
-}[]>([
|
|
|
+const menuList_old = JSON.parse(localStorage.getItem("_menuList")) || [
|
|
|
{
|
|
|
name: "全部",
|
|
|
- id: '-1',
|
|
|
+ id: 0,
|
|
|
checked: true
|
|
|
}
|
|
|
-])
|
|
|
-const currentTabId = ref('-1')
|
|
|
+]
|
|
|
+const menuList = ref<{
|
|
|
+ name: string,
|
|
|
+ id: number,
|
|
|
+ checked: boolean
|
|
|
+}[]>(cloneDeep(menuList_old))
|
|
|
+const currentTabId = ref(parseInt(localStorage.getItem("_currentTabId") as string) || 0)
|
|
|
const tabClickHandle = (item) => {
|
|
|
if (currentTabId.value === item['id']) return;
|
|
|
- if (item['id'] === '-1') {
|
|
|
- menuList.value = [{
|
|
|
- name: "全部",
|
|
|
- id: '-1',
|
|
|
- checked: true
|
|
|
- }]
|
|
|
- getDataSource();
|
|
|
+ currentTabId.value = item['id']
|
|
|
+ item['checked'] = true;
|
|
|
+ if (item['id'] === 0) {
|
|
|
+ menuList.value = [item];
|
|
|
} else {
|
|
|
- getDataSource({
|
|
|
- id: item.id,
|
|
|
- });
|
|
|
+ let end = 0;
|
|
|
+ for (let i = 0; i < menuList.value.length; i++){
|
|
|
+ if (menuList.value[i].id === item.id) {
|
|
|
+ end = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ menuList.value = menuList.value.slice(0, end+1)
|
|
|
}
|
|
|
+ localStorage.setItem("_currentTabId", currentTabId.value.toString())
|
|
|
+ localStorage.setItem("_menuList", JSON.stringify(menuList.value))
|
|
|
+ getDataSource();
|
|
|
}
|
|
|
// 切换目录
|
|
|
-const changeMenu = (fileName: any = null) => {
|
|
|
+const changeMenu = (data: any = null) => {
|
|
|
// 切换目录时重置搜索内容和选中的文件
|
|
|
searchValue.value = "";
|
|
|
state.selectedRowKeys = [];
|
|
|
-
|
|
|
- if (!fileName) {
|
|
|
- // 清空选择打开的文件夹
|
|
|
- clickFileDetail.value = null;
|
|
|
- // 刷新列表
|
|
|
- getDataSource();
|
|
|
- return;
|
|
|
- }
|
|
|
menuList.value.forEach((item) => {
|
|
|
item['checked'] = false;
|
|
|
})
|
|
|
menuList.value.push({
|
|
|
- name: fileName,
|
|
|
- id: '',
|
|
|
+ name: data.name,
|
|
|
+ id: data.id,
|
|
|
checked: true,
|
|
|
})
|
|
|
+ localStorage.setItem("_currentTabId", currentTabId.value.toString())
|
|
|
+ localStorage.setItem("_menuList", JSON.stringify(menuList.value))
|
|
|
};
|
|
|
|
|
|
-// 获取数据
|
|
|
+// 表格列
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ title: "文档名称",
|
|
|
+ dataIndex: "name",
|
|
|
+ key: "name",
|
|
|
+ width: 560
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "文档类型",
|
|
|
+ dataIndex: "type",
|
|
|
+ key: "type",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "文档大小",
|
|
|
+ dataIndex: "size",
|
|
|
+ key: "size",
|
|
|
+ sorter: {
|
|
|
+ compare: (a, b) => a.size - b.size,
|
|
|
+ multiple: 2,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "创建时间",
|
|
|
+ dataIndex: "createTime",
|
|
|
+ key: "createTime",
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "操作",
|
|
|
+ key: "action",
|
|
|
+ width: 250,
|
|
|
+ align: "center",
|
|
|
+ },
|
|
|
+];
|
|
|
const searchValue = ref("");
|
|
|
const dataSource = ref<any[]>([]);
|
|
|
-const getDataSource = (params = {}) => {
|
|
|
+const getDataSource = () => {
|
|
|
// 重置选中的文件
|
|
|
state.selectedRowKeys = [];
|
|
|
+ const urlStr = `/ai/knowledge/file/list`
|
|
|
// 获取文档列表
|
|
|
- getDocList(params).then((res) => {
|
|
|
- if (res.success) {
|
|
|
- dataSource.value = res.data.map((item: any) => ({
|
|
|
- key: item.id,
|
|
|
- ...item,
|
|
|
- }));
|
|
|
+ http.get(urlStr, {
|
|
|
+ name: searchValue.value,
|
|
|
+ parentId: currentTabId.value
|
|
|
+ }).then((result) => {
|
|
|
+ if (result.data) {
|
|
|
+ dataSource.value = result.data;
|
|
|
}
|
|
|
});
|
|
|
};
|
|
@@ -289,38 +319,37 @@ const state = reactive<{
|
|
|
const onSelectChange = (selectedRowKeys: any[]) => {
|
|
|
state.selectedRowKeys = selectedRowKeys;
|
|
|
};
|
|
|
-
|
|
|
+const searchHandle = () => {
|
|
|
+ getDataSource()
|
|
|
+}
|
|
|
// 点击进入文件夹
|
|
|
const clickFileDetail = ref<null | any>(null);
|
|
|
const jumpToFile = (data: any) => {
|
|
|
clickFileDetail.value = data;
|
|
|
currentTabId.value = data.id;
|
|
|
// 触发目录切换的回调
|
|
|
- changeMenu(data.fileName);
|
|
|
- getDataSource({
|
|
|
- id: data.id,
|
|
|
- });
|
|
|
+ changeMenu(data);
|
|
|
+ getDataSource();
|
|
|
};
|
|
|
|
|
|
// 新建文件夹
|
|
|
-const openNewFolderModel = ref(false);
|
|
|
const folderName = ref("");
|
|
|
-const newFolder = async () => {
|
|
|
- const res = await isRepeatFolder(folderName.value);
|
|
|
- if (!res.success) {
|
|
|
- message.info("文件夹名称重复,请重新输入!");
|
|
|
- return false;
|
|
|
- }
|
|
|
- const res2 = await madeNewFolder(folderName.value);
|
|
|
- if (res2.success) {
|
|
|
- message.success("文件夹新建成功!");
|
|
|
- folderName.value = "";
|
|
|
- // 刷新列表
|
|
|
- getDataSource();
|
|
|
- openNewFolderModel.value = false;
|
|
|
- } else {
|
|
|
- message.error("新建文件夹失败,请稍后重试!");
|
|
|
- }
|
|
|
+const openNewFolderModel = ref(false);
|
|
|
+const createFolder = async () => {
|
|
|
+ const urlStr = '/ai/knowledge/file/create'
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append("name", folderName.value)
|
|
|
+ formData.append("parentId", currentTabId.value.toString());
|
|
|
+ http.post(urlStr, formData).then((result) => {
|
|
|
+ if (result.data) {
|
|
|
+ message.success("文件夹新建成功!");
|
|
|
+ getDataSource(currentTabId.value);
|
|
|
+ folderName.value = "";
|
|
|
+ openNewFolderModel.value = false;
|
|
|
+ } else {
|
|
|
+ message.error("新建文件夹失败,请稍后重试!");
|
|
|
+ }
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
// 下载(单文件下载)
|
|
@@ -345,6 +374,9 @@ const downloadFile = async (data: any) => {
|
|
|
// 上传文档
|
|
|
const userUploadFileRef = ref<any>(null);
|
|
|
const uploadFiles = () => userUploadFileRef.value.showModal();
|
|
|
+const closeHandle = () => {
|
|
|
+ getDataSource();
|
|
|
+}
|
|
|
// 多文件打包下载
|
|
|
const downloadFiles = async (ids: any[] = []) => {
|
|
|
message.success("正在为你下载文件,请稍等 ...");
|
|
@@ -354,19 +386,53 @@ const downloadFiles = async (ids: any[] = []) => {
|
|
|
message.error("下载失败,请稍后重试!");
|
|
|
}
|
|
|
};
|
|
|
+//文件夹编辑
|
|
|
const editableData = reactive({});
|
|
|
-const save = (key: string) => {
|
|
|
- const item = dataSource.value.filter(item => key === item.key)[0];
|
|
|
- Object.assign(item, editableData[key]);
|
|
|
- delete editableData[key];
|
|
|
-};
|
|
|
-//编辑文件夹名称
|
|
|
-const editFolderName = (key) => {
|
|
|
- editableData[key] = cloneDeep(dataSource.value.filter(item => key === item.key)[0]);
|
|
|
+const editFolderName = (id) => {
|
|
|
+ editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
|
|
|
}
|
|
|
+const updateHandle = (id: string) => {
|
|
|
+ const item = dataSource.value.filter(item => id === item.id)[0];
|
|
|
+ Object.assign(item, editableData[id]);
|
|
|
+ const urlStr = `/ai/knowledge/file/update`
|
|
|
+ const sendData = {
|
|
|
+ ...item
|
|
|
+ }
|
|
|
+ http.post(urlStr, sendData).then((result) => {
|
|
|
+ if (result.data) {
|
|
|
+ message.success("重命名成功!");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ delete editableData[id];
|
|
|
+};
|
|
|
+
|
|
|
+// 置顶
|
|
|
+const topFileHandle = async (item) => {
|
|
|
+ const urlStr = `/ai/knowledge/file/update`
|
|
|
+ const sendData = {
|
|
|
+ ...item
|
|
|
+ }
|
|
|
+ sendData['sort'] = 0
|
|
|
+ http.post(urlStr, sendData).then((result) => {
|
|
|
+ if (result.data) {
|
|
|
+ message.success("置顶成功!");
|
|
|
+ getDataSource();
|
|
|
+ } else {
|
|
|
+ message.error("置顶失败,请稍后重试!");
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
//刪除
|
|
|
-const deleteFiles = () => {
|
|
|
-
|
|
|
+const deleteFiles = (id) => {
|
|
|
+ const urlStr = `/ai/knowledge/file/delete?id=${id}`
|
|
|
+ http.get(urlStr).then((result) => {
|
|
|
+ if (result.data) {
|
|
|
+ message.success("删除成功!");
|
|
|
+ getDataSource();
|
|
|
+ } else {
|
|
|
+ message.error("删除失败,请稍后重试!");
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
// 移动:最外层文件禁止多选移动,文件夹类型禁止移动
|
|
|
const moveFileModel = ref(false);
|
|
@@ -384,9 +450,7 @@ const closeMoveFileModel = () => {
|
|
|
const refreshList = () => {
|
|
|
if (clickFileDetail.value) {
|
|
|
// 关闭弹窗后刷新列表
|
|
|
- getDataSource({
|
|
|
- id: clickFileDetail.value.id,
|
|
|
- });
|
|
|
+ getDataSource();
|
|
|
// 刷新目录
|
|
|
changeMenu(clickFileDetail.value.fileName);
|
|
|
} else {
|
|
@@ -397,18 +461,6 @@ const refreshList = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 置顶
|
|
|
-const topFile = async (id: string) => {
|
|
|
- const res = await topDocs(id);
|
|
|
- if (res.success) {
|
|
|
- message.success("置顶成功!");
|
|
|
- // 刷新列表
|
|
|
- refreshList();
|
|
|
- } else {
|
|
|
- message.error("置顶失败,请稍后重试!");
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
// 跳到文件详情页面
|
|
|
const showFileDetail = (data: any) => {
|
|
|
clickFileDetail.value = {
|