{% extends "base.html" %}
{% block title %}{{ profile }} - 部署流程{% endblock %}
{% block content %}
<div class="page-header">
<h1>{{ profile }}</h1>
<a href="{{ url_for('index') }}" class="btn-back">返回首页</a>
</div>
<div class="workflow-container">
<div class="workflow-sidebar">
<h3>部署步骤</h3>
<div class="workflow-steps">
{% for step in workflow %}
<div class="workflow-step {% if loop.first %}active{% endif %}"
data-step="{{ step.name }}"
data-index="{{ loop.index0 }}"
onclick="selectStep('{{ step.name }}')">
<div class="step-number">{{ loop.index }}</div>
<div class="step-info">
<span class="step-title">{{ step.title }}</span>
<span class="step-desc">{{ step.description }}</span>
</div>
<div class="step-actions">
{% if step.standalone %}
<a href="{{ url_for('step_page', profile=profile, step_name=step.name) }}"
class="btn-execute">执行</a>
{% endif %}
{% if step.skip_allowed and not loop.last %}
<button class="btn-skip" onclick="skipStep('{{ step.name }}', event)">跳过</button>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<div class="workflow-actions">
<button class="btn-primary btn-large" onclick="executeAll()">
一键执行全部
</button>
</div>
</div>
<div class="workflow-main">
<div class="step-detail-panel">
<h2>{{ workflow[0].title }}</h2>
<p class="step-description">{{ workflow[0].description }}</p>
<div class="step-meta">
{% if workflow[0].standalone %}
<span class="badge badge-success">可单独执行</span>
{% endif %}
{% if workflow[0].skip_allowed %}
<span class="badge badge-info">可跳过</span>
{% endif %}
{% if workflow[0].needs_reboot %}
<span class="badge badge-warning">需要重启</span>
{% endif %}
</div>
<div class="step-params-preview">
<h4>参数预览</h4>
{% if workflow[0].params %}
<ul class="params-list">
{% for param in workflow[0].params %}
<li>
<strong>{{ param.label }}</strong>
{% if param.required %}
<span class="required">*</span>
{% endif %}
<span class="param-type">({{ param.type }})</span>
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-params">此步骤无需参数</p>
{% endif %}
</div>
<div class="step-action-buttons">
<a href="{{ url_for('step_page', profile=profile, step_name=workflow[0].name) }}"
class="btn-primary">
进入执行页面
</a>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
const workflow = {{ workflow | tojson }};
const profile = "{{ profile }}";
function selectStep(stepName) {
document.querySelectorAll('.workflow-step').forEach(el => {
el.classList.remove('active');
if (el.dataset.step === stepName) {
el.classList.add('active');
}
});
const step = workflow.find(s => s.name === stepName);
if (step) {
updateStepDetail(step);
}
}
function updateStepDetail(step) {
const panel = document.querySelector('.step-detail-panel');
panel.querySelector('h2').textContent = step.title;
panel.querySelector('.step-description').textContent = step.description;
const metaDiv = panel.querySelector('.step-meta');
metaDiv.innerHTML = '';
if (step.standalone) {
metaDiv.innerHTML += '<span class="badge badge-success">可单独执行</span>';
}
if (step.skip_allowed) {
metaDiv.innerHTML += '<span class="badge badge-info">可跳过</span>';
}
if (step.needs_reboot) {
metaDiv.innerHTML += '<span class="badge badge-warning">需要重启</span>';
}
const paramsDiv = panel.querySelector('.step-params-preview');
const paramsList = paramsDiv.querySelector('.params-list') || paramsDiv;
if (step.params && step.params.length > 0) {
paramsDiv.innerHTML = '<h4>参数预览</h4><ul class="params-list">';
step.params.forEach(param => {
paramsDiv.innerHTML += `<li>
<strong>${param.label}</strong>
${param.required ? '<span class="required">*</span>' : ''}
<span class="param-type">(${param.type})</span>
</li>`;
});
paramsDiv.innerHTML += '</ul>';
} else {
paramsDiv.innerHTML = '<h4>参数预览</h4><p class="no-params">此步骤无需参数</p>';
}
const actionDiv = panel.querySelector('.step-action-buttons');
const stepIndex = workflow.findIndex(s => s.name === step.name);
let buttonsHtml = `<a href="/step/${profile}/${step.name}" class="btn-primary">进入执行页面</a>`;
if (step.skip_allowed && stepIndex < workflow.length - 1) {
const nextStep = workflow[stepIndex + 1];
buttonsHtml += ` <button class="btn-secondary" onclick="location.href='/step/${profile}/${nextStep.name}'">跳过并进入下一步</button>`;
}
actionDiv.innerHTML = buttonsHtml;
}
function skipStep(stepName, event) {
event.stopPropagation();
const stepIndex = workflow.findIndex(s => s.name === stepName);
if (stepIndex < workflow.length - 1) {
const nextStep = workflow[stepIndex + 1];
location.href = `/step/${profile}/${nextStep.name}`;
}
}
function executeAll() {
alert('即将按顺序执行所有步骤,请从第一个步骤开始');
location.href = `/step/${profile}/${workflow[0].name}`;
}
</script>
{% endblock %}