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:
balibabu
2024-01-30 19:26:29 +08:00
committed by GitHub
parent 96a1a44cb6
commit 362ec6c364
29 changed files with 1911 additions and 1938 deletions

View File

@ -1,102 +1,116 @@
import React, { useEffect, useState } from 'react'
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form } from 'antd'
import styles from './index.less';
import type { chunkModelState } from './model'
import EditTag from './editTag'
import { Form, Input, Modal } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'umi';
import EditTag from './editTag';
type FieldType = {
content_ltks?: string;
content_ltks?: string;
};
interface kFProps {
dispatch: Dispatch;
chunkModel: chunkModelState;
getChunkList: () => void;
isShowCreateModal: boolean;
doc_id: string;
chunk_id: string
getChunkList: () => void;
isShowCreateModal: boolean;
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) {
console.log('Failed:', errorInfo);
}
};
const Index: React.FC<kFProps> = ({
getChunkList,
doc_id,
isShowCreateModal,
chunk_id,
}) => {
const dispatch = useDispatch();
const [form] = Form.useForm();
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 >
// 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,
},
});
};
const getChunk = useCallback(async () => {
if (chunk_id && isShowCreateModal) {
const data = await dispatch<any>({
type: 'chunkModel/get_chunk',
payload: {
chunk_id,
},
});
);
}
export default connect(({ chunkModel, loading }) => ({ chunkModel, loading }))(Index);
if (data?.retcode === 0) {
const { content_ltks, important_kwd = [] } = data.data;
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;

View File

@ -1,142 +1,141 @@
import React, { useEffect, useRef, useState } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import type { InputRef } from 'antd';
import { Input, Space, Tag, theme, Tooltip } from 'antd';
interface editTagsProps {
tags: any[],
setTags: (tags: any[]) => void
import { Input, Space, Tag, Tooltip, theme } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
interface EditTagsProps {
tags: any[];
setTags: (tags: any[]) => void;
}
const App: React.FC<editTagsProps> = ({ tags, setTags }) => {
const { token } = theme.useToken();
const EditTag: React.FC<EditTagsProps> = ({ tags, setTags }) => {
const { token } = theme.useToken();
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const [editInputIndex, setEditInputIndex] = useState(-1);
const [editInputValue, setEditInputValue] = useState('');
const inputRef = useRef<InputRef>(null);
const editInputRef = useRef<InputRef>(null);
const [inputVisible, setInputVisible] = useState(false);
const [inputValue, setInputValue] = useState('');
const [editInputIndex, setEditInputIndex] = useState(-1);
const [editInputValue, setEditInputValue] = useState('');
const inputRef = useRef<InputRef>(null);
const editInputRef = useRef<InputRef>(null);
useEffect(() => {
if (inputVisible) {
inputRef.current?.focus();
useEffect(() => {
if (inputVisible) {
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]);
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}
/>
);
const isLongTag = tag.length > 20;
const tagElem = (
<Tag
key={tag}
closable={index !== 0}
style={{ userSelect: 'none' }}
onClose={() => handleClose(tag)}
>
<span
onDoubleClick={(e) => {
if (index !== 0) {
setEditInputIndex(index);
setEditInputValue(tag);
e.preventDefault();
}
const isLongTag = tag.length > 20;
const tagElem = (
<Tag
key={tag}
closable={index !== 0}
style={{ userSelect: 'none' }}
onClose={() => handleClose(tag)}
>
<span
onDoubleClick={(e) => {
if (index !== 0) {
setEditInputIndex(index);
setEditInputValue(tag);
e.preventDefault();
}
}}
>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</span>
</Tag>
);
return isLongTag ? (
<Tooltip title={tag} key={tag}>
{tagElem}
</Tooltip>
) : (
tagElem
);
})}
{inputVisible ? (
<Input
ref={inputRef}
type="text"
size="small"
style={tagInputStyle}
value={inputValue}
onChange={handleInputChange}
onBlur={handleInputConfirm}
onPressEnter={handleInputConfirm}
/>
) : (
<Tag style={tagPlusStyle} onClick={showInput}>
</Tag>
)}
</Space>
);
}}
>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</span>
</Tag>
);
return isLongTag ? (
<Tooltip title={tag} key={tag}>
{tagElem}
</Tooltip>
) : (
tagElem
);
})}
{inputVisible ? (
<Input
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;

View File

@ -1,225 +1,282 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useNavigate, connect, Dispatch } from 'umi'
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
import { api_host } from '@/utils/api';
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
import type { PaginationProps } from 'antd';
import { api_host } from '@/utils/api'
import CreateModal from './components/createModal'
import {
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 type { chunkModelState } from './model'
interface chunkProps {
dispatch: Dispatch;
chunkModel: chunkModelState;
doc_id: string
import styles from './index.less';
interface PayloadType {
doc_id: string;
keywords?: string;
available_int?: number;
}
const Index: React.FC<chunkProps> = ({ chunkModel, dispatch, doc_id }) => {
const [keywords, SetKeywords] = useState('')
const [available_int, setAvailableInt] = useState(-1)
const navigate = useNavigate()
const [pagination, setPagination] = useState({ page: 1, size: 30 })
interface IProps {
doc_id: string;
}
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 { data = [], total, loading, chunk_id, isShowCreateModal } = chunkModel
console.log(chunkModel)
const { data = [], total, chunk_id, isShowCreateModal } = chunkModel;
const effects = useSelector((state: any) => state.loading.effects);
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
'create_hunk',
'chunk_list',
'switch_chunk',
]);
const getChunkList = (value?: string) => {
dispatch({
type: 'chunkModel/updateState',
payload: {
loading: true
}
});
interface payloadType {
doc_id: string;
keywords?: string;
available_int?: number
}
const payload: payloadType = {
const payload: PayloadType = {
doc_id,
keywords: value || keywords,
available_int
}
available_int,
};
if (payload.available_int === -1) {
delete payload.available_int
delete payload.available_int;
}
dispatch({
type: 'chunkModel/chunk_list',
payload: {
...payload,
...pagination
}
});
}
const confirm = (id: string) => {
console.log(id)
dispatch({
type: 'chunkModel/rm_chunk',
payload: {
chunk_ids: [id]
...pagination,
},
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) => {
dispatch({
type: 'chunkModel/updateState',
payload: {
isShowCreateModal: true,
chunk_id,
doc_id
doc_id,
},
callback: getChunkList
});
}
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
setPagination({ page, size })
getChunkList();
};
const switchChunk = (id: string, available_int: boolean) => {
dispatch({
type: 'chunkModel/updateState',
payload: {
loading: true
}
});
dispatch({
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
page,
size,
) => {
setPagination({ page, size });
};
const switchChunk = async (id: string, available_int: boolean) => {
const retcode = await dispatch<any>({
type: 'chunkModel/switch_chunk',
payload: {
chunk_ids: [id],
available_int: Number(available_int),
doc_id
doc_id,
},
callback: getChunkList
});
}
retcode === 0 && getChunkList();
};
useEffect(() => {
getChunkList()
}, [doc_id, available_int, pagination])
const debounceChange = debounce(getChunkList, 300)
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const value = e.target.value
SetKeywords(value)
debounceCallback(value)
}
getChunkList();
}, [doc_id, available_int, pagination]);
const debounceChange = debounce(getChunkList, 300);
const debounceCallback = useCallback(
(value: string) => debounceChange(value),
[],
);
const handleInputChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const value = e.target.value;
SetKeywords(value);
debounceCallback(value);
};
const handleSelectChange = (value: number) => {
setAvailableInt(value)
}
console.log('loading', loading)
return (<>
<div className={styles.chunkPage}>
<div className={styles.filter}>
<div>
<Input placeholder="搜索" style={{ width: 220 }} value={keywords} allowClear onChange={handleInputChange} />
<Select
showSearch
placeholder="是否启用"
optionFilterProp="children"
value={available_int}
onChange={handleSelectChange}
style={{ width: 220 }}
options={[
{
value: -1,
label: '全部',
},
{
value: 1,
label: '启用',
},
{
value: 0,
label: '未启用',
},
]}
/>
setAvailableInt(value);
};
return (
<>
<div className={styles.chunkPage}>
<div className={styles.filter}>
<div>
<Input
placeholder="搜索"
style={{ width: 220 }}
value={keywords}
allowClear
onChange={handleInputChange}
/>
<Select
showSearch
placeholder="是否启用"
optionFilterProp="children"
value={available_int}
onChange={handleSelectChange}
style={{ width: 220 }}
options={[
{
value: -1,
label: '全部',
},
{
value: 1,
label: '启用',
},
{
value: 0,
label: '未启用',
},
]}
/>
</div>
<Button
onClick={() => {
handleEditchunk();
}}
type="link"
>
</Button>
</div>
<Button onClick={() => { handleEditchunk() }} type='link'></Button>
</div>
<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.chunk_id) }}
<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}
>
<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.available_int == '1'} onChange={(checked: boolean, e: any) => {
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation(); switchChunk(item.chunk_id, checked)
}} />
</span>
<Card
className={styles.card}
onClick={() => {
handleEditchunk(item.chunk_id);
}}
>
<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.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 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>
</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.pageFooter}>
<Pagination
responsive
showLessItems
showQuickJumper
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} />
</>
)
<CreateModal
doc_id={doc_id}
isShowCreateModal={isShowCreateModal}
chunk_id={chunk_id}
getChunkList={getChunkList}
/>
</>
);
};
export default connect(({ chunkModel, loading }) => ({ chunkModel, loading }))(Index);
export default Chunk;

View File

@ -1,8 +1,7 @@
import kbService from '@/services/kbService';
import { Effect, Reducer } from 'umi';
import { DvaModel } from 'umi';
export interface chunkModelState {
loading: boolean;
export interface ChunkModelState {
data: any[];
total: number;
isShowCreateModal: boolean;
@ -10,25 +9,10 @@ export interface chunkModelState {
doc_id: string;
chunkInfo: any;
}
export interface chunkgModelType {
namespace: 'chunkModel';
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 = {
const model: DvaModel<ChunkModelState> = {
namespace: 'chunkModel',
state: {
loading: false,
data: [],
total: 0,
isShowCreateModal: false,
@ -36,6 +20,14 @@ const Model: chunkgModelType = {
doc_id: '',
chunkInfo: {},
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload,
};
},
},
// subscriptions: {
// setup({ dispatch, history }) {
// history.listen(location => {
@ -44,7 +36,7 @@ const Model: chunkgModelType = {
// }
// },
effects: {
*chunk_list({ payload = {}, callback }, { call, put }) {
*chunk_list({ payload = {} }, { call, put }) {
const { data, response } = yield call(kbService.chunk_list, payload);
const { retcode, data: res, retmsg } = data;
@ -55,28 +47,23 @@ const Model: chunkgModelType = {
payload: {
data: res.chunks,
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 { retcode, data: res, retmsg } = data;
if (retcode === 0) {
callback && callback();
}
return retcode;
},
*rm_chunk({ payload = {}, callback }, { call, put }) {
*rm_chunk({ payload = {} }, { call, put }) {
console.log('shanchu');
const { data, response } = yield call(kbService.rm_chunk, payload);
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 { retcode, data: res, retmsg } = data;
if (retcode === 0) {
@ -86,28 +73,16 @@ const Model: chunkgModelType = {
chunkInfo: res,
},
});
callback && callback(res);
}
return data;
},
*create_hunk({ payload = {} }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true,
},
});
let service = kbService.create_chunk;
if (payload.chunk_id) {
service = kbService.set_chunk;
}
const { data, response } = yield call(service, payload);
const { retcode, data: res, retmsg } = data;
yield put({
type: 'updateState',
payload: {
loading: false,
},
});
if (retcode === 0) {
yield put({
type: 'updateState',
@ -118,13 +93,5 @@ const Model: chunkgModelType = {
}
},
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload,
};
},
},
};
export default Model;
export default model;

View File

@ -1,79 +1,73 @@
import React from 'react'
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { useTranslation, Trans } from 'react-i18next'
import { Input, Modal, Form } from 'antd'
import styles from './index.less';
import type { kFModelState } from './model'
import { Form, Input, Modal } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
type FieldType = {
name?: string;
name?: string;
};
interface kFProps {
dispatch: Dispatch;
kFModel: kFModelState;
getKfList: () => void;
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) {
console.log('Failed:', errorInfo);
}
};
const FileCreatingModal: React.FC<kFProps> = ({ getKfList, kb_id }) => {
const dispatch = useDispatch();
const kFModel = useSelector((state: any) => state.kFModel);
const { isShowCEFwModal } = kFModel;
const [form] = Form.useForm();
const { t } = useTranslation();
return (
<Modal title="Basic Modal" open={isShowCEFwModal} onOk={handleOk} onCancel={handleCancel}>
<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>
const handleCancel = () => {
dispatch({
type: 'kFModel/updateState',
payload: {
isShowCEFwModal: false,
},
});
};
const handleOk = async () => {
try {
const values = await form.validateFields();
const retcode = await dispatch<any>({
type: 'kFModel/document_create',
payload: {
name: values.name,
kb_id,
},
});
if (retcode === 0) {
getKfList && getKfList();
}
} catch (errorInfo) {
console.log('Failed:', errorInfo);
}
};
</Form>
</Modal >
);
}
export default connect(({ kFModel, loading }) => ({ kFModel, loading }))(Index);
return (
<Modal
title="Basic Modal"
open={isShowCEFwModal}
onOk={handleOk}
onCancel={handleCancel}
>
<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;

View File

@ -1,228 +1,273 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { connect, Dispatch, useNavigate } from 'umi'
import { Space, Table, Input, Button, Switch, Dropdown, } from 'antd';
import { getOneNamespaceEffectsLoading } from '@/utils/stroreUtil';
import { DownOutlined } from '@ant-design/icons';
import type { MenuProps } from 'antd';
import { DownOutlined } from '@ant-design/icons'
import { debounce } from 'lodash';
import { Button, Dropdown, Input, Space, Switch, Table } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import UploadFile from './upload'
import CreateEPModal from './createEFileModal'
import SegmentSetModal from './segmentSetModal'
import styles from './index.less'
import type { kFModelState } from './model'
import { debounce } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useNavigate, useSelector } from 'umi';
import CreateEPModal from './createEFileModal';
import styles from './index.less';
import SegmentSetModal from './segmentSetModal';
import UploadFile from './upload';
interface DataType {
name: string;
chunk_num: string;
token_num: number;
update_date: string;
size: string;
status: string;
id: string;
parser_id: string
name: string;
chunk_num: string;
token_num: number;
update_date: string;
size: string;
status: string;
id: string;
parser_id: string;
}
interface kFProps {
dispatch: Dispatch;
kFModel: kFModelState;
kb_id: string
interface KFProps {
kb_id: string;
}
const Index: React.FC<kFProps> = ({ kFModel, dispatch, kb_id }) => {
const { data, loading } = kFModel
const [inputValue, setInputValue] = useState('')
const [doc_id, setDocId] = useState('0')
const [parser_id, setParserId] = useState('0')
let navigate = useNavigate();
const getKfList = (keywords?: string) => {
const payload = {
kb_id,
keywords
}
if (!keywords) {
delete payload.keywords
}
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 KnowledgeFile: React.FC<KFProps> = ({ kb_id }) => {
const dispatch = useDispatch();
const kFModel = useSelector((state: any) => state.kFModel);
const effects = useSelector((state: any) => state.loading.effects);
const { data } = kFModel;
const loading = getOneNamespaceEffectsLoading('kFModel', effects, [
'getKfList',
'updateDocumentStatus',
]);
const [inputValue, setInputValue] = useState('');
const [doc_id, setDocId] = useState('0');
const [parser_id, setParserId] = useState('0');
let navigate = useNavigate();
}
const onChangeStatus = (e: boolean, doc_id: string) => {
dispatch({
type: 'kFModel/updateDocumentStatus',
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
}
});
const getKfList = (keywords?: string) => {
const payload = {
kb_id,
keywords,
};
const showSegmentSetModal = () => {
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}`);
if (!keywords) {
delete payload.keywords;
}
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>
),
},
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 onChangeStatus = (e: boolean, doc_id: string) => {
dispatch({
type: 'kFModel/updateDocumentStatus',
payload: {
doc_id,
status: Number(e),
kb_id,
},
});
};
const onRmDocument = () => {
dispatch({
type: 'kFModel/document_rm',
payload: {
doc_id,
kb_id,
},
});
};
const showCEFModal = () => {
dispatch({
type: 'kFModel/updateState',
payload: {
isShowCEFwModal: true,
},
});
};
const showSegmentSetModal = () => {
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 <>
<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>
}, [kb_id]);
const chunkItems: MenuProps['items'] = [
{
key: '1',
label: (
<div>
<Button type="link" onClick={showSegmentSetModal}>
{' '}
</Button>
</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;

View File

@ -1,57 +1,47 @@
import kbService from '@/services/kbService';
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;
isShowTntModal: boolean;
isShowSegmentSetModal: boolean;
loading: boolean;
tenantIfo: any;
data: any[];
}
export interface kFModelType {
namespace: 'kFModel';
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 = {
const model: DvaModel<KFModelState> = {
namespace: 'kFModel',
state: {
isShowCEFwModal: false,
isShowTntModal: false,
isShowSegmentSetModal: false,
loading: false,
tenantIfo: {},
data: [],
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload,
};
},
},
subscriptions: {
setup({ dispatch, history }) {
history.listen((location) => {});
},
},
effects: {
*createKf({ payload = {}, callback }, { call, put }) {
*createKf({ payload = {} }, { call, put }) {
const { data, response } = yield call(kbService.createKb, payload);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
message.success('创建成功!');
}
},
*updateKf({ payload = {}, callback }, { call, put }) {
*updateKf({ payload = {} }, { call, put }) {
const { data, response } = yield call(kbService.updateKb, payload);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
@ -67,23 +57,12 @@ const Model: kFModelType = {
}
},
*getKfList({ payload = {} }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true,
},
});
const { data, response } = yield call(
kbService.get_document_list,
payload,
);
const { retcode, data: res, retmsg } = data;
yield put({
type: 'updateState',
payload: {
loading: false,
},
});
if (retcode === 0) {
yield put({
type: 'updateState',
@ -93,64 +72,64 @@ const Model: kFModelType = {
});
}
},
*updateDocumentStatus({ payload = {}, callback }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true,
},
});
*updateDocumentStatus({ payload = {} }, { call, put }) {
const { data, response } = yield call(
kbService.document_change_status,
payload,
pick(payload, ['doc_id', 'status']),
);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
message.success('修改成功!');
yield put({
type: 'updateState',
payload: {
loading: false,
},
put({
type: 'getKfList',
payload: { kb_id: payload.kb_id },
});
callback && callback();
}
},
*document_rm({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.document_rm, payload);
*document_rm({ payload = {} }, { call, put }) {
const { data, response } = yield call(kbService.document_rm, {
doc_id: payload.doc_id,
});
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
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 { retcode, data: res, retmsg } = data;
if (retcode === 0) {
put({
type: 'kFModel/updateState',
payload: {
isShowCEFwModal: false,
},
});
message.success('创建成功!');
callback && callback();
}
return retcode;
},
*document_change_parser({ payload = {}, callback }, { call, put }) {
*document_change_parser({ payload = {} }, { call, put }) {
const { data, response } = yield call(
kbService.document_change_parser,
payload,
);
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
put({
type: 'updateState',
payload: {
isShowSegmentSetModal: false,
},
});
message.success('修改成功!');
callback && callback();
}
},
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload,
};
return retcode;
},
},
};
export default Model;
export default model;

View File

@ -1,91 +1,87 @@
import React from 'react';
import { connect, Dispatch } from 'umi';
import i18n from 'i18next';
import { useTranslation, } from 'react-i18next'
import { Modal, Tag, Space } from 'antd'
import { useEffect, useState } from 'react';
import { Modal, Space, Tag } from 'antd';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'umi';
import styles from './index.less';
import type { kFModelState } from './model'
import type { settingModelState } from '@/pages/setting/model'
const { CheckableTag } = Tag;
interface kFProps {
dispatch: Dispatch;
kFModel: kFModelState;
settingModel: settingModelState;
getKfList: () => void;
parser_id: string;
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 [selectedTag, setSelectedTag] = useState('')
const { tenantIfo = {} } = settingModel
const { parser_ids = '' } = tenantIfo
useEffect(() => {
dispatch({
type: 'settingModel/getTenantInfo',
payload: {
}
});
setSelectedTag(parser_id)
}, [parser_id])
const { isShowSegmentSetModal } = kFModel
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 SegmentSetModal: React.FC<kFProps> = ({
getKfList,
parser_id,
doc_id,
}) => {
const dispatch = useDispatch();
const kFModel = useSelector((state: any) => state.kFModel);
const settingModel = useSelector((state: any) => state.settingModel);
const [selectedTag, setSelectedTag] = useState('');
const { tenantIfo = {} } = settingModel;
const { parser_ids = '' } = tenantIfo;
const { isShowSegmentSetModal } = kFModel;
const { t } = useTranslation();
const handleChange = (tag: string, checked: boolean) => {
const nextSelectedTag = checked
? tag
: selectedTag;
console.log('You are interested in: ', nextSelectedTag);
setSelectedTag(nextSelectedTag);
};
useEffect(() => {
dispatch({
type: 'settingModel/getTenantInfo',
payload: {},
});
setSelectedTag(parser_id);
}, [parser_id]);
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 >
const handleCancel = () => {
dispatch({
type: 'kFModel/updateState',
payload: {
isShowSegmentSetModal: false,
},
});
};
const handleOk = async () => {
console.log(1111, selectedTag);
const retcode = await dispatch<any>({
type: 'kFModel/document_change_parser',
payload: {
parser_id: selectedTag,
doc_id,
},
});
);
}
export default connect(({ kFModel, settingModel, loading }) => ({ kFModel, settingModel, loading }))(Index);
retcode === 0 && getKfList && getKfList();
};
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;

View File

@ -1,33 +1,39 @@
import React from 'react';
import { connect } from 'umi'
import uploadService from '@/services/uploadService';
import type { UploadProps } from 'antd';
import { Button, Upload } from 'antd';
import uploadService from '@/services/uploadService'
import React from 'react';
interface PropsType {
kb_id: string;
getKfList: () => void
kb_id: string;
getKfList: () => void;
}
type UploadRequestOption = Parameters<
NonNullable<UploadProps["customRequest"]>
NonNullable<UploadProps['customRequest']>
>[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 {
onError && onError(data);
}
getKfList && getKfList()
};
const uploadProps: UploadProps = {
customRequest: createRequest,
showUploadList: false,
};
return (<Upload {...uploadProps} >
<Button type="link"></Button>
</Upload>)
}
const FileUpload: 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 {
onError && onError(data);
}
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;

View File

@ -1,247 +1,278 @@
import React, { useEffect, useState, useCallback, } from 'react';
import { useNavigate, connect, Dispatch } from 'umi'
import { Card, Row, Col, Input, Select, Switch, Pagination, Spin, Button, Popconfirm } from 'antd';
import { MinusSquareOutlined, DeleteOutlined, } from '@ant-design/icons';
import { api_host } from '@/utils/api';
import { DeleteOutlined, MinusSquareOutlined } from '@ant-design/icons';
import type { PaginationProps } from 'antd';
import { api_host } from '@/utils/api'
import CreateModal from '../knowledge-chunk/components/createModal'
import {
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 styles from './index.less'
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
import { debounce } from 'lodash';
import type { kSearchModelState } from './model'
import type { chunkModelState } from '../knowledge-chunk/model'
import styles from './index.less';
interface chunkProps {
dispatch: Dispatch;
kSearchModel: kSearchModelState;
chunkModel: chunkModelState;
kb_id: string
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 { chunk_id, doc_id, isShowCreateModal } = chunkModel
const KnowledgeSearching: React.FC<chunkProps> = ({ kb_id }) => {
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 = () => {
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({
type: 'kSearchModel/chunk_list',
payload: {
...payload,
...pagination
}
kb_id,
},
});
}
};
const confirm = (id: string) => {
console.log(id)
dispatch({
type: 'kSearchModel/rm_chunk',
payload: {
chunk_ids: [id]
chunk_ids: [id],
kb_id,
},
callback: getChunkList
});
};
const handleEditchunk = (item: any) => {
const { chunk_id, doc_id } = item
const { chunk_id, doc_id } = item;
dispatch({
type: 'chunkModel/updateState',
payload: {
isShowCreateModal: true,
chunk_id,
doc_id
doc_id,
},
callback: getChunkList
});
}
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (page, size) => {
getChunkList();
};
const onShowSizeChange: PaginationProps['onShowSizeChange'] = (
page,
size,
) => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
pagination: { page, size }
}
pagination: { page, size },
},
});
};
useEffect(() => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
loading: false,
doc_ids: [],
question: ""
}
question: '',
},
});
dispatch({
type: 'kSearchModel/getKfList',
payload: {
kb_id
}
kb_id,
},
});
}, [])
}, []);
const switchChunk = (item: any, available_int: boolean) => {
const { chunk_id, doc_id } = item
dispatch({
type: 'kSearchModel/updateState',
payload: {
loading: true
}
});
const { chunk_id, doc_id } = item;
dispatch({
type: 'kSearchModel/switch_chunk',
payload: {
chunk_ids: [chunk_id],
doc_id,
available_int
available_int,
kb_id,
},
callback: getChunkList
});
}
};
useEffect(() => {
getChunkList()
}, [doc_ids, pagination, question])
getChunkList();
}, [doc_ids, pagination, question]);
const debounceChange = debounce((value) => {
dispatch({
type: 'kSearchModel/updateState',
payload: {
question: value
}
question: value,
},
});
}, 300)
const debounceCallback = useCallback((value: string) => debounceChange(value), [])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const value = e.target.value
debounceCallback(value)
}
const handleSelectChange = (value:
any[]) => {
}, 300);
const debounceCallback = useCallback(
(value: string) => debounceChange(value),
[],
);
const handleInputChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const value = e.target.value;
debounceCallback(value);
};
const handleSelectChange = (value: any[]) => {
dispatch({
type: 'kSearchModel/updateState',
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>
<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}
<Input.TextArea
autoSize={{ minRows: 6, maxRows: 6 }}
placeholder="搜索"
style={{ width: 300 }}
allowClear
onChange={handleInputChange}
/>
</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 getChunkList={getChunkList} isShowCreateModal={isShowCreateModal} chunk_id={chunk_id} doc_id={doc_id} />
</>
)
<CreateModal
getChunkList={getChunkList}
isShowCreateModal={isShowCreateModal}
chunk_id={chunk_id}
doc_id={doc_id}
/>
</>
);
};
export default connect(({ kSearchModel, chunkModel, loading }) => ({ kSearchModel, chunkModel, loading }))(Index);
export default KnowledgeSearching;

View File

@ -1,8 +1,8 @@
import { Effect, Reducer, Subscription } from 'umi'
import { message } from 'antd';
import kbService from '@/services/kbService';
import omit from 'lodash/omit';
import { DvaModel } from 'umi';
export interface kSearchModelState {
export interface KSearchModelState {
loading: boolean;
data: any[];
total: number;
@ -13,26 +13,10 @@ export interface kSearchModelState {
question: string;
doc_ids: any[];
pagination: any;
doc_id: string
doc_id: string;
}
}
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 = {
const model: DvaModel<KSearchModelState> = {
namespace: 'kSearchModel',
state: {
loading: false,
@ -45,114 +29,132 @@ const Model: chunkgModelType = {
question: '',
doc_ids: [],
pagination: { page: 1, size: 30 },
doc_id: ''
doc_id: '',
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload,
};
},
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
console.log(location)
history.listen((location) => {
console.log(location);
});
}
},
},
effects: {
*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) {
yield put({
type: 'updateState',
payload: {
d_list: res
}
d_list: res,
},
});
}
},
* chunk_list({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.retrieval_test, payload);
const { retcode, data: res, retmsg } = data
*chunk_list({ payload = {} }, { call, put, select }) {
const { question, doc_ids, pagination }: KSearchModelState = yield select(
(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) {
console.log(res)
yield put({
type: 'updateState',
payload: {
data: res.chunks,
total: res.total,
loading: false
}
},
});
callback && callback()
}
},
*switch_chunk({ payload = {}, callback }, { call, put }) {
const { data, response } = yield call(kbService.switch_chunk, payload);
const { retcode, data: res, retmsg } = data
*switch_chunk({ payload = {} }, { call, put }) {
const { data } = yield call(
kbService.switch_chunk,
omit(payload, ['kb_id']),
);
const { retcode } = data;
if (retcode === 0) {
callback && callback()
yield put({
type: 'chunk_list',
payload: {
kb_id: payload.kb_id,
},
});
}
},
*rm_chunk({ payload = {}, callback }, { call, put }) {
console.log('shanchu')
const { data, response } = yield call(kbService.rm_chunk, payload);
const { retcode, data: res, retmsg } = data
*rm_chunk({ payload = {} }, { call, put }) {
const { data } = yield call(kbService.rm_chunk, {
chunk_ids: payload.chunk_ids,
});
const { retcode, data: res, retmsg } = data;
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 { retcode, data: res, retmsg } = data
const { retcode, data: res, retmsg } = data;
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
chunkInfo: res
}
chunkInfo: res,
},
});
callback && callback(res)
}
},
*create_hunk({ payload = {} }, { call, put }) {
yield put({
type: 'updateState',
payload: {
loading: true
}
loading: true,
},
});
let service = kbService.create_chunk
let service = kbService.create_chunk;
if (payload.chunk_id) {
service = kbService.set_chunk
service = kbService.set_chunk;
}
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
}
loading: false,
},
});
if (retcode === 0) {
yield put({
type: 'updateState',
payload: {
isShowCreateModal: false
}
isShowCreateModal: false,
},
});
}
},
},
reducers: {
updateState(state, { payload }) {
return {
...state,
...payload
};
}
}
};
export default Model;
export default model;

View File

@ -1,170 +1,157 @@
import React, { useEffect, useState } from 'react';
import { useNavigate, connect, Dispatch } from 'umi'
import { Button, Form, Input, Radio, Select, Tag, Space, } from 'antd';
import type { kSModelState } from './model'
import type { settingModelState } from '@/pages/setting/model'
import styles from './index.less'
import { Button, Form, Input, Radio, Select, Space, Tag } from 'antd';
import React, { useCallback, useEffect, useState } from 'react';
import { useDispatch, useNavigate, useSelector } from 'umi';
import styles from './index.less';
const { CheckableTag } = Tag;
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
labelAlign: 'left' as const
labelCol: { span: 8 },
wrapperCol: { span: 16 },
labelAlign: 'left' as const,
};
const { Option } = Select
const { Option } = Select;
/* eslint-disable no-template-curly-in-string */
interface kSProps {
dispatch: Dispatch;
kSModel: kSModelState;
settingModel: settingModelState;
kb_id: string
kb_id: string;
}
const Index: React.FC<kSProps> = ({ settingModel, kSModel, dispatch, kb_id }) => {
let navigate = useNavigate();
const { tenantIfo = {} } = settingModel
const { parser_ids = '', embd_id = '' } = tenantIfo
const [form] = Form.useForm();
const KnowledgeSetting: React.FC<kSProps> = ({ kb_id }) => {
const dispatch = useDispatch();
const settingModel = useSelector((state: any) => state.settingModel);
let navigate = useNavigate();
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({
type: 'settingModel/getTenantInfo',
payload: {
}
type: 'kSModel/updateKb',
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({
type: 'kSModel/getKbDetail',
payload: {
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)
}
});
}
useEffect(() => {
getTenantInfo();
}, [getTenantInfo]);
}, [kb_id])
const [selectedTag, setSelectedTag] = useState('')
const values = Form.useWatch([], form);
console.log(values, '......变化')
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}`);
}
});
}
},
() => {
const handleChange = (tag: string, checked: boolean) => {
const nextSelectedTag = checked ? tag : selectedTag;
console.log('You are interested in: ', nextSelectedTag);
setSelectedTag(nextSelectedTag);
};
},
);
};
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 }}
return (
<Form
{...layout}
form={form}
name="validateOnly"
style={{ maxWidth: 1000, padding: 14 }}
>
<Form.Item name='name' label="知识库名称" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name='description' label="知识库描述">
<Input.TextArea />
</Form.Item>
<Form.Item name="permission" label="可见权限">
<Radio.Group>
<Radio value="me"></Radio>
<Radio value="team"></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
name="embd_id"
label="Embedding 模型"
hasFeedback
rules={[{ required: true, message: 'Please select your country!' }]}
>
<Select placeholder="Please select a country" >
{embd_id.split(',').map((item: string) => {
return <Option value={item} key={item}>{item}</Option>
})}
</Select>
</Form.Item>
<div style={{ marginTop: '5px' }}>
Embedding <span style={{ color: '#1677ff' }}></span>
<Form.Item name="name" label="知识库名称" rules={[{ required: true }]}>
<Input />
</Form.Item>
<Form.Item name="description" label="知识库描述">
<Input.TextArea />
</Form.Item>
<Form.Item name="permission" label="可见权限">
<Radio.Group>
<Radio value="me"></Radio>
<Radio value="team"></Radio>
</Radio.Group>
</Form.Item>
<Form.Item
name="embd_id"
label="Embedding 模型"
hasFeedback
rules={[{ required: true, message: 'Please select your country!' }]}
>
<Select placeholder="Please select a country">
{embd_id.split(',').map((item: string) => {
return (
<Option value={item} key={item}>
{item}
</Option>
);
})}
</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>
<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>
<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>
</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>
}
);
};
export default connect(({ settingModel, kSModel, loading }) => ({ settingModel, kSModel, loading }))(Index);
export default KnowledgeSetting;

View File

@ -1,72 +1,54 @@
import { message } from 'antd';
import { Effect, Reducer, Subscription } from 'umi'
import kbService from '@/services/kbService';
import { message } from 'antd';
import { DvaModel } from 'umi';
export interface kSModelState {
export interface KSModelState {
isShowPSwModal: boolean;
isShowTntModal: boolean;
loading: boolean;
tenantIfo: any
tenantIfo: any;
}
export interface kSModelType {
namespace: 'kSModel';
state: kSModelState;
effects: {
createKb: Effect;
updateKb: Effect;
getKbDetail: Effect;
};
reducers: {
updateState: Reducer<kSModelState>;
};
subscriptions: { setup: Subscription };
}
const Model: kSModelType = {
const model: DvaModel<KSModelState> = {
namespace: 'kSModel',
state: {
isShowPSwModal: false,
isShowTntModal: false,
loading: false,
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)
}
},
tenantIfo: {},
},
reducers: {
updateState(state, { payload }) {
return {
...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;