1
0

fix: 修复供应商管理弹窗交互问题并去掉 API Key 脱敏

- Dialog 设置 lazy={false} 修复首次打开编辑弹窗表单为空
- API Key 改为普通字段(前端去掉 password 类型,后端去掉掩码逻辑)
- 删除模型编辑弹窗中的统一模型 ID 字段
- 简化 ProviderService.Get 签名(去掉 maskKey 参数)
- 删除 domain 和 config 层的 MaskAPIKey() 方法
- 更新前后端测试(107 单元测试 + 16 E2E 全部通过)
- 同步 delta spec 到主 spec
This commit is contained in:
2026-04-22 13:13:25 +08:00
parent 81dcecb723
commit 5d58acf5a6
23 changed files with 68 additions and 128 deletions

View File

@@ -125,9 +125,6 @@ describe('ModelForm', () => {
const dialog = getDialog();
expect(within(dialog).getByText('编辑模型')).toBeInTheDocument();
// Check that unified ID field is displayed
expect(within(dialog).getByText('统一模型 ID')).toBeInTheDocument();
// Check model name input
const modelNameInput = within(dialog).getByPlaceholderText('例如: gpt-4o') as HTMLInputElement;
expect(modelNameInput.value).toBe('gpt-4o');

View File

@@ -63,13 +63,16 @@ describe('ProviderForm', () => {
const baseUrlInput = within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1') as HTMLInputElement;
expect(baseUrlInput.value).toBe('https://api.openai.com/v1');
const apiKeyInput = within(dialog).getByPlaceholderText('sk-...') as HTMLInputElement;
expect(apiKeyInput.value).toBe('sk-old-key');
});
it('shows API Key label variant in edit mode', () => {
it('shows API Key label in edit mode', () => {
render(<ProviderForm {...defaultProps} provider={mockProvider} />);
const dialog = getDialog();
expect(within(dialog).getByText('API Key(留空则不修改)')).toBeInTheDocument();
expect(within(dialog).getByText('API Key')).toBeInTheDocument();
});
it('shows validation error messages for required fields', async () => {

View File

@@ -1,4 +1,4 @@
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { ProviderTable } from '@/pages/Providers/ProviderTable';
@@ -48,19 +48,18 @@ const defaultProps = {
};
describe('ProviderTable', () => {
it('renders provider list with name, baseUrl, masked apiKey, and status tags', () => {
it('renders provider list with name, baseUrl, apiKey, and status tags', () => {
render(<ProviderTable {...defaultProps} />);
expect(screen.getByText('供应商列表')).toBeInTheDocument();
// Check that provider names appear (they will appear in both name column and potentially protocol column)
expect(screen.getAllByText('OpenAI').length).toBeGreaterThan(0);
expect(screen.getByText('https://api.openai.com/v1')).toBeInTheDocument();
expect(screen.getByText('****5678')).toBeInTheDocument();
expect(screen.getByText('sk-abcdefgh12345678')).toBeInTheDocument();
expect(screen.getAllByText('Anthropic').length).toBeGreaterThan(0);
expect(screen.getByText('https://api.anthropic.com')).toBeInTheDocument();
expect(screen.getByText('****test')).toBeInTheDocument();
expect(screen.getByText('sk-ant-test')).toBeInTheDocument();
const enabledTags = screen.getAllByText('启用');
const disabledTags = screen.getAllByText('禁用');
@@ -77,7 +76,7 @@ describe('ProviderTable', () => {
expect(container.querySelector('.t-card__body')).toBeInTheDocument();
});
it('renders short api keys fully masked', () => {
it('renders short api keys directly', () => {
const shortKeyProvider: Provider[] = [
{
...mockProviders[0],
@@ -88,7 +87,7 @@ describe('ProviderTable', () => {
];
render(<ProviderTable {...defaultProps} providers={shortKeyProvider} />);
expect(screen.getByText('****')).toBeInTheDocument();
expect(screen.getByText('ab')).toBeInTheDocument();
});
it('calls onAdd when clicking "添加供应商" button', async () => {