feat: focus highlight, delete-btn visibility isolation, multi_select crash fix

- Move delete-btn to top-right of smart-field-wrapper via absolute positioning
- Add template-editor-mode class to TemplateManage editor for CSS isolation
- Show delete-btn only on hover/focus-within inside template-editor-mode
- Add .field-value:focus highlight with background darken and blue glow
- Sync defaultContent.ts smartField() HTML structure
- Fix ReportEditor multi_select .map crash with Array.isArray guard
This commit is contained in:
2026-04-17 11:21:32 +08:00
parent db5df13a05
commit 0ff1cbe5f0
8 changed files with 273 additions and 11 deletions

View File

@@ -127,24 +127,35 @@
.smart-field-wrapper .field-value:empty::before {
content: '\200b';
}
.smart-field-wrapper .field-value:focus {
background-color: #e2e8f0;
border-color: #94a3b8;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.25);
}
.smart-field-wrapper .delete-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
margin-right: 2px;
position: absolute;
top: -8px;
right: -8px;
width: 16px;
height: 16px;
background: #ef4444;
color: white;
border-radius: 50%;
font-size: 10px;
line-height: 1;
line-height: 16px;
text-align: center;
cursor: pointer;
user-select: none;
display: none;
z-index: 10;
}
.smart-field-wrapper .delete-btn:hover {
background: #dc2626;
}
.template-editor-mode .smart-field-wrapper:hover .delete-btn,
.template-editor-mode .smart-field-wrapper:focus-within .delete-btn {
display: block;
}
}
@media print {

View File

@@ -1224,6 +1224,8 @@ export default function ReportEditor() {
if (field.type === 'multi_select') {
const isOpen = openDropdown === field.key;
const opts = field.options || multiSelectOptions[field.key] || [];
const rawValue = (reportData as any)[field.key];
const tags = Array.isArray(rawValue) ? rawValue : (rawValue ? [String(rawValue)] : []);
return (
<div key={field.key} className="space-y-1 select-dropdown-root relative">
<label className="block text-xs font-bold text-text-main">{field.label}</label>
@@ -1231,7 +1233,7 @@ export default function ReportEditor() {
className="w-full px-3 py-2 border border-border rounded-lg bg-white flex flex-wrap gap-1 items-center min-h-[42px] cursor-text"
onClick={() => setOpenDropdown(field.key)}
>
{((reportData as any)[field.key] || []).map((tag: string) => (
{tags.map((tag: string) => (
<span key={tag} className="px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 flex items-center gap-1">
{tag}
<span className="cursor-pointer hover:text-amber-900" onClick={(e) => { e.stopPropagation(); removeTag(field.key, tag); }}>×</span>

View File

@@ -249,7 +249,7 @@ export default function TemplateManage() {
alert(`字段 "${field.label}" 已存在,请勿重复插入。`);
return;
}
const html = `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="delete-btn" contenteditable="false">×</span><span class="field-value" data-bind="${field.key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;"> </span></span>`;
const html = `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;position:relative;"><span class="field-value" data-bind="${field.key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;outline:none;"> </span><span class="delete-btn" contenteditable="false">×</span></span>`;
document.execCommand('insertHTML', false, html);
editorRef.current?.focus();
};
@@ -577,7 +577,7 @@ export default function TemplateManage() {
<div
ref={editorRef}
contentEditable
className="editor-content print-content"
className="editor-content print-content template-editor-mode"
>
</div>
</div>

View File

@@ -1,4 +1,4 @@
const smartField = (key: string) => `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;"><span class="delete-btn" contenteditable="false">×</span><span class="field-value" data-bind="${key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;"> </span></span>`;
const smartField = (key: string) => `<span class="smart-field-wrapper" contenteditable="false" style="white-space:nowrap;position:relative;"><span class="field-value" data-bind="${key}" contenteditable="true" style="min-width:32px;padding:0 4px;margin:0 2px;border:1px solid #cbd5e1;border-radius:2px;display:inline-block;background:#f8fafc;color:#0f172a;line-height:1.2;font-size:inherit;vertical-align:text-bottom;box-sizing:border-box;min-height:1.2em;outline:none;"> </span><span class="delete-btn" contenteditable="false">×</span></span>`;
export const defaultReportContent = `
<!-- 医院Logo -->