| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | import React, { useEffect, useState } from 'react';
|
| | import {
|
| | Modal,
|
| | Table,
|
| | Spin,
|
| | Button,
|
| | Typography,
|
| | Empty,
|
| | Input,
|
| | } from '@douyinfe/semi-ui';
|
| | import {
|
| | IllustrationNoResult,
|
| | IllustrationNoResultDark,
|
| | } from '@douyinfe/semi-illustrations';
|
| | import { IconSearch } from '@douyinfe/semi-icons';
|
| | import { API, showError } from '../../../../helpers';
|
| | import { MODEL_TABLE_PAGE_SIZE } from '../../../../constants';
|
| | import { useIsMobile } from '../../../../hooks/common/useIsMobile';
|
| |
|
| | const MissingModelsModal = ({ visible, onClose, onConfigureModel, t }) => {
|
| | const [loading, setLoading] = useState(false);
|
| | const [missingModels, setMissingModels] = useState([]);
|
| | const [searchKeyword, setSearchKeyword] = useState('');
|
| | const [currentPage, setCurrentPage] = useState(1);
|
| | const isMobile = useIsMobile();
|
| |
|
| | const fetchMissing = async () => {
|
| | setLoading(true);
|
| | try {
|
| | const res = await API.get('/api/models/missing');
|
| | if (res.data.success) {
|
| | setMissingModels(res.data.data || []);
|
| | } else {
|
| | showError(res.data.message);
|
| | }
|
| | } catch (_) {
|
| | showError(t('获取未配置模型失败'));
|
| | }
|
| | setLoading(false);
|
| | };
|
| |
|
| | useEffect(() => {
|
| | if (visible) {
|
| | fetchMissing();
|
| | setSearchKeyword('');
|
| | setCurrentPage(1);
|
| | } else {
|
| | setMissingModels([]);
|
| | }
|
| | }, [visible]);
|
| |
|
| |
|
| | const filteredModels = missingModels.filter((model) =>
|
| | model.toLowerCase().includes(searchKeyword.toLowerCase()),
|
| | );
|
| |
|
| | const dataSource = (() => {
|
| | const start = (currentPage - 1) * MODEL_TABLE_PAGE_SIZE;
|
| | const end = start + MODEL_TABLE_PAGE_SIZE;
|
| | return filteredModels.slice(start, end).map((model) => ({
|
| | model,
|
| | key: model,
|
| | }));
|
| | })();
|
| |
|
| | const columns = [
|
| | {
|
| | title: t('模型名称'),
|
| | dataIndex: 'model',
|
| | render: (text) => (
|
| | <div className='flex items-center'>
|
| | <Typography.Text strong>{text}</Typography.Text>
|
| | </div>
|
| | ),
|
| | },
|
| | {
|
| | title: '',
|
| | dataIndex: 'operate',
|
| | fixed: 'right',
|
| | width: 120,
|
| | render: (text, record) => (
|
| | <Button
|
| | type='primary'
|
| | size='small'
|
| | onClick={() => onConfigureModel(record.model)}
|
| | >
|
| | {t('配置')}
|
| | </Button>
|
| | ),
|
| | },
|
| | ];
|
| |
|
| | return (
|
| | <Modal
|
| | title={
|
| | <div className='flex flex-col gap-2 w-full'>
|
| | <div className='flex items-center gap-2'>
|
| | <Typography.Text
|
| | strong
|
| | className='!text-[var(--semi-color-text-0)] !text-base'
|
| | >
|
| | {t('未配置的模型列表')}
|
| | </Typography.Text>
|
| | <Typography.Text type='tertiary' size='small'>
|
| | {t('共')} {missingModels.length} {t('个未配置模型')}
|
| | </Typography.Text>
|
| | </div>
|
| | </div>
|
| | }
|
| | visible={visible}
|
| | onCancel={onClose}
|
| | footer={null}
|
| | size={isMobile ? 'full-width' : 'medium'}
|
| | className='!rounded-lg'
|
| | >
|
| | <Spin spinning={loading}>
|
| | {missingModels.length === 0 && !loading ? (
|
| | <Empty
|
| | image={<IllustrationNoResult style={{ width: 150, height: 150 }} />}
|
| | darkModeImage={
|
| | <IllustrationNoResultDark style={{ width: 150, height: 150 }} />
|
| | }
|
| | description={t('暂无缺失模型')}
|
| | style={{ padding: 30 }}
|
| | />
|
| | ) : (
|
| | <div className='missing-models-content'>
|
| | {/* 搜索框 */}
|
| | <div className='flex items-center justify-end gap-2 w-full mb-4'>
|
| | <Input
|
| | placeholder={t('搜索模型...')}
|
| | value={searchKeyword}
|
| | onChange={(v) => {
|
| | setSearchKeyword(v);
|
| | setCurrentPage(1);
|
| | }}
|
| | className='!w-full'
|
| | prefix={<IconSearch />}
|
| | showClear
|
| | />
|
| | </div>
|
| |
|
| | {/* 表格 */}
|
| | {filteredModels.length > 0 ? (
|
| | <Table
|
| | columns={columns}
|
| | dataSource={dataSource}
|
| | pagination={{
|
| | currentPage: currentPage,
|
| | pageSize: MODEL_TABLE_PAGE_SIZE,
|
| | total: filteredModels.length,
|
| | showSizeChanger: false,
|
| | onPageChange: (page) => setCurrentPage(page),
|
| | }}
|
| | />
|
| | ) : (
|
| | <Empty
|
| | image={
|
| | <IllustrationNoResult style={{ width: 100, height: 100 }} />
|
| | }
|
| | darkModeImage={
|
| | <IllustrationNoResultDark
|
| | style={{ width: 100, height: 100 }}
|
| | />
|
| | }
|
| | description={
|
| | searchKeyword ? t('未找到匹配的模型') : t('暂无缺失模型')
|
| | }
|
| | style={{ padding: 20 }}
|
| | />
|
| | )}
|
| | </div>
|
| | )}
|
| | </Spin>
|
| | </Modal>
|
| | );
|
| | };
|
| |
|
| | export default MissingModelsModal;
|
| |
|