From 5b4f9de364064e6f686efd9ccc73772a726e1ebe Mon Sep 17 00:00:00 2001 From: iqudoo Date: Fri, 12 Jun 2026 23:41:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E6=8E=92=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 226 ++++++++++++++++++++++++++------- src/components/PropSidebar.tsx | 23 +++- src/elementAlign.ts | 27 ++++ 3 files changed, 227 insertions(+), 49 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index d46802e..5a35383 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo, useEffect, useLayoutEffect } from 'react'; +import React, { useState, useMemo, useEffect, useLayoutEffect, useRef } from 'react'; import { LabelTemplate, PaperConfig, ImportData, RecordRow, ExportRangeConfig, CutLineConfig } from './types'; import { stripTemplateForStorage, @@ -28,10 +28,11 @@ import { Code, Loader2, Plus, - Download, Upload, Printer, + Pencil, Trash2, + MoreHorizontal, X, } from 'lucide-react'; import logoUrl from './assets/logo.svg'; @@ -145,6 +146,10 @@ export default function App() { const [newTmplName, setNewTmplName] = useState(''); const [newTmplW, setNewTmplW] = useState(75); const [newTmplH, setNewTmplH] = useState(45); + const [editingTemplateId, setEditingTemplateId] = useState(null); + const [editTmplName, setEditTmplName] = useState(''); + const [templateMenuId, setTemplateMenuId] = useState(null); + const templateMenuRef = useRef(null); const paper = workingTemplate.paper ?? DEFAULT_PAPER_CONFIG; const cutLine = workingTemplate.cutLine ?? DEFAULT_CUT_LINE_CONFIG; @@ -247,7 +252,7 @@ export default function App() { const newId = `custom_tmpl_${Date.now()}`; const newTmpl: LabelTemplate = { id: newId, - name: `${newTmplName} (${newTmplW}x${newTmplH}mm)`, + name: `${newTmplName}`, width: Math.max(10, Number(newTmplW) || 70), height: Math.max(10, Number(newTmplH) || 40), elements: [ @@ -259,7 +264,7 @@ export default function App() { y: 5, width: Math.max(10, newTmplW - 10), height: 10, - content: '请插入绑定的文本内容 {货位编号}', + content: '{变量}', fontSize: 12, textAlign: 'center', fontWeight: 'bold', @@ -287,11 +292,52 @@ export default function App() { setNewTmplH(45); }; + const openEditTemplateDialog = (tmpl: LabelTemplate) => { + setEditingTemplateId(tmpl.id!); + setEditTmplName(tmpl.name); + }; + + const closeEditTemplateDialog = () => { + setEditingTemplateId(null); + setEditTmplName(''); + }; + + const closeTemplateMenu = () => setTemplateMenuId(null); + + useEffect(() => { + if (!templateMenuId) return; + const handlePointerDown = (e: PointerEvent) => { + if (templateMenuRef.current?.contains(e.target as Node)) return; + closeTemplateMenu(); + }; + document.addEventListener('pointerdown', handlePointerDown); + return () => document.removeEventListener('pointerdown', handlePointerDown); + }, [templateMenuId]); + + const handleEditTemplateSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!editingTemplateId) return; + const trimmed = editTmplName.trim(); + if (!trimmed) { + await showAlert('请先输入合法的模板名', { variant: 'warning' }); + return; + } + const target = templates.find((t) => t.id === editingTemplateId); + if (!target) { + closeEditTemplateDialog(); + return; + } + saveTemplatesToStorage( + templates.map((t) => (t.id === editingTemplateId ? { ...t, name: trimmed } : t)) + ); + closeEditTemplateDialog(); + }; + // Export templates list or single active template as standard json const handleExportTemplate = (tmpl: LabelTemplate) => { const dataStr = JSON.stringify(normalizeTemplate(tmpl), null, 2); const dataUri = 'data:application/json;charset=utf-8,' + encodeURIComponent(dataStr); - const exportFileDefaultName = `模板_${tmpl.name?.replace(/\s+/g, '_') || tmpl.id}.lad`; + const exportFileDefaultName = `${tmpl.name?.replace(/\s+/g, '_') || tmpl.id}_${Date.now()}.lad`; const linkElement = document.createElement('a'); linkElement.setAttribute('href', dataUri); @@ -654,8 +700,8 @@ export default function App() { {!(isMobile && workflowStep === 'print-view') && (
{/* Title logo and slogan description */} @@ -691,8 +737,8 @@ export default function App() { )}