feat:替换 Dify 为自建 RAG去实现
1、修复了若干无权限时的失败提示语 2、新增了一个生成后续建议问题的功能 3、重构了知识问答部分的权限管理模块 4、修复了若干渲染不恰当的样式渲染
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import {
|
||||
Card,
|
||||
Table,
|
||||
@@ -24,7 +24,6 @@ import {
|
||||
Flex,
|
||||
Typography,
|
||||
Popconfirm,
|
||||
Spin,
|
||||
Tooltip,
|
||||
} from 'antd';
|
||||
import {
|
||||
@@ -35,8 +34,7 @@ import {
|
||||
CheckCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useAreaDatasetConfig } from '~/hooks/use-area-dataset-config';
|
||||
import { fetchDatasets } from '~/api/dify-dataset/api/datasetApi';
|
||||
import type { Dataset as DifyDataset } from '~/api/dify-dataset/type';
|
||||
import { usePermission } from '~/hooks/usePermission';
|
||||
import type { AreaDataset } from '~/api/v3/dify/area-datasets';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
@@ -90,13 +88,11 @@ export default function AreaDatasetConfig() {
|
||||
canManageDataset,
|
||||
} = useAreaDatasetConfig();
|
||||
|
||||
const { userRole: rawUserRole, userArea: rawUserArea } = usePermission();
|
||||
const isProvincialAdmin = rawUserRole === 'provincial_admin';
|
||||
|
||||
// 内部状态
|
||||
const [form] = Form.useForm();
|
||||
const [difyDatasets, setDifyDatasets] = useState<DifyDataset[]>([]);
|
||||
const [difyDatasetsLoading, setDifyDatasetsLoading] = useState<boolean>(false);
|
||||
const [difyDatasetsTotal, setDifyDatasetsTotal] = useState<number>(0);
|
||||
const [difyDatasetsPage, setDifyDatasetsPage] = useState<number>(1);
|
||||
const [isLoadingDifyDatasets, setIsLoadingDifyDatasets] = useState<boolean>(false);
|
||||
|
||||
// ==================== Effects ====================
|
||||
|
||||
@@ -107,7 +103,6 @@ export default function AreaDatasetConfig() {
|
||||
if (record) {
|
||||
form.setFieldsValue({
|
||||
area: record.area,
|
||||
dataset_id: record.dataset_id,
|
||||
dataset_name: record.dataset_name,
|
||||
dataset_description: record.dataset_description,
|
||||
is_public: record.is_public,
|
||||
@@ -116,51 +111,14 @@ export default function AreaDatasetConfig() {
|
||||
});
|
||||
}
|
||||
} else if (!editingId && modalVisible) {
|
||||
// 新增时重置表单
|
||||
form.resetFields();
|
||||
loadDifyDatasets(); // 加载Dify知识库列表
|
||||
// 非省级管理员自动填充地区
|
||||
if (!isProvincialAdmin && rawUserArea) {
|
||||
form.setFieldValue('area', rawUserArea);
|
||||
}
|
||||
}
|
||||
}, [editingId, modalVisible, datasets, form]);
|
||||
|
||||
// ==================== Dify Datasets Loading ====================
|
||||
|
||||
/**
|
||||
* 从Dify API加载知识库列表
|
||||
*/
|
||||
const loadDifyDatasets = async (pageNum: number = 1) => {
|
||||
if (isLoadingDifyDatasets) return;
|
||||
|
||||
setIsLoadingDifyDatasets(true);
|
||||
try {
|
||||
const response = await fetchDatasets(pageNum, 20);
|
||||
setDifyDatasets(response.data);
|
||||
setDifyDatasetsTotal(response.total);
|
||||
setDifyDatasetsPage(pageNum);
|
||||
setDifyDatasetsLoading(false);
|
||||
} catch (error: any) {
|
||||
console.error('加载Dify知识库列表失败:', error);
|
||||
message.error('加载Dify知识库列表失败');
|
||||
setDifyDatasetsLoading(false);
|
||||
} finally {
|
||||
setIsLoadingDifyDatasets(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dify数据集选择器滚动加载
|
||||
*/
|
||||
const handleDatasetSelectScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
||||
const { target } = e;
|
||||
const { scrollTop, scrollHeight, clientHeight } = target as HTMLDivElement;
|
||||
|
||||
// 滚动到底部且还有更多数据时加载下一页
|
||||
if (scrollHeight - scrollTop === clientHeight &&
|
||||
difyDatasets.length < difyDatasetsTotal &&
|
||||
!difyDatasetsLoading) {
|
||||
loadDifyDatasets(difyDatasetsPage + 1);
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== Event Handlers ====================
|
||||
|
||||
/**
|
||||
@@ -168,13 +126,12 @@ export default function AreaDatasetConfig() {
|
||||
*/
|
||||
const handleCreateClick = () => {
|
||||
if (!canManageDataset) {
|
||||
message.error('您没有创建知识库绑定的权限');
|
||||
message.error('您没有创建知识库的权限');
|
||||
return;
|
||||
}
|
||||
setEditingId(null);
|
||||
setModalVisible(true);
|
||||
form.resetFields();
|
||||
loadDifyDatasets();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -208,6 +165,24 @@ export default function AreaDatasetConfig() {
|
||||
* 处理表单提交
|
||||
*/
|
||||
const handleFormSubmit = async (values: any) => {
|
||||
// 编辑时检查 is_default 是否从 false 变为 true
|
||||
if (editingId && values.is_default) {
|
||||
const record = datasets.find((item) => item.id === editingId);
|
||||
if (record && !record.is_default) {
|
||||
Modal.confirm({
|
||||
title: '切换默认知识库',
|
||||
content: '确认将此知识库设为默认?该地区的对话助手将自动绑定此知识库进行问答。',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => doSubmit(values),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
await doSubmit(values);
|
||||
};
|
||||
|
||||
const doSubmit = async (values: any) => {
|
||||
let success = false;
|
||||
|
||||
if (editingId) {
|
||||
@@ -269,6 +244,7 @@ export default function AreaDatasetConfig() {
|
||||
key: 'dataset_name',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
align: 'center',
|
||||
render: (text: string) => (
|
||||
<Tooltip title={text}>
|
||||
<Text style={{ color: colors.text }} strong>
|
||||
@@ -277,25 +253,26 @@ export default function AreaDatasetConfig() {
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '知识库ID',
|
||||
dataIndex: 'dataset_id',
|
||||
key: 'dataset_id',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
render: (text: string) => (
|
||||
<Tooltip title={text}>
|
||||
<Text type="secondary" style={{ fontSize: '12px' }}>
|
||||
{text.substring(0, 8)}...{text.substring(text.length - 4)}
|
||||
</Text>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// title: '知识库ID',
|
||||
// dataIndex: 'dataset_id',
|
||||
// key: 'dataset_id',
|
||||
// width: 200,
|
||||
// ellipsis: true,
|
||||
// render: (text: string) => (
|
||||
// <Tooltip title={text}>
|
||||
// <Text type="secondary" style={{ fontSize: '12px' }}>
|
||||
// {text.substring(0, 8)}...{text.substring(text.length - 4)}
|
||||
// </Text>
|
||||
// </Tooltip>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'dataset_description',
|
||||
key: 'dataset_description',
|
||||
ellipsis: true,
|
||||
align: 'center',
|
||||
render: (text: string) =>
|
||||
text ? (
|
||||
<Tooltip title={text}>
|
||||
@@ -319,7 +296,7 @@ export default function AreaDatasetConfig() {
|
||||
</Tag>
|
||||
)}
|
||||
{record.is_default && (
|
||||
<Tag color={colors.primary} style={{ color: '#fff' }}>
|
||||
<Tag color={colors.primary} style={{ color: '#00684a' }}>
|
||||
默认
|
||||
</Tag>
|
||||
)}
|
||||
@@ -330,7 +307,7 @@ export default function AreaDatasetConfig() {
|
||||
title: '排序',
|
||||
dataIndex: 'sort_order',
|
||||
key: 'sort_order',
|
||||
width: 70,
|
||||
width: 170,
|
||||
align: 'center' as const,
|
||||
sorter: (a: AreaDataset, b: AreaDataset) => a.sort_order - b.sort_order,
|
||||
},
|
||||
@@ -364,29 +341,37 @@ export default function AreaDatasetConfig() {
|
||||
key: 'actions',
|
||||
width: 120,
|
||||
fixed: 'right' as const,
|
||||
render: (_: any, record: AreaDataset) => (
|
||||
<Space size="small">
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleEditClick(record)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
description="删除后该地区的用户将无法访问此知识库"
|
||||
onConfirm={() => handleDeleteClick(record.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="link" danger size="small" icon={<DeleteOutlined />}>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Space>
|
||||
),
|
||||
render: (_: any, record: AreaDataset) => {
|
||||
// 市级管理员只能编辑自己地区的知识库
|
||||
const canEdit = isProvincialAdmin || record.area === rawUserArea;
|
||||
return (
|
||||
<Space size="small">
|
||||
{canEdit && (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => handleEditClick(record)}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{isProvincialAdmin && (
|
||||
<Popconfirm
|
||||
title="确定删除?"
|
||||
description="删除后该地区的用户将无法访问此知识库"
|
||||
onConfirm={() => handleDeleteClick(record.id)}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Button type="link" danger size="small" icon={<DeleteOutlined />}>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
@@ -432,7 +417,7 @@ export default function AreaDatasetConfig() {
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleCreateClick}
|
||||
>
|
||||
新增绑定
|
||||
新增知识库
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
@@ -503,7 +488,7 @@ export default function AreaDatasetConfig() {
|
||||
|
||||
{/* 新增/编辑对话框 */}
|
||||
<Modal
|
||||
title={editingId ? '编辑知识库绑定' : '新增知识库绑定'}
|
||||
title={editingId ? '编辑知识库' : '新增知识库'}
|
||||
open={modalVisible}
|
||||
onOk={() => form.submit()}
|
||||
onCancel={handleFormCancel}
|
||||
@@ -529,55 +514,12 @@ export default function AreaDatasetConfig() {
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择地区"
|
||||
disabled={!!editingId} // 编辑时禁用
|
||||
options={Array.isArray(areas) ? areas.map((area) => ({
|
||||
label: area,
|
||||
value: area,
|
||||
})) : []}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* Dify知识库选择(仅新增时可选) */}
|
||||
<Form.Item
|
||||
name="dataset_id"
|
||||
label="Dify知识库"
|
||||
rules={[{ required: true, message: '请选择Dify知识库' }]}
|
||||
>
|
||||
<Select
|
||||
placeholder="请选择或输入知识库ID"
|
||||
disabled={!!editingId}
|
||||
loading={difyDatasetsLoading}
|
||||
onPopupScroll={handleDatasetSelectScroll}
|
||||
dropdownRender={(menu) => (
|
||||
<div>
|
||||
{menu}
|
||||
{difyDatasets.length < difyDatasetsTotal && (
|
||||
<div style={{ textAlign: 'center', padding: '8px' }}>
|
||||
<Spin size="small" />
|
||||
<Text style={{ marginLeft: '8px' }} type="secondary">
|
||||
加载中...
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
onDropdownVisibleChange={(open) => {
|
||||
if (open && !editingId) {
|
||||
loadDifyDatasets();
|
||||
}
|
||||
}}
|
||||
options={difyDatasets.map((ds) => ({
|
||||
label: (
|
||||
<Flex vertical>
|
||||
<Text strong>{ds.name}</Text>
|
||||
<Text type="secondary" style={{ fontSize: '12px' }}>
|
||||
ID: {ds.id}
|
||||
</Text>
|
||||
</Flex>
|
||||
),
|
||||
value: ds.id,
|
||||
}))}
|
||||
styles={{ popup: { root: { maxHeight: '300px' } } }}
|
||||
options={
|
||||
isProvincialAdmin
|
||||
? (Array.isArray(areas) ? areas.map((area) => ({ label: area, value: area })) : [])
|
||||
: (rawUserArea ? [{ label: rawUserArea, value: rawUserArea }] : [])
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -594,7 +536,7 @@ export default function AreaDatasetConfig() {
|
||||
</Form.Item>
|
||||
|
||||
{/* 知识库描述 */}
|
||||
{/* <Form.Item
|
||||
<Form.Item
|
||||
name="dataset_description"
|
||||
label="知识库描述"
|
||||
>
|
||||
@@ -603,36 +545,33 @@ export default function AreaDatasetConfig() {
|
||||
rows={3}
|
||||
maxLength={500}
|
||||
/>
|
||||
</Form.Item> */}
|
||||
</Form.Item>
|
||||
|
||||
{/* 高级设置折叠面板 */}
|
||||
{/* 高级设置 */}
|
||||
<div style={{ marginTop: '24px' }}>
|
||||
<Text strong style={{ color: colors.text, display: 'block', marginBottom: '16px' }}>
|
||||
高级设置
|
||||
</Text>
|
||||
|
||||
<Flex gap="24px">
|
||||
{/* 是否公开 */}
|
||||
<Form.Item
|
||||
name="is_public"
|
||||
label="公开知识库"
|
||||
valuePropName="checked"
|
||||
tooltip="公开后所有地区的用户都可以访问此知识库"
|
||||
tooltip="公开后,其他地区的用户可以在对话中选择此知识库的问答助手"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
{/* 是否默认 */}
|
||||
<Form.Item
|
||||
name="is_default"
|
||||
label="默认知识库"
|
||||
valuePropName="checked"
|
||||
tooltip="设置为该地区的默认知识库,用户优先使用"
|
||||
tooltip="设为默认后,该地区的对话助手将自动切换为使用此知识库"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
|
||||
{/* 排序顺序 */}
|
||||
<Form.Item
|
||||
name="sort_order"
|
||||
label="排序顺序"
|
||||
|
||||
Reference in New Issue
Block a user