Просмотр исходного кода

🔄 fix: improve vendor-tab filtering & counts, resolve SQL ambiguity, and reload data correctly

Backend
• model/model_meta.go
  – Import strconv
  – SearchModels: support numeric vendor ID filter vs. fuzzy name search
  – Explicitly order by `models.id` to avoid “ambiguous column name: id” error

Frontend
• hooks/useModelsData.js
  – Change vendor-filter API to pass vendor ID
  – Automatically reload models when `activeVendorKey` changes
  – Update vendor counts only when viewing “All” to preserve other tab totals
• Add missing effect in EditModelModal to refresh vendor list only when modal visible
• Other minor updates to keep lints clean

Result
Tabs now:
1. Trigger API requests on click
2. Show accurate per-vendor totals
3. Filter models without resetting other counts
Backend search handles both vendor IDs and names without SQL errors.
t0ng7u 7 месяцев назад
Родитель
Сommit
232612898b

+ 8 - 2
model/model_meta.go

@@ -2,6 +2,7 @@ package model
 
 
 import (
 import (
     "one-api/common"
     "one-api/common"
+    "strconv"
 
 
     "gorm.io/gorm"
     "gorm.io/gorm"
 )
 )
@@ -96,13 +97,18 @@ func SearchModels(keyword string, vendor string, offset int, limit int) ([]*Mode
         db = db.Where("model_name LIKE ? OR description LIKE ? OR tags LIKE ?", like, like, like)
         db = db.Where("model_name LIKE ? OR description LIKE ? OR tags LIKE ?", like, like, like)
     }
     }
     if vendor != "" {
     if vendor != "" {
-        db = db.Joins("JOIN vendors ON vendors.id = models.vendor_id").Where("vendors.name LIKE ?", "%"+vendor+"%")
+        // 如果是数字,按供应商 ID 精确匹配;否则按名称模糊匹配
+        if vid, err := strconv.Atoi(vendor); err == nil {
+            db = db.Where("models.vendor_id = ?", vid)
+        } else {
+            db = db.Joins("JOIN vendors ON vendors.id = models.vendor_id").Where("vendors.name LIKE ?", "%"+vendor+"%")
+        }
     }
     }
     var total int64
     var total int64
     err := db.Count(&total).Error
     err := db.Count(&total).Error
     if err != nil {
     if err != nil {
         return nil, 0, err
         return nil, 0, err
     }
     }
-    err = db.Offset(offset).Limit(limit).Order("id DESC").Find(&models).Error
+    err = db.Offset(offset).Limit(limit).Order("models.id DESC").Find(&models).Error
     return models, total, err
     return models, total, err
 }
 }

+ 4 - 3
web/src/components/table/models/modals/EditModelModal.jsx

@@ -75,9 +75,10 @@ const EditModelModal = (props) => {
   };
   };
 
 
   useEffect(() => {
   useEffect(() => {
-    fetchVendors();
-  }, []);
-
+    if (props.visiable) {
+      fetchVendors();
+    }
+  }, [props.visiable]);
 
 
   const getInitValues = () => ({
   const getInitValues = () => ({
     model_name: '',
     model_name: '',

+ 14 - 10
web/src/hooks/models/useModelsData.js

@@ -87,7 +87,7 @@ export const useModelsData = () => {
     setModels(models);
     setModels(models);
   };
   };
 
 
-  // 获取供应商列表
+  // Vendor list
   const [vendors, setVendors] = useState([]);
   const [vendors, setVendors] = useState([]);
   const [vendorCounts, setVendorCounts] = useState({});
   const [vendorCounts, setVendorCounts] = useState({});
   const [activeVendorKey, setActiveVendorKey] = useState('all');
   const [activeVendorKey, setActiveVendorKey] = useState('all');
@@ -103,7 +103,7 @@ export const useModelsData = () => {
     return map;
     return map;
   }, [vendors]);
   }, [vendors]);
 
 
-  // 加载供应商列表
+  // Load vendor list
   const loadVendors = async () => {
   const loadVendors = async () => {
     try {
     try {
       const res = await API.get('/api/vendors/?page_size=1000');
       const res = await API.get('/api/vendors/?page_size=1000');
@@ -122,11 +122,8 @@ export const useModelsData = () => {
     try {
     try {
       let url = `/api/models/?p=${page}&page_size=${size}`;
       let url = `/api/models/?p=${page}&page_size=${size}`;
       if (vendorKey && vendorKey !== 'all') {
       if (vendorKey && vendorKey !== 'all') {
-        // 按供应商筛选,通过vendor搜索接口
-        const vendor = vendors.find(v => String(v.id) === vendorKey);
-        if (vendor) {
-          url = `/api/models/search?vendor=${vendor.name}&p=${page}&page_size=${size}`;
-        }
+        // Filter by vendor ID
+        url = `/api/models/search?vendor=${vendorKey}&p=${page}&page_size=${size}`;
       }
       }
 
 
       const res = await API.get(url);
       const res = await API.get(url);
@@ -138,8 +135,10 @@ export const useModelsData = () => {
         setModelCount(data.total || newPageData.length);
         setModelCount(data.total || newPageData.length);
         setModelFormat(newPageData);
         setModelFormat(newPageData);
 
 
-        // 更新供应商统计
-        updateVendorCounts(newPageData);
+        // Refresh vendor counts only when viewing 'all' to preserve other counts
+        if (vendorKey === 'all') {
+          updateVendorCounts(newPageData);
+        }
       } else {
       } else {
         showError(message);
         showError(message);
         setModels([]);
         setModels([]);
@@ -227,7 +226,7 @@ export const useModelsData = () => {
     }
     }
   };
   };
 
 
-  // 更新供应商统计
+  // Update vendor counts
   const updateVendorCounts = (models) => {
   const updateVendorCounts = (models) => {
     const counts = { all: models.length };
     const counts = { all: models.length };
     models.forEach(model => {
     models.forEach(model => {
@@ -244,6 +243,11 @@ export const useModelsData = () => {
     loadModels(page, pageSize, activeVendorKey);
     loadModels(page, pageSize, activeVendorKey);
   };
   };
 
 
+  // Reload models when activeVendorKey changes
+  useEffect(() => {
+    loadModels(1, pageSize, activeVendorKey);
+  }, [activeVendorKey]);
+
   // Handle page size change
   // Handle page size change
   const handlePageSizeChange = async (size) => {
   const handlePageSizeChange = async (size) => {
     setPageSize(size);
     setPageSize(size);