chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -22,7 +22,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { ImageRender } from '../../../src/components/renders/image-render';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/bot-semi', () => ({
Image: ({ src, fallback, placeholder, onClick, preview, ...props }: any) => {
if (!src) {
@@ -55,7 +55,7 @@ vi.mock('@coze-arch/bot-icons', () => ({
),
}));
// 模拟useImagePreview钩子
// Simulation useImagePreview hook
vi.mock(
'../../../src/components/renders/image-render/use-image-preview',
() => ({
@@ -84,7 +84,7 @@ describe('ImageRender', () => {
render(<ImageRender srcList={srcList} />);
// 验证图片容器被渲染
// Verify that the image container is rendered
const images = screen.getAllByTestId('image');
expect(images).toHaveLength(2);
expect(images[0]).toHaveAttribute('src', srcList[0]);
@@ -94,11 +94,11 @@ describe('ImageRender', () => {
test('应该处理空的图片列表', () => {
render(<ImageRender srcList={[]} />);
// 验证没有图片被渲染
// Verify that no images are being rendered
const images = screen.queryAllByTestId('image');
expect(images).toHaveLength(0);
// 验证空状态容器存在
// Verify that an empty state container exists
const emptyContainer = screen.getByTestId('image-preview-modal');
expect(emptyContainer).toBeInTheDocument();
});
@@ -112,7 +112,7 @@ describe('ImageRender', () => {
render(<ImageRender srcList={[]} customEmpty={customEmpty} />);
// 验证自定义空状态被渲染
// Verify that the custom empty state is rendered
const customEmptyElement = screen.getByTestId('custom-empty');
expect(customEmptyElement).toBeInTheDocument();
expect(customEmptyElement).toHaveTextContent('自定义空状态');
@@ -126,8 +126,8 @@ describe('ImageRender', () => {
/>,
);
// 验证自定义className被应用
// 由于组件结构复杂,我们直接查找包含custom-class的元素
// Verify that the custom className is applied
// Due to the complex structure of components, we directly look for elements containing custom-classes
const container = document.querySelector('.custom-class');
expect(container).toBeInTheDocument();
});
@@ -137,11 +137,11 @@ describe('ImageRender', () => {
render(<ImageRender srcList={srcList} />);
// 点击图片
// Click on the picture.
const image = screen.getByTestId('image');
fireEvent.click(image);
// 验证预览模态框存在
// Verify that the preview modal box exists
const previewModal = screen.getByTestId('image-preview-modal');
expect(previewModal).toBeInTheDocument();
expect(previewModal).toHaveAttribute('data-src', srcList[0]);
@@ -155,7 +155,7 @@ describe('ImageRender', () => {
/>,
);
// 验证editable属性被传递给预览模态框
// Verify that the editable property is passed to the preview modal box
const previewModal = screen.getByTestId('image-preview-modal');
expect(previewModal).toHaveAttribute('data-editable', 'false');
});
@@ -169,7 +169,7 @@ describe('ImageRender', () => {
/>,
);
// 验证onChange属性被传递给预览模态框
// Verify that the onChange property is passed to the preview modal box
const previewModal = screen.getByTestId('image-preview-modal');
expect(previewModal).toBeInTheDocument();
});

View File

@@ -22,7 +22,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { useImagePreview } from '../../../src/components/renders/image-render/use-image-preview';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/coze-design', () => ({
Upload: function Upload({
children,
@@ -167,7 +167,7 @@ vi.mock('../../../src/components/renders/image-render/utils', () => ({
isValidSize: vi.fn().mockReturnValue(true),
}));
// 模拟 CustomError
// Simulate CustomError
vi.mock('@coze-arch/bot-error', () => ({
CustomError: class CustomError extends Error {
constructor(event: string, message: string) {
@@ -179,7 +179,7 @@ vi.mock('@coze-arch/bot-error', () => ({
describe('useImagePreview 基本功能测试', () => {
test('测试图片URL输入框更新', () => {
// 创建一个简单的测试组件
// Create a simple test component
const TestComponent = () => {
const [src, setSrc] = React.useState('https://example.com/image.jpg');
const onChange = vi.fn();
@@ -201,16 +201,16 @@ describe('useImagePreview 基本功能测试', () => {
render(<TestComponent />);
// 验证初始URL正确显示
// Verify that the initial URL is displayed correctly
const urlInput = screen.getByTestId('image-url-input');
expect(urlInput).toHaveValue('https://example.com/image.jpg');
// 修改URL
// Modify URL
fireEvent.change(urlInput, {
target: { value: 'https://example.com/new-image.jpg' },
});
// 验证URL已更新
// Verify that the URL has been updated
expect(
screen.getByText('当前图片URL: https://example.com/new-image.jpg'),
).toBeInTheDocument();
@@ -219,7 +219,7 @@ describe('useImagePreview 基本功能测试', () => {
test('测试确认按钮调用onChange', () => {
const onChange = vi.fn();
// 创建一个简单的测试组件
// Create a simple test component
const TestComponent = () => {
const [src, setSrc] = React.useState('https://example.com/image.jpg');
@@ -235,16 +235,16 @@ describe('useImagePreview 基本功能测试', () => {
render(<TestComponent />);
// 点击确认按钮
// Click the confirm button.
const okButton = screen.getByTestId('modal-ok');
fireEvent.click(okButton);
// 验证onChange被调用
// Verify that onChange is invoked
expect(onChange).toHaveBeenCalledWith('https://example.com/image.jpg', '');
});
test('测试editable属性', () => {
// 创建一个简单的测试组件
// Create a simple test component
const TestComponent = () => {
const [src, setSrc] = React.useState('https://example.com/image.jpg');
const onChange = vi.fn();
@@ -261,7 +261,7 @@ describe('useImagePreview 基本功能测试', () => {
render(<TestComponent />);
// 验证输入框被禁用
// Verify text box is disabled
const urlInput = screen.getByTestId('image-url-input');
expect(urlInput).toBeDisabled();
});

View File

@@ -23,7 +23,7 @@ import {
isValidSize,
} from '../../../src/components/renders/image-render/utils';
// 模拟 CustomError
// Simulate CustomError
vi.mock('@coze-arch/bot-error', () => ({
CustomError: class CustomError extends Error {
constructor(event: string, message: string) {
@@ -48,7 +48,7 @@ describe('getFileExtension', () => {
describe('isValidSize', () => {
test('文件大小小于限制时应返回true', () => {
// 20MB限制
// 20MB limit
const validSize = 10 * 1024 * 1024; // 10MB
expect(isValidSize(validSize)).toBe(true);
});
@@ -66,10 +66,10 @@ describe('isValidSize', () => {
describe('getBase64', () => {
test('应该正确转换文件为base64字符串', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsDataURL: vi.fn(),
onload: null as any,
@@ -77,36 +77,36 @@ describe('getBase64', () => {
onabort: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getBase64
// Call getBase64
const promise = getBase64(mockBlob);
// 触发onload事件
// Trigger onload event
mockFileReader.onload({
target: {
result: 'data:text/plain;base64,dGVzdCBjb250ZW50',
},
} as any);
// 验证结果
// validation result
const result = await promise;
expect(result).toBe('dGVzdCBjb250ZW50');
expect(mockFileReader.readAsDataURL).toHaveBeenCalledWith(mockBlob);
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
test('当FileReader.onload返回非字符串结果时应拒绝Promise', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsDataURL: vi.fn(),
onload: null as any,
@@ -114,34 +114,34 @@ describe('getBase64', () => {
onabort: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getBase64
// Call getBase64
const promise = getBase64(mockBlob);
// 触发onload事件但返回非字符串结果
// Fires the onload event, but returns a non-string result
mockFileReader.onload({
target: {
result: null,
},
} as any);
// 验证Promise被拒绝
// Verification Promise Rejected
await expect(promise).rejects.toThrow('file read invalid');
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
test('当FileReader.onerror触发时应拒绝Promise', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsDataURL: vi.fn(),
onload: null as any,
@@ -149,30 +149,30 @@ describe('getBase64', () => {
onabort: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getBase64
// Call getBase64
const promise = getBase64(mockBlob);
// 触发onerror事件
// Trigger the onerror event
mockFileReader.onerror();
// 验证Promise被拒绝
// Verification Promise Rejected
await expect(promise).rejects.toThrow('file read fail');
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
test('当FileReader.onabort触发时应拒绝Promise', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsDataURL: vi.fn(),
onload: null as any,
@@ -180,100 +180,100 @@ describe('getBase64', () => {
onabort: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getBase64
// Call getBase64
const promise = getBase64(mockBlob);
// 触发onabort事件
// Trigger onabort event
mockFileReader.onabort();
// 验证Promise被拒绝
// Verification Promise Rejected
await expect(promise).rejects.toThrow('file read abort');
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
});
describe('getUint8Array', () => {
test('应该正确转换文件为Uint8Array', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 创建一个模拟的ArrayBuffer
const mockArrayBuffer = new ArrayBuffer(12); // 'test content' 的长度
// Create a simulated ArrayBuffer
const mockArrayBuffer = new ArrayBuffer(12); // Length of'test content '
const uint8Array = new Uint8Array(mockArrayBuffer);
for (let i = 0; i < 12; i++) {
uint8Array[i] = 'test content'.charCodeAt(i);
}
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsArrayBuffer: vi.fn(),
onload: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getUint8Array
// Call getUint8Array
const promise = getUint8Array(mockBlob);
// 触发onload事件
// Trigger onload event
mockFileReader.onload({
target: {
result: mockArrayBuffer,
},
} as any);
// 验证结果
// validation result
const result = await promise;
expect(result).toBeInstanceOf(Uint8Array);
expect(result.length).toBe(12);
expect(mockFileReader.readAsArrayBuffer).toHaveBeenCalledWith(mockBlob);
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
test('当FileReader.onload返回无效结果时应拒绝Promise', async () => {
// 创建一个模拟的Blob对象
// Create a simulated blob object
const mockBlob = new Blob(['test content'], { type: 'text/plain' });
// 模拟FileReader
// Analog FileReader
const mockFileReader = {
readAsArrayBuffer: vi.fn(),
onload: null as any,
};
// 保存原始的FileReader
// Save the original FileReader
const originalFileReader = global.FileReader;
// 模拟FileReader构造函数
// Mock FileReader constructor
global.FileReader = vi.fn(() => mockFileReader) as any;
// 调用getUint8Array
// Call getUint8Array
const promise = getUint8Array(mockBlob);
// 触发onload事件,但返回无效结果
// The onload event is fired, but an invalid result is returned
mockFileReader.onload({
target: {
result: null,
},
} as any);
// 验证Promise被拒绝
// Verification Promise Rejected
await expect(promise).rejects.toThrow('file read invalid');
// 恢复原始的FileReader
// Restore the original FileReader
global.FileReader = originalFileReader;
});
});

View File

@@ -22,7 +22,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { ActionsRender } from '../../../src/components/renders/actions-render';
// 使用vi.mock的回调函数形式来避免linter错误
// Use the callback function form of vi.mock to avoid linter errors
vi.mock('@coze-arch/coze-design/icons', () => ({
IconCozEdit: () => <div data-testid="edit-icon" />,
IconCozTrashCan: () => <div data-testid="delete-icon" />,
@@ -49,9 +49,9 @@ describe('ActionsRender', () => {
render(<ActionsRender record={mockRecord} index={mockIndex} />);
// 验证按钮被渲染
// Verify button is rendered
const buttons = screen.getAllByTestId('button');
expect(buttons).toHaveLength(2); // 编辑和删除按钮
expect(buttons).toHaveLength(2); // Edit and delete buttons
});
test('应该在点击编辑按钮时调用onEdit回调', () => {
@@ -67,11 +67,11 @@ describe('ActionsRender', () => {
/>,
);
// 点击编辑按钮
// Click the Edit button
const buttons = screen.getAllByTestId('button');
fireEvent.click(buttons[0]); // 第一个按钮是编辑按钮
fireEvent.click(buttons[0]); // The first button is the edit button
// 验证编辑回调被调用
// Verify edit callback is invoked
expect(mockOnEdit).toHaveBeenCalledWith(mockRecord, mockIndex);
});
@@ -88,11 +88,11 @@ describe('ActionsRender', () => {
/>,
);
// 点击删除按钮
// Click the Delete button.
const buttons = screen.getAllByTestId('button');
fireEvent.click(buttons[1]); // 第二个按钮是删除按钮
fireEvent.click(buttons[1]); // The second button is the delete button.
// 验证删除回调被调用
// Verify that the delete callback is invoked
expect(mockOnDelete).toHaveBeenCalledWith(mockIndex);
});
@@ -108,7 +108,7 @@ describe('ActionsRender', () => {
/>,
);
// 验证只有一个按钮(删除按钮)
// Verify that there is only one button (delete button)
const buttons = screen.getAllByTestId('button');
expect(buttons).toHaveLength(1);
});
@@ -125,7 +125,7 @@ describe('ActionsRender', () => {
/>,
);
// 验证只有一个按钮(编辑按钮)
// Verify that there is only one button (edit button)
const buttons = screen.getAllByTestId('button');
expect(buttons).toHaveLength(1);
});

View File

@@ -22,7 +22,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import { EditHeaderRender } from '../../../src/components/renders/edit-header-render';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/bot-semi', () => {
const uiButton = ({ children, onClick, ...props }: any) => (
<button data-testid="button" onClick={onClick} {...props}>
@@ -82,7 +82,7 @@ describe('EditHeaderRender', () => {
<EditHeaderRender value="测试标题" onBlur={mockOnBlur} validator={{}} />,
);
// 验证预览模式显示正确的值
// Verify that the preview mode displays the correct value
const previewElement = screen.getByText('测试标题');
expect(previewElement).toBeInTheDocument();
});
@@ -94,11 +94,11 @@ describe('EditHeaderRender', () => {
<EditHeaderRender value="测试标题" onBlur={mockOnBlur} validator={{}} />,
);
// 点击预览文本
// Click to preview text
const previewElement = screen.getByText('测试标题');
fireEvent.click(previewElement);
// 验证输入框出现
// Verify text box appears
const inputElement = screen.getByTestId('input');
expect(inputElement).toBeInTheDocument();
expect(inputElement).toHaveValue('测试标题');
@@ -108,7 +108,7 @@ describe('EditHeaderRender', () => {
const mockOnBlur = vi.fn();
const mockEditPropsOnBlur = vi.fn();
// 渲染组件
// rendering component
render(
<EditHeaderRender
value="测试标题"
@@ -120,17 +120,17 @@ describe('EditHeaderRender', () => {
/>,
);
// 点击预览文本进入编辑模式
// Click on the preview text to enter edit mode
const previewElement = screen.getByText('测试标题');
fireEvent.click(previewElement);
// 获取输入框
// Get text box
const inputElement = screen.getByTestId('input');
// 触发 blur 事件,让组件内部的 onBlurFn 函数被调用
// The blur event is triggered, causing the onBlurFn function inside the component to be called
fireEvent.blur(inputElement);
// 验证 editProps.onBlur 被调用,并且传递了正确的参数
// Verify that editProps.onBlur is called and the correct parameters are passed
expect(mockEditPropsOnBlur).toHaveBeenCalledWith('测试标题');
});
@@ -149,15 +149,15 @@ describe('EditHeaderRender', () => {
/>,
);
// 点击预览文本进入编辑模式
// Click on the preview text to enter edit mode
const previewElement = screen.getByText('测试标题');
fireEvent.click(previewElement);
// 获取输入框并修改值
// Get the text box and modify the value
const inputElement = screen.getByTestId('input');
fireEvent.change(inputElement, { target: { value: '新标题' } });
// 验证 onChange 回调被调用
// Verify that the onChange callback is invoked
expect(mockOnChange).toHaveBeenCalledWith('新标题');
});
@@ -177,11 +177,11 @@ describe('EditHeaderRender', () => {
/>,
);
// 点击删除按钮
// Click the Delete button.
const deleteButton = screen.getByTestId('button');
fireEvent.click(deleteButton);
// 验证 onDelete 回调被调用
// Verify that the onDelete callback is invoked
expect(mockOnDelete).toHaveBeenCalledWith('测试标题');
});
@@ -201,11 +201,11 @@ describe('EditHeaderRender', () => {
/>,
);
// 验证删除按钮被禁用
// Verify that the delete button is disabled
const deleteButton = screen.getByTestId('button');
expect(deleteButton).toHaveAttribute('disabled');
// 点击删除按钮不应调用回调
// Clicking the delete button should not invoke a callback
fireEvent.click(deleteButton);
expect(mockOnDelete).not.toHaveBeenCalled();
});
@@ -222,7 +222,7 @@ describe('EditHeaderRender', () => {
/>,
);
// 验证删除按钮不存在
// Verify that the delete button does not exist
expect(screen.queryByTestId('button')).not.toBeInTheDocument();
});
@@ -241,12 +241,12 @@ describe('EditHeaderRender', () => {
/>,
);
// 点击预览文本进入编辑模式
// Click on the preview text to enter edit mode
const previewElement = screen.getByText('测试标题');
fireEvent.click(previewElement);
// 由于我们的模拟实现中,错误图标和提示是通过 suffix 属性传递的
// 所以我们需要检查 tooltip error-icon 是否存在于文档中
// Since in our simulation implementation, error icons and hints are passed through the suffix attribute
// So we need to check if tooltip and error-icon exist in the document
expect(screen.getByTestId('error-icon')).toBeInTheDocument();
expect(screen.getByTestId('tooltip')).toHaveAttribute(
'data-content',

View File

@@ -39,7 +39,7 @@ describe('TagRender', () => {
<TagRender value="标签文本" record={mockRecord} index={mockIndex} />,
);
// 验证标签内容被正确渲染
// Verify that the tag content is rendered correctly
const tag = screen.getByTestId('tag');
expect(tag).toBeInTheDocument();
expect(tag).toHaveTextContent('标签文本');
@@ -53,7 +53,7 @@ describe('TagRender', () => {
<TagRender value="标签文本" record={mockRecord} index={mockIndex} />,
);
// 验证标签使用默认颜色
// Verify that the label uses the default color
const tag = screen.getByTestId('tag');
expect(tag).toHaveAttribute('data-color', 'primary');
});
@@ -71,7 +71,7 @@ describe('TagRender', () => {
/>,
);
// 验证标签使用自定义颜色
// Verify labels with custom colors
const tag = screen.getByTestId('tag');
expect(tag).toHaveAttribute('data-color', 'red');
});
@@ -84,7 +84,7 @@ describe('TagRender', () => {
<TagRender value={undefined} record={mockRecord} index={mockIndex} />,
);
// 验证标签内容为空字符串
// Verify tag content is empty string
const tag = screen.getByTestId('tag');
expect(tag).toHaveTextContent('');
});

View File

@@ -22,7 +22,7 @@ import '@testing-library/jest-dom';
import { TextRender } from '../../../src/components/renders/text-render';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/coze-design', () => ({
TextArea: ({
value,
@@ -80,10 +80,10 @@ describe('TextRender', () => {
/>,
);
// 验证文本内容被正确渲染
// Verify that the text content is rendered correctly
expect(screen.getByText('测试文本')).toBeInTheDocument();
// 验证 TextArea 不可见
// Verify that the TextArea is not visible
expect(screen.queryByTestId('text-area')).not.toBeInTheDocument();
});
@@ -99,13 +99,13 @@ describe('TextRender', () => {
/>,
);
// 验证文本内容被正确渲染
// Verify that the text content is rendered correctly
expect(screen.getByText('测试文本')).toBeInTheDocument();
// 点击文本进入编辑模式
// Click on the text to enter edit mode
fireEvent.click(screen.getByText('测试文本'));
// 验证 TextArea 可见
// Verify that the TextArea is visible
expect(screen.getByTestId('text-area')).toBeInTheDocument();
expect(screen.getByTestId('text-area')).toHaveValue('测试文本');
});
@@ -122,20 +122,20 @@ describe('TextRender', () => {
/>,
);
// 点击文本进入编辑模式
// Click on the text to enter edit mode
fireEvent.click(screen.getByText('测试文本'));
// 修改输入值
// Modify input value
fireEvent.change(screen.getByTestId('text-area'), {
target: { value: '新文本' },
});
// 验证 onChange 被调用
// Verify that onChange is invoked
expect(mockOnChange).toHaveBeenCalledWith('新文本', mockRecord, mockIndex);
});
test('应该在失去焦点时调用 onBlur', async () => {
// 使用 dataIndex 属性
// Using the dataIndex property
render(
<TextRender
value="测试文本"
@@ -144,33 +144,33 @@ describe('TextRender', () => {
onBlur={mockOnBlur}
onChange={mockOnChange}
editable={true}
dataIndex="name" // 添加 dataIndex 属性
dataIndex="name" // Add dataIndex property
/>,
);
// 点击文本进入编辑模式
// Click on the text to enter edit mode
fireEvent.click(screen.getByText('测试文本'));
// 修改输入值
// Modify input value
fireEvent.change(screen.getByTestId('text-area'), {
target: { value: '新文本' },
});
// 失去焦点
// Lost focus
fireEvent.blur(screen.getByTestId('text-area'));
// 验证 onBlur 被调用,并且传递了正确的参数
// 根据组件实现onBlur 会被调用,参数是 inputValue, updateRecord, index
// 其中 updateRecord { ...record, [dataIndex]: inputValue } 并且删除了 tableViewKey
// Verify that onBlur is called and the correct parameters are passed
// Depending on the component implementation, onBlur will be called with the parameters inputValue, updateRecord, index
// Where updateRecord is {... record, [dataIndex]: inputValue} and removed tableViewKey
await waitFor(() => {
expect(mockOnBlur).toHaveBeenCalledWith(
'新文本',
{ id: '1', name: '新文本' }, // 更新后的 record
{ id: '1', name: '新文本' }, // Updated records
mockIndex,
);
});
// 验证组件回到只读模式
// Verify that the component returns to read-only mode
await waitFor(() => {
expect(screen.queryByTestId('text-area')).not.toBeInTheDocument();
expect(screen.getByText('新文本')).toBeInTheDocument();
@@ -179,7 +179,7 @@ describe('TextRender', () => {
test('应该在验证失败时显示错误提示', () => {
const mockValidator = {
validate: vi.fn().mockReturnValue(true), // 返回 true 表示验证失败
validate: vi.fn().mockReturnValue(true), // Returning true indicates that the verification failed.
errorMsg: '输入不合法',
};
@@ -192,32 +192,32 @@ describe('TextRender', () => {
onChange={mockOnChange}
editable={true}
validator={mockValidator}
isEditing={true} // 直接进入编辑模式
isEditing={true} // Go straight to edit mode
/>,
);
// 验证 TextArea 可见
// Verify that the TextArea is visible
expect(screen.getByTestId('text-area')).toBeInTheDocument();
// 修改输入值
// Modify input value
fireEvent.change(screen.getByTestId('text-area'), {
target: { value: '新文本' },
});
// 验证验证函数被调用
// The validation function is called
expect(mockValidator.validate).toHaveBeenCalledWith(
'新文本',
mockRecord,
mockIndex,
);
// 验证错误状态
// validation error status
expect(screen.getByTestId('text-area')).toHaveAttribute(
'data-validate-status',
'error',
);
// 验证错误图标和提示被显示
// Validation error icons and prompts are displayed
expect(screen.getByTestId('error-icon')).toBeInTheDocument();
expect(screen.getByTestId('tooltip')).toHaveAttribute(
'data-content',
@@ -238,7 +238,7 @@ describe('TextRender', () => {
/>,
);
// 验证 TextArea 直接可见
// Verify that the TextArea is directly visible
expect(screen.getByTestId('text-area')).toBeInTheDocument();
expect(screen.getByTestId('text-area')).toHaveValue('测试文本');
});
@@ -256,10 +256,10 @@ describe('TextRender', () => {
/>,
);
// 验证 TextArea 直接可见
// Verify that the TextArea is directly visible
expect(screen.getByTestId('text-area')).toBeInTheDocument();
// 重新渲染组件,isEditing undefined
// Render the component again, isEditing is undefined
rerender(
<TextRender
value="测试文本"
@@ -271,7 +271,7 @@ describe('TextRender', () => {
/>,
);
// 验证组件回到只读模式
// Verify that the component returns to read-only mode
await waitFor(() => {
expect(screen.queryByTestId('text-area')).not.toBeInTheDocument();
expect(screen.getByText('测试文本')).toBeInTheDocument();

View File

@@ -26,7 +26,7 @@ import {
EditToolBar,
} from '../../../src/components/table-view/edit-menu';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/i18n', () => ({
I18n: {
t: (key: string, options?: any) => {
@@ -82,7 +82,7 @@ vi.mock('@coze-arch/coze-design/icons', () => ({
IconCozTrashCan: () => <div data-testid="icon-trash"></div>,
}));
// 模拟样式
// simulation style
vi.mock('../../../src/components/table-view/index.module.less', () => ({
default: {
'table-edit-menu': 'table-edit-menu-class',
@@ -207,11 +207,11 @@ describe('EditMenu 组件', () => {
expect.any(Function),
);
// 触发点击事件
// trigger click event
window.dispatchEvent(new Event('click'));
expect(mockOnExit).toHaveBeenCalled();
// 卸载组件
// uninstall components
unmount();
expect(removeEventListenerSpy).toHaveBeenCalledWith(
'click',
@@ -260,7 +260,7 @@ describe('EditToolBar 组件', () => {
expect(screen.getByTestId('button-group')).toBeInTheDocument();
expect(screen.getByText('已选择 2 项')).toBeInTheDocument();
expect(screen.getAllByTestId('button')).toHaveLength(3); // 编辑、删除和关闭按钮
expect(screen.getAllByTestId('button')).toHaveLength(3); // Edit, delete, and close buttons
});
test('点击编辑按钮应调用onEdit回调', () => {
@@ -352,7 +352,7 @@ describe('EditToolBar 组件', () => {
const toolbar = screen.getByTestId('button-group').parentElement;
expect(toolbar).toHaveStyle('margin-left: -145px');
// 重新渲染,只选择一个项目
// Re-render, select only one item
rerender(
<EditToolBar
configs={[]}

View File

@@ -22,7 +22,7 @@ import '@testing-library/jest-dom';
import { TableView } from '../../../src/components/table-view';
// 模拟依赖
// simulated dependency
vi.mock('ahooks', () => ({
useDebounceFn: fn => ({
run: fn,
@@ -125,7 +125,7 @@ vi.mock('../../../src/components/table-view/edit-menu', () => ({
) : null,
}));
// 模拟样式
// simulation style
vi.mock('../../../src/components/table-view/index.module.less', () => ({
default: {
'data-table-view': 'data-table-view-class',
@@ -196,7 +196,7 @@ describe('TableView 组件', () => {
test('当启用虚拟滚动时应渲染AutoSizer', () => {
render(<TableView {...defaultProps} isVirtualized={true} />);
// 由于我们模拟了AutoSizer我们可以检查UITable是否接收了正确的props
// Since we simulate AutoSizer, we can check if UITable receives the correct props.
const uiTable = screen.getByTestId('ui-table');
expect(uiTable).toBeInTheDocument();
});
@@ -204,23 +204,23 @@ describe('TableView 组件', () => {
test('当启用行选择时应传递rowSelection属性', () => {
render(<TableView {...defaultProps} rowSelect={true} />);
// 由于我们模拟了UITable我们无法直接检查rowSelection属性
// 但我们可以检查表格是否正确渲染
// Since we simulate UITable, we cannot directly check the rowSelection property
// But we can check if the table is rendered correctly.
expect(screen.getByTestId('ui-table')).toBeInTheDocument();
});
test('当启用列伸缩时应传递resizable属性', () => {
render(<TableView {...defaultProps} resizable={true} />);
// 由于我们模拟了UITable我们无法直接检查resizable属性
// 但我们可以检查表格是否正确渲染
// Since we simulate UITable, we cannot directly check the resizable property
// But we can check if the table is rendered correctly.
expect(screen.getByTestId('ui-table')).toBeInTheDocument();
});
test('当滚动到底部时应调用scrollToBottom回调', () => {
render(<TableView {...defaultProps} isVirtualized={true} />);
// 模拟滚动事件
// simulated rolling event
act(() => {
const onScrollProp = vi.fn();
onScrollProp({
@@ -231,25 +231,25 @@ describe('TableView 组件', () => {
});
});
// 由于我们模拟了useDebounceFnscrollToBottom会被立即调用
// 但由于我们无法直接触发onScroll回调这个测试实际上并不能验证scrollToBottom是否被调用
// 这里只是为了测试代码覆盖率
// Since we emulated useDebounceFn, scrollToBottom will be called immediately
// But since we can't directly trigger the onScroll callback, this test doesn't actually verify that scrollToBottom was called
// This is just to test code coverage
});
test('应该正确处理右键菜单', () => {
render(<TableView {...defaultProps} rowOperation={true} />);
// 模拟右键点击
// Simulated right click
const firstRow = screen.getByTestId('row-0');
const firstCell = firstRow.querySelector('td');
if (firstCell) {
// 模拟右键点击
// Simulated right click
fireEvent.contextMenu(firstCell);
// 检查菜单是否显示
// 注意由于我们无法直接触发onCell.onMouseDown这个测试实际上并不能验证菜单是否显示
// 这里只是为了测试代码覆盖率
// Check if the menu is displayed
// Note: Since we cannot directly trigger onCell.onMouseDown, this test does not actually verify that the menu is displayed
// This is just to test code coverage
}
});
@@ -258,14 +258,14 @@ describe('TableView 组件', () => {
<TableView {...defaultProps} rowSelect={true} />,
);
// 初始状态下工具栏不应显示
// The toolbar should not be displayed in the initial state
expect(screen.queryByTestId('edit-toolbar')).not.toBeInTheDocument();
// 模拟选择行
// 注意由于我们无法直接设置selected状态这个测试实际上并不能验证工具栏是否显示
// 这里只是为了测试代码覆盖率
// Simulate select row
// Note: Since we can't set the selected state directly, this test doesn't actually verify that the toolbar is displayed
// This is just to test code coverage
// 重新渲染组件
// Rerender component
rerender(<TableView {...defaultProps} rowSelect={true} />);
});
@@ -273,11 +273,11 @@ describe('TableView 组件', () => {
const ref = React.createRef();
render(<TableView {...defaultProps} ref={ref} />);
// 检查ref是否包含正确的方法
// Check if the ref contains the correct method
expect(ref.current).toHaveProperty('resetSelected');
expect(ref.current).toHaveProperty('getTableHeight');
// 调用ref方法
// Call the ref method
act(() => {
ref.current.resetSelected();
});
@@ -287,8 +287,8 @@ describe('TableView 组件', () => {
height = ref.current.getTableHeight();
});
// 验证getTableHeight返回正确的高度
// 行高56 * 3行 + 表头高41 = 209
// Verify that getTableHeight returns the correct height
// Line height 56 * 3 lines + header height 41 = 209
expect(height).toBe(209);
});
});

View File

@@ -19,7 +19,7 @@ import { CustomError } from '@coze-arch/bot-error';
import { colWidthCacheService } from '../../../src/components/table-view/service';
// 模拟 localStorage
// simulated localStorage
const localStorageMock = {
getItem: vi.fn(),
setItem: vi.fn(),
@@ -27,12 +27,12 @@ const localStorageMock = {
clear: vi.fn(),
};
// 模拟 window.localStorage
// Emulate window.localStorage
Object.defineProperty(window, 'localStorage', {
value: localStorageMock,
});
// 模拟 CustomError
// Simulate CustomError
vi.mock('@coze-arch/bot-error', () => {
const mockCustomError = vi.fn().mockImplementation((event, message) => {
const error = new Error(message);
@@ -59,22 +59,22 @@ describe('ColWidthCacheService', () => {
describe('initWidthMap', () => {
test('当 localStorage 中不存在缓存时应该初始化一个空 Map', () => {
// 模拟 localStorage.getItem 返回 null
// Simulate localStorage.getItem returns null
localStorageMock.getItem.mockReturnValueOnce(null);
colWidthCacheService.initWidthMap();
// 验证 localStorage.setItem 被调用,并且参数是一个空 Map 的字符串表示
// Verify that localStorage.setItem is called and that the argument is a string representation of an empty Map
expect(localStorageMock.setItem).toHaveBeenCalledWith(mapName, '[]');
});
test('当 localStorage 中已存在缓存时不应该重新初始化', () => {
// 模拟 localStorage.getItem 返回一个已存在的缓存
// Simulate localStorage.getItem to return an existing cache
localStorageMock.getItem.mockReturnValueOnce('[["table1",{"col1":100}]]');
colWidthCacheService.initWidthMap();
// 验证 localStorage.setItem 没有被调用
// Verify that localStorage.setItem is not called
expect(localStorageMock.setItem).not.toHaveBeenCalled();
});
});
@@ -83,18 +83,18 @@ describe('ColWidthCacheService', () => {
test('当 tableKey 为空时不应该设置缓存', () => {
colWidthCacheService.setWidthMap({ col1: 100 }, undefined);
// 验证 localStorage.getItem localStorage.setItem 都没有被调用
// Verify that neither localStorage.getItem nor localStorage.setItem is called
expect(localStorageMock.getItem).not.toHaveBeenCalled();
expect(localStorageMock.setItem).not.toHaveBeenCalled();
});
test('当缓存中已存在相同 tableKey 时应该更新缓存', () => {
// 模拟 localStorage.getItem 返回一个已存在的缓存
// Simulate localStorage.getItem to return an existing cache
localStorageMock.getItem.mockReturnValueOnce('[["table1",{"col1":100}]]');
colWidthCacheService.setWidthMap({ col1: 200 }, 'table1');
// 验证 localStorage.setItem 被调用,并且参数是更新后的缓存
// Verify that localStorage.setItem is called and that the parameter is the updated cache
expect(localStorageMock.setItem).toHaveBeenCalledWith(
mapName,
'[["table1",{"col1":200}]]',
@@ -102,12 +102,12 @@ describe('ColWidthCacheService', () => {
});
test('当缓存中不存在相同 tableKey 且缓存未满时应该添加新缓存', () => {
// 模拟 localStorage.getItem 返回一个已存在的缓存
// Simulate localStorage.getItem to return an existing cache
localStorageMock.getItem.mockReturnValueOnce('[["table1",{"col1":100}]]');
colWidthCacheService.setWidthMap({ col1: 200 }, 'table2');
// 验证 localStorage.setItem 被调用,并且参数是添加新缓存后的结果
// Verify that localStorage.setItem is called and that the argument is the result of adding a new cache
expect(localStorageMock.setItem).toHaveBeenCalledWith(
mapName,
'[["table1",{"col1":100}],["table2",{"col1":200}]]',
@@ -115,37 +115,37 @@ describe('ColWidthCacheService', () => {
});
test('当缓存中不存在相同 tableKey 且缓存已满时应该移除最旧的缓存并添加新缓存', () => {
// 创建一个已满的缓存(容量为 20
// Create a full cache (capacity 20)
const fullCache = new Map();
for (let i = 0; i < colWidthCacheService.capacity; i++) {
fullCache.set(`table${i}`, { col1: 100 });
}
// 模拟 localStorage.getItem 返回已满的缓存
// Simulate localStorage.getItem returns a full cache
localStorageMock.getItem.mockReturnValueOnce(
JSON.stringify(Array.from(fullCache)),
);
colWidthCacheService.setWidthMap({ col1: 200 }, 'tableNew');
// 验证 localStorage.setItem 被调用
// Verify that localStorage.setItem is called
expect(localStorageMock.setItem).toHaveBeenCalled();
// 解析设置的新缓存
// New cache for parsing settings
const setItemCall = localStorageMock.setItem.mock.calls[0];
const newCacheStr = setItemCall[1];
const newCache = JSON.parse(newCacheStr);
// 验证新缓存的大小仍然是容量限制
// Verify that the size of the new cache is still the capacity limit
expect(newCache.length).toBe(colWidthCacheService.capacity);
// 验证最旧的缓存table0被移除
// Verify that the oldest cache (table0) is removed
const hasOldestCache = newCache.some(
([key]: [string, any]) => key === 'table0',
);
expect(hasOldestCache).toBe(false);
// 验证新缓存被添加
// Verify that the new cache is added
const hasNewCache = newCache.some(
([key]: [string, any]) => key === 'tableNew',
);
@@ -153,12 +153,12 @@ describe('ColWidthCacheService', () => {
});
test('当 localStorage 操作抛出异常时应该抛出 CustomError', () => {
// 模拟 localStorage.getItem 抛出异常
// Simulate localStorage.getItem throwing an exception
localStorageMock.getItem.mockImplementationOnce(() => {
throw new Error('localStorage error');
});
// 验证调用 setWidthMap 会抛出 CustomError
// Verify that calling setWidthMap throws a CustomError
expect(() =>
colWidthCacheService.setWidthMap({ col1: 100 }, 'table1'),
).toThrow(CustomError);
@@ -167,27 +167,27 @@ describe('ColWidthCacheService', () => {
describe('getTableWidthMap', () => {
test('当缓存中存在 tableKey 时应该返回对应的缓存并更新其位置', () => {
// 模拟 localStorage.getItem 返回一个已存在的缓存
// Simulate localStorage.getItem to return an existing cache
localStorageMock.getItem.mockReturnValueOnce(
'[["table1",{"col1":100}],["table2",{"col1":200}]]',
);
const result = colWidthCacheService.getTableWidthMap('table1');
// 验证返回正确的缓存
// Verify that the correct cache is returned
expect(result).toEqual({ col1: 100 });
// 注意:实际实现中并没有调用 localStorage.setItem所以移除这个期望
// 只验证返回的缓存数据是否正确
// Note: The actual implementation does not call localStorage.setItem, so remove this expectation
// Only verify that the cached data returned is correct
});
test('当 localStorage 操作抛出异常时应该抛出 CustomError', () => {
// 模拟 localStorage.getItem 抛出异常
// Simulate localStorage.getItem throwing an exception
localStorageMock.getItem.mockImplementationOnce(() => {
throw new Error('localStorage error');
});
// 验证调用 getTableWidthMap 会抛出 CustomError
// Verify that calling getTableWidthMap throws a CustomError
expect(() => colWidthCacheService.getTableWidthMap('table1')).toThrow(
CustomError,
);

View File

@@ -127,34 +127,34 @@ describe('utils', () => {
onDelete,
});
// 验证返回的配置对象包含正确的菜单项
// Verify that the returned configuration object contains the correct menu items
expect(result).toHaveProperty(EditMenuItem.EDIT);
expect(result).toHaveProperty(EditMenuItem.DELETE);
expect(result).toHaveProperty(EditMenuItem.DELETEALL);
// 验证编辑菜单项
// Verify edit menu item
expect(result[EditMenuItem.EDIT].text).toBe('knowledge_tableview_01');
expect(result[EditMenuItem.EDIT].icon).toBeDefined();
// 验证删除菜单项
// Verify deletion of menu items
expect(result[EditMenuItem.DELETE].text).toBe('knowledge_tableview_02');
expect(result[EditMenuItem.DELETE].icon).toBeDefined();
// 验证批量删除菜单项
// Verify bulk deletion of menu items
expect(result[EditMenuItem.DELETEALL].text).toBe(
'knowledge_tableview_02',
);
expect(result[EditMenuItem.DELETEALL].icon).toBeDefined();
// 测试点击编辑菜单项
// Test click edit menu item
result[EditMenuItem.EDIT].onClick();
expect(onEdit).toHaveBeenCalledWith(record, indexs[0]);
// 测试点击删除菜单项
// Test Click Delete Menu Item
result[EditMenuItem.DELETE].onClick();
expect(onDelete).toHaveBeenCalledWith(indexs);
// 测试点击批量删除菜单项
// Test click to delete menu items in bulk
result[EditMenuItem.DELETEALL].onClick();
expect(onDelete).toHaveBeenCalledWith(indexs);
});
@@ -167,18 +167,18 @@ describe('utils', () => {
selected: { record, indexs },
});
// 验证返回的配置对象包含正确的菜单项
// Verify that the returned configuration object contains the correct menu items
expect(result).toHaveProperty(EditMenuItem.EDIT);
expect(result).toHaveProperty(EditMenuItem.DELETE);
expect(result).toHaveProperty(EditMenuItem.DELETEALL);
// 测试点击编辑菜单项不应该抛出错误
// Tests that clicking on the edit menu item should not throw an error
expect(() => result[EditMenuItem.EDIT].onClick()).not.toThrow();
// 测试点击删除菜单项不应该抛出错误
// Test that clicking on the delete menu item should not throw an error
expect(() => result[EditMenuItem.DELETE].onClick()).not.toThrow();
// 测试点击批量删除菜单项不应该抛出错误
// Test clicking to delete menu items in bulk should not throw an error
expect(() => result[EditMenuItem.DELETEALL].onClick()).not.toThrow();
});
});

View File

@@ -26,12 +26,12 @@ export interface ActionsRenderProps {
index: number;
editProps?: {
disabled: boolean;
// 编辑回调
// edit callback
onEdit?: (record: TableViewRecord, index: number) => void;
};
deleteProps?: {
disabled: boolean;
// 删除回调
// Delete callback
onDelete?: (index: number) => void;
};
className?: string;

View File

@@ -25,20 +25,20 @@ import styles from './index.module.less';
export interface EditHeaderRenderProps {
value: string;
deleteProps?: {
// 禁用删除
// disable deletion
disabled: boolean;
// 删除回调
// Delete callback
onDelete?: (v: string) => void;
};
editProps?: {
// 编辑回调
// edit callback
onChange?: (v: string) => void;
// 失焦回调
// out of focus callback
onBlur?: (v: string) => void;
};
// 失焦回调
// out of focus callback
onBlur: (v: string) => void;
// 表头校验逻辑
// header check logic
validator: ValidatorProps;
editable?: boolean;
}
@@ -75,7 +75,7 @@ export const EditHeaderRender = ({
const isError = useMemo(() => validate && validate(value), [inputValue]);
return (
<div className={styles['edit-header-render']}>
{/* 编辑态组件 */}
{/* edit state component */}
{isEditCom && (
<UIInput
autoFocus
@@ -100,7 +100,7 @@ export const EditHeaderRender = ({
/>
)}
{/* 预览态组件 */}
{/* preview component */}
{!isEditCom && (
<div
className={styles['header-preview']}
@@ -110,7 +110,7 @@ export const EditHeaderRender = ({
</div>
)}
{/* 列删除按钮 */}
{/* column delete button */}
{editable && (
<UIButton
disabled={deleteDisabled}

View File

@@ -23,7 +23,7 @@ import styles from '../index.module.less';
import { useImagePreview } from './use-image-preview';
export interface ImageRenderProps {
srcList: string[];
// 图片是否可编辑,默认为false
// Whether the picture can be edited, the default is false
editable?: boolean;
onChange?: (tosKey: string, src: string) => void;
dataIndex?: string;
@@ -60,7 +60,7 @@ const ImageContainer = ({
}}
preview={false}
src={src}
// 失败时兜底图
// bottom line on failure
fallback={
<IconImageFailOutlined
className={styles['image-failed']}
@@ -70,7 +70,7 @@ const ImageContainer = ({
}}
/>
}
// 图片加载时的占位图,主要用于大图加载
// The placeholder map when the picture is loaded, mainly used for large image loading
placeholder={<div className="image-skeleton" onClick={onClick} />}
/>
))}

View File

@@ -74,7 +74,7 @@ export const useImagePreview = ({
return;
}
try {
// 业务
// business
const { name, fileInstance, url } = file;
setUploading(true);
if (fileInstance) {

View File

@@ -70,7 +70,7 @@ export const TextRender = ({
try {
await onBlur(inputValue, updateRecord, index);
} catch (e) {
// 更新失败,恢复原值
// Update failed, restore original value
console.log('update table content error', e);
setInputValue(String(value));
}
@@ -86,7 +86,7 @@ export const TextRender = ({
}
setInputValue(v);
};
// 校验状态
// check state
const isError = useMemo(
() => !!validate?.(String(inputValue), record, index),
[inputValue, validate],
@@ -113,7 +113,7 @@ export const TextRender = ({
className={`${styles['cell-text-render']} text-render-wrapper`}
data-testid={CommonE2e.CommonTableViewTextRender}
>
{/* 编辑态组件 */}
{/* edit state component */}
{isEditCom ? (
<span
className={`${styles['cell-text-edit']} ${
@@ -141,7 +141,7 @@ export const TextRender = ({
</span>
) : null}
{/* 预览态组件 */}
{/* preview component */}
{!isEditCom && (
<div
className={`${styles['cell-text-preview']} text-content`}

View File

@@ -42,7 +42,7 @@ export interface EditMenuProps {
};
onExit?: () => void | Promise<void>;
onDelete?: (indexs: (string | number)[]) => void | Promise<void>;
// 行操作编辑行的回调
// Line operations edit line callbacks
onEdit?: (
record: TableViewRecord,
index: string | number,

View File

@@ -9,9 +9,9 @@
.table-wrapper {
:global {
/** 公共样式 **/
/** Common Style **/
/** 重置table背景色 */
/** Reset table background color */
.semi-table-tbody>.semi-table-row,
.semi-table-thead>.semi-table-row>.semi-table-row-head,
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-left,
@@ -37,7 +37,7 @@
}
/** table header样式 **/
/** Table header style **/
.semi-table-thead {
// 拖拽列宽度的图标样式
&:hover {
@@ -85,13 +85,13 @@
}
}
/** table body部分样式 **/
/** Table body part style **/
.semi-table-tbody {
.semi-table-row {
>.semi-table-row-cell {
/**
* table 开启虚拟滚动后 单元格会加上 overflow: hidden
* 未开启虚拟滚动情况下正常展示溢出内容
* After table turns on virtual scrolling, the cell will be added with overflow: hidden.
* Display overflow content normally without virtual scrolling enabled
*/
overflow: visible;
border-top: 1px solid var(--coz-stroke-primary);

View File

@@ -52,40 +52,40 @@ import { EditMenu, EditToolBar } from './edit-menu';
import styles from './index.module.less';
export interface TableViewProps {
// 唯一标识表,且会作为列宽缓存map中的key值
// Uniquely identifies the table and is used as the key value in the column width cache map
tableKey?: string;
// 类名,用于样式覆盖
// Class name for style overrides
className?: string;
// 编辑配置
// Edit Configuration
editProps?: {
// 数据删除的回调,支持批量
// Callback for data deletion, batch support
onDelete?: (indexs: (string | number)[]) => void;
// 行操作编辑行的回调
// Line operations edit line callbacks
onEdit?: (record: TableViewRecord, index: string | number) => void;
};
// 滚动到底部的回调
// Scroll to the bottom of the callback
scrollToBottom?: () => void | Promise<void>;
// 拖拽钩子
// Drag hook
onResize?: (col: TableViewColumns) => void;
// 是否开启虚拟滚动,默认为false
// Whether to enable virtual scrolling, the default is false
isVirtualized?: boolean;
// 是否开启伸缩列,默认为false
// Whether to enable scaled columns, the default is false
resizable?: boolean;
// 是否开启行选择,默认为false
// Whether to enable line selection, the default is false
rowSelect?: boolean;
// 是否支持行操作,默认为false
// Whether line operations are supported, the default is false
rowOperation?: boolean;
// 数据
// data
dataSource: TableViewRecord[];
// 表头项
// header item
columns: TableViewColumns[];
// 数据为空的兜底展示
// The data is empty.
empty?: ReactNode;
// loading
loading?: boolean;
// 不消费仅用于触发渲染的state需优化
// No consumption, only used to trigger the rendered state, which needs to be optimized
resizeTriState?: number;
// 额外 tableProps
// Additional tableProps
tableProps?: TableProps;
}
export interface TableViewMethods {
@@ -204,7 +204,7 @@ export const TableView = forwardRef<TableViewMethods, TableViewProps>(
if (e.button === MOUSE_RIGHT_BTN && rowOperation) {
e.preventDefault();
const { offsetWidth, offsetHeight } = document.body;
// 如果右键位置非选中项,取消选中
// If the right-click position is not selected, uncheck it
if (
rowIndex &&
selected?.length &&
@@ -212,7 +212,7 @@ export const TableView = forwardRef<TableViewMethods, TableViewProps>(
) {
setSelected([]);
}
// 右键展示菜单
// right-click to display the menu
setFocusRow(rowIndex);
setMenuVisible(true);
setMenuStyle({
@@ -283,8 +283,8 @@ export const TableView = forwardRef<TableViewMethods, TableViewProps>(
scrollDirection === 'forward' &&
scrollOffset &&
/**
* 这一行一点余量都没留 可能在不同浏览器渲染下会有 bad case 导致无法满足条件
* 如果有遇到类似反馈可以优先排查这里
* This line has no margin at all, and there may be bad cases in different browsers that cannot meet the conditions.
* If you encounter similar feedback, you can give priority to checking here.
*/
scrollOffset + height - HEADER_SIZE >= tableData.length * ITEM_SIZE &&
!scrollUpdateWasRequested &&
@@ -330,7 +330,7 @@ export const TableView = forwardRef<TableViewMethods, TableViewProps>(
onResize: col =>
onResize ? onResize(col) : resizeFn(col),
onResizeStop: col => {
// resize完后缓存列宽
// Cache column width after resizing
const resizedCols = newColumns.map(oCol => {
if (oCol.dataIndex === col.dataIndex) {
return col;

View File

@@ -18,7 +18,7 @@ import { REPORT_EVENTS } from '@coze-arch/report-events';
import { CustomError } from '@coze-arch/bot-error';
/**
* 缓存列宽的方法类
* Method class with cache column width
*/
class ColWidthCacheService {
@@ -46,18 +46,18 @@ class ColWidthCacheService {
}
/**
* 初始化伸缩列缓存
* Initializing the scaled column cache
*/
initWidthMap() {
const widthMap = window.localStorage.getItem(this.mapName);
if (!widthMap) {
// 利用Map可记录键值对顺序的特性完成一个简易的LRU
// Completing a simple LRU using the characteristic that Map can record the order of key-value pairs
window.localStorage.setItem(this.mapName, this.mapToString(new Map()));
}
}
/**
* 设置列宽缓存,若超过缓存个数删除map中最近未使用的值
* Set the column width cache, if it exceeds the number of caches, delete the most recently unused value in the map
*/
setWidthMap(widthMap: Record<string, number>, tableKey?: string) {
if (!tableKey) {
@@ -68,11 +68,11 @@ class ColWidthCacheService {
window.localStorage.getItem(this.mapName) || '',
);
if (cacheWidthMap.has(tableKey)) {
// 存在即更新(删除后加入)
// Exist and update (join after deletion)
cacheWidthMap.delete(tableKey);
} else if (cacheWidthMap.size >= this.capacity) {
// 不存在即加入
// 缓存超过最大值,则移除最近没有使用的
// Join if you don't exist
// If the cache exceeds the maximum value, remove the recently unused
cacheWidthMap.delete(cacheWidthMap.keys().next().value);
}
cacheWidthMap.set(tableKey, widthMap);
@@ -89,7 +89,7 @@ class ColWidthCacheService {
}
/**
* 以表维度查询列宽缓存信息
* Query column width cache information in table dimension
* @param tableKey
*/
getTableWidthMap(tableKey: string) {
@@ -97,7 +97,7 @@ class ColWidthCacheService {
const cacheWidthMap = this.stringToMap(
window.localStorage.getItem(this.mapName) || '',
);
// 存在即更新
// exist and update
const temp = cacheWidthMap.get(tableKey);
cacheWidthMap.delete(tableKey);
cacheWidthMap.set(tableKey, temp);

View File

@@ -39,7 +39,7 @@ export interface GetRowOpConfig {
}
/**
* 表格列伸缩时的回调,用于限制伸缩边界
* Callbacks when table columns are scaled to limit the scaling boundaries
* @param column
* @returns
*/
@@ -64,7 +64,7 @@ export const getRowKey: RowKey<TableViewRecord> = (record?: TableViewRecord) =>
record?.tableViewKey || '';
/**
* 获取行操作配置
* Get row operation configuration
* @param record
* @param indexs
* @param onEdit