基本功能已初步完善
This commit is contained in:
@@ -195337,21 +195337,6 @@ const DQe =
|
||||
{ path: "subscribe-template", element: Q.jsx(LQe, {}) },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "payment",
|
||||
lazy: async () => ({
|
||||
Component: (
|
||||
await xp(
|
||||
async () => {
|
||||
const { default: e } = await Promise.resolve().then(() => kXt);
|
||||
return { default: e };
|
||||
},
|
||||
void 0,
|
||||
import.meta.url,
|
||||
)
|
||||
).default,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "plugin",
|
||||
lazy: async () => ({
|
||||
@@ -195499,36 +195484,6 @@ const DQe =
|
||||
).default,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "coupon",
|
||||
lazy: async () => ({
|
||||
Component: (
|
||||
await xp(
|
||||
async () => {
|
||||
const { default: e } = await Promise.resolve().then(() => z3t);
|
||||
return { default: e };
|
||||
},
|
||||
void 0,
|
||||
import.meta.url,
|
||||
)
|
||||
).default,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "gift-card",
|
||||
lazy: async () => ({
|
||||
Component: (
|
||||
await xp(
|
||||
async () => {
|
||||
const { default: e } = await Promise.resolve().then(() => d6t);
|
||||
return { default: e };
|
||||
},
|
||||
void 0,
|
||||
import.meta.url,
|
||||
)
|
||||
).default,
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -195565,6 +195520,18 @@ const DQe =
|
||||
).default,
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "realname",
|
||||
lazy: async () => ({ Component: codexNativeRealnamePage }),
|
||||
},
|
||||
{
|
||||
path: "online-devices",
|
||||
lazy: async () => ({ Component: codexNativeOnlineDevicesPage }),
|
||||
},
|
||||
{
|
||||
path: "ipv6-subscription",
|
||||
lazy: async () => ({ Component: codexNativeIPv6Page }),
|
||||
},
|
||||
{
|
||||
path: "traffic-reset-logs",
|
||||
lazy: async () => ({
|
||||
@@ -233443,17 +233410,11 @@ var Zst = {
|
||||
href: "/config/system",
|
||||
icon: Q.jsx(Kf, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:pluginManagement",
|
||||
label: "",
|
||||
href: "/config/plugin",
|
||||
icon: Q.jsx(Fat, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:themeConfig",
|
||||
label: "",
|
||||
href: "/config/theme",
|
||||
icon: Q.jsx(im, { size: 18 }),
|
||||
icon: Q.jsx(Kf, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:noticeManagement",
|
||||
@@ -233461,12 +233422,6 @@ var Zst = {
|
||||
href: "/config/notice",
|
||||
icon: Q.jsx(pm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:paymentConfig",
|
||||
label: "",
|
||||
href: "/config/payment",
|
||||
icon: Q.jsx(tm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:knowledgeManagement",
|
||||
label: "",
|
||||
@@ -233519,18 +233474,6 @@ var Zst = {
|
||||
href: "/finance/order",
|
||||
icon: Q.jsx(tm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:couponManagement",
|
||||
label: "",
|
||||
href: "/finance/coupon",
|
||||
icon: Q.jsx(rm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "nav:giftCardManagement",
|
||||
label: "",
|
||||
href: "/finance/gift-card",
|
||||
icon: Q.jsx(lm, { size: 18 }),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -233551,6 +233494,24 @@ var Zst = {
|
||||
href: "/user/ticket",
|
||||
icon: Q.jsx(xm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "实名认证",
|
||||
label: "",
|
||||
href: "/user/realname",
|
||||
icon: Q.jsx(xm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "在线 IP 统计",
|
||||
label: "",
|
||||
href: "/user/online-devices",
|
||||
icon: Q.jsx(xm, { size: 18 }),
|
||||
},
|
||||
{
|
||||
title: "IPv6 子账号",
|
||||
label: "",
|
||||
href: "/user/ipv6-subscription",
|
||||
icon: Q.jsx(xm, { size: 18 }),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -264036,26 +263997,6 @@ function x$t({ className: e }) {
|
||||
return Q.jsxs("div", {
|
||||
className: Rf("grid gap-4 md:grid-cols-2 lg:grid-cols-4", e),
|
||||
children: [
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.todayIncome"),
|
||||
value: DS(i.todayIncome),
|
||||
icon: Q.jsx(Jst, { className: "h-4 w-4 text-emerald-500" }),
|
||||
trend: {
|
||||
value: i.dayIncomeGrowth,
|
||||
label: n("dashboard:stats.vsYesterday"),
|
||||
isPositive: i.dayIncomeGrowth > 0,
|
||||
},
|
||||
}),
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.monthlyIncome"),
|
||||
value: DS(i.currentMonthIncome),
|
||||
icon: Q.jsx(rat, { className: "h-4 w-4 text-blue-500" }),
|
||||
trend: {
|
||||
value: i.monthIncomeGrowth,
|
||||
label: n("dashboard:stats.vsLastMonth"),
|
||||
isPositive: i.monthIncomeGrowth > 0,
|
||||
},
|
||||
}),
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.pendingTickets"),
|
||||
value: i.ticketPendingTotal,
|
||||
@@ -264072,38 +264013,6 @@ function x$t({ className: e }) {
|
||||
onClick: () => t("/user/ticket"),
|
||||
highlight: i.ticketPendingTotal > 0,
|
||||
}),
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.pendingCommission"),
|
||||
value: i.commissionPendingTotal,
|
||||
icon: Q.jsx(oat, {
|
||||
className: Rf(
|
||||
"h-4 w-4",
|
||||
i.commissionPendingTotal > 0 ? "text-blue-500" : "text-muted-foreground",
|
||||
),
|
||||
}),
|
||||
description:
|
||||
i.commissionPendingTotal > 0
|
||||
? n("dashboard:stats.hasPendingCommission")
|
||||
: n("dashboard:stats.noPendingCommission"),
|
||||
onClick: () => {
|
||||
const e = new URLSearchParams();
|
||||
(e.set("commission_status", c$t.PENDING.toString()),
|
||||
e.set("status", o$t.COMPLETED.toString()),
|
||||
e.set("commission_balance", "gt:0"),
|
||||
t(`/finance/order?${e.toString()}`));
|
||||
},
|
||||
highlight: i.commissionPendingTotal > 0,
|
||||
}),
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.monthlyNewUsers"),
|
||||
value: i.currentMonthNewUsers,
|
||||
icon: Q.jsx(dlt, { className: "h-4 w-4 text-blue-500" }),
|
||||
trend: {
|
||||
value: i.userGrowth,
|
||||
label: n("dashboard:stats.vsLastMonth"),
|
||||
isPositive: i.userGrowth > 0,
|
||||
},
|
||||
}),
|
||||
Q.jsx(y$t, {
|
||||
title: n("dashboard:stats.totalUsers"),
|
||||
value: i.totalUsers,
|
||||
@@ -269438,7 +269347,7 @@ const tGt = Object.freeze(
|
||||
className: "space-y-6",
|
||||
children: Q.jsxs("div", {
|
||||
className: "grid gap-6",
|
||||
children: [Q.jsx(x$t, {}), Q.jsx(t$t, {}), Q.jsx(dqt, {}), Q.jsx(eGt, {})],
|
||||
children: [Q.jsx(x$t, {}), Q.jsx(dqt, {}), Q.jsx(eGt, {})],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
@@ -293836,23 +293745,27 @@ const I5t = {
|
||||
Q.jsxs("span", {
|
||||
className: "flex flex-col items-start gap-0.5 leading-tight",
|
||||
children: [
|
||||
Q.jsx("span", { className: "flex items-center gap-0.5", children: i ?? n }),
|
||||
e.parent
|
||||
? Q.jsxs("span", {
|
||||
className: "flex items-center gap-1",
|
||||
children: [
|
||||
Q.jsx("span", { children: n }),
|
||||
Q.jsx("span", {
|
||||
className: "text-sm text-muted-foreground/30",
|
||||
children: "\u2192",
|
||||
}),
|
||||
Q.jsx("span", { children: e.parent_id ?? e.parent?.id }),
|
||||
],
|
||||
})
|
||||
: Q.jsx("span", {
|
||||
className: "flex items-center gap-0.5",
|
||||
children: n,
|
||||
}),
|
||||
i &&
|
||||
Q.jsxs("span", {
|
||||
className: "font-mono text-[10px] text-muted-foreground",
|
||||
children: [t("columns.originalId"), ": ", n],
|
||||
children: [t("columns.customId"), ": ", i],
|
||||
}),
|
||||
e.parent
|
||||
? Q.jsxs(Q.Fragment, {
|
||||
children: [
|
||||
Q.jsx("span", {
|
||||
className: "text-sm text-muted-foreground/30",
|
||||
children: "→",
|
||||
}),
|
||||
Q.jsx("span", { children: e.parent?.code || e.parent?.id }),
|
||||
],
|
||||
})
|
||||
: null,
|
||||
],
|
||||
}),
|
||||
],
|
||||
@@ -304571,6 +304484,496 @@ function l8t() {
|
||||
})
|
||||
);
|
||||
}
|
||||
function codexNativePageLayout(e, t, n) {
|
||||
return Q.jsxs(Wot, {
|
||||
children: [
|
||||
Q.jsxs(Hot, {
|
||||
children: [
|
||||
Q.jsx(Vdt, {}),
|
||||
Q.jsxs("div", {
|
||||
className: "ml-auto flex items-center space-x-4",
|
||||
children: [Q.jsx(Wdt, {}), Q.jsx(vut, {})],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Q.jsxs(zot, {
|
||||
className: "flex flex-col",
|
||||
fixedHeight: !0,
|
||||
children: [
|
||||
Q.jsx("div", {
|
||||
className: "mb-2 flex items-center justify-between space-y-2",
|
||||
children: Q.jsxs("div", {
|
||||
children: [
|
||||
Q.jsx("h2", { className: "text-2xl font-bold tracking-tight", children: e }),
|
||||
Q.jsx("p", { className: "mt-2 text-muted-foreground", children: t }),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
Q.jsx("div", {
|
||||
className: "-mx-4 flex-1 overflow-auto px-4 py-1 lg:flex-row lg:space-x-12 lg:space-y-0",
|
||||
children: Q.jsx("div", { className: "w-full", children: n }),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeStatusBadge(e) {
|
||||
const t = String(e || "-").toLowerCase(),
|
||||
n = /approved|active|enabled|ready/.test(t)
|
||||
? "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400"
|
||||
: /pending|eligible|unverified/.test(t)
|
||||
? "bg-yellow-500/15 text-yellow-700 dark:text-yellow-400"
|
||||
: "bg-destructive/10 text-destructive";
|
||||
return Q.jsx("span", {
|
||||
className: Rf("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", n),
|
||||
children: e || "-",
|
||||
});
|
||||
}
|
||||
function codexNativeRelationChip(e, t) {
|
||||
return Q.jsxs("span", {
|
||||
className:
|
||||
"inline-flex items-center gap-1 rounded-full border bg-muted/50 px-2.5 py-1 font-mono text-xs",
|
||||
children: [
|
||||
e,
|
||||
Q.jsx("span", { className: "text-muted-foreground/60", children: "\u2192" }),
|
||||
t,
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeSearchToolbar({
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: n,
|
||||
onReset: i,
|
||||
refetch: r,
|
||||
actions: o,
|
||||
}) {
|
||||
return Q.jsxs("div", {
|
||||
className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between",
|
||||
children: [
|
||||
Q.jsxs("div", {
|
||||
className: "flex flex-1 flex-wrap items-center gap-2 sm:flex-nowrap",
|
||||
children: [
|
||||
Q.jsx(Q6e, {
|
||||
placeholder: "搜索用户 ID / 邮箱",
|
||||
value: e,
|
||||
onChange: (e) => t(e.target.value),
|
||||
onKeyDown: (e) => {
|
||||
"Enter" === e.key && n();
|
||||
},
|
||||
className: "h-8 w-full min-w-[150px] sm:w-[180px] lg:w-[280px]",
|
||||
}),
|
||||
Q.jsx(Nm, { variant: "outline", className: "h-8 px-3", onClick: n, children: "搜索" }),
|
||||
Q.jsx(Nm, { variant: "ghost", className: "h-8 px-3", onClick: i, children: "重置" }),
|
||||
Q.jsx(Nm, { variant: "ghost", className: "h-8 px-3", onClick: () => r(), children: "刷新" }),
|
||||
],
|
||||
}),
|
||||
o ? Q.jsx("div", { className: "flex flex-wrap items-center gap-2", children: o }) : null,
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeRealnameTable() {
|
||||
const [e, t] = H.useState(""),
|
||||
[n, i] = H.useState(""),
|
||||
[r, o] = H.useState({}),
|
||||
[s, a] = H.useState({}),
|
||||
[l, c] = H.useState({ pageIndex: 0, pageSize: 20 }),
|
||||
{
|
||||
refetch: d,
|
||||
data: u,
|
||||
isLoading: h,
|
||||
} = gC({
|
||||
queryKey: ["codexNativeRealname", l, n],
|
||||
queryFn: () =>
|
||||
TL(`${RL()}/realname/records`, {
|
||||
params: { page: l.pageIndex + 1, per_page: l.pageSize, keyword: n },
|
||||
}),
|
||||
}),
|
||||
g = H.useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: () => "用户 ID",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-sm font-medium", children: e.getValue("id") }),
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: () => "邮箱",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "max-w-[240px] truncate", children: e.getValue("email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "real_name",
|
||||
header: () => "姓名",
|
||||
cell: ({ row: e }) => e.getValue("real_name") || "-",
|
||||
},
|
||||
{
|
||||
accessorKey: "identity_no_masked",
|
||||
header: () => "证件号",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-xs", children: e.getValue("identity_no_masked") || "-" }),
|
||||
},
|
||||
JKt.display({
|
||||
id: "status",
|
||||
header: () => "状态",
|
||||
cell: ({ row: e }) => codexNativeStatusBadge(e.original.status_label || e.original.status),
|
||||
}),
|
||||
JKt.display({
|
||||
id: "actions",
|
||||
header: () => "操作",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsxs("div", {
|
||||
className: "flex flex-wrap items-center gap-2",
|
||||
children: [
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/realname/review/${e.original.id}`, { status: "approved", reason: "" });
|
||||
hN.success("已通过实名认证");
|
||||
d();
|
||||
},
|
||||
children: "通过",
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
const t = window.prompt("请输入驳回原因", "") || "";
|
||||
await IL(`${RL()}/realname/review/${e.original.id}`, {
|
||||
status: "rejected",
|
||||
reason: t,
|
||||
});
|
||||
hN.success("已驳回实名认证");
|
||||
d();
|
||||
},
|
||||
children: "驳回",
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "ghost",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/realname/reset/${e.original.id}`, {});
|
||||
hN.success("已重置实名记录");
|
||||
d();
|
||||
},
|
||||
children: "重置",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
[d],
|
||||
),
|
||||
p = PKt({
|
||||
data: u?.data?.data ?? [],
|
||||
columns: g,
|
||||
state: { columnVisibility: o, rowSelection: s, pagination: l },
|
||||
getRowId: (e) => String(e.id),
|
||||
rowCount: u?.data?.pagination?.total ?? 0,
|
||||
manualPagination: !0,
|
||||
enableRowSelection: !0,
|
||||
onRowSelectionChange: a,
|
||||
onColumnVisibilityChange: o,
|
||||
onPaginationChange: c,
|
||||
getCoreRowModel: LKt(),
|
||||
getPaginationRowModel: OKt(),
|
||||
});
|
||||
return Q.jsxs("div", {
|
||||
className: "space-y-4",
|
||||
children: [
|
||||
Q.jsx(codexNativeSearchToolbar, {
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: () => {
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
i(e.trim());
|
||||
},
|
||||
onReset: () => {
|
||||
t("");
|
||||
i("");
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
},
|
||||
refetch: d,
|
||||
actions: Q.jsxs(Q.Fragment, {
|
||||
children: [
|
||||
Q.jsx(Nm, {
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/realname/sync-all`, {});
|
||||
hN.success("已同步全部实名状态");
|
||||
d();
|
||||
},
|
||||
children: "同步全部",
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/realname/approve-all`, {});
|
||||
hN.success("已全部通过");
|
||||
d();
|
||||
},
|
||||
children: "全部通过",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
Q.jsx(QKt, {
|
||||
table: p,
|
||||
isLoading: h,
|
||||
showPagination: !0,
|
||||
mobilePrimaryField: "email",
|
||||
mobileGridFields: ["real_name", "status", "identity_no_masked"],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeRealnamePage() {
|
||||
return codexNativePageLayout("实名认证", "审核实名记录并同步实名状态。", Q.jsx(codexNativeRealnameTable, {}));
|
||||
}
|
||||
function codexNativeOnlineDevicesTable() {
|
||||
const [e, t] = H.useState(""),
|
||||
[n, i] = H.useState(""),
|
||||
[r, o] = H.useState({}),
|
||||
[s, a] = H.useState({}),
|
||||
[l, c] = H.useState({ pageIndex: 0, pageSize: 20 }),
|
||||
{
|
||||
refetch: d,
|
||||
data: u,
|
||||
isLoading: h,
|
||||
} = gC({
|
||||
queryKey: ["codexNativeOnlineDevices", l, n],
|
||||
queryFn: () =>
|
||||
TL(`${RL()}/user-online-devices/users`, {
|
||||
params: { page: l.pageIndex + 1, per_page: l.pageSize, keyword: n },
|
||||
}),
|
||||
}),
|
||||
g = H.useMemo(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: () => "用户 ID",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-sm font-medium", children: e.getValue("id") }),
|
||||
},
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: () => "邮箱",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "max-w-[240px] truncate", children: e.getValue("email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "subscription_name",
|
||||
header: () => "套餐",
|
||||
cell: ({ row: e }) => e.getValue("subscription_name") || "-",
|
||||
},
|
||||
JKt.display({
|
||||
id: "online_devices",
|
||||
header: () => "在线 IP",
|
||||
cell: ({ row: e }) => {
|
||||
const t = e.original.online_devices || [];
|
||||
return t.length
|
||||
? Q.jsx("div", {
|
||||
className: "flex flex-col gap-1 font-mono text-xs",
|
||||
children: t.map((e, t) => Q.jsx("span", { children: e }, `${e}-${t}`)),
|
||||
})
|
||||
: "-";
|
||||
},
|
||||
}),
|
||||
{
|
||||
accessorKey: "online_count",
|
||||
header: () => "数量",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-sm", children: e.getValue("online_count") || 0 }),
|
||||
},
|
||||
JKt.display({
|
||||
id: "status",
|
||||
header: () => "Status",
|
||||
cell: ({ row: e }) => codexNativeStatusBadge(e.original.status_label || e.original.status),
|
||||
}),
|
||||
{
|
||||
accessorKey: "last_online_text",
|
||||
header: () => "最后在线",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "text-nowrap text-sm text-muted-foreground", children: e.getValue("last_online_text") || "-" }),
|
||||
},
|
||||
],
|
||||
[],
|
||||
),
|
||||
p = PKt({
|
||||
data: u?.data?.list ?? [],
|
||||
columns: g,
|
||||
state: { columnVisibility: r, rowSelection: s, pagination: l },
|
||||
getRowId: (e) => String(e.id),
|
||||
rowCount: u?.data?.pagination?.total ?? 0,
|
||||
manualPagination: !0,
|
||||
enableRowSelection: !0,
|
||||
onRowSelectionChange: a,
|
||||
onColumnVisibilityChange: o,
|
||||
onPaginationChange: c,
|
||||
getCoreRowModel: LKt(),
|
||||
getPaginationRowModel: OKt(),
|
||||
});
|
||||
return Q.jsxs("div", {
|
||||
className: "space-y-4",
|
||||
children: [
|
||||
Q.jsx(codexNativeSearchToolbar, {
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: () => {
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
i(e.trim());
|
||||
},
|
||||
onReset: () => {
|
||||
t("");
|
||||
i("");
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
},
|
||||
refetch: d,
|
||||
}),
|
||||
Q.jsx(QKt, {
|
||||
table: p,
|
||||
isLoading: h,
|
||||
showPagination: !0,
|
||||
mobilePrimaryField: "email",
|
||||
mobileGridFields: ["subscription_name", "online_count", "status", "last_online_text"],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeOnlineDevicesPage() {
|
||||
return codexNativePageLayout("在线设备", "查看用户在线 IP、数量和最后在线时间。", Q.jsx(codexNativeOnlineDevicesTable, {}));
|
||||
}
|
||||
function codexNativeIPv6Table() {
|
||||
const [e, t] = H.useState(""),
|
||||
[n, i] = H.useState(""),
|
||||
[r, o] = H.useState({}),
|
||||
[s, a] = H.useState({}),
|
||||
[l, c] = H.useState({ pageIndex: 0, pageSize: 20 }),
|
||||
{
|
||||
refetch: d,
|
||||
data: u,
|
||||
isLoading: h,
|
||||
} = gC({
|
||||
queryKey: ["codexNativeIPv6", l, n],
|
||||
queryFn: () =>
|
||||
TL(`${RL()}/user-add-ipv6-subscription/users`, {
|
||||
params: { page: l.pageIndex + 1, per_page: l.pageSize, keyword: n },
|
||||
}),
|
||||
}),
|
||||
g = H.useMemo(
|
||||
() => [
|
||||
JKt.display({
|
||||
id: "relation",
|
||||
header: () => "主从关系",
|
||||
cell: ({ row: e }) =>
|
||||
codexNativeRelationChip(e.original.id, e.original.shadow_user_id || "-"),
|
||||
}),
|
||||
{
|
||||
accessorKey: "email",
|
||||
header: () => "主账号",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "max-w-[240px] truncate", children: e.getValue("email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "ipv6_email",
|
||||
header: () => "IPv6 账号",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsx("div", { className: "font-mono text-xs", children: e.getValue("ipv6_email") || "-" }),
|
||||
},
|
||||
{
|
||||
accessorKey: "plan_name",
|
||||
header: () => "套餐",
|
||||
cell: ({ row: e }) => e.getValue("plan_name") || "-",
|
||||
},
|
||||
JKt.display({
|
||||
id: "status",
|
||||
header: () => "状态",
|
||||
cell: ({ row: e }) => codexNativeStatusBadge(e.original.status_label || e.original.status),
|
||||
}),
|
||||
JKt.display({
|
||||
id: "actions",
|
||||
header: () => "操作",
|
||||
cell: ({ row: e }) =>
|
||||
Q.jsxs("div", {
|
||||
className: "flex flex-wrap items-center gap-2",
|
||||
children: [
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/enable/${e.original.id}`, {});
|
||||
hN.success("已开通并同步 IPv6 子账号");
|
||||
d();
|
||||
},
|
||||
children: "开通并同步",
|
||||
}),
|
||||
Q.jsx(Nm, {
|
||||
size: "sm",
|
||||
variant: "outline",
|
||||
className: "h-8",
|
||||
onClick: async () => {
|
||||
await IL(`${RL()}/user-add-ipv6-subscription/sync-password/${e.original.id}`, {});
|
||||
hN.success("已同步密码");
|
||||
d();
|
||||
},
|
||||
children: "同步密码",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
[d],
|
||||
),
|
||||
p = PKt({
|
||||
data: u?.data?.list ?? [],
|
||||
columns: g,
|
||||
state: { columnVisibility: r, rowSelection: s, pagination: l },
|
||||
getRowId: (e) => String(e.id),
|
||||
rowCount: u?.data?.pagination?.total ?? 0,
|
||||
manualPagination: !0,
|
||||
enableRowSelection: !0,
|
||||
onRowSelectionChange: a,
|
||||
onColumnVisibilityChange: o,
|
||||
onPaginationChange: c,
|
||||
getCoreRowModel: LKt(),
|
||||
getPaginationRowModel: OKt(),
|
||||
});
|
||||
return Q.jsxs("div", {
|
||||
className: "space-y-4",
|
||||
children: [
|
||||
Q.jsx(codexNativeSearchToolbar, {
|
||||
keyword: e,
|
||||
setKeyword: t,
|
||||
onSearch: () => {
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
i(e.trim());
|
||||
},
|
||||
onReset: () => {
|
||||
t("");
|
||||
i("");
|
||||
c((e) => ({ ...e, pageIndex: 0 }));
|
||||
},
|
||||
refetch: d,
|
||||
}),
|
||||
Q.jsx(QKt, {
|
||||
table: p,
|
||||
isLoading: h,
|
||||
showPagination: !0,
|
||||
mobilePrimaryField: "email",
|
||||
mobileGridFields: ["ipv6_email", "plan_name", "status"],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
function codexNativeIPv6Page() {
|
||||
return codexNativePageLayout("IPv6 子账号", "管理 IPv6 子账号开通、主从关系和密码同步。", Q.jsx(codexNativeIPv6Table, {}));
|
||||
}
|
||||
function c8t() {
|
||||
const [e] = Hg(),
|
||||
[t, n] = H.useState({}),
|
||||
|
||||
Reference in New Issue
Block a user