feat: 6项交互优化 - placeholder虚线框清除、删除按钮遮挡修复、*分隔输入、签名尺寸固定、移除isSigned、多选文本拼接重构
This commit is contained in:
@@ -36,7 +36,6 @@ export default function ReportEditor() {
|
||||
assistant: [],
|
||||
anesthesiologist: [],
|
||||
anesthesiaType: '',
|
||||
isSigned: '未签字',
|
||||
reportNote: '',
|
||||
status: 'draft'
|
||||
});
|
||||
@@ -387,6 +386,8 @@ export default function ReportEditor() {
|
||||
<img src="${src}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
|
||||
`;
|
||||
placeholder.classList.add('has-image');
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
};
|
||||
@@ -895,13 +896,9 @@ export default function ReportEditor() {
|
||||
if (status === 'completed') {
|
||||
const hasSignatureField = editorRef.current?.querySelector('[data-bind="surgeonSignature"]');
|
||||
if (hasSignatureField) {
|
||||
const isSigned = (reportData as any).isSigned === '已签字';
|
||||
const hasSignatureImage = !!currentUser?.signature;
|
||||
if (!isSigned) {
|
||||
const proceed = window.confirm('提示:模板中包含【手术者签名】字段,但您在基本信息中未选择"已签字"。是否继续完成报告?');
|
||||
if (!proceed) return;
|
||||
} else if (!hasSignatureImage) {
|
||||
const proceed = window.confirm('提示:您选择了"已签字",但您的账号尚未上传电子签名图片。报告中将不显示签名图片,是否继续完成?');
|
||||
if (!hasSignatureImage) {
|
||||
const proceed = window.confirm('提示:模板中包含【手术者签名】字段,但您的账号尚未上传电子签名图片。报告中将不显示签名图片,是否继续完成?');
|
||||
if (!proceed) return;
|
||||
}
|
||||
}
|
||||
@@ -993,9 +990,8 @@ export default function ReportEditor() {
|
||||
const fieldKey = el.getAttribute('data-bind')!;
|
||||
|
||||
if (fieldKey === 'surgeonSignature') {
|
||||
const isSigned = (reportData as any).isSigned === '已签字';
|
||||
const signatureData = currentUser?.signature;
|
||||
if (isSigned && signatureData) {
|
||||
if (signatureData) {
|
||||
const imgHtml = `<img src="${signatureData}" class="report-signature-img" alt="签名" draggable="false" />`;
|
||||
if (el.innerHTML !== imgHtml) {
|
||||
el.innerHTML = imgHtml;
|
||||
@@ -1003,7 +999,7 @@ export default function ReportEditor() {
|
||||
el.style.backgroundColor = 'transparent';
|
||||
}
|
||||
} else {
|
||||
const placeholder = isSigned ? '【请上传电子签】' : '【未签字】';
|
||||
const placeholder = '【请上传电子签】';
|
||||
if (el.innerText !== placeholder) {
|
||||
el.innerText = placeholder;
|
||||
el.style.border = '';
|
||||
@@ -1298,7 +1294,39 @@ export default function ReportEditor() {
|
||||
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)] : []);
|
||||
const currentValues = Array.isArray(rawValue) ? rawValue : (rawValue ? [String(rawValue)] : []);
|
||||
const displayText = currentValues.join(', ');
|
||||
|
||||
const parseMultiInput = (text: string): string[] => {
|
||||
return Array.from(new Set(text.split(/[,,;;、]/).map(s => s.trim()).filter(Boolean)));
|
||||
};
|
||||
|
||||
const handleMultiChange = (text: string) => {
|
||||
const values = parseMultiInput(text);
|
||||
const next = { ...reportData, [field.key]: values };
|
||||
setReportData(next);
|
||||
stateRef.current = { ...stateRef.current, reportData: next };
|
||||
saveDraftToStorage();
|
||||
};
|
||||
|
||||
const handleMultiCommit = (text: string) => {
|
||||
const values = parseMultiInput(text);
|
||||
const currentOpts = field.options || multiSelectOptions[field.key] || [];
|
||||
const newOpts = values.filter(v => !currentOpts.includes(v));
|
||||
if (newOpts.length > 0) {
|
||||
const mergedOpts = [...currentOpts, ...newOpts];
|
||||
const nextMulti = { ...multiSelectOptions, [field.key]: mergedOpts };
|
||||
setMultiSelectOptions(nextMulti);
|
||||
storage.set('multiSelectOptions', nextMulti);
|
||||
const fieldDef = formFields.find(f => f.key === field.key);
|
||||
if (fieldDef) {
|
||||
const updatedFields = formFields.map(f => f.key === field.key ? { ...f, options: mergedOpts } : f);
|
||||
setFormFields(updatedFields);
|
||||
storage.set('formFieldsConfig', updatedFields);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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>
|
||||
@@ -1306,22 +1334,18 @@ 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)}
|
||||
>
|
||||
{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>
|
||||
</span>
|
||||
))}
|
||||
<input
|
||||
type="text"
|
||||
className="outline-none text-sm min-w-[60px] flex-1 bg-transparent"
|
||||
placeholder="输入或选择"
|
||||
className="outline-none text-sm w-full bg-transparent"
|
||||
placeholder="输入或选择,多个用逗号分隔"
|
||||
value={displayText}
|
||||
onChange={(e) => handleMultiChange(e.target.value)}
|
||||
onFocus={() => setOpenDropdown(field.key)}
|
||||
onBlur={(e) => handleMultiCommit(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const val = (e.target as HTMLInputElement).value.trim();
|
||||
if (val) { addTag(field.key, val); (e.target as HTMLInputElement).value = ''; }
|
||||
handleMultiCommit((e.target as HTMLInputElement).value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -1332,7 +1356,11 @@ export default function ReportEditor() {
|
||||
<div
|
||||
key={opt}
|
||||
className="px-3 py-2 text-sm hover:bg-slate-50 cursor-pointer flex justify-between items-center"
|
||||
onClick={() => { addTag(field.key, opt); }}
|
||||
onClick={() => {
|
||||
const newText = currentValues.length > 0 ? `${displayText}, ${opt}` : opt;
|
||||
handleMultiChange(newText);
|
||||
handleMultiCommit(newText);
|
||||
}}
|
||||
>
|
||||
<span>{opt}</span>
|
||||
<span
|
||||
|
||||
@@ -125,6 +125,8 @@ export default function TemplateManage() {
|
||||
<img src="${src}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
|
||||
`;
|
||||
placeholder.classList.add('has-image');
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
saveTemplateContent();
|
||||
};
|
||||
|
||||
@@ -486,24 +488,23 @@ export default function TemplateManage() {
|
||||
const insertImage = () => {
|
||||
editorRef.current?.focus();
|
||||
restoreSelection();
|
||||
const input = prompt('请输入占位符的最大宽度和高度(px),用英文逗号分隔(如: 100,50)。留空则默认宽高为 200*200。(提示: 正文一行文字高度约为 20 像素左右)', '');
|
||||
if (input === null) return;
|
||||
const parts = input.split(',').map(s => s.trim());
|
||||
const widthStr = parts[0] || '';
|
||||
const heightStr = parts[1] || '';
|
||||
|
||||
let width = parseInt(widthStr) || 0;
|
||||
let height = parseInt(heightStr) || 0;
|
||||
if (!widthStr && !heightStr) {
|
||||
width = 200;
|
||||
height = 200;
|
||||
} else if (widthStr && !heightStr) {
|
||||
height = 200;
|
||||
} else if (!widthStr && heightStr) {
|
||||
width = 200;
|
||||
let width = 200;
|
||||
let height = 200;
|
||||
while (true) {
|
||||
const input = prompt('请输入占位符的最大宽度和高度(px),用 * 分隔(如: 100*50)。留空则默认宽高为 200*200。(提示: 正文一行文字高度约为 20 像素左右)', '');
|
||||
if (input === null) return;
|
||||
const trimmed = input.trim();
|
||||
if (trimmed === '') break;
|
||||
const parts = trimmed.split('*').map(s => s.trim());
|
||||
if (parts.length === 2 && /^\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
||||
width = parseInt(parts[0]) || 0;
|
||||
height = parseInt(parts[1]) || 0;
|
||||
break;
|
||||
}
|
||||
alert('格式错误,请确保使用 * 分隔两个数字,例如 100*50');
|
||||
}
|
||||
|
||||
let styleStr = 'display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;overflow:hidden;';
|
||||
let styleStr = 'display:inline-flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;';
|
||||
if (width > 0) styleStr += `width:${width}px;`;
|
||||
if (height > 0) styleStr += `height:${height}px;`;
|
||||
|
||||
|
||||
@@ -136,5 +136,4 @@ export const DEFAULT_FORM_FIELDS: FormField[] = [
|
||||
{ key: 'specimenDescription', label: '切除标本描述', category: '单选', type: 'single_select', visibleInForm: true, isSystemLocked: true, options: ['胆囊一枚,壁厚约0.3cm,内含数枚结石'] },
|
||||
{ key: 'pathologyCheck', label: '是否送病理检查', category: '单选', type: 'single_select', visibleInForm: true, isSystemLocked: true, options: ['是', '否'] },
|
||||
{ key: 'frozenPathology', label: '冰冻病理结果', category: '单选', type: 'single_select', visibleInForm: true, isSystemLocked: true, options: ['未见恶性', '待石蜡'] },
|
||||
{ key: 'isSigned', label: '手术者签名确认', category: '单选', type: 'single_select', visibleInForm: true, isSystemLocked: false, options: ['已签字', '未签字'] },
|
||||
];
|
||||
|
||||
@@ -87,47 +87,47 @@ export const defaultReportContent = `
|
||||
<table style="width: 100%; border-collapse: collapse; margin: 20px 0; table-layout: fixed;">
|
||||
<tbody><tr>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图A 腹腔镜探查</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图B 胆囊管夹闭与离断</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图C 胆囊动脉夹闭与离断</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图D 胆囊剥离与床面止血</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图E 胆囊取出与钛夹确认</p>
|
||||
</td>
|
||||
<td style="width: 33%; text-align: center; padding: 10px; vertical-align: top; border: 1px solid #e2e8f0;">
|
||||
<div class="image-placeholder" data-placeholder="true" contenteditable="false">
|
||||
<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:100%;height:150px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;cursor:pointer;">
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<p class="placeholder-text" style="color: #94a3b8; font-size: 11px; margin: 0; pointer-events: none;">插入/点击放置图片</p>
|
||||
</div>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
</span>
|
||||
<p style="color: #64748b; font-size: 13px; margin: 0;">图F 止血材料覆盖及检查</p>
|
||||
</td>
|
||||
</tr></tbody>
|
||||
@@ -151,7 +151,7 @@ export const defaultReportContent = `
|
||||
</p>
|
||||
|
||||
<p style="font-family: SimSun;">
|
||||
手术者签名:<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;min-width:80px;min-height:24px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入图片</span></span>
|
||||
手术者签名:<span class="image-placeholder" data-placeholder="true" contenteditable="false" style="display:inline-flex;align-items:center;justify-content:center;width:200px;height:40px;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入图片</span></span>
|
||||
</p>
|
||||
|
||||
<p style="text-align: right; font-family: SimSun; color: #bdbdbd;">
|
||||
|
||||
63
过往经验/经验记录.md
63
过往经验/经验记录.md
@@ -289,6 +289,69 @@ if ((settings.autoInsertDelay || 0) > 0) {
|
||||
|
||||
---
|
||||
|
||||
## 记录 13:6 项交互优化(placeholder 虚线框、删除按钮、签名尺寸、多选重构)
|
||||
|
||||
**A. 具体问题**
|
||||
用户提出 6 个 UI/UX 改进需求:
|
||||
1. 图片插入占位符后虚线框残留——内联 `border:1px dashed #cbd5e1` 优先级高于 `.has-image` CSS class;
|
||||
2. `insertImage` 生成的 placeholder 中 `overflow:hidden` 裁切了绝对定位的删除按钮(`×`);
|
||||
3. 占位符尺寸输入从逗号分隔改为星号(`*`)分隔,格式错误时提示重新输入;
|
||||
4. 默认模板中「手术者签名」占位符固定为 `200×40px`;
|
||||
5. 删除「手术者签名确认」字段及相关的弱阻断确认弹窗;
|
||||
6. 多选组件从 tag 形态重构为纯文本拼接形态,支持多种标点符号拆分并自动保存新选项。
|
||||
|
||||
**B. 产生问题原因**
|
||||
1. `fillPlaceholderSrc` 仅添加了 `has-image` class,但内联 `style="border:..."` 的优先级永远高于外部 CSS,导致虚线框无法消除。
|
||||
2. `insertImage` 的 `styleStr` 中硬编码了 `overflow:hidden;`,而删除按钮使用 `position:absolute; top:-8px; right:-8px` 之类的定位,必然被父级裁切。
|
||||
3. 英文逗号分隔容易与用户输入的千位分隔符或中文逗号混淆。
|
||||
4. 默认模板中签名占位符使用 `min-width:80px;min-height:24px`,尺寸过小且不一致。
|
||||
5. `isSigned` 字段与签名图片是两个独立的状态,造成医生需要多点一次确认,流程冗余。
|
||||
6. 原多选使用 tag 胶囊形式,每个 tag 带背景色和删除按钮,占用空间大,且无法直接复制粘贴整段文本。
|
||||
|
||||
**C. 解决问题方案**
|
||||
1. **清除内联样式**:在 `ReportEditor.tsx` 和 `TemplateManage.tsx` 的 `fillPlaceholderSrc` 中增加:
|
||||
```ts
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
```
|
||||
同时统一 `defaultContent.ts` 中所有 8 个 placeholder 为 `<span style="display:inline-flex;...">` 格式,表格中的 6 个也统一使用 `width:100%;height:150px;`。
|
||||
2. **移除 overflow:hidden**:从两个 `insertImage` 的 `styleStr` 中删除 `overflow:hidden;`,保留在 `placeholder-text` 子元素上(文字截断仍可用)。
|
||||
3. **星号分隔 + 校验循环**:
|
||||
```ts
|
||||
while (true) {
|
||||
const input = prompt('...用 * 分隔...', '');
|
||||
if (input === null) return;
|
||||
const trimmed = input.trim();
|
||||
if (trimmed === '') break;
|
||||
const parts = trimmed.split('*').map(s => s.trim());
|
||||
if (parts.length === 2 && /^\d+$/.test(parts[0]) && /^\d+$/.test(parts[1])) {
|
||||
width = parseInt(parts[0]); height = parseInt(parts[1]); break;
|
||||
}
|
||||
alert('格式错误...');
|
||||
}
|
||||
```
|
||||
4. **签名占位符尺寸**:`defaultContent.ts` 中改为 `width:200px;height:40px;`。
|
||||
5. **移除 `isSigned`**:
|
||||
- `types.ts` 的 `DEFAULT_FORM_FIELDS` 中删除;
|
||||
- `ReportEditor.tsx` 的初始 `reportData` 中删除;
|
||||
- `saveReport` 的完成确认逻辑中删除 `isSigned` 判断;
|
||||
- smart field 同步逻辑中删除 `isSigned` 判断,只要有 `signatureData` 就直接显示签名图。
|
||||
6. **多选重构为文本拼接**:
|
||||
- `displayText = currentValues.join(', ')`;
|
||||
- input 使用 `value={displayText}` 受控组件;
|
||||
- `onChange` 实时解析并更新 `reportData`:`parseMultiInput(text)` 用 `/[,,;;、]/` 正则拆分、去重;
|
||||
- `onBlur` / `Enter` 时调用 `handleMultiCommit`,将拆分出的新选项保存到 `multiSelectOptions` 和 `formFieldsConfig`;
|
||||
- 下拉选择时追加 `, opt` 到现有文本。
|
||||
|
||||
**D. 后续如何避免问题**
|
||||
- 当使用内联样式设置边框/背景时,如需在特定状态下移除,**必须在内联层面重置**(`style.border = 'none'`),不能仅依赖 CSS class 覆盖。
|
||||
- `overflow:hidden` 与绝对定位子元素互斥,若需要裁切文字但保留溢出按钮,应将 `overflow:hidden` 限制在文字子元素上,而非父容器。
|
||||
- 用户输入的格式校验应使用 `while` 循环 + `alert` 重试,避免静默容错导致不可预期的行为。
|
||||
- 删除字段时务必全局搜索(`grep -r 'isSigned'`),确保初始化状态、表单验证、模板绑定等所有引用点都被清理。
|
||||
- 将「标签胶囊」改为「纯文本拼接」时,注意保持 `reportData` 的数据结构仍为数组,UI 层只做 `join/split` 转换。
|
||||
|
||||
---
|
||||
|
||||
## 记录 11:关键帧在路由切换后丢失——压缩 Canvas 分辨率并增加存储错误日志
|
||||
|
||||
**A. 具体问题**
|
||||
|
||||
Reference in New Issue
Block a user