PageSourceSearch

https://nickz.ai/assets/js/index-DBhtkjoi.js

js nickz.ai collected 2026-10-05 14:20:35 UTC 7,355 bytes, 1 lines download raw bytes

1import{r as e,j as t}from"./vendor-react-DejgYtBM.js";import{f as a,m as s,j as i,i as n,F as r,B as o,l,y as d,Y as u}from"./vendor-semi-D8d7bTtM.js";import{i as c,V as m}from"./vendor-charts-CKochBGt.js";import{u as h,A as y,s as p,V as x,N as g}from"./index-BeIIFw6E.js";import{x as b,R as j}from"./vendor-icons-EJvJ5X-w.js";import"./vendor-motion-Chfy_MiU.js";const{Title:f,Text:v}=a,k={mode:"desktop-browser"},_=[1,10,50,100,1e3,1e4,1e5,1e6],w=()=>{const{t:a,i18n:w}=h(),[S,z]=e.useState(!1),[q,C]=e.useState(!1),[I,N]=e.useState(null),[B,M]=e.useState([]),[L,R]=e.useState(!1),[T,$]=e.useState(""),[D,E]=e.useState(!1),[F,W]=e.useState(null);e.useEffect(()=>{c({isWatchingMode:!0}),K()},[]),e.useEffect(()=>{L&&P()},[L]),e.useEffect(()=>{I&&Y(I)},[w.language]);const K=async()=>{try{const e=await y.get("/api/user/quota_distribution/excludes"),{success:t,data:a}=e.data;t&&M(a||[])}catch{}finally{R(!0)}},Q=e.useCallback(async e=>{C(!0);try{const t=await y.put("/api/user/quota_distribution/excludes",{ids:e.map(e=>e.id)}),{success:s,message:i}=t.data;s||p(i||a("保存排除列表失败"))}catch(t){p(t.message)}finally{C(!1)}},[a]),V=e.useCallback(()=>{const e=x();return!e||e<=0?[]:_.map(t=>Math.round(t*e))},[]),A=e.useCallback((e,t)=>{const s=x();if(0===e&&0===t)return a("零总额");if(-1===t){const t=s>0?Math.round(e/s):e;return a("> {{count}} 单位",{count:t.toLocaleString()})}const i=s>0?Math.round(t/s):t;if(e<=1)return a("< {{count}} 单位",{count:i.toLocaleString()});const n=s>0?Math.round(e/s):e;return a("{{min}} ~ {{max}} 单位",{min:n.toLocaleString(),max:i.toLocaleString()})},[a]),P=e.useCallback(async()=>{z(!0);try{const e=V().join(","),t={};e&&(t.thresholds=e);const s=await y.get("/api/user/quota_distribution",{params:t}),{success:i,data:n,message:r}=s.data;i?(N(n),Y(n)):p(r||a("获取数据失败"))}catch(e){p(e.message)}finally{z(!1)}},[V,a]),Y=e=>{if(!e||!e.buckets)return;const t=e.buckets.map(e=>({label:A(Number(e.min),Number(e.max)),count:Number(e.count),totalQuota:Number(e.total_quota)}));W({type:"bar",data:[{id:"bucketData",values:t}],xField:"label",yField:"count",label:{visible:!0,position:"top",formatMethod:e=>a("{{count}} 人",{count:e})},tooltip:{mark:{content:[{key:a("用户数"),value:e=>a("{{count}} 人",{count:e.count})},{key:a("区间总额(余额+已用)"),value:e=>g(e.totalQuota,4)}]}},title:{visible:!0,text:a("用户总额分布(余额 + 已用余额)"),subtext:a("参与统计用户:{{total}} 人(已排除 {{excluded}} 个账号)",{total:e.total_users,excluded:e.excluded_count})},bar:{state:{hover:{stroke:"#000",lineWidth:1}}}})},G=async()=>{const e=T.trim();if(!e)return;if(!/^\d+$/.test(e))return void u.warning(a("请输入纯数字用户 ID"));const t=parseInt(e,10);if(B.find(e=>e.id===t))u.warning(a("该用户已在排除列表中"));else{E(!0);try{const t=await y.get("/api/user/search",{params:{user_id:e,page:1,page_size:1}}),{success:s,data:i}=t.data,n=i?.items||i||[];if(!s||0===n.length)return void u.error(a("未找到 ID 为 {{id}} 的用户",{id:e}));const r=n[0],o=[...B,{id:r.id,username:r.username,display_name:r.display_name||""}];M(o),Q(o),$("")}catch(s){p(s.message)}finally{E(!1)}}},H=I?.total_users||0,J=I?.total_quota||0,O=I?.total_current_quota||0,U=H>0?Math.floor(J/H):0,X=I?.top_users?.[0]?.quota||0,Z=[{label:a("参与统计用户数"),value:a("{{count}} 人",{count:H})},{label:a("需预留余额(当前余额)"),value:g(O,2)},{label:a("用户总分配额(余额+已用)"),value:g(J,2)},{label:a("人均总额"),value:g(U,2)},{label:a("最高单用户总额"),value:g(X,2)}],ee=[{title:a("总额区间(余额+已用)"),key:"label",render:(e,t)=>A(Number(t.min),Number(t.max))},{title:a("用户数"),dataIndex:"count",key:"count",render:e=>Number(e).toLocaleString()},{title:a("用户占比"),key:"user_pct",render:(e,t)=>H>0?`${(Number(t.count)/H*100).toFixed(1)}%`:"0%"},{title:a("区间总额"),key:"total_quota",render:(e,t)=>g(t.total_quota,2)},{title:a("总额占比"),key:"quota_pct",render:(e,t)=>J>0?`${(Number(t.total_quota)/J*100).toFixed(1)}%`:"0%"}],te=[{title:a("排名"),key:"rank",render:(e,t,a)=>a+1,width:60},{title:"ID",dataIndex:"id",key:"id",width:80},{title:a("用户名"),dataIndex:"username",key:"username"},{title:a("显示名"),dataIndex:"display_name",key:"display_name",render:e=>e||"-"},{title:a("总额(余额+已用)"),key:"quota",render:(e,t)=>g(t.quota,2)}];return t.jsx("div",{style:{marginTop:64,padding:16},children:t.jsxs("div",{style:{maxWidth:1200,margin:"0 auto"},children:[t.jsx(f,{heading:2,style:{marginBottom:16},children:a("用户总额分布统计(余额 + 已用余额)")}),t.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(220px, 1fr))",gap:16,marginBottom:16},children:Z.map(e=>t.jsxs(s,{shadows:"hover",style:{borderRadius:12},bodyStyle:{padding:"16px 20px"},children:[t.jsx(v,{type:"tertiary",size:14,children:e.label}),t.jsx("div",{style:{fontSize:22,fontWeight:700,marginTop:4},children:e.value})]},e.label))}),t.jsxs(s,{shadows:"hover",style:{borderRadius:12,marginBottom:16},title:a("排除账号(后付费/内部账号)"),headerExtraContent:t.jsxs(i,{children:[q&&t.jsx(l,{size:14}),t.jsx(o,{icon:t.jsx(j,{size:16}),onClick:P,loading:S,type:"tertiary",size:"small",children:a("刷新统计")})]}),children:[t.jsx(v,{type:"tertiary",size:14,style:{display:"block",marginBottom:10},children:a("排除列表保存在数据库中,重启后依然生效。被排除的用户不计入余额统计。")}),t.jsxs(i,{wrap:!0,style:{marginBottom:12},children:[B.map(e=>t.jsxs(n,{closable:!0,onClose:()=>(e=>{const t=B.filter(t=>t.id!==e);M(t),Q(t)})(e.id),color:"orange",size:"large",children:[e.username||e.display_name||`#${e.id}`,t.jsxs(v,{type:"tertiary",size:14,style:{marginLeft:4},children:["#",e.id]})]},e.id)),0===B.length&&t.jsx(v,{type:"tertiary",children:a("暂无排除账号")})]}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx(r,{value:T,onChange:$,onEnterPress:G,placeholder:a("输入用户 ID,按回车添加"),style:{width:220},type:"number",min:1}),t.jsx(o,{icon:t.jsx(b,{size:16}),onClick:G,loading:D,theme:"solid",size:"small",children:a("添加")}),B.length>0&&t.jsx(o,{type:"danger",theme:"borderless",size:"small",onClick:()=>{M([]),Q([])},children:a("清空排除列表")})]})]}),t.jsx(s,{shadows:"hover",style:{borderRadius:12,marginBottom:16}
1,title:a("总额区间分布图(余额 + 已用余额)"),children:t.jsx(l,{spinning:S,children:F?t.jsx("div",{style:{height:340},children:t.jsx(m,{spec:F,option:k})}):t.jsx("div",{style:{height:340,display:"flex",alignItems:"center",justifyContent:"center"},children:t.jsx(v,{type:"tertiary",children:a("暂无数据")})})})}),t.jsx(s,{shadows:"hover",style:{borderRadius:12,marginBottom:16},title:a("总额区间详情(余额 + 已用余额)"),children:t.jsx(l,{spinning:S,children:t.jsx(d,{columns:ee,dataSource:I?.buckets||[],rowKey:e=>`${e.min}_${e.max}`,pagination:!1,size:"small"})})}),t.jsx(s,{shadows:"hover",style:{borderRadius:12,marginBottom:16},title:a("高总额用户 Top {{count}}(按余额 + 已用余额排序)",{count:(I?.top_users||[]).length}),children:t.jsx(l,{spinning:S,children:t.jsx(d,{columns:te,dataSource:I?.top_users||[],rowKey:"id",pagination:!1,size:"small"})})})]})})};export{w 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.