知识库以及文件重命名、移动、删除

This commit is contained in:
1025859868@qq.com
2024-06-07 13:49:49 +08:00
parent 2e6312e84f
commit 8af9a4cb61
6 changed files with 228 additions and 57 deletions

View File

@@ -167,6 +167,14 @@ export async function updateFileLib(data) {
return await axios.put(`/api/v1/knowledge/update`, data); return await axios.put(`/api/v1/knowledge/update`, data);
} }
/**
* 修改支持库文件
*
*/
export async function updateFile(data) {
return await axios.put(`/api/v1/knowledge/file/update`, data);
}
/** /**
* 删除支持库 * 删除支持库
* *

View File

@@ -18,7 +18,6 @@ import folderIcon from "../../../assets/knowledge/folder-icon.png";
export default function CreateModal({ createType, parentId, datalist, open, setOpen, reload }) { export default function CreateModal({ createType, parentId, datalist, open, setOpen, reload }) {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const nameRef = useRef(null) const nameRef = useRef(null)
const descRef = useRef(null) const descRef = useRef(null)
const [type, setType] = useState(createType) const [type, setType] = useState(createType)
@@ -29,12 +28,13 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
// Fetch model data // Fetch model data
useEffect(() => { useEffect(() => {
setType(createType)
getEmbeddingModel().then(res => { getEmbeddingModel().then(res => {
const models = res.models || [] const models = res.models || []
setOptions(models) setOptions(models)
setModal(models[0] || '') setModal(models[0] || '')
}) })
}, []) }, [createType])
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
@@ -63,7 +63,6 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
parent_id: parentId, parent_id: parentId,
type: type type: type
}).then(res => { }).then(res => {
// @ts-ignore
reload() reload()
setOpen(false) setOpen(false)
})) }))
@@ -177,7 +176,7 @@ export default function CreateModal({ createType, parentId, datalist, open, setO
return ( return (
<div> <div>
{ {
type == 1? <CreateFolder /> : <CreateKnowLedge /> createType == 1? <CreateFolder /> : <CreateKnowLedge />
} }
</div> </div>
); );

View File

@@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {useContext, useEffect, useRef, useState} from "react"; import {useContext, useEffect, useRef, useState} from "react";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
import {readFileLibDatabase, updateFileLib} from "../../../controllers/API"; import {readFileLibDatabase, updateFile, updateFileLib} from "../../../controllers/API";
import {alertContext} from "../../../contexts/alertContext"; import {alertContext} from "../../../contexts/alertContext";
import {captureAndAlertRequestErrorHoc} from "../../../controllers/request"; import {captureAndAlertRequestErrorHoc} from "../../../controllers/request";
import { import {
@@ -14,32 +14,58 @@ import {useTable} from "../../../util/hook";
import moveIcon from "../../../assets/knowledge/move-icon.png"; import moveIcon from "../../../assets/knowledge/move-icon.png";
import folderIcon from "../../../assets/knowledge/folder-icon.png"; import folderIcon from "../../../assets/knowledge/folder-icon.png";
import noFolderIcon from "../../../assets/knowledge/no-folder-icon.png"; import noFolderIcon from "../../../assets/knowledge/no-folder-icon.png";
import knowledgeIcon from "@/assets/knowledge/knowledge-icon.png";
export default function MoveModal({ data, open, setOpen, reload }) { export default function MoveModal({ data, open, setOpen, reload }) {
if(!open) return null
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const [parentId, setParentId] = useState("") const [parentId, setParentId] = useState("")
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const [error, setError] = useState({ name: false }) const [error, setError] = useState({ name: false })
const [datalist, setDatalist] = useState([])
useEffect(() => {
readFileLibDatabase(1, 10000, "", data.nameType == "file" ? data.knowledge_id : data.parent_id, '1').then(res => {
const list = res.data || []
const array = []
list.forEach((item) => {
if(item.id != data.id){
array.push(item)
}
})
setDatalist(array)
})
}, [])
const handleMove = () => { const handleMove = () => {
const errorlist = [] const errorlist = []
if (!parentId) errorlist.push(t('lib.selectFold')) if (!parentId) errorlist.push(t('lib.selectFold'))
if (errorlist.length) return handleError(errorlist) if (errorlist.length) return handleError(errorlist)
captureAndAlertRequestErrorHoc(updateFileLib({ if(data.nameType == "file"){
id: data.id, captureAndAlertRequestErrorHoc(updateFile({
name: data.name, id: data.id,
parent_id: parentId file_name: data.file_name,
}).then(res => { knowledge_id: parentId
reload() }).then(res => {
setOpen(false) reload()
})) setOpen(false)
}))
}else{
captureAndAlertRequestErrorHoc(updateFileLib({
id: data.id,
name: data.name,
parent_id: parentId
}).then(res => {
reload()
setOpen(false)
}))
}
} }
const { page, pageSize, data: datalist, total, loading, setPage, search} = useTable({},(param) =>
readFileLibDatabase(param.page, 10000, param.keyword, '', '1')
)
const handleError = (list) => { const handleError = (list) => {
setErrorData({ setErrorData({
@@ -57,13 +83,12 @@ export default function MoveModal({ data, open, setOpen, reload }) {
datalist.length > 0 ? datalist.length > 0 ?
<div className={"folder-list third-list"}> <div className={"folder-list third-list"}>
{datalist.map((el) => ( {datalist.map((el) => (
el.id != data.id ?
<div className={parentId == el.id ? "folder-item third-item folder-item-active" : "folder-item third-item"} key={el.id}> <div className={parentId == el.id ? "folder-item third-item folder-item-active" : "folder-item third-item"} key={el.id}>
<div className={"folder-content-item"} onClick={() =>setParentId(el.id)}> <div className={"folder-content-item"} onClick={() =>setParentId(el.id)}>
<div className={"folder-header"}> <div className={"folder-header"}>
<span className={"knowledge-img-bg"}> <span className={"knowledge-img-bg"}>
<img src={folderIcon}/> <img src={folderIcon}/>
</span> </span>
<label>{el.name}</label> <label>{el.name}</label>
</div> </div>
<div className={"folder-description"}> <div className={"folder-description"}>
@@ -72,12 +97,11 @@ export default function MoveModal({ data, open, setOpen, reload }) {
<div className={"folder-type"}>{el.type == 1?t('lib.folder'):el.type == 2?t('lib.universalKnowledgeBase'):t('lib.webSite')}</div> <div className={"folder-type"}>{el.type == 1?t('lib.folder'):el.type == 2?t('lib.universalKnowledgeBase'):t('lib.webSite')}</div>
</div> </div>
</div> </div>
: ""
))} ))}
</div> </div>
: :
<div className={"no-folder"}> <div className={"no-folder"} style={{marginBottom: '50px'}}>
<img src={noFolderIcon}/> <img src={noFolderIcon} style={{marginTop: '100px'}}/>
<p>{t('lib.noFold')}</p> <p>{t('lib.noFold')}</p>
</div> </div>
} }

View File

@@ -1,7 +1,7 @@
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import {useContext, useEffect, useRef, useState} from "react"; import {useContext, useEffect, useRef, useState} from "react";
import {useNavigate} from "react-router-dom"; import {useNavigate} from "react-router-dom";
import {updateFileLib} from "../../../controllers/API"; import {updateFileLib, updateFile} from "../../../controllers/API";
import {alertContext} from "../../../contexts/alertContext"; import {alertContext} from "../../../contexts/alertContext";
import {captureAndAlertRequestErrorHoc} from "../../../controllers/request"; import {captureAndAlertRequestErrorHoc} from "../../../controllers/request";
import writeIcon from "../../../assets/knowledge/write-icon.png"; import writeIcon from "../../../assets/knowledge/write-icon.png";
@@ -9,11 +9,12 @@ import writeIcon from "../../../assets/knowledge/write-icon.png";
export default function CreateModal({ data, open, setOpen, reload }) { export default function CreateModal({ data, open, setOpen, reload }) {
const { t } = useTranslation() const { t } = useTranslation()
const navigate = useNavigate() const navigate = useNavigate()
const [nameValue, setNameValue] = useState(data.name) const name = data.nameType == "file"? data.file_name :data.name
const [nameValue, setNameValue] = useState(name)
useEffect(() => { useEffect(() => {
setNameValue(data.name); setNameValue(name)
}, [data.name]); }, [name]);
const nameRef = useRef(data.name) const nameRef = useRef(data.name)
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
@@ -28,14 +29,25 @@ export default function CreateModal({ data, open, setOpen, reload }) {
setError({ name: !!nameErrors}) setError({ name: !!nameErrors})
if (errorlist.length) return handleError(errorlist) if (errorlist.length) return handleError(errorlist)
captureAndAlertRequestErrorHoc(updateFileLib({ if(data.nameType == "file"){
id: data.id, captureAndAlertRequestErrorHoc(updateFile({
name: name, id: data.id,
parent_id: data.parent_id file_name: name,
}).then(res => { knowledge_id: data.knowledge_id
reload() }).then(res => {
setOpen(false) reload()
})) setOpen(false)
}))
}else{
captureAndAlertRequestErrorHoc(updateFileLib({
id: data.id,
name: name,
parent_id: data.parent_id
}).then(res => {
reload()
setOpen(false)
}))
}
} }
const handleError = (list) => { const handleError = (list) => {

View File

@@ -34,6 +34,10 @@ export default function FileLibPage() {
readFileLibDatabase(param.page, 10000, param.keyword, parentId) readFileLibDatabase(param.page, 10000, param.keyword, parentId)
) )
useEffect(() => {
reload()
}, [])
// Delete // Delete
const { delShow, idRef, close, delConfirm } = useDelete(); const { delShow, idRef, close, delConfirm } = useDelete();
@@ -62,12 +66,12 @@ export default function FileLibPage() {
const backFolder = (parentId, index) => { const backFolder = (parentId, index) => {
setParentId(parentId) setParentId(parentId)
reload(); reload();
if(index != -1){ if(index == -1){
titleArray.splice(index) setTitleArray([])
}else if(index == (titleArray.length - 1)){ }else if(index == (titleArray.length - 1)){
return; return;
}else{ }else{
setTitleArray([]) titleArray.splice(index+1)
} }
} }
@@ -108,7 +112,7 @@ export default function FileLibPage() {
{ {
titleArray.map((title, index) => ( titleArray.map((title, index) => (
<div className={"title-item"} key={title}> <div className={"title-item"} key={title}>
<span>{index == (titleArray.length - 1)? ">" : ""}</span> <span>{index <= (titleArray.length - 1)? ">" : ""}</span>
<label onClick={()=>backFolder(title.id, index)}>{title.name}</label> <label onClick={()=>backFolder(title.id, index)}>{title.name}</label>
</div> </div>
)) ))

View File

@@ -25,7 +25,13 @@ import ShadTooltip from "../../components/ShadTooltipComponent";
import { Input } from "../../components/ui/input"; import { Input } from "../../components/ui/input";
import { Select, SelectContent, SelectGroup, SelectIconTrigger, SelectItem } from "../../components/ui/select1"; import { Select, SelectContent, SelectGroup, SelectIconTrigger, SelectItem } from "../../components/ui/select1";
import { locationContext } from "../../contexts/locationContext"; import { locationContext } from "../../contexts/locationContext";
import { deleteFile, readFileByLibDatabase, retryKnowledgeFileApi } from "../../controllers/API"; import {
deleteFile,
deleteFileLib,
readFileByLibDatabase,
readFileLibDatabase,
retryKnowledgeFileApi
} from "../../controllers/API";
import { captureAndAlertRequestErrorHoc } from "../../controllers/request"; import { captureAndAlertRequestErrorHoc } from "../../controllers/request";
import UploadModal from "../../modals/UploadModal"; import UploadModal from "../../modals/UploadModal";
import { useTable } from "../../util/hook"; import { useTable } from "../../util/hook";
@@ -50,16 +56,15 @@ export default function FilesPage() {
const nameRef = useRef(null) const nameRef = useRef(null)
const [renameOpen, setRenameOpen] = useState(false); const [renameOpen, setRenameOpen] = useState(false);
const [moveOpen, setMoveOpen] = useState(false); const [moveOpen, setMoveOpen] = useState(false);
const [parentId, setParentId] = useState('0') const [parentId, setParentId] = useState(id)
useEffect(() => {
setParentId(id)
}, [id])
const [type, setType] = useState(1) const [type, setType] = useState(1)
const [data, setData] = useState({}) const [data, setData] = useState({})
const [titleArray, setTitleArray] = useState([]);
const { page, pageSize, data: datalist, total, loading, setPage, search, reload, filterData, refreshData } = useTable({}, (param) =>
readFileByLibDatabase({ ...param, id, name: param.keyword }).then(res => {
setHasPermission(res.writeable)
return res
})
)
const detailData = { const detailData = {
img_url: "" img_url: ""
@@ -70,10 +75,28 @@ export default function FilesPage() {
// filter // filter
const [filter, setFilter] = useState(999) const [filter, setFilter] = useState(999)
const { data: libList, total: libTotal, loading: libLoading, search: libSearch, reload:libReload } = useTable({},(param) =>
readFileLibDatabase(param.page, 10000, param.keyword, parentId)
)
const { page, pageSize, data: datalist, total, loading, setPage, search, reload:fileReload, filterData, refreshData } = useTable({}, (param) =>
readFileByLibDatabase({ ...param, id: parentId, pageSize: 10000, name: param.keyword }).then(res => {
setHasPermission(res.writeable)
return res
})
)
useEffect(() => { useEffect(() => {
filterData({ status: filter }) filterData({ status: filter })
}, [filter]) }, [filter])
const reload = () => {
fileReload()
libReload()
}
useEffect(() => { useEffect(() => {
// @ts-ignore // @ts-ignore
const libname = window.libname // 临时记忆 const libname = window.libname // 临时记忆
@@ -91,13 +114,22 @@ export default function FilesPage() {
} }
// 删除 // 删除
const { delShow, idRef, close, delConfim } = useDelete() const { delShow, idRef, delType, close, delConfim } = useDelete()
const handleDelete = () => { const handleDelete = () => {
captureAndAlertRequestErrorHoc(deleteFile(idRef.current).then(res => { //知识库里面有文件和文件夹,它对应两个表
reload() if(delType == "file"){
close() captureAndAlertRequestErrorHoc(deleteFile(idRef.current).then(res => {
})) reload()
close()
}))
}else if(delType == "folder"){
captureAndAlertRequestErrorHoc(deleteFileLib(idRef.current).then(res => {
reload();
close();
}));
}
} }
const [repeatFiles, setRepeatFiles] = useState([]) const [repeatFiles, setRepeatFiles] = useState([])
@@ -141,6 +173,25 @@ export default function FilesPage() {
setFilter(Number(id)) setFilter(Number(id))
} }
const handleLibDetail = (el) => {
setParentId(el.id)
titleArray.push(el)
setTitleArray(titleArray)
reload();
}
const backFolder = (parentId, index) => {
setParentId(parentId)
reload();
if(index == -1){
setTitleArray([])
}else if(index == (titleArray.length - 1)){
return;
}else{
titleArray.splice(index+1)
}
}
return ( return (
<div className="w-full h-screen relative"> <div className="w-full h-screen relative">
{loading && <div className="absolute w-full h-full top-0 left-0 flex justify-center items-center z-10 bg-[rgba(255,255,255,0.6)] dark:bg-blur-shared"> {loading && <div className="absolute w-full h-full top-0 left-0 flex justify-center items-center z-10 bg-[rgba(255,255,255,0.6)] dark:bg-blur-shared">
@@ -158,7 +209,7 @@ export default function FilesPage() {
<img src={"/src/assets/knowledge/knowledge-icon.png"}/> <img src={"/src/assets/knowledge/knowledge-icon.png"}/>
</span> </span>
} }
<label></label> <label>{ title }</label>
</div> </div>
<div className={"folder-type"}>{t('lib.universalKnowledgeBase')}</div> <div className={"folder-type"}>{t('lib.universalKnowledgeBase')}</div>
<div className={"file-menu-active"}> <div className={"file-menu-active"}>
@@ -178,7 +229,23 @@ export default function FilesPage() {
<div className={"file-list p-6 overflow-y-auto"}> <div className={"file-list p-6 overflow-y-auto"}>
<div className={'knowledge-header'}> <div className={'knowledge-header'}>
<div className={'knowledge-title'}> <div className={'knowledge-title'}>
{t("lib.file")}6 {titleArray.length > 0?
<div className={"title-list"}>
<div className={"title-item"}>
<label onClick={()=>backFolder(id, -1)}>{t("lib.rootDirectory")}</label>
</div>
{
titleArray.map((title, index) => (
<div className={"title-item"} key={title}>
<span>{index <= (titleArray.length - 1)? ">" : ""}</span>
<label onClick={()=>backFolder(title.id, index)}>{title.name}</label>
</div>
))
}
</div>
:
<div>{t("lib.file")}{libTotal + total}</div>
}
</div> </div>
{hasPermission && {hasPermission &&
<div className={'knowledge-create-box'}> <div className={'knowledge-create-box'}>
@@ -190,7 +257,10 @@ export default function FilesPage() {
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent> <DropdownMenuContent>
<DropdownMenuItem ><img src={"/src/assets/knowledge/folder-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.folder")}</DropdownMenuItem> <DropdownMenuItem onClick={()=>{
setType(1)
setOpen(true)
}}><img src={"/src/assets/knowledge/folder-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.folder")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/write-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.manualDataset")}</DropdownMenuItem> <DropdownMenuItem ><img src={"/src/assets/knowledge/write-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.manualDataset")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/knowledge-no-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.textDataset")}</DropdownMenuItem> <DropdownMenuItem ><img src={"/src/assets/knowledge/knowledge-no-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.textDataset")}</DropdownMenuItem>
<DropdownMenuItem ><img src={"/src/assets/knowledge/table-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.tableDataset")}</DropdownMenuItem> <DropdownMenuItem ><img src={"/src/assets/knowledge/table-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.tableDataset")}</DropdownMenuItem>
@@ -237,6 +307,56 @@ export default function FilesPage() {
<span className={el.status === 3 && 'text-red-500'}>{[t('lib.parseFailed'), t('lib.parsing'), t('lib.completed'), t('lib.parseFailed')][el.status]}</span> <span className={el.status === 3 && 'text-red-500'}>{[t('lib.parseFailed'), t('lib.parsing'), t('lib.completed'), t('lib.parseFailed')][el.status]}</span>
} }
</TableCell> </TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger>
<img src={"/src/assets/chat/duihua-gengduo.png"} className={'more-button'}/>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem onClick={(event)=>{
event.stopPropagation();
// 数据集重命名
setData({ ...el, nameType: "file" })
setRenameOpen(true)
}}><img src={"/src/assets/knowledge/write-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.rename")}</DropdownMenuItem>
<DropdownMenuItem onClick={(event)=>{
event.stopPropagation();
setData({ ...el, nameType: "file" })
setMoveOpen(true)
}}><img src={"/src/assets/knowledge/move-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t("lib.move")}</DropdownMenuItem>
{hasPermission &&
<DropdownMenuItem onClick={(event) => {
event.stopPropagation();
delConfim(el.id, "file")
}}>
<img src={"/src/assets/knowledge/delete-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t('delete')}
</DropdownMenuItem>
}
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
{libList.map((el,index) => (
<TableRow key={el.id} className={"file-row"}>
<TableCell>{index + 1}</TableCell>
<TableCell onClick={ () => handleLibDetail(el) }>
<img className={"img-icon"} src={"/src/assets/knowledge/folder-icon.png"}/>
{el.name}
</TableCell>
<TableCell></TableCell>
<TableCell>{el.update_time.replace('T', ' ')}</TableCell>
<TableCell>
{el.status === 3 ? <div className="flex items-center">
<div className="tooltip" data-tip={el.remark}>
<span className='text-red-500'>{t('lib.parseFailed')}</span>
</div>
<Button variant="link"><RotateCw size={16} onClick={() => handleRetry([el])} /></Button>
</div> :
<span className={el.status === 3 && 'text-red-500'}>{[t('lib.parseFailed'), t('lib.parsing'), t('lib.completed'), t('lib.parseFailed')][el.status]}</span>
}
</TableCell>
<TableCell> <TableCell>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger> <DropdownMenuTrigger>
@@ -256,7 +376,7 @@ export default function FilesPage() {
{hasPermission && {hasPermission &&
<DropdownMenuItem onClick={(event) => { <DropdownMenuItem onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
delConfim(el.id) delConfim(el.id, "folder")
}}> }}>
<img src={"/src/assets/knowledge/delete-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t('delete')} <img src={"/src/assets/knowledge/delete-icon.png"} style={{width:'13px',height:'13px',marginRight:'8px'}}/>{t('delete')}
</DropdownMenuItem> </DropdownMenuItem>
@@ -293,16 +413,20 @@ export default function FilesPage() {
const useDelete = () => { const useDelete = () => {
const [delShow, setDelShow] = useState(false) const [delShow, setDelShow] = useState(false)
const [delType, setDelType] = useState("")
const idRef = useRef<any>(null) const idRef = useRef<any>(null)
return { return {
delShow, delShow,
idRef, idRef,
delType,
close: () => { close: () => {
setDelShow(false) setDelShow(false)
}, },
delConfim: (id) => { delConfim: (id, delType) => {
idRef.current = id idRef.current = id
setDelType(delType)
console.log(delType)
setDelShow(true) setDelShow(true)
} }
} }