🚀 refactor: migrate vendor-count aggregation to model layer & align frontend logic

Summary
• Backend
  – Moved duplicate-name validation and total vendor-count aggregation from controllers (`controller/model_meta.go`, `controller/vendor_meta.go`, `controller/prefill_group.go`) to model layer (`model/model_meta.go`, `model/vendor_meta.go`, `model/prefill_group.go`).
  – Added `GetVendorModelCounts()` and `Is*NameDuplicated()` helpers; controllers now call these instead of duplicating queries.
  – API response for `/api/models` now returns `vendor_counts` with per-vendor totals across all pages, plus `all` summary.
  – Removed redundant checks and unused imports, eliminating `go vet` warnings.

• Frontend
  – `useModelsData.js` updated to consume backend-supplied `vendor_counts`, calculate the `all` total once, and drop legacy client-side counting logic.
  – Simplified initial data flow: first render now triggers only one models request.
  – Deleted obsolete `updateVendorCounts` helper and related comments.
  – Ensured search flow also sets `vendorCounts`, keeping tab badges accurate.

Why
This refactor enforces single-responsibility (aggregation in model layer), delivers consistent totals irrespective of pagination, and removes redundant client queries, leading to cleaner code and better performance.
This commit is contained in:
t0ng7u
2025-08-06 01:40:08 +08:00
parent d61a862fa2
commit 7c814a5fd9
12 changed files with 334 additions and 175 deletions

View File

@@ -32,10 +32,12 @@ import {
Row,
} from '@douyinfe/semi-ui';
import {
IconSave,
IconClose,
IconLayers,
} from '@douyinfe/semi-icons';
Save,
X,
FileText,
Building,
Settings,
} from 'lucide-react';
import { API, showError, showSuccess } from '../../../../helpers';
import { useTranslation } from 'react-i18next';
import { useIsMobile } from '../../../../hooks/common/useIsMobile';
@@ -258,7 +260,7 @@ const EditModelModal = (props) => {
theme='solid'
className='!rounded-lg'
onClick={() => formApiRef.current?.submitForm()}
icon={<IconSave />}
icon={<Save size={16} />}
loading={loading}
>
{t('提交')}
@@ -268,7 +270,7 @@ const EditModelModal = (props) => {
className='!rounded-lg'
type='primary'
onClick={handleCancel}
icon={<IconClose />}
icon={<X size={16} />}
>
{t('取消')}
</Button>
@@ -291,7 +293,7 @@ const EditModelModal = (props) => {
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='green' className='mr-2 shadow-md'>
<IconLayers size={16} />
<FileText size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('基本信息')}</Text>
@@ -373,7 +375,7 @@ const EditModelModal = (props) => {
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='blue' className='mr-2 shadow-md'>
<IconLayers size={16} />
<Building size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('供应商信息')}</Text>
@@ -405,7 +407,7 @@ const EditModelModal = (props) => {
<Card className='!rounded-2xl shadow-sm border-0'>
<div className='flex items-center mb-2'>
<Avatar size='small' color='purple' className='mr-2 shadow-md'>
<IconLayers size={16} />
<Settings size={16} />
</Avatar>
<div>
<Text className='text-lg font-medium'>{t('功能配置')}</Text>