diff --git a/web/src/NetworkExitsPage.jsx b/web/src/NetworkExitsPage.jsx
index aecb2b6..729a96b 100644
--- a/web/src/NetworkExitsPage.jsx
+++ b/web/src/NetworkExitsPage.jsx
@@ -244,16 +244,18 @@ function ExitTable({ exits, accountsByExit, bindingsError, busy, onAction }) {
const columns = [
{
header: "出口",
- width: "20%",
+ width: "22%",
render: (exit) => (
- {exit.protocol}://{exit.host}:{exit.port}
+ {exit.id}
-
{exit.id}
+
+ {exit.protocol}://{exit.host}:{exit.port}
+
),
},
@@ -264,14 +266,14 @@ function ExitTable({ exits, accountsByExit, bindingsError, busy, onAction }) {
},
{
header: "用户名",
- width: "11%",
+ width: "10%",
render: (exit) => (
{exit.username || "无"}
),
},
{
header: "密码",
- width: "11%",
+ width: "10%",
render: (exit) => (
{exit.password || "无"}
),
@@ -280,7 +282,9 @@ function ExitTable({ exits, accountsByExit, bindingsError, busy, onAction }) {
header: "出口IP",
width: "13%",
render: (exit) => (
- {exit.observed_public_ip || "尚无观测"}
+
+ {exit.observed_public_ip || "尚无观测"}
+
),
},
{
@@ -309,11 +313,7 @@ function ExitTable({ exits, accountsByExit, bindingsError, busy, onAction }) {
width: "8%",
align: "right",
render: (exit) => (
-
+
),
},
];
diff --git a/web/src/NetworkExitsPage.test.jsx b/web/src/NetworkExitsPage.test.jsx
index 919d535..102892c 100644
--- a/web/src/NetworkExitsPage.test.jsx
+++ b/web/src/NetworkExitsPage.test.jsx
@@ -74,10 +74,13 @@ describe("NetworkExitList", () => {
expect(await screen.findByText(/创建并检测健康后/)).toBeTruthy();
});
- it("shows stored credentials and runs an explicit health check", async () => {
+ it("shows the exit ID as the primary identifier with stored credentials", async () => {
const dataProvider = provider([networkExit]);
renderExits(dataProvider);
+ const idLink = await screen.findByRole("link", { name: "exit-a" });
+ expect(idLink.getAttribute("href")).toBe("/network-exits/exit-a");
+ expect(screen.getByText("socks5://proxy.example:1080")).toBeTruthy();
expect((await screen.findAllByText(/proxy-user/)).length).toBeGreaterThan(
0,
);