Enhance simulation file management and frontend status display

- Updated SimulationRunner to include additional files for deletion, specifically Twitter and Reddit simulation databases, and environment status files.
- Refactored Step3Simulation component to streamline the status display, removing unnecessary conditions and improving the user interface for simulation phases.
- Introduced a reset function to clear all simulation states before starting a new simulation, ensuring a clean environment for each run.
This commit is contained in:
666ghj 2025-12-12 16:44:05 +08:00
parent ec418c1def
commit d768fd1ea2
2 changed files with 35 additions and 161 deletions

View file

@ -1053,6 +1053,9 @@ class SimulationRunner:
- reddit/actions.jsonl - reddit/actions.jsonl
- simulation.log - simulation.log
- stdout.log / stderr.log - stdout.log / stderr.log
- twitter_simulation.db模拟数据库
- reddit_simulation.db模拟数据库
- env_status.json环境状态
注意不会删除配置文件simulation_config.json profile 文件 注意不会删除配置文件simulation_config.json profile 文件
@ -1072,12 +1075,15 @@ class SimulationRunner:
cleaned_files = [] cleaned_files = []
errors = [] errors = []
# 要删除的文件列表 # 要删除的文件列表(包括数据库文件)
files_to_delete = [ files_to_delete = [
"run_state.json", "run_state.json",
"simulation.log", "simulation.log",
"stdout.log", "stdout.log",
"stderr.log", "stderr.log",
"twitter_simulation.db", # Twitter 平台数据库
"reddit_simulation.db", # Reddit 平台数据库
"env_status.json", # 环境状态文件
] ]
# 要删除的目录列表(包含动作日志) # 要删除的目录列表(包含动作日志)

View file

@ -2,7 +2,7 @@
<div class="simulation-panel"> <div class="simulation-panel">
<!-- Top Control Bar --> <!-- Top Control Bar -->
<div class="control-bar"> <div class="control-bar">
<div class="status-group" v-if="phase >= 1"> <div class="status-group">
<!-- Twitter 平台进度 --> <!-- Twitter 平台进度 -->
<div class="platform-status twitter" :class="{ active: runStatus.twitter_running, completed: runStatus.twitter_completed }"> <div class="platform-status twitter" :class="{ active: runStatus.twitter_running, completed: runStatus.twitter_completed }">
<div class="platform-header"> <div class="platform-header">
@ -49,81 +49,23 @@
</div> </div>
</div> </div>
</div> </div>
<!-- Phase 0 时显示简单状态 -->
<div class="status-group" v-else>
<div class="status-item">
<span class="label">ROUND</span>
<span class="value mono">0<span class="total">/{{ maxRounds || '-' }}</span></span>
</div>
<div class="status-item">
<span class="label">TIME</span>
<span class="value mono">0<span class="unit">h</span></span>
</div>
</div>
<div class="action-controls"> <div class="action-controls">
<button <button
v-if="phase === 0"
class="ctrl-btn start"
:disabled="isStarting"
@click="doStartSimulation"
>
<span v-if="isStarting" class="spinner-sm"></span>
{{ isStarting ? 'INITIALIZING...' : 'START ENGINE' }}
</button>
<button
v-if="phase === 1"
class="ctrl-btn stop"
:disabled="isStopping"
@click="handleStopSimulation"
>
{{ isStopping ? 'STOPPING...' : 'STOP SIMULATION' }}
</button>
<button
v-if="phase === 2"
class="ctrl-btn next" class="ctrl-btn next"
:disabled="phase !== 2"
@click="handleNextStep" @click="handleNextStep"
> >
GENERATE REPORT <span v-if="phase !== 2" class="spinner-sm running"></span>
{{ phase === 2 ? 'GENERATE REPORT ➝' : 'SIMULATING...' }}
</button> </button>
</div> </div>
</div> </div>
<!-- Main Content: Dual Timeline or Start Screen --> <!-- Main Content: Dual Timeline -->
<div class="main-content-area" ref="scrollContainer"> <div class="main-content-area" ref="scrollContainer">
<!-- Start Screen (Phase 0) --> <!-- Timeline Feed -->
<div v-if="phase === 0" class="start-screen"> <div class="timeline-feed">
<div class="engine-status">
<div class="engine-icon"></div>
<h2>Simulation Engine Ready</h2>
<p>Initialize the dual-platform parallel simulation environment.</p>
</div>
<div class="config-grid">
<div class="config-card">
<span class="label">SIMULATION ID</span>
<span class="val mono">{{ simulationId }}</span>
</div>
<div class="config-card">
<span class="label">TARGET ROUNDS</span>
<span class="val">{{ maxRounds || 'AUTO' }}</span>
</div>
<div class="config-card">
<span class="label">PLATFORMS</span>
<span class="val">Twitter + Reddit</span>
</div>
</div>
<div v-if="startError" class="error-banner">
{{ startError }}
</div>
</div>
<!-- Timeline Feed (Phase >= 1) -->
<div v-else class="timeline-feed">
<div class="timeline-axis"></div> <div class="timeline-axis"></div>
<TransitionGroup name="timeline-item"> <TransitionGroup name="timeline-item">
@ -238,6 +180,19 @@ const addLog = (msg) => {
emit('add-log', msg) emit('add-log', msg)
} }
//
const resetAllState = () => {
phase.value = 0
runStatus.value = {}
recentActions.value = []
prevTwitterRound.value = 0
prevRedditRound.value = 0
startError.value = null
isStarting.value = false
isStopping.value = false
stopPolling() //
}
// //
const doStartSimulation = async () => { const doStartSimulation = async () => {
if (!props.simulationId) { if (!props.simulationId) {
@ -245,6 +200,9 @@ const doStartSimulation = async () => {
return return
} }
//
resetAllState()
isStarting.value = true isStarting.value = true
startError.value = null startError.value = null
addLog('正在启动双平台并行模拟...') addLog('正在启动双平台并行模拟...')
@ -522,30 +480,6 @@ onUnmounted(() => {
gap: 16px; gap: 16px;
} }
.status-item {
display: flex;
flex-direction: column;
}
.status-item .label {
font-size: 10px;
color: #999;
font-weight: 600;
letter-spacing: 0.5px;
}
.status-item .value {
font-size: 16px;
font-weight: 700;
color: #333;
}
.status-item .total, .status-item .unit {
font-size: 12px;
color: #999;
font-weight: 500;
}
/* 双平台进度卡片 */ /* 双平台进度卡片 */
.platform-status { .platform-status {
display: flex; display: flex;
@ -649,16 +583,6 @@ onUnmounted(() => {
transition: all 0.2s; transition: all 0.2s;
} }
.ctrl-btn.start {
background: #000;
color: #FFF;
}
.ctrl-btn.stop {
background: #FFEBEE;
color: #C62828;
}
.ctrl-btn.next { .ctrl-btn.next {
background: #E8F5E9; background: #E8F5E9;
color: #2E7D32; color: #2E7D32;
@ -682,67 +606,6 @@ onUnmounted(() => {
background: #FAFAFA; background: #FAFAFA;
} }
/* Start Screen */
.start-screen {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40px;
}
.engine-status {
text-align: center;
margin-bottom: 40px;
}
.engine-icon {
font-size: 48px;
margin-bottom: 16px;
}
.engine-status h2 {
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.engine-status p {
color: #666;
font-size: 14px;
}
.config-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
width: 100%;
max-width: 600px;
}
.config-card {
background: #FFF;
padding: 16px;
border-radius: 8px;
border: 1px solid #EAEAEA;
text-align: center;
}
.config-card .label {
display: block;
font-size: 10px;
color: #999;
margin-bottom: 8px;
}
.config-card .val {
display: block;
font-size: 14px;
font-weight: 600;
color: #333;
}
/* --- Timeline Feed --- */ /* --- Timeline Feed --- */
.timeline-feed { .timeline-feed {
padding: 24px; padding: 24px;
@ -1018,6 +881,11 @@ onUnmounted(() => {
animation: spin 0.8s linear infinite; animation: spin 0.8s linear infinite;
} }
.spinner-sm.running {
border: 2px solid rgba(46, 125, 50, 0.3);
border-top-color: #2E7D32;
}
@keyframes spin { @keyframes spin {
to { transform: rotate(360deg); } to { transform: rotate(360deg); }
} }