add:新增一键测试
This commit is contained in:
1 parent
45a8627276
commit
1495666ea6
4 files changed
+90
No files matched your search
@@ -16,7 +16,9 @@ import {
|
||||
import {
|
||||
filterSites,
|
||||
sortSites,
|
||||
summarizeSiteTests,
|
||||
type SiteSortState,
|
||||
type SiteTestResult,
|
||||
} from "./core/sites";
|
||||
import type {
|
||||
AdminData,
|
||||
@@ -547,6 +549,44 @@ const App = () => {
|
||||
[apiFetch, loadSites],
|
||||
);
|
||||
|
||||
const handleSiteTestAll = useCallback(async () => {
|
||||
if (data.sites.length === 0) {
|
||||
setNotice("暂无站点可测试");
|
||||
return;
|
||||
}
|
||||
setNotice("正在执行一键测试...");
|
||||
const results: SiteTestResult[] = [];
|
||||
for (const site of data.sites) {
|
||||
if (site.status !== "active") {
|
||||
results.push({ status: "skipped" });
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
await apiFetch(`/api/channels/${site.id}/test`, {
|
||||
method: "POST",
|
||||
});
|
||||
results.push({ status: "success" });
|
||||
} catch (_error) {
|
||||
results.push({ status: "failed" });
|
||||
}
|
||||
}
|
||||
await loadSites();
|
||||
const summary = summarizeSiteTests(results);
|
||||
const testedTotal = summary.success + summary.failed;
|
||||
if (testedTotal === 0) {
|
||||
setNotice(`已跳过 ${summary.skipped} 个禁用站点,暂无可测试站点。`);
|
||||
return;
|
||||
}
|
||||
let message =
|
||||
summary.failed > 0
|
||||
? `一键测试完成,成功 ${summary.success}/${testedTotal},失败 ${summary.failed}。`
|
||||
: `一键测试完成,成功 ${summary.success}/${testedTotal}。`;
|
||||
if (summary.skipped > 0) {
|
||||
message += ` 已跳过 ${summary.skipped} 个禁用站点。`;
|
||||
}
|
||||
setNotice(message);
|
||||
}, [apiFetch, data.sites, loadSites]);
|
||||
|
||||
const handleSiteDelete = useCallback(
|
||||
async (id: string) => {
|
||||
try {
|
||||
@@ -753,6 +793,7 @@ const App = () => {
|
||||
onSortChange={handleSiteSortChange}
|
||||
onFormChange={handleSiteFormChange}
|
||||
onRunAll={handleCheckinRunAll}
|
||||
onTestAll={handleSiteTestAll}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,19 @@ export type SiteSortState = {
|
||||
direction: SiteSortDirection;
|
||||
};
|
||||
|
||||
export type SiteTestStatus = "success" | "failed" | "skipped";
|
||||
|
||||
export type SiteTestResult = {
|
||||
status: SiteTestStatus;
|
||||
};
|
||||
|
||||
export type SiteTestSummary = {
|
||||
total: number;
|
||||
success: number;
|
||||
failed: number;
|
||||
skipped: number;
|
||||
};
|
||||
|
||||
export const SITE_TYPE_LABELS: Record<Site["site_type"], string> = {
|
||||
"new-api": "New API",
|
||||
"done-hub": "Done Hub",
|
||||
@@ -32,6 +45,30 @@ export const getSiteTypeLabel = (siteType: Site["site_type"]) =>
|
||||
export const getSiteStatusLabel = (status: string) =>
|
||||
status === "active" ? "启用" : "禁用";
|
||||
|
||||
export const summarizeSiteTests = (
|
||||
results: SiteTestResult[],
|
||||
): SiteTestSummary => {
|
||||
return results.reduce(
|
||||
(acc, item) => {
|
||||
acc.total += 1;
|
||||
if (item.status === "success") {
|
||||
acc.success += 1;
|
||||
} else if (item.status === "failed") {
|
||||
acc.failed += 1;
|
||||
} else {
|
||||
acc.skipped += 1;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
total: 0,
|
||||
success: 0,
|
||||
failed: 0,
|
||||
skipped: 0,
|
||||
} as SiteTestSummary,
|
||||
);
|
||||
};
|
||||
|
||||
export const getSiteCheckinLabel = (site: Site, today?: string) => {
|
||||
const shouldShow =
|
||||
site.site_type === "new-api" && Boolean(site.checkin_enabled);
|
||||
|
||||
@@ -37,6 +37,7 @@ type SitesViewProps = {
|
||||
onSortChange: (next: SiteSortState) => void;
|
||||
onFormChange: (patch: Partial<SiteForm>) => void;
|
||||
onRunAll: () => void;
|
||||
onTestAll: () => void;
|
||||
};
|
||||
|
||||
const pageSizeOptions = [10, 20, 50];
|
||||
@@ -76,6 +77,7 @@ export const SitesView = ({
|
||||
onSortChange,
|
||||
onFormChange,
|
||||
onRunAll,
|
||||
onTestAll,
|
||||
}: SitesViewProps) => {
|
||||
const isEditing = Boolean(editingSite);
|
||||
const pageItems = buildPageItems(sitePage, siteTotalPages);
|
||||
@@ -156,6 +158,13 @@ export const SitesView = ({
|
||||
>
|
||||
一键签到
|
||||
</button>
|
||||
<button
|
||||
class="h-9 rounded-full border border-stone-200 bg-stone-100 px-4 text-xs font-semibold text-stone-700 transition-all duration-200 ease-in-out hover:-translate-y-0.5 hover:shadow-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-400/70 focus-visible:ring-offset-2 focus-visible:ring-offset-white"
|
||||
type="button"
|
||||
onClick={onTestAll}
|
||||
>
|
||||
一键测试
|
||||
</button>
|
||||
<button
|
||||
class="h-9 rounded-full bg-stone-900 px-4 text-xs font-semibold text-white transition-all duration-200 ease-in-out hover:-translate-y-0.5 hover:shadow-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-400/70 focus-visible:ring-offset-2 focus-visible:ring-offset-white"
|
||||
type="button"
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
### 微调
|
||||
|
||||
- **[admin-ui]**: 站点管理新增一键测试并汇总结果提示
|
||||
- 类型: 微调(无方案包)
|
||||
- 文件: apps/ui/src/App.tsx, apps/ui/src/features/SitesView.tsx, apps/ui/src/core/sites.ts, tests/ui/sites.test.ts
|
||||
- **[admin-ui]**: 编辑站点时站点类型/状态选择与当前值一致
|
||||
- 类型: 微调(无方案包)
|
||||
- 文件: apps/ui/src/features/SitesView.tsx:567-689
|
||||
|
||||
Reference in new issue
Block a user