Files
devops-platform-web/src/views/ProjectsView.vue
T
2026-06-12 04:12:22 +08:00

188 lines
5.2 KiB
Vue

<script setup lang="ts">
/**
* 项目配置页展示项目仓库、发布环境以及真实 Jenkins job 诊断状态。
*/
import { onMounted, ref } from 'vue'
import StatusPill from '../components/StatusPill.vue'
import { usePlatformStore } from '../stores/platform'
import type { EnvironmentStatus } from '../types/devops'
const platform = usePlatformStore()
const diagnosticsLoading = ref(false)
onMounted(() => {
void refreshJenkinsDiagnostics()
})
async function refreshJenkinsDiagnostics() {
diagnosticsLoading.value = true
try {
await platform.loadProjectJenkinsDiagnostics()
} finally {
diagnosticsLoading.value = false
}
}
function lastBuildText(env: EnvironmentStatus): string {
if (!env.jenkinsLastBuild?.number) {
return '-'
}
if (env.jenkinsLastBuild.building) {
return `#${env.jenkinsLastBuild.number} 运行中`
}
return `#${env.jenkinsLastBuild.number} ${env.jenkinsLastBuild.result || 'UNKNOWN'}`
}
</script>
<template>
<div class="page-shell">
<div class="page-header">
<div>
<h1>项目配置</h1>
<p>展示后端返回的项目环境Jenkins JobGitea 仓库和通知通道绑定关系</p>
</div>
<ElButton type="primary" plain disabled>新增项目</ElButton>
</div>
<section class="panel">
<div class="panel-header">
<h2>项目清单</h2>
<ElButton
size="small"
plain
:loading="diagnosticsLoading"
@click="refreshJenkinsDiagnostics"
>
刷新 Jenkins 诊断
</ElButton>
</div>
<div class="panel-body">
<ElTable :data="platform.projects" row-key="key">
<ElTableColumn type="expand">
<template #default="{ row }">
<div class="env-config">
<div v-for="env in row.environments" :key="env.name" class="env-config-card">
<div class="env-config-head">
<strong>{{ env.label }}</strong>
<StatusPill :state="env.status" />
</div>
<dl>
<dt>分支策略</dt>
<dd>{{ env.branchPolicy }}</dd>
<dt>Jenkins Job</dt>
<dd class="mono">{{ env.jenkinsJob }}</dd>
<dt>Job 状态</dt>
<dd>
<StatusPill :state="env.jenkinsStatus" />
<span class="diagnostic-message">{{ env.jenkinsMessage }}</span>
</dd>
<dt>最近构建</dt>
<dd>
<a
v-if="env.jenkinsLastBuild?.url"
:href="env.jenkinsLastBuild.url"
target="_blank"
rel="noreferrer"
>
{{ lastBuildText(env) }}
</a>
<span v-else>{{ lastBuildText(env) }}</span>
</dd>
<dt>通知通道</dt>
<dd>{{ env.wecomRobot }}</dd>
<dt>最近发布</dt>
<dd>{{ env.lastRunId }} · {{ env.version }}</dd>
</dl>
</div>
</div>
</template>
</ElTableColumn>
<ElTableColumn prop="name" label="项目" min-width="150" />
<ElTableColumn prop="serviceType" label="类型" min-width="130" />
<ElTableColumn prop="repository" label="Gitea 仓库" min-width="320">
<template #default="{ row }">
<span class="mono">{{ row.repository }}</span>
</template>
</ElTableColumn>
<ElTableColumn prop="defaultBranch" label="默认分支" width="120" />
<ElTableColumn prop="tagPolicy" label="Tag 策略" min-width="220" />
<ElTableColumn label="集成状态" width="280">
<template #default="{ row }">
<div class="status-tags">
<StatusPill :state="row.integrations.jenkins" text="Jenkins" />
<StatusPill :state="row.integrations.gitea" text="Gitea" />
<StatusPill :state="row.integrations.wecom" text="通知" />
<StatusPill :state="row.integrations.llm" text="LLM" />
</div>
</template>
</ElTableColumn>
</ElTable>
</div>
</section>
</div>
</template>
<style scoped>
.env-config {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px;
padding: 14px 46px;
background: #f8fafc;
}
.env-config-card {
padding: 14px;
border: 1px solid #e1e8f2;
border-radius: 8px;
background: #ffffff;
}
.env-config-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
dl {
display: grid;
grid-template-columns: 100px minmax(0, 1fr);
gap: 8px 12px;
margin: 0;
color: #596578;
font-size: 13px;
}
dt {
color: #7b8798;
}
dd {
margin: 0;
word-break: break-word;
}
.status-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.diagnostic-message {
margin-left: 8px;
color: #596578;
font-size: 12px;
}
@media (max-width: 760px) {
.env-config {
grid-template-columns: 1fr;
padding: 12px;
}
}
</style>