🔄 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.
This commit is contained in:
t0ng7u
2025-07-31 23:30:45 +08:00
parent 6a37efb871
commit 232612898b
3 changed files with 26 additions and 15 deletions

View File

@@ -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
} }

View File

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

View File

@@ -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搜索接口 // Filter by vendor ID
const vendor = vendors.find(v => String(v.id) === vendorKey); url = `/api/models/search?vendor=${vendorKey}&p=${page}&page_size=${size}`;
if (vendor) {
url = `/api/models/search?vendor=${vendor.name}&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);
// 更新供应商统计 // Refresh vendor counts only when viewing 'all' to preserve other counts
updateVendorCounts(newPageData); 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);