(function () { const API_BASE = window.CITY3D_API_BASE || (location.protocol.startsWith("http") ? "" : (["", "localhost", "127.0.0.1"].includes(location.hostname) ? "http://127.0.0.1:8000" : "http://172.16.16.70:8000")); const TOKEN_KEY = "city3d_token"; const state = {user:null, mode:"login"}; const $ = id => document.getElementById(id); const overlay = $("authOverlay"), dialog = $("authDialog"), drawer = $("taskDrawer"), menu = $("userMenu"); const initials = user => [...(user?.nickname || user?.username || "游").trim()][0] || "游"; function authHeaders(extra={}) { const token=localStorage.getItem(TOKEN_KEY); return token ? {...extra,Authorization:`Bearer ${token}`} : extra; } function renderAccount() { const user=state.user; $("accountAvatar").textContent=initials(user); $("accountName").textContent=user?(user.nickname||user.username):"登录 / 注册"; $("menuNickname").textContent=user?(user.nickname||"个人账户"):"游客模式"; $("menuPhone").textContent=user?user.username:"未登录"; $("menuLogout").style.display=user?"block":"none"; } function setMode(mode) { state.mode=mode; dialog.classList.toggle("register",mode==="register"); document.querySelectorAll("[data-auth-mode]").forEach(btn=>btn.classList.toggle("active",btn.dataset.authMode===mode)); $("authTitle").textContent=mode==="register"?"建立个人账户":"欢迎回来"; $("authSubmit").textContent=mode==="register"?"注册并登录":"登录"; $("authPassword").autocomplete=mode==="register"?"new-password":"current-password"; } function openAuth(mode="login") { setMode(mode); overlay.classList.add("open"); overlay.setAttribute("aria-hidden","false"); setTimeout(()=>$(mode==="register"?"authNickname":"authPhone").focus(),50); } function closeAuth() { overlay.classList.remove("open"); overlay.setAttribute("aria-hidden","true"); $("authError").textContent=""; } async function api(path,options={}) { const response=await fetch(`${API_BASE}${path}`,{...options,headers:authHeaders(options.headers||{})}); const data=await response.json().catch(()=>({})); if(!response.ok||(data.code&&data.code!=="SUCCESS")) throw new Error(data.message||`请求失败 (${response.status})`); return data; } async function checkAuth() { if(!localStorage.getItem(TOKEN_KEY)){renderAccount();return;} try{const data=await api("/api/v1/auth/me");state.user=data.is_guest?null:data.user;if(!state.user)localStorage.removeItem(TOKEN_KEY);}catch(_){state.user=null;localStorage.removeItem(TOKEN_KEY);} renderAccount(); } function taskCard(task) { const pending=task.status!=="SUCCESS"; return `

${task.file_name||"未命名CAD任务"}

${task.status||"UNKNOWN"}
文件大小${Number(task.file_size_mb||0).toFixed(2)} MB
空间范围${task.bounds_desc||"--"}
提交时间${task.created_at||"--"}
任务编号#${task.id||"--"}
${task.task_id||""}
`; } async function openTasks() { menu.classList.remove("open"); drawer.classList.add("open"); drawer.setAttribute("aria-hidden","false"); if(!state.user){$("taskList").innerHTML='
请先登录,再查看个人专属历史任务。
';$("drawerLogin").onclick=()=>{closeTasks();openAuth();};return;} $("taskList").innerHTML='
正在读取历史任务…
'; try{const data=await api("/api/v1/user/tasks?limit=50");$("taskDrawerSubtitle").textContent=`${state.user.nickname||state.user.username} · 共 ${data.total||0} 条记录`;$("taskList").innerHTML=data.tasks?.length?data.tasks.map(taskCard).join(""):'
还没有历史任务。
上传第一份CAD图纸后会显示在这里。
';}catch(error){$("taskList").innerHTML=`
${error.message}
请确认认证服务已启动。
`;} } function closeTasks(){drawer.classList.remove("open");drawer.setAttribute("aria-hidden","true");} $("userAccountButton").addEventListener("click",event=>{event.stopPropagation();if(!state.user)openAuth();else menu.classList.toggle("open");}); $("historyTasksButton").addEventListener("click",openTasks); $("menuHistory").addEventListener("click",openTasks); $("authClose").addEventListener("click",closeAuth); $("taskDrawerClose").addEventListener("click",closeTasks); overlay.addEventListener("click",event=>{if(event.target===overlay)closeAuth();}); document.querySelectorAll("[data-auth-mode]").forEach(btn=>btn.addEventListener("click",()=>setMode(btn.dataset.authMode))); document.addEventListener("click",event=>{if(!menu.contains(event.target)&&event.target!==$("userAccountButton"))menu.classList.remove("open");}); document.addEventListener("keydown",event=>{if(event.key==="Escape"){closeAuth();closeTasks();menu.classList.remove("open");}}); $("menuLogout").addEventListener("click",()=>{localStorage.removeItem(TOKEN_KEY);state.user=null;menu.classList.remove("open");renderAccount();window.toast?.("已退出登录,当前为游客模式");}); $("authForm").addEventListener("submit",async event=>{ event.preventDefault();const phone=$("authPhone").value.trim(),password=$("authPassword").value,nickname=$("authNickname").value.trim(); if(!/^1\d{10}$/.test(phone)){$("authError").textContent="请输入正确的11位手机号码";return;} if(password.length<8){$("authError").textContent="密码至少需要8位字符";return;} if(state.mode==="register"&&!nickname){$("authError").textContent="请填写姓名或昵称";return;} const button=$("authSubmit");button.disabled=true;button.textContent="正在连接…";$("authError").textContent="";try{const body=state.mode==="register"?{username:phone,password,nickname}:{username:phone,password};const data=await api(`/api/v1/auth/${state.mode}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(body)});localStorage.setItem(TOKEN_KEY,data.access_token);state.user=data.user;renderAccount();closeAuth();window.toast?.(data.message||"登录成功");}catch(error){$("authError").textContent=error.message==="Failed to fetch"?"无法连接认证服务,请确认后端8000端口已启动":error.message;}finally{button.disabled=false;button.textContent=state.mode==="register"?"注册并登录":"登录";} }); renderAccount();checkAuth(); })();