diff --git a/src/stores/platform.ts b/src/stores/platform.ts index 3df99d1..6d136e3 100644 --- a/src/stores/platform.ts +++ b/src/stores/platform.ts @@ -55,6 +55,7 @@ export const usePlatformStore = defineStore('platform', () => { const summary = await devopsApi.getDashboard({ includeAdminConfig: includeAdminData }) projects.value = summary.projects runs.value = summary.runs + applyProjectRunSummaries() integrations.value = summary.integrations agentCards.value = summary.agentCards settings.value = summary.settings @@ -200,6 +201,49 @@ export const usePlatformStore = defineStore('platform', () => { function upsertRun(run: ReleaseRun) { runs.value = [run, ...runs.value.filter((item) => item.id !== run.id)] + applyProjectRunSummaries() + } + + function applyProjectRunSummaries() { + const latestRunByEnvironment = new Map() + + // 后端 /deploy-runs 按最近记录返回;首次出现的项目环境即当前展示摘要。 + runs.value.forEach((run) => { + const key = projectEnvironmentKey(run.projectKey, run.environment) + + if (!latestRunByEnvironment.has(key)) { + latestRunByEnvironment.set(key, run) + } + }) + + projects.value = projects.value.map((project) => ({ + ...project, + environments: project.environments.map((environment) => { + const run = latestRunByEnvironment.get( + projectEnvironmentKey(project.key, environment.name), + ) + + if (!run) { + return { + ...environment, + status: 'idle', + version: '-', + lastRunId: '-', + lastReleasedAt: '-', + lastActor: '-', + } + } + + return { + ...environment, + status: run.status, + version: run.ref, + lastRunId: run.id, + lastReleasedAt: run.startedAt, + lastActor: run.actor, + } + }), + })) } return { @@ -263,3 +307,10 @@ function jenkinsDiagnosticMessage( return 'Jenkins job 不可用' } + +function projectEnvironmentKey( + projectKey: string, + environment: ReleaseRun['environment'], +): string { + return `${projectKey}:${environment}` +} diff --git a/src/views/ProjectsView.vue b/src/views/ProjectsView.vue index 01808a2..682dc4d 100644 --- a/src/views/ProjectsView.vue +++ b/src/views/ProjectsView.vue @@ -48,8 +48,8 @@ function lastBuildText(env: EnvironmentStatus): string {
-
-

项目清单

+
+

项目清单

通知通道
{{ env.wecomRobot }}
最近发布
-
{{ env.lastRunId }} · {{ env.version }}
+
+
+
+ + + {{ env.lastRunId }} + +
+ + {{ env.version }} · {{ env.lastActor }} · {{ env.lastReleasedAt }} + +
+ 暂无真实发布记录 +
@@ -178,6 +194,31 @@ dd { font-size: 12px; } +.latest-release { + display: grid; + gap: 6px; +} + +.latest-release-head { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; +} + +.latest-release small { + color: #7b8798; +} + +.run-link { + color: #2563eb; + text-decoration: none; +} + +.run-link:hover { + text-decoration: underline; +} + @media (max-width: 760px) { .env-config { grid-template-columns: 1fr; diff --git a/src/views/RunsView.vue b/src/views/RunsView.vue index 36bc5c2..426dd0d 100644 --- a/src/views/RunsView.vue +++ b/src/views/RunsView.vue @@ -4,7 +4,8 @@ */ import { CircleClose, RefreshRight } from '@element-plus/icons-vue' import { ElMessage } from 'element-plus' -import { computed, ref } from 'vue' +import { computed, ref, watch } from 'vue' +import { useRoute } from 'vue-router' import BpmnStatusViewer from '../components/BpmnStatusViewer.vue' import RunExecutionDetails from '../components/RunExecutionDetails.vue' import StatusPill from '../components/StatusPill.vue' @@ -12,6 +13,7 @@ import { usePlatformStore } from '../stores/platform' import type { ReleaseRun } from '../types/devops' const platform = usePlatformStore() +const route = useRoute() const selectedRunId = ref(platform.runs[0]?.id || '') const syncingAll = ref(false) @@ -29,6 +31,23 @@ const canRetrySelectedRun = computed(() => { const canSyncAnyRun = computed(() => platform.runs.some((run) => canSyncRun(run))) +watch( + () => [route.query.runId, platform.runs.map((run) => run.id).join('|')], + () => { + const queryRunId = typeof route.query.runId === 'string' ? route.query.runId : '' + + if (queryRunId && platform.runs.some((run) => run.id === queryRunId)) { + selectedRunId.value = queryRunId + return + } + + if (!selectedRunId.value && platform.runs[0]) { + selectedRunId.value = platform.runs[0].id + } + }, + { immediate: true }, +) + function canSyncRun(run?: ReleaseRun): boolean { return ( Boolean(run?.jenkinsQueueId || run?.jenkinsBuildNumber) &&