merge: 同步 upstream/main 新功能到定制版本

- feat: Add slider verification code (bd67997)
- fix bug: Inventory cannot be zero (1f7a6ee)
- fix: resolve merge conflicts and lint errors
This commit is contained in:
2026-03-23 21:50:10 -07:00
parent 3806264343
commit d6616c5859
63 changed files with 3111 additions and 1130 deletions
+21 -12
View File
@@ -44,6 +44,10 @@ import {
ProTable,
type ProTableActions,
} from "@workspace/ui/composed/pro-table/pro-table";
import {
// getUserGroupList,
previewUserNodes,
} from "@workspace/ui/services/admin/group";
import {
createUser,
deleteUser,
@@ -51,10 +55,6 @@ import {
getUserList,
updateUserBasicInfo,
} from "@workspace/ui/services/admin/user";
import {
// getUserGroupList,
previewUserNodes,
} from "@workspace/ui/services/admin/group";
import { useCallback, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
@@ -639,16 +639,19 @@ function PreviewNodesDialog({ userId }: { userId: number }) {
) : previewData ? (
<div className="space-y-4">
<div>
<span className="text-sm font-medium text-muted-foreground">
<span className="font-medium text-muted-foreground text-sm">
{t("availableNodes", "Available Nodes")}:
</span>{" "}
{previewData.node_groups?.reduce((sum, group) => sum + (group.nodes?.length || 0), 0) || 0}
{previewData.node_groups?.reduce(
(sum, group) => sum + (group.nodes?.length || 0),
0
) || 0}
</div>
{previewData.node_groups && previewData.node_groups.length > 0 ? (
<div className="max-h-[400px] overflow-y-auto space-y-4">
<div className="max-h-[400px] space-y-4 overflow-y-auto">
{previewData.node_groups.map((group) => (
<div key={group.id}>
<h4 className="text-sm font-semibold mb-2">
<h4 className="mb-2 font-semibold text-sm">
{group.name ||
(group.id === -1
? t("subscriptionNodes", "Subscription Nodes")
@@ -661,16 +664,22 @@ function PreviewNodesDialog({ userId }: { userId: number }) {
<thead>
<tr className="border-b">
<th className="p-2 text-left font-medium">ID</th>
<th className="p-2 text-left font-medium">{t("name", "Name")}</th>
<th className="p-2 text-left font-medium">{t("address", "Address")}</th>
<th className="p-2 text-left font-medium">
{t("name", "Name")}
</th>
<th className="p-2 text-left font-medium">
{t("address", "Address")}
</th>
</tr>
</thead>
<tbody>
{group.nodes.map((node) => (
<tr key={node.id} className="border-b">
<tr className="border-b" key={node.id}>
<td className="p-2">{node.id}</td>
<td className="p-2">{node.name}</td>
<td className="p-2">{node.address}:{node.port}</td>
<td className="p-2">
{node.address}:{node.port}
</td>
</tr>
))}
</tbody>
+3 -1
View File
@@ -103,7 +103,9 @@ export function UserSubscribeDetail({
</span>
</li>
<li className="flex items-center justify-between">
<span className="text-muted-foreground">{t("remainingTraffic")}</span>
<span className="text-muted-foreground">
{t("remainingTraffic")}
</span>
<span>
{data
? totalTraffic === 0
@@ -280,7 +280,8 @@ export default function UserSubscription({ userId }: { userId: number }) {
const upload = row.original.upload || 0;
const download = row.original.download || 0;
const totalTraffic = row.original.traffic || 0;
const remainingTraffic = totalTraffic > 0 ? totalTraffic - upload - download : 0;
const remainingTraffic =
totalTraffic > 0 ? totalTraffic - upload - download : 0;
return (
<Display type="traffic" unlimited value={remainingTraffic} />
);