mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-04-23 22:50:17 +08:00
feat: create chunk and edit chunk and delete chunk (#58)
* feat: create chunk and edit chunk * feat: delete chunk * feat: search chunks * feat: delete chunks in batches * feat: set whether chunks are available in batches
This commit is contained in:
parent
97d4387982
commit
eb8254e688
115
web/package-lock.json
generated
115
web/package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
|
"rc-tween-one": "^3.0.6",
|
||||||
"react-i18next": "^14.0.0",
|
"react-i18next": "^14.0.0",
|
||||||
"react-infinite-scroll-component": "^6.1.0",
|
"react-infinite-scroll-component": "^6.1.0",
|
||||||
"umi": "^4.0.90",
|
"umi": "^4.0.90",
|
||||||
@ -6508,6 +6509,16 @@
|
|||||||
"type": "^1.0.1"
|
"type": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/d3-array": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
|
||||||
|
},
|
||||||
|
"node_modules/d3-polygon": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/d3-polygon/-/d3-polygon-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ=="
|
||||||
|
},
|
||||||
"node_modules/data-uri-to-buffer": {
|
"node_modules/data-uri-to-buffer": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||||
@ -6994,6 +7005,11 @@
|
|||||||
"dva-core": "^1.1.0 || ^1.5.0-0 || ^1.6.0-0"
|
"dva-core": "^1.1.0 || ^1.5.0-0 || ^1.6.0-0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/earcut": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/earcut/-/earcut-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
|
||||||
|
},
|
||||||
"node_modules/easy-icons": {
|
"node_modules/easy-icons": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmmirror.com/easy-icons/-/easy-icons-1.1.5.tgz",
|
"resolved": "https://registry.npmmirror.com/easy-icons/-/easy-icons-1.1.5.tgz",
|
||||||
@ -8324,6 +8340,24 @@
|
|||||||
"deprecated": "flatten is deprecated in favor of utility frameworks such as lodash.",
|
"deprecated": "flatten is deprecated in favor of utility frameworks such as lodash.",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/flubber": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/flubber/-/flubber-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-79RkJe3rA4nvRCVc2uXjj7U/BAUq84TS3KHn6c0Hr9K64vhj83ZNLUziNx4pJoBumSPhOl5VjH+Z0uhi+eE8Uw==",
|
||||||
|
"dependencies": {
|
||||||
|
"d3-array": "^1.2.0",
|
||||||
|
"d3-polygon": "^1.0.3",
|
||||||
|
"earcut": "^2.1.1",
|
||||||
|
"svg-path-properties": "^0.2.1",
|
||||||
|
"svgpath": "^2.2.1",
|
||||||
|
"topojson-client": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/flubber/node_modules/svg-path-properties": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/svg-path-properties/-/svg-path-properties-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-GmrB+b6woz6CCdQe6w1GHs/1lt25l7SR5hmhF8jRdarpv/OgjLyuQygLu1makJapixeb1aQhP/Oa1iKi93o/aQ=="
|
||||||
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.4",
|
"version": "1.15.4",
|
||||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||||
@ -11847,6 +11881,11 @@
|
|||||||
"node": ">=0.12"
|
"node": ">=0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/performance-now": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz",
|
||||||
@ -12777,6 +12816,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"dependencies": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ramda": {
|
"node_modules/ramda": {
|
||||||
"version": "0.27.2",
|
"version": "0.27.2",
|
||||||
"resolved": "https://registry.npmmirror.com/ramda/-/ramda-0.27.2.tgz",
|
"resolved": "https://registry.npmmirror.com/ramda/-/ramda-0.27.2.tgz",
|
||||||
@ -13325,6 +13372,23 @@
|
|||||||
"react-dom": "*"
|
"react-dom": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rc-tween-one": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/rc-tween-one/-/rc-tween-one-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-5zTSXyyv7bahDBQ/kJw/kNxxoBqTouttoelw8FOVOyWqmTMndizJEpvaj1N+yES5Xjss6Y2iVw+9vSJQZE8Z6g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.11.1",
|
||||||
|
"style-utils": "^0.3.4",
|
||||||
|
"tween-one": "^1.0.50"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.x"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.9.0",
|
||||||
|
"react-dom": ">=16.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rc-upload": {
|
"node_modules/rc-upload": {
|
||||||
"version": "4.5.2",
|
"version": "4.5.2",
|
||||||
"resolved": "https://registry.npmmirror.com/rc-upload/-/rc-upload-4.5.2.tgz",
|
"resolved": "https://registry.npmmirror.com/rc-upload/-/rc-upload-4.5.2.tgz",
|
||||||
@ -15285,6 +15349,11 @@
|
|||||||
"integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==",
|
"integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
|
"node_modules/style-utils": {
|
||||||
|
"version": "0.3.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/style-utils/-/style-utils-0.3.8.tgz",
|
||||||
|
"integrity": "sha512-RmGftIhY4tqtD1ERwKsVEDlt/M6UyxN/rcr95UmlooWmhtL0RwVUYJkpo1kSx3ppd9/JZzbknhy742zbMAawjQ=="
|
||||||
|
},
|
||||||
"node_modules/stylelint": {
|
"node_modules/stylelint": {
|
||||||
"version": "14.16.1",
|
"version": "14.16.1",
|
||||||
"resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz",
|
"resolved": "https://registry.npmmirror.com/stylelint/-/stylelint-14.16.1.tgz",
|
||||||
@ -15467,6 +15536,11 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz",
|
"resolved": "https://registry.npmmirror.com/svg-parser/-/svg-parser-2.0.4.tgz",
|
||||||
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="
|
"integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/svg-path-properties": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/svg-path-properties/-/svg-path-properties-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-R1+z37FrqyS3UXDhajNfvMxKI0smuVdedqOo4YbAQUfGqA86B9mGvr2IEXrwjjvGzCtdIKy/ad9N8m6YclaKAw=="
|
||||||
|
},
|
||||||
"node_modules/svg-tags": {
|
"node_modules/svg-tags": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/svg-tags/-/svg-tags-1.0.0.tgz",
|
||||||
@ -15501,6 +15575,11 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svgpath": {
|
||||||
|
"version": "2.6.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/svgpath/-/svgpath-2.6.0.tgz",
|
||||||
|
"integrity": "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg=="
|
||||||
|
},
|
||||||
"node_modules/swr": {
|
"node_modules/swr": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmmirror.com/swr/-/swr-2.2.4.tgz",
|
"resolved": "https://registry.npmmirror.com/swr/-/swr-2.2.4.tgz",
|
||||||
@ -15815,6 +15894,24 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/toggle-selection/-/toggle-selection-1.0.6.tgz",
|
||||||
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
|
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/topojson-client": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/topojson-client/-/topojson-client-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"topo2geo": "bin/topo2geo",
|
||||||
|
"topomerge": "bin/topomerge",
|
||||||
|
"topoquantize": "bin/topoquantize"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/topojson-client/node_modules/commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||||
|
},
|
||||||
"node_modules/trim-newlines": {
|
"node_modules/trim-newlines": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/trim-newlines/-/trim-newlines-3.0.1.tgz",
|
||||||
@ -16235,6 +16332,24 @@
|
|||||||
"resolved": "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||||
"integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw=="
|
"integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/tween-functions": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tween-functions/-/tween-functions-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-PZBtLYcCLtEcjL14Fzb1gSxPBeL7nWvGhO5ZFPGqziCcr8uvHp0NDmdjBchp6KHL+tExcg0m3NISmKxhU394dA=="
|
||||||
|
},
|
||||||
|
"node_modules/tween-one": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tween-one/-/tween-one-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-F+Z9LO9GsYqf0j5bgNhAF98RDrAZ7QjQrujJ2lVYSHl4+dBPW/atHluL2bwclZf8Vo0Yo96f6pw2uq1OGzpC/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.11.1",
|
||||||
|
"flubber": "^0.4.2",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"style-utils": "^0.3.6",
|
||||||
|
"svg-path-properties": "^1.0.4",
|
||||||
|
"tween-functions": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type": {
|
"node_modules/type": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz",
|
"resolved": "https://registry.npmmirror.com/type/-/type-1.2.0.tgz",
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
|
"rc-tween-one": "^3.0.6",
|
||||||
"react-i18next": "^14.0.0",
|
"react-i18next": "^14.0.0",
|
||||||
"react-infinite-scroll-component": "^6.1.0",
|
"react-infinite-scroll-component": "^6.1.0",
|
||||||
"umi": "^4.0.90",
|
"umi": "^4.0.90",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import showDeleteConfirm from '@/components/deleting-confirm';
|
import showDeleteConfirm from '@/components/deleting-confirm';
|
||||||
import { IKnowledge } from '@/interfaces/database/knowledge';
|
import { IKnowledge } from '@/interfaces/database/knowledge';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
||||||
|
|
||||||
export const useKnowledgeBaseId = (): string => {
|
export const useKnowledgeBaseId = (): string => {
|
||||||
@ -46,3 +47,33 @@ export const useGetDocumentDefaultParser = (knowledgeBaseId: string) => {
|
|||||||
parserConfig: item?.parser_config ?? '',
|
parserConfig: item?.parser_config ?? '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useDeleteChunkByIds = (): {
|
||||||
|
removeChunk: (chunkIds: string[], documentId: string) => Promise<number>;
|
||||||
|
} => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const removeChunk = useCallback(
|
||||||
|
(chunkIds: string[], documentId: string) => () => {
|
||||||
|
return dispatch({
|
||||||
|
type: 'chunkModel/rm_chunk',
|
||||||
|
payload: {
|
||||||
|
chunk_ids: chunkIds,
|
||||||
|
doc_id: documentId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onRemoveChunk = useCallback(
|
||||||
|
(chunkIds: string[], documentId: string): Promise<number> => {
|
||||||
|
return showDeleteConfirm({ onOk: removeChunk(chunkIds, documentId) });
|
||||||
|
},
|
||||||
|
[removeChunk],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
removeChunk: onRemoveChunk,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -6,3 +6,11 @@
|
|||||||
.imagePreview {
|
.imagePreview {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
em {
|
||||||
|
color: red;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { IChunk } from '@/interfaces/database/knowledge';
|
import { IChunk } from '@/interfaces/database/knowledge';
|
||||||
import { api_host } from '@/utils/api';
|
import { api_host } from '@/utils/api';
|
||||||
import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd';
|
import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd';
|
||||||
import { useDispatch } from 'umi';
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
@ -9,6 +8,8 @@ import styles from './index.less';
|
|||||||
interface IProps {
|
interface IProps {
|
||||||
item: IChunk;
|
item: IChunk;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
switchChunk: (available?: number, chunkIds?: string[]) => void;
|
||||||
|
editChunk: (chunkId: string) => void;
|
||||||
handleCheckboxClick: (chunkId: string, checked: boolean) => void;
|
handleCheckboxClick: (chunkId: string, checked: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,32 +29,29 @@ const Image = ({ id, className, ...props }: IImage) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChunkCard = ({ item, checked, handleCheckboxClick }: IProps) => {
|
const ChunkCard = ({
|
||||||
const dispatch = useDispatch();
|
item,
|
||||||
|
checked,
|
||||||
|
handleCheckboxClick,
|
||||||
|
editChunk,
|
||||||
|
switchChunk,
|
||||||
|
}: IProps) => {
|
||||||
const available = Number(item.available_int);
|
const available = Number(item.available_int);
|
||||||
const [enabled, setEnabled] = useState(available === 1);
|
const [enabled, setEnabled] = useState(available === 1);
|
||||||
|
|
||||||
const switchChunk = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/switch_chunk',
|
|
||||||
payload: {
|
|
||||||
chunk_ids: [item.chunk_id],
|
|
||||||
available_int: available === 0 ? 1 : 0,
|
|
||||||
doc_id: item.doc_id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChange = (checked: boolean) => {
|
const onChange = (checked: boolean) => {
|
||||||
setEnabled(checked);
|
setEnabled(checked);
|
||||||
switchChunk();
|
switchChunk(available === 0 ? 1 : 0, [item.chunk_id]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheck: CheckboxProps['onChange'] = (e) => {
|
const handleCheck: CheckboxProps['onChange'] = (e) => {
|
||||||
handleCheckboxClick(item.chunk_id, e.target.checked);
|
handleCheckboxClick(item.chunk_id, e.target.checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleContentClick = () => {
|
||||||
|
editChunk(item.chunk_id);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card>
|
<Card>
|
||||||
@ -75,7 +73,13 @@ const ChunkCard = ({ item, checked, handleCheckboxClick }: IProps) => {
|
|||||||
</Popover>
|
</Popover>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<section>{item.content_with_weight}</section>
|
<section
|
||||||
|
onDoubleClick={handleContentClick}
|
||||||
|
className={styles.content}
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.content_with_weight }}
|
||||||
|
>
|
||||||
|
{/* {item.content_with_weight} */}
|
||||||
|
</section>
|
||||||
<div>
|
<div>
|
||||||
<Switch checked={enabled} onChange={onChange} />
|
<Switch checked={enabled} onChange={onChange} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
import { useDeleteChunkByIds } from '@/hooks/knowledgeHook';
|
||||||
|
import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
|
||||||
|
import { DeleteOutlined } from '@ant-design/icons';
|
||||||
|
import { Checkbox, Form, Input, Modal, Space } from 'antd';
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'umi';
|
||||||
|
import EditTag from '../edit-tag';
|
||||||
|
|
||||||
|
type FieldType = {
|
||||||
|
content?: string;
|
||||||
|
};
|
||||||
|
interface kFProps {
|
||||||
|
doc_id: string;
|
||||||
|
chunkId: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ChunkCreatingModal: React.FC<kFProps> = ({ doc_id, chunkId }) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const isShowCreateModal: boolean = useSelector(
|
||||||
|
(state: any) => state.chunkModel.isShowCreateModal,
|
||||||
|
);
|
||||||
|
const [checked, setChecked] = useState(false);
|
||||||
|
const [keywords, setKeywords] = useState<string[]>([]);
|
||||||
|
const loading = useOneNamespaceEffectsLoading('chunkModel', ['create_chunk']);
|
||||||
|
const { removeChunk } = useDeleteChunkByIds();
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'chunkModel/setIsShowCreateModal',
|
||||||
|
payload: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getChunk = useCallback(async () => {
|
||||||
|
console.info(chunkId);
|
||||||
|
if (chunkId && isShowCreateModal) {
|
||||||
|
const data = await dispatch<any>({
|
||||||
|
type: 'chunkModel/get_chunk',
|
||||||
|
payload: {
|
||||||
|
chunk_id: chunkId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data?.retcode === 0) {
|
||||||
|
const { content_with_weight, important_kwd = [] } = data.data;
|
||||||
|
form.setFieldsValue({ content: content_with_weight });
|
||||||
|
setKeywords(important_kwd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chunkId) {
|
||||||
|
setKeywords([]);
|
||||||
|
form.setFieldsValue({ content: undefined });
|
||||||
|
}
|
||||||
|
}, [chunkId, isShowCreateModal, dispatch, form]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getChunk();
|
||||||
|
}, [getChunk]);
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
const values = await form.validateFields();
|
||||||
|
dispatch({
|
||||||
|
type: 'chunkModel/create_chunk',
|
||||||
|
payload: {
|
||||||
|
content_with_weight: values.content,
|
||||||
|
doc_id,
|
||||||
|
chunk_id: chunkId,
|
||||||
|
important_kwd: keywords, // keywords
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (errorInfo) {
|
||||||
|
console.log('Failed:', errorInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemove = () => {
|
||||||
|
if (chunkId) {
|
||||||
|
return removeChunk([chunkId], doc_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleCheck = () => {
|
||||||
|
setChecked(!checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title={`${chunkId ? 'Edit' : 'Create'} Chunk`}
|
||||||
|
open={isShowCreateModal}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
okButtonProps={{ loading }}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
// name="validateOnly"
|
||||||
|
autoComplete="off"
|
||||||
|
layout={'vertical'}
|
||||||
|
>
|
||||||
|
<Form.Item<FieldType>
|
||||||
|
label="Chunk"
|
||||||
|
name="content"
|
||||||
|
rules={[{ required: true, message: 'Please input value!' }]}
|
||||||
|
>
|
||||||
|
<Input.TextArea autoSize={{ minRows: 4, maxRows: 10 }} />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
<section>
|
||||||
|
<p>Keyword*</p>
|
||||||
|
<EditTag tags={keywords} setTags={setKeywords} />
|
||||||
|
</section>
|
||||||
|
{chunkId && (
|
||||||
|
<section>
|
||||||
|
<p>Function*</p>
|
||||||
|
<Space size={'large'}>
|
||||||
|
<Checkbox onChange={handleCheck} checked={checked}>
|
||||||
|
Enabled
|
||||||
|
</Checkbox>
|
||||||
|
|
||||||
|
<span onClick={handleRemove}>
|
||||||
|
<DeleteOutlined /> Delete
|
||||||
|
</span>
|
||||||
|
</Space>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default ChunkCreatingModal;
|
@ -15,6 +15,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Flex,
|
Flex,
|
||||||
|
Input,
|
||||||
Menu,
|
Menu,
|
||||||
MenuProps,
|
MenuProps,
|
||||||
Popover,
|
Popover,
|
||||||
@ -22,7 +23,7 @@ import {
|
|||||||
RadioChangeEvent,
|
RadioChangeEvent,
|
||||||
Space,
|
Space,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { ChangeEventHandler, useCallback, useMemo, useState } from 'react';
|
||||||
import { Link, useDispatch, useSelector } from 'umi';
|
import { Link, useDispatch, useSelector } from 'umi';
|
||||||
import { ChunkModelState } from '../../model';
|
import { ChunkModelState } from '../../model';
|
||||||
|
|
||||||
@ -30,24 +31,62 @@ interface IProps {
|
|||||||
checked: boolean;
|
checked: boolean;
|
||||||
getChunkList: () => void;
|
getChunkList: () => void;
|
||||||
selectAllChunk: (checked: boolean) => void;
|
selectAllChunk: (checked: boolean) => void;
|
||||||
|
createChunk: () => void;
|
||||||
|
removeChunk: () => void;
|
||||||
|
switchChunk: (available: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
const ChunkToolBar = ({
|
||||||
const { documentInfo, available }: ChunkModelState = useSelector(
|
getChunkList,
|
||||||
(state: any) => state.chunkModel,
|
selectAllChunk,
|
||||||
);
|
checked,
|
||||||
|
createChunk,
|
||||||
|
removeChunk,
|
||||||
|
switchChunk,
|
||||||
|
}: IProps) => {
|
||||||
|
const { documentInfo, available, searchString }: ChunkModelState =
|
||||||
|
useSelector((state: any) => state.chunkModel);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const knowledgeBaseId = useKnowledgeBaseId();
|
const knowledgeBaseId = useKnowledgeBaseId();
|
||||||
|
const [isShowSearchBox, setIsShowSearchBox] = useState(false);
|
||||||
|
|
||||||
const handleSelectAllCheck = useCallback(
|
const handleSelectAllCheck = useCallback(
|
||||||
(e: any) => {
|
(e: any) => {
|
||||||
// console.info(e.target.checked);
|
|
||||||
selectAllChunk(e.target.checked);
|
selectAllChunk(e.target.checked);
|
||||||
},
|
},
|
||||||
[selectAllChunk],
|
[selectAllChunk],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleSearchIconClick = () => {
|
||||||
|
setIsShowSearchBox(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchChange: ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
dispatch({ type: 'chunkModel/setSearchString', payload: val });
|
||||||
|
dispatch({
|
||||||
|
type: 'chunkModel/throttledGetChunkList',
|
||||||
|
payload: documentInfo.id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchBlur = () => {
|
||||||
|
if (!searchString.trim()) {
|
||||||
|
setIsShowSearchBox(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = useCallback(() => {
|
||||||
|
removeChunk();
|
||||||
|
}, [removeChunk]);
|
||||||
|
|
||||||
|
const handleEnabledClick = () => {
|
||||||
|
switchChunk(1);
|
||||||
|
};
|
||||||
|
const handleDisabledClick = () => {
|
||||||
|
switchChunk(0);
|
||||||
|
};
|
||||||
|
|
||||||
const items: MenuProps['items'] = useMemo(() => {
|
const items: MenuProps['items'] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -64,7 +103,7 @@ const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
|||||||
{
|
{
|
||||||
key: '2',
|
key: '2',
|
||||||
label: (
|
label: (
|
||||||
<Space>
|
<Space onClick={handleEnabledClick}>
|
||||||
<CheckCircleOutlined />
|
<CheckCircleOutlined />
|
||||||
<b>Enabled Selected</b>
|
<b>Enabled Selected</b>
|
||||||
</Space>
|
</Space>
|
||||||
@ -73,7 +112,7 @@ const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
|||||||
{
|
{
|
||||||
key: '3',
|
key: '3',
|
||||||
label: (
|
label: (
|
||||||
<Space>
|
<Space onClick={handleDisabledClick}>
|
||||||
<CloseCircleOutlined />
|
<CloseCircleOutlined />
|
||||||
<b>Disabled Selected</b>
|
<b>Disabled Selected</b>
|
||||||
</Space>
|
</Space>
|
||||||
@ -83,20 +122,21 @@ const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
|||||||
{
|
{
|
||||||
key: '4',
|
key: '4',
|
||||||
label: (
|
label: (
|
||||||
<Space>
|
<Space onClick={handleDelete}>
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
<b>Delete Selected</b>
|
<b>Delete Selected</b>
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [checked, handleSelectAllCheck]);
|
}, [checked, handleSelectAllCheck, handleDelete]);
|
||||||
|
|
||||||
const content = (
|
const content = (
|
||||||
<Menu style={{ width: 200 }} items={items} selectable={false} />
|
<Menu style={{ width: 200 }} items={items} selectable={false} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFilterChange = (e: RadioChangeEvent) => {
|
const handleFilterChange = (e: RadioChangeEvent) => {
|
||||||
|
selectAllChunk(false);
|
||||||
dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value });
|
dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value });
|
||||||
getChunkList();
|
getChunkList();
|
||||||
};
|
};
|
||||||
@ -129,12 +169,28 @@ const ChunkToolBar = ({ getChunkList, selectAllChunk, checked }: IProps) => {
|
|||||||
<DownOutlined />
|
<DownOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
<Button icon={<SearchOutlined />} />
|
{isShowSearchBox ? (
|
||||||
|
<Input
|
||||||
|
size="middle"
|
||||||
|
placeholder="Search"
|
||||||
|
prefix={<SearchOutlined />}
|
||||||
|
allowClear
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
onBlur={handleSearchBlur}
|
||||||
|
value={searchString}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button icon={<SearchOutlined />} onClick={handleSearchIconClick} />
|
||||||
|
)}
|
||||||
|
|
||||||
<Popover content={filterContent} placement="bottom" arrow={false}>
|
<Popover content={filterContent} placement="bottom" arrow={false}>
|
||||||
<Button icon={<FilterIcon />} />
|
<Button icon={<FilterIcon />} />
|
||||||
</Popover>
|
</Popover>
|
||||||
<Button icon={<DeleteOutlined />} />
|
<Button
|
||||||
<Button icon={<PlusOutlined />} type="primary" />
|
icon={<PlusOutlined />}
|
||||||
|
type="primary"
|
||||||
|
onClick={() => createChunk()}
|
||||||
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -1,116 +0,0 @@
|
|||||||
import { Form, Input, Modal } from 'antd';
|
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch } from 'umi';
|
|
||||||
import EditTag from './editTag';
|
|
||||||
|
|
||||||
type FieldType = {
|
|
||||||
content_ltks?: string;
|
|
||||||
};
|
|
||||||
interface kFProps {
|
|
||||||
getChunkList: () => void;
|
|
||||||
isShowCreateModal: boolean;
|
|
||||||
doc_id: string;
|
|
||||||
chunk_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Index: React.FC<kFProps> = ({
|
|
||||||
getChunkList,
|
|
||||||
doc_id,
|
|
||||||
isShowCreateModal,
|
|
||||||
chunk_id,
|
|
||||||
}) => {
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
|
|
||||||
// const { , chunkInfo } = chunkModel
|
|
||||||
const [important_kwd, setImportantKwd] = useState([
|
|
||||||
'Unremovable',
|
|
||||||
'Tag 2',
|
|
||||||
'Tag 3',
|
|
||||||
]);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const handleCancel = () => {
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/updateState',
|
|
||||||
payload: {
|
|
||||||
isShowCreateModal: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getChunk = useCallback(async () => {
|
|
||||||
if (chunk_id && isShowCreateModal) {
|
|
||||||
const data = await dispatch<any>({
|
|
||||||
type: 'chunkModel/get_chunk',
|
|
||||||
payload: {
|
|
||||||
chunk_id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (data?.retcode === 0) {
|
|
||||||
const { content_ltks, important_kwd = [] } = data.data;
|
|
||||||
form.setFieldsValue({ content_ltks });
|
|
||||||
setImportantKwd(important_kwd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [chunk_id, isShowCreateModal]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getChunk();
|
|
||||||
}, [getChunk]);
|
|
||||||
|
|
||||||
const handleOk = async () => {
|
|
||||||
try {
|
|
||||||
const values = await form.validateFields();
|
|
||||||
dispatch({
|
|
||||||
type: 'chunkModel/create_hunk',
|
|
||||||
payload: {
|
|
||||||
content_ltks: values.content_ltks,
|
|
||||||
doc_id,
|
|
||||||
chunk_id,
|
|
||||||
important_kwd,
|
|
||||||
},
|
|
||||||
// callback: () => {
|
|
||||||
// dispatch({
|
|
||||||
// type: 'chunkModel/updateState',
|
|
||||||
// payload: {
|
|
||||||
// isShowCreateModal: false,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
// getChunkList && getChunkList();
|
|
||||||
// },
|
|
||||||
});
|
|
||||||
} catch (errorInfo) {
|
|
||||||
console.log('Failed:', errorInfo);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
title="Basic Modal"
|
|
||||||
open={isShowCreateModal}
|
|
||||||
onOk={handleOk}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
name="validateOnly"
|
|
||||||
labelCol={{ span: 5 }}
|
|
||||||
wrapperCol={{ span: 19 }}
|
|
||||||
style={{ maxWidth: 600 }}
|
|
||||||
autoComplete="off"
|
|
||||||
>
|
|
||||||
<Form.Item<FieldType>
|
|
||||||
label="chunk 内容"
|
|
||||||
name="content_ltks"
|
|
||||||
rules={[{ required: true, message: 'Please input value!' }]}
|
|
||||||
>
|
|
||||||
<Input.TextArea />
|
|
||||||
</Form.Item>
|
|
||||||
<EditTag tags={important_kwd} setTags={setImportantKwd} />
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default Index;
|
|
@ -0,0 +1,3 @@
|
|||||||
|
.tweenGroup {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
|
import type { InputRef } from 'antd';
|
||||||
|
import { Input, Tag, theme } from 'antd';
|
||||||
|
import { TweenOneGroup } from 'rc-tween-one';
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import styles from './index.less';
|
||||||
|
|
||||||
|
interface EditTagsProps {
|
||||||
|
tags: string[];
|
||||||
|
setTags: (tags: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditTag = ({ tags, setTags }: EditTagsProps) => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
const [inputVisible, setInputVisible] = useState(false);
|
||||||
|
const [inputValue, setInputValue] = useState('');
|
||||||
|
const inputRef = useRef<InputRef>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (inputVisible) {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}
|
||||||
|
}, [inputVisible]);
|
||||||
|
|
||||||
|
const handleClose = (removedTag: string) => {
|
||||||
|
const newTags = tags.filter((tag) => tag !== removedTag);
|
||||||
|
console.log(newTags);
|
||||||
|
setTags(newTags);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showInput = () => {
|
||||||
|
setInputVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setInputValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputConfirm = () => {
|
||||||
|
if (inputValue && tags.indexOf(inputValue) === -1) {
|
||||||
|
setTags([...tags, inputValue]);
|
||||||
|
}
|
||||||
|
setInputVisible(false);
|
||||||
|
setInputValue('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const forMap = (tag: string) => {
|
||||||
|
const tagElem = (
|
||||||
|
<Tag
|
||||||
|
closable
|
||||||
|
onClose={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
handleClose(tag);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tag}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<span key={tag} style={{ display: 'inline-block' }}>
|
||||||
|
{tagElem}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagChild = tags.map(forMap);
|
||||||
|
|
||||||
|
const tagPlusStyle: React.CSSProperties = {
|
||||||
|
background: token.colorBgContainer,
|
||||||
|
borderStyle: 'dashed',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span>
|
||||||
|
<TweenOneGroup
|
||||||
|
className={styles.tweenGroup}
|
||||||
|
enter={{
|
||||||
|
scale: 0.8,
|
||||||
|
opacity: 0,
|
||||||
|
type: 'from',
|
||||||
|
duration: 100,
|
||||||
|
}}
|
||||||
|
onEnd={(e) => {
|
||||||
|
if (e.type === 'appear' || e.type === 'enter') {
|
||||||
|
(e.target as any).style = 'display: inline-block';
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
leave={{ opacity: 0, width: 0, scale: 0, duration: 200 }}
|
||||||
|
appear={false}
|
||||||
|
>
|
||||||
|
{tagChild}
|
||||||
|
</TweenOneGroup>
|
||||||
|
</span>
|
||||||
|
{inputVisible ? (
|
||||||
|
<Input
|
||||||
|
ref={inputRef}
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
style={{ width: 78 }}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onBlur={handleInputConfirm}
|
||||||
|
onPressEnter={handleInputConfirm}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Tag onClick={showInput} style={tagPlusStyle}>
|
||||||
|
<PlusOutlined />
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditTag;
|
@ -23,6 +23,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chunkContainer {
|
||||||
|
height: calc(100vh - 320px);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.pageFooter {
|
.pageFooter {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
|
import { getOneNamespaceEffectsLoading } from '@/utils/storeUtil';
|
||||||
import type { PaginationProps } from 'antd';
|
import type { PaginationProps } from 'antd';
|
||||||
import { Button, Input, Pagination, Space, Spin } from 'antd';
|
import { Divider, Pagination, Space, Spin, message } from 'antd';
|
||||||
import { debounce } from 'lodash';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
|
||||||
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
import { useDispatch, useSearchParams, useSelector } from 'umi';
|
||||||
import CreateModal from './components/createModal';
|
import CreatingModal from './components/chunk-creating-modal';
|
||||||
|
|
||||||
|
import { useDeleteChunkByIds } from '@/hooks/knowledgeHook';
|
||||||
import ChunkCard from './components/chunk-card';
|
import ChunkCard from './components/chunk-card';
|
||||||
import ChunkToolBar from './components/chunk-toolbar';
|
import ChunkToolBar from './components/chunk-toolbar';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
@ -21,16 +21,9 @@ const Chunk = () => {
|
|||||||
const chunkModel: ChunkModelState = useSelector(
|
const chunkModel: ChunkModelState = useSelector(
|
||||||
(state: any) => state.chunkModel,
|
(state: any) => state.chunkModel,
|
||||||
);
|
);
|
||||||
const [keywords, SetKeywords] = useState('');
|
|
||||||
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
const [selectedChunkIds, setSelectedChunkIds] = useState<string[]>([]);
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const {
|
const { data = [], total, pagination } = chunkModel;
|
||||||
data = [],
|
|
||||||
total,
|
|
||||||
chunk_id,
|
|
||||||
isShowCreateModal,
|
|
||||||
pagination,
|
|
||||||
} = chunkModel;
|
|
||||||
const effects = useSelector((state: any) => state.loading.effects);
|
const effects = useSelector((state: any) => state.loading.effects);
|
||||||
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
|
const loading = getOneNamespaceEffectsLoading('chunkModel', effects, [
|
||||||
'create_hunk',
|
'create_hunk',
|
||||||
@ -38,8 +31,10 @@ const Chunk = () => {
|
|||||||
'switch_chunk',
|
'switch_chunk',
|
||||||
]);
|
]);
|
||||||
const documentId: string = searchParams.get('doc_id') || '';
|
const documentId: string = searchParams.get('doc_id') || '';
|
||||||
|
const [chunkId, setChunkId] = useState<string | undefined>();
|
||||||
|
const { removeChunk } = useDeleteChunkByIds();
|
||||||
|
|
||||||
const getChunkList = () => {
|
const getChunkList = useCallback(() => {
|
||||||
const payload: PayloadType = {
|
const payload: PayloadType = {
|
||||||
doc_id: documentId,
|
doc_id: documentId,
|
||||||
};
|
};
|
||||||
@ -50,30 +45,19 @@ const Chunk = () => {
|
|||||||
...payload,
|
...payload,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
}, [dispatch, documentId]);
|
||||||
|
|
||||||
const confirm = async (id: string) => {
|
const handleEditChunk = useCallback(
|
||||||
const retcode = await dispatch<any>({
|
(chunk_id?: string) => {
|
||||||
type: 'chunkModel/rm_chunk',
|
setChunkId(chunk_id);
|
||||||
payload: {
|
|
||||||
chunk_ids: [id],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
retcode === 0 && getChunkList();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEditchunk = (chunk_id?: string) => {
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'chunkModel/updateState',
|
type: 'chunkModel/setIsShowCreateModal',
|
||||||
payload: {
|
payload: true,
|
||||||
isShowCreateModal: true,
|
|
||||||
chunk_id,
|
|
||||||
doc_id: documentId,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
getChunkList();
|
},
|
||||||
};
|
[dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
const onPaginationChange: PaginationProps['onShowSizeChange'] = (
|
const onPaginationChange: PaginationProps['onShowSizeChange'] = (
|
||||||
page,
|
page,
|
||||||
@ -93,9 +77,6 @@ const Chunk = () => {
|
|||||||
const selectAllChunk = useCallback(
|
const selectAllChunk = useCallback(
|
||||||
(checked: boolean) => {
|
(checked: boolean) => {
|
||||||
setSelectedChunkIds(checked ? data.map((x) => x.chunk_id) : []);
|
setSelectedChunkIds(checked ? data.map((x) => x.chunk_id) : []);
|
||||||
// setSelectedChunkIds((previousIds) => {
|
|
||||||
// return checked ? [...previousIds, ...data.map((x) => x.chunk_id)] : [];
|
|
||||||
// });
|
|
||||||
},
|
},
|
||||||
[data],
|
[data],
|
||||||
);
|
);
|
||||||
@ -115,6 +96,46 @@ const Chunk = () => {
|
|||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
const showSelectedChunkWarning = () => {
|
||||||
|
message.warning('Please select chunk!');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveChunk = useCallback(async () => {
|
||||||
|
if (selectedChunkIds.length > 0) {
|
||||||
|
const resCode: number = await removeChunk(selectedChunkIds, documentId);
|
||||||
|
if (resCode === 0) {
|
||||||
|
setSelectedChunkIds([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showSelectedChunkWarning();
|
||||||
|
}
|
||||||
|
}, [selectedChunkIds, documentId, removeChunk]);
|
||||||
|
|
||||||
|
const switchChunk = useCallback(
|
||||||
|
async (available?: number, chunkIds?: string[]) => {
|
||||||
|
let ids = chunkIds;
|
||||||
|
if (!chunkIds) {
|
||||||
|
ids = selectedChunkIds;
|
||||||
|
if (selectedChunkIds.length === 0) {
|
||||||
|
showSelectedChunkWarning();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resCode: number = await dispatch<any>({
|
||||||
|
type: 'chunkModel/switch_chunk',
|
||||||
|
payload: {
|
||||||
|
chunk_ids: ids,
|
||||||
|
available_int: available,
|
||||||
|
doc_id: documentId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!chunkIds && resCode === 0) {
|
||||||
|
getChunkList();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dispatch, documentId, getChunkList, selectedChunkIds],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getChunkList();
|
getChunkList();
|
||||||
@ -123,22 +144,7 @@ const Chunk = () => {
|
|||||||
type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly
|
type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}, [documentId]);
|
}, [dispatch, getChunkList]);
|
||||||
|
|
||||||
const debounceChange = debounce(getChunkList, 300);
|
|
||||||
const debounceCallback = useCallback(
|
|
||||||
(value: string) => debounceChange(value),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleInputChange = (
|
|
||||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
|
|
||||||
) => {
|
|
||||||
setSelectedChunkIds([]);
|
|
||||||
const value = e.target.value;
|
|
||||||
SetKeywords(value);
|
|
||||||
debounceCallback(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -146,36 +152,27 @@ const Chunk = () => {
|
|||||||
<ChunkToolBar
|
<ChunkToolBar
|
||||||
getChunkList={getChunkList}
|
getChunkList={getChunkList}
|
||||||
selectAllChunk={selectAllChunk}
|
selectAllChunk={selectAllChunk}
|
||||||
|
createChunk={handleEditChunk}
|
||||||
|
removeChunk={handleRemoveChunk}
|
||||||
checked={selectedChunkIds.length === data.length}
|
checked={selectedChunkIds.length === data.length}
|
||||||
|
switchChunk={switchChunk}
|
||||||
></ChunkToolBar>
|
></ChunkToolBar>
|
||||||
<div className={styles.filter}>
|
<Divider></Divider>
|
||||||
<div>
|
|
||||||
<Input
|
|
||||||
placeholder="搜索"
|
|
||||||
style={{ width: 220 }}
|
|
||||||
value={keywords}
|
|
||||||
allowClear
|
|
||||||
onChange={handleInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
handleEditchunk();
|
|
||||||
}}
|
|
||||||
type="link"
|
|
||||||
>
|
|
||||||
添加分段
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className={styles.pageContent}>
|
<div className={styles.pageContent}>
|
||||||
<Spin spinning={loading} className={styles.spin} size="large">
|
<Spin spinning={loading} className={styles.spin} size="large">
|
||||||
<Space direction="vertical" size={'middle'}>
|
<Space
|
||||||
|
direction="vertical"
|
||||||
|
size={'middle'}
|
||||||
|
className={styles.chunkContainer}
|
||||||
|
>
|
||||||
{data.map((item) => (
|
{data.map((item) => (
|
||||||
<ChunkCard
|
<ChunkCard
|
||||||
item={item}
|
item={item}
|
||||||
key={item.chunk_id}
|
key={item.chunk_id}
|
||||||
|
editChunk={handleEditChunk}
|
||||||
checked={selectedChunkIds.some((x) => x === item.chunk_id)}
|
checked={selectedChunkIds.some((x) => x === item.chunk_id)}
|
||||||
handleCheckboxClick={handleSingleCheckboxClick}
|
handleCheckboxClick={handleSingleCheckboxClick}
|
||||||
|
switchChunk={switchChunk}
|
||||||
></ChunkCard>
|
></ChunkCard>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
@ -188,19 +185,14 @@ const Chunk = () => {
|
|||||||
showQuickJumper
|
showQuickJumper
|
||||||
showSizeChanger
|
showSizeChanger
|
||||||
onChange={onPaginationChange}
|
onChange={onPaginationChange}
|
||||||
defaultPageSize={10}
|
pageSize={pagination.pageSize}
|
||||||
pageSizeOptions={[10, 30, 60, 90]}
|
pageSizeOptions={[10, 30, 60, 90]}
|
||||||
defaultCurrent={pagination.current}
|
current={pagination.current}
|
||||||
total={total}
|
total={total}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CreateModal
|
<CreatingModal doc_id={documentId} chunkId={chunkId} />
|
||||||
doc_id={documentId}
|
|
||||||
isShowCreateModal={isShowCreateModal}
|
|
||||||
chunk_id={chunk_id}
|
|
||||||
getChunkList={getChunkList}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@ import { BaseState } from '@/interfaces/common';
|
|||||||
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
import { IKnowledgeFile } from '@/interfaces/database/knowledge';
|
||||||
import kbService from '@/services/kbService';
|
import kbService from '@/services/kbService';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
import { pick } from 'lodash';
|
||||||
// import { delay } from '@/utils/storeUtil';
|
// import { delay } from '@/utils/storeUtil';
|
||||||
import { DvaModel } from 'umi';
|
import { DvaModel } from 'umi';
|
||||||
|
|
||||||
@ -40,6 +41,13 @@ const model: DvaModel<ChunkModelState> = {
|
|||||||
...payload,
|
...payload,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
setIsShowCreateModal(state, { payload }) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
isShowCreateModal:
|
||||||
|
typeof payload === 'boolean' ? payload : !state.isShowCreateModal,
|
||||||
|
};
|
||||||
|
},
|
||||||
setAvailable(state, { payload }) {
|
setAvailable(state, { payload }) {
|
||||||
return { ...state, available: payload };
|
return { ...state, available: payload };
|
||||||
},
|
},
|
||||||
@ -49,7 +57,7 @@ const model: DvaModel<ChunkModelState> = {
|
|||||||
setPagination(state, { payload }) {
|
setPagination(state, { payload }) {
|
||||||
return { ...state, pagination: { ...state.pagination, ...payload } };
|
return { ...state, pagination: { ...state.pagination, ...payload } };
|
||||||
},
|
},
|
||||||
resetFilter(state, { payload }) {
|
resetFilter(state, {}) {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
pagination: {
|
pagination: {
|
||||||
@ -84,7 +92,13 @@ const model: DvaModel<ChunkModelState> = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
*switch_chunk({ payload = {} }, { call, put }) {
|
throttledGetChunkList: [
|
||||||
|
function* ({ payload }, { put }) {
|
||||||
|
yield put({ type: 'chunk_list', payload: { doc_id: payload } });
|
||||||
|
},
|
||||||
|
{ type: 'throttle', ms: 1000 }, // TODO: Provide type support for this effect
|
||||||
|
],
|
||||||
|
*switch_chunk({ payload = {} }, { call }) {
|
||||||
const { data } = yield call(kbService.switch_chunk, payload);
|
const { data } = yield call(kbService.switch_chunk, payload);
|
||||||
const { retcode } = data;
|
const { retcode } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
@ -93,15 +107,21 @@ const model: DvaModel<ChunkModelState> = {
|
|||||||
return retcode;
|
return retcode;
|
||||||
},
|
},
|
||||||
*rm_chunk({ payload = {} }, { call, put }) {
|
*rm_chunk({ payload = {} }, { call, put }) {
|
||||||
console.log('shanchu');
|
const { data } = yield call(kbService.rm_chunk, payload);
|
||||||
const { data, response } = yield call(kbService.rm_chunk, payload);
|
const { retcode } = data;
|
||||||
const { retcode, data: res, retmsg } = data;
|
if (retcode === 0) {
|
||||||
|
yield put({
|
||||||
|
type: 'setIsShowCreateModal',
|
||||||
|
payload: false,
|
||||||
|
});
|
||||||
|
yield put({ type: 'setPagination', payload: { current: 1 } });
|
||||||
|
yield put({ type: 'chunk_list', payload: pick(payload, ['doc_id']) });
|
||||||
|
}
|
||||||
return retcode;
|
return retcode;
|
||||||
},
|
},
|
||||||
*get_chunk({ payload = {} }, { call, put }) {
|
*get_chunk({ payload = {} }, { call, put }) {
|
||||||
const { data, response } = yield call(kbService.get_chunk, payload);
|
const { data } = yield call(kbService.get_chunk, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode, data: res } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
@ -112,20 +132,20 @@ const model: DvaModel<ChunkModelState> = {
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
*create_hunk({ payload = {} }, { call, put }) {
|
*create_chunk({ payload = {} }, { call, put }) {
|
||||||
let service = kbService.create_chunk;
|
let service = kbService.create_chunk;
|
||||||
if (payload.chunk_id) {
|
if (payload.chunk_id) {
|
||||||
service = kbService.set_chunk;
|
service = kbService.set_chunk;
|
||||||
}
|
}
|
||||||
const { data, response } = yield call(service, payload);
|
const { data } = yield call(service, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode } = data;
|
||||||
if (retcode === 0) {
|
if (retcode === 0) {
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'setIsShowCreateModal',
|
||||||
payload: {
|
payload: false,
|
||||||
isShowCreateModal: false,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
yield put({ type: 'chunk_list', payload: pick(payload, ['doc_id']) });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
import { useDispatch, useSelector } from 'umi';
|
import { useDispatch, useSelector } from 'umi';
|
||||||
import CreateModal from '../knowledge-chunk/components/createModal';
|
import CreateModal from '../knowledge-chunk/components/chunk-creating-modal';
|
||||||
|
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
@ -265,7 +265,6 @@ const KnowledgeSearching = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CreateModal
|
<CreateModal
|
||||||
getChunkList={getChunkList}
|
|
||||||
isShowCreateModal={isShowCreateModal}
|
isShowCreateModal={isShowCreateModal}
|
||||||
chunk_id={chunk_id}
|
chunk_id={chunk_id}
|
||||||
doc_id={doc_id}
|
doc_id={doc_id}
|
||||||
|
@ -138,8 +138,8 @@ const model: DvaModel<KSearchModelState> = {
|
|||||||
if (payload.chunk_id) {
|
if (payload.chunk_id) {
|
||||||
service = kbService.set_chunk;
|
service = kbService.set_chunk;
|
||||||
}
|
}
|
||||||
const { data, response } = yield call(service, payload);
|
const { data } = yield call(service, payload);
|
||||||
const { retcode, data: res, retmsg } = data;
|
const { retcode } = data;
|
||||||
yield put({
|
yield put({
|
||||||
type: 'updateState',
|
type: 'updateState',
|
||||||
payload: {
|
payload: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user