2 lines
9.2 KiB
JavaScript
2 lines
9.2 KiB
JavaScript
import{r,X as K,_ as V,Y as T,n as y,E as e,V as R,I as u,F as H,Z as o,J as Z,$ as G,a0 as J,L as b,a1 as F,Q as P,U as I,A as z,a2 as Q,T as W,P as C,S as X,G as Y}from"./index-CSGym-Bq.js";import{A as $,P as O,S as ee,M as se,a as ae}from"./Table-B79wm3oj.js";import"./index-Di2wY8BS.js";var te={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M608 112c-167.9 0-304 136.1-304 304 0 70.3 23.9 135 63.9 186.5L255.8 713.6l-62.3-62.3a8.19 8.19 0 00-11.4 0l-39.8 39.8a8.19 8.19 0 000 11.4l62.3 62.3-44.9 44.9-62.3-62.3a8.19 8.19 0 00-11.4 0l-39.8 39.8a8.19 8.19 0 000 11.4l110.3 111.2c3.1 3.1 8.2 3.1 11.3 0l253.6-253.6A304.1 304.1 0 00608 720c167.9 0 304-136.1 304-304S775.9 112 608 112m161.2 465.2C726.2 620.3 668.9 644 608 644s-118.2-23.7-161.2-66.8C403.7 534.2 380 476.9 380 416s23.7-118.2 66.8-161.2c43-43.1 100.3-66.8 161.2-66.8s118.2 23.7 161.2 66.8c43.1 43 66.8 100.3 66.8 161.2s-23.7 118.2-66.8 161.2"}}]},name:"key",theme:"outlined"},ne=function(m,i){return r.createElement(K,V({},m,{ref:i,icon:te}))},re=r.forwardRef(ne);const{Text:h}=W;function ie({token:l,currentUser:m,nodes:i,onChanged:j}){const{message:d}=T.useApp(),[f,k]=r.useState([]),[S,w]=r.useState(!1),[N,x]=r.useState(!1),[a,n]=r.useState(null),[p,A]=r.useState(null),[g]=o.useForm(),[v]=o.useForm(),_=r.useCallback(async()=>{w(!0);try{const s=await y("/v1/users",{token:l});k(s.users||[])}catch(s){d.error(s.message)}finally{w(!1)}},[d,l]);r.useEffect(()=>{_()},[_]);const D=r.useMemo(()=>new Map(i.map(s=>[s.node_id,s])),[i]),E=()=>{n(null),g.resetFields(),g.setFieldsValue({role:"member",active:!0,node_ids:[]}),x(!0)},M=s=>{n(s),g.resetFields(),g.setFieldsValue({username:s.username,display_name:s.display_name,role:s.role,active:s.active,node_ids:s.node_ids||[]}),x(!0)},U=async s=>{const t={username:s.username,display_name:s.display_name,role:s.role,active:s.active,node_ids:s.role==="member"?s.node_ids||[]:[]};try{a?await y(`/v1/users/${encodeURIComponent(a.id)}`,{token:l,method:"PATCH",body:{display_name:t.display_name,role:t.role,active:t.active,node_ids:t.node_ids}}):await y("/v1/users",{token:l,method:"POST",body:{...t,password:s.password}}),d.success(a?"用户权限已更新":"用户已创建"),x(!1),await _(),j==null||j()}catch(c){d.error(c.message)}},q=async(s,t)=>{try{await y(`/v1/users/${encodeURIComponent(s.id)}`,{token:l,method:"PATCH",body:{display_name:s.display_name,role:s.role,active:t,node_ids:s.node_ids||[]}}),d.success(t?"用户已启用":"用户已停用,现有会话已撤销"),await _()}catch(c){d.error(c.message)}},B=async s=>{try{await y(`/v1/users/${encodeURIComponent(p.id)}/password`,{token:l,method:"POST",body:{password:s.password}}),d.success("密码已重置,该用户的现有会话已撤销"),A(null),v.resetFields()}catch(t){d.error(t.message)}},L=[{title:"用户",dataIndex:"username",key:"user",render:(s,t)=>{var c;return e.jsxs(I,{children:[e.jsx(z,{size:"small",icon:e.jsx(Y,{}),children:(c=t.display_name)==null?void 0:c.slice(0,1)}),e.jsxs("span",{children:[e.jsx(h,{strong:!0,children:t.display_name}),e.jsx("br",{}),e.jsx(h,{type:"secondary",children:t.username})]})]})}},{title:"角色",dataIndex:"role",width:130,render:s=>e.jsx(C,{color:s==="admin"?"blue":"default",children:s==="admin"?"管理员":"成员"})},{title:"可访问 Desktop Agent / Node",dataIndex:"node_ids",render:(s,t)=>t.role==="admin"?e.jsx(h,{type:"secondary",children:"全部 Node"}):s!=null&&s.length?e.jsx(I,{wrap:!0,children:s.map(c=>e.jsx(C,{color:D.has(c)?"geekblue":"default",children:c},c))}):e.jsx(h,{type:"secondary",children:"尚未分配"})},{title:"状态",dataIndex:"active",width:100,render:s=>e.jsx(C,{color:s?"success":"default",children:s?"启用":"停用"})},{title:"创建时间",dataIndex:"created_at",width:175,render:R},{title:"操作",key:"actions",width:230,valueType:"option",render:(s,t)=>e.jsxs(I,{size:4,children:[e.jsx(u,{type:"link",size:"small",onClick:()=>M(t),children:"编辑与分配"}),e.jsx(u,{type:"link",size:"small",icon:e.jsx(re,{}),onClick:()=>{A(t),v.resetFields()},children:"重置密码"}),e.jsx(ae,{title:t.active?"停用此账号?":"重新启用此账号?",description:t.active?"该用户的现有会话将被撤销。":void 0,onConfirm:()=>void q(t,!t.active),disabled:t.id===m.id,children:e.jsx(u,{type:"link",size:"small",disabled:t.id===m.id,children:t.active?"停用":"启用"})})]})}];return e.jsxs("div",{className:"admin-page-stack",children:[e.jsx($,{type:"info",showIcon:!0,message:"用户与 Node 权限使用真实控制面数据库",description:"管理员拥有全部 Node 访问权;成员只可访问明确分配的 Desktop Agent / Node。环境变量中的旧 Web 账号仅在用户表首次初始化时导入为管理员。"}),e.jsx(O,{rowKey:"id",headerTitle:`控制面用户 · ${f.length}`,columns:L,dataSource:f,loading:S,search:!1,options:!1,scroll:{x:"max-content",y:"max(100px, calc(100dvh - 500px))"},pagination:{pageSize:10,showSizeChanger:!0},toolBarRender:()=>[e.jsx(u,{icon:e.jsx(Z,{}),onClick:()=>void _(),children:"刷新"},"reload"),e.jsx(u,{type:"primary",icon:e.jsx(G,{}),onClick:E,children:"创建用户"},"create")]}),e.jsx(J,{title:a?"编辑用户与 Node 分配":"创建控制面用户",width:520,open:N,onClose:()=>x(!1),destroyOnClose:!0,children:e.jsxs(o,{form:g,layout:"vertical",onFinish:U,requiredMark:"optional",children:[e.jsx(o.Item,{name:"username",label:"用户名",rules:[{required:!0,min:3,max:64,pattern:/^[A-Za-z0-9._@-]+$/,message:"使用 3–64 位字母、数字或 . _ @ -"}],children:e.jsx(b,{disabled:!!a,autoComplete:"username"})}),e.jsx(o.Item,{name:"display_name",label:"显示名称",rules:[{required:!0,max:120}],children:e.jsx(b,{maxLength:120})}),!a&&e.jsx(o.Item,{name:"password",label:"初始密码",rules:[{required:!0,min:12,message:"密码至少 12 个字符"}],children:e.jsx(b.Password,{autoComplete:"new-password"})}),e.jsx(o.Item,{name:"role",label:"角色",rules:[{required:!0}],children:e.jsx(F,{options:[{value:"member",label:"成员(按分配 Node 隔离)"},{value:"admin",label:"管理员(可管理用户并访问全部 Node)"}],disabled:(a==null?void 0:a.id)===m.id})}),e.jsx(o.Item,{noStyle:!0,shouldUpdate:(s,t)=>s.role!==t.role,children:({getFieldValue:s})=>s("role")==="member"?e.jsx(o.Item,{name:"node_ids",label:"分配 Desktop Agent / Node",children:e.jsx(F,{mode:"multiple",allowClear:!0,showSearch:!0,optionFilterProp:"label",placeholder:"选择此成员可访问的 Node",options:i.map(t=>({value:t.node_id,label:`${t.node_id} · ${P(t.status)}`}))})}):e.jsx($,{type:"info",showIcon:!0,message:"管理员可访问全部 Node;管理员账号不使用成员分配列表。"})}),a&&e.jsx(o.Item,{name:"active",label:"账号状态",valuePropName:"checked",children:e.jsx(ee,{checkedChildren:"启用",unCheckedChildren:"停用",disabled:a.id===m.id})}),e.jsxs("div",{className:"drawer-footer",children:[e.jsx(u,{onClick:()=>x(!1),children:"取消"}),e.jsx(u,{type:"primary",htmlType:"submit",children:a?"保存变更":"创建用户"})]})]})}),e.jsx(se,{title:`重置密码 · ${(p==null?void 0:p.username)||""}`,open:!!p,onCancel:()=>A(null),onOk:()=>v.submit(),okText:"重置并撤销会话",destroyOnClose:!0,children:e.jsx(o,{form:v,layout:"vertical",onFinish:B,children:e.jsx(o.Item,{name:"password",label:"新密码",rules:[{required:!0,min:12,message:"密码至少 12 个字符"}],children:e.jsx(b.Password,{autoComplete:"new-password"})})})})]})}function ce({token:l,nodes:m,isAdmin:i,onGoUsers:j}){const{message:d}=T.useApp(),[f,k]=r.useState([]),[S,w]=r.useState(!1);r.useEffect(()=>{if(!i)return;let a=!0;return w(!0),y("/v1/users",{token:l}).then(n=>{a&&k(n.users||[])}).catch(n=>d.error(n.message)).finally(()=>{a&&w(!1)}),()=>{a=!1}},[i,d,l]);const N=r.useMemo(()=>{const a=new Map;for(const n of f)if(!(n.role!=="member"||!n.active))for(const p of n.node_ids||[])a.set(p,[...a.get(p)||[],n.display_name||n.username]);return a},[f]),x=[{title:"Desktop Agent / Node",dataIndex:"node_id",key:"node_id",render:a=>e.jsxs(I,{children:[e.jsx(z,{size:"small",icon:e.jsx(Q,{})})," ",e.jsx(h,{strong:!0,children:a})]})},{title:"连接状态",dataIndex:"status",width:130,render:a=>e.jsx(C,{color:X(a),children:P(a)})},{title:"活动账号",dataIndex:"active_account_id",render:a=>a||e.jsx(h,{type:"secondary",children:"未确认"})},{title:"最近心跳",dataIndex:"last_heartbeat_at",width:180,render:R},{title:"Agent 版本",dataIndex:"agent_version",width:150,render:a=>a||"—"},{title:"账号",dataIndex:"accounts",width:90,render:a=>(a==null?void 0:a.length)||0},...i?[{title:"已分配成员",dataIndex:"node_id",render:a=>{var n;return S?"读取中…":((n=N.get(a))==null?void 0:n.join("、"))||e.jsx(h,{type:"secondary",children:"未分配"})}}]:[]];return e.jsxs("div",{className:"admin-page-stack",children:[e.jsx($,{type:"info",showIcon:!0,message:"这里管理的是已连接的 Desktop Agent / Node",description:"成员分配按 Node 生效,并同时约束该 Node 下已授权微信账号的消息、通讯录、事件与任务接口。AI Flow 不是本页面中的 Desktop Agent。"}),e.jsx(O,{rowKey:"node_id",headerTitle:`已授权节点 · ${m.length}`,columns:x,dataSource:m,search:!1,options:!1,scroll:{x:"max-content",y:"max(100px, calc(100dvh - 500px))"},pagination:{pageSize:10},toolBarRender:i?()=>[e.jsx(u,{icon:e.jsx(H,{}),onClick:j,children:"管理用户分配"},"users")]:!1})]})}export{ce as NodesView,ie as UsersView};
|