| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- /*
- Copyright (C) 2025 QuantumNous
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
- For commercial licensing, please contact support@quantumnous.com
- */
- import React from 'react';
- import {
- Button,
- Space,
- Tag,
- Typography,
- Modal
- } from '@douyinfe/semi-ui';
- import {
- timestamp2string,
- getLobeHubIcon,
- stringToColor
- } from '../../../helpers';
- import { renderLimitedItems, renderDescription } from './ui/RenderUtils.jsx';
- const { Text } = Typography;
- // Render timestamp
- function renderTimestamp(timestamp) {
- return <>{timestamp2string(timestamp)}</>;
- }
- // Render vendor column with icon
- const renderVendorTag = (vendorId, vendorMap, t) => {
- if (!vendorId || !vendorMap[vendorId]) return '-';
- const v = vendorMap[vendorId];
- return (
- <Tag
- color='white'
- shape='circle'
- prefixIcon={getLobeHubIcon(v.icon || 'Layers', 14)}
- >
- {v.name}
- </Tag>
- );
- };
- // Render groups (enable_groups)
- const renderGroups = (groups) => {
- if (!groups || groups.length === 0) return '-';
- return renderLimitedItems({
- items: groups,
- renderItem: (g, idx) => (
- <Tag key={idx} size="small" shape='circle' color={stringToColor(g)}>
- {g}
- </Tag>
- ),
- });
- };
- // Render tags
- const renderTags = (text) => {
- if (!text) return '-';
- const tagsArr = text.split(',').filter(Boolean);
- return renderLimitedItems({
- items: tagsArr,
- renderItem: (tag, idx) => (
- <Tag key={idx} size="small" shape='circle' color={stringToColor(tag)}>
- {tag}
- </Tag>
- ),
- });
- };
- // Render endpoints
- const renderEndpoints = (text) => {
- let arr;
- try {
- arr = JSON.parse(text);
- } catch (_) { }
- if (!Array.isArray(arr)) return text || '-';
- return renderLimitedItems({
- items: arr,
- renderItem: (ep, idx) => (
- <Tag key={idx} color="white" size="small" shape='circle'>
- {ep}
- </Tag>
- ),
- });
- };
- // Render quota type
- const renderQuotaType = (qt, t) => {
- if (qt === 1) {
- return (
- <Tag color='teal' size='small' shape='circle'>
- {t('按次计费')}
- </Tag>
- );
- }
- if (qt === 0) {
- return (
- <Tag color='violet' size='small' shape='circle'>
- {t('按量计费')}
- </Tag>
- );
- }
- return qt ?? '-';
- };
- // Render bound channels
- const renderBoundChannels = (channels) => {
- if (!channels || channels.length === 0) return '-';
- return renderLimitedItems({
- items: channels,
- renderItem: (c, idx) => (
- <Tag key={idx} color="white" size="small" shape='circle'>
- {c.name}({c.type})
- </Tag>
- ),
- });
- };
- // Render operations column
- const renderOperations = (text, record, setEditingModel, setShowEdit, manageModel, refresh, t) => {
- return (
- <Space wrap>
- {record.status === 1 ? (
- <Button
- type='danger'
- size="small"
- onClick={() => manageModel(record.id, 'disable', record)}
- >
- {t('禁用')}
- </Button>
- ) : (
- <Button
- size="small"
- onClick={() => manageModel(record.id, 'enable', record)}
- >
- {t('启用')}
- </Button>
- )}
- <Button
- type='tertiary'
- size="small"
- onClick={() => {
- setEditingModel(record);
- setShowEdit(true);
- }}
- >
- {t('编辑')}
- </Button>
- <Button
- type='danger'
- size="small"
- onClick={() => {
- Modal.confirm({
- title: t('确定是否要删除此模型?'),
- content: t('此修改将不可逆'),
- onOk: () => {
- (async () => {
- await manageModel(record.id, 'delete', record);
- await refresh();
- })();
- },
- });
- }}
- >
- {t('删除')}
- </Button>
- </Space>
- );
- };
- export const getModelsColumns = ({
- t,
- manageModel,
- setEditingModel,
- setShowEdit,
- refresh,
- vendorMap,
- }) => {
- return [
- {
- title: t('模型名称'),
- dataIndex: 'model_name',
- render: (text) => (
- <Text copyable onClick={(e) => e.stopPropagation()}>
- {text}
- </Text>
- ),
- },
- {
- title: t('描述'),
- dataIndex: 'description',
- render: (text) => renderDescription(text, 200),
- },
- {
- title: t('供应商'),
- dataIndex: 'vendor_id',
- render: (vendorId, record) => renderVendorTag(vendorId, vendorMap, t),
- },
- {
- title: t('标签'),
- dataIndex: 'tags',
- render: renderTags,
- },
- {
- title: t('端点'),
- dataIndex: 'endpoints',
- render: renderEndpoints,
- },
- {
- title: t('已绑定渠道'),
- dataIndex: 'bound_channels',
- render: renderBoundChannels,
- },
- {
- title: t('可用分组'),
- dataIndex: 'enable_groups',
- render: renderGroups,
- },
- {
- title: t('计费类型'),
- dataIndex: 'quota_type',
- render: (qt) => renderQuotaType(qt, t),
- },
- {
- title: t('创建时间'),
- dataIndex: 'created_time',
- render: (text, record, index) => {
- return <div>{renderTimestamp(text)}</div>;
- },
- },
- {
- title: t('更新时间'),
- dataIndex: 'updated_time',
- render: (text, record, index) => {
- return <div>{renderTimestamp(text)}</div>;
- },
- },
- {
- title: '',
- dataIndex: 'operate',
- fixed: 'right',
- render: (text, record, index) => renderOperations(
- text,
- record,
- setEditingModel,
- setShowEdit,
- manageModel,
- refresh,
- t
- ),
- },
- ];
- };
|