412 lines
10 KiB
TypeScript
412 lines
10 KiB
TypeScript
/**
|
|
* 进度条模块
|
|
*
|
|
* 功能说明:
|
|
* - 显示开发流程进度: Spec -> Design代码编写 -> 仿真检查 -> AST -> Done
|
|
* - 支持动态更新当前进度状态
|
|
* - 提供视觉反馈显示已完成和进行中的步骤
|
|
*/
|
|
|
|
/**
|
|
* 获取进度条的 HTML 内容
|
|
*/
|
|
export function getProgressBarContent(): string {
|
|
return `
|
|
<div class="progress-bar-container" style="display: none;">
|
|
<div class="progress-bar-header">
|
|
<span class="progress-bar-title">开发流程</span>
|
|
<button class="progress-bar-toggle" title="收起/展开">
|
|
<span class="toggle-icon">▼</span>
|
|
</button>
|
|
</div>
|
|
<div class="progress-steps">
|
|
<div class="progress-step" data-step="spec">
|
|
<div class="step-circle">
|
|
<span class="step-number">1</span>
|
|
<span class="step-check">✓</span>
|
|
</div>
|
|
<div class="step-label">Spec</div>
|
|
</div>
|
|
|
|
<div class="progress-line"></div>
|
|
|
|
<div class="progress-step" data-step="design">
|
|
<div class="step-circle">
|
|
<span class="step-number">2</span>
|
|
<span class="step-check">✓</span>
|
|
</div>
|
|
<div class="step-label">Design</div>
|
|
</div>
|
|
|
|
<div class="progress-line"></div>
|
|
|
|
<div class="progress-step" data-step="simulation">
|
|
<div class="step-circle">
|
|
<span class="step-number">3</span>
|
|
<span class="step-check">✓</span>
|
|
</div>
|
|
<div class="step-label">Simulation</div>
|
|
</div>
|
|
|
|
<div class="progress-line"></div>
|
|
|
|
<div class="progress-step" data-step="done">
|
|
<div class="step-circle">
|
|
<span class="step-number">4</span>
|
|
<span class="step-check">✓</span>
|
|
</div>
|
|
<div class="step-label">Done</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取进度条的样式
|
|
*/
|
|
export function getProgressBarStyles(): string {
|
|
return `
|
|
.progress-bar-container {
|
|
background: var(--vscode-editor-background);
|
|
border-bottom: 1px solid var(--vscode-panel-border);
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.progress-bar-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 8px 20px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
}
|
|
|
|
.progress-bar-title {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
color: var(--vscode-foreground);
|
|
}
|
|
|
|
.progress-bar-toggle {
|
|
background: none;
|
|
border: none;
|
|
color: var(--vscode-foreground);
|
|
cursor: pointer;
|
|
padding: 2px 6px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
opacity: 0.7;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.progress-bar-toggle:hover {
|
|
opacity: 1;
|
|
}
|
|
|
|
.toggle-icon {
|
|
font-size: 10px;
|
|
transition: transform 0.3s ease;
|
|
}
|
|
|
|
.progress-bar-container.collapsed .toggle-icon {
|
|
transform: rotate(-90deg);
|
|
}
|
|
|
|
.progress-steps {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
max-width: 700px;
|
|
margin: 0 auto;
|
|
padding: 0 20px 10px 20px;
|
|
max-height: 60px;
|
|
overflow: hidden;
|
|
transition: max-height 0.3s ease, padding 0.3s ease;
|
|
}
|
|
|
|
.progress-bar-container.collapsed .progress-steps {
|
|
max-height: 0;
|
|
padding: 0 20px;
|
|
}
|
|
|
|
.progress-step {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
position: relative;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.step-circle {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 50%;
|
|
background: var(--vscode-input-background);
|
|
border: 2px solid var(--vscode-input-border);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
transition: all 0.3s ease;
|
|
z-index: 2;
|
|
}
|
|
|
|
.step-number {
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
color: var(--vscode-foreground);
|
|
}
|
|
|
|
.step-check {
|
|
display: none;
|
|
font-size: 12px;
|
|
color: var(--vscode-button-foreground);
|
|
}
|
|
|
|
.step-label {
|
|
margin-top: 4px;
|
|
font-size: 10px;
|
|
color: var(--vscode-descriptionForeground);
|
|
text-align: center;
|
|
white-space: nowrap;
|
|
transition: color 0.3s ease;
|
|
}
|
|
|
|
.progress-line {
|
|
flex: 1;
|
|
height: 2px;
|
|
background: var(--vscode-input-border);
|
|
margin: 0 6px;
|
|
position: relative;
|
|
top: -10px;
|
|
transition: background 0.3s ease;
|
|
}
|
|
|
|
/* 已完成状态 */
|
|
.progress-step.completed .step-circle {
|
|
background: var(--vscode-button-background);
|
|
border-color: var(--vscode-button-background);
|
|
}
|
|
|
|
.progress-step.completed .step-number {
|
|
display: none;
|
|
}
|
|
|
|
.progress-step.completed .step-check {
|
|
display: block;
|
|
}
|
|
|
|
.progress-step.completed .step-label {
|
|
color: var(--vscode-foreground);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.progress-step.completed + .progress-line {
|
|
background: var(--vscode-button-background);
|
|
}
|
|
|
|
/* 进行中状态 */
|
|
.progress-step.active .step-circle {
|
|
background: var(--vscode-button-background);
|
|
border-color: var(--vscode-button-background);
|
|
box-shadow: 0 0 0 2px var(--vscode-button-background)33;
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
.progress-step.active .step-number {
|
|
color: var(--vscode-button-foreground);
|
|
}
|
|
|
|
.progress-step.active .step-label {
|
|
color: var(--vscode-foreground);
|
|
font-weight: 600;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% {
|
|
box-shadow: 0 0 0 2px var(--vscode-button-background)33;
|
|
}
|
|
50% {
|
|
box-shadow: 0 0 0 4px var(--vscode-button-background)1a;
|
|
}
|
|
}
|
|
|
|
/* 响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.progress-steps {
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.step-label {
|
|
font-size: 9px;
|
|
}
|
|
|
|
.step-circle {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.step-number {
|
|
font-size: 9px;
|
|
}
|
|
|
|
.progress-line {
|
|
margin: 0 4px;
|
|
}
|
|
}
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* 获取进度条的脚本
|
|
*/
|
|
export function getProgressBarScript(): string {
|
|
return `
|
|
// 进度条管理
|
|
const ProgressBar = {
|
|
steps: ['spec', 'design', 'simulation', 'done'],
|
|
currentStep: 'spec',
|
|
isCollapsed: false,
|
|
|
|
/**
|
|
* 初始化进度条
|
|
*/
|
|
init() {
|
|
this.updateProgress('spec');
|
|
this.initToggle();
|
|
},
|
|
|
|
/**
|
|
* 初始化收起/展开功能
|
|
*/
|
|
initToggle() {
|
|
const container = document.querySelector('.progress-bar-container');
|
|
const header = document.querySelector('.progress-bar-header');
|
|
const toggle = document.querySelector('.progress-bar-toggle');
|
|
|
|
if (!container || !header || !toggle) return;
|
|
|
|
// 点击头部或按钮都可以切换
|
|
const handleToggle = (e) => {
|
|
e.stopPropagation();
|
|
this.isCollapsed = !this.isCollapsed;
|
|
|
|
if (this.isCollapsed) {
|
|
container.classList.add('collapsed');
|
|
} else {
|
|
container.classList.remove('collapsed');
|
|
}
|
|
};
|
|
|
|
header.addEventListener('click', handleToggle);
|
|
toggle.addEventListener('click', handleToggle);
|
|
},
|
|
|
|
/**
|
|
* 显示进度条
|
|
*/
|
|
show() {
|
|
const container = document.querySelector('.progress-bar-container');
|
|
if (container) {
|
|
container.style.display = 'block';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 隐藏进度条
|
|
*/
|
|
hide() {
|
|
const container = document.querySelector('.progress-bar-container');
|
|
if (container) {
|
|
container.style.display = 'none';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 更新进度到指定步骤
|
|
* @param {string} stepName - 步骤名称
|
|
*/
|
|
updateProgress(stepName) {
|
|
if (!this.steps.includes(stepName)) {
|
|
console.warn('Invalid step name:', stepName);
|
|
return;
|
|
}
|
|
|
|
this.currentStep = stepName;
|
|
const currentIndex = this.steps.indexOf(stepName);
|
|
|
|
// 更新所有步骤的状态
|
|
document.querySelectorAll('.progress-step').forEach((step, index) => {
|
|
step.classList.remove('completed', 'active');
|
|
|
|
if (index < currentIndex) {
|
|
step.classList.add('completed');
|
|
} else if (index === currentIndex) {
|
|
step.classList.add('active');
|
|
}
|
|
});
|
|
|
|
// 更新连接线
|
|
document.querySelectorAll('.progress-line').forEach((line, index) => {
|
|
if (index < currentIndex) {
|
|
line.style.background = 'var(--vscode-button-background)';
|
|
} else {
|
|
line.style.background = 'var(--vscode-input-border)';
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* 前进到下一步
|
|
*/
|
|
nextStep() {
|
|
const currentIndex = this.steps.indexOf(this.currentStep);
|
|
if (currentIndex < this.steps.length - 1) {
|
|
this.updateProgress(this.steps[currentIndex + 1]);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 重置进度条
|
|
*/
|
|
reset() {
|
|
this.updateProgress('spec');
|
|
},
|
|
|
|
/**
|
|
* 完成所有步骤
|
|
*/
|
|
complete() {
|
|
this.updateProgress('done');
|
|
// 将最后一步也标记为完成
|
|
const lastStep = document.querySelector('.progress-step[data-step="done"]');
|
|
if (lastStep) {
|
|
lastStep.classList.remove('active');
|
|
lastStep.classList.add('completed');
|
|
}
|
|
}
|
|
};
|
|
|
|
// 初始化进度条
|
|
ProgressBar.init();
|
|
|
|
// 监听来自扩展的消息以更新进度
|
|
window.addEventListener('message', (event) => {
|
|
const message = event.data;
|
|
if (message.type === 'updateProgress') {
|
|
ProgressBar.updateProgress(message.step);
|
|
} else if (message.type === 'resetProgress') {
|
|
ProgressBar.reset();
|
|
} else if (message.type === 'completeProgress') {
|
|
ProgressBar.complete();
|
|
} else if (message.type === 'showProgress') {
|
|
ProgressBar.show();
|
|
} else if (message.type === 'hideProgress') {
|
|
ProgressBar.hide();
|
|
}
|
|
});
|
|
`;
|
|
}
|