Implement simulation environment management features in frontend
- Added new API functions for closing the simulation environment and retrieving its status. - Enhanced the SimulationRunView and SimulationView components to gracefully handle simulation termination when navigating between steps. - Introduced logging for better user feedback during the simulation closure process, including attempts to force stop if graceful closure fails.
This commit is contained in:
parent
0577ecdae8
commit
ec418c1def
3 changed files with 132 additions and 4 deletions
|
|
@ -152,3 +152,19 @@ export const getSimulationActions = (simulationId, params = {}) => {
|
||||||
return service.get(`/api/simulation/${simulationId}/actions`, { params })
|
return service.get(`/api/simulation/${simulationId}/actions`, { params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭模拟环境(优雅退出)
|
||||||
|
* @param {Object} data - { simulation_id, timeout? }
|
||||||
|
*/
|
||||||
|
export const closeSimulationEnv = (data) => {
|
||||||
|
return service.post('/api/simulation/close-env', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取模拟环境状态
|
||||||
|
* @param {Object} data - { simulation_id }
|
||||||
|
*/
|
||||||
|
export const getEnvStatus = (data) => {
|
||||||
|
return service.post('/api/simulation/env-status', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||||
import GraphPanel from '../components/GraphPanel.vue'
|
import GraphPanel from '../components/GraphPanel.vue'
|
||||||
import Step3Simulation from '../components/Step3Simulation.vue'
|
import Step3Simulation from '../components/Step3Simulation.vue'
|
||||||
import { getProject, getGraphData } from '../api/graph'
|
import { getProject, getGraphData } from '../api/graph'
|
||||||
import { getSimulation } from '../api/simulation'
|
import { getSimulation, stopSimulation, closeSimulationEnv, getEnvStatus } from '../api/simulation'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
@ -142,7 +142,50 @@ const toggleMaximize = (target) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGoBack = () => {
|
const handleGoBack = async () => {
|
||||||
|
// 在返回 Step 2 之前,先关闭正在运行的模拟
|
||||||
|
addLog('准备返回 Step 2,正在关闭模拟...')
|
||||||
|
|
||||||
|
// 停止轮询
|
||||||
|
stopGraphRefresh()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 先尝试优雅关闭模拟环境
|
||||||
|
const envStatusRes = await getEnvStatus({ simulation_id: currentSimulationId.value })
|
||||||
|
|
||||||
|
if (envStatusRes.success && envStatusRes.data?.env_alive) {
|
||||||
|
addLog('正在关闭模拟环境...')
|
||||||
|
try {
|
||||||
|
await closeSimulationEnv({
|
||||||
|
simulation_id: currentSimulationId.value,
|
||||||
|
timeout: 10
|
||||||
|
})
|
||||||
|
addLog('✓ 模拟环境已关闭')
|
||||||
|
} catch (closeErr) {
|
||||||
|
addLog(`关闭模拟环境失败,尝试强制停止...`)
|
||||||
|
try {
|
||||||
|
await stopSimulation({ simulation_id: currentSimulationId.value })
|
||||||
|
addLog('✓ 模拟已强制停止')
|
||||||
|
} catch (stopErr) {
|
||||||
|
addLog(`强制停止失败: ${stopErr.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 环境未运行,检查是否需要停止进程
|
||||||
|
if (isSimulating.value) {
|
||||||
|
addLog('正在停止模拟进程...')
|
||||||
|
try {
|
||||||
|
await stopSimulation({ simulation_id: currentSimulationId.value })
|
||||||
|
addLog('✓ 模拟已停止')
|
||||||
|
} catch (err) {
|
||||||
|
addLog(`停止模拟失败: ${err.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
addLog(`检查模拟状态失败: ${err.message}`)
|
||||||
|
}
|
||||||
|
|
||||||
// 返回到 Step 2 (环境搭建)
|
// 返回到 Step 2 (环境搭建)
|
||||||
router.push({ name: 'Simulation', params: { simulationId: currentSimulationId.value } })
|
router.push({ name: 'Simulation', params: { simulationId: currentSimulationId.value } })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||||
import GraphPanel from '../components/GraphPanel.vue'
|
import GraphPanel from '../components/GraphPanel.vue'
|
||||||
import Step2EnvSetup from '../components/Step2EnvSetup.vue'
|
import Step2EnvSetup from '../components/Step2EnvSetup.vue'
|
||||||
import { getProject, getGraphData } from '../api/graph'
|
import { getProject, getGraphData } from '../api/graph'
|
||||||
import { getSimulation } from '../api/simulation'
|
import { getSimulation, stopSimulation, getEnvStatus, closeSimulationEnv } from '../api/simulation'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
@ -171,6 +171,70 @@ const handleNextStep = (params = {}) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Data Logic ---
|
// --- Data Logic ---
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并关闭正在运行的模拟
|
||||||
|
* 当用户从 Step 3 返回到 Step 2 时,默认用户要退出模拟
|
||||||
|
*/
|
||||||
|
const checkAndStopRunningSimulation = async () => {
|
||||||
|
if (!currentSimulationId.value) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 先检查模拟环境是否存活
|
||||||
|
const envStatusRes = await getEnvStatus({ simulation_id: currentSimulationId.value })
|
||||||
|
|
||||||
|
if (envStatusRes.success && envStatusRes.data?.env_alive) {
|
||||||
|
addLog('检测到模拟环境正在运行,正在关闭...')
|
||||||
|
|
||||||
|
// 尝试优雅关闭模拟环境
|
||||||
|
try {
|
||||||
|
const closeRes = await closeSimulationEnv({
|
||||||
|
simulation_id: currentSimulationId.value,
|
||||||
|
timeout: 10 // 10秒超时
|
||||||
|
})
|
||||||
|
|
||||||
|
if (closeRes.success) {
|
||||||
|
addLog('✓ 模拟环境已关闭')
|
||||||
|
} else {
|
||||||
|
addLog(`关闭模拟环境失败: ${closeRes.error || '未知错误'}`)
|
||||||
|
// 如果优雅关闭失败,尝试强制停止
|
||||||
|
await forceStopSimulation()
|
||||||
|
}
|
||||||
|
} catch (closeErr) {
|
||||||
|
addLog(`关闭模拟环境异常: ${closeErr.message}`)
|
||||||
|
// 如果优雅关闭异常,尝试强制停止
|
||||||
|
await forceStopSimulation()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 环境未运行,但可能进程还在,检查模拟状态
|
||||||
|
const simRes = await getSimulation(currentSimulationId.value)
|
||||||
|
if (simRes.success && simRes.data?.status === 'running') {
|
||||||
|
addLog('检测到模拟状态为运行中,正在停止...')
|
||||||
|
await forceStopSimulation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// 检查环境状态失败不影响后续流程
|
||||||
|
console.warn('检查模拟状态失败:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制停止模拟
|
||||||
|
*/
|
||||||
|
const forceStopSimulation = async () => {
|
||||||
|
try {
|
||||||
|
const stopRes = await stopSimulation({ simulation_id: currentSimulationId.value })
|
||||||
|
if (stopRes.success) {
|
||||||
|
addLog('✓ 模拟已强制停止')
|
||||||
|
} else {
|
||||||
|
addLog(`强制停止模拟失败: ${stopRes.error || '未知错误'}`)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
addLog(`强制停止模拟异常: ${err.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loadSimulationData = async () => {
|
const loadSimulationData = async () => {
|
||||||
try {
|
try {
|
||||||
addLog(`加载模拟数据: ${currentSimulationId.value}`)
|
addLog(`加载模拟数据: ${currentSimulationId.value}`)
|
||||||
|
|
@ -222,8 +286,13 @@ const refreshGraph = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
addLog('SimulationView 初始化')
|
addLog('SimulationView 初始化')
|
||||||
|
|
||||||
|
// 检查并关闭正在运行的模拟(用户从 Step 3 返回时)
|
||||||
|
await checkAndStopRunningSimulation()
|
||||||
|
|
||||||
|
// 加载模拟数据
|
||||||
loadSimulationData()
|
loadSimulationData()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue