Selaa lähdekoodia

feat(待接入工具): 新增待接入工具创建功能及搜索优化

- 添加待接入工具创建页面及API接口
- 为待接入工具、工具库和自动接入任务列表添加搜索和过滤功能
- 优化各列表页面的状态显示和操作流程
- 修复工具库详情页MCP工具名称字段禁用问题
max_liu 1 viikko sitten
vanhempi
commit
340b51c82d

+ 28 - 4
server/routes/autoAccessTasks.js

@@ -4,24 +4,48 @@ const { executeQuery } = require('../config/database');
 
 router.get('/', async (req, res) => {
   try {
-    const { page = 1, pageSize = 10 } = req.query;
+    const { page = 1, pageSize = 10, search, status } = req.query;
     const offset = (page - 1) * pageSize;
 
+    // 构建WHERE条件
+    let whereConditions = [];
+    let queryParams = [];
+
+    // 添加搜索条件
+    if (search) {
+      whereConditions.push('tools_name LIKE ?');
+      queryParams.push(`%${search}%`);
+    }
+
+    // 添加状态过滤条件
+    if (status !== undefined && status !== '') {
+      whereConditions.push('status = ?');
+      queryParams.push(parseInt(status));
+    }
+
+    // 构建WHERE子句
+    const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : '';
+
     const sql = `
       SELECT access_task_id, search_task_id, tools_name, tools_function_name,
              access_type, tools_function_desc, api_doc, api_class_name,
              operate_path_data, origin_content_link, status, fail_reason,
              create_time, update_time
       FROM tools_auto_access_task
+      ${whereClause}
       ORDER BY create_time DESC
       LIMIT ? OFFSET ?
     `;
 
-    const countSql = `SELECT COUNT(*) as total FROM tools_auto_access_task`;
+    const countSql = `SELECT COUNT(*) as total FROM tools_auto_access_task ${whereClause}`;
+
+    // 为查询添加分页参数
+    const sqlParams = [...queryParams, parseInt(pageSize), offset];
+    const countParams = [...queryParams];
 
     const [data, countResult] = await Promise.all([
-      executeQuery(sql, [parseInt(pageSize), offset]),
-      executeQuery(countSql)
+      executeQuery(sql, sqlParams),
+      executeQuery(countSql, countParams)
     ]);
 
     res.json({

+ 104 - 8
server/routes/pendingTools.js

@@ -4,7 +4,7 @@ const { executeQuery } = require('../config/database');
 
 router.get('/', async (req, res) => {
   try {
-    const { search, page = 1, pageSize = 10 } = req.query;
+    const { search, toolsName, status, page = 1, pageSize = 10 } = req.query;
     const offset = (page - 1) * pageSize;
 
     let sql = `
@@ -13,20 +13,51 @@ router.get('/', async (req, res) => {
       FROM tools_info_search_task
     `;
     let params = [];
+    let whereConditions = [];
 
+    // 添加工具名称搜索条件
+    if (toolsName) {
+      whereConditions.push('tools_name LIKE ?');
+      params.push(`%${toolsName}%`);
+    }
+
+    // 添加状态搜索条件
+    if (status !== undefined && status !== '') {
+      whereConditions.push('status = ?');
+      params.push(parseInt(status));
+    }
+
+    // 添加全文搜索条件
     if (search) {
-      sql += ` WHERE tools_name LIKE ? OR tools_function_name LIKE ? OR tools_function_desc LIKE ?`;
-      params = [`%${search}%`, `%${search}%`, `%${search}%`];
+      whereConditions.push('(tools_name LIKE ? OR tools_function_name LIKE ? OR tools_function_desc LIKE ?)');
+      params.push(`%${search}%`, `%${search}%`, `%${search}%`);
+    }
+
+    // 构建WHERE子句
+    if (whereConditions.length > 0) {
+      sql += ` WHERE ${whereConditions.join(' AND ')}`;
     }
 
     sql += ` ORDER BY create_time DESC LIMIT ? OFFSET ?`;
     params.push(parseInt(pageSize), offset);
 
-    const countSql = search
-      ? `SELECT COUNT(*) as total FROM tools_info_search_task WHERE tools_name LIKE ? OR tools_function_name LIKE ? OR tools_function_desc LIKE ?`
-      : `SELECT COUNT(*) as total FROM tools_info_search_task`;
-
-    const countParams = search ? [`%${search}%`, `%${search}%`, `%${search}%`] : [];
+    // 构建计数查询
+    let countSql = `SELECT COUNT(*) as total FROM tools_info_search_task`;
+    let countParams = [];
+
+    if (whereConditions.length > 0) {
+      countSql += ` WHERE ${whereConditions.join(' AND ')}`;
+      // 重新构建计数查询的参数
+      if (toolsName) {
+        countParams.push(`%${toolsName}%`);
+      }
+      if (status !== undefined && status !== '') {
+        countParams.push(parseInt(status));
+      }
+      if (search) {
+        countParams.push(`%${search}%`, `%${search}%`, `%${search}%`);
+      }
+    }
 
     const [data, countResult] = await Promise.all([
       executeQuery(sql, params),
@@ -45,6 +76,71 @@ router.get('/', async (req, res) => {
   }
 });
 
+// 新增待接入工具
+router.post('/', async (req, res) => {
+  try {
+    const {
+      search_task_id,
+      tools_name,
+      tools_function_name,
+      tools_function_desc,
+      status = 0
+    } = req.body;
+
+    // 验证必填字段
+    if (!search_task_id || !tools_name || !tools_function_name || !tools_function_desc) {
+      return res.status(400).json({
+        success: false,
+        message: '缺少必填字段'
+      });
+    }
+
+    // 检查search_task_id是否已存在
+    const checkSql = 'SELECT search_task_id FROM tools_info_search_task WHERE search_task_id = ?';
+    const existingTool = await executeQuery(checkSql, [search_task_id]);
+    
+    if (existingTool.length > 0) {
+      return res.status(400).json({
+        success: false,
+        message: '工具ID已存在'
+      });
+    }
+
+    // 插入新记录
+    const insertSql = `
+      INSERT INTO tools_info_search_task 
+      (search_task_id, tools_name, tools_function_name, tools_function_desc, status, create_time, update_time)
+      VALUES (?, ?, ?, ?, ?, NOW(), NOW())
+    `;
+    
+    const result = await executeQuery(insertSql, [
+      search_task_id,
+      tools_name,
+      tools_function_name,
+      tools_function_desc,
+      status
+    ]);
+
+    res.json({
+      success: true,
+      message: '新增工具成功',
+      data: {
+        search_task_id,
+        tools_name,
+        tools_function_name,
+        tools_function_desc,
+        status
+      }
+    });
+  } catch (error) {
+    console.error('新增工具失败:', error);
+    res.status(500).json({
+      success: false,
+      message: '服务器内部错误'
+    });
+  }
+});
+
 router.get('/:id', async (req, res) => {
   try {
     const { id } = req.params;

+ 33 - 4
server/routes/toolsLibrary.js

@@ -4,23 +4,52 @@ const { executeQuery } = require("../config/database");
 
 router.get("/", async (req, res) => {
   try {
-    const { page = 1, pageSize = 10 } = req.query;
+    const { page = 1, pageSize = 10, toolsName, mcpToolsName, status } = req.query;
     const offset = (page - 1) * pageSize;
 
+    // 构建WHERE条件
+    let whereConditions = [];
+    let sqlParams = [];
+    let countParams = [];
+
+    if (toolsName) {
+      whereConditions.push("tools_name LIKE ?");
+      sqlParams.push(`%${toolsName}%`);
+      countParams.push(`%${toolsName}%`);
+    }
+
+    if (mcpToolsName) {
+      whereConditions.push("mcp_tools_name LIKE ?");
+      sqlParams.push(`%${mcpToolsName}%`);
+      countParams.push(`%${mcpToolsName}%`);
+    }
+
+    if (status) {
+      whereConditions.push("status = ?");
+      sqlParams.push(status);
+      countParams.push(status);
+    }
+
+    const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : '';
+
     const sql = `
       SELECT tools_id, tools_name, tools_function_name, mcp_tools_name, tools_full_name,
              tools_desc, tools_version, access_task_id, status, call_type,
              api_provider, api_url_path, create_time, update_time
       FROM tools_library
+      ${whereClause}
       ORDER BY create_time DESC
       LIMIT ? OFFSET ?
     `;
 
-    const countSql = `SELECT COUNT(*) as total FROM tools_library`;
+    const countSql = `SELECT COUNT(*) as total FROM tools_library ${whereClause}`;
+
+    // 添加分页参数
+    sqlParams.push(parseInt(pageSize), offset);
 
     const [data, countResult] = await Promise.all([
-      executeQuery(sql, [parseInt(pageSize), offset]),
-      executeQuery(countSql),
+      executeQuery(sql, sqlParams),
+      executeQuery(countSql, countParams),
     ]);
 
     res.json({

+ 2 - 0
src/App.js

@@ -4,6 +4,7 @@ import { Layout, Menu } from "antd";
 import { ToolOutlined, SearchOutlined, AppstoreOutlined } from "@ant-design/icons";
 import Dashboard from "./components/Dashboard";
 import PendingToolsList from "./pages/PendingToolsList";
+import PendingToolsAdd from "./pages/PendingToolsAdd";
 import PendingToolsDetail from "./pages/PendingToolsDetail";
 import AutoAccessTaskList from "./pages/AutoAccessTaskList";
 import AutoAccessTaskDetail from "./pages/AutoAccessTaskDetail";
@@ -68,6 +69,7 @@ function AppContent() {
               <Route path="/" element={<Navigate to="/pending-tools" replace />} />
               <Route path="/dashboard" element={<Dashboard />} />
               <Route path="/pending-tools" element={<PendingToolsList />} />
+              <Route path="/pending-tools/add" element={<PendingToolsAdd />} />
               <Route path="/pending-tools/:id" element={<PendingToolsDetail />} />
               <Route path="/auto-access-tasks" element={<AutoAccessTaskList />} />
               <Route path="/auto-access-tasks/:id" element={<AutoAccessTaskDetail />} />

+ 99 - 33
src/pages/AutoAccessTaskList.js

@@ -1,6 +1,6 @@
 import React, { useState, useEffect } from "react";
-import { Table, Button, Space, Tag, message, Tooltip } from "antd";
-import { EditOutlined, EyeOutlined } from "@ant-design/icons";
+import { Table, Button, Space, Tag, message, Tooltip, Input, Select, Row, Col } from "antd";
+import { EditOutlined, EyeOutlined, SearchOutlined, ReloadOutlined } from "@ant-design/icons";
 import { useNavigate } from "react-router-dom";
 import { autoAccessTasksApi } from "../services/api";
 import moment from "moment";
@@ -24,6 +24,8 @@ export const STATUS_MAP = {
   6: "审核不通过",
 };
 
+const { Option } = Select;
+
 const AutoAccessTaskList = () => {
   const [data, setData] = useState([]);
   const [loading, setLoading] = useState(false);
@@ -32,6 +34,8 @@ const AutoAccessTaskList = () => {
     pageSize: 10,
     total: 0,
   });
+  const [searchText, setSearchText] = useState("");
+  const [statusFilter, setStatusFilter] = useState(undefined);
   const navigate = useNavigate();
 
   const getStatusColor = (status) => {
@@ -64,18 +68,7 @@ const AutoAccessTaskList = () => {
         </Tooltip>
       ),
     },
-    {
-      title: "检索任务ID",
-      dataIndex: "search_task_id",
-      key: "search_task_id",
-      width: 150,
-      ellipsis: true,
-      render: (text) => (
-        <Tooltip title={text}>
-          <span className="cursor-pointer">{text}</span>
-        </Tooltip>
-      ),
-    },
+
     {
       title: "工具名称",
       dataIndex: "tools_name",
@@ -96,17 +89,13 @@ const AutoAccessTaskList = () => {
       render: (type) => <Tag color="blue">{getAccessTypeText(type)}</Tag>,
     },
     {
-      title: "工具功能描述",
-      dataIndex: "tools_function_desc",
-      key: "tools_function_desc",
-      width: 300,
-      ellipsis: true,
-      render: (text) => (
-        <Tooltip title={text}>
-          <span className="cursor-pointer">{text}</span>
-        </Tooltip>
-      ),
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+      width: 100,
+      render: (status) => <Tag color={getStatusColor(status)}>{getStatusText(status)}</Tag>,
     },
+
     {
       title: "API类名",
       dataIndex: "api_class_name",
@@ -120,11 +109,16 @@ const AutoAccessTaskList = () => {
       ),
     },
     {
-      title: "状态",
-      dataIndex: "status",
-      key: "status",
-      width: 100,
-      render: (status) => <Tag color={getStatusColor(status)}>{getStatusText(status)}</Tag>,
+      title: "工具功能描述",
+      dataIndex: "tools_function_desc",
+      key: "tools_function_desc",
+      width: 300,
+      ellipsis: true,
+      render: (text) => (
+        <Tooltip title={text}>
+          <span className="cursor-pointer">{text}</span>
+        </Tooltip>
+      ),
     },
     {
       title: "失败原因",
@@ -179,13 +173,25 @@ const AutoAccessTaskList = () => {
     },
   ];
 
-  const fetchData = async (page = 1, pageSize = 10) => {
+  const fetchData = async (page = 1, pageSize = 10, search = "", status = undefined) => {
     setLoading(true);
     try {
-      const response = await autoAccessTasksApi.getList({
+      const params = {
         page,
         pageSize,
-      });
+      };
+
+      // 添加搜索参数
+      if (search) {
+        params.search = search;
+      }
+
+      // 添加状态过滤参数
+      if (status !== undefined) {
+        params.status = status;
+      }
+
+      const response = await autoAccessTasksApi.getList(params);
       setData(response.data.data);
       setPagination({
         current: response.data.page,
@@ -200,7 +206,22 @@ const AutoAccessTaskList = () => {
   };
 
   const handleTableChange = (paginationConfig) => {
-    fetchData(paginationConfig.current, paginationConfig.pageSize);
+    fetchData(paginationConfig.current, paginationConfig.pageSize, searchText, statusFilter);
+  };
+
+  const handleSearch = () => {
+    fetchData(1, pagination.pageSize, searchText, statusFilter);
+  };
+
+  const handleReset = () => {
+    setSearchText("");
+    setStatusFilter(undefined);
+    fetchData(1, pagination.pageSize, "", undefined);
+  };
+
+  const handleStatusChange = (value) => {
+    setStatusFilter(value);
+    fetchData(1, pagination.pageSize, searchText, value);
   };
 
   useEffect(() => {
@@ -209,6 +230,51 @@ const AutoAccessTaskList = () => {
 
   return (
     <div className="table-container">
+      <div style={{ marginBottom: 16, padding: 16, backgroundColor: '#fafafa', borderRadius: 6 }}>
+        <Row gutter={[16, 16]}>
+          <Col span={6}>
+            <Input
+              placeholder="搜索工具名称"
+              value={searchText}
+              onChange={(e) => setSearchText(e.target.value)}
+              allowClear
+            />
+          </Col>
+          <Col span={6}>
+            <Select
+              placeholder="选择状态"
+              value={statusFilter}
+              onChange={handleStatusChange}
+              allowClear
+              style={{ width: '100%' }}
+            >
+              {Object.entries(STATUS_MAP).map(([key, value]) => (
+                <Option key={key} value={parseInt(key)}>
+                  {value}
+                </Option>
+              ))}
+            </Select>
+          </Col>
+          <Col span={6}>
+            <Space>
+              <Button
+                type="primary"
+                icon={<SearchOutlined />}
+                onClick={handleSearch}
+              >
+                搜索
+              </Button>
+              <Button
+                icon={<ReloadOutlined />}
+                onClick={handleReset}
+              >
+                重置
+              </Button>
+            </Space>
+          </Col>
+        </Row>
+      </div>
+      
       <Table
         columns={columns}
         dataSource={data}

+ 143 - 0
src/pages/PendingToolsAdd.js

@@ -0,0 +1,143 @@
+import React, { useState } from "react";
+import { Form, Input, Button, Card, message, Space } from "antd";
+import { ArrowLeftOutlined, SaveOutlined } from "@ant-design/icons";
+import { useNavigate } from "react-router-dom";
+import { pendingToolsApi } from "../services/api";
+
+const { TextArea } = Input;
+
+const PendingToolsAdd = () => {
+  const [form] = Form.useForm();
+  const [loading, setLoading] = useState(false);
+  const navigate = useNavigate();
+
+  // 生成search_task_id的函数(基于Python代码的JavaScript版本)
+  const generateSearchTaskId = () => {
+    // 获取当前时间,精确到毫秒
+    const now = new Date();
+    const year = now.getFullYear();
+    const month = String(now.getMonth() + 1).padStart(2, "0");
+    const day = String(now.getDate()).padStart(2, "0");
+    const hours = String(now.getHours()).padStart(2, "0");
+    const minutes = String(now.getMinutes()).padStart(2, "0");
+    const seconds = String(now.getSeconds()).padStart(2, "0");
+    const milliseconds = String(now.getMilliseconds()).padStart(3, "0");
+
+    const timestamp = `${year}${month}${day}${hours}${minutes}${seconds}${milliseconds}`;
+
+    // 生成 6 位随机数,范围 100000~999999
+    const randomNumber = Math.floor(Math.random() * (999999 - 100000 + 1)) + 100000;
+
+    return `${timestamp}${randomNumber}`;
+  };
+
+  const handleSubmit = async (values) => {
+    setLoading(true);
+    try {
+      const searchTaskId = generateSearchTaskId();
+      const submitData = {
+        search_task_id: searchTaskId,
+        tools_name: values.toolsName,
+        tools_function_name: values.toolsFunctionName,
+        tools_function_desc: values.toolsFunctionDesc,
+        status: 0, // 默认状态为待处理
+        created_at: new Date().toISOString(),
+        updated_at: new Date().toISOString(),
+      };
+
+      await pendingToolsApi.create(submitData);
+      message.success("新增工具成功!");
+      navigate("/pending-tools");
+    } catch (error) {
+      console.error("新增工具失败:", error);
+      message.error("新增工具失败,请重试");
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleBack = () => {
+    navigate("/pending-tools");
+  };
+
+  return (
+    <div className="p-6">
+      <Card
+        title={
+          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }}>
+            <Button
+              type="text"
+              icon={<ArrowLeftOutlined />}
+              onClick={handleBack}
+            >
+              返回列表
+            </Button>
+            <span style={{ fontSize: "18px", fontWeight: "bold", flex: 1, textAlign: "center" }}>新增待接入工具</span>
+            <div style={{ width: "80px" }}></div> {/* 占位元素,保持标题居中 */}
+          </div>
+        }
+      >
+        <Form
+          form={form}
+          layout="vertical"
+          onFinish={handleSubmit}
+          autoComplete="off"
+        >
+          <Form.Item
+            label="工具名称"
+            name="toolsName"
+            rules={[
+              { required: true, message: "请输入工具名称" },
+              { max: 100, message: "工具名称不能超过100个字符" },
+            ]}
+          >
+            <Input placeholder="请输入工具名称" />
+          </Form.Item>
+
+          <Form.Item
+            label="工具功能名称"
+            name="toolsFunctionName"
+            rules={[
+              { required: true, message: "请输入工具功能名称" },
+              { max: 200, message: "工具功能名称不能超过200个字符" },
+            ]}
+          >
+            <Input placeholder="请输入工具功能名称" />
+          </Form.Item>
+
+          <Form.Item
+            label="工具功能描述"
+            name="toolsFunctionDesc"
+            rules={[
+              { required: true, message: "请输入工具功能描述" },
+              { max: 1000, message: "工具功能描述不能超过1000个字符" },
+            ]}
+          >
+            <TextArea
+              placeholder="请输入工具功能描述"
+              rows={6}
+              showCount
+              maxLength={1000}
+            />
+          </Form.Item>
+
+          <Form.Item style={{ textAlign: 'center' }}>
+            <Space>
+              <Button
+                type="primary"
+                htmlType="submit"
+                loading={loading}
+                icon={<SaveOutlined />}
+              >
+                保存
+              </Button>
+              <Button onClick={handleBack}>取消</Button>
+            </Space>
+          </Form.Item>
+        </Form>
+      </Card>
+    </div>
+  );
+};
+
+export default PendingToolsAdd;

+ 136 - 16
src/pages/PendingToolsList.js

@@ -1,6 +1,13 @@
 import React, { useState, useEffect } from "react";
-import { Table, Button, Input, Space, Tag, message, Modal, Tooltip } from "antd";
-import { SearchOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from "@ant-design/icons";
+import { Table, Button, Input, Space, Tag, message, Modal, Tooltip, Select } from "antd";
+import {
+  SearchOutlined,
+  EditOutlined,
+  DeleteOutlined,
+  EyeOutlined,
+  ReloadOutlined,
+  PlusOutlined,
+} from "@ant-design/icons";
 import { useNavigate } from "react-router-dom";
 import { pendingToolsApi } from "../services/api";
 import moment from "moment";
@@ -33,6 +40,10 @@ const PendingToolsList = () => {
     total: 0,
   });
   const [searchText, setSearchText] = useState("");
+  const [searchForm, setSearchForm] = useState({
+    toolsName: "",
+    status: undefined,
+  });
   const navigate = useNavigate();
 
   const getStatusColor = (status) => {
@@ -142,14 +153,27 @@ const PendingToolsList = () => {
     },
   ];
 
-  const fetchData = async (page = 1, pageSize = 10, search = "") => {
+  const fetchData = async (page = 1, pageSize = 10, searchParams = {}) => {
     setLoading(true);
     try {
-      const response = await pendingToolsApi.getList({
+      const params = {
         page,
         pageSize,
-        search,
-      });
+      };
+
+      // 添加搜索参数
+      if (searchParams.toolsName) {
+        params.toolsName = searchParams.toolsName;
+      }
+      if (searchParams.status !== undefined && searchParams.status !== "") {
+        params.status = searchParams.status;
+      }
+      // 保持原有的search参数兼容性
+      if (searchParams.search) {
+        params.search = searchParams.search;
+      }
+
+      const response = await pendingToolsApi.getList(params);
       setData(response.data.data);
       setPagination({
         current: response.data.page,
@@ -164,12 +188,57 @@ const PendingToolsList = () => {
   };
 
   const handleTableChange = (paginationConfig) => {
-    fetchData(paginationConfig.current, paginationConfig.pageSize, searchText);
+    const searchParams = {
+      ...searchForm,
+      search: searchText,
+    };
+    fetchData(paginationConfig.current, paginationConfig.pageSize, searchParams);
   };
 
   const handleSearch = (value) => {
     setSearchText(value);
-    fetchData(1, pagination.pageSize, value);
+    const searchParams = {
+      ...searchForm,
+      search: value,
+    };
+    fetchData(1, pagination.pageSize, searchParams);
+  };
+
+  // 新的搜索处理函数
+  const handleNewSearch = () => {
+    const searchParams = {
+      ...searchForm,
+      search: searchText,
+    };
+    fetchData(1, pagination.pageSize, searchParams);
+  };
+
+  // 重置处理函数
+  const handleReset = () => {
+    setSearchForm({
+      toolsName: "",
+      status: undefined,
+    });
+    setSearchText("");
+    fetchData(1, pagination.pageSize, {});
+  };
+
+  // 搜索表单变更处理函数
+  const handleSearchFormChange = (field, value) => {
+    const newSearchForm = {
+      ...searchForm,
+      [field]: value,
+    };
+    setSearchForm(newSearchForm);
+
+    // 选择状态后立即刷新数据
+    if (field === "status") {
+      const searchParams = {
+        ...newSearchForm,
+        search: searchText,
+      };
+      fetchData(1, pagination.pageSize, searchParams);
+    }
   };
 
   const handleDelete = (id) => {
@@ -198,14 +267,65 @@ const PendingToolsList = () => {
     <div className="space-y-6">
       <div className="table-container">
         <div className="mb-6">
-          <Search
-            placeholder="搜索工具名称、功能名称或描述"
-            allowClear
-            enterButton={<SearchOutlined />}
-            size="large"
-            onSearch={handleSearch}
-            className="max-w-md"
-          />
+          {/* 新的搜索区域 */}
+          <div className="bg-gray-50 p-4 rounded-lg mb-4 flex justify-between items-center">
+            <div className="grid grid-cols-1 md:grid-cols-5 gap-4 items-end">
+              {/* 工具名称搜索 */}
+              <div>
+                <Input
+                  placeholder="请输入工具名称"
+                  value={searchForm.toolsName}
+                  onChange={(e) => handleSearchFormChange("toolsName", e.target.value)}
+                  allowClear
+                />
+              </div>
+
+              {/* 状态下拉选择 */}
+              <div>
+                <Select
+                  placeholder="选择状态"
+                  value={searchForm.status}
+                  onChange={(value) => handleSearchFormChange("status", value)}
+                  allowClear
+                  className="w-full"
+                >
+                  <Select.Option value={0}>待处理</Select.Option>
+                  <Select.Option value={1}>处理中</Select.Option>
+                  <Select.Option value={2}>已完成</Select.Option>
+                  <Select.Option value={3}>失败</Select.Option>
+                  <Select.Option value={4}>待审核</Select.Option>
+                </Select>
+              </div>
+
+              {/* 操作按钮 */}
+              <div className="flex space-x-2">
+                <Button
+                  type="primary"
+                  icon={<SearchOutlined />}
+                  onClick={handleNewSearch}
+                >
+                  搜索
+                </Button>
+                <Button
+                  icon={<ReloadOutlined />}
+                  onClick={handleReset}
+                >
+                  重置
+                </Button>
+              </div>
+            </div>
+            {/* 新增按钮 */}
+            <div>
+              <Button
+                type="primary"
+                icon={<PlusOutlined />}
+                onClick={() => navigate("/pending-tools/add")}
+                className="w-full"
+              >
+                新增工具
+              </Button>
+            </div>
+          </div>
         </div>
         <Table
           columns={columns}

+ 2 - 2
src/pages/ToolsLibraryDetail.js

@@ -1,5 +1,5 @@
 import React, { useState, useEffect } from "react";
-import { Form, Input, Select, Button, Card, Descriptions, Tag, message, Spin, Row, Col, Tooltip } from "antd";
+import { Form, Input, Select, Button, Card, Descriptions, Tag, message, Spin, Row, Text, Col, Tooltip } from "antd";
 import { useParams, useNavigate, useLocation } from "react-router-dom";
 import { ArrowLeftOutlined, CopyOutlined } from "@ant-design/icons";
 import { toolsLibraryApi } from "../services/api";
@@ -229,7 +229,7 @@ const ToolsLibraryDetail = () => {
               label="MCP工具名称"
               name="mcp_tools_name"
             >
-              <Input />
+              <Input disabled />
             </Form.Item>
             <Form.Item
               label="工具描述"

+ 122 - 12
src/pages/ToolsLibraryList.js

@@ -1,6 +1,6 @@
 import React, { useState, useEffect } from "react";
-import { Table, Button, Space, Tag, message, Modal, Tooltip } from "antd";
-import { EditOutlined, EyeOutlined, SendOutlined } from "@ant-design/icons";
+import { Table, Button, Space, Tag, message, Modal, Tooltip, Input, Select, Row, Col } from "antd";
+import { EditOutlined, EyeOutlined, SendOutlined, SearchOutlined, ReloadOutlined } from "@ant-design/icons";
 import { useNavigate } from "react-router-dom";
 import { toolsLibraryApi } from "../services/api";
 import moment from "moment";
@@ -18,6 +18,7 @@ export const STATUS_TAG_COLOR = {
 };
 
 const { confirm } = Modal;
+const { Option } = Select;
 
 const ToolsLibraryList = () => {
   const [data, setData] = useState([]);
@@ -27,6 +28,12 @@ const ToolsLibraryList = () => {
     pageSize: 10,
     total: 0,
   });
+  // 搜索状态
+  const [searchForm, setSearchForm] = useState({
+    toolsName: "",
+    mcpToolsName: "",
+    status: undefined,
+  });
   const navigate = useNavigate();
 
   const getStatusColor = (status) => {
@@ -103,6 +110,13 @@ const ToolsLibraryList = () => {
         </Tooltip>
       ),
     },
+    {
+      title: "状态",
+      dataIndex: "status",
+      key: "status",
+      width: 100,
+      render: (status) => <Tag color={getStatusColor(status)}>{getStatusText(status)}</Tag>,
+    },
     {
       title: "工具描述",
       dataIndex: "tools_desc",
@@ -122,13 +136,7 @@ const ToolsLibraryList = () => {
       width: 80,
       render: (version) => <Tag color="geekblue">{version}</Tag>,
     },
-    {
-      title: "状态",
-      dataIndex: "status",
-      key: "status",
-      width: 100,
-      render: (status) => <Tag color={getStatusColor(status)}>{getStatusText(status)}</Tag>,
-    },
+
     {
       title: "调用方式",
       dataIndex: "call_type",
@@ -206,13 +214,31 @@ const ToolsLibraryList = () => {
     },
   ];
 
-  const fetchData = async (page = 1, pageSize = 10) => {
+  const fetchData = async (page = 1, pageSize = 10, searchParams = null) => {
     setLoading(true);
     try {
-      const response = await toolsLibraryApi.getList({
+      const params = {
         page,
         pageSize,
-      });
+      };
+      
+      // 使用传入的搜索参数或当前的搜索表单状态
+      const currentSearchParams = searchParams || searchForm;
+      
+      // 添加搜索参数
+      if (currentSearchParams.toolsName) {
+        params.toolsName = currentSearchParams.toolsName;
+      }
+      
+      if (currentSearchParams.mcpToolsName) {
+        params.mcpToolsName = currentSearchParams.mcpToolsName;
+      }
+      
+      if (currentSearchParams.status !== undefined && currentSearchParams.status !== '') {
+        params.status = currentSearchParams.status;
+      }
+      
+      const response = await toolsLibraryApi.getList(params);
       setData(response.data.data);
       setPagination({
         current: response.data.page,
@@ -248,12 +274,96 @@ const ToolsLibraryList = () => {
     });
   };
 
+  // 搜索处理函数
+  const handleSearch = () => {
+    fetchData(1, pagination.pageSize, searchForm);
+  };
+
+  // 重置处理函数
+  const handleReset = () => {
+    const resetForm = {
+      toolsName: "",
+      mcpToolsName: "",
+      status: undefined,
+    };
+    setSearchForm(resetForm);
+    fetchData(1, pagination.pageSize, resetForm);
+  };
+
+  // 搜索表单变更处理
+  const handleSearchFormChange = (field, value) => {
+    const newSearchForm = {
+      ...searchForm,
+      [field]: value
+    };
+    setSearchForm(newSearchForm);
+    
+    // 只有状态选择时才自动刷新数据,工具名称和MCP工具名称需要点击搜索按钮
+    if (field === 'status') {
+      fetchData(1, pagination.pageSize, newSearchForm);
+    }
+  };
+
   useEffect(() => {
     fetchData();
   }, []);
 
   return (
     <div className="table-container">
+      {/* 搜索区域 */}
+      <div style={{ marginBottom: 16, padding: 16, backgroundColor: '#fafafa', borderRadius: 6 }}>
+        <Row gutter={[16, 16]}>
+          <Col span={6}>
+            <Input
+              placeholder="搜索工具名称"
+              value={searchForm.toolsName}
+              onChange={(e) => handleSearchFormChange('toolsName', e.target.value)}
+              allowClear
+            />
+          </Col>
+          <Col span={6}>
+            <Input
+              placeholder="搜索MCP工具名称"
+              value={searchForm.mcpToolsName}
+              onChange={(e) => handleSearchFormChange('mcpToolsName', e.target.value)}
+              allowClear
+            />
+          </Col>
+          <Col span={6}>
+            <Select
+              placeholder="选择状态"
+              value={searchForm.status}
+              onChange={(value) => handleSearchFormChange('status', value)}
+              allowClear
+              style={{ width: '100%' }}
+            >
+              {Object.entries(STATUS_MAP).map(([key, value]) => (
+                <Option key={key} value={key}>
+                  {value}
+                </Option>
+              ))}
+            </Select>
+          </Col>
+          <Col span={6}>
+            <Space>
+              <Button
+                type="primary"
+                icon={<SearchOutlined />}
+                onClick={handleSearch}
+              >
+                搜索
+              </Button>
+              <Button
+                icon={<ReloadOutlined />}
+                onClick={handleReset}
+              >
+                重置
+              </Button>
+            </Space>
+          </Col>
+        </Row>
+      </div>
+      
       <Table
         columns={columns}
         dataSource={data}

+ 1 - 0
src/services/api.js

@@ -22,6 +22,7 @@ api.interceptors.response.use(
 export const pendingToolsApi = {
   getList: (params) => api.get("/pending-tools", { params }),
   getDetail: (id) => api.get(`/pending-tools/${id}`),
+  create: (data) => api.post("/pending-tools", data),
   update: (id, data) => api.put(`/pending-tools/${id}`, data),
   delete: (id) => api.delete(`/pending-tools/${id}`),
 };