Browse Source

feat: 上传后支持更换户型图,点击/拖拽双通道上传

画布区新增『更换户型图』按钮;第一步上传区与第二步画布区均支持拖拽上传(dragover 高亮提示),载入后自动重新识别;同名文件可重复选择
缪子怡 2 weeks ago
parent
commit
62f898fec7
1 changed files with 23 additions and 5 deletions
  1. 23 5
      AI快速报价_Demo2.optimizing.html

+ 23 - 5
AI快速报价_Demo2.optimizing.html

@@ -130,6 +130,10 @@
     text-align: center; cursor: pointer; transition: all 0.2s; background: #FAFBFC;
     text-align: center; cursor: pointer; transition: all 0.2s; background: #FAFBFC;
   }
   }
   .upload-area:hover { border-color: var(--accent); background: #EBF8FF; }
   .upload-area:hover { border-color: var(--accent); background: #EBF8FF; }
+  .upload-area.dragover { border-color: var(--primary); background: #EBF8FF; }
+  .drop-zone { position: relative; }
+  .drop-zone .drop-hint { display:none; position:absolute; inset:0; background:rgba(49,130,206,.14); border:2px dashed var(--primary); color:#2B6CB0; font-weight:700; font-size:14px; align-items:center; justify-content:center; pointer-events:none; z-index:5; }
+  .drop-zone.dragover .drop-hint { display:flex; }
   .upload-area .icon { font-size: 36px; margin-bottom: 8px; }
   .upload-area .icon { font-size: 36px; margin-bottom: 8px; }
   .upload-area .text { font-size: 14px; color: var(--text-muted); }
   .upload-area .text { font-size: 14px; color: var(--text-muted); }
   .upload-area .types { font-size: 12px; color: #A0AEC0; margin-top: 4px; }
   .upload-area .types { font-size: 12px; color: #A0AEC0; margin-top: 4px; }
@@ -388,7 +392,7 @@
 
 
           <div id="q-upload-zone-unified" class="upload-area" onclick="document.getElementById('q-file-unified').click()" style="padding:16px;margin-bottom:10px;">
           <div id="q-upload-zone-unified" class="upload-area" onclick="document.getElementById('q-file-unified').click()" style="padding:16px;margin-bottom:10px;">
             <div class="icon">📐</div>
             <div class="icon">📐</div>
-            <div class="text">点击上传户型图 / CAD图纸</div>
+            <div class="text">点击或拖拽上传户型图 / CAD图纸</div>
             <div class="types">户型图支持 JPG、PNG、WEBP;CAD支持 DWG、DXF、PDF | 上传后自动进入 AI 解析</div>
             <div class="types">户型图支持 JPG、PNG、WEBP;CAD支持 DWG、DXF、PDF | 上传后自动进入 AI 解析</div>
           </div>
           </div>
           <div style="display:flex;gap:6px;flex-wrap:wrap;">
           <div style="display:flex;gap:6px;flex-wrap:wrap;">
@@ -455,10 +459,14 @@
       </div>
       </div>
 
 
       <div style="display:flex;gap:16px;flex-wrap:wrap;align-items:stretch;">
       <div style="display:flex;gap:16px;flex-wrap:wrap;align-items:stretch;">
-        <div style="flex:3;min-width:380px;border:1px solid var(--border);border-radius:8px;overflow:hidden;background:#fff;">
-          <div style="font-size:11px;color:var(--text-muted);padding:7px 10px;background:#F7FAFC;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;">
+        <div id="q-canvas-drop" class="drop-zone" style="flex:3;min-width:380px;border:1px solid var(--border);border-radius:8px;overflow:hidden;background:#fff;">
+          <div class="drop-hint">📥 松开即更换户型图(JPG / PNG / WEBP,自动重新识别)</div>
+          <div style="font-size:11px;color:var(--text-muted);padding:7px 10px;background:#F7FAFC;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;gap:8px;">
             <span>📐 图纸识别结果叠加(<span style="color:#805AD5;">厨房</span> / <span style="color:#3182CE;">柜体</span>;图纸自带红框不二次叠加)</span>
             <span>📐 图纸识别结果叠加(<span style="color:#805AD5;">厨房</span> / <span style="color:#3182CE;">柜体</span>;图纸自带红框不二次叠加)</span>
-            <span id="q-ai-scene-chip" style="font-size:11px;font-weight:600;color:#2B6CB0;">等待识别…</span>
+            <span style="display:flex;align-items:center;gap:8px;">
+              <button class="btn btn-outline btn-sm" onclick="document.getElementById('q-file-unified').click()" title="点击选择新图纸,或直接将图纸拖拽到本区域">🔄 更换户型图</button>
+              <span id="q-ai-scene-chip" style="font-size:11px;font-weight:600;color:#2B6CB0;">等待识别…</span>
+            </span>
           </div>
           </div>
           <canvas id="q-ai-canvas" style="width:100%;display:block;background:#fff;"></canvas>
           <canvas id="q-ai-canvas" style="width:100%;display:block;background:#fff;"></canvas>
         </div>
         </div>
@@ -872,9 +880,18 @@ function genSample(u,cad){
   const im=new Image();im.src=c.toDataURL("image/png");return im;
   const im=new Image();im.src=c.toDataURL("image/png");return im;
 }
 }
 function qUseMockDrawing(isU,isCad){const im=genSample(isU,isCad);im.onload=()=>{showImg(im);toast(isCad?"已载入示例CAD图(黑白线图)":isU?"已载入示例户型图(U型厨房+红框)":"已载入示例户型图(L型厨房+红框)");qStartAnalysis();};}
 function qUseMockDrawing(isU,isCad){const im=genSample(isU,isCad);im.onload=()=>{showImg(im);toast(isCad?"已载入示例CAD图(黑白线图)":isU?"已载入示例户型图(U型厨房+红框)":"已载入示例户型图(L型厨房+红框)");qStartAnalysis();};}
-function qHandleUnified(inp){const f=inp.files[0];if(!f)return;
+/* 统一图纸载入入口:点击上传 / 拖拽上传 / 更换户型图 共用,载入后自动重新识别 */
+function qLoadFile(f){if(!f)return;
   if(/\.(pdf|dwg|dxf)$/i.test(f.name)){alert("PDF/DWG 请先转 JPG/PNG(Demo 限制)");return;}
   if(/\.(pdf|dwg|dxf)$/i.test(f.name)){alert("PDF/DWG 请先转 JPG/PNG(Demo 限制)");return;}
+  if(f.type&&f.type.indexOf("image")!==0&&!/\.(jpe?g|png|webp|bmp)$/i.test(f.name)){alert("仅支持图片格式:JPG / PNG / WEBP");return;}
   const rd=new FileReader();rd.onload=()=>{const im=new Image();im.onload=()=>{showImg(im);qStartAnalysis();};im.src=rd.result;};rd.readAsDataURL(f);}
   const rd=new FileReader();rd.onload=()=>{const im=new Image();im.onload=()=>{showImg(im);qStartAnalysis();};im.src=rd.result;};rd.readAsDataURL(f);}
+function qHandleUnified(inp){qLoadFile(inp.files[0]);inp.value="";}   /* 清空 value:同名文件可重复选择触发 onchange */
+/* 拖拽上传绑定:dragover 高亮提示,drop 载入并自动重新识别 */
+function qBindDrop(el){if(!el)return;
+  ["dragenter","dragover"].forEach(ev=>el.addEventListener(ev,e=>{e.preventDefault();e.stopPropagation();el.classList.add("dragover");}));
+  ["dragleave","dragend"].forEach(ev=>el.addEventListener(ev,e=>{e.preventDefault();e.stopPropagation();el.classList.remove("dragover");}));
+  el.addEventListener("drop",e=>{e.preventDefault();e.stopPropagation();el.classList.remove("dragover");
+    const f=e.dataTransfer&&e.dataTransfer.files&&e.dataTransfer.files[0];qLoadFile(f);});}
 function qStartAnalysis(){if(!img){toast("请先上传图纸或选择示例","toast-error");return;}qOpenEditorStep(2);
 function qStartAnalysis(){if(!img){toast("请先上传图纸或选择示例","toast-error");return;}qOpenEditorStep(2);
   runAI().catch(e=>{ /* 识别异常兜底:清叠加、重绘画布、提示重试,避免留下错位/半残页面 */
   runAI().catch(e=>{ /* 识别异常兜底:清叠加、重绘画布、提示重试,避免留下错位/半残页面 */
     overlays=[];if(img)draw();setProg(0,"");setProg(1,"");setProg(2,"");
     overlays=[];if(img)draw();setProg(0,"");setProg(1,"");setProg(2,"");
@@ -1856,6 +1873,7 @@ function renderRules(){
 $("q-red-anno").oninput=()=>{if(S.redArrow){const old=dimScale();const inf=annoInfer(S.scale600||0);if(!inf)return;S.scale=inf.scale;S.scaleSrc="红标注箭头校准(推断单位"+inf.unit+" · 与600mm锚点交叉校验)";const nw=dimScale();if(S.kitBox&&old&&nw)S.kitBox={wM:S.kitBox.wM/old*nw,hM:S.kitBox.hM/old*nw};renderAnnoInfer();recalc();renderAIResults();}};
 $("q-red-anno").oninput=()=>{if(S.redArrow){const old=dimScale();const inf=annoInfer(S.scale600||0);if(!inf)return;S.scale=inf.scale;S.scaleSrc="红标注箭头校准(推断单位"+inf.unit+" · 与600mm锚点交叉校验)";const nw=dimScale();if(S.kitBox&&old&&nw)S.kitBox={wM:S.kitBox.wM/old*nw,hM:S.kitBox.hM/old*nw};renderAnnoInfer();recalc();renderAIResults();}};
 $("btnFb").onclick=()=>{const px=+$("fbPx").value||0,mm=+$("fbMm").value||0;if(px>0&&mm>0){S.scale=(mm/1000)/px;S.scaleSrc="用户补充已知尺寸";recalc();toast("比例已建立");}else toast("请填写像素数与毫米数","toast-error");};
 $("btnFb").onclick=()=>{const px=+$("fbPx").value||0,mm=+$("fbMm").value||0;if(px>0&&mm>0){S.scale=(mm/1000)/px;S.scaleSrc="用户补充已知尺寸";recalc();toast("比例已建立");}else toast("请填写像素数与毫米数","toast-error");};
 
 
+qBindDrop($("q-upload-zone-unified"));qBindDrop($("q-canvas-drop"));   /* 点击 + 拖拽双通道上传/更换图纸 */
 renderTiers();renderRules();renderQuoteList();rebuildObjs();recalc();
 renderTiers();renderRules();renderQuoteList();rebuildObjs();recalc();
 </script>
 </script>
 </body>
 </body>