import React, { useEffect, useState } from "../../../recovery-preview/node_modules/react/index.js"; import { compactText, datetimeLocalToUnix, formatBytes, formatCurrencyFen, formatUnixSeconds, requestJson, unixToDatetimeLocal, } from "../../runtime/client.js"; const initialEditForm = { id: "", email: "", password: "", balance: "", commission_balance: "", commission_type: "", commission_rate: "", group_id: "", plan_id: "", speed_limit: "", device_limit: "", expired_at: "", remarks: "", }; const initialMailForm = { user_id: "", subject: "", content: "", }; function UserManagePage() { const [loading, setLoading] = useState(true); const [refreshTick, setRefreshTick] = useState(0); const [searchInput, setSearchInput] = useState(""); const [keyword, setKeyword] = useState(""); const [rows, setRows] = useState([]); const [pagination, setPagination] = useState({ current: 1, last_page: 1, per_page: 20, total: 0 }); const [plans, setPlans] = useState([]); const [groups, setGroups] = useState([]); const [modal, setModal] = useState(null); const [editForm, setEditForm] = useState(initialEditForm); const [mailForm, setMailForm] = useState(initialMailForm); const [notice, setNotice] = useState(""); const [error, setError] = useState(""); useEffect(() => { let active = true; (async () => { try { const [planResult, groupResult] = await Promise.all([ requestJson("/plan/fetch"), requestJson("/server/group/fetch"), ]); if (!active) { return; } setPlans(Array.isArray(planResult?.data) ? planResult.data : planResult?.list || planResult || []); setGroups(Array.isArray(groupResult?.data) ? groupResult.data : groupResult?.list || groupResult || []); } catch (err) { if (active) { setNotice(err.message || "Reference data failed to load"); } } })(); return () => { active = false; }; }, []); useEffect(() => { let active = true; (async () => { setLoading(true); setError(""); try { const query = new URLSearchParams({ page: String(pagination.current || 1), per_page: String(pagination.per_page || 20), }); if (keyword) { query.set("keyword", keyword); } const payload = await requestJson(`/user/fetch?${query.toString()}`); if (!active) { return; } setRows(Array.isArray(payload?.list) ? payload.list : []); setPagination(payload?.pagination || pagination); } catch (err) { if (active) { setError(err.message || "Failed to load users"); setRows([]); } } finally { if (active) { setLoading(false); } } })(); return () => { active = false; }; }, [keyword, pagination.current, pagination.per_page, refreshTick]); const openEditModal = (user) => { setEditForm({ id: user.id, email: user.email || "", password: "", balance: user.balance ?? "", commission_balance: user.commission_balance ?? "", commission_type: user.commission_type ?? "", commission_rate: user.commission_rate ?? "", group_id: user.group_id ?? "", plan_id: user.plan_id ?? "", speed_limit: user.speed_limit ?? "", device_limit: user.device_limit ?? "", expired_at: unixToDatetimeLocal(user.expired_at), remarks: user.remarks || "", }); setModal({ type: "edit", user }); }; const openMailModal = (user) => { setMailForm({ user_id: user.id, subject: `Hello ${user.email}`, content: "", }); setModal({ type: "mail", user }); }; const submitSearch = (event) => { event.preventDefault(); setPagination((current) => ({ ...current, current: 1 })); setKeyword(compactText(searchInput)); }; const reload = () => setRefreshTick((value) => value + 1); const saveUser = async (event) => { event.preventDefault(); setNotice(""); setError(""); try { const payload = { id: Number(editForm.id), email: compactText(editForm.email), password: compactText(editForm.password) || undefined, balance: toNullableNumber(editForm.balance), commission_balance: toNullableNumber(editForm.commission_balance), commission_type: toNullableNumber(editForm.commission_type), commission_rate: toNullableNumber(editForm.commission_rate), group_id: toNullableNumber(editForm.group_id), plan_id: toNullableNumber(editForm.plan_id), speed_limit: toNullableNumber(editForm.speed_limit), device_limit: toNullableNumber(editForm.device_limit), expired_at: datetimeLocalToUnix(editForm.expired_at), remarks: compactText(editForm.remarks), }; pruneUndefined(payload); await requestJson("/user/update", { method: "POST", body: payload }); setModal(null); reload(); } catch (err) { setError(err.message || "Failed to save user"); } }; const resetSecret = async (user) => { if (!window.confirm(`Reset secret for ${user.email}?`)) { return; } try { const payload = await requestJson("/user/resetSecret", { method: "POST", body: { id: user.id }, }); setNotice(typeof payload?.data === "string" ? `Secret reset: ${payload.data}` : "Secret reset"); reload(); } catch (err) { setError(err.message || "Failed to reset secret"); } }; const resetTraffic = async (user) => { if (!window.confirm(`Reset traffic for ${user.email}?`)) { return; } try { await requestJson("/user/resetTraffic", { method: "POST", body: { id: user.id }, }); setNotice("Traffic reset complete"); reload(); } catch (err) { setError(err.message || "Failed to reset traffic"); } }; const toggleBan = async (user) => { const banned = !Boolean(user.banned); if (!window.confirm(`${banned ? "Ban" : "Unban"} ${user.email}?`)) { return; } try { await requestJson("/user/ban", { method: "POST", body: { id: user.id, banned }, }); reload(); } catch (err) { setError(err.message || "Failed to update status"); } }; const deleteUser = async (user) => { if (!window.confirm(`Delete ${user.email}?`)) { return; } try { await requestJson("/user/drop", { method: "POST", body: { id: user.id }, }); reload(); } catch (err) { setError(err.message || "Failed to delete user"); } }; const saveMail = async (event) => { event.preventDefault(); try { await requestJson("/user/sendMail", { method: "POST", body: { user_id: Number(mailForm.user_id), subject: compactText(mailForm.subject), content: compactText(mailForm.content), }, }); setModal(null); setNotice("Mail submitted"); } catch (err) { setError(err.message || "Failed to send mail"); } }; return (

Recovered React Page

User Management

Search, edit, ban, reset traffic, and reset secrets against the live admin API.

{pagination.total}users
{pagination.current}page
{plans.length}plans
setSearchInput(event.target.value)} placeholder="Search by email or ID" />
{notice ?
{notice}
: null} {error ?
{error}
: null}
{loading ? ( ) : rows.length === 0 ? ( ) : rows.map((user) => ( ))}
ID User Plan / Group Traffic Balance Status Updated Actions
Loading...
No users found
{user.id}
{user.email} UID: {user.id} {user.online_ip ? {user.online_ip} : null}
{user.plan_name || `Plan ${user.plan_id || "-"}`} {user.group_name || `Group ${user.group_id || "-"}`}
{formatBytes(user.transfer_enable)} Used {formatBytes(Number(user.u || 0) + Number(user.d || 0))}
{formatCurrencyFen(user.balance)} Comm {formatCurrencyFen(user.commission_balance)}
{user.banned ? "Banned" : "Active"} {formatUnixSeconds(user.updated_at || user.last_login_at || user.created_at)}
Page {pagination.current} / {pagination.last_page}
{modal?.type === "edit" ? ( setModal(null)}>