diff --git a/chfs-ng/internal/api/web/index.html b/chfs-ng/internal/api/web/index.html
index 9a2a3b2..8b32c75 100644
--- a/chfs-ng/internal/api/web/index.html
+++ b/chfs-ng/internal/api/web/index.html
@@ -66,10 +66,12 @@ $("modal").addEventListener("click",e=>{if(e.target.id==="modal")closeModal()})
async function showUsers(){try{const d=await api("/chfs/users");let html='
用户管理
';for(const u of d.users)html+='
'+esc(u.username)+' · '+(u.enabled?"启用":"已禁用")+' · '+esc(u.home||"")+(u.managed&&!u.admin?' ':"")+"
";html+='
';show(html)}catch(e){alert(e.message)}}
async function createUser(){try{await api("/chfs/users",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:$("nu").value,password:$("np").value})});showUsers()}catch(e){alert(e.message)}}
async function resetUser(u){const p=prompt("为 "+u+" 设置新密码");if(!p)return;try{await api("/chfs/users",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:u,password:p})});alert("密码已更新")}catch(e){alert(e.message)}}
-async function editUser(name){const d=await api("/chfs/users");const u=d.users.find(x=>x.username===name);if(!u)return;window._editUser=u;window._editRules=[...(u.rules||[])];show(''+esc(u.username)+'
主目录:'+esc(u.home)+'
主目录固定为 RWD;额外规则用于开放其他目录或显式拒绝访问。
');renderEditRules()}
-function addRule(){const dir=$("rp").value.trim().replace(/^\/+|\/+$/g,"");if(!dir)return;const rule={dir,mask:$("rm").value};if($("rd").checked)rule.deny=true;if($("rc").checked)rule.childrenOnly=true;window._editRules.push(rule);$("rp").value="";renderEditRules()}
-function removeRule(i){window._editRules.splice(i,1);renderEditRules()}
-function renderEditRules(){$("rules").innerHTML=window._editRules.map((r,i)=>{const flags=(r.deny?"拒绝":"允许")+(r.childrenOnly?" · 仅子项":"");return ''+esc(r.dir)+' · '+esc(r.mask||"禁止")+' · '+flags+'
'}).join("")}
+async function editUser(name){const d=await api("/chfs/users");const u=d.users.find(x=>x.username===name);if(!u)return;window._editUser=u;window._editRules=[...(u.rules||[])];show(''+esc(u.username)+'
主目录:'+esc(u.home)+'
主目录始终保留 RWD;下面的“共享目录”用于给用户开放其他位置,也可以单独设置拒绝规则。
共享目录
高级规则
可对已授权目录增加更细的拒绝规则,例如禁止访问 public/private。
');renderEditRules()}
+function isHomeRule(r){return String(r.dir||"").replace(/^\/+|\/+$/g,"")===String(window._editUser.home||"").replace(/^\/+|\/+$/g,"")}
+function setRulePreset(level){const mask=["","r","rw","rwd"][level];$("rd").checked=level===0;$("rm").value=mask;$("rp").focus()}
+function addRule(){const dir=$("rp").value.trim().replace(/^\/+|\/+$/g,"");if(!dir)return;const rule={dir,mask:$("rm").value};if($("rd").checked)rule.deny=true;if($("rc").checked)rule.childrenOnly=true;window._editRules=window._editRules.filter(r=>!(String(r.dir||"").replace(/^\/+|\/+$/g,"")===dir&&!isHomeRule(r)));window._editRules.push(rule);$("rp").value="";$("rd").checked=false;$("rc").checked=false;renderEditRules()}
+function removeRule(i){if(i<0||isHomeRule(window._editRules[i]))return;window._editRules.splice(i,1);renderEditRules()}
+function renderEditRules(){const shared=window._editRules.filter(r=>!isHomeRule(r));$("sharedRules").innerHTML=shared.length?shared.map(r=>{const i=window._editRules.indexOf(r);const flags=(r.deny?"禁止":"允许")+" · "+(r.mask||"无权限")+(r.childrenOnly?" · 仅子项":"");return ''+esc(r.dir)+'
'+esc(flags)+'
'}).join(""):'还没有共享目录权限
';$("rules").innerHTML=window._editRules.map((r,i)=>isHomeRule(r)?'':''+esc(r.dir)+' · '+esc((r.deny?"拒绝":"允许")+" · "+(r.mask||"禁止")+(r.childrenOnly?" · 仅子项":""))+'
').join("")}
async function saveUser(u){try{await api("/chfs/users",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:u,enabled:$("ue").checked,rules:window._editRules})});showUsers()}catch(e){alert(e.message)}}
async function deleteUser(u){if(!confirm("删除用户 "+u+"?用户目录不会自动删除。"))return;try{await api("/chfs/users?username="+encodeURIComponent(u),{method:"DELETE"});showUsers()}catch(e){alert(e.message)}}
init();