Revamp simulation rounds configuration in Step2EnvSetup.vue for enhanced user experience
- Redesigned the simulation rounds section with a new header layout and improved descriptions for clarity. - Introduced a toggle for custom round settings, allowing users to switch between automatic and custom configurations. - Enhanced the slider for custom rounds with better styling and estimated time display, improving usability. - Updated CSS for a more modern look and feel, including transitions for smoother interactions.
This commit is contained in:
parent
65c1835879
commit
bf7fe8b053
1 changed files with 316 additions and 202 deletions
|
|
@ -436,47 +436,76 @@
|
|||
|
||||
<!-- 模拟轮数配置 -->
|
||||
<div class="rounds-config-section">
|
||||
<div class="rounds-notice">
|
||||
<div class="notice-icon">⏱️</div>
|
||||
<div class="notice-content">
|
||||
<p class="notice-main">系统自动配置的模拟轮数为 <strong>{{ autoGeneratedRounds }} 轮</strong>,每轮代表现实中 <strong>1 小时</strong>的时间流逝。</p>
|
||||
<p class="notice-sub">完整模拟耗时较长,建议将轮数设置为 <strong>50 轮</strong>(预计耗时约 30 分钟)以快速预览效果。</p>
|
||||
<div class="rounds-header">
|
||||
<div class="header-left">
|
||||
<span class="section-title">模拟轮数设定</span>
|
||||
<span class="section-desc">MiroFish 自动规划推演现实 <span class="desc-highlight">{{ simulationConfig?.time_config?.total_simulation_hours || '-' }}</span> 小时,每轮代表现实 <span class="desc-highlight">{{ simulationConfig?.time_config?.minutes_per_round || '-' }}</span> 分钟时间流逝</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounds-control">
|
||||
<label class="custom-checkbox">
|
||||
<input type="checkbox" v-model="useCustomRounds" />
|
||||
<span class="checkmark"></span>
|
||||
<span class="checkbox-label">自定义模拟轮数 <span class="recommend-badge">推荐</span></span>
|
||||
<label class="switch-control">
|
||||
<input type="checkbox" v-model="useCustomRounds">
|
||||
<span class="switch-track"></span>
|
||||
<span class="switch-label">自定义</span>
|
||||
</label>
|
||||
|
||||
<div v-if="useCustomRounds" class="slider-container">
|
||||
<div class="slider-header">
|
||||
<span class="slider-label">模拟轮数</span>
|
||||
<span class="slider-value">{{ customMaxRounds }} 轮</span>
|
||||
</div>
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="customMaxRounds"
|
||||
min="10"
|
||||
max="120"
|
||||
step="5"
|
||||
class="rounds-slider"
|
||||
/>
|
||||
<div class="slider-marks">
|
||||
<span>10</span>
|
||||
<span class="mark-recommend">50 (推荐)</span>
|
||||
<span>120</span>
|
||||
</div>
|
||||
<p class="slider-estimate">预计耗时:约 {{ Math.round(customMaxRounds * 0.6) }} 分钟</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="auto-mode-hint">
|
||||
<span class="hint-icon">ℹ️</span>
|
||||
<span>将使用自动配置的 {{ autoGeneratedRounds }} 轮完整模拟</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="useCustomRounds" class="rounds-content custom" key="custom">
|
||||
<div class="slider-display">
|
||||
<div class="slider-main-value">
|
||||
<span class="val-num">{{ customMaxRounds }}</span>
|
||||
<span class="val-unit">轮</span>
|
||||
</div>
|
||||
<div class="slider-meta-info">
|
||||
<span>预计耗时约 {{ Math.round(customMaxRounds * 0.6) }} 分钟</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="range-wrapper">
|
||||
<input
|
||||
type="range"
|
||||
v-model.number="customMaxRounds"
|
||||
min="10"
|
||||
max="120"
|
||||
step="5"
|
||||
class="minimal-slider"
|
||||
:style="{ '--percent': ((customMaxRounds - 10) / (120 - 10)) * 100 + '%' }"
|
||||
/>
|
||||
<div class="range-marks">
|
||||
<span>10</span>
|
||||
<span
|
||||
class="mark-recommend"
|
||||
:class="{ active: customMaxRounds === 40 }"
|
||||
@click="customMaxRounds = 40"
|
||||
:style="{ position: 'absolute', left: 'calc(27.27% - 30px)' }"
|
||||
>40 (推荐)</span>
|
||||
<span>120</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="rounds-content auto" key="auto">
|
||||
<div class="auto-info-card">
|
||||
<div class="auto-value">
|
||||
<span class="val-num">{{ autoGeneratedRounds }}</span>
|
||||
<span class="val-unit">轮</span>
|
||||
</div>
|
||||
<div class="auto-content">
|
||||
<div class="auto-meta-row">
|
||||
<span class="duration-badge">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<polyline points="12 6 12 12 16 14"></polyline>
|
||||
</svg>
|
||||
预计耗时 {{ Math.round(autoGeneratedRounds * 0.6) }} 分钟
|
||||
</span>
|
||||
</div>
|
||||
<div class="auto-desc">
|
||||
<p class="highlight-tip" @click="useCustomRounds = true">若首次运行,强烈建议切换至‘自定义模式’减少模拟轮数,以便快速预览效果并降低报错风险 ➝</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<div class="action-group dual">
|
||||
|
|
@ -634,8 +663,8 @@ const selectedProfile = ref(null)
|
|||
const showProfilesDetail = ref(true)
|
||||
|
||||
// 模拟轮数配置
|
||||
const useCustomRounds = ref(true) // 默认使用自定义轮数(推荐)
|
||||
const customMaxRounds = ref(50) // 默认推荐50轮
|
||||
const useCustomRounds = ref(false) // 默认使用自动配置轮数
|
||||
const customMaxRounds = ref(40) // 默认推荐40轮
|
||||
const autoGeneratedRounds = ref(120) // 自动生成的轮数(从配置中读取)
|
||||
|
||||
// Watch stage to update phase
|
||||
|
|
@ -2155,220 +2184,305 @@ onUnmounted(() => {
|
|||
|
||||
/* 模拟轮数配置样式 */
|
||||
.rounds-config-section {
|
||||
margin: 20px 0;
|
||||
padding: 16px;
|
||||
background: #FAFAFA;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #E5E5E5;
|
||||
margin: 24px 0;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #EAEAEA;
|
||||
}
|
||||
|
||||
.rounds-notice {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
padding: 14px;
|
||||
background: #FFF8E1;
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #FFC107;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.notice-icon {
|
||||
font-size: 20px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.notice-main {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
margin: 0 0 6px 0;
|
||||
}
|
||||
|
||||
.notice-main strong {
|
||||
color: #E65100;
|
||||
}
|
||||
|
||||
.notice-sub {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.notice-sub strong {
|
||||
color: #2E7D32;
|
||||
}
|
||||
|
||||
.rounds-control {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.custom-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.custom-checkbox input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid #CCC;
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
transition: all 0.2s;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.custom-checkbox input:checked + .checkmark {
|
||||
background: #FF5722;
|
||||
border-color: #FF5722;
|
||||
}
|
||||
|
||||
.custom-checkbox input:checked + .checkmark::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
width: 5px;
|
||||
height: 9px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.recommend-badge {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: #FFF;
|
||||
background: #4CAF50;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.slider-container {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: #FFF;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #E5E5E5;
|
||||
}
|
||||
|
||||
.slider-header {
|
||||
.rounds-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.slider-label {
|
||||
.header-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1E293B;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
font-size: 12px;
|
||||
color: #94A3B8;
|
||||
}
|
||||
|
||||
.desc-highlight {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-weight: 600;
|
||||
color: #1E293B;
|
||||
background: #F1F5F9;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
/* Switch Control */
|
||||
.switch-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
padding: 4px 8px 4px 4px;
|
||||
border-radius: 20px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.switch-control:hover {
|
||||
background: #F8FAFC;
|
||||
}
|
||||
|
||||
.switch-control input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.switch-track {
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
background: #E2E8F0;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
||||
}
|
||||
|
||||
.switch-track::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #FFF;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
||||
}
|
||||
|
||||
.switch-control input:checked + .switch-track {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.switch-control input:checked + .switch-track::after {
|
||||
transform: translateX(16px);
|
||||
}
|
||||
|
||||
.switch-label {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #64748B;
|
||||
}
|
||||
|
||||
.switch-control input:checked ~ .switch-label {
|
||||
color: #1E293B;
|
||||
}
|
||||
|
||||
/* Slider Content */
|
||||
.rounds-content {
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
.slider-display {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.slider-main-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.val-num {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.val-unit {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
.slider-meta-info {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #FF5722;
|
||||
font-size: 11px;
|
||||
color: #64748B;
|
||||
background: #F1F5F9;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.rounds-slider {
|
||||
.range-wrapper {
|
||||
position: relative;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.minimal-slider {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: linear-gradient(to right, #E0E0E0, #E0E0E0);
|
||||
border-radius: 3px;
|
||||
height: 4px;
|
||||
background: #E2E8F0;
|
||||
border-radius: 2px;
|
||||
outline: none;
|
||||
background-image: linear-gradient(#000, #000);
|
||||
background-size: var(--percent, 0%) 100%;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.rounds-slider::-webkit-slider-thumb {
|
||||
.minimal-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #FF5722;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: #FFF;
|
||||
border: 2px solid #000;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 6px rgba(255, 87, 34, 0.3);
|
||||
transition: transform 0.2s;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.1);
|
||||
transition: transform 0.1s;
|
||||
margin-top: -6px; /* Center thumb */
|
||||
}
|
||||
|
||||
.rounds-slider::-webkit-slider-thumb:hover {
|
||||
.minimal-slider::-webkit-slider-thumb:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.rounds-slider::-moz-range-thumb {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #FF5722;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 6px rgba(255, 87, 34, 0.3);
|
||||
.minimal-slider::-webkit-slider-runnable-track {
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.slider-marks {
|
||||
.range-marks {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
color: #94A3B8;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mark-recommend {
|
||||
color: #4CAF50;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mark-recommend:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.mark-recommend.active {
|
||||
color: #000;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.slider-estimate {
|
||||
margin: 12px 0 0 0;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
padding: 8px;
|
||||
background: #F5F5F5;
|
||||
border-radius: 4px;
|
||||
.mark-recommend::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 1px;
|
||||
height: 4px;
|
||||
background: #CBD5E1;
|
||||
}
|
||||
|
||||
.auto-mode-hint {
|
||||
margin-top: 12px;
|
||||
padding: 12px;
|
||||
background: #F5F5F5;
|
||||
border-radius: 6px;
|
||||
/* Auto Info */
|
||||
.auto-info-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
gap: 24px;
|
||||
background: #F8FAFC;
|
||||
padding: 16px 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.hint-icon {
|
||||
font-size: 14px;
|
||||
.auto-value {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
padding-right: 24px;
|
||||
border-right: 1px solid #E2E8F0;
|
||||
}
|
||||
|
||||
.auto-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.auto-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.duration-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: #64748B;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #E2E8F0;
|
||||
padding: 3px 8px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
.auto-desc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.auto-desc p {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
color: #64748B;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.highlight-tip {
|
||||
margin-top: 4px !important;
|
||||
font-size: 12px !important;
|
||||
color: #000 !important;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.highlight-tip:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(4px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* Modal Transition */
|
||||
|
|
|
|||
Loading…
Reference in a new issue