feat: select dataset
This commit is contained in:
parent
ce47c96b9f
commit
b40561ad37
@ -23,6 +23,7 @@ import { QuoteItemType } from '@/types/chat';
|
|||||||
/* knowledge base */
|
/* knowledge base */
|
||||||
export const getKbList = (parentId?: string) =>
|
export const getKbList = (parentId?: string) =>
|
||||||
GET<KbListItemType[]>(`/plugins/kb/list`, { parentId });
|
GET<KbListItemType[]>(`/plugins/kb/list`, { parentId });
|
||||||
|
export const getAllDataset = () => GET<KbListItemType[]>(`/plugins/kb/allDataset`);
|
||||||
|
|
||||||
export const getKbPaths = (parentId?: string) =>
|
export const getKbPaths = (parentId?: string) =>
|
||||||
GET<KbPathItemType[]>('/plugins/kb/paths', { parentId });
|
GET<KbPathItemType[]>('/plugins/kb/paths', { parentId });
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import {
|
|||||||
import MyModal from '../MyModal';
|
import MyModal from '../MyModal';
|
||||||
import { useTranslation } from 'next-i18next';
|
import { useTranslation } from 'next-i18next';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import Avatar from '../Avatar';
|
import Avatar from '../Avatar';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
@ -29,7 +29,7 @@ const SelectDataset = ({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { myKbList, loadKbList } = useUserStore();
|
const { myKbList, loadKbList } = useDatasetStore();
|
||||||
const [selectedId, setSelectedId] = useState<string>();
|
const [selectedId, setSelectedId] = useState<string>();
|
||||||
|
|
||||||
useQuery(['loadKbList'], () => loadKbList());
|
useQuery(['loadKbList'], () => loadKbList());
|
||||||
|
|||||||
34
client/src/pages/api/plugins/kb/allDataset.ts
Normal file
34
client/src/pages/api/plugins/kb/allDataset.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@/service/response';
|
||||||
|
import { connectToDatabase, KB } from '@/service/mongo';
|
||||||
|
import { authUser } from '@/service/utils/auth';
|
||||||
|
import { getVectorModel } from '@/service/utils/data';
|
||||||
|
import { KbListItemType } from '@/types/plugin';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
// 凭证校验
|
||||||
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
|
||||||
|
await connectToDatabase();
|
||||||
|
|
||||||
|
const kbList = await KB.find({
|
||||||
|
userId,
|
||||||
|
type: 'dataset'
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = kbList.map((item) => ({
|
||||||
|
...item.toJSON(),
|
||||||
|
vectorModel: getVectorModel(item.vectorModel)
|
||||||
|
}));
|
||||||
|
|
||||||
|
jsonRes<KbListItemType[]>(res, {
|
||||||
|
data
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error: err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
|
|||||||
import { NodeProps } from 'reactflow';
|
import { NodeProps } from 'reactflow';
|
||||||
import { FlowModuleItemType } from '@/types/flow';
|
import { FlowModuleItemType } from '@/types/flow';
|
||||||
import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react';
|
import { Flex, Box, Button, useTheme, useDisclosure, Grid } from '@chakra-ui/react';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import NodeCard from '../modules/NodeCard';
|
import NodeCard from '../modules/NodeCard';
|
||||||
import Divider from '../modules/Divider';
|
import Divider from '../modules/Divider';
|
||||||
@ -21,7 +21,7 @@ const KBSelect = ({
|
|||||||
onChange: (e: SelectedKbType) => void;
|
onChange: (e: SelectedKbType) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { myKbList, loadKbList } = useUserStore();
|
const { datasets, loadAllDatasets } = useDatasetStore();
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenKbSelect,
|
isOpen: isOpenKbSelect,
|
||||||
onOpen: onOpenKbSelect,
|
onOpen: onOpenKbSelect,
|
||||||
@ -29,11 +29,11 @@ const KBSelect = ({
|
|||||||
} = useDisclosure();
|
} = useDisclosure();
|
||||||
|
|
||||||
const showKbList = useMemo(
|
const showKbList = useMemo(
|
||||||
() => myKbList.filter((item) => activeKbs.find((kb) => kb.kbId === item._id)),
|
() => datasets.filter((item) => activeKbs.find((kb) => kb.kbId === item._id)),
|
||||||
[myKbList, activeKbs]
|
[datasets, activeKbs]
|
||||||
);
|
);
|
||||||
|
|
||||||
useQuery(['initkb'], () => loadKbList());
|
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -58,12 +58,7 @@ const KBSelect = ({
|
|||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
{isOpenKbSelect && (
|
{isOpenKbSelect && (
|
||||||
<KBSelectModal
|
<KBSelectModal activeKbs={activeKbs} onChange={onChange} onClose={onCloseKbSelect} />
|
||||||
kbList={myKbList}
|
|
||||||
activeKbs={activeKbs}
|
|
||||||
onChange={onChange}
|
|
||||||
onClose={onCloseKbSelect}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -56,18 +56,21 @@ import MyIcon from '@/components/Icon';
|
|||||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||||
|
|
||||||
import { addVariable } from '../VariableEditModal';
|
import { addVariable } from '../VariableEditModal';
|
||||||
import { KBSelectModal, KbParamsModal } from '../KBSelectModal';
|
import { KbParamsModal } from '../KBSelectModal';
|
||||||
import { AppTypeEnum } from '@/constants/app';
|
import { AppTypeEnum } from '@/constants/app';
|
||||||
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const VariableEditModal = dynamic(() => import('../VariableEditModal'));
|
const VariableEditModal = dynamic(() => import('../VariableEditModal'));
|
||||||
const InfoModal = dynamic(() => import('../InfoModal'));
|
const InfoModal = dynamic(() => import('../InfoModal'));
|
||||||
|
const KBSelectModal = dynamic(() => import('../KBSelectModal'));
|
||||||
|
|
||||||
const Settings = ({ appId }: { appId: string }) => {
|
const Settings = ({ appId }: { appId: string }) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { appDetail, updateAppDetail, loadKbList, myKbList } = useUserStore();
|
const { appDetail, updateAppDetail } = useUserStore();
|
||||||
|
const { loadAllDatasets, datasets } = useDatasetStore();
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
|
|
||||||
const [editVariable, setEditVariable] = useState<VariableItemType>();
|
const [editVariable, setEditVariable] = useState<VariableItemType>();
|
||||||
@ -122,8 +125,8 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
);
|
);
|
||||||
}, [getValues, refresh]);
|
}, [getValues, refresh]);
|
||||||
const selectedKbList = useMemo(
|
const selectedKbList = useMemo(
|
||||||
() => myKbList.filter((item) => kbList.find((kb) => kb.kbId === item._id)),
|
() => datasets.filter((item) => kbList.find((kb) => kb.kbId === item._id)),
|
||||||
[myKbList, kbList]
|
[datasets, kbList]
|
||||||
);
|
);
|
||||||
|
|
||||||
/* 点击删除 */
|
/* 点击删除 */
|
||||||
@ -167,7 +170,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
appModule2Form();
|
appModule2Form();
|
||||||
}, [appModule2Form]);
|
}, [appModule2Form]);
|
||||||
|
|
||||||
useQuery(['initkb', appId], () => loadKbList());
|
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||||
|
|
||||||
const BoxStyles: BoxProps = {
|
const BoxStyles: BoxProps = {
|
||||||
bg: 'myWhite.200',
|
bg: 'myWhite.200',
|
||||||
@ -304,6 +307,23 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
{/* welcome */}
|
||||||
|
<Box mt={5} {...BoxStyles}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Avatar src={'/imgs/module/userGuide.png'} w={'18px'} />
|
||||||
|
<Box mx={2}>对话开场白</Box>
|
||||||
|
<MyTooltip label={welcomeTextTip} forceShow>
|
||||||
|
<QuestionOutlineIcon />
|
||||||
|
</MyTooltip>
|
||||||
|
</Flex>
|
||||||
|
<Textarea
|
||||||
|
mt={2}
|
||||||
|
rows={5}
|
||||||
|
placeholder={welcomeTextTip}
|
||||||
|
borderColor={'myGray.100'}
|
||||||
|
{...register('guide.welcome.text')}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
{/* variable */}
|
{/* variable */}
|
||||||
<Box mt={2} {...BoxStyles}>
|
<Box mt={2} {...BoxStyles}>
|
||||||
<Flex alignItems={'center'}>
|
<Flex alignItems={'center'}>
|
||||||
@ -498,24 +518,6 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* welcome */}
|
|
||||||
<Box mt={5} {...BoxStyles}>
|
|
||||||
<Flex alignItems={'center'}>
|
|
||||||
<Avatar src={'/imgs/module/userGuide.png'} w={'18px'} />
|
|
||||||
<Box mx={2}>对话开场白</Box>
|
|
||||||
<MyTooltip label={welcomeTextTip} forceShow>
|
|
||||||
<QuestionOutlineIcon />
|
|
||||||
</MyTooltip>
|
|
||||||
</Flex>
|
|
||||||
<Textarea
|
|
||||||
mt={2}
|
|
||||||
rows={5}
|
|
||||||
placeholder={welcomeTextTip}
|
|
||||||
borderColor={'myGray.100'}
|
|
||||||
{...register('guide.welcome.text')}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
|
|
||||||
<ConfirmSaveModal />
|
<ConfirmSaveModal />
|
||||||
<ConfirmDelModal />
|
<ConfirmDelModal />
|
||||||
{settingAppInfo && (
|
{settingAppInfo && (
|
||||||
@ -548,7 +550,6 @@ const Settings = ({ appId }: { appId: string }) => {
|
|||||||
)}
|
)}
|
||||||
{isOpenKbSelect && (
|
{isOpenKbSelect && (
|
||||||
<KBSelectModal
|
<KBSelectModal
|
||||||
kbList={myKbList}
|
|
||||||
activeKbs={selectedKbList.map((item) => ({
|
activeKbs={selectedKbList.map((item) => ({
|
||||||
kbId: item._id,
|
kbId: item._id,
|
||||||
vectorModel: item.vectorModel
|
vectorModel: item.vectorModel
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
Flex,
|
Flex,
|
||||||
@ -8,18 +8,25 @@ import {
|
|||||||
ModalHeader,
|
ModalHeader,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
useTheme,
|
useTheme,
|
||||||
Textarea
|
Textarea,
|
||||||
|
Grid,
|
||||||
|
Divider
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
import { getKbPaths } from '@/api/plugins/kb';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import type { KbListItemType, SelectedKbType } from '@/types/plugin';
|
import type { SelectedKbType } from '@/types/plugin';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import MySlider from '@/components/Slider';
|
import MySlider from '@/components/Slider';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
|
import { KbTypeEnum } from '@/constants/kb';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
export type KbParamsType = {
|
export type KbParamsType = {
|
||||||
searchSimilarity: number;
|
searchSimilarity: number;
|
||||||
@ -28,20 +35,42 @@ export type KbParamsType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const KBSelectModal = ({
|
export const KBSelectModal = ({
|
||||||
kbList,
|
|
||||||
activeKbs = [],
|
activeKbs = [],
|
||||||
onChange,
|
onChange,
|
||||||
onClose
|
onClose
|
||||||
}: {
|
}: {
|
||||||
kbList: KbListItemType[];
|
|
||||||
activeKbs: SelectedKbType;
|
activeKbs: SelectedKbType;
|
||||||
onChange: (e: SelectedKbType) => void;
|
onChange: (e: SelectedKbType) => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [selectedKbList, setSelectedKbList] = useState<SelectedKbType>(activeKbs);
|
const [selectedKbList, setSelectedKbList] = useState<SelectedKbType>(activeKbs);
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const [parentId, setParentId] = useState<string>();
|
||||||
|
const { myKbList, loadKbList, datasets, loadAllDatasets } = useDatasetStore();
|
||||||
|
|
||||||
|
const { data } = useQuery(['loadKbList', parentId], () => {
|
||||||
|
return Promise.all([loadKbList(parentId), getKbPaths(parentId)]);
|
||||||
|
});
|
||||||
|
useQuery(['loadAllDatasets'], loadAllDatasets);
|
||||||
|
const paths = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
parentId: '',
|
||||||
|
parentName: t('kb.My Dataset')
|
||||||
|
},
|
||||||
|
...(data?.[1] || [])
|
||||||
|
],
|
||||||
|
[data, t]
|
||||||
|
);
|
||||||
|
const filterKbList = useMemo(() => {
|
||||||
|
return {
|
||||||
|
selected: datasets.filter((item) => selectedKbList.find((kb) => kb.kbId === item._id)),
|
||||||
|
unSelected: myKbList.filter((item) => !selectedKbList.find((kb) => kb.kbId === item._id))
|
||||||
|
};
|
||||||
|
}, [myKbList, datasets, selectedKbList]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MyModal
|
<MyModal
|
||||||
@ -53,10 +82,43 @@ export const KBSelectModal = ({
|
|||||||
>
|
>
|
||||||
<Flex flexDirection={'column'} h={['90vh', 'auto']}>
|
<Flex flexDirection={'column'} h={['90vh', 'auto']}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<Box>关联的知识库({selectedKbList.length})</Box>
|
{!!parentId ? (
|
||||||
<Box fontSize={'sm'} color={'myGray.500'} fontWeight={'normal'}>
|
<Flex flex={1}>
|
||||||
仅能选择同一个索引模型的知识库
|
{paths.map((item, i) => (
|
||||||
</Box>
|
<Flex key={item.parentId} mr={2} alignItems={'center'}>
|
||||||
|
<Box
|
||||||
|
fontSize={'lg'}
|
||||||
|
borderRadius={'md'}
|
||||||
|
{...(i === paths.length - 1
|
||||||
|
? {
|
||||||
|
cursor: 'default'
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
cursor: 'pointer',
|
||||||
|
_hover: {
|
||||||
|
color: 'myBlue.600'
|
||||||
|
},
|
||||||
|
onClick: () => {
|
||||||
|
setParentId(item.parentId);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{item.parentName}
|
||||||
|
</Box>
|
||||||
|
{i !== paths.length - 1 && (
|
||||||
|
<MyIcon name={'rightArrowLight'} color={'myGray.500'} />
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
) : (
|
||||||
|
<Box>关联的知识库({selectedKbList.length})</Box>
|
||||||
|
)}
|
||||||
|
{isPc && (
|
||||||
|
<Box fontSize={'sm'} color={'myGray.500'} fontWeight={'normal'}>
|
||||||
|
仅能选择同一个索引模型的知识库
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody
|
<ModalBody
|
||||||
@ -64,72 +126,119 @@ export const KBSelectModal = ({
|
|||||||
maxH={'80vh'}
|
maxH={'80vh'}
|
||||||
overflowY={'auto'}
|
overflowY={'auto'}
|
||||||
display={'grid'}
|
display={'grid'}
|
||||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
|
|
||||||
gridGap={3}
|
|
||||||
userSelect={'none'}
|
userSelect={'none'}
|
||||||
>
|
>
|
||||||
{kbList.map((item) =>
|
<Grid
|
||||||
(() => {
|
h={'auto'}
|
||||||
const selected = !!selectedKbList.find((kb) => kb.kbId === item._id);
|
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
|
||||||
const active = !!activeKbs.find((kb) => kb.kbId === item._id);
|
gridGap={3}
|
||||||
return (
|
>
|
||||||
<Card
|
{filterKbList.selected.map((item) =>
|
||||||
key={item._id}
|
(() => {
|
||||||
p={3}
|
return (
|
||||||
border={theme.borders.base}
|
<Card
|
||||||
boxShadow={'sm'}
|
key={item._id}
|
||||||
h={'80px'}
|
p={3}
|
||||||
cursor={'pointer'}
|
border={theme.borders.base}
|
||||||
order={active ? 0 : 1}
|
boxShadow={'sm'}
|
||||||
_hover={{
|
bg={'myBlue.300'}
|
||||||
boxShadow: 'md'
|
>
|
||||||
}}
|
<Flex alignItems={'center'} h={'38px'}>
|
||||||
{...(selected
|
<Avatar src={item.avatar} w={['24px', '28px']}></Avatar>
|
||||||
? {
|
<Box flex={'1 0 0'} mx={3}>
|
||||||
bg: 'myBlue.300'
|
{item.name}
|
||||||
}
|
</Box>
|
||||||
: {})}
|
<MyIcon
|
||||||
onClick={() => {
|
name={'delete'}
|
||||||
if (selected) {
|
w={'14px'}
|
||||||
setSelectedKbList((state) => state.filter((kb) => kb.kbId !== item._id));
|
cursor={'pointer'}
|
||||||
} else {
|
_hover={{ color: 'red.500' }}
|
||||||
const vectorModel = selectedKbList[0]?.vectorModel?.model;
|
onClick={() => {
|
||||||
|
setSelectedKbList((state) => state.filter((kb) => kb.kbId !== item._id));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
{filterKbList.selected.length > 0 && <Divider my={3} />}
|
||||||
return toast({
|
|
||||||
status: 'warning',
|
<Grid
|
||||||
title: '仅能选择同一个索引模型的知识库'
|
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)', 'repeat(3,1fr)']}
|
||||||
});
|
gridGap={3}
|
||||||
|
>
|
||||||
|
{filterKbList.unSelected.map((item) =>
|
||||||
|
(() => {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
key={item._id}
|
||||||
|
p={3}
|
||||||
|
border={theme.borders.base}
|
||||||
|
boxShadow={'sm'}
|
||||||
|
h={'80px'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
_hover={{
|
||||||
|
boxShadow: 'md'
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
if (item.type === KbTypeEnum.folder) {
|
||||||
|
setParentId(item._id);
|
||||||
|
} else if (item.type === KbTypeEnum.dataset) {
|
||||||
|
const vectorModel = selectedKbList[0]?.vectorModel?.model;
|
||||||
|
|
||||||
|
if (vectorModel && vectorModel !== item.vectorModel.model) {
|
||||||
|
return toast({
|
||||||
|
status: 'warning',
|
||||||
|
title: '仅能选择同一个索引模型的知识库'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setSelectedKbList((state) => [
|
||||||
|
...state,
|
||||||
|
{ kbId: item._id, vectorModel: item.vectorModel }
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
setSelectedKbList((state) => [
|
}}
|
||||||
...state,
|
>
|
||||||
{ kbId: item._id, vectorModel: item.vectorModel }
|
<Flex alignItems={'center'} h={'38px'}>
|
||||||
]);
|
<Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar>
|
||||||
}
|
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
|
||||||
}}
|
{item.name}
|
||||||
>
|
</Box>
|
||||||
<Flex alignItems={'center'} h={'38px'}>
|
</Flex>
|
||||||
<Avatar src={item.avatar} w={['24px', '28px', '32px']}></Avatar>
|
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
|
||||||
<Box ml={3} fontWeight={'bold'} fontSize={['md', 'lg', 'xl']}>
|
{item.type === KbTypeEnum.folder ? (
|
||||||
{item.name}
|
<Box color={'myGray.500'}>{t('Folder')}</Box>
|
||||||
</Box>
|
) : (
|
||||||
</Flex>
|
<>
|
||||||
<Flex justifyContent={'flex-end'} alignItems={'center'} fontSize={'sm'}>
|
<MyIcon mr={1} name="kbTest" w={'12px'} />
|
||||||
<MyIcon mr={1} name="kbTest" w={'12px'} />
|
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
|
||||||
<Box color={'myGray.500'}>{item.vectorModel.name}</Box>
|
</>
|
||||||
</Flex>
|
)}
|
||||||
</Card>
|
</Flex>
|
||||||
);
|
</Card>
|
||||||
})()
|
);
|
||||||
|
})()
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
{filterKbList.unSelected.length === 0 && (
|
||||||
|
<Flex mt={5} flexDirection={'column'} alignItems={'center'}>
|
||||||
|
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||||
|
<Box mt={2} color={'myGray.500'}>
|
||||||
|
这个目录已经没东西可选了~
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// filter out the kb that is not in the kbList
|
// filter out the kb that is not in the kList
|
||||||
const filterKbList = selectedKbList.filter((kb) => {
|
const filterKbList = selectedKbList.filter((kb) => {
|
||||||
return kbList.find((item) => item._id === kb.kbId);
|
return datasets.find((item) => item._id === kb.kbId);
|
||||||
});
|
});
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
|
|||||||
@ -26,12 +26,12 @@ import MyTooltip from '@/components/MyTooltip';
|
|||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import FileSelect, { type FileItemType } from './FileSelect';
|
import FileSelect, { type FileItemType } from './FileSelect';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
const fileExtension = '.txt, .doc, .docx, .pdf, .md';
|
||||||
|
|
||||||
const ChunkImport = ({ kbId }: { kbId: string }) => {
|
const ChunkImport = ({ kbId }: { kbId: string }) => {
|
||||||
const { kbDetail } = useUserStore();
|
const { kbDetail } = useDatasetStore();
|
||||||
|
|
||||||
const vectorModel = kbDetail.vectorModel;
|
const vectorModel = kbDetail.vectorModel;
|
||||||
const unitPrice = vectorModel?.price || 0.2;
|
const unitPrice = vectorModel?.price || 0.2;
|
||||||
|
|||||||
@ -10,12 +10,12 @@ import DeleteIcon, { hoverDeleteStyles } from '@/components/Icon/delete';
|
|||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import FileSelect, { type FileItemType } from './FileSelect';
|
import FileSelect, { type FileItemType } from './FileSelect';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const fileExtension = '.csv';
|
const fileExtension = '.csv';
|
||||||
|
|
||||||
const CsvImport = ({ kbId }: { kbId: string }) => {
|
const CsvImport = ({ kbId }: { kbId: string }) => {
|
||||||
const { kbDetail } = useUserStore();
|
const { kbDetail } = useDatasetStore();
|
||||||
const maxToken = kbDetail.vectorModel?.maxToken || 2000;
|
const maxToken = kbDetail.vectorModel?.maxToken || 2000;
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import dynamic from 'next/dynamic';
|
|||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { FetchResultItem, DatasetItemType } from '@/types/plugin';
|
import { FetchResultItem, DatasetItemType } from '@/types/plugin';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const UrlFetchModal = dynamic(() => import('./UrlFetchModal'));
|
const UrlFetchModal = dynamic(() => import('./UrlFetchModal'));
|
||||||
const CreateFileModal = dynamic(() => import('./CreateFileModal'));
|
const CreateFileModal = dynamic(() => import('./CreateFileModal'));
|
||||||
@ -55,7 +55,7 @@ const FileSelect = ({
|
|||||||
showCreateFile = true,
|
showCreateFile = true,
|
||||||
...props
|
...props
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { kbDetail } = useUserStore();
|
const { kbDetail } = useDatasetStore();
|
||||||
const { Loading: FileSelectLoading } = useLoading();
|
const { Loading: FileSelectLoading } = useLoading();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|||||||
@ -6,14 +6,14 @@ import { useRequest } from '@/hooks/useRequest';
|
|||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { postKbDataFromList } from '@/api/plugins/kb';
|
import { postKbDataFromList } from '@/api/plugins/kb';
|
||||||
import { TrainingModeEnum } from '@/constants/plugin';
|
import { TrainingModeEnum } from '@/constants/plugin';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
type ManualFormType = { q: string; a: string };
|
type ManualFormType = { q: string; a: string };
|
||||||
|
|
||||||
const ManualImport = ({ kbId }: { kbId: string }) => {
|
const ManualImport = ({ kbId }: { kbId: string }) => {
|
||||||
const { kbDetail } = useUserStore();
|
const { kbDetail } = useDatasetStore();
|
||||||
const maxToken = kbDetail.vectorModel?.maxToken || 2000;
|
const maxToken = kbDetail.vectorModel?.maxToken || 2000;
|
||||||
|
|
||||||
const { register, handleSubmit, reset } = useForm({
|
const { register, handleSubmit, reset } = useForm({
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { QuestionOutlineIcon, DeleteIcon } from '@chakra-ui/icons';
|
|||||||
import { delKbById, putKbById } from '@/api/plugins/kb';
|
import { delKbById, putKbById } from '@/api/plugins/kb';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { UseFormReturn } from 'react-hook-form';
|
import { UseFormReturn } from 'react-hook-form';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/file';
|
||||||
@ -47,7 +47,7 @@ const Info = (
|
|||||||
multiple: false
|
multiple: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const { kbDetail, getKbDetail, loadKbList, myKbList } = useUserStore();
|
const { kbDetail, getKbDetail, loadKbList } = useDatasetStore();
|
||||||
|
|
||||||
/* 点击删除 */
|
/* 点击删除 */
|
||||||
const onclickDelKb = useCallback(async () => {
|
const onclickDelKb = useCallback(async () => {
|
||||||
|
|||||||
@ -9,10 +9,10 @@ import MyIcon from '@/components/Icon';
|
|||||||
import MyModal from '@/components/MyModal';
|
import MyModal from '@/components/MyModal';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { DatasetItemType } from '@/types/plugin';
|
import { DatasetItemType } from '@/types/plugin';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
export type FormData = { dataId?: string } & DatasetItemType;
|
export type FormData = { dataId?: string } & DatasetItemType;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ const InputDataModal = ({
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const { kbDetail, getKbDetail } = useUserStore();
|
const { kbDetail, getKbDetail } = useDatasetStore();
|
||||||
|
|
||||||
const { getValues, register, handleSubmit, reset } = useForm<FormData>({
|
const { getValues, register, handleSubmit, reset } = useForm<FormData>({
|
||||||
defaultValues
|
defaultValues
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react';
|
import { Box, Textarea, Button, Flex, useTheme, Grid, Progress } from '@chakra-ui/react';
|
||||||
import { useKbStore } from '@/store/kb';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import type { KbTestItemType } from '@/types/plugin';
|
import type { KbTestItemType } from '@/types/plugin';
|
||||||
import { searchText, getKbDataItemById } from '@/api/plugins/kb';
|
import { searchText, getKbDataItemById } from '@/api/plugins/kb';
|
||||||
import MyIcon from '@/components/Icon';
|
import MyIcon from '@/components/Icon';
|
||||||
@ -13,16 +13,14 @@ import { useToast } from '@/hooks/useToast';
|
|||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import MyTooltip from '@/components/MyTooltip';
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 12);
|
||||||
|
|
||||||
const Test = ({ kbId }: { kbId: string }) => {
|
const Test = ({ kbId }: { kbId: string }) => {
|
||||||
const { kbDetail } = useUserStore();
|
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { setLoading } = useGlobalStore();
|
const { setLoading } = useGlobalStore();
|
||||||
const { kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } = useKbStore();
|
const { kbDetail, kbTestList, pushKbTestItem, delKbTestItemById, updateKbItemById } =
|
||||||
|
useDatasetStore();
|
||||||
const [inputText, setInputText] = useState('');
|
const [inputText, setInputText] = useState('');
|
||||||
const [kbTestItem, setKbTestItem] = useState<KbTestItemType>();
|
const [kbTestItem, setKbTestItem] = useState<KbTestItemType>();
|
||||||
const [editData, setEditData] = useState<FormData>();
|
const [editData, setEditData] = useState<FormData>();
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { Box, Flex, IconButton, useTheme } from '@chakra-ui/react';
|
|||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useUserStore } from '@/store/user';
|
|
||||||
import { KbItemType } from '@/types/plugin';
|
import { KbItemType } from '@/types/plugin';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
@ -24,6 +23,7 @@ import { QuestionOutlineIcon } from '@chakra-ui/icons';
|
|||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
import FileCard from './components/FileCard';
|
import FileCard from './components/FileCard';
|
||||||
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
|
|
||||||
const DataCard = dynamic(() => import('./components/DataCard'), {
|
const DataCard = dynamic(() => import('./components/DataCard'), {
|
||||||
ssr: false
|
ssr: false
|
||||||
@ -50,7 +50,7 @@ const Detail = ({ kbId, currentTab }: { kbId: string; currentTab: `${TabEnum}` }
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { isPc } = useGlobalStore();
|
const { isPc } = useGlobalStore();
|
||||||
const { kbDetail, getKbDetail } = useUserStore();
|
const { kbDetail, getKbDetail } = useDatasetStore();
|
||||||
|
|
||||||
const tabList = useRef([
|
const tabList = useRef([
|
||||||
{ label: '数据集', id: TabEnum.dataset, icon: 'overviewLight' },
|
{ label: '数据集', id: TabEnum.dataset, icon: 'overviewLight' },
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
Image
|
Image
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useDatasetStore } from '@/store/dataset';
|
||||||
import PageContainer from '@/components/PageContainer';
|
import PageContainer from '@/components/PageContainer';
|
||||||
import { useConfirm } from '@/hooks/useConfirm';
|
import { useConfirm } from '@/hooks/useConfirm';
|
||||||
import { AddIcon } from '@chakra-ui/icons';
|
import { AddIcon } from '@chakra-ui/icons';
|
||||||
@ -49,7 +49,7 @@ const Kb = () => {
|
|||||||
title: t('common.Delete Warning'),
|
title: t('common.Delete Warning'),
|
||||||
content: ''
|
content: ''
|
||||||
});
|
});
|
||||||
const { myKbList, loadKbList, setKbList } = useUserStore();
|
const { myKbList, loadKbList, setKbList } = useDatasetStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenCreateModal,
|
isOpen: isOpenCreateModal,
|
||||||
|
|||||||
86
client/src/store/dataset.ts
Normal file
86
client/src/store/dataset.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { create } from 'zustand';
|
||||||
|
import { devtools, persist } from 'zustand/middleware';
|
||||||
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
import { type KbTestItemType } from '@/types/plugin';
|
||||||
|
import type { KbItemType, KbListItemType } from '@/types/plugin';
|
||||||
|
import { getKbList, getKbById, getAllDataset } from '@/api/plugins/kb';
|
||||||
|
import { defaultKbDetail } from '@/constants/kb';
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
datasets: KbListItemType[];
|
||||||
|
loadAllDatasets: () => Promise<KbListItemType[]>;
|
||||||
|
myKbList: KbListItemType[];
|
||||||
|
loadKbList: (parentId?: string) => Promise<any>;
|
||||||
|
setKbList(val: KbListItemType[]): void;
|
||||||
|
kbDetail: KbItemType;
|
||||||
|
getKbDetail: (id: string, init?: boolean) => Promise<KbItemType>;
|
||||||
|
|
||||||
|
kbTestList: KbTestItemType[];
|
||||||
|
pushKbTestItem: (data: KbTestItemType) => void;
|
||||||
|
delKbTestItemById: (id: string) => void;
|
||||||
|
updateKbItemById: (data: KbTestItemType) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDatasetStore = create<State>()(
|
||||||
|
devtools(
|
||||||
|
persist(
|
||||||
|
immer((set, get) => ({
|
||||||
|
datasets: [],
|
||||||
|
async loadAllDatasets() {
|
||||||
|
const res = await getAllDataset();
|
||||||
|
set((state) => {
|
||||||
|
state.datasets = res;
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
myKbList: [],
|
||||||
|
async loadKbList(parentId) {
|
||||||
|
const res = await getKbList(parentId);
|
||||||
|
set((state) => {
|
||||||
|
state.myKbList = res;
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
setKbList(val) {
|
||||||
|
set((state) => {
|
||||||
|
state.myKbList = val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
kbDetail: defaultKbDetail,
|
||||||
|
async getKbDetail(id: string, init = false) {
|
||||||
|
if (id === get().kbDetail._id && !init) return get().kbDetail;
|
||||||
|
|
||||||
|
const data = await getKbById(id);
|
||||||
|
|
||||||
|
set((state) => {
|
||||||
|
state.kbDetail = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
kbTestList: [],
|
||||||
|
pushKbTestItem(data) {
|
||||||
|
set((state) => {
|
||||||
|
state.kbTestList = [data, ...state.kbTestList].slice(0, 500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
delKbTestItemById(id) {
|
||||||
|
set((state) => {
|
||||||
|
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateKbItemById(data: KbTestItemType) {
|
||||||
|
set((state) => {
|
||||||
|
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
{
|
||||||
|
name: 'kbStore',
|
||||||
|
partialize: (state) => ({
|
||||||
|
kbTestList: state.kbTestList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
@ -1,42 +0,0 @@
|
|||||||
import { create } from 'zustand';
|
|
||||||
import { devtools, persist } from 'zustand/middleware';
|
|
||||||
import { immer } from 'zustand/middleware/immer';
|
|
||||||
import { type KbTestItemType } from '@/types/plugin';
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
kbTestList: KbTestItemType[];
|
|
||||||
pushKbTestItem: (data: KbTestItemType) => void;
|
|
||||||
delKbTestItemById: (id: string) => void;
|
|
||||||
updateKbItemById: (data: KbTestItemType) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useKbStore = create<State>()(
|
|
||||||
devtools(
|
|
||||||
persist(
|
|
||||||
immer((set, get) => ({
|
|
||||||
kbTestList: [],
|
|
||||||
pushKbTestItem(data) {
|
|
||||||
set((state) => {
|
|
||||||
state.kbTestList = [data, ...state.kbTestList].slice(0, 500);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
delKbTestItemById(id) {
|
|
||||||
set((state) => {
|
|
||||||
state.kbTestList = state.kbTestList.filter((item) => item.id !== id);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateKbItemById(data: KbTestItemType) {
|
|
||||||
set((state) => {
|
|
||||||
state.kbTestList = state.kbTestList.map((item) => (item.id === data.id ? data : item));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})),
|
|
||||||
{
|
|
||||||
name: 'kbStore',
|
|
||||||
partialize: (state) => ({
|
|
||||||
kbTestList: state.kbTestList
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
@ -7,9 +7,7 @@ import { formatPrice } from '@/utils/user';
|
|||||||
import { getTokenLogin, putUserInfo } from '@/api/user';
|
import { getTokenLogin, putUserInfo } from '@/api/user';
|
||||||
import { defaultApp } from '@/constants/model';
|
import { defaultApp } from '@/constants/model';
|
||||||
import { AppListItemType, AppUpdateParams } from '@/types/app';
|
import { AppListItemType, AppUpdateParams } from '@/types/app';
|
||||||
import type { KbItemType, KbListItemType } from '@/types/plugin';
|
|
||||||
import { getKbList, getKbById, putKbById } from '@/api/plugins/kb';
|
|
||||||
import { defaultKbDetail } from '@/constants/kb';
|
|
||||||
import type { AppSchema } from '@/types/mongoSchema';
|
import type { AppSchema } from '@/types/mongoSchema';
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@ -24,12 +22,6 @@ type State = {
|
|||||||
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
|
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
|
||||||
updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>;
|
updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>;
|
||||||
clearAppModules(): void;
|
clearAppModules(): void;
|
||||||
// kb
|
|
||||||
myKbList: KbListItemType[];
|
|
||||||
loadKbList: (parentId?: string) => Promise<any>;
|
|
||||||
setKbList(val: KbListItemType[]): void;
|
|
||||||
kbDetail: KbItemType;
|
|
||||||
getKbDetail: (id: string, init?: boolean) => Promise<KbItemType>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useUserStore = create<State>()(
|
export const useUserStore = create<State>()(
|
||||||
@ -106,31 +98,6 @@ export const useUserStore = create<State>()(
|
|||||||
modules: []
|
modules: []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
|
||||||
myKbList: [],
|
|
||||||
async loadKbList(parentId) {
|
|
||||||
const res = await getKbList(parentId);
|
|
||||||
set((state) => {
|
|
||||||
state.myKbList = res;
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
},
|
|
||||||
setKbList(val) {
|
|
||||||
set((state) => {
|
|
||||||
state.myKbList = val;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
kbDetail: defaultKbDetail,
|
|
||||||
async getKbDetail(id: string, init = false) {
|
|
||||||
if (id === get().kbDetail._id && !init) return get().kbDetail;
|
|
||||||
|
|
||||||
const data = await getKbById(id);
|
|
||||||
|
|
||||||
set((state) => {
|
|
||||||
state.kbDetail = data;
|
|
||||||
});
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user