8cea7dee20
- SiteForge Enterprise V8.10.0-dev.1 upstream source (210 tests) - Fix: v8_workflows._mapped_input now reads both 类型/分类 columns so WXR imports keep post/product types instead of collapsing to page - Docs: trade-pro theme port spec (R3) and implementation plan Co-Authored-By: Claude Code <noreply@anthropic.com>
19 lines
3.9 KiB
Vue
19 lines
3.9 KiB
Vue
<template><section class="release-center"><h2>构建与发布中心</h2><p>构建先通过迁移与质量验收,再提交独立审批;通过后才能部署到预先配置的 HTTPS 环境。</p>
|
||
<el-card shadow="never"><el-space><el-select v-model="siteId" @change="reload" style="width:240px"><el-option v-for="s in sites" :label="s.name" :value="s.id" :key="s.id" /></el-select><el-button @click="reload" :loading="loading">刷新任务</el-button></el-space></el-card>
|
||
<el-card shadow="never" style="margin-top:16px"><template #header>构建版本</template><el-table :data="builds" max-height="360"><el-table-column prop="id" label="版本ID" min-width="170"/><el-table-column prop="status" label="状态" width="110"/><el-table-column prop="total_pages" label="页面数" width="90"/><el-table-column prop="created_at" label="生成日期" width="180"/><el-table-column label="操作" min-width="260"><template #default="{row}"><el-button link @click="review(row.id)">申请审批</el-button><el-button link type="primary" @click="deploy(row.id,'staging')">发布测试环境</el-button><el-button link type="danger" @click="deploy(row.id,'production')">正式发布</el-button></template></el-table-column></el-table></el-card>
|
||
<el-card shadow="never" style="margin-top:16px"><template #header>审批请求</template><el-table :data="requests"><el-table-column prop="build_id" label="构建ID"/><el-table-column prop="state" label="审批状态" width="150"/><el-table-column prop="requested_by" label="申请人"/><el-table-column label="操作"><template #default="{row}"><el-button v-if="row.state==='pending'" link @click="approve(row.id)">审核通过</el-button></template></el-table-column></el-table></el-card>
|
||
</section></template>
|
||
<script setup lang="ts">
|
||
import {onMounted,ref} from 'vue'
|
||
import {ElMessage,ElMessageBox} from 'element-plus'
|
||
interface Site{id:string;name:string}
|
||
const sites=ref<Site[]>([]),siteId=ref(''),builds=ref<any[]>([]),requests=ref<any[]>([]),loading=ref(false),csrf=ref('')
|
||
async function api(path:string,method='GET',body?:unknown){const res=await fetch(path,{method,headers:{...(method==='GET'?{}:{'Content-Type':'application/json','X-SiteForge-CSRF':csrf.value})},credentials:'same-origin',body:body===undefined?undefined:JSON.stringify(body)});const data=await res.json();if(!res.ok)throw Error(data.detail||'请求失败');return data}
|
||
async function reload(){if(!siteId.value)return;loading.value=true;try{[builds.value,requests.value]=await Promise.all([api(`/api/sites/${siteId.value}/builds`),api(`/api/factory/sites/${siteId.value}/release-requests`)])}catch(e:any){ElMessage.error(e.message)}finally{loading.value=false}}
|
||
async function review(id:string){try{const r=await api(`/api/factory/sites/${siteId.value}/release-requests`,'POST',{build_id:id});ElMessage.success('审批请求已建立:'+r.id);await reload()}catch(e:any){ElMessage.error(e.message)}}
|
||
async function approve(id:string){try{await ElMessageBox.confirm('审批人不能是申请人,是否批准?','审核发布');await api(`/api/factory/sites/${siteId.value}/release-requests/${id}/review`,'POST',{state:'approved'});ElMessage.success('审批完成');await reload()}catch(e:any){if(e!=='cancel')ElMessage.error(e.message)}}
|
||
async function deploy(build_id:string,target:'staging'|'production'){try{await ElMessageBox.confirm(`将构建版本 ${build_id} 部署到 ${target},确认目标环境已配置 HTTPS?`,'发布确认');await api(`/api/production/sites/${siteId.value}/deploy`,'POST',{build_id,target});ElMessage.success('远程部署接收端已确认发布')}catch(e:any){if(e!=='cancel')ElMessage.error(e.message)}}
|
||
onMounted(async()=>{try{csrf.value=(await api('/api/auth/me')).csrf;sites.value=await api('/api/sites');siteId.value=sites.value[0]?.id||'';await reload()}catch(e:any){ElMessage.error(e.message)}})
|
||
</script>
|
||
<style scoped>.release-center h2{font-size:24px;margin:0 0 8px}.release-center p{color:var(--el-text-color-secondary);margin:0 0 25px;font-size:13px}</style>
|