+
-
+
+
+
+
示例数据
@@ -69,6 +83,7 @@ import { fetchProjectOverview } from "../../api/overview";
import { fetchSites } from "../../api/sites";
import StateEmpty from "../../components/StateEmpty.vue";
import StateLoading from "../../components/StateLoading.vue";
+import KpiCard from "../../components/KpiCard.vue";
import CenterProgressRow from "./project-overview/CenterProgressRow.vue";
import EnrollmentBarChart, { type EnrollmentBarItem } from "./project-overview/EnrollmentBarChart.vue";
import { adaptProjectOverview, type CenterOverview, type ProjectOverviewViewModel } from "./project-overview/overview.adapter";
@@ -84,6 +99,35 @@ const updatedAtLabel = ref(displayDateTime(new Date()));
const preferApi = String(import.meta.env.VITE_USE_OVERVIEW_API || "").toLowerCase() === "true";
const centers = computed(() => overview.value?.centers || []);
+const kpiItems = computed(() => {
+ const summary = overview.value?.summary;
+ const totalTarget = summary?.total_target ?? 0;
+ const totalActual = summary?.total_actual ?? 0;
+ const activeCenters = centers.value.filter((item) => item.is_active !== false).length;
+ return [
+ {
+ key: "target",
+ title: "总入组目标",
+ value: totalTarget,
+ subtext: "项目整体计划",
+ type: "primary" as const,
+ },
+ {
+ key: "actual",
+ title: "当前入组",
+ value: totalActual,
+ subtext: `达成率 ${totalTarget > 0 ? Math.round((totalActual / totalTarget) * 100) : 0}%`,
+ type: "success" as const,
+ },
+ {
+ key: "centers",
+ title: "活跃中心",
+ value: activeCenters,
+ subtext: `中心总数 ${centers.value.length}`,
+ type: "info" as const,
+ },
+ ];
+});
const buildFallbackCentersFromSites = (siteList: any[]): CenterOverview[] =>
siteList.map((site: any) => ({
@@ -208,6 +252,12 @@ watch(
gap: 0;
}
+.kpi-grid {
+ display: grid;
+ gap: 12px;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+}
+
.demo-tag {
border-color: var(--ctms-border-color);
color: var(--ctms-text-secondary);
diff --git a/frontend/src/views/ia/RiskIssueMonitoringVisits.vue b/frontend/src/views/ia/RiskIssueMonitoringVisits.vue
index 1254ce06..b3728bdf 100644
--- a/frontend/src/views/ia/RiskIssueMonitoringVisits.vue
+++ b/frontend/src/views/ia/RiskIssueMonitoringVisits.vue
@@ -1,7 +1,7 @@
-
+
+
+
+
-
+
diff --git a/frontend/src/views/ia/RiskIssuePd.vue b/frontend/src/views/ia/RiskIssuePd.vue
index a5e368fb..4a2c49d8 100644
--- a/frontend/src/views/ia/RiskIssuePd.vue
+++ b/frontend/src/views/ia/RiskIssuePd.vue
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/frontend/src/views/ia/RiskIssueSae.vue b/frontend/src/views/ia/RiskIssueSae.vue
index cbcf6824..94ef9a6f 100644
--- a/frontend/src/views/ia/RiskIssueSae.vue
+++ b/frontend/src/views/ia/RiskIssueSae.vue
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/frontend/src/views/ia/SubjectManagement.vue b/frontend/src/views/ia/SubjectManagement.vue
index 2e4ae57d..384918aa 100644
--- a/frontend/src/views/ia/SubjectManagement.vue
+++ b/frontend/src/views/ia/SubjectManagement.vue
@@ -1,6 +1,6 @@
-
-
+
+