From 5b26287cffc112de19afe954400180de258f9540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Sat, 30 May 2026 20:29:12 +0800 Subject: [PATCH] =?UTF-8?q?refactor(qrcode):=20=E4=BC=98=E5=8C=96=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E9=80=BB=E8=BE=91=EF=BC=8C=E8=BE=93=E5=85=A5=E6=80=81?= =?UTF-8?q?=E9=9A=90=E8=97=8F=E9=A2=84=E8=A7=88=E5=8C=BA=E5=9F=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 输入态:只显示输入框和生成按钮,隐藏二维码预览 - 预览态:上方显示文本预览(超长文本截断),下方显示二维码 - 点击编辑返回输入态,隐藏二维码预览 - 更新测试用例适配新布局 --- src/pages/QrCode/__tests__/index.test.tsx | 55 ++++---- src/pages/QrCode/components/GeneratePanel.tsx | 124 +++++++++--------- 2 files changed, 97 insertions(+), 82 deletions(-) diff --git a/src/pages/QrCode/__tests__/index.test.tsx b/src/pages/QrCode/__tests__/index.test.tsx index 1f52b3c..75eac20 100644 --- a/src/pages/QrCode/__tests__/index.test.tsx +++ b/src/pages/QrCode/__tests__/index.test.tsx @@ -27,12 +27,7 @@ vi.mock('@/config/features', async (importOriginal) => { }); vi.mock('@/components/QrCodePreview', () => ({ - default: ({ placeholderText }: { placeholderText?: string }) => ( -
- QrCodePreview - {placeholderText && {placeholderText}} -
- ), + default: () =>
QrCodePreview
, })); vi.mock('@/components/ImageUploader', () => ({ @@ -60,7 +55,8 @@ describe('QrCodePage', () => { render(); expect(screen.getByText('输入 URL 或文本')).toBeInTheDocument(); expect(screen.getByText('生成二维码')).toBeInTheDocument(); - expect(screen.getByTestId('qr-code-preview')).toBeInTheDocument(); + // 输入态应该隐藏二维码预览 + expect(screen.queryByTestId('qr-code-preview')).not.toBeInTheDocument(); }); it('应该渲染模式切换按钮', () => { @@ -73,17 +69,16 @@ describe('QrCodePage', () => { render(); fireEvent.click(screen.getByText('二维码转文本')); expect(screen.getByTestId('image-uploader')).toBeInTheDocument(); - expect(screen.queryByTestId('qr-code-preview')).not.toBeInTheDocument(); }); - it('切换回生成模式应该渲染 QrCodePreview', () => { + it('切换回生成模式应该渲染输入态', () => { render(); // 先切换到解析模式 fireEvent.click(screen.getByText('二维码转文本')); - expect(screen.getByTestId('image-uploader')).toBeInTheDocument(); // 再切换回生成模式 fireEvent.click(screen.getByText('文本转二维码')); - expect(screen.getByTestId('qr-code-preview')).toBeInTheDocument(); + expect(screen.getByText('输入 URL 或文本')).toBeInTheDocument(); + expect(screen.getByText('生成二维码')).toBeInTheDocument(); }); it('应该渲染输入区域的系统标签', () => { @@ -91,12 +86,6 @@ describe('QrCodePage', () => { expect(screen.getByText('输入 URL 或文本')).toBeInTheDocument(); }); - it('应该渲染双翼响应式卡片网格布局', () => { - const { container } = render(); - const gridContainer = container.querySelector('.grid'); - expect(gridContainer).toBeInTheDocument(); - }); - it('输入态应该显示生成按钮', () => { render(); const generateButton = screen.getByText('生成二维码'); @@ -128,20 +117,40 @@ describe('QrCodePage', () => { expect(screen.getByText('原始文本')).toBeInTheDocument(); expect(screen.getByText('编辑')).toBeInTheDocument(); expect(screen.queryByText('生成二维码')).not.toBeInTheDocument(); + // 预览态应该显示二维码 + expect(screen.getByTestId('qr-code-preview')).toBeInTheDocument(); }); - it('预览态应该显示保存的文本', () => { + it('预览态应该显示截断的文本', () => { render(); - // 输入文本 + // 输入长文本 + const longText = + 'https://example.com/very/long/path/that/should/be/truncated/in/the/preview/because/it/exceeds/the/maximum/length'; const textarea = screen.getByPlaceholderText('请输入 URL 或文本内容,将自动生成二维码'); - fireEvent.change(textarea, { target: { value: 'https://example.com' } }); + fireEvent.change(textarea, { target: { value: longText } }); // 点击生成按钮 fireEvent.click(screen.getByText('生成二维码')); - // 验证显示保存的文本 - expect(screen.getByText('https://example.com')).toBeInTheDocument(); + // 验证显示截断的文本(100字符 + "...") + const truncatedText = longText.slice(0, 100) + '...'; + expect(screen.getByText(truncatedText)).toBeInTheDocument(); + }); + + it('预览态应该显示完整的短文本', () => { + render(); + + // 输入短文本 + const shortText = 'https://example.com'; + const textarea = screen.getByPlaceholderText('请输入 URL 或文本内容,将自动生成二维码'); + fireEvent.change(textarea, { target: { value: shortText } }); + + // 点击生成按钮 + fireEvent.click(screen.getByText('生成二维码')); + + // 验证显示完整文本 + expect(screen.getByText(shortText)).toBeInTheDocument(); }); it('点击编辑按钮应该返回输入态', () => { @@ -159,6 +168,8 @@ describe('QrCodePage', () => { expect(screen.getByText('输入 URL 或文本')).toBeInTheDocument(); expect(screen.getByText('生成二维码')).toBeInTheDocument(); expect(screen.queryByText('编辑')).not.toBeInTheDocument(); + // 输入态应该隐藏二维码预览 + expect(screen.queryByTestId('qr-code-preview')).not.toBeInTheDocument(); }); it('返回编辑态应该保留上次输入的内容', () => { diff --git a/src/pages/QrCode/components/GeneratePanel.tsx b/src/pages/QrCode/components/GeneratePanel.tsx index 76bfdca..a21b692 100644 --- a/src/pages/QrCode/components/GeneratePanel.tsx +++ b/src/pages/QrCode/components/GeneratePanel.tsx @@ -7,6 +7,9 @@ import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { cn } from '@/lib/utils'; +/** 文本预览的最大显示字符数 */ +const TEXT_PREVIEW_MAX_LENGTH = 100; + export default function GeneratePanel() { const { t } = useI18n('qrCode'); const { @@ -21,60 +24,40 @@ export default function GeneratePanel() { const isInputStep = generatorState.step === 'input'; const hasText = generatorState.textToEncode.trim().length > 0; - return ( -
- {/* 左侧:输入态显示输入框,预览态显示文本预览 */} -
-
-
+ /** 截断文本用于预览显示 */ + const getTruncatedText = (text: string) => { + if (text.length <= TEXT_PREVIEW_MAX_LENGTH) return text; + return text.slice(0, TEXT_PREVIEW_MAX_LENGTH) + '...'; + }; + + // 输入态:只显示输入框和生成按钮 + if (isInputStep) { + return ( +
+
+
- {/* 预览态显示编辑按钮 */} - {!isInputStep && ( - - )} -
+ setTextToEncode('')} + /> -
- {isInputStep ? ( - /* 输入态:可编辑的输入框 */ - setTextToEncode('')} - /> - ) : ( - /* 预览态:只读文本预览 */ -
-

- {generatorState.savedText} -

-
- )} -
- - {/* 输入态显示生成按钮 */} - {isInputStep && ( - )} +
+
+
+ ); + } + + // 预览态:显示文本预览 + 二维码 + return ( +
+ {/* 文本预览区域 */} +
+
+ + +
+
+ {getTruncatedText(generatorState.savedText)}
- {/* 右侧:二维码预览区域 */} -
- -
+ {/* 二维码预览区域 */} +
); }