mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-07-29 16:01:59 +08:00
feat: remove loading from model and use DvaModel instead of redundant types such as kAModelType (#47)
* feat: use DvaModel instead of redundant types such as kAModelType * feat: set the type for registerServer * feat: remove loading from model
This commit is contained in:
parent
96a1a44cb6
commit
362ec6c364
11
web/src/hooks/storeHooks.ts
Normal file
11
web/src/hooks/storeHooks.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
||||||
|
import { useSelector } from 'umi';
|
||||||
|
|
||||||
|
// Get the loading status of given effects under a certain namespace
|
||||||
|
export const useOneNamespaceEffectsLoading = (
|
||||||
|
namespace: string,
|
||||||
|
effectNames: Array<string>,
|
||||||
|
) => {
|
||||||
|
const effects = useSelector((state: any) => state.loading.effects);
|
||||||
|
return getOneNamespaceEffectsLoading(namespace, effects, effectNames);
|
||||||
|
};
|
@ -1,102 +1,116 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import { Form, Input, Modal } from 'antd';
|
||||||
import { connect, Dispatch } from 'umi';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import i18n from 'i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useTranslation, Trans } from 'react-i18next'
|
import { useDispatch } from 'umi';
|
||||||
import { Input, Modal, Form } from 'antd'
|
import EditTag from './editTag';
|
||||||
import styles from './index.less';
|
|
||||||
import type { chunkModelState } from './model'
|
|
||||||
import EditTag from './editTag'
|
|
||||||
|
|
||||||
type FieldType = {
|
type FieldType = {
|
||||||
content_ltks?: string;
|
content_ltks?: string;
|
||||||
};
|
};
|
||||||
interface kFProps {
|
interface kFProps {
|
||||||
dispatch: Dispatch;
|
getChunkList: () => void;
|
||||||
chunkModel: chunkModelState;
|
isShowCreateModal: boolean;
|
||||||
getChunkList: () => void;
|
doc_id: string;
|
||||||
isShowCreateModal: boolean;
|
chunk_id: string;
|
||||||
doc_id: string;
|
|
||||||
chunk_id: string
|
|
||||||
}
|
}
|
||||||
const Index: React.FC<kFProps> = ({ dispatch, getChunkList, doc_id, isShowCreateModal, chunk_id }) => {
|
|
||||||
// const { , chunkInfo } = chunkModel
|
|
||||||
const [important_kwd, setImportantKwd] = useState(['Unremovable', 'Tag 2', 'Tag 3']);
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const handleCancel = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCreateModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(chunk_id, isShowCreateModal)
|
|
||||||
if (chunk_id && isShowCreateModal) {
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/get_chunk',
|
|
||||||
payload: {
|
|
||||||
chunk_id
|
|
||||||
},
|
|
||||||
callback(info: any) {
|
|
||||||
console.log(info)
|
|
||||||
const { content_ltks, important_kwd = [] } = info
|
|
||||||
form.setFieldsValue({ content_ltks })
|
|
||||||
setImportantKwd(important_kwd)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [chunk_id, isShowCreateModal])
|
|
||||||
const [form] = Form.useForm()
|
|
||||||
const handleOk = async () => {
|
|
||||||
try {
|
|
||||||
const values = await form.validateFields();
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/create_hunk',
|
|
||||||
payload: {
|
|
||||||
content_ltks: values.content_ltks,
|
|
||||||
doc_id,
|
|
||||||
chunk_id,
|
|
||||||
important_kwd
|
|
||||||
},
|
|
||||||
callback: () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCreateModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
getChunkList && getChunkList()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (errorInfo) {
|
const Index: React.FC<kFProps> = ({
|
||||||
console.log('Failed:', errorInfo);
|
getChunkList,
|
||||||
}
|
doc_id,
|
||||||
};
|
isShowCreateModal,
|
||||||
|
chunk_id,
|
||||||
|
}) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
return (
|
// const { , chunkInfo } = chunkModel
|
||||||
<Modal title="Basic Modal" open={isShowCreateModal} onOk={handleOk} onCancel={handleCancel}>
|
const [important_kwd, setImportantKwd] = useState([
|
||||||
<Form
|
'Unremovable',
|
||||||
form={form}
|
'Tag 2',
|
||||||
name="validateOnly"
|
'Tag 3',
|
||||||
labelCol={{ span: 5 }}
|
]);
|
||||||
wrapperCol={{ span: 19 }}
|
const { t } = useTranslation();
|
||||||
style={{ maxWidth: 600 }}
|
const handleCancel = () => {
|
||||||
autoComplete="off"
|
dispatch({
|
||||||
>
|
type: 'chunkModel/updateState',
|
||||||
<Form.Item<FieldType>
|
payload: {
|
||||||
label="chunk 内容"
|
isShowCreateModal: false,
|
||||||
name="content_ltks"
|
},
|
||||||
rules={[{ required: true, message: 'Please input value!' }]}
|
});
|
||||||
>
|
};
|
||||||
<Input.TextArea />
|
|
||||||
</Form.Item>
|
|
||||||
<EditTag tags={important_kwd} setTags={setImportantKwd} />
|
|
||||||
</Form>
|
|
||||||
</Modal >
|
|
||||||
|
|
||||||
|
const getChunk = useCallback(async () => {
|
||||||
|
if (chunk_id && isShowCreateModal) {
|
||||||
|
const data = await dispatch<any>({
|
||||||
|
type: 'chunkModel/get_chunk',
|
||||||
|
payload: {
|
||||||
|
chunk_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
);
|
if (data?.retcode === 0) {
|
||||||
}
|
const { content_ltks, important_kwd = [] } = data.data;
|
||||||
export default connect(({ chunkModel, loading }) => ({ chunkModel, loading }))(Index);
|
form.setFieldsValue({ content_ltks });
|
||||||
|
setImportantKwd(important_kwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [chunk_id, isShowCreateModal]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getChunk();
|
||||||
|
}, [getChunk]);
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
const values = await form.validateFields();
|
||||||
|
dispatch({
|
||||||
|
type: 'chunkModel/create_hunk',
|
||||||
|
payload: {
|
||||||
|
content_ltks: values.content_ltks,
|
||||||
|
doc_id,
|
||||||
|
chunk_id,
|
||||||
|
important_kwd,
|
||||||
|
},
|
||||||
|
// callback: () => {
|
||||||
|
// dispatch({
|
||||||
|
// type: 'chunkModel/updateState',
|
||||||
|
// payload: {
|
||||||
|
// isShowCreateModal: false,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// getChunkList && getChunkList();
|
||||||
|
// },
|
||||||
|
});
|
||||||
|
} catch (errorInfo) {
|
||||||
|
console.log('Failed:', errorInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="Basic Modal"
|
||||||
|
open={isShowCreateModal}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
name="validateOnly"
|
||||||
|
labelCol={{ span: 5 }}
|
||||||
|
wrapperCol={{ span: 19 }}
|
||||||
|
style={{ maxWidth: 600 }}
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<Form.Item<FieldType>
|
||||||
|
label="chunk 内容"
|
||||||
|
name="content_ltks"
|
||||||
|
rules={[{ required: true, message: 'Please input value!' }]}
|
||||||
|
>
|
||||||
|
<Input.TextArea />
|
||||||
|
</Form.Item>
|
||||||
|
<EditTag tags={important_kwd} setTags={setImportantKwd} />
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default Index;
|
||||||
|
@ -1,142 +1,141 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
|
||||||
import type { InputRef } from 'antd';
|
import type { InputRef } from 'antd';
|
||||||
import { Input, Space, Tag, theme, Tooltip } from 'antd';
|
import { Input, Space, Tag, Tooltip, theme } from 'antd';
|
||||||
interface editTagsProps {
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
tags: any[],
|
interface EditTagsProps {
|
||||||
setTags: (tags: any[]) => void
|
tags: any[];
|
||||||
|
setTags: (tags: any[]) => void;
|
||||||
}
|
}
|
||||||
const App: React.FC<editTagsProps> = ({ tags, setTags }) => {
|
const EditTag: React.FC<EditTagsProps> = ({ tags, setTags }) => {
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
|
||||||
const [inputVisible, setInputVisible] = useState(false);
|
const [inputVisible, setInputVisible] = useState(false);
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [editInputIndex, setEditInputIndex] = useState(-1);
|
const [editInputIndex, setEditInputIndex] = useState(-1);
|
||||||
const [editInputValue, setEditInputValue] = useState('');
|
const [editInputValue, setEditInputValue] = useState('');
|
||||||
const inputRef = useRef<InputRef>(null);
|
const inputRef = useRef<InputRef>(null);
|
||||||
const editInputRef = useRef<InputRef>(null);
|
const editInputRef = useRef<InputRef>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (inputVisible) {
|
if (inputVisible) {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
|
}
|
||||||
|
}, [inputVisible]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
editInputRef.current?.focus();
|
||||||
|
}, [editInputValue]);
|
||||||
|
|
||||||
|
const handleClose = (removedTag: string) => {
|
||||||
|
const newTags = tags.filter((tag) => tag !== removedTag);
|
||||||
|
console.log(newTags);
|
||||||
|
setTags(newTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showInput = () => {
|
||||||
|
setInputVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setInputValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputConfirm = () => {
|
||||||
|
if (inputValue && !tags.includes(inputValue)) {
|
||||||
|
setTags([...tags, inputValue]);
|
||||||
|
}
|
||||||
|
setInputVisible(false);
|
||||||
|
setInputValue('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setEditInputValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditInputConfirm = () => {
|
||||||
|
const newTags = [...tags];
|
||||||
|
newTags[editInputIndex] = editInputValue;
|
||||||
|
setTags(newTags);
|
||||||
|
setEditInputIndex(-1);
|
||||||
|
setEditInputValue('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagInputStyle: React.CSSProperties = {
|
||||||
|
width: 64,
|
||||||
|
height: 22,
|
||||||
|
marginInlineEnd: 8,
|
||||||
|
verticalAlign: 'top',
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagPlusStyle: React.CSSProperties = {
|
||||||
|
height: 22,
|
||||||
|
background: token.colorBgContainer,
|
||||||
|
borderStyle: 'dashed',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space size={[0, 8]} wrap>
|
||||||
|
{tags.map((tag, index) => {
|
||||||
|
if (editInputIndex === index) {
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
ref={editInputRef}
|
||||||
|
key={tag}
|
||||||
|
size="small"
|
||||||
|
style={tagInputStyle}
|
||||||
|
value={editInputValue}
|
||||||
|
onChange={handleEditInputChange}
|
||||||
|
onBlur={handleEditInputConfirm}
|
||||||
|
onPressEnter={handleEditInputConfirm}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [inputVisible]);
|
const isLongTag = tag.length > 20;
|
||||||
|
const tagElem = (
|
||||||
useEffect(() => {
|
<Tag
|
||||||
editInputRef.current?.focus();
|
key={tag}
|
||||||
}, [editInputValue]);
|
closable={index !== 0}
|
||||||
|
style={{ userSelect: 'none' }}
|
||||||
const handleClose = (removedTag: string) => {
|
onClose={() => handleClose(tag)}
|
||||||
const newTags = tags.filter((tag) => tag !== removedTag);
|
>
|
||||||
console.log(newTags);
|
<span
|
||||||
setTags(newTags);
|
onDoubleClick={(e) => {
|
||||||
};
|
if (index !== 0) {
|
||||||
|
setEditInputIndex(index);
|
||||||
const showInput = () => {
|
setEditInputValue(tag);
|
||||||
setInputVisible(true);
|
e.preventDefault();
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setInputValue(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputConfirm = () => {
|
|
||||||
if (inputValue && !tags.includes(inputValue)) {
|
|
||||||
setTags([...tags, inputValue]);
|
|
||||||
}
|
|
||||||
setInputVisible(false);
|
|
||||||
setInputValue('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setEditInputValue(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditInputConfirm = () => {
|
|
||||||
const newTags = [...tags];
|
|
||||||
newTags[editInputIndex] = editInputValue;
|
|
||||||
setTags(newTags);
|
|
||||||
setEditInputIndex(-1);
|
|
||||||
setEditInputValue('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const tagInputStyle: React.CSSProperties = {
|
|
||||||
width: 64,
|
|
||||||
height: 22,
|
|
||||||
marginInlineEnd: 8,
|
|
||||||
verticalAlign: 'top',
|
|
||||||
};
|
|
||||||
|
|
||||||
const tagPlusStyle: React.CSSProperties = {
|
|
||||||
height: 22,
|
|
||||||
background: token.colorBgContainer,
|
|
||||||
borderStyle: 'dashed',
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Space size={[0, 8]} wrap>
|
|
||||||
{tags.map((tag, index) => {
|
|
||||||
if (editInputIndex === index) {
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
ref={editInputRef}
|
|
||||||
key={tag}
|
|
||||||
size="small"
|
|
||||||
style={tagInputStyle}
|
|
||||||
value={editInputValue}
|
|
||||||
onChange={handleEditInputChange}
|
|
||||||
onBlur={handleEditInputConfirm}
|
|
||||||
onPressEnter={handleEditInputConfirm}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
const isLongTag = tag.length > 20;
|
}}
|
||||||
const tagElem = (
|
>
|
||||||
<Tag
|
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||||
key={tag}
|
</span>
|
||||||
closable={index !== 0}
|
</Tag>
|
||||||
style={{ userSelect: 'none' }}
|
);
|
||||||
onClose={() => handleClose(tag)}
|
return isLongTag ? (
|
||||||
>
|
<Tooltip title={tag} key={tag}>
|
||||||
<span
|
{tagElem}
|
||||||
onDoubleClick={(e) => {
|
</Tooltip>
|
||||||
if (index !== 0) {
|
) : (
|
||||||
setEditInputIndex(index);
|
tagElem
|
||||||
setEditInputValue(tag);
|
);
|
||||||
e.preventDefault();
|
})}
|
||||||
}
|
{inputVisible ? (
|
||||||
}}
|
<Input
|
||||||
>
|
ref={inputRef}
|
||||||
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
type="text"
|
||||||
</span>
|
size="small"
|
||||||
</Tag>
|
style={tagInputStyle}
|
||||||
);
|
value={inputValue}
|
||||||
return isLongTag ? (
|
onChange={handleInputChange}
|
||||||
<Tooltip title={tag} key={tag}>
|
onBlur={handleInputConfirm}
|
||||||
{tagElem}
|
onPressEnter={handleInputConfirm}
|
||||||
</Tooltip>
|
/>
|
||||||
) : (
|
) : (
|
||||||
tagElem
|
<Tag style={tagPlusStyle} onClick={showInput}>
|
||||||
);
|
添加关键词
|
||||||
})}
|
</Tag>
|
||||||
{inputVisible ? (
|
)}
|
||||||
<Input
|
</Space>
|
||||||
ref={inputRef}
|
);
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
style={tagInputStyle}
|
|
||||||
value={inputValue}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
onBlur={handleInputConfirm}
|
|
||||||
onPressEnter={handleInputConfirm}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Tag style={tagPlusStyle} onClick={showInput}>
|
|
||||||
添加关键词
|
|
||||||
</Tag>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default EditTag;
|
||||||
|
@ -1,225 +1,282 @@
|
|||||||
import React, { useEffect, useState, useCallback } from 'react';
|
import { api_host } from '@/utils/api';
|
||||||
import { useNavigate, connect, Dispatch } from 'umi'
|
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
||||||
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
|
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
|
||||||
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
|
|
||||||
import type { PaginationProps } from 'antd';
|
import type { PaginationProps } from 'antd';
|
||||||
import { api_host } from '@/utils/api'
|
import {
|
||||||
import CreateModal from './components/createModal'
|
Button,
|
||||||
|
Card,
|
||||||
|
Col,
|
||||||
|
Input,
|
||||||
|
Pagination,
|
||||||
|
Popconfirm,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Spin,
|
||||||
|
Switch,
|
||||||
|
} from 'antd';
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
|
import CreateModal from './components/createModal';
|
||||||
|
|
||||||
|
|
||||||
import styles from './index.less'
|
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import type { chunkModelState } from './model'
|
import styles from './index.less';
|
||||||
interface chunkProps {
|
|
||||||
dispatch: Dispatch;
|
interface PayloadType {
|
||||||
chunkModel: chunkModelState;
|
doc_id: string;
|
||||||
doc_id: string
|
keywords?: string;
|
||||||
|
available_int?: number;
|
||||||
}
|
}
|
||||||
const Index: React.FC<chunkProps> = ({ chunkModel, dispatch, doc_id }) => {
|
|
||||||
const [keywords, SetKeywords] = useState('')
|
interface IProps {
|
||||||
const [available_int, setAvailableInt] = useState(-1)
|
doc_id: string;
|
||||||
const navigate = useNavigate()
|
}
|
||||||
const [pagination, setPagination] = useState({ page: 1, size: 30 })
|
|
||||||
|
const Chunk = ({ doc_id }: IProps) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const chunkModel = useSelector((state: any) => state.chunkModel);
|
||||||
|
const [keywords, SetKeywords] = useState('');
|
||||||
|
const [available_int, setAvailableInt] = useState(-1);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [pagination, setPagination] = useState({ page: 1, size: 30 });
|
||||||
// const [datas, setDatas] = useState(data)
|
// const [datas, setDatas] = useState(data)
|
||||||
const { data = [], total, loading, chunk_id, isShowCreateModal } = chunkModel
|
const { data = [], total, chunk_id, isShowCreateModal } = chunkModel;
|
||||||
console.log(chunkModel)
|
const effects = useSelector((state: any) => state.loading.effects);
|
||||||
|
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
|
||||||
|
'create_hunk',
|
||||||
|
'chunk_list',
|
||||||
|
'switch_chunk',
|
||||||
|
]);
|
||||||
|
|
||||||
const getChunkList = (value?: string) => {
|
const getChunkList = (value?: string) => {
|
||||||
dispatch({
|
const payload: PayloadType = {
|
||||||
type: 'chunkModel/updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
interface payloadType {
|
|
||||||
doc_id: string;
|
|
||||||
keywords?: string;
|
|
||||||
available_int?: number
|
|
||||||
}
|
|
||||||
const payload: payloadType = {
|
|
||||||
doc_id,
|
doc_id,
|
||||||
keywords: value || keywords,
|
keywords: value || keywords,
|
||||||
available_int
|
available_int,
|
||||||
}
|
};
|
||||||
if (payload.available_int === -1) {
|
if (payload.available_int === -1) {
|
||||||
delete payload.available_int
|
delete payload.available_int;
|
||||||
}
|
}
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'chunkModel/chunk_list',
|
type: 'chunkModel/chunk_list',
|
||||||
payload: {
|
payload: {
|
||||||
...payload,
|
...payload,
|
||||||
...pagination
|
...pagination,
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const confirm = (id: string) => {
|
|
||||||
console.log(id)
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/rm_chunk',
|
|
||||||
payload: {
|
|
||||||
chunk_ids: [id]
|
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const confirm = async (id: string) => {
|
||||||
|
const retcode = await dispatch<any>({
|
||||||
|
type: 'chunkModel/rm_chunk',
|
||||||
|
payload: {
|
||||||
|
chunk_ids: [id],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
retcode === 0 && getChunkList();
|
||||||
|
};
|
||||||
|
|
||||||
const handleEditchunk = (chunk_id?: string) => {
|
const handleEditchunk = (chunk_id?: string) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'chunkModel/updateState',
|
type: 'chunkModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
isShowCreateModal: true,
|
isShowCreateModal: true,
|
||||||
chunk_id,
|
chunk_id,
|
||||||
doc_id
|
doc_id,
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
}
|
getChunkList();
|
||||||
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
|
|
||||||
setPagination({ page, size })
|
|
||||||
};
|
};
|
||||||
const switchChunk = (id: string, available_int: boolean) => {
|
|
||||||
dispatch({
|
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
|
||||||
type: 'chunkModel/updateState',
|
page,
|
||||||
payload: {
|
size,
|
||||||
loading: true
|
) => {
|
||||||
}
|
setPagination({ page, size });
|
||||||
});
|
};
|
||||||
dispatch({
|
|
||||||
|
const switchChunk = async (id: string, available_int: boolean) => {
|
||||||
|
const retcode = await dispatch<any>({
|
||||||
type: 'chunkModel/switch_chunk',
|
type: 'chunkModel/switch_chunk',
|
||||||
payload: {
|
payload: {
|
||||||
chunk_ids: [id],
|
chunk_ids: [id],
|
||||||
available_int: Number(available_int),
|
available_int: Number(available_int),
|
||||||
doc_id
|
doc_id,
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
retcode === 0 && getChunkList();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getChunkList()
|
getChunkList();
|
||||||
}, [doc_id, available_int, pagination])
|
}, [doc_id, available_int, pagination]);
|
||||||
const debounceChange = debounce(getChunkList, 300)
|
|
||||||
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
|
const debounceChange = debounce(getChunkList, 300);
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const debounceCallback = useCallback(
|
||||||
const value = e.target.value
|
(value: string) => debounceChange(value),
|
||||||
SetKeywords(value)
|
[],
|
||||||
debounceCallback(value)
|
);
|
||||||
}
|
|
||||||
|
const handleInputChange = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
SetKeywords(value);
|
||||||
|
debounceCallback(value);
|
||||||
|
};
|
||||||
const handleSelectChange = (value: number) => {
|
const handleSelectChange = (value: number) => {
|
||||||
setAvailableInt(value)
|
setAvailableInt(value);
|
||||||
}
|
};
|
||||||
console.log('loading', loading)
|
return (
|
||||||
return (<>
|
<>
|
||||||
<div className={styles.chunkPage}>
|
<div className={styles.chunkPage}>
|
||||||
<div className={styles.filter}>
|
<div className={styles.filter}>
|
||||||
<div>
|
<div>
|
||||||
<Input placeholder="搜索" style={{ width: 220 }} value={keywords} allowClear onChange={handleInputChange} />
|
<Input
|
||||||
<Select
|
placeholder="搜索"
|
||||||
showSearch
|
style={{ width: 220 }}
|
||||||
placeholder="是否启用"
|
value={keywords}
|
||||||
optionFilterProp="children"
|
allowClear
|
||||||
value={available_int}
|
onChange={handleInputChange}
|
||||||
onChange={handleSelectChange}
|
/>
|
||||||
style={{ width: 220 }}
|
<Select
|
||||||
options={[
|
showSearch
|
||||||
{
|
placeholder="是否启用"
|
||||||
value: -1,
|
optionFilterProp="children"
|
||||||
label: '全部',
|
value={available_int}
|
||||||
},
|
onChange={handleSelectChange}
|
||||||
{
|
style={{ width: 220 }}
|
||||||
value: 1,
|
options={[
|
||||||
label: '启用',
|
{
|
||||||
},
|
value: -1,
|
||||||
{
|
label: '全部',
|
||||||
value: 0,
|
},
|
||||||
label: '未启用',
|
{
|
||||||
},
|
value: 1,
|
||||||
]}
|
label: '启用',
|
||||||
/>
|
},
|
||||||
|
{
|
||||||
|
value: 0,
|
||||||
|
label: '未启用',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
handleEditchunk();
|
||||||
|
}}
|
||||||
|
type="link"
|
||||||
|
>
|
||||||
|
添加分段
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={() => { handleEditchunk() }} type='link'>添加分段</Button>
|
<div className={styles.pageContent}>
|
||||||
</div>
|
<Spin spinning={loading} className={styles.spin} size="large">
|
||||||
<div className={styles.pageContent}>
|
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
|
||||||
<Spin spinning={loading} className={styles.spin} size='large'>
|
{data.map((item: any) => {
|
||||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }} >
|
return (
|
||||||
{
|
<Col
|
||||||
data.map((item: any) => {
|
className="gutter-row"
|
||||||
return (<Col className="gutter-row" key={item.chunk_id} xs={24} sm={12} md={12} lg={8}>
|
key={item.chunk_id}
|
||||||
<Card className={styles.card}
|
xs={24}
|
||||||
onClick={() => { handleEditchunk(item.chunk_id) }}
|
sm={12}
|
||||||
|
md={12}
|
||||||
|
lg={8}
|
||||||
>
|
>
|
||||||
<img style={{ width: '50px' }} src={`${api_host}/document/image/${item.img_id}`} alt="" />
|
<Card
|
||||||
<div className={styles.container}>
|
className={styles.card}
|
||||||
<div className={styles.content}>
|
onClick={() => {
|
||||||
<span className={styles.context}>
|
handleEditchunk(item.chunk_id);
|
||||||
{item.content_ltks}
|
}}
|
||||||
</span>
|
>
|
||||||
<span className={styles.delete}>
|
<img
|
||||||
<Switch size="small" defaultValue={item.available_int == '1'} onChange={(checked: boolean, e: any) => {
|
style={{ width: '50px' }}
|
||||||
e.stopPropagation();
|
src={`${api_host}/document/image/${item.img_id}`}
|
||||||
e.nativeEvent.stopImmediatePropagation(); switchChunk(item.chunk_id, checked)
|
alt=""
|
||||||
}} />
|
/>
|
||||||
</span>
|
<div className={styles.container}>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<span className={styles.context}>
|
||||||
|
{item.content_ltks}
|
||||||
|
</span>
|
||||||
|
<span className={styles.delete}>
|
||||||
|
<Switch
|
||||||
|
size="small"
|
||||||
|
defaultValue={item.available_int == '1'}
|
||||||
|
onChange={(checked: boolean, e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
switchChunk(item.chunk_id, checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.footer}>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.doc_num}文档
|
||||||
|
</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.chunk_num}个
|
||||||
|
</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.token_num}千字符
|
||||||
|
</span>
|
||||||
|
<span style={{ float: 'right' }}>
|
||||||
|
<Popconfirm
|
||||||
|
title="Delete the task"
|
||||||
|
description="Are you sure to delete this task?"
|
||||||
|
onConfirm={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
console.log(confirm);
|
||||||
|
confirm(item.chunk_id);
|
||||||
|
}}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<DeleteOutlined
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popconfirm>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.footer}>
|
</Card>
|
||||||
<span className={styles.text}>
|
</Col>
|
||||||
<MinusSquareOutlined />{item.doc_num}文档
|
);
|
||||||
</span>
|
})}
|
||||||
<span className={styles.text}>
|
</Row>
|
||||||
<MinusSquareOutlined />{item.chunk_num}个
|
</Spin>
|
||||||
</span>
|
</div>
|
||||||
<span className={styles.text}>
|
<div className={styles.pageFooter}>
|
||||||
<MinusSquareOutlined />{item.token_num}千字符
|
<Pagination
|
||||||
</span>
|
responsive
|
||||||
<span style={{ float: 'right' }}>
|
showLessItems
|
||||||
<Popconfirm
|
showQuickJumper
|
||||||
title="Delete the task"
|
showSizeChanger
|
||||||
description="Are you sure to delete this task?"
|
onChange={onShowSizeChange}
|
||||||
onConfirm={(e: any) => {
|
defaultPageSize={30}
|
||||||
e.stopPropagation();
|
pageSizeOptions={[30, 60, 90]}
|
||||||
e.nativeEvent.stopImmediatePropagation()
|
defaultCurrent={pagination.page}
|
||||||
console.log(confirm)
|
total={total}
|
||||||
confirm(item.chunk_id)
|
/>
|
||||||
|
</div>
|
||||||
}}
|
|
||||||
okText="Yes"
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<DeleteOutlined onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.nativeEvent.stopImmediatePropagation()
|
|
||||||
}} />
|
|
||||||
</Popconfirm>
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Row>
|
|
||||||
</Spin>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.pageFooter}>
|
<CreateModal
|
||||||
<Pagination
|
doc_id={doc_id}
|
||||||
responsive
|
isShowCreateModal={isShowCreateModal}
|
||||||
showLessItems
|
chunk_id={chunk_id}
|
||||||
showQuickJumper
|
getChunkList={getChunkList}
|
||||||
showSizeChanger
|
/>
|
||||||
onChange={onShowSizeChange}
|
</>
|
||||||
defaultPageSize={30}
|
);
|
||||||
pageSizeOptions={[30, 60, 90]}
|
|
||||||
defaultCurrent={pagination.page}
|
|
||||||
total={total}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div >
|
|
||||||
<CreateModal doc_id={doc_id} isShowCreateModal={isShowCreateModal} chunk_id={chunk_id} getChunkList={getChunkList} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ chunkModel, loading }) => ({ chunkModel, loading }))(Index);
|
export default Chunk;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
import { Effect, Reducer } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface chunkModelState {
|
export interface ChunkModelState {
|
||||||
loading: boolean;
|
|
||||||
data: any[];
|
data: any[];
|
||||||
total: number;
|
total: number;
|
||||||
isShowCreateModal: boolean;
|
isShowCreateModal: boolean;
|
||||||
@ -10,25 +9,10 @@ export interface chunkModelState {
|
|||||||
doc_id: string;
|
doc_id: string;
|
||||||
chunkInfo: any;
|
chunkInfo: any;
|
||||||
}
|
}
|
||||||
export interface chunkgModelType {
|
|
||||||
namespace: 'chunkModel';
|
const model: DvaModel<ChunkModelState> = {
|
||||||
state: chunkModelState;
|
|
||||||
effects: {
|
|
||||||
chunk_list: Effect;
|
|
||||||
get_chunk: Effect;
|
|
||||||
create_hunk: Effect;
|
|
||||||
switch_chunk: Effect;
|
|
||||||
rm_chunk: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<chunkModelState>;
|
|
||||||
};
|
|
||||||
// subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: chunkgModelType = {
|
|
||||||
namespace: 'chunkModel',
|
namespace: 'chunkModel',
|
||||||
state: {
|
state: {
|
||||||
loading: false,
|
|
||||||
data: [],
|
data: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
isShowCreateModal: false,
|
isShowCreateModal: false,
|
||||||
@ -36,6 +20,14 @@ const Model: chunkgModelType = {
|
|||||||
doc_id: '',
|
doc_id: '',
|
||||||
chunkInfo: {},
|
chunkInfo: {},
|
||||||
},
|
},
|
||||||
|
reducers: {
|
||||||
|
updateState(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
// subscriptions: {
|
// subscriptions: {
|
||||||
// setup({ dispatch, history }) {
|
// setup({ dispatch, history }) {
|
||||||
// history.listen(location => {
|
// history.listen(location => {
|
||||||
@ -44,7 +36,7 @@ const Model: chunkgModelType = {
|
|||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
effects: {
|
effects: {
|
||||||
*chunk_list({ payload = {}, callback }, { call, put }) {
|
*chunk_list({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.chunk_list, payload);
|
const { data, response } = yield call(kbService.chunk_list, payload);
|
||||||
|
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
@ -55,28 +47,23 @@ const Model: chunkgModelType = {
|
|||||||
payload: {
|
payload: {
|
||||||
data: res.chunks,
|
data: res.chunks,
|
||||||
total: res.total,
|
total: res.total,
|
||||||
loading: false,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
callback && callback();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*switch_chunk({ payload = {}, callback }, { call, put }) {
|
*switch_chunk({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.switch_chunk, payload);
|
const { data, response } = yield call(kbService.switch_chunk, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
return retcode;
|
||||||
callback && callback();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
*rm_chunk({ payload = {}, callback }, { call, put }) {
|
*rm_chunk({ payload = {} }, { call, put }) {
|
||||||
console.log('shanchu');
|
console.log('shanchu');
|
||||||
const { data, response } = yield call(kbService.rm_chunk, payload);
|
const { data, response } = yield call(kbService.rm_chunk, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
|
||||||
callback && callback();
|
return retcode;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
*get_chunk({ payload = {}, callback }, { call, put }) {
|
*get_chunk({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.get_chunk, payload);
|
const { data, response } = yield call(kbService.get_chunk, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
@ -86,28 +73,16 @@ const Model: chunkgModelType = {
|
|||||||
chunkInfo: res,
|
chunkInfo: res,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
callback && callback(res);
|
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
},
|
},
|
||||||
*create_hunk({ payload = {} }, { call, put }) {
|
*create_hunk({ payload = {} }, { call, put }) {
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
let service = kbService.create_chunk;
|
let service = kbService.create_chunk;
|
||||||
if (payload.chunk_id) {
|
if (payload.chunk_id) {
|
||||||
service = kbService.set_chunk;
|
service = kbService.set_chunk;
|
||||||
}
|
}
|
||||||
const { data, response } = yield call(service, payload);
|
const { data, response } = yield call(service, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
@ -118,13 +93,5 @@ const Model: chunkgModelType = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,79 +1,73 @@
|
|||||||
import React from 'react'
|
import { Form, Input, Modal } from 'antd';
|
||||||
import { connect, Dispatch } from 'umi';
|
import React from 'react';
|
||||||
import i18n from 'i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useTranslation, Trans } from 'react-i18next'
|
import { useDispatch, useSelector } from 'umi';
|
||||||
import { Input, Modal, Form } from 'antd'
|
|
||||||
import styles from './index.less';
|
|
||||||
import type { kFModelState } from './model'
|
|
||||||
|
|
||||||
type FieldType = {
|
type FieldType = {
|
||||||
name?: string;
|
name?: string;
|
||||||
};
|
};
|
||||||
interface kFProps {
|
interface kFProps {
|
||||||
dispatch: Dispatch;
|
getKfList: () => void;
|
||||||
kFModel: kFModelState;
|
kb_id: string;
|
||||||
getKfList: () => void;
|
|
||||||
kb_id: string
|
|
||||||
}
|
}
|
||||||
const Index: React.FC<kFProps> = ({ kFModel, dispatch, getKfList, kb_id }) => {
|
|
||||||
const { isShowCEFwModal } = kFModel
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const handleCancel = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCEFwModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const [form] = Form.useForm()
|
|
||||||
const handleOk = async () => {
|
|
||||||
try {
|
|
||||||
const values = await form.validateFields();
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/document_create',
|
|
||||||
payload: {
|
|
||||||
name: values.name,
|
|
||||||
kb_id
|
|
||||||
},
|
|
||||||
callback: () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCEFwModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
getKfList && getKfList()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (errorInfo) {
|
const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => {
|
||||||
console.log('Failed:', errorInfo);
|
const dispatch = useDispatch();
|
||||||
}
|
const kFModel = useSelector((state: any) => state.kFModel);
|
||||||
};
|
const { isShowCEFwModal } = kFModel;
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
const handleCancel = () => {
|
||||||
<Modal title="Basic Modal" open={isShowCEFwModal} onOk={handleOk} onCancel={handleCancel}>
|
dispatch({
|
||||||
<Form
|
type: 'kFModel/updateState',
|
||||||
form={form}
|
payload: {
|
||||||
name="validateOnly"
|
isShowCEFwModal: false,
|
||||||
labelCol={{ span: 8 }}
|
},
|
||||||
wrapperCol={{ span: 16 }}
|
});
|
||||||
style={{ maxWidth: 600 }}
|
};
|
||||||
autoComplete="off"
|
const handleOk = async () => {
|
||||||
>
|
try {
|
||||||
<Form.Item<FieldType>
|
const values = await form.validateFields();
|
||||||
label="文件名"
|
const retcode = await dispatch<any>({
|
||||||
name="name"
|
type: 'kFModel/document_create',
|
||||||
rules={[{ required: true, message: 'Please input value!' }]}
|
payload: {
|
||||||
>
|
name: values.name,
|
||||||
<Input />
|
kb_id,
|
||||||
</Form.Item>
|
},
|
||||||
|
});
|
||||||
|
if (retcode === 0) {
|
||||||
|
getKfList && getKfList();
|
||||||
|
}
|
||||||
|
} catch (errorInfo) {
|
||||||
|
console.log('Failed:', errorInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
</Form>
|
return (
|
||||||
</Modal >
|
<Modal
|
||||||
|
title="Basic Modal"
|
||||||
|
open={isShowCEFwModal}
|
||||||
);
|
onOk={handleOk}
|
||||||
}
|
onCancel={handleCancel}
|
||||||
export default connect(({ kFModel, loading }) => ({ kFModel, loading }))(Index);
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
name="validateOnly"
|
||||||
|
labelCol={{ span: 8 }}
|
||||||
|
wrapperCol={{ span: 16 }}
|
||||||
|
style={{ maxWidth: 600 }}
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<Form.Item<FieldType>
|
||||||
|
label="文件名"
|
||||||
|
name="name"
|
||||||
|
rules={[{ required: true, message: 'Please input value!' }]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default FileCreatingModal;
|
||||||
|
@ -1,228 +1,273 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
|
||||||
import { connect, Dispatch, useNavigate } from 'umi'
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
import { Space, Table, Input, Button, Switch, Dropdown, } from 'antd';
|
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import { DownOutlined } from '@ant-design/icons'
|
import { Button, Dropdown, Input, Space, Switch, Table } from 'antd';
|
||||||
import { debounce } from 'lodash';
|
|
||||||
import type { ColumnsType } from 'antd/es/table';
|
import type { ColumnsType } from 'antd/es/table';
|
||||||
import UploadFile from './upload'
|
import { debounce } from 'lodash';
|
||||||
import CreateEPModal from './createEFileModal'
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import SegmentSetModal from './segmentSetModal'
|
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
import styles from './index.less'
|
import CreateEPModal from './createEFileModal';
|
||||||
import type { kFModelState } from './model'
|
import styles from './index.less';
|
||||||
|
import SegmentSetModal from './segmentSetModal';
|
||||||
|
import UploadFile from './upload';
|
||||||
|
|
||||||
interface DataType {
|
interface DataType {
|
||||||
name: string;
|
name: string;
|
||||||
chunk_num: string;
|
chunk_num: string;
|
||||||
token_num: number;
|
token_num: number;
|
||||||
update_date: string;
|
update_date: string;
|
||||||
size: string;
|
size: string;
|
||||||
status: string;
|
status: string;
|
||||||
id: string;
|
id: string;
|
||||||
parser_id: string
|
parser_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface kFProps {
|
interface KFProps {
|
||||||
dispatch: Dispatch;
|
kb_id: string;
|
||||||
kFModel: kFModelState;
|
|
||||||
kb_id: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Index: React.FC<kFProps> = ({ kFModel, dispatch, kb_id }) => {
|
const KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => {
|
||||||
const { data, loading } = kFModel
|
const dispatch = useDispatch();
|
||||||
const [inputValue, setInputValue] = useState('')
|
const kFModel = useSelector((state: any) => state.kFModel);
|
||||||
const [doc_id, setDocId] = useState('0')
|
const effects = useSelector((state: any) => state.loading.effects);
|
||||||
const [parser_id, setParserId] = useState('0')
|
const { data } = kFModel;
|
||||||
let navigate = useNavigate();
|
const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
|
||||||
const getKfList = (keywords?: string) => {
|
'getKfList',
|
||||||
const payload = {
|
'updateDocumentStatus',
|
||||||
kb_id,
|
]);
|
||||||
keywords
|
const [inputValue, setInputValue] = useState('');
|
||||||
}
|
const [doc_id, setDocId] = useState('0');
|
||||||
if (!keywords) {
|
const [parser_id, setParserId] = useState('0');
|
||||||
delete payload.keywords
|
let navigate = useNavigate();
|
||||||
}
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/getKfList',
|
|
||||||
payload
|
|
||||||
});
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
if (kb_id) {
|
|
||||||
getKfList()
|
|
||||||
}
|
|
||||||
}, [kb_id])
|
|
||||||
const debounceChange = debounce(getKfList, 300)
|
|
||||||
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
||||||
const value = e.target.value
|
|
||||||
setInputValue(value)
|
|
||||||
debounceCallback(e.target.value)
|
|
||||||
|
|
||||||
}
|
const getKfList = (keywords?: string) => {
|
||||||
const onChangeStatus = (e: boolean, doc_id: string) => {
|
const payload = {
|
||||||
dispatch({
|
kb_id,
|
||||||
type: 'kFModel/updateDocumentStatus',
|
keywords,
|
||||||
payload: {
|
|
||||||
doc_id,
|
|
||||||
status: Number(e)
|
|
||||||
},
|
|
||||||
callback() {
|
|
||||||
getKfList()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const onRmDocument = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/document_rm',
|
|
||||||
payload: {
|
|
||||||
doc_id
|
|
||||||
},
|
|
||||||
callback() {
|
|
||||||
getKfList()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
const showCEFModal = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCEFwModal: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
if (!keywords) {
|
||||||
const showSegmentSetModal = () => {
|
delete payload.keywords;
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowSegmentSetModal: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const actionItems: MenuProps['items'] = useMemo(() => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: (
|
|
||||||
<div>
|
|
||||||
<UploadFile kb_id={kb_id} getKfList={getKfList} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
label: (
|
|
||||||
<div>
|
|
||||||
<Button type="link" onClick={showCEFModal}> 导入虚拟文件</Button>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
// disabled: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}, [kb_id]);
|
|
||||||
const chunkItems: MenuProps['items'] = [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<Button type="link" onClick={showSegmentSetModal}> 分段设置</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
label: (
|
|
||||||
<div>
|
|
||||||
<Button type="link" onClick={onRmDocument}> 删除</Button>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
// disabled: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const toChunk = (id: string) => {
|
|
||||||
console.log(id)
|
|
||||||
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}&doc_id=${id}`);
|
|
||||||
}
|
}
|
||||||
const columns: ColumnsType<DataType> = [
|
dispatch({
|
||||||
{
|
type: 'kFModel/getKfList',
|
||||||
title: '名称',
|
payload,
|
||||||
dataIndex: 'name',
|
});
|
||||||
key: 'name',
|
};
|
||||||
render: (text: any, { id }) => <div className={styles.tochunks} onClick={() => toChunk(id)}><img className={styles.img} src='https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg' alt="" />{text}</div>,
|
|
||||||
className: `${styles.column}`
|
useEffect(() => {
|
||||||
},
|
if (kb_id) {
|
||||||
{
|
getKfList();
|
||||||
title: '数据总量',
|
}
|
||||||
dataIndex: 'chunk_num',
|
}, [kb_id]);
|
||||||
key: 'chunk_num',
|
|
||||||
className: `${styles.column}`
|
const debounceChange = debounce(getKfList, 300);
|
||||||
},
|
const debounceCallback = useCallback(
|
||||||
{
|
(value: string) => debounceChange(value),
|
||||||
title: 'Tokens',
|
[],
|
||||||
dataIndex: 'token_num',
|
);
|
||||||
key: 'token_num',
|
const handleInputChange = (
|
||||||
className: `${styles.column}`
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
},
|
) => {
|
||||||
{
|
const value = e.target.value;
|
||||||
title: '文件大小',
|
setInputValue(value);
|
||||||
dataIndex: 'size',
|
debounceCallback(e.target.value);
|
||||||
key: 'size',
|
};
|
||||||
className: `${styles.column}`
|
const onChangeStatus = (e: boolean, doc_id: string) => {
|
||||||
},
|
dispatch({
|
||||||
{
|
type: 'kFModel/updateDocumentStatus',
|
||||||
title: '状态',
|
payload: {
|
||||||
key: 'status',
|
doc_id,
|
||||||
dataIndex: 'status',
|
status: Number(e),
|
||||||
className: `${styles.column}`,
|
kb_id,
|
||||||
render: (_, { status: string, id }) => (
|
},
|
||||||
<>
|
});
|
||||||
<Switch defaultChecked={status === '1'} onChange={(e) => {
|
};
|
||||||
onChangeStatus(e, id)
|
const onRmDocument = () => {
|
||||||
}} />
|
dispatch({
|
||||||
</>
|
type: 'kFModel/document_rm',
|
||||||
),
|
payload: {
|
||||||
},
|
doc_id,
|
||||||
{
|
kb_id,
|
||||||
title: 'Action',
|
},
|
||||||
key: 'action',
|
});
|
||||||
className: `${styles.column}`,
|
};
|
||||||
render: (_, record) => (
|
const showCEFModal = () => {
|
||||||
<Space size="middle">
|
dispatch({
|
||||||
<Dropdown menu={{ items: chunkItems }} trigger={['click']}>
|
type: 'kFModel/updateState',
|
||||||
<a onClick={() => {
|
payload: {
|
||||||
setDocId(record.id)
|
isShowCEFwModal: true,
|
||||||
setParserId(record.parser_id)
|
},
|
||||||
}}>
|
});
|
||||||
分段设置 <DownOutlined />
|
};
|
||||||
</a>
|
|
||||||
</Dropdown>
|
const showSegmentSetModal = () => {
|
||||||
</Space>
|
dispatch({
|
||||||
),
|
type: 'kFModel/updateState',
|
||||||
},
|
payload: {
|
||||||
|
isShowSegmentSetModal: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const actionItems: MenuProps['items'] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
<UploadFile kb_id={kb_id} getKfList={getKfList} />
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
<Button type="link" onClick={showCEFModal}>
|
||||||
|
{' '}
|
||||||
|
导入虚拟文件
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
// disabled: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
return <>
|
}, [kb_id]);
|
||||||
<div className={styles.filter}>
|
const chunkItems: MenuProps['items'] = [
|
||||||
<div className="search">
|
{
|
||||||
<Input placeholder="搜索" value={inputValue} style={{ width: 220 }} allowClear onChange={handleInputChange} />
|
key: '1',
|
||||||
</div>
|
label: (
|
||||||
<div className="operate">
|
<div>
|
||||||
<Dropdown menu={{ items: actionItems }} trigger={['click']} >
|
<Button type="link" onClick={showSegmentSetModal}>
|
||||||
<a>
|
{' '}
|
||||||
导入文件 <DownOutlined />
|
分段设置
|
||||||
</a>
|
</Button>
|
||||||
</Dropdown>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Table rowKey='id' columns={columns} dataSource={data} loading={loading} pagination={false} scroll={{ scrollToFirstRowOnChange: true, x: true }} />
|
),
|
||||||
<CreateEPModal getKfList={getKfList} kb_id={kb_id} />
|
},
|
||||||
<SegmentSetModal getKfList={getKfList} parser_id={parser_id} doc_id={doc_id} />
|
{
|
||||||
|
key: '2',
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
<Button type="link" onClick={onRmDocument}>
|
||||||
|
{' '}
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
// disabled: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toChunk = (id: string) => {
|
||||||
|
console.log(id);
|
||||||
|
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}&doc_id=${id}`);
|
||||||
|
};
|
||||||
|
const columns: ColumnsType<DataType> = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
render: (text: any, { id }) => (
|
||||||
|
<div className={styles.tochunks} onClick={() => toChunk(id)}>
|
||||||
|
<img
|
||||||
|
className={styles.img}
|
||||||
|
src="https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
className: `${styles.column}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '数据总量',
|
||||||
|
dataIndex: 'chunk_num',
|
||||||
|
key: 'chunk_num',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Tokens',
|
||||||
|
dataIndex: 'token_num',
|
||||||
|
key: 'token_num',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '文件大小',
|
||||||
|
dataIndex: 'size',
|
||||||
|
key: 'size',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
dataIndex: 'status',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
render: (_, { status: string, id }) => (
|
||||||
|
<>
|
||||||
|
<Switch
|
||||||
|
defaultChecked={status === '1'}
|
||||||
|
onChange={(e) => {
|
||||||
|
onChangeStatus(e, id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
className: `${styles.column}`,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
<Dropdown menu={{ items: chunkItems }} trigger={['click']}>
|
||||||
|
<a
|
||||||
|
onClick={() => {
|
||||||
|
setDocId(record.id);
|
||||||
|
setParserId(record.parser_id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
分段设置 <DownOutlined />
|
||||||
|
</a>
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.filter}>
|
||||||
|
<div className="search">
|
||||||
|
<Input
|
||||||
|
placeholder="搜索"
|
||||||
|
value={inputValue}
|
||||||
|
style={{ width: 220 }}
|
||||||
|
allowClear
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="operate">
|
||||||
|
<Dropdown menu={{ items: actionItems }} trigger={['click']}>
|
||||||
|
<a>
|
||||||
|
导入文件 <DownOutlined />
|
||||||
|
</a>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Table
|
||||||
|
rowKey="id"
|
||||||
|
columns={columns}
|
||||||
|
dataSource={data}
|
||||||
|
loading={loading}
|
||||||
|
pagination={false}
|
||||||
|
scroll={{ scrollToFirstRowOnChange: true, x: true }}
|
||||||
|
/>
|
||||||
|
<CreateEPModal getKfList={getKfList} kb_id={kb_id} />
|
||||||
|
<SegmentSetModal
|
||||||
|
getKfList={getKfList}
|
||||||
|
parser_id={parser_id}
|
||||||
|
doc_id={doc_id}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ kFModel, loading }) => ({ kFModel, loading }))(Index);
|
export default KnowledgeFile;
|
||||||
|
@ -1,57 +1,47 @@
|
|||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { Effect, Reducer, Subscription } from 'umi';
|
import pick from 'lodash/pick';
|
||||||
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface kFModelState {
|
export interface KFModelState {
|
||||||
isShowCEFwModal: boolean;
|
isShowCEFwModal: boolean;
|
||||||
isShowTntModal: boolean;
|
isShowTntModal: boolean;
|
||||||
isShowSegmentSetModal: boolean;
|
isShowSegmentSetModal: boolean;
|
||||||
loading: boolean;
|
|
||||||
tenantIfo: any;
|
tenantIfo: any;
|
||||||
data: any[];
|
data: any[];
|
||||||
}
|
}
|
||||||
export interface kFModelType {
|
|
||||||
namespace: 'kFModel';
|
const model: DvaModel<KFModelState> = {
|
||||||
state: kFModelState;
|
|
||||||
effects: {
|
|
||||||
createKf: Effect;
|
|
||||||
updateKf: Effect;
|
|
||||||
getKfDetail: Effect;
|
|
||||||
getKfList: Effect;
|
|
||||||
updateDocumentStatus: Effect;
|
|
||||||
document_rm: Effect;
|
|
||||||
document_create: Effect;
|
|
||||||
document_change_parser: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<kFModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: kFModelType = {
|
|
||||||
namespace: 'kFModel',
|
namespace: 'kFModel',
|
||||||
state: {
|
state: {
|
||||||
isShowCEFwModal: false,
|
isShowCEFwModal: false,
|
||||||
isShowTntModal: false,
|
isShowTntModal: false,
|
||||||
isShowSegmentSetModal: false,
|
isShowSegmentSetModal: false,
|
||||||
loading: false,
|
|
||||||
tenantIfo: {},
|
tenantIfo: {},
|
||||||
data: [],
|
data: [],
|
||||||
},
|
},
|
||||||
|
reducers: {
|
||||||
|
updateState(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
subscriptions: {
|
subscriptions: {
|
||||||
setup({ dispatch, history }) {
|
setup({ dispatch, history }) {
|
||||||
history.listen((location) => {});
|
history.listen((location) => {});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
effects: {
|
effects: {
|
||||||
*createKf({ payload = {}, callback }, { call, put }) {
|
*createKf({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.createKb, payload);
|
const { data, response } = yield call(kbService.createKb, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
message.success('创建成功!');
|
message.success('创建成功!');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*updateKf({ payload = {}, callback }, { call, put }) {
|
*updateKf({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.updateKb, payload);
|
const { data, response } = yield call(kbService.updateKb, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
@ -67,23 +57,12 @@ const Model: kFModelType = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
*getKfList({ payload = {} }, { call, put }) {
|
*getKfList({ payload = {} }, { call, put }) {
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { data, response } = yield call(
|
const { data, response } = yield call(
|
||||||
kbService.get_document_list,
|
kbService.get_document_list,
|
||||||
payload,
|
payload,
|
||||||
);
|
);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
@ -93,64 +72,64 @@ const Model: kFModelType = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*updateDocumentStatus({ payload = {}, callback }, { call, put }) {
|
*updateDocumentStatus({ payload = {} }, { call, put }) {
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { data, response } = yield call(
|
const { data, response } = yield call(
|
||||||
kbService.document_change_status,
|
kbService.document_change_status,
|
||||||
payload,
|
pick(payload, ['doc_id', 'status']),
|
||||||
);
|
);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
message.success('修改成功!');
|
message.success('修改成功!');
|
||||||
yield put({
|
put({
|
||||||
type: 'updateState',
|
type: 'getKfList',
|
||||||
payload: {
|
payload: { kb_id: payload.kb_id },
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
callback && callback();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*document_rm({ payload = {}, callback }, { call, put }) {
|
*document_rm({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.document_rm, payload);
|
const { data, response } = yield call(kbService.document_rm, {
|
||||||
|
doc_id: payload.doc_id,
|
||||||
|
});
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
message.success('删除成功!');
|
message.success('删除成功!');
|
||||||
callback && callback();
|
put({
|
||||||
|
type: 'getKfList',
|
||||||
|
payload: { kb_id: payload.kb_id },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*document_create({ payload = {}, callback }, { call, put }) {
|
*document_create({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.document_create, payload);
|
const { data, response } = yield call(kbService.document_create, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
|
put({
|
||||||
|
type: 'kFModel/updateState',
|
||||||
|
payload: {
|
||||||
|
isShowCEFwModal: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
message.success('创建成功!');
|
message.success('创建成功!');
|
||||||
callback && callback();
|
|
||||||
}
|
}
|
||||||
|
return retcode;
|
||||||
},
|
},
|
||||||
*document_change_parser({ payload = {}, callback }, { call, put }) {
|
*document_change_parser({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(
|
const { data, response } = yield call(
|
||||||
kbService.document_change_parser,
|
kbService.document_change_parser,
|
||||||
payload,
|
payload,
|
||||||
);
|
);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
|
put({
|
||||||
|
type: 'updateState',
|
||||||
|
payload: {
|
||||||
|
isShowSegmentSetModal: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
message.success('修改成功!');
|
message.success('修改成功!');
|
||||||
callback && callback();
|
|
||||||
}
|
}
|
||||||
},
|
return retcode;
|
||||||
},
|
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,91 +1,87 @@
|
|||||||
import React from 'react';
|
import { Modal, Space, Tag } from 'antd';
|
||||||
import { connect, Dispatch } from 'umi';
|
import React, { useEffect, useState } from 'react';
|
||||||
import i18n from 'i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useTranslation, } from 'react-i18next'
|
import { useDispatch, useSelector } from 'umi';
|
||||||
import { Modal, Tag, Space } from 'antd'
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import type { kFModelState } from './model'
|
|
||||||
import type { settingModelState } from '@/pages/setting/model'
|
|
||||||
const { CheckableTag } = Tag;
|
const { CheckableTag } = Tag;
|
||||||
interface kFProps {
|
interface kFProps {
|
||||||
dispatch: Dispatch;
|
getKfList: () => void;
|
||||||
kFModel: kFModelState;
|
parser_id: string;
|
||||||
settingModel: settingModelState;
|
doc_id: string;
|
||||||
getKfList: () => void;
|
|
||||||
parser_id: string;
|
|
||||||
doc_id: string;
|
|
||||||
}
|
}
|
||||||
const Index: React.FC<kFProps> = ({ kFModel, settingModel, dispatch, getKfList, parser_id, doc_id }) => {
|
const SegmentSetModal: React.FC<kFProps> = ({
|
||||||
const [selectedTag, setSelectedTag] = useState('')
|
getKfList,
|
||||||
const { tenantIfo = {} } = settingModel
|
parser_id,
|
||||||
const { parser_ids = '' } = tenantIfo
|
doc_id,
|
||||||
useEffect(() => {
|
}) => {
|
||||||
dispatch({
|
const dispatch = useDispatch();
|
||||||
type: 'settingModel/getTenantInfo',
|
const kFModel = useSelector((state: any) => state.kFModel);
|
||||||
payload: {
|
const settingModel = useSelector((state: any) => state.settingModel);
|
||||||
}
|
const [selectedTag, setSelectedTag] = useState('');
|
||||||
});
|
const { tenantIfo = {} } = settingModel;
|
||||||
setSelectedTag(parser_id)
|
const { parser_ids = '' } = tenantIfo;
|
||||||
}, [parser_id])
|
const { isShowSegmentSetModal } = kFModel;
|
||||||
const { isShowSegmentSetModal } = kFModel
|
const { t } = useTranslation();
|
||||||
const { t } = useTranslation()
|
|
||||||
const handleCancel = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowSegmentSetModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const handleOk = () => {
|
|
||||||
console.log(1111, selectedTag)
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/document_change_parser',
|
|
||||||
payload: {
|
|
||||||
parser_id: selectedTag,
|
|
||||||
doc_id
|
|
||||||
},
|
|
||||||
callback: () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'kFModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowSegmentSetModal: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
getKfList && getKfList()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChange = (tag: string, checked: boolean) => {
|
useEffect(() => {
|
||||||
const nextSelectedTag = checked
|
dispatch({
|
||||||
? tag
|
type: 'settingModel/getTenantInfo',
|
||||||
: selectedTag;
|
payload: {},
|
||||||
console.log('You are interested in: ', nextSelectedTag);
|
});
|
||||||
setSelectedTag(nextSelectedTag);
|
setSelectedTag(parser_id);
|
||||||
};
|
}, [parser_id]);
|
||||||
|
|
||||||
return (
|
const handleCancel = () => {
|
||||||
<Modal title="Basic Modal" open={isShowSegmentSetModal} onOk={handleOk} onCancel={handleCancel}>
|
dispatch({
|
||||||
<Space size={[0, 8]} wrap>
|
type: 'kFModel/updateState',
|
||||||
<div className={styles.tags}>
|
payload: {
|
||||||
{
|
isShowSegmentSetModal: false,
|
||||||
parser_ids.split(',').map((tag: string) => {
|
},
|
||||||
return (<CheckableTag
|
});
|
||||||
key={tag}
|
};
|
||||||
checked={selectedTag === tag}
|
|
||||||
onChange={(checked) => handleChange(tag, checked)}
|
|
||||||
>
|
|
||||||
{tag}
|
|
||||||
</CheckableTag>)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</Modal >
|
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
console.log(1111, selectedTag);
|
||||||
|
const retcode = await dispatch<any>({
|
||||||
|
type: 'kFModel/document_change_parser',
|
||||||
|
payload: {
|
||||||
|
parser_id: selectedTag,
|
||||||
|
doc_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
);
|
retcode === 0 && getKfList && getKfList();
|
||||||
}
|
};
|
||||||
export default connect(({ kFModel, settingModel, loading }) => ({ kFModel, settingModel, loading }))(Index);
|
|
||||||
|
const handleChange = (tag: string, checked: boolean) => {
|
||||||
|
const nextSelectedTag = checked ? tag : selectedTag;
|
||||||
|
console.log('You are interested in: ', nextSelectedTag);
|
||||||
|
setSelectedTag(nextSelectedTag);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="Basic Modal"
|
||||||
|
open={isShowSegmentSetModal}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
>
|
||||||
|
<Space size={[0, 8]} wrap>
|
||||||
|
<div className={styles.tags}>
|
||||||
|
{parser_ids.split(',').map((tag: string) => {
|
||||||
|
return (
|
||||||
|
<CheckableTag
|
||||||
|
key={tag}
|
||||||
|
checked={selectedTag === tag}
|
||||||
|
onChange={(checked) => handleChange(tag, checked)}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</CheckableTag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default SegmentSetModal;
|
||||||
|
@ -1,33 +1,39 @@
|
|||||||
import React from 'react';
|
import uploadService from '@/services/uploadService';
|
||||||
import { connect } from 'umi'
|
|
||||||
import type { UploadProps } from 'antd';
|
import type { UploadProps } from 'antd';
|
||||||
import { Button, Upload } from 'antd';
|
import { Button, Upload } from 'antd';
|
||||||
import uploadService from '@/services/uploadService'
|
import React from 'react';
|
||||||
interface PropsType {
|
interface PropsType {
|
||||||
kb_id: string;
|
kb_id: string;
|
||||||
getKfList: () => void
|
getKfList: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type UploadRequestOption = Parameters<
|
type UploadRequestOption = Parameters<
|
||||||
NonNullable<UploadProps["customRequest"]>
|
NonNullable<UploadProps['customRequest']>
|
||||||
>[0];
|
>[0];
|
||||||
const Index: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
|
||||||
const createRequest: (props: UploadRequestOption) => void = async function ({ file, onSuccess, onError }) {
|
|
||||||
const { retcode, data } = await uploadService.uploadFile(file, kb_id);
|
|
||||||
if (retcode === 0) {
|
|
||||||
onSuccess && onSuccess(data, file);
|
|
||||||
|
|
||||||
} else {
|
const FileUpload: React.FC<PropsType> = ({ kb_id, getKfList }) => {
|
||||||
onError && onError(data);
|
const createRequest: (props: UploadRequestOption) => void = async function ({
|
||||||
}
|
file,
|
||||||
getKfList && getKfList()
|
onSuccess,
|
||||||
};
|
onError,
|
||||||
const uploadProps: UploadProps = {
|
}) {
|
||||||
customRequest: createRequest,
|
const { retcode, data } = await uploadService.uploadFile(file, kb_id);
|
||||||
showUploadList: false,
|
if (retcode === 0) {
|
||||||
};
|
onSuccess && onSuccess(data, file);
|
||||||
return (<Upload {...uploadProps} >
|
} else {
|
||||||
<Button type="link">导入文件</Button>
|
onError && onError(data);
|
||||||
</Upload>)
|
}
|
||||||
}
|
getKfList && getKfList();
|
||||||
|
};
|
||||||
|
const uploadProps: UploadProps = {
|
||||||
|
customRequest: createRequest,
|
||||||
|
showUploadList: false,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Upload {...uploadProps}>
|
||||||
|
<Button type="link">导入文件</Button>
|
||||||
|
</Upload>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default connect(({ kFModel, settingModel, loading }) => ({ kFModel, settingModel, loading }))(Index);
|
export default FileUpload;
|
||||||
|
@ -1,247 +1,278 @@
|
|||||||
import React, { useEffect, useState, useCallback, } from 'react';
|
import { api_host } from '@/utils/api';
|
||||||
import { useNavigate, connect, Dispatch } from 'umi'
|
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
|
||||||
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
|
|
||||||
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
|
|
||||||
import type { PaginationProps } from 'antd';
|
import type { PaginationProps } from 'antd';
|
||||||
import { api_host } from '@/utils/api'
|
import {
|
||||||
import CreateModal from '../knowledge-chunk/components/createModal'
|
Card,
|
||||||
|
Col,
|
||||||
|
Input,
|
||||||
|
Pagination,
|
||||||
|
Popconfirm,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Spin,
|
||||||
|
Switch,
|
||||||
|
} from 'antd';
|
||||||
|
import React, { useCallback, useEffect } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'umi';
|
||||||
|
import CreateModal from '../knowledge-chunk/components/createModal';
|
||||||
|
|
||||||
|
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||||
import styles from './index.less'
|
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import type { kSearchModelState } from './model'
|
import styles from './index.less';
|
||||||
import type { chunkModelState } from '../knowledge-chunk/model'
|
|
||||||
interface chunkProps {
|
interface chunkProps {
|
||||||
dispatch: Dispatch;
|
kb_id: string;
|
||||||
kSearchModel: kSearchModelState;
|
|
||||||
chunkModel: chunkModelState;
|
|
||||||
kb_id: string
|
|
||||||
}
|
}
|
||||||
const Index: React.FC<chunkProps> = ({ kSearchModel, chunkModel, dispatch, kb_id }) => {
|
|
||||||
|
|
||||||
const { data = [], total, loading, d_list = [], question, doc_ids, pagination, } = kSearchModel
|
const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => {
|
||||||
const { chunk_id, doc_id, isShowCreateModal } = chunkModel
|
const dispatch = useDispatch();
|
||||||
|
const kSearchModel = useSelector((state: any) => state.kSearchModel);
|
||||||
|
const chunkModel = useSelector((state: any) => state.chunkModel);
|
||||||
|
const loading = useOneNamespaceEffectsLoading('kSearchModel', [
|
||||||
|
'chunk_list',
|
||||||
|
'switch_chunk',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data = [],
|
||||||
|
total,
|
||||||
|
d_list = [],
|
||||||
|
question,
|
||||||
|
doc_ids,
|
||||||
|
pagination,
|
||||||
|
} = kSearchModel;
|
||||||
|
const { chunk_id, doc_id, isShowCreateModal } = chunkModel;
|
||||||
|
|
||||||
const getChunkList = () => {
|
const getChunkList = () => {
|
||||||
dispatch({
|
|
||||||
type: 'kSearchModel/updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
interface payloadType {
|
|
||||||
kb_id: string;
|
|
||||||
question?: string;
|
|
||||||
doc_ids: any[];
|
|
||||||
similarity_threshold?: number
|
|
||||||
}
|
|
||||||
const payload: payloadType = {
|
|
||||||
kb_id,
|
|
||||||
question,
|
|
||||||
doc_ids,
|
|
||||||
similarity_threshold: 0.1
|
|
||||||
}
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/chunk_list',
|
type: 'kSearchModel/chunk_list',
|
||||||
payload: {
|
payload: {
|
||||||
...payload,
|
kb_id,
|
||||||
...pagination
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
const confirm = (id: string) => {
|
const confirm = (id: string) => {
|
||||||
console.log(id)
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/rm_chunk',
|
type: 'kSearchModel/rm_chunk',
|
||||||
payload: {
|
payload: {
|
||||||
chunk_ids: [id]
|
chunk_ids: [id],
|
||||||
|
kb_id,
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleEditchunk = (item: any) => {
|
const handleEditchunk = (item: any) => {
|
||||||
const { chunk_id, doc_id } = item
|
const { chunk_id, doc_id } = item;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'chunkModel/updateState',
|
type: 'chunkModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
isShowCreateModal: true,
|
isShowCreateModal: true,
|
||||||
chunk_id,
|
chunk_id,
|
||||||
doc_id
|
doc_id,
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
}
|
getChunkList();
|
||||||
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
|
};
|
||||||
|
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/updateState',
|
type: 'kSearchModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
pagination: { page, size }
|
pagination: { page, size },
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/updateState',
|
type: 'kSearchModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
loading: false,
|
|
||||||
doc_ids: [],
|
doc_ids: [],
|
||||||
question: ""
|
question: '',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/getKfList',
|
type: 'kSearchModel/getKfList',
|
||||||
payload: {
|
payload: {
|
||||||
kb_id
|
kb_id,
|
||||||
}
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
}, [])
|
}, []);
|
||||||
const switchChunk = (item: any, available_int: boolean) => {
|
const switchChunk = (item: any, available_int: boolean) => {
|
||||||
const { chunk_id, doc_id } = item
|
const { chunk_id, doc_id } = item;
|
||||||
dispatch({
|
|
||||||
type: 'kSearchModel/updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/switch_chunk',
|
type: 'kSearchModel/switch_chunk',
|
||||||
payload: {
|
payload: {
|
||||||
chunk_ids: [chunk_id],
|
chunk_ids: [chunk_id],
|
||||||
doc_id,
|
doc_id,
|
||||||
available_int
|
available_int,
|
||||||
|
kb_id,
|
||||||
},
|
},
|
||||||
callback: getChunkList
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getChunkList()
|
getChunkList();
|
||||||
}, [doc_ids, pagination, question])
|
}, [doc_ids, pagination, question]);
|
||||||
const debounceChange = debounce((value) => {
|
const debounceChange = debounce((value) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/updateState',
|
type: 'kSearchModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
question: value
|
question: value,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, 300)
|
}, 300);
|
||||||
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const debounceCallback = useCallback(
|
||||||
const value = e.target.value
|
(value: string) => debounceChange(value),
|
||||||
debounceCallback(value)
|
[],
|
||||||
}
|
);
|
||||||
const handleSelectChange = (value:
|
const handleInputChange = (
|
||||||
any[]) => {
|
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||||
|
) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
debounceCallback(value);
|
||||||
|
};
|
||||||
|
const handleSelectChange = (value: any[]) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'kSearchModel/updateState',
|
type: 'kSearchModel/updateState',
|
||||||
payload: {
|
payload: {
|
||||||
doc_ids: value
|
doc_ids: value,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
console.log('loading', loading)
|
|
||||||
return (<>
|
|
||||||
<div className={styles.chunkPage}>
|
|
||||||
<div className={styles.filter}>
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
placeholder="文件列表"
|
|
||||||
optionFilterProp="children"
|
|
||||||
onChange={handleSelectChange}
|
|
||||||
style={{ width: 300, marginBottom: 20 }}
|
|
||||||
options={d_list}
|
|
||||||
fieldNames={{ label: 'name', value: 'id' }}
|
|
||||||
mode='multiple'
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input.TextArea autoSize={{ minRows: 6, maxRows: 6 }} placeholder="搜索" style={{ width: 300 }} allowClear onChange={handleInputChange} />
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.chunkPage}>
|
||||||
|
<div className={styles.filter}>
|
||||||
|
<Select
|
||||||
|
showSearch
|
||||||
|
placeholder="文件列表"
|
||||||
|
optionFilterProp="children"
|
||||||
|
onChange={handleSelectChange}
|
||||||
|
style={{ width: 300, marginBottom: 20 }}
|
||||||
|
options={d_list}
|
||||||
|
fieldNames={{ label: 'name', value: 'id' }}
|
||||||
|
mode="multiple"
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
<Input.TextArea
|
||||||
<div className={styles.pageContainer}>
|
autoSize={{ minRows: 6, maxRows: 6 }}
|
||||||
<div className={styles.pageContent}>
|
placeholder="搜索"
|
||||||
<Spin spinning={loading} className={styles.spin} size='large'>
|
style={{ width: 300 }}
|
||||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }} >
|
allowClear
|
||||||
{
|
onChange={handleInputChange}
|
||||||
data.map((item: any) => {
|
|
||||||
return (<Col className="gutter-row" key={item.chunk_id} xs={24} sm={12} md={12} lg={8}>
|
|
||||||
<Card className={styles.card}
|
|
||||||
onClick={() => { handleEditchunk(item) }}
|
|
||||||
>
|
|
||||||
<img style={{ width: '50px' }} src={`${api_host}/document/image/${item.img_id}`} alt="" />
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<span className={styles.context}>
|
|
||||||
{item.content_ltks}
|
|
||||||
</span>
|
|
||||||
<span className={styles.delete}>
|
|
||||||
<Switch size="small" defaultValue={item.doc_ids == '1'} onChange={(checked: boolean, e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.nativeEvent.stopImmediatePropagation(); switchChunk(item, checked)
|
|
||||||
}} />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.footer}>
|
|
||||||
<span className={styles.text}>
|
|
||||||
<MinusSquareOutlined />{item.doc_num}文档
|
|
||||||
</span>
|
|
||||||
<span className={styles.text}>
|
|
||||||
<MinusSquareOutlined />{item.chunk_num}个
|
|
||||||
</span>
|
|
||||||
<span className={styles.text}>
|
|
||||||
<MinusSquareOutlined />{item.token_num}千字符
|
|
||||||
</span>
|
|
||||||
<span style={{ float: 'right' }}>
|
|
||||||
<Popconfirm
|
|
||||||
title="Delete the task"
|
|
||||||
description="Are you sure to delete this task?"
|
|
||||||
onConfirm={(e: any) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.nativeEvent.stopImmediatePropagation()
|
|
||||||
console.log(confirm)
|
|
||||||
confirm(item.chunk_id)
|
|
||||||
|
|
||||||
}}
|
|
||||||
okText="Yes"
|
|
||||||
cancelText="No"
|
|
||||||
>
|
|
||||||
<DeleteOutlined onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
e.nativeEvent.stopImmediatePropagation()
|
|
||||||
}} />
|
|
||||||
</Popconfirm>
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Row>
|
|
||||||
</Spin>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div className={styles.pageFooter}>
|
|
||||||
<Pagination
|
|
||||||
responsive
|
|
||||||
showLessItems
|
|
||||||
showQuickJumper
|
|
||||||
showSizeChanger
|
|
||||||
onChange={onShowSizeChange}
|
|
||||||
defaultPageSize={30}
|
|
||||||
pageSizeOptions={[30, 60, 90]}
|
|
||||||
defaultCurrent={pagination.page}
|
|
||||||
total={total}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className={styles.pageContainer}>
|
||||||
|
<div className={styles.pageContent}>
|
||||||
|
<Spin spinning={loading} className={styles.spin} size="large">
|
||||||
|
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 24 }}>
|
||||||
|
{data.map((item: any) => {
|
||||||
|
return (
|
||||||
|
<Col
|
||||||
|
className="gutter-row"
|
||||||
|
key={item.chunk_id}
|
||||||
|
xs={24}
|
||||||
|
sm={12}
|
||||||
|
md={12}
|
||||||
|
lg={8}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
className={styles.card}
|
||||||
|
onClick={() => {
|
||||||
|
handleEditchunk(item);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
style={{ width: '50px' }}
|
||||||
|
src={`${api_host}/document/image/${item.img_id}`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<span className={styles.context}>
|
||||||
|
{item.content_ltks}
|
||||||
|
</span>
|
||||||
|
<span className={styles.delete}>
|
||||||
|
<Switch
|
||||||
|
size="small"
|
||||||
|
defaultValue={item.doc_ids == '1'}
|
||||||
|
onChange={(checked: boolean, e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
switchChunk(item, checked);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.footer}>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.doc_num}文档
|
||||||
|
</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.chunk_num}个
|
||||||
|
</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
<MinusSquareOutlined />
|
||||||
|
{item.token_num}千字符
|
||||||
|
</span>
|
||||||
|
<span style={{ float: 'right' }}>
|
||||||
|
<Popconfirm
|
||||||
|
title="Delete the task"
|
||||||
|
description="Are you sure to delete this task?"
|
||||||
|
onConfirm={(e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
console.log(confirm);
|
||||||
|
confirm(item.chunk_id);
|
||||||
|
}}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<DeleteOutlined
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.nativeEvent.stopImmediatePropagation();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popconfirm>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Row>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
<div className={styles.pageFooter}>
|
||||||
|
<Pagination
|
||||||
|
responsive
|
||||||
|
showLessItems
|
||||||
|
showQuickJumper
|
||||||
|
showSizeChanger
|
||||||
|
onChange={onShowSizeChange}
|
||||||
|
defaultPageSize={30}
|
||||||
|
pageSizeOptions={[30, 60, 90]}
|
||||||
|
defaultCurrent={pagination.page}
|
||||||
|
total={total}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<CreateModal
|
||||||
</div >
|
getChunkList={getChunkList}
|
||||||
<CreateModal getChunkList={getChunkList} isShowCreateModal={isShowCreateModal} chunk_id={chunk_id} doc_id={doc_id} />
|
isShowCreateModal={isShowCreateModal}
|
||||||
</>
|
chunk_id={chunk_id}
|
||||||
)
|
doc_id={doc_id}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ kSearchModel, chunkModel, loading }) => ({ kSearchModel, chunkModel, loading }))(Index);
|
export default KnowledgeSearching;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Effect, Reducer, Subscription } from 'umi'
|
|
||||||
import { message } from 'antd';
|
|
||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
|
import omit from 'lodash/omit';
|
||||||
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface kSearchModelState {
|
export interface KSearchModelState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
data: any[];
|
data: any[];
|
||||||
total: number;
|
total: number;
|
||||||
@ -13,26 +13,10 @@ export interface kSearchModelState {
|
|||||||
question: string;
|
question: string;
|
||||||
doc_ids: any[];
|
doc_ids: any[];
|
||||||
pagination: any;
|
pagination: any;
|
||||||
doc_id: string
|
doc_id: string;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
const model: DvaModel<KSearchModelState> = {
|
||||||
export interface chunkgModelType {
|
|
||||||
namespace: 'kSearchModel';
|
|
||||||
state: kSearchModelState;
|
|
||||||
effects: {
|
|
||||||
chunk_list: Effect;
|
|
||||||
get_chunk: Effect;
|
|
||||||
create_hunk: Effect;
|
|
||||||
switch_chunk: Effect;
|
|
||||||
rm_chunk: Effect;
|
|
||||||
getKfList: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<kSearchModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: chunkgModelType = {
|
|
||||||
namespace: 'kSearchModel',
|
namespace: 'kSearchModel',
|
||||||
state: {
|
state: {
|
||||||
loading: false,
|
loading: false,
|
||||||
@ -45,114 +29,132 @@ const Model: chunkgModelType = {
|
|||||||
question: '',
|
question: '',
|
||||||
doc_ids: [],
|
doc_ids: [],
|
||||||
pagination: { page: 1, size: 30 },
|
pagination: { page: 1, size: 30 },
|
||||||
doc_id: ''
|
doc_id: '',
|
||||||
|
},
|
||||||
|
reducers: {
|
||||||
|
updateState(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
subscriptions: {
|
subscriptions: {
|
||||||
setup({ dispatch, history }) {
|
setup({ dispatch, history }) {
|
||||||
history.listen(location => {
|
history.listen((location) => {
|
||||||
console.log(location)
|
console.log(location);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
effects: {
|
effects: {
|
||||||
*getKfList({ payload = {} }, { call, put }) {
|
*getKfList({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.get_document_list, payload);
|
const { data, response } = yield call(
|
||||||
|
kbService.get_document_list,
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
|
||||||
const { retcode, data: res, retmsg } = data
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
d_list: res
|
d_list: res,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
* chunk_list({ payload = {}, callback }, { call, put }) {
|
*chunk_list({ payload = {} }, { call, put, select }) {
|
||||||
const { data, response } = yield call(kbService.retrieval_test, payload);
|
const { question, doc_ids, pagination }: KSearchModelState = yield select(
|
||||||
const { retcode, data: res, retmsg } = data
|
(state: any) => state.kSearchModel,
|
||||||
|
);
|
||||||
|
const { data } = yield call(kbService.retrieval_test, {
|
||||||
|
...payload,
|
||||||
|
...pagination,
|
||||||
|
question,
|
||||||
|
doc_ids,
|
||||||
|
similarity_threshold: 0.1,
|
||||||
|
});
|
||||||
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
console.log(res)
|
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
data: res.chunks,
|
data: res.chunks,
|
||||||
total: res.total,
|
total: res.total,
|
||||||
loading: false
|
},
|
||||||
}
|
|
||||||
});
|
});
|
||||||
callback && callback()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*switch_chunk({ payload = {}, callback }, { call, put }) {
|
*switch_chunk({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.switch_chunk, payload);
|
const { data } = yield call(
|
||||||
const { retcode, data: res, retmsg } = data
|
kbService.switch_chunk,
|
||||||
|
omit(payload, ['kb_id']),
|
||||||
|
);
|
||||||
|
const { retcode } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
callback && callback()
|
yield put({
|
||||||
|
type: 'chunk_list',
|
||||||
|
payload: {
|
||||||
|
kb_id: payload.kb_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*rm_chunk({ payload = {}, callback }, { call, put }) {
|
*rm_chunk({ payload = {} }, { call, put }) {
|
||||||
console.log('shanchu')
|
const { data } = yield call(kbService.rm_chunk, {
|
||||||
const { data, response } = yield call(kbService.rm_chunk, payload);
|
chunk_ids: payload.chunk_ids,
|
||||||
const { retcode, data: res, retmsg } = data
|
});
|
||||||
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
callback && callback()
|
// TODO: Can be extracted
|
||||||
|
yield put({
|
||||||
|
type: 'chunk_list',
|
||||||
|
payload: {
|
||||||
|
kb_id: payload.kb_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
* get_chunk({ payload = {}, callback }, { call, put }) {
|
*get_chunk({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.get_chunk, payload);
|
const { data, response } = yield call(kbService.get_chunk, payload);
|
||||||
const { retcode, data: res, retmsg } = data
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
|
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
chunkInfo: res
|
chunkInfo: res,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
callback && callback(res)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*create_hunk({ payload = {} }, { call, put }) {
|
*create_hunk({ payload = {} }, { call, put }) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
loading: true
|
loading: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
let service = kbService.create_chunk
|
let service = kbService.create_chunk;
|
||||||
if (payload.chunk_id) {
|
if (payload.chunk_id) {
|
||||||
service = kbService.set_chunk
|
service = kbService.set_chunk;
|
||||||
}
|
}
|
||||||
const { data, response } = yield call(service, payload);
|
const { data, response } = yield call(service, payload);
|
||||||
const { retcode, data: res, retmsg } = data
|
const { retcode, data: res, retmsg } = data;
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
loading: false
|
loading: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
isShowCreateModal: false
|
isShowCreateModal: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,170 +1,157 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import { Button, Form, Input, Radio, Select, Space, Tag } from 'antd';
|
||||||
import { useNavigate, connect, Dispatch } from 'umi'
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { Button, Form, Input, Radio, Select, Tag, Space, } from 'antd';
|
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
import type { kSModelState } from './model'
|
import styles from './index.less';
|
||||||
import type { settingModelState } from '@/pages/setting/model'
|
|
||||||
import styles from './index.less'
|
|
||||||
const { CheckableTag } = Tag;
|
const { CheckableTag } = Tag;
|
||||||
const layout = {
|
const layout = {
|
||||||
labelCol: { span: 8 },
|
labelCol: { span: 8 },
|
||||||
wrapperCol: { span: 16 },
|
wrapperCol: { span: 16 },
|
||||||
labelAlign: 'left' as const
|
labelAlign: 'left' as const,
|
||||||
};
|
};
|
||||||
const { Option } = Select
|
const { Option } = Select;
|
||||||
/* eslint-disable no-template-curly-in-string */
|
/* eslint-disable no-template-curly-in-string */
|
||||||
|
|
||||||
interface kSProps {
|
interface kSProps {
|
||||||
dispatch: Dispatch;
|
kb_id: string;
|
||||||
kSModel: kSModelState;
|
|
||||||
settingModel: settingModelState;
|
|
||||||
kb_id: string
|
|
||||||
}
|
}
|
||||||
const Index: React.FC<kSProps> = ({ settingModel, kSModel, dispatch, kb_id }) => {
|
const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => {
|
||||||
let navigate = useNavigate();
|
const dispatch = useDispatch();
|
||||||
const { tenantIfo = {} } = settingModel
|
const settingModel = useSelector((state: any) => state.settingModel);
|
||||||
const { parser_ids = '', embd_id = '' } = tenantIfo
|
let navigate = useNavigate();
|
||||||
const [form] = Form.useForm();
|
const { tenantIfo = {} } = settingModel;
|
||||||
|
const { parser_ids = '', embd_id = '' } = tenantIfo;
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [selectedTag, setSelectedTag] = useState('');
|
||||||
|
const values = Form.useWatch([], form);
|
||||||
|
|
||||||
useEffect(() => {
|
const getTenantInfo = useCallback(async () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'settingModel/getTenantInfo',
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
if (kb_id) {
|
||||||
|
const data = await dispatch<any>({
|
||||||
|
type: 'kSModel/getKbDetail',
|
||||||
|
payload: {
|
||||||
|
kb_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (data.retcode === 0) {
|
||||||
|
const { description, name, permission, embd_id } = data.data;
|
||||||
|
form.setFieldsValue({ description, name, permission, embd_id });
|
||||||
|
setSelectedTag(data.data.parser_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [kb_id]);
|
||||||
|
|
||||||
|
const onFinish = async () => {
|
||||||
|
try {
|
||||||
|
await form.validateFields();
|
||||||
|
|
||||||
|
if (kb_id) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'settingModel/getTenantInfo',
|
type: 'kSModel/updateKb',
|
||||||
payload: {
|
payload: {
|
||||||
}
|
...values,
|
||||||
|
parser_id: selectedTag,
|
||||||
|
kb_id,
|
||||||
|
embd_id: undefined,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
if (kb_id) {
|
} else {
|
||||||
|
const retcode = await dispatch<any>({
|
||||||
|
type: 'kSModel/createKb',
|
||||||
|
payload: {
|
||||||
|
...values,
|
||||||
|
parser_id: selectedTag,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
retcode === 0 &&
|
||||||
|
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
dispatch({
|
useEffect(() => {
|
||||||
type: 'kSModel/getKbDetail',
|
getTenantInfo();
|
||||||
payload: {
|
}, [getTenantInfo]);
|
||||||
kb_id
|
|
||||||
},
|
|
||||||
callback(detail: any) {
|
|
||||||
console.log(detail)
|
|
||||||
const { description, name, permission, embd_id } = detail
|
|
||||||
form.setFieldsValue({ description, name, permission, embd_id })
|
|
||||||
setSelectedTag(detail.parser_id)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [kb_id])
|
const handleChange = (tag: string, checked: boolean) => {
|
||||||
const [selectedTag, setSelectedTag] = useState('')
|
const nextSelectedTag = checked ? tag : selectedTag;
|
||||||
const values = Form.useWatch([], form);
|
console.log('You are interested in: ', nextSelectedTag);
|
||||||
console.log(values, '......变化')
|
setSelectedTag(nextSelectedTag);
|
||||||
const onFinish = () => {
|
};
|
||||||
form.validateFields().then(
|
|
||||||
() => {
|
|
||||||
if (kb_id) {
|
|
||||||
dispatch({
|
|
||||||
type: 'kSModel/updateKb',
|
|
||||||
payload: {
|
|
||||||
...values,
|
|
||||||
parser_id: selectedTag,
|
|
||||||
kb_id,
|
|
||||||
embd_id: undefined
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
dispatch({
|
|
||||||
type: 'kSModel/createKb',
|
|
||||||
payload: {
|
|
||||||
...values,
|
|
||||||
parser_id: selectedTag
|
|
||||||
},
|
|
||||||
callback(id: string) {
|
|
||||||
navigate(`/knowledge/add/setting?activeKey=file&id=${kb_id}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
|
|
||||||
},
|
return (
|
||||||
);
|
<Form
|
||||||
|
{...layout}
|
||||||
|
form={form}
|
||||||
|
name="validateOnly"
|
||||||
};
|
style={{ maxWidth: 1000, padding: 14 }}
|
||||||
|
|
||||||
const handleChange = (tag: string, checked: boolean) => {
|
|
||||||
const nextSelectedTag = checked
|
|
||||||
? tag
|
|
||||||
: selectedTag;
|
|
||||||
console.log('You are interested in: ', nextSelectedTag);
|
|
||||||
setSelectedTag(nextSelectedTag);
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Form
|
|
||||||
{...layout}
|
|
||||||
form={form}
|
|
||||||
name="validateOnly"
|
|
||||||
style={{ maxWidth: 1000, padding: 14 }}
|
|
||||||
>
|
>
|
||||||
<Form.Item name='name' label="知识库名称" rules={[{ required: true }]}>
|
<Form.Item name="name" label="知识库名称" rules={[{ required: true }]}>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name='description' label="知识库描述">
|
<Form.Item name="description" label="知识库描述">
|
||||||
<Input.TextArea />
|
<Input.TextArea />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="permission" label="可见权限">
|
<Form.Item name="permission" label="可见权限">
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
<Radio value="me">只有我</Radio>
|
<Radio value="me">只有我</Radio>
|
||||||
<Radio value="team">所有团队成员</Radio>
|
<Radio value="team">所有团队成员</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="embd_id"
|
name="embd_id"
|
||||||
label="Embedding 模型"
|
label="Embedding 模型"
|
||||||
hasFeedback
|
hasFeedback
|
||||||
rules={[{ required: true, message: 'Please select your country!' }]}
|
rules={[{ required: true, message: 'Please select your country!' }]}
|
||||||
>
|
>
|
||||||
<Select placeholder="Please select a country" >
|
<Select placeholder="Please select a country">
|
||||||
{embd_id.split(',').map((item: string) => {
|
{embd_id.split(',').map((item: string) => {
|
||||||
return <Option value={item} key={item}>{item}</Option>
|
return (
|
||||||
})}
|
<Option value={item} key={item}>
|
||||||
|
{item}
|
||||||
</Select>
|
</Option>
|
||||||
</Form.Item>
|
);
|
||||||
<div style={{ marginTop: '5px' }}>
|
})}
|
||||||
修改Embedding 模型,请去<span style={{ color: '#1677ff' }}>设置</span>
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<div style={{ marginTop: '5px' }}>
|
||||||
|
修改Embedding 模型,请去<span style={{ color: '#1677ff' }}>设置</span>
|
||||||
|
</div>
|
||||||
|
<Space size={[0, 8]} wrap>
|
||||||
|
<div className={styles.tags}>
|
||||||
|
{parser_ids.split(',').map((tag: string) => {
|
||||||
|
return (
|
||||||
|
<CheckableTag
|
||||||
|
key={tag}
|
||||||
|
checked={selectedTag === tag}
|
||||||
|
onChange={(checked) => handleChange(tag, checked)}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</CheckableTag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<Space size={[0, 8]} wrap>
|
</Space>
|
||||||
<div className={styles.tags}>
|
<Space size={[0, 8]} wrap></Space>
|
||||||
{
|
<div className={styles.preset}>
|
||||||
parser_ids.split(',').map((tag: string) => {
|
<div className={styles.left}>xxxxx文章</div>
|
||||||
return (<CheckableTag
|
<div className={styles.right}>预估份数</div>
|
||||||
key={tag}
|
</div>
|
||||||
checked={selectedTag === tag}
|
<Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
|
||||||
onChange={(checked) => handleChange(tag, checked)}
|
<Button type="primary" onClick={onFinish}>
|
||||||
>
|
保存并处理
|
||||||
{tag}
|
</Button>
|
||||||
</CheckableTag>)
|
<Button htmlType="button" style={{ marginLeft: '20px' }}>
|
||||||
})
|
取消
|
||||||
}
|
</Button>
|
||||||
</div>
|
</Form.Item>
|
||||||
</Space>
|
|
||||||
<Space size={[0, 8]} wrap>
|
|
||||||
|
|
||||||
</Space>
|
|
||||||
<div className={styles.preset}>
|
|
||||||
<div className={styles.left}>
|
|
||||||
xxxxx文章
|
|
||||||
</div>
|
|
||||||
<div className={styles.right}>
|
|
||||||
预估份数
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Form.Item wrapperCol={{ ...layout.wrapperCol, offset: 8 }}>
|
|
||||||
<Button type="primary" onClick={onFinish}>
|
|
||||||
保存并处理
|
|
||||||
</Button>
|
|
||||||
<Button htmlType="button" style={{ marginLeft: '20px' }}>
|
|
||||||
取消
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
</Form>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KnowledgeSetting;
|
||||||
|
|
||||||
export default connect(({ settingModel, kSModel, loading }) => ({ settingModel, kSModel, loading }))(Index);
|
|
||||||
|
@ -1,72 +1,54 @@
|
|||||||
import { message } from 'antd';
|
|
||||||
import { Effect, Reducer, Subscription } from 'umi'
|
|
||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface kSModelState {
|
export interface KSModelState {
|
||||||
isShowPSwModal: boolean;
|
isShowPSwModal: boolean;
|
||||||
isShowTntModal: boolean;
|
isShowTntModal: boolean;
|
||||||
loading: boolean;
|
tenantIfo: any;
|
||||||
tenantIfo: any
|
|
||||||
}
|
}
|
||||||
export interface kSModelType {
|
|
||||||
namespace: 'kSModel';
|
const model: DvaModel<KSModelState> = {
|
||||||
state: kSModelState;
|
|
||||||
effects: {
|
|
||||||
createKb: Effect;
|
|
||||||
updateKb: Effect;
|
|
||||||
getKbDetail: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<kSModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: kSModelType = {
|
|
||||||
namespace: 'kSModel',
|
namespace: 'kSModel',
|
||||||
state: {
|
state: {
|
||||||
isShowPSwModal: false,
|
isShowPSwModal: false,
|
||||||
isShowTntModal: false,
|
isShowTntModal: false,
|
||||||
loading: false,
|
tenantIfo: {},
|
||||||
tenantIfo: {}
|
|
||||||
},
|
|
||||||
subscriptions: {
|
|
||||||
setup({ dispatch, history }) {
|
|
||||||
history.listen(location => {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
effects: {
|
|
||||||
* createKb({ payload = {}, callback }, { call, put }) {
|
|
||||||
const { data, response } = yield call(kbService.createKb, payload);
|
|
||||||
const { retcode, data: res, retmsg } = data
|
|
||||||
if (retcode === 0) {
|
|
||||||
message.success('创建知识库成功!');
|
|
||||||
callback && callback(res.kb_id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
* updateKb({ payload = {}, callback }, { call, put }) {
|
|
||||||
const { data, response } = yield call(kbService.updateKb, payload);
|
|
||||||
const { retcode, data: res, retmsg } = data
|
|
||||||
if (retcode === 0) {
|
|
||||||
message.success('更新知识库成功!');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
*getKbDetail({ payload = {}, callback }, { call, put }) {
|
|
||||||
const { data, response } = yield call(kbService.get_kb_detail, payload);
|
|
||||||
const { retcode, data: res, retmsg } = data
|
|
||||||
if (retcode === 0) {
|
|
||||||
// localStorage.setItem('userInfo',res.)
|
|
||||||
callback && callback(res)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
updateState(state, { payload }) {
|
updateState(state, { payload }) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
...payload
|
...payload,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
subscriptions: {
|
||||||
|
setup({ dispatch, history }) {
|
||||||
|
history.listen((location) => {});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
effects: {
|
||||||
|
*createKb({ payload = {} }, { call, put }) {
|
||||||
|
const { data } = yield call(kbService.createKb, payload);
|
||||||
|
const { retcode } = data;
|
||||||
|
if (retcode === 0) {
|
||||||
|
message.success('创建知识库成功!');
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
},
|
||||||
|
*updateKb({ payload = {} }, { call, put }) {
|
||||||
|
const { data } = yield call(kbService.updateKb, payload);
|
||||||
|
const { retcode, data: res, retmsg } = data;
|
||||||
|
if (retcode === 0) {
|
||||||
|
message.success('更新知识库成功!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
*getKbDetail({ payload = {} }, { call, put }) {
|
||||||
|
const { data } = yield call(kbService.get_kb_detail, payload);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,123 +1,120 @@
|
|||||||
import { connect, useNavigate, useLocation, Dispatch } from 'umi'
|
import { getWidth } from '@/utils';
|
||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import { BarsOutlined, SearchOutlined, ToolOutlined } from '@ant-design/icons';
|
||||||
import type { MenuProps } from 'antd';
|
import type { MenuProps } from 'antd';
|
||||||
import { Menu } from 'antd';
|
import { Menu } from 'antd';
|
||||||
import {
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
ToolOutlined,
|
import { useDispatch, useLocation, useNavigate, useSelector } from 'umi';
|
||||||
BarsOutlined,
|
import Chunk from './components/knowledge-chunk';
|
||||||
SearchOutlined
|
import File from './components/knowledge-file';
|
||||||
} from '@ant-design/icons';
|
import Search from './components/knowledge-search';
|
||||||
import File from './components/knowledge-file'
|
import Setting from './components/knowledge-setting';
|
||||||
import Setting from './components/knowledge-setting'
|
import styles from './index.less';
|
||||||
import Search from './components/knowledge-search'
|
|
||||||
import Chunk from './components/knowledge-chunk'
|
|
||||||
import styles from './index.less'
|
|
||||||
import { getWidth } from '@/utils'
|
|
||||||
import { kAModelState } from './model'
|
|
||||||
|
|
||||||
|
const KnowledgeAdding = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const kAModel = useSelector((state: any) => state.kAModel);
|
||||||
|
const { id, activeKey, doc_id } = kAModel;
|
||||||
|
|
||||||
interface kAProps {
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
dispatch: Dispatch;
|
const [windowWidth, setWindowWidth] = useState(getWidth());
|
||||||
kAModel: kAModelState;
|
let navigate = useNavigate();
|
||||||
}
|
const location = useLocation();
|
||||||
const Index: React.FC<kAProps> = ({ kAModel, dispatch }) => {
|
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
|
||||||
const { id, activeKey, doc_id } = kAModel
|
|
||||||
const [windowWidth, setWindowWidth] = useState(getWidth());
|
|
||||||
let navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
|
||||||
// 标记一下
|
|
||||||
console.log(doc_id, '>>>>>>>>>>>>>doc_id')
|
|
||||||
useEffect(() => {
|
|
||||||
const widthSize = () => {
|
|
||||||
const width = getWidth()
|
|
||||||
console.log(width)
|
|
||||||
|
|
||||||
setWindowWidth(width);
|
// 标记一下
|
||||||
};
|
console.log(doc_id, '>>>>>>>>>>>>>doc_id');
|
||||||
window.addEventListener("resize", widthSize);
|
useEffect(() => {
|
||||||
return () => {
|
const widthSize = () => {
|
||||||
window.removeEventListener("resize", widthSize);
|
const width = getWidth();
|
||||||
};
|
console.log(width);
|
||||||
}, []);
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(location)
|
|
||||||
const search = location.search.slice(1)
|
|
||||||
const map = search.split('&').reduce((obj, cur) => {
|
|
||||||
const [key, value] = cur.split('=')
|
|
||||||
obj[key] = value
|
|
||||||
return obj
|
|
||||||
}, {})
|
|
||||||
dispatch({
|
|
||||||
type: 'kAModel/updateState',
|
|
||||||
payload: {
|
|
||||||
doc_id: undefined,
|
|
||||||
...map,
|
|
||||||
|
|
||||||
|
setWindowWidth(width);
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', widthSize);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', widthSize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
useEffect(() => {
|
||||||
|
const search: string = location.search.slice(1);
|
||||||
|
const map = search.split('&').reduce<Record<string, string>>((obj, cur) => {
|
||||||
|
const [key, value] = cur.split('=');
|
||||||
|
obj[key] = value;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'kAModel/updateState',
|
||||||
|
payload: {
|
||||||
|
doc_id: undefined,
|
||||||
|
...map,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (windowWidth.width > 957) {
|
||||||
|
setCollapsed(false);
|
||||||
|
} else {
|
||||||
|
setCollapsed(true);
|
||||||
|
}
|
||||||
|
}, [windowWidth.width]);
|
||||||
|
|
||||||
|
type MenuItem = Required<MenuProps>['items'][number];
|
||||||
|
|
||||||
|
function getItem(
|
||||||
|
label: React.ReactNode,
|
||||||
|
key: React.Key,
|
||||||
|
icon?: React.ReactNode,
|
||||||
|
disabled?: boolean,
|
||||||
|
children?: MenuItem[],
|
||||||
|
type?: 'group',
|
||||||
|
): MenuItem {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
icon,
|
||||||
|
children,
|
||||||
|
label,
|
||||||
|
type,
|
||||||
|
disabled,
|
||||||
|
} as MenuItem;
|
||||||
|
}
|
||||||
|
const items: MenuItem[] = useMemo(() => {
|
||||||
|
const disabled = !id;
|
||||||
|
return [
|
||||||
|
getItem('配置', 'setting', <ToolOutlined />),
|
||||||
|
getItem('知识库', 'file', <BarsOutlined />, disabled),
|
||||||
|
getItem('搜索测试', 'search', <SearchOutlined />, disabled),
|
||||||
|
];
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
|
const handleSelect: MenuProps['onSelect'] = (e) => {
|
||||||
|
navigate(`/knowledge/add/setting?activeKey=${e.key}&id=${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.menu}>
|
||||||
|
<Menu
|
||||||
|
selectedKeys={[activeKey]}
|
||||||
|
mode="inline"
|
||||||
|
className={
|
||||||
|
windowWidth.width > 957 ? styles.defaultWidth : styles.minWidth
|
||||||
}
|
}
|
||||||
});
|
inlineCollapsed={collapsed}
|
||||||
}, [location])
|
items={items}
|
||||||
useEffect(() => {
|
onSelect={handleSelect}
|
||||||
if (windowWidth.width > 957) {
|
/>
|
||||||
setCollapsed(false)
|
</div>
|
||||||
} else {
|
<div className={styles.content}>
|
||||||
setCollapsed(true)
|
{activeKey === 'file' && !doc_id && <File kb_id={id} />}
|
||||||
}
|
{activeKey === 'setting' && <Setting kb_id={id} />}
|
||||||
}, [windowWidth.width])
|
{activeKey === 'search' && <Search kb_id={id} />}
|
||||||
type MenuItem = Required<MenuProps>['items'][number];
|
{activeKey === 'file' && !!doc_id && <Chunk doc_id={doc_id} />}
|
||||||
|
</div>
|
||||||
function getItem(
|
</div>
|
||||||
label: React.ReactNode,
|
</>
|
||||||
key: React.Key,
|
);
|
||||||
icon?: React.ReactNode,
|
|
||||||
disabled?: boolean,
|
|
||||||
children?: MenuItem[],
|
|
||||||
type?: 'group',
|
|
||||||
|
|
||||||
): MenuItem {
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
icon,
|
|
||||||
children,
|
|
||||||
label,
|
|
||||||
type,
|
|
||||||
disabled
|
|
||||||
} as MenuItem;
|
|
||||||
}
|
|
||||||
const items: MenuItem[] = useMemo(() => {
|
|
||||||
const disabled = !id
|
|
||||||
return [
|
|
||||||
getItem('配置', 'setting', <ToolOutlined />),
|
|
||||||
getItem('知识库', 'file', <BarsOutlined />, disabled),
|
|
||||||
getItem('搜索测试', 'search', <SearchOutlined />, disabled),
|
|
||||||
]
|
|
||||||
}, [id]);
|
|
||||||
const handleSelect: MenuProps['onSelect'] = (e) => {
|
|
||||||
navigate(`/knowledge/add/setting?activeKey=${e.key}&id=${id}`);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.menu}>
|
|
||||||
<Menu
|
|
||||||
selectedKeys={[activeKey]}
|
|
||||||
mode="inline"
|
|
||||||
className={windowWidth.width > 957 ? styles.defaultWidth : styles.minWidth}
|
|
||||||
inlineCollapsed={collapsed}
|
|
||||||
items={items}
|
|
||||||
onSelect={handleSelect}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.content}>
|
|
||||||
{activeKey === 'file' && !doc_id && <File kb_id={id} />}
|
|
||||||
{activeKey === 'setting' && <Setting kb_id={id} />}
|
|
||||||
{activeKey === 'search' && <Search kb_id={id} />}
|
|
||||||
{activeKey === 'file' && !!doc_id && <Chunk doc_id={doc_id} />}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ kAModel, loading }) => ({ kAModel, loading }))(Index);
|
export default KnowledgeAdding;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import { Effect, Reducer, Subscription } from 'umi'
|
import { DvaModel } from 'umi';
|
||||||
import { message } from 'antd';
|
|
||||||
import kbService from '@/services/kbService';
|
|
||||||
export interface kAModelState {
|
export interface kAModelState {
|
||||||
isShowPSwModal: boolean;
|
isShowPSwModal: boolean;
|
||||||
isShowTntModal: boolean;
|
isShowTntModal: boolean;
|
||||||
@ -8,20 +6,10 @@ export interface kAModelState {
|
|||||||
tenantIfo: any;
|
tenantIfo: any;
|
||||||
activeKey: string;
|
activeKey: string;
|
||||||
id: string;
|
id: string;
|
||||||
doc_id: string
|
doc_id: string;
|
||||||
}
|
}
|
||||||
export interface kAModelType {
|
|
||||||
namespace: 'kAModel';
|
|
||||||
state: kAModelState;
|
|
||||||
effects: {
|
|
||||||
|
|
||||||
};
|
const model: DvaModel<kAModelState> = {
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<kAModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: kAModelType = {
|
|
||||||
namespace: 'kAModel',
|
namespace: 'kAModel',
|
||||||
state: {
|
state: {
|
||||||
isShowPSwModal: false,
|
isShowPSwModal: false,
|
||||||
@ -30,25 +18,21 @@ const Model: kAModelType = {
|
|||||||
tenantIfo: {},
|
tenantIfo: {},
|
||||||
activeKey: 'setting',
|
activeKey: 'setting',
|
||||||
id: '',
|
id: '',
|
||||||
doc_id: ''
|
doc_id: '',
|
||||||
|
|
||||||
},
|
|
||||||
subscriptions: {
|
|
||||||
setup({ dispatch, history }) {
|
|
||||||
history.listen(location => {
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
effects: {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
updateState(state, { payload }) {
|
updateState(state, { payload }) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
...payload
|
...payload,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
subscriptions: {
|
||||||
|
setup({ dispatch, history }) {
|
||||||
|
history.listen((location) => {});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
effects: {},
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
import React from 'react';
|
import { useSelector } from 'umi';
|
||||||
import { connect, Dispatch } from 'umi';
|
|
||||||
import type { chatModelState } from './model'
|
|
||||||
|
|
||||||
interface chatProps {
|
const Chat = () => {
|
||||||
chatModel: chatModelState;
|
const { name } = useSelector((state: any) => state.chatModel);
|
||||||
dispatch: Dispatch
|
return <div>chat:{name} </div>;
|
||||||
}
|
|
||||||
|
|
||||||
const View: React.FC<chatProps> = ({ chatModel, dispatch }) => {
|
|
||||||
const { name } = chatModel;
|
|
||||||
return <div>chat:{name} </div>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ chatModel, loading }) => ({ chatModel, loading }))(View);
|
export default Chat;
|
||||||
|
@ -1,46 +1,32 @@
|
|||||||
import { Effect, Reducer, Subscription } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface chatModelState {
|
export interface ChatModelState {
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface chatModelType {
|
const model: DvaModel<ChatModelState> = {
|
||||||
namespace: 'chatModel';
|
namespace: 'chatModel',
|
||||||
state: chatModelState;
|
state: {
|
||||||
effects: {
|
name: 'kate',
|
||||||
query: Effect;
|
},
|
||||||
};
|
reducers: {
|
||||||
reducers: {
|
save(state, action) {
|
||||||
save: Reducer<chatModelState>;
|
return {
|
||||||
};
|
...state,
|
||||||
subscriptions: { setup: Subscription };
|
...action.payload,
|
||||||
}
|
};
|
||||||
|
|
||||||
const Model: chatModelType = {
|
|
||||||
namespace: 'chatModel',
|
|
||||||
state: {
|
|
||||||
name: 'kate',
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
effects: {
|
subscriptions: {
|
||||||
*query({ payload }, { call, put }) { },
|
setup({ dispatch, history }) {
|
||||||
},
|
return history.listen((query) => {
|
||||||
reducers: {
|
console.log(query);
|
||||||
save(state, action) {
|
});
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...action.payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
subscriptions: {
|
|
||||||
setup({ dispatch, history }) {
|
|
||||||
return history.listen((query) => {
|
|
||||||
console.log(query)
|
|
||||||
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
effects: {
|
||||||
|
*query({ payload }, { call, put }) {},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,51 +1,50 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { UploadOutlined } from '@ant-design/icons';
|
||||||
import { Button, Upload } from 'antd';
|
import { Button, Upload } from 'antd';
|
||||||
import type { UploadFile } from 'antd/es/upload/interface';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const File: React.FC = () => {
|
||||||
const App: React.FC = () => {
|
const [fileList, setFileList] = useState([
|
||||||
const [fileList, setFileList] = useState([{
|
{
|
||||||
uid: '0',
|
uid: '0',
|
||||||
name: 'xxx.png',
|
name: 'xxx.png',
|
||||||
status: 'uploading',
|
status: 'uploading',
|
||||||
percent: 10,
|
percent: 10,
|
||||||
}])
|
},
|
||||||
const obj = {
|
]);
|
||||||
uid: '-1',
|
const obj = {
|
||||||
name: 'yyy.png',
|
uid: '-1',
|
||||||
status: 'done',
|
name: 'yyy.png',
|
||||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
status: 'done',
|
||||||
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
}
|
thumbUrl:
|
||||||
useEffect(() => {
|
'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
const timer = setInterval(() => {
|
};
|
||||||
setFileList((fileList: any) => {
|
useEffect(() => {
|
||||||
const percent = fileList[0]?.percent
|
const timer = setInterval(() => {
|
||||||
if (percent + 10 >= 100) {
|
setFileList((fileList: any) => {
|
||||||
clearInterval(timer)
|
const percent = fileList[0]?.percent;
|
||||||
return [obj]
|
if (percent + 10 >= 100) {
|
||||||
}
|
clearInterval(timer);
|
||||||
const list = [{ ...fileList[0], percent: percent + 10 }]
|
return [obj];
|
||||||
console.log(list)
|
}
|
||||||
return list
|
const list = [{ ...fileList[0], percent: percent + 10 }];
|
||||||
|
console.log(list);
|
||||||
})
|
return list;
|
||||||
}, 300)
|
});
|
||||||
}, [])
|
}, 300);
|
||||||
return (
|
}, []);
|
||||||
|
return (
|
||||||
<>
|
<>
|
||||||
<Upload
|
<Upload
|
||||||
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
|
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
|
||||||
listType="picture"
|
listType="picture"
|
||||||
fileList={[...fileList]}
|
fileList={[...fileList]}
|
||||||
multiple
|
multiple
|
||||||
>
|
>
|
||||||
<Button icon={<UploadOutlined />}>Upload</Button>
|
<Button icon={<UploadOutlined />}>Upload</Button>
|
||||||
</Upload>
|
</Upload>
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default File;
|
||||||
|
@ -5,21 +5,22 @@ import {
|
|||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
|
import { Card, Col, FloatButton, Popconfirm, Row } from 'antd';
|
||||||
import React, { useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { Dispatch, connect, useNavigate } from 'umi';
|
import { useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
import type { knowledgeModelState } from './model';
|
|
||||||
interface KnowledgeProps {
|
|
||||||
dispatch: Dispatch;
|
|
||||||
knowledgeModel: knowledgeModelState;
|
|
||||||
}
|
|
||||||
const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
// const [datas, setDatas] = useState(data)
|
|
||||||
const { data = [] } = knowledgeModel;
|
|
||||||
console.log(knowledgeModel);
|
|
||||||
|
|
||||||
// const x = useSelector((state) => state.knowledgeModel);
|
const Knowledge = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const knowledgeModel = useSelector((state: any) => state.knowledgeModel);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { data = [] } = knowledgeModel;
|
||||||
|
|
||||||
|
const fetchList = useCallback(() => {
|
||||||
|
dispatch({
|
||||||
|
type: 'knowledgeModel/getList',
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const confirm = (id: string) => {
|
const confirm = (id: string) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
@ -27,12 +28,6 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|||||||
payload: {
|
payload: {
|
||||||
kb_id: id,
|
kb_id: id,
|
||||||
},
|
},
|
||||||
callback: () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'knowledgeModel/getList',
|
|
||||||
payload: {},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleAddKnowledge = () => {
|
const handleAddKnowledge = () => {
|
||||||
@ -42,11 +37,8 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|||||||
navigate(`add/setting?activeKey=file&id=${id}`);
|
navigate(`add/setting?activeKey=file&id=${id}`);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({
|
fetchList();
|
||||||
type: 'knowledgeModel/getList',
|
}, [fetchList]);
|
||||||
payload: {},
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.knowledge}>
|
<div className={styles.knowledge}>
|
||||||
@ -125,7 +117,4 @@ const Index: React.FC<KnowledgeProps> = ({ knowledgeModel, dispatch }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ knowledgeModel, loading }) => ({
|
export default Knowledge;
|
||||||
knowledgeModel,
|
|
||||||
loading,
|
|
||||||
}))(Index);
|
|
||||||
|
@ -1,58 +1,38 @@
|
|||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
import { Effect, Reducer } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface knowledgeModelState {
|
export interface KnowledgeModelState {
|
||||||
loading: boolean;
|
|
||||||
data: any[];
|
data: any[];
|
||||||
}
|
}
|
||||||
export interface knowledgegModelType {
|
|
||||||
namespace: 'knowledgeModel';
|
const model: DvaModel<KnowledgeModelState> = {
|
||||||
state: knowledgeModelState;
|
|
||||||
effects: {
|
|
||||||
rmKb: Effect;
|
|
||||||
getList: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<knowledgeModelState>;
|
|
||||||
};
|
|
||||||
// subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: knowledgegModelType = {
|
|
||||||
namespace: 'knowledgeModel',
|
namespace: 'knowledgeModel',
|
||||||
state: {
|
state: {
|
||||||
loading: false,
|
|
||||||
data: [],
|
data: [],
|
||||||
},
|
},
|
||||||
// subscriptions: {
|
reducers: {
|
||||||
// setup({ dispatch, history }) {
|
updateState(state, { payload }) {
|
||||||
// history.listen((location) => {
|
return {
|
||||||
// console.log(location);
|
...state,
|
||||||
// });
|
...payload,
|
||||||
// },
|
};
|
||||||
// },
|
},
|
||||||
|
},
|
||||||
effects: {
|
effects: {
|
||||||
*rmKb({ payload = {}, callback }, { call, put }) {
|
*rmKb({ payload = {}, callback }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.rmKb, payload);
|
const { data } = yield call(kbService.rmKb, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
callback && callback();
|
yield put({
|
||||||
|
type: 'getList',
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*getList({ payload = {} }, { call, put }) {
|
*getList({ payload = {} }, { call, put }) {
|
||||||
yield put({
|
const { data } = yield call(kbService.getList, payload);
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { data, response } = yield call(kbService.getList, payload);
|
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
yield put({
|
|
||||||
type: 'updateState',
|
|
||||||
payload: {
|
|
||||||
loading: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
@ -63,13 +43,5 @@ const Model: knowledgegModelType = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import { rsaPsw } from '@/utils';
|
import { rsaPsw } from '@/utils';
|
||||||
import { Button, Checkbox, Form, Input } from 'antd';
|
import { Button, Checkbox, Form, Input } from 'antd';
|
||||||
import { FC, useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Dispatch, Icon, connect, useNavigate } from 'umi';
|
import { Icon, useDispatch, useNavigate, useSelector } from 'umi';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
interface LoginProps {
|
const Login = () => {
|
||||||
dispatch: Dispatch;
|
|
||||||
}
|
|
||||||
const View: FC<LoginProps> = ({ dispatch }) => {
|
|
||||||
let navigate = useNavigate();
|
|
||||||
const [title, setTitle] = useState('login');
|
const [title, setTitle] = useState('login');
|
||||||
|
let navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const effectsLoading: any = useSelector<any>( // TODO: Type needs to be improved
|
||||||
|
(state) => state.loading.effects,
|
||||||
|
);
|
||||||
|
|
||||||
|
const signLoading =
|
||||||
|
effectsLoading['loginModel/login'] || effectsLoading['loginModel/register'];
|
||||||
|
|
||||||
const changeTitle = () => {
|
const changeTitle = () => {
|
||||||
setTitle((title) => (title === 'login' ? 'register' : 'login'));
|
setTitle((title) => (title === 'login' ? 'register' : 'login'));
|
||||||
};
|
};
|
||||||
@ -26,27 +31,29 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|||||||
|
|
||||||
var rsaPassWord = rsaPsw(params.password);
|
var rsaPassWord = rsaPsw(params.password);
|
||||||
if (title === 'login') {
|
if (title === 'login') {
|
||||||
const ret = await dispatch({
|
const retcode = await dispatch<any>({
|
||||||
type: 'loginModel/login',
|
type: 'loginModel/login',
|
||||||
payload: {
|
payload: {
|
||||||
email: params.email,
|
email: params.email,
|
||||||
password: rsaPassWord,
|
password: rsaPassWord,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.info(ret);
|
if (retcode === 0) {
|
||||||
navigate('/knowledge');
|
navigate('/knowledge');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
// TODO: Type needs to be improved
|
||||||
|
const retcode = await dispatch<any>({
|
||||||
type: 'loginModel/register',
|
type: 'loginModel/register',
|
||||||
payload: {
|
payload: {
|
||||||
nickname: params.nickname,
|
nickname: params.nickname,
|
||||||
email: params.email,
|
email: params.email,
|
||||||
password: rsaPassWord,
|
password: rsaPassWord,
|
||||||
},
|
},
|
||||||
callback() {
|
|
||||||
setTitle('login');
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
if (retcode === 0) {
|
||||||
|
setTitle('login');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (errorInfo) {
|
} catch (errorInfo) {
|
||||||
console.log('Failed:', errorInfo);
|
console.log('Failed:', errorInfo);
|
||||||
@ -106,7 +113,7 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|||||||
label="Password"
|
label="Password"
|
||||||
rules={[{ required: true, message: 'Please input value' }]}
|
rules={[{ required: true, message: 'Please input value' }]}
|
||||||
>
|
>
|
||||||
<Input size="large" placeholder="Please input value" />
|
<Input.Password size="large" placeholder="Please input value" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{title === 'login' && (
|
{title === 'login' && (
|
||||||
<Form.Item name="remember" valuePropName="checked">
|
<Form.Item name="remember" valuePropName="checked">
|
||||||
@ -132,7 +139,13 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Button type="primary" block size="large" onClick={onCheck}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
size="large"
|
||||||
|
onClick={onCheck}
|
||||||
|
loading={signLoading}
|
||||||
|
>
|
||||||
{title === 'login' ? 'Sign in' : 'Continue'}
|
{title === 'login' ? 'Sign in' : 'Continue'}
|
||||||
</Button>
|
</Button>
|
||||||
{title === 'login' && (
|
{title === 'login' && (
|
||||||
@ -175,6 +188,4 @@ const View: FC<LoginProps> = ({ dispatch }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(({ loginModel, loading }) => ({ loginModel, loading }))(
|
export default Login;
|
||||||
View,
|
|
||||||
);
|
|
||||||
|
@ -2,32 +2,29 @@ import { Authorization } from '@/constants/authorization';
|
|||||||
import userService from '@/services/userService';
|
import userService from '@/services/userService';
|
||||||
import authorizationUtil from '@/utils/authorizationUtil';
|
import authorizationUtil from '@/utils/authorizationUtil';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { Effect, Reducer, Subscription } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface loginModelState {
|
export interface LoginModelState {
|
||||||
list: any[];
|
list: any[];
|
||||||
info: any;
|
info: any;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
export interface logingModelType {
|
|
||||||
namespace: 'loginModel';
|
const model: DvaModel<LoginModelState> = {
|
||||||
state: loginModelState;
|
|
||||||
effects: {
|
|
||||||
login: Effect;
|
|
||||||
register: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<loginModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: logingModelType = {
|
|
||||||
namespace: 'loginModel',
|
namespace: 'loginModel',
|
||||||
state: {
|
state: {
|
||||||
list: [],
|
list: [],
|
||||||
info: {},
|
info: {},
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
|
reducers: {
|
||||||
|
updateState(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
subscriptions: {
|
subscriptions: {
|
||||||
setup({ dispatch, history }) {
|
setup({ dispatch, history }) {
|
||||||
history.listen((location) => {});
|
history.listen((location) => {});
|
||||||
@ -53,29 +50,18 @@ const Model: logingModelType = {
|
|||||||
userInfo: JSON.stringify(userInfo),
|
userInfo: JSON.stringify(userInfo),
|
||||||
Token: token,
|
Token: token,
|
||||||
});
|
});
|
||||||
// setTimeout(() => {
|
|
||||||
// window.location.href = '/file';
|
|
||||||
// }, 300);
|
|
||||||
}
|
}
|
||||||
return data;
|
return retcode;
|
||||||
},
|
},
|
||||||
*register({ payload = {}, callback }, { call, put }) {
|
*register({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(userService.register, payload);
|
const { data, response } = yield call(userService.register, payload);
|
||||||
console.log();
|
console.log();
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res, retmsg } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
message.success('注册成功!');
|
message.success('注册成功!');
|
||||||
callback && callback();
|
|
||||||
}
|
}
|
||||||
},
|
return retcode;
|
||||||
},
|
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import userService from '@/services/userService';
|
import userService from '@/services/userService';
|
||||||
import authorizationUtil from '@/utils/authorizationUtil';
|
import authorizationUtil from '@/utils/authorizationUtil';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { Effect, Reducer, Subscription } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
export interface settingModelState {
|
export interface SettingModelState {
|
||||||
isShowPSwModal: boolean;
|
isShowPSwModal: boolean;
|
||||||
isShowTntModal: boolean;
|
isShowTntModal: boolean;
|
||||||
isShowSAKModal: boolean;
|
isShowSAKModal: boolean;
|
||||||
@ -16,25 +16,7 @@ export interface settingModelState {
|
|||||||
factoriesList: any[];
|
factoriesList: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface settingModelType {
|
const model: DvaModel<SettingModelState> = {
|
||||||
namespace: 'settingModel';
|
|
||||||
state: settingModelState;
|
|
||||||
effects: {
|
|
||||||
setting: Effect;
|
|
||||||
getUserInfo: Effect;
|
|
||||||
getTenantInfo: Effect;
|
|
||||||
set_tenant_info: Effect;
|
|
||||||
factories_list: Effect;
|
|
||||||
llm_list: Effect;
|
|
||||||
my_llm: Effect;
|
|
||||||
set_api_key: Effect;
|
|
||||||
};
|
|
||||||
reducers: {
|
|
||||||
updateState: Reducer<settingModelState>;
|
|
||||||
};
|
|
||||||
subscriptions: { setup: Subscription };
|
|
||||||
}
|
|
||||||
const Model: settingModelType = {
|
|
||||||
namespace: 'settingModel',
|
namespace: 'settingModel',
|
||||||
state: {
|
state: {
|
||||||
isShowPSwModal: false,
|
isShowPSwModal: false,
|
||||||
@ -48,6 +30,14 @@ const Model: settingModelType = {
|
|||||||
myLlm: [],
|
myLlm: [],
|
||||||
factoriesList: [],
|
factoriesList: [],
|
||||||
},
|
},
|
||||||
|
reducers: {
|
||||||
|
updateState(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
subscriptions: {
|
subscriptions: {
|
||||||
setup({ dispatch, history }) {
|
setup({ dispatch, history }) {
|
||||||
history.listen((location) => {});
|
history.listen((location) => {});
|
||||||
@ -176,13 +166,5 @@ const Model: settingModelType = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
|
||||||
updateState(state, { payload }) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
...payload,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
export default Model;
|
export default model;
|
||||||
|
@ -19,101 +19,83 @@ const {
|
|||||||
get_chunk,
|
get_chunk,
|
||||||
switch_chunk,
|
switch_chunk,
|
||||||
rm_chunk,
|
rm_chunk,
|
||||||
retrieval_test } = api;
|
retrieval_test,
|
||||||
interface kbService {
|
} = api;
|
||||||
createKb: () => void;
|
|
||||||
updateKb: () => void;
|
const methods = {
|
||||||
rmKb: () => void;
|
// 知识库管理
|
||||||
get_kb_detail: () => void;
|
createKb: {
|
||||||
getList: () => void;
|
url: create_kb,
|
||||||
get_document_list: () => void;
|
method: 'post',
|
||||||
document_change_status: () => void;
|
|
||||||
document_rm: () => void;
|
|
||||||
document_create: () => void;
|
|
||||||
document_change_parser: () => void;
|
|
||||||
chunk_list: () => void;
|
|
||||||
create_chunk: () => void;
|
|
||||||
set_chunk: () => void;
|
|
||||||
get_chunk: () => void;
|
|
||||||
switch_chunk: () => void;
|
|
||||||
rm_chunk: () => void;
|
|
||||||
retrieval_test: () => void;
|
|
||||||
}
|
|
||||||
const kbService: kbService = registerServer(
|
|
||||||
{
|
|
||||||
// 知识库管理
|
|
||||||
createKb: {
|
|
||||||
url: create_kb,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
updateKb: {
|
|
||||||
url: update_kb,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
rmKb: {
|
|
||||||
url: rm_kb,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
get_kb_detail: {
|
|
||||||
url: get_kb_detail,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
getList: {
|
|
||||||
url: kb_list,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
// 文件管理
|
|
||||||
get_document_list: {
|
|
||||||
url: get_document_list,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
document_change_status: {
|
|
||||||
url: document_change_status,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
document_rm: {
|
|
||||||
url: document_rm,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
document_create: {
|
|
||||||
url: document_create,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
document_change_parser: {
|
|
||||||
url: document_change_parser,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
// chunk管理
|
|
||||||
chunk_list: {
|
|
||||||
url: chunk_list,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
create_chunk: {
|
|
||||||
url: create_chunk,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
set_chunk: {
|
|
||||||
url: set_chunk,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
get_chunk: {
|
|
||||||
url: get_chunk,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
switch_chunk: {
|
|
||||||
url: switch_chunk,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
rm_chunk: {
|
|
||||||
url: rm_chunk,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
retrieval_test: {
|
|
||||||
url: retrieval_test,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
request
|
updateKb: {
|
||||||
);
|
url: update_kb,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
rmKb: {
|
||||||
|
url: rm_kb,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
get_kb_detail: {
|
||||||
|
url: get_kb_detail,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
getList: {
|
||||||
|
url: kb_list,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
// 文件管理
|
||||||
|
get_document_list: {
|
||||||
|
url: get_document_list,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
document_change_status: {
|
||||||
|
url: document_change_status,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
document_rm: {
|
||||||
|
url: document_rm,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
document_create: {
|
||||||
|
url: document_create,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
document_change_parser: {
|
||||||
|
url: document_change_parser,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
// chunk管理
|
||||||
|
chunk_list: {
|
||||||
|
url: chunk_list,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
create_chunk: {
|
||||||
|
url: create_chunk,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
set_chunk: {
|
||||||
|
url: set_chunk,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
get_chunk: {
|
||||||
|
url: get_chunk,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
switch_chunk: {
|
||||||
|
url: switch_chunk,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
rm_chunk: {
|
||||||
|
url: rm_chunk,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
retrieval_test: {
|
||||||
|
url: retrieval_test,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const kbService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
|
||||||
export default kbService;
|
export default kbService;
|
||||||
|
@ -3,55 +3,61 @@ import registerServer from '@/utils/registerServer';
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
login, register, setting, user_info, tenant_info, factories_list, llm_list, my_llm, set_api_key, set_tenant_info } = api;
|
login,
|
||||||
interface userServiceType {
|
register,
|
||||||
login: (params: any) => void
|
setting,
|
||||||
}
|
user_info,
|
||||||
const userService = registerServer(
|
tenant_info,
|
||||||
{
|
factories_list,
|
||||||
login: {
|
llm_list,
|
||||||
url: login,
|
my_llm,
|
||||||
method: 'post',
|
set_api_key,
|
||||||
|
set_tenant_info,
|
||||||
|
} = api;
|
||||||
|
|
||||||
},
|
const methods = {
|
||||||
register: {
|
login: {
|
||||||
url: register,
|
url: login,
|
||||||
method: 'post'
|
method: 'post',
|
||||||
},
|
|
||||||
setting: {
|
|
||||||
url: setting,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
user_info: {
|
|
||||||
url: user_info,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
get_tenant_info: {
|
|
||||||
url: tenant_info,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
set_tenant_info: {
|
|
||||||
url: set_tenant_info,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
factories_list: {
|
|
||||||
url: factories_list,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
llm_list: {
|
|
||||||
url: llm_list,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
my_llm: {
|
|
||||||
url: my_llm,
|
|
||||||
method: 'get'
|
|
||||||
},
|
|
||||||
set_api_key: {
|
|
||||||
url: set_api_key,
|
|
||||||
method: 'post'
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
request
|
register: {
|
||||||
);
|
url: register,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
setting: {
|
||||||
|
url: setting,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
user_info: {
|
||||||
|
url: user_info,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
get_tenant_info: {
|
||||||
|
url: tenant_info,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
set_tenant_info: {
|
||||||
|
url: set_tenant_info,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
factories_list: {
|
||||||
|
url: factories_list,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
llm_list: {
|
||||||
|
url: llm_list,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
my_llm: {
|
||||||
|
url: my_llm,
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
set_api_key: {
|
||||||
|
url: set_api_key,
|
||||||
|
method: 'post',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const userService = registerServer<keyof typeof methods>(methods, request);
|
||||||
|
|
||||||
export default userService;
|
export default userService;
|
||||||
|
@ -1,17 +1,24 @@
|
|||||||
const registerServer = (opt: any, request: any): any => {
|
import { RequestMethod } from 'umi-request';
|
||||||
let server = {};
|
|
||||||
|
type Service<T extends string> = Record<T, (params: any) => any>;
|
||||||
|
|
||||||
|
const registerServer = <T extends string>(
|
||||||
|
opt: Record<T, { url: string; method: string }>,
|
||||||
|
request: RequestMethod,
|
||||||
|
) => {
|
||||||
|
const server: Service<T> = {} as Service<T>;
|
||||||
for (let key in opt) {
|
for (let key in opt) {
|
||||||
server[key] = (params: any) => {
|
server[key] = (params) => {
|
||||||
if (opt[key].method === 'post' || opt[key].method === 'POST') {
|
if (opt[key].method === 'post' || opt[key].method === 'POST') {
|
||||||
return request(opt[key].url, {
|
return request(opt[key].url, {
|
||||||
method: opt[key].method,
|
method: opt[key].method,
|
||||||
data: params
|
data: params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt[key].method === 'get' || opt[key].method === 'GET') {
|
if (opt[key].method === 'get' || opt[key].method === 'GET') {
|
||||||
return request.get(opt[key].url, {
|
return request.get(opt[key].url, {
|
||||||
params
|
params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { message, notification } from 'antd';
|
import { message, notification } from 'antd';
|
||||||
import { extend } from 'umi-request';
|
import { RequestMethod, extend } from 'umi-request';
|
||||||
|
|
||||||
import { Authorization } from '@/constants/authorization';
|
import { Authorization } from '@/constants/authorization';
|
||||||
import api from '@/utils/api';
|
import api from '@/utils/api';
|
||||||
@ -9,7 +9,7 @@ const { login } = api;
|
|||||||
|
|
||||||
const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
|
const ABORT_REQUEST_ERR_MESSAGE = 'The user aborted a request.'; // 手动中断请求。errorHandler 抛出的error message
|
||||||
|
|
||||||
const retcodeMessage = {
|
const RetcodeMessage = {
|
||||||
200: '服务器成功返回请求的数据。',
|
200: '服务器成功返回请求的数据。',
|
||||||
201: '新建或修改数据成功。',
|
201: '新建或修改数据成功。',
|
||||||
202: '一个请求已经进入后台排队(异步任务)。',
|
202: '一个请求已经进入后台排队(异步任务)。',
|
||||||
@ -26,7 +26,7 @@ const retcodeMessage = {
|
|||||||
503: '服务不可用,服务器暂时过载或维护。',
|
503: '服务不可用,服务器暂时过载或维护。',
|
||||||
504: '网关超时。',
|
504: '网关超时。',
|
||||||
};
|
};
|
||||||
type retcode =
|
type ResultCode =
|
||||||
| 200
|
| 200
|
||||||
| 201
|
| 201
|
||||||
| 202
|
| 202
|
||||||
@ -45,7 +45,7 @@ type retcode =
|
|||||||
/**
|
/**
|
||||||
* 异常处理程序
|
* 异常处理程序
|
||||||
*/
|
*/
|
||||||
interface responseType {
|
interface ResponseType {
|
||||||
retcode: number;
|
retcode: number;
|
||||||
data: any;
|
data: any;
|
||||||
retmsg: string;
|
retmsg: string;
|
||||||
@ -62,7 +62,7 @@ const errorHandler = (error: {
|
|||||||
} else {
|
} else {
|
||||||
if (response && response.status) {
|
if (response && response.status) {
|
||||||
const errorText =
|
const errorText =
|
||||||
retcodeMessage[response.status as retcode] || response.statusText;
|
RetcodeMessage[response.status as ResultCode] || response.statusText;
|
||||||
const { status, url } = response;
|
const { status, url } = response;
|
||||||
notification.error({
|
notification.error({
|
||||||
message: `请求错误 ${status}: ${url}`,
|
message: `请求错误 ${status}: ${url}`,
|
||||||
@ -81,7 +81,7 @@ const errorHandler = (error: {
|
|||||||
/**
|
/**
|
||||||
* 配置request请求时的默认参数
|
* 配置request请求时的默认参数
|
||||||
*/
|
*/
|
||||||
const request = extend({
|
const request: RequestMethod = extend({
|
||||||
errorHandler, // 默认错误处理
|
errorHandler, // 默认错误处理
|
||||||
timeout: 3000000,
|
timeout: 3000000,
|
||||||
getResponse: true,
|
getResponse: true,
|
||||||
@ -108,7 +108,7 @@ request.interceptors.request.use((url: string, options: any) => {
|
|||||||
|
|
||||||
request.interceptors.response.use(async (response: any, request) => {
|
request.interceptors.response.use(async (response: any, request) => {
|
||||||
console.log(response, request);
|
console.log(response, request);
|
||||||
const data: responseType = await response.clone().json();
|
const data: ResponseType = await response.clone().json();
|
||||||
// response 拦截
|
// response 拦截
|
||||||
|
|
||||||
if (data.retcode === 401 || data.retcode === 401) {
|
if (data.retcode === 401 || data.retcode === 401) {
|
||||||
|
9
web/src/utils/stroreUtil.ts
Normal file
9
web/src/utils/stroreUtil.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const getOneNamespaceEffectsLoading = (
|
||||||
|
namespace: string,
|
||||||
|
effects: Record<string, boolean>,
|
||||||
|
effectNames: Array<string>,
|
||||||
|
) => {
|
||||||
|
return effectNames.some(
|
||||||
|
(effectName) => effects[`${namespace}/${effectName}`],
|
||||||
|
);
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user