balibabu commited on
Commit
362ec6c
·
1 Parent(s): 96a1a44

feat: remove loading from model and use DvaModel instead of redundant types such as kAModelType (#47)

Browse files

* feat: use DvaModel instead of redundant types such as kAModelType

* feat: set the type for registerServer

* feat: remove loading from model

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