refactor: 使用 Label 组件替换原生 label 元素,并在 DecodeResultPaper 中引入 Input 组件

This commit is contained in:
雨霖铃
2026-06-10 08:15:09 +08:00
parent 355a94d116
commit 1f9288f780
5 changed files with 32 additions and 29 deletions
+2 -6
View File
@@ -9,6 +9,7 @@
*/ */
import { Download } from 'lucide-react'; import { Download } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { formatBytes } from '@/utils/format'; import { formatBytes } from '@/utils/format';
import { useI18n } from '@/utils/chromeI18n'; import { useI18n } from '@/utils/chromeI18n';
@@ -63,12 +64,7 @@ export default function DecodeResultPaper({
<label className="block text-xs font-medium text-muted-foreground mb-1"> <label className="block text-xs font-medium text-muted-foreground mb-1">
{t('decodedFileName')} {t('decodedFileName')}
</label> </label>
<input <Input value={fileName} onChange={(e) => onFileNameChange(e.target.value)} />
type="text"
value={fileName}
onChange={(e) => onFileNameChange(e.target.value)}
className="w-full px-3 py-2 text-sm border border-border rounded-lg focus:outline-none focus:ring-2 focus:ring-primary"
/>
</div> </div>
{/* 下载按钮 */} {/* 下载按钮 */}
+9 -5
View File
@@ -1,6 +1,8 @@
import { useCallback, useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import { Image, X } from 'lucide-react'; import { Image, X } from 'lucide-react';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { useI18n } from '@/utils/chromeI18n'; import { useI18n } from '@/utils/chromeI18n';
interface ImageUploaderProps { interface ImageUploaderProps {
@@ -125,7 +127,7 @@ const ImageUploader = ({
className="hidden" className="hidden"
id="qr-code-upload" id="qr-code-upload"
/> />
<label htmlFor="qr-code-upload" className="cursor-pointer text-center w-full"> <Label htmlFor="qr-code-upload" className="cursor-pointer text-center w-full">
{selectedFile ? ( {selectedFile ? (
<div className="text-center w-full relative"> <div className="text-center w-full relative">
<div className="relative inline-block"> <div className="relative inline-block">
@@ -134,17 +136,19 @@ const ImageUploader = ({
alt="QR Code Preview" alt="QR Code Preview"
className="max-w-full max-h-40 rounded-lg object-contain" className="max-w-full max-h-40 rounded-lg object-contain"
/> />
<button <Button
type="button" type="button"
variant="destructive"
size="icon"
data-testid="ClearIcon" data-testid="ClearIcon"
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleClearFile(); handleClearFile();
}} }}
className="absolute -top-2 -right-2 w-6 h-6 bg-red-500 text-white rounded-full flex items-center justify-center hover:bg-red-600 transition-colors" className="absolute -top-2 -right-2 h-6 w-6 rounded-full"
> >
<X className="w-3 h-3" /> <X className="w-3 h-3" />
</button> </Button>
</div> </div>
<span className="block text-sm text-muted-foreground mt-2">{selectedFile.name}</span> <span className="block text-sm text-muted-foreground mt-2">{selectedFile.name}</span>
<span className="block text-xs text-muted-foreground">{t('qrCode:clickToChange')}</span> <span className="block text-xs text-muted-foreground">{t('qrCode:clickToChange')}</span>
@@ -163,7 +167,7 @@ const ImageUploader = ({
</span> </span>
</> </>
)} )}
</label> </Label>
</div> </div>
); );
}; };
@@ -6,6 +6,7 @@
import { useState, useCallback } from 'react'; import { useState, useCallback } from 'react';
import { useI18n } from '@/utils/chromeI18n'; import { useI18n } from '@/utils/chromeI18n';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { getGeneratorById } from '@/lib/generators'; import { getGeneratorById } from '@/lib/generators';
@@ -110,9 +111,9 @@ export default function FieldEditor({ field, onChange, allFieldNames = [] }: Fie
<div className="space-y-4"> <div className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_fieldName')} {t('testDataGenerator_fieldName')}
</label> </Label>
<span className="text-xs text-muted-foreground">{field.name.length}/20</span> <span className="text-xs text-muted-foreground">{field.name.length}/20</span>
</div> </div>
<Input <Input
@@ -127,9 +128,9 @@ export default function FieldEditor({ field, onChange, allFieldNames = [] }: Fie
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_fieldDescription')} {t('testDataGenerator_fieldDescription')}
</label> </Label>
<span className="text-xs text-muted-foreground"> <span className="text-xs text-muted-foreground">
{(field.description || '').length}/50 {(field.description || '').length}/50
</span> </span>
@@ -147,9 +148,9 @@ export default function FieldEditor({ field, onChange, allFieldNames = [] }: Fie
{/* 必填/选填配置 */} {/* 必填/选填配置 */}
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_required')} {t('testDataGenerator_required')}
</label> </Label>
<Switch checked={field.required} onCheckedChange={handleRequiredChange} /> <Switch checked={field.required} onCheckedChange={handleRequiredChange} />
</div> </div>
@@ -198,26 +199,26 @@ export default function FieldEditor({ field, onChange, allFieldNames = [] }: Fie
{/* 唯一性约束 */} {/* 唯一性约束 */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_uniqueConstraint')} {t('testDataGenerator_uniqueConstraint')}
</label> </Label>
<Switch checked={field.unique} onCheckedChange={handleUniqueChange} /> <Switch checked={field.unique} onCheckedChange={handleUniqueChange} />
</div> </div>
{/* 生成器选择 */} {/* 生成器选择 */}
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_generator')} {t('testDataGenerator_generator')}
</label> </Label>
<GeneratorSelector selectedId={field.generatorId} onChange={handleGeneratorChange} /> <GeneratorSelector selectedId={field.generatorId} onChange={handleGeneratorChange} />
</div> </div>
{/* 生成器参数配置 */} {/* 生成器参数配置 */}
{generator && ( {generator && (
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_generatorParams')} {t('testDataGenerator_generatorParams')}
</label> </Label>
<GeneratorConfig <GeneratorConfig
generator={generator} generator={generator}
params={field.params} params={field.params}
@@ -5,6 +5,7 @@
import { useI18n } from '@/utils/chromeI18n'; import { useI18n } from '@/utils/chromeI18n';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
interface GenerateOptionsProps { interface GenerateOptionsProps {
count: number; count: number;
@@ -32,9 +33,9 @@ export default function GenerateOptions({
<div className="space-y-4"> <div className="space-y-4">
{/* 生成数量 */} {/* 生成数量 */}
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_count')} {t('testDataGenerator_count')}
</label> </Label>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{COUNT_PRESETS.map((preset) => ( {COUNT_PRESETS.map((preset) => (
<button <button
@@ -67,9 +68,9 @@ export default function GenerateOptions({
{/* 数据格式 */} {/* 数据格式 */}
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{t('testDataGenerator_format')} {t('testDataGenerator_format')}
</label> </Label>
<div className="flex gap-2"> <div className="flex gap-2">
{FORMAT_OPTIONS.map((option) => ( {FORMAT_OPTIONS.map((option) => (
<button <button
@@ -4,6 +4,7 @@
*/ */
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
import { import {
Select, Select,
@@ -39,10 +40,10 @@ export default function GeneratorConfig({ generator, params, onChange }: Generat
<div className="space-y-4 p-3 rounded-lg bg-muted/30"> <div className="space-y-4 p-3 rounded-lg bg-muted/30">
{generator.params.map((param) => ( {generator.params.map((param) => (
<div key={param.key} className="space-y-2"> <div key={param.key} className="space-y-2">
<label className="text-sm font-medium text-foreground"> <Label className="text-sm font-medium text-foreground">
{param.label} {param.label}
{param.required && <span className="text-destructive ml-1">*</span>} {param.required && <span className="text-destructive ml-1">*</span>}
</label> </Label>
{param.description && ( {param.description && (
<p className="text-xs text-muted-foreground">{param.description}</p> <p className="text-xs text-muted-foreground">{param.description}</p>
)} )}