2026-04-18-19-08-43 - 六项UI优化:基础字段无下划线、field-value联动高亮、视频按钮整合、视频间距紧凑、签名空行、图片占位符自适应高度
This commit is contained in:
@@ -54,6 +54,7 @@ export default function ReportEditor() {
|
||||
const prevVideoCountRef = useRef(0);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<'info' | 'video'>('info');
|
||||
const [activeFieldKey, setActiveFieldKey] = useState<string | null>(null);
|
||||
const [multiSelectOptions, setMultiSelectOptions] = useState<Record<string, string[]>>({
|
||||
surgeon: ['张医生', '李医生', '王医生'],
|
||||
assistant: ['赵医生', '钱医生', '孙医生'],
|
||||
@@ -378,13 +379,14 @@ export default function ReportEditor() {
|
||||
const targetEl = node as HTMLElement | null;
|
||||
if (!targetEl) return;
|
||||
|
||||
// Handle click on field-value: switch to info tab and focus corresponding input
|
||||
// Handle click on field-value: switch to info tab, highlight and focus corresponding input
|
||||
const fieldValue = targetEl.closest('.field-value') as HTMLElement | null;
|
||||
if (fieldValue) {
|
||||
const bindKey = fieldValue.getAttribute('data-bind');
|
||||
if (bindKey) {
|
||||
setActiveTab('info');
|
||||
stateRef.current = { ...stateRef.current, activeTab: 'info' };
|
||||
setActiveFieldKey(bindKey);
|
||||
setTimeout(() => {
|
||||
const inputEl = document.getElementById(`input-${bindKey}`);
|
||||
if (inputEl) {
|
||||
@@ -489,11 +491,14 @@ export default function ReportEditor() {
|
||||
const fillPlaceholderSrc = (placeholder: HTMLElement, src: string) => {
|
||||
placeholder.innerHTML = `
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<img src="${src}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
|
||||
<img src="${src}" style="max-width:100%;height:auto;display:block;margin:0 auto;" draggable="false">
|
||||
`;
|
||||
placeholder.classList.add('has-image');
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
placeholder.style.height = 'auto';
|
||||
placeholder.style.width = 'auto';
|
||||
placeholder.style.lineHeight = 'normal';
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
};
|
||||
@@ -664,6 +669,9 @@ export default function ReportEditor() {
|
||||
emptyPlaceholder.classList.add('has-image');
|
||||
emptyPlaceholder.style.border = 'none';
|
||||
emptyPlaceholder.style.background = 'transparent';
|
||||
emptyPlaceholder.style.height = 'auto';
|
||||
emptyPlaceholder.style.width = 'auto';
|
||||
emptyPlaceholder.style.lineHeight = 'normal';
|
||||
contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
}
|
||||
@@ -690,11 +698,14 @@ export default function ReportEditor() {
|
||||
const fillPlaceholder = (placeholder: HTMLElement, frame: CapturedFrame) => {
|
||||
placeholder.innerHTML = `
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<img src="${frame.dataUrl}" style="max-width:100%;max-height:100%;object-fit:contain;display:block;margin:0 auto;" draggable="false">
|
||||
<img src="${frame.dataUrl}" style="max-width:100%;height:auto;display:block;margin:0 auto;" draggable="false">
|
||||
`;
|
||||
placeholder.classList.add('has-image');
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
placeholder.style.height = 'auto';
|
||||
placeholder.style.width = 'auto';
|
||||
placeholder.style.lineHeight = 'normal';
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
};
|
||||
@@ -1453,7 +1464,7 @@ export default function ReportEditor() {
|
||||
if (field.type === 'text' || field.type === 'date') {
|
||||
const inputType = field.type === 'date' ? 'date' : 'text';
|
||||
return (
|
||||
<div key={field.key} id={`input-${field.key}`} className={field.category === '填空' && formFields.filter(f2 => f2.visibleInForm && f2.type === 'text' && f2.isSystemLocked).length > 1 && (field.key === 'patientName' || field.key === 'hospitalId') ? 'flex-1 space-y-1' : 'space-y-1'}>
|
||||
<div key={field.key} id={`input-${field.key}`} className={`${field.category === '填空' && formFields.filter(f2 => f2.visibleInForm && f2.type === 'text' && f2.isSystemLocked).length > 1 && (field.key === 'patientName' || field.key === 'hospitalId') ? 'flex-1 space-y-1' : 'space-y-1'} p-2 -mx-2 rounded-xl transition-all duration-300 ${activeFieldKey === field.key ? 'bg-blue-50 ring-1 ring-accent shadow-sm' : ''}`}>
|
||||
<label className="block text-xs font-bold text-text-main">
|
||||
{field.label} {isRequired && <span className="text-red-500">*</span>}
|
||||
</label>
|
||||
@@ -1473,7 +1484,7 @@ export default function ReportEditor() {
|
||||
const isOpen = openDropdown === field.key;
|
||||
const opts = field.options || (field.key === 'anesthesiaType' ? anesthesiaOptions : []);
|
||||
return (
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
|
||||
<div key={field.key} id={`input-${field.key}`} className={`space-y-1 select-dropdown-root relative p-2 -mx-2 rounded-xl transition-all duration-300 ${activeFieldKey === field.key ? 'bg-blue-50 ring-1 ring-accent shadow-sm' : ''}`}>
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
<div
|
||||
className="w-full px-3 py-2 border border-border rounded-lg bg-white flex items-center min-h-[42px] cursor-text"
|
||||
@@ -1582,7 +1593,7 @@ export default function ReportEditor() {
|
||||
const currentInputText = multiInputText[field.key] !== undefined ? multiInputText[field.key] : displayText;
|
||||
|
||||
return (
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1 select-dropdown-root relative">
|
||||
<div key={field.key} id={`input-${field.key}`} className={`space-y-1 select-dropdown-root relative p-2 -mx-2 rounded-xl transition-all duration-300 ${activeFieldKey === field.key ? 'bg-blue-50 ring-1 ring-accent shadow-sm' : ''}`}>
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}(可多选)</label>
|
||||
<div
|
||||
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"
|
||||
@@ -1663,7 +1674,7 @@ export default function ReportEditor() {
|
||||
const { h: h12, isPM } = from24h(h24val);
|
||||
|
||||
return (
|
||||
<div key={field.key} id={`input-${field.key}`} className="space-y-1">
|
||||
<div key={field.key} id={`input-${field.key}`} className={`space-y-1 p-2 -mx-2 rounded-xl transition-all duration-300 ${activeFieldKey === field.key ? 'bg-blue-50 ring-1 ring-accent shadow-sm' : ''}`}>
|
||||
<label className="block text-xs font-bold text-text-main">{field.label}</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
@@ -1777,7 +1788,7 @@ export default function ReportEditor() {
|
||||
)}
|
||||
|
||||
{activeTab === 'video' && (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<input
|
||||
ref={videoInputRef}
|
||||
type="file"
|
||||
@@ -1786,20 +1797,17 @@ export default function ReportEditor() {
|
||||
className="hidden"
|
||||
onChange={handleVideoUpload}
|
||||
/>
|
||||
<button
|
||||
onClick={() => videoInputRef.current?.click()}
|
||||
className="w-full flex items-center justify-center gap-2 p-3 border border-dashed border-border rounded-lg hover:border-accent hover:bg-slate-50 transition-all"
|
||||
>
|
||||
<Video size={18} />
|
||||
<div className="text-left">
|
||||
<p className="text-xs font-bold text-text-main">点击上传手术视频</p>
|
||||
<p className="text-[10px] text-text-muted">支持 MP4, MOV 格式</p>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{videos.length > 0 && (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex gap-2 overflow-x-auto pb-2 no-scrollbar">
|
||||
<button
|
||||
onClick={() => videoInputRef.current?.click()}
|
||||
className="shrink-0 w-24 h-[68px] flex flex-col items-center justify-center gap-1 border-2 border-dashed border-border rounded-xl hover:border-accent hover:bg-slate-50 transition-all text-text-muted hover:text-accent"
|
||||
>
|
||||
<Video size={18} />
|
||||
<span className="text-[10px] font-bold">上传视频</span>
|
||||
</button>
|
||||
{videos.map((v, i) => (
|
||||
<div
|
||||
key={v.id}
|
||||
@@ -1828,7 +1836,7 @@ export default function ReportEditor() {
|
||||
</div>
|
||||
|
||||
{currentVideoIndex !== -1 && (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="relative bg-slate-900 rounded-2xl overflow-hidden aspect-video shadow-lg">
|
||||
<video
|
||||
ref={videoRef}
|
||||
@@ -1866,7 +1874,7 @@ export default function ReportEditor() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center pt-2">
|
||||
<div className="flex justify-between items-center pt-1 border-t border-border">
|
||||
<span className="text-[10px] font-bold text-text-main uppercase tracking-wider">关键帧摘取</span>
|
||||
<button
|
||||
onClick={captureFrame}
|
||||
|
||||
Reference in New Issue
Block a user