1
0
Files
nex/frontend/src/pages/Providers/ProviderTable.tsx
lanyuanxiaoyao c04a13bf8a refactor: 重写 Git hooks 体系,委托已有检查、新增模板与 LFS 校验
pre-commit 代码检查改为委托 _backend-lint / _versionctl-lint / _frontend-check,新增 LFS 指针校验;commit-msg 新增多行空行格式校验和模板注释忽略,移除 CJK/Python 字符集检测;新增 prepare-commit-msg 提交信息模板;hooks-install 增加 source 文件存在性校验;前端 check 补入 tsc -b 类型检查并修复暴露的类型错误
2026-05-06 13:44:28 +08:00

158 lines
4.1 KiB
TypeScript

import { Button, Table, Tag, Popconfirm, Space, Card, Typography, MessagePlugin } from 'tdesign-react'
import type { Provider, Model } from '@/types'
import { ModelTable } from './ModelTable'
import type { PrimaryTableCol } from 'tdesign-react/es/table/type'
interface ProviderTableProps {
providers: Provider[]
loading: boolean
onAdd: () => void
onEdit: (provider: Provider) => void
onDelete: (id: string) => void
onAddModel: (providerId: string) => void
onEditModel: (model: Model) => void
}
export function ProviderTable({
providers,
loading,
onAdd,
onEdit,
onDelete,
onAddModel,
onEditModel,
}: ProviderTableProps) {
const columns: PrimaryTableCol<Provider>[] = [
{
title: '名称',
colKey: 'name',
width: 180,
ellipsis: true,
},
{
title: 'Base URL',
colKey: 'baseUrl',
cell: ({ row }) =>
row.baseUrl ? (
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, maxWidth: '100%' }}>
<span
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
minWidth: 0,
}}
>
{row.baseUrl}
</span>
<Typography.Text
style={{ flexShrink: 0 }}
copyable={{
text: row.baseUrl,
onCopy: () => MessagePlugin.success('已复制 Base URL'),
}}
>
{''}
</Typography.Text>
</span>
) : null,
},
{
title: '协议',
colKey: 'protocol',
width: 100,
cell: ({ row }) => (
<Tag theme={row.protocol === 'openai' ? 'primary' : 'success'} variant='light' shape='round'>
{row.protocol === 'openai' ? 'OpenAI' : 'Anthropic'}
</Tag>
),
},
{
title: 'API Key',
colKey: 'apiKey',
cell: ({ row }) =>
row.apiKey ? (
<span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, maxWidth: '100%' }}>
<span
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
minWidth: 0,
}}
>
{row.apiKey}
</span>
<Typography.Text
style={{ flexShrink: 0 }}
copyable={{
text: row.apiKey,
onCopy: () => MessagePlugin.success('已复制 API Key'),
}}
>
{''}
</Typography.Text>
</span>
) : null,
},
{
title: '状态',
colKey: 'enabled',
width: 80,
cell: ({ row }) =>
row.enabled ? (
<Tag theme='success' variant='light' shape='round'>
</Tag>
) : (
<Tag theme='danger' variant='light' shape='round'>
</Tag>
),
},
{
title: '操作',
colKey: 'action',
width: 160,
cell: ({ row }) => (
<Space>
<Button variant='text' size='small' onClick={() => onEdit(row)}>
</Button>
<Popconfirm content='确定要删除这个供应商吗?关联的模型也会被删除。' onConfirm={() => onDelete(row.id)}>
<Button variant='text' theme='danger' size='small'>
</Button>
</Popconfirm>
</Space>
),
},
]
return (
<Card
title='供应商列表'
headerBordered
hoverShadow
actions={
<Button theme='primary' onClick={onAdd}>
</Button>
}
>
<Table<Provider>
columns={columns}
data={providers}
rowKey='id'
loading={loading}
stripe
expandedRow={({ row }) => (
<ModelTable providerId={row.id} onAdd={() => onAddModel(row.id)} onEdit={onEditModel} />
)}
pagination={undefined}
empty='暂无供应商,点击上方按钮添加'
/>
</Card>
)
}