PageSourceSearch

https://www.ieduonline.cn/_nuxt/BYIkDcZo.js

js ieduonline.cn collected 2026-10-06 14:18:07 UTC 14,839 bytes, 1 lines download raw bytes

1import{d as ns,u as is,c as F,o as as,f as i,g as s,s as l,t as d,j as c,h as B,i as g,p as w,ab as ds,F as p,r as v,m as G,G as S,v as z,H as us,J as rs,D as H,y as _,e as a,A as cs}from"./CxjwaSEV.js";import{R as ps,a as D}from"./CKkkeG25.js";import{u as ms,a as vs}from"./CO4UvFh5.js";import"./Bu7hayz2.js";const fs={class:"ops-page"},bs={key:0,class:"ops-error"},ws={class:"ops-card block"},_s={class:"ops-table matrix"},ys={class:"cell-sub mono"},ks={key:0,class:"yes"},gs={key:1,class:"no"},hs={class:"ops-card block"},Cs={class:"block-head"},xs={class:"block-head-sub"},$s={key:0,class:"empty"},Es={key:1,class:"ops-table"},As={class:"cell-sub"},Rs={key:0,class:"cell-sub"},Ss={class:"cell-sub"},Os={key:0,class:"tag warn"},Ts={key:1,class:"cell-sub"},Us={class:"cell-time"},Vs=["onClick"],Ps=["onClick"],Ds=["disabled","onClick"],Ls={key:0},Ms={class:"modal"},Is={class:"modal-head"},Bs={class:"modal-body"},Gs={class:"form-grid"},Ns={class:"field"},js=["disabled"],Fs={class:"field"},zs={class:"field"},Hs=["value"],Ks={key:0,class:"field"},qs={key:1,class:"field"},Js={class:"perm-area"},Zs={class:"switch-line"},Qs={class:"cell-sub"},Ws={key:0,class:"perm-warn"},Xs={class:"perm-warn-bar"},Ys={class:"cell-sub"},se={key:0,class:"diff missing"},ee={key:1,class:"diff extra"},te={key:0,class:"diff-detail"},le={key:1,class:"perm-grid"},oe={class:"perm-group-title"},ne=["checked","onChange"],ie={key:2,class:"perm-preview"},ae={class:"modal-foot"},de={class:"modal narrow"},ue={class:"modal-head"},re={class:"modal-body"},ce={key:0,class:"ops-error"},pe={class:"field"},me={class:"field"},ve={class:"modal-foot"},fe={class:"modal narrow"},be={class:"modal-head"},we={class:"modal-body"},_e={class:"del-text"},ye={class:"modal-foot"},ke={key:4,class:"ops-toast"},O="/admin/accounts",ge=ns({__name:"index",setup(he){is({title:"账号与权限 - 运营后台"});const{profile:K,restore:q}=ms(),{request:x,guarded:$}=vs(),L=F(()=>K.value),M=_(!1),f=_(""),E=_(""),A=_([]),N=[{title:"数据看板",items:["dashboard.view"]},{title:"学校 / 机构",items:["school.view","school.edit","school.audit"]},{title:"内容管理",items:["content.view","content.edit"]},{title:"AI 采集",items:["harvest.view","harvest.edit"]},{title:"预约",items:["appointment.view","appointment.edit"]},{title:"线索",items:["lead.view","lead.edit"]},{title:"AI 规划线索",items:["ai_lead.view","ai_lead.edit"]},{title:"系统",items:["account.manage"]}],T={"dashboard.view":"查看数据看板","school.view":"查看学校/机构","school.edit":"编辑学校内容","school.audit":"审核发布 / 删除恢复","content.view":"查看文章与配置","content.edit":"编辑发布文章与运营配置","harvest.view":"查看采集工作台","harvest.edit":"采集抓取 / 改写 / 发布","appointment.view":"查看预约","appointment.edit":"处理预约","lead.view":"查看线索","lead.edit":"跟进 / 导出线索","lead.phone":"查看家长完整手机号","ai_lead.view":"查看 AI 规划线索","ai_lead.edit":"跟进 AI 规划线索","account.manage":"账号与权限管理","billing.view":"查看套餐 / 账单","billing.edit":"开通 / 调整套餐","commission.view":"查看佣金","commission.edit":"结算 / 调整佣金","coop_lead.view":"查看合作申请","coop_lead.edit":"处理合作申请","site_config.view":"查看站点配置","site_config.edit":"编辑站点配置","traffic.view":"查看流量统计"},J={super:"err",manager:"warn",editor:"info",viewer:"muted"},U=_(!1),u=_(null),o=H({username:"",display_name:"",role:"editor",password:"Admin@2026",status:"active",custom:!1,permissions:[]});function k(n){return ps[n]||[]}function V(n){return D.find(e=>e.code===n)?.label||n}function Z(n){const e=o.permissions.indexOf(n);e>=0?o.permissions.splice(e,1):o.permissions.push(n)}function Q(){Object.assign(o,{username:"",display_name:"",role:"editor",password:"Admin@2026",status:"active",custom:!1,permissions:[]}),u.value={mode:"create"}}function W(n){Object.assign(o,{username:n.username,display_name:n.display_name||"",role:n.role,password:"",status:n.status,custom:!!n.custom,permissions:n.custom?[...n.permissions||[]]:[...k(n.role)]}),u.value={mode:"edit",row:n}}function X(){o.custom=!1,o.permissions=[...k(o.role)],R("已恢复「"+V(o.role)+"」的默认权限")}function Y(){o.custom&&!o.permissions.length&&(o.permissions=[...k(o.role)])}const h=F(()=>
1{if(!o.custom)return{missing:[],extra:[]};const n=k(o.role),e=o.permissions;return{missing:n.filter(t=>!e.includes(t)),extra:e.filter(t=>!n.includes(t))}});function ss(n){return n?String(n).slice(0,16).replace("T"," "):"—"}function R(n){E.value=n,setTimeout(()=>{E.value===n&&(E.value="")},2400)}async function P(){M.value=!0,f.value="";const n=await $(()=>x("GET",O));M.value=!1,n&&(A.value=n)}async function es(){if(f.value="",u.value?.mode==="create"){if(!/^[A-Za-z0-9_.-]{3,30}$/.test(o.username.trim())){f.value="账号名需为 3-30 位字母 / 数字 / . _ -";return}if(String(o.password).length<6){f.value="初始密码至少 6 位";return}const n={username:o.username.trim(),display_name:o.display_name.trim()||o.username.trim(),role:o.role,password:o.password};o.custom&&(n.permissions=o.permissions),await $(()=>x("POST",O,n))&&(u.value=null,R("账号已创建"),P())}else{const n=u.value?.row;if(!n)return;if(o.custom){if(!o.permissions.length){f.value="已勾选「单独指定权限」但一项都没选,该账号将无法访问任何页面。请勾选所需权限,或关闭开关以继承角色默认。";return}if(!o.permissions.includes("dashboard.view")&&!o.permissions.includes("account.manage")){f.value="当前自定义权限缺少「查看数据看板」(dashboard.view),保存后该账号登录后会提示「无操作权限」,后台各页面均无法打开。请补勾该项,或点「恢复角色默认」。";return}}const e={role:o.role,status:o.status};e.permissions=o.custom?o.permissions:null,await $(()=>x("PUT",`${O}/${n.id}`,e))&&(u.value=null,R("已保存"),P())}}const y=_(null),m=H({password:"",confirm:""}),C=_("");function ts(n){m.password="",m.confirm="",C.value="",y.value={row:n}}async function j(){if(C.value="",String(m.password).length<6){C.value="密码至少 6 位";return}if(m.password!==m.confirm){C.value="两次输入的密码不一致";return}const n=y.value?.row;if(!n)return;await $(()=>x("PUT",`${O}/${n.id}/password`,{password:m.password}))&&(y.value=null,R(`已重置 ${n.username} 的密码`))}const b=_(null);function ls(n){if(n.id===L.value?.uid){f.value="不能删除当前登录的账号";return}b.value={row:n}}async function os(){const n=b.value?.row;if(!n)return;await $(()=>x("DELETE",`${O}/${n.id}`))&&(b.value=null,R(`已删除账号 ${n.username}`),P())}return as(()=>{q(),P()}),(n,e)=>(a(),i("div",fs,[s("div",{class:"ops-page-head"},[e[18]||(e[18]=s("h1",null,"账号与权限",-1)),e[19]||(e[19]=s("p",{class:"ops-page-sub"}," 四级角色:超级管理员 / 运营主管 / 内容编辑 / 只读观察 · 可针对单个账号微调权限 ",-1)),s("button",{class:"ops-btn ops-btn-new",onClick:Q},"+ 新建账号")]),l(f)?(a(),i("div",bs,d(l(f)),1)):c("",!0),s("div",ws,[s("div",{class:"block-head clickable",onClick:e[0]||(e[0]=t=>U.value=!l(U))},[s("span",{class:B(["caret",{open:l(U)}])},"▸",2),e[20]||(e[20]=g(" 角色权限矩阵 ",-1)),e[21]||(e[21]=s("span",{class:"block-head-sub"},"各角色默认权限一览,单个账号可单独指定覆盖",-1))]),w(s("table",_s,[s("thead",null,[s("tr",null,[e[22]||(e[22]=s("th",{style:{width:"260px"}},"权限点",-1)),(a(!0),i(p,null,v(l(D),t=>(a(),i("th",{key:t.code,class:"center"},d(t.label),1))),128))])]),s("tbody",null,[(a(),i(p,null,v(N,t=>(a(),i(p,{key:t.title},[(a(!0),i(p,null,v(t.items,r=>(a(),i("tr",{key:r},[s("td",null,[g(d(T[r]||r)+" ",1),s("span",ys,d(r),1)]),(a(!0),i(p,null,v(l(D),I=>(a(),i("td",{key:I.code,class:"center"},[k(I.code).includes(r)?(a(),i("span",ks,"✓")):(a(),i("span",gs,"—"))]))),128))]))),128))],64))),64))])],512),[[ds,l(U)]])]),s("div",hs,[s("div",Cs,[e[23]||(e[23]=g("后台账号",-1)),s("span",xs,d(l(A).length)+" 个",1)]),l(M)&&!l(A).length?(a(),i("div",$s,"加载中…")):(a(),i("table",Es,[e[25]||(e[25]=s("thead",null,[s("tr",null,[s("th",{style:{width:"200px"}},"账号"),s("th",{style:{width:"120px"}},"角色"),s("th",null,"权限"),s("th",{style:{width:"90px"}},"状态"),s("th",{style:{width:"150px"}},"最近登录"),s("th",{style:{width:"210px"}},"操作")])],-1)),s("tbody",null,[(a(!0),i(p,null,v(l(A),t=>(a(),i("tr",{key:t.id},[s("td",null,[s("strong",null,d(t.username),1),s("div",As,d(t.display_name||"—"),1)]),s("td",null,[s("span",{class:B(["tag",J[t.role]||"muted"])},d(V(t.role)),3),t.id===l(L)?.uid?(a(),i("div",Rs,"当前登录")):c("",!0)]),s("td",Ss,[t.custom?(a(),i("span",Os,"自定义")):(a(),i("span",Ts,"角色默认")),g(" "+d(t.effective_permissions?.length??0)+" 项 ",1)]),s("td",null,[s("span",{class:B(["tag",t.status==="active"?"ok":"muted"])},d(t.status==="active"?"启用":"停用"),3)]),s("td",Us,d(ss(t.last_login_at)),1),s("td",null,[s("button",{class:"ops-mini",onClick:r=>W(t)},"编辑",8,Vs),s("button",{class:"ops-mini",onClick:r=>ts(t)},"重置密码",8,Ps),s("button",{class:"ops-mini danger",disabled:t.id===l(L)?.uid,onClick:r=>ls(t)}," 删除 ",8,Ds)])]))),128)),l(A).length?c("",!0):(a(),i("tr",Ls,[...e[24]||(e[24]=[s("td",{colspan:"6",class:"empty"},"暂无账号",-1)])]))])]))]),l(u)?(a(),i("div",{key:1,class:"modal-mask",onClick:e[9]||(e[9]=G(t=>u.value=null,["self"]))},[s("div",Ms,[s("div",Is,[s("strong",null,d(l(u).mode==="create"?"新建账号":`编辑账号 · ${l(u).row?.username}`),1),s("button",{class:"close",onClick:e[1]||(e[1]=t=>u.value=null)},"×")]),s("div",Bs,[s("div",Gs,[s("div",Ns,[e[26]||(e[26]=s("label",null,"账号名",-1)),w(s("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>l(o).username=t),class:"ops-input full",disabled:l(u).mode==="edit",placeholder:"如:editor01"},null,8,js),[[S,l(o).username]])]),s("div",Fs,[e[27]||(e[27]=s("label",null,"显示名",-1)),w(s("input",{"onUpdate:modelValue":e[3]||(e[3]=t=>l(o).display_name=t),class:"ops-input full",placeholder:"如:内容编辑-小王"},null,512),[[S,l(o).display_name]])]),s("div",zs,[e[28]||(e[28]=s("label",null,"角色",-1)),w(s("select",{"onUpdate:modelValue":e[4]||(e[4]=t=>l(o).role=t),class:"ops-select",style:{width:"100%"}},[(a(!0),i(p,null,v(l(D),t=>(a(),i("option",{key:t.code,value:t.code},d(t.label),9,Hs))),128))],512),[[z,l(o).role]])]),l(u).mode==="create"?(a(),i("div",Ks,[e[29]||(e[29]=s("label",null,"初始密码",-1)),w(s("input",{"onUpdate:modelValue":e[5]||(e[5]=t=>l(o).password=t),class:"ops-input full",placeholder:"默认 Admin@2026"},null,512),[[S,l(o).password]])])):(a(),i("div",qs,[e[31]||(e[31]=s("label",null,"状态",-1)),w(s("select",{"onUpdate:modelValue":e[6]||(e[6]=t=>l(o).status=t),class:"ops-select",style:{width:"100%"}},[...e[30]||(e[30]=[s("option",{value:"active"},"启用",-1),s("option",{value:"disabled"},"停用",-1)])],512),[[z,l(o).status]])]))]),s("div",Js,[s("label",Zs,[w(s("input",{"onUpdate:modelValue":e[7]||
1(e[7]=t=>l(o).custom=t),type:"checkbox",onChange:Y},null,544),[[us,l(o).custom]]),s("span",null,[e[32]||(e[32]=g("单独指定权限",-1)),s("em",Qs,"(不勾选则继承「"+d(V(l(o).role))+"」默认 "+d(k(l(o).role).length)+" 项)",1)])]),l(o).custom?(a(),i("div",Ws,[e[34]||(e[34]=s("strong",null,"⚠ 自定义权限会完全取代角色默认,不是追加",-1)),e[35]||(e[35]=s("p",null," 保存后账号只拥有下面勾选的权限。若漏掉「查看数据看板」,该账号登录后会提示「无操作权限(需要:dashboard.view)」,后台所有页面都打不开。 ",-1)),s("div",Xs,[s("button",{class:"ops-mini",onClick:X},"恢复「"+d(V(l(o).role))+"」默认",1),s("span",Ys,"已选 "+d(l(o).permissions.length)+" 项",1),l(h).missing.length?(a(),i("span",se," 缺少默认项 "+d(l(h).missing.length)+" 个 ",1)):c("",!0),l(h).extra.length?(a(),i("span",ee," 超出默认 "+d(l(h).extra.length)+" 个 ",1)):c("",!0)]),l(h).missing.length?(a(),i("div",te,[e[33]||(e[33]=s("span",{class:"cell-sub"},"缺少:",-1)),(a(!0),i(p,null,v(l(h).missing,t=>(a(),i("span",{key:t,class:"perm-chip chip-bad"},d(T[t]||t),1))),128))])):c("",!0)])):c("",!0),l(o).custom?(a(),i("div",le,[(a(),i(p,null,v(N,t=>s("div",{key:t.title,class:"perm-group"},[s("div",oe,d(t.title),1),(a(!0),i(p,null,v(t.items,r=>(a(),i("label",{key:r,class:"perm-item"},[s("input",{type:"checkbox",checked:l(o).permissions.includes(r),onChange:I=>Z(r)},null,40,ne),s("span",null,d(T[r]||r),1)]))),128))])),64))])):(a(),i("div",ie,[(a(!0),i(p,null,v(k(l(o).role),t=>(a(),i("span",{key:t,class:"perm-chip"},d(T[t]||t),1))),128))]))])]),s("div",ae,[s("button",{class:"ops-btn ghost",onClick:e[8]||(e[8]=t=>u.value=null)},"取消"),s("button",{class:"ops-btn",onClick:es},d(l(u).mode==="create"?"创建":"保存"),1)])])])):c("",!0),l(y)?(a(),i("div",{key:2,class:"modal-mask",onClick:e[14]||(e[14]=G(t=>y.value=null,["self"]))},[s("div",de,[s("div",ue,[s("strong",null,"重置密码 · "+d(l(y).row?.username),1),s("button",{class:"close",onClick:e[10]||(e[10]=t=>y.value=null)},"×")]),s("div",re,[l(C)?(a(),i("div",ce,d(l(C)),1)):c("",!0),s("div",pe,[e[36]||(e[36]=s("label",null,"新密码",-1)),w(s("input",{"onUpdate:modelValue":e[11]||(e[11]=t=>l(m).password=t),type:"password",class:"ops-input full",placeholder:"至少 6 位"},null,512),[[S,l(m).password]])]),s("div",me,[e[37]||(e[37]=s("label",null,"确认新密码",-1)),w(s("input",{"onUpdate:modelValue":e[12]||(e[12]=t=>l(m).confirm=t),type:"password",class:"ops-input full",placeholder:"再次输入",onKeyup:rs(j,["enter"])},null,544),[[S,l(m).confirm]])]),e[38]||(e[38]=s("p",{class:"cell-sub"},"重置后该账号的旧密码立即失效,请通过安全渠道告知使用人。",-1))]),s("div",ve,[s("button",{class:"ops-btn ghost",onClick:e[13]||(e[13]=t=>y.value=null)},"取消"),s("button",{class:"ops-btn",onClick:j},"确认重置")])])])):c("",!0),l(b)?(a(),i("div",{key:3,class:"modal-mask",onClick:e[17]||(e[17]=G(t=>b.value=null,["self"]))},[s("div",fe,[s("div",be,[e[39]||(e[39]=s("strong",null,"删除账号",-1)),s("button",{class:"close",onClick:e[15]||(e[15]=t=>b.value=null)},"×")]),s("div",we,[s("p",_e,[e[40]||(e[40]=g(" 确认删除账号 ",-1)),s("strong",null,d(l(b).row?.username),1),g(" ("+d(l(b).row?.display_name||"—")+")? ",1)]),e[41]||(e[41]=s("p",{class:"cell-sub"}," 该账号为软删除,删除后立即无法登录后台。其历史操作记录会保留。 ",-1))]),s("div",ye,[s("button",{class:"ops-btn ghost",onClick:e[16]||(e[16]=t=>b.value=null)},"取消"),s("button",{class:"ops-btn danger",onClick:os},"确认删除")])])])):c("",!0),l(E)?(a(),i("div",ke,d(l(E)),1)):c("",!0)]))}}),Ae=cs(ge,[["__scopeId","data-v-730bd13f"]]);export{Ae as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.