feat: 添加对话应用选择和知识库切换功能

- 新增对话应用管理模块(dify-chat-apps),支持获取和切换对话应用
- 优化对话应用切换后自动刷新会话列表功能
- 知识库管理页面新增下拉选择器,支持切换不同知识库
- API 层支持 app_id 参数传递,实现多应用会话隔离

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-08 01:44:34 +08:00
parent 27aff59152
commit 3f5c23123b
27 changed files with 925 additions and 167 deletions
@@ -65,9 +65,9 @@ export default function AreaDatasetConfig() {
areas,
// areasLoading, // 地区列表已加载hook中
// 筛选
filterArea,
setFilterArea,
// 筛选 - 多选
filterAreas,
setFilterAreas,
page,
setPage,
pageSize,
@@ -233,24 +233,17 @@ export default function AreaDatasetConfig() {
};
/**
* 处理地区筛选变化
* 处理地区筛选变化 - 支持多选
*/
const handleAreaFilterChange = (value: string) => {
setFilterArea(value);
const handleAreaFilterChange = (values: string[]) => {
setFilterAreas(values);
setPage(1); // 重置到第一页
};
// ==================== Render ====================
// 计算用户角色标签
const userRoleLabel = (() => {
const labels: Record<string, string> = {
common: '普通用户',
admin: '市级管理员',
provincial_admin: '省级管理员',
};
return labels[userRole] || '未知角色';
})();
// 用户角色已经在 hook 中处理好了,直接使用 userRole
const userRoleLabel = userRole || '未知角色';
// 表格列定义
const columns = [
@@ -456,16 +449,15 @@ export default function AreaDatasetConfig() {
<Flex gap="16px" align="center">
<Text style={{ color: colors.text }}>:</Text>
<Select
style={{ width: '150px' }}
placeholder="全部地区"
mode="multiple"
style={{ minWidth: '200px', maxWidth: '400px' }}
placeholder="请选择地区(可多选)"
allowClear
value={filterArea || undefined}
value={filterAreas}
onChange={handleAreaFilterChange}
options={[
{ label: '全部', value: '' },
{ label: '省级', value: '省级' },
...areas.map((area) => ({ label: area, value: area })),
]}
maxTagCount={3}
maxTagPlaceholder={(omittedValues) => `+${omittedValues.length}`}
options={Array.isArray(areas) ? areas.map((area) => ({ label: area, value: area })) : []}
/>
</Flex>
</Card>
@@ -538,10 +530,10 @@ export default function AreaDatasetConfig() {
<Select
placeholder="请选择地区"
disabled={!!editingId} // 编辑时禁用
options={areas.map((area) => ({
options={Array.isArray(areas) ? areas.map((area) => ({
label: area,
value: area,
}))}
})) : []}
/>
</Form.Item>
+15 -1
View File
@@ -4,6 +4,7 @@ import DocumentList from './document-list';
import DocumentDetail from './document-detail';
import RetrieveTest from './retrieve-test';
import DatasetSettings from './dataset-settings';
import AreaDatasetConfig from './area-dataset-config';
import { useDatasetManager } from '~/hooks/dify-dataset-manager';
import '../../styles/components/dify-dataset-manager/index.css';
@@ -25,7 +26,11 @@ export default function DatasetManager() {
error,
activeTab,
selectedDocument,
// 知识库列表(基于权限)
availableDatasets,
loadingAvailableDatasets,
// 方法
handlePageChange,
handleDocumentDeleted,
@@ -35,6 +40,7 @@ export default function DatasetManager() {
handleBackToDocuments,
handleTabChange,
handleDatasetUpdated,
handleDatasetChange,
} = useDatasetManager();
// 加载中状态
@@ -101,6 +107,11 @@ export default function DatasetManager() {
return <RetrieveTest datasetId={dataset?.id || ''} />;
}
// 配置管理菜单
if (activeTab === 'area-config') {
return <AreaDatasetConfig />;
}
// 设置菜单
if (activeTab === 'settings') {
return (
@@ -122,6 +133,9 @@ export default function DatasetManager() {
onTabChange={handleTabChange}
showBackButton={activeTab === 'documents' && !!selectedDocument}
onBack={handleBackToDocuments}
availableDatasets={availableDatasets}
loadingAvailableDatasets={loadingAvailableDatasets}
onDatasetChange={handleDatasetChange}
>
{renderContent()}
</DatasetLayout>
+45 -8
View File
@@ -1,10 +1,12 @@
import { Button, Tooltip } from 'antd';
import { Button, Tooltip, Select, Spin } from 'antd';
import {
FileTextOutlined,
SearchOutlined,
SettingOutlined,
ArrowLeftOutlined,
DatabaseOutlined,
AppstoreOutlined,
SwapOutlined,
} from '@ant-design/icons';
import type { DatasetLayoutProps, MenuTab, MenuItem } from '~/types/dify-dataset-manager/layout';
@@ -19,28 +21,63 @@ export default function DatasetLayout({
showBackButton = false,
onBack,
children,
availableDatasets = [],
loadingAvailableDatasets = false,
onDatasetChange,
}: DatasetLayoutProps) {
const menuItems: MenuItem[] = [
{ key: 'documents', icon: <FileTextOutlined />, label: '文档' },
{ key: 'retrieve', icon: <SearchOutlined />, label: '召回测试' },
{ key: 'area-config', icon: <AppstoreOutlined />, label: '配置管理' },
{ key: 'settings', icon: <SettingOutlined />, label: '设置' },
];
// 是否显示知识库选择器(有多个知识库时显示)
const showDatasetSelector = availableDatasets.length > 1;
return (
<div className="dataset-layout">
{/* 左侧侧边栏 */}
<aside className="dataset-sidebar">
{/* 知识库信息 */}
{/* 知识库信息 / 选择器 */}
<div className="sidebar-header">
<div className="dataset-icon">
<DatabaseOutlined />
</div>
<div className="dataset-info">
<Tooltip title={dataset?.name} placement="right">
<h2 className="dataset-name">{dataset?.name || '知识库'}</h2>
</Tooltip>
<span className="dataset-type"></span>
</div>
{showDatasetSelector ? (
/* 多个知识库时显示下拉选择器 */
<div className="dataset-selector">
<Select
value={dataset?.id}
onChange={onDatasetChange}
loading={loadingAvailableDatasets}
className="dataset-select"
placeholder="选择知识库"
suffixIcon={<SwapOutlined />}
popupMatchSelectWidth={false}
dropdownStyle={{ minWidth: 200 }}
>
{availableDatasets.map(ds => (
<Select.Option key={ds.dataset_id} value={ds.dataset_id}>
<div className="dataset-option">
<span className="dataset-option-name">{ds.dataset_name}</span>
{ds.is_default && <span className="dataset-option-tag"></span>}
{ds.is_public && <span className="dataset-option-tag public"></span>}
</div>
</Select.Option>
))}
</Select>
<span className="dataset-type"></span>
</div>
) : (
/* 单个或无知识库时显示名称 */
<div className="dataset-info">
<Tooltip title={dataset?.name} placement="right">
<h2 className="dataset-name">{dataset?.name || '知识库'}</h2>
</Tooltip>
<span className="dataset-type"></span>
</div>
)}
</div>
{/* 统计信息 */}