feat(delivery): stream task updates with SSE

This commit is contained in:
mac
2026-07-28 09:55:04 +08:00
parent 7b4b9d2ee7
commit 5a260c443f
5 changed files with 168 additions and 4 deletions
+39 -1
View File
@@ -332,7 +332,7 @@
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Back, CircleCheck, Promotion, Refresh } from '@element-plus/icons-vue'
import { useRoute, useRouter } from 'vue-router'
@@ -553,6 +553,7 @@ const taskRefreshing = ref(false)
const taskRestoring = ref(false)
const seenEventIds = ref(new Set<number>())
const deliveryLog = ref('[ready] 等待创建交付任务...')
let taskEventSource: EventSource | undefined
const deliveryForm = reactive({
instanceName: `mysql-${currentName.value}-billing-02`,
@@ -674,6 +675,10 @@ onMounted(async () => {
await restoreActiveTask()
})
onUnmounted(() => {
stopTaskStream()
})
function handleCardClick(service: Service) {
if (service.disabled) {
if (service.key !== 'new') ElMessage.warning(`${service.name} 功能规划中,敬请期待`)
@@ -730,6 +735,7 @@ function startNewTask() {
}
function resetExecutionState() {
stopTaskStream()
precheckPassed.value = false
running.value = false
deliveryDone.value = false
@@ -816,6 +822,7 @@ async function createTask() {
deliveryLog.value += `\n[task] ${task.id} created by ${currentName.value}`
applyDeliveryStatus(task.status, '')
await refreshTaskSnapshot()
startTaskStream(task.id)
ElMessage.success('交付任务已创建')
} catch (error) {
running.value = false
@@ -909,6 +916,8 @@ async function restoreActiveTask() {
applyDeliveryStatus(detail.task.status, detail.task.error_message || '')
if (isTerminalDeliveryStatus(detail.task.status)) {
activeView.value = 'result'
} else {
startTaskStream(detail.task.id)
}
} catch (error) {
ElMessage.error(error instanceof Error ? error.message : '恢复交付任务失败')
@@ -933,6 +942,35 @@ function hydrateTaskSnapshot(task: DeliveryTask) {
}
}
function startTaskStream(taskId: string) {
stopTaskStream()
taskEventSource = deliveryApi.streamTask(taskId)
taskEventSource.addEventListener('snapshot', (event) => {
try {
const data = JSON.parse((event as MessageEvent).data) as { task?: DeliveryTask; events?: TaskEvent[] }
if (!data.task) return
hydrateTaskSnapshot(data.task)
applyTaskEvents(Array.isArray(data.events) ? data.events : [])
applyDeliveryStatus(data.task.status, data.task.error_message || '')
if (isTerminalDeliveryStatus(data.task.status)) {
activeView.value = 'result'
stopTaskStream()
}
} catch (error) {
appendLog(`[stream] ${error instanceof Error ? error.message : '解析任务状态失败'}`)
}
})
taskEventSource.onerror = () => {
if (running.value) appendLog('[stream] 实时连接中断,正在等待浏览器自动重连')
}
}
function stopTaskStream() {
if (!taskEventSource) return
taskEventSource.close()
taskEventSource = undefined
}
async function cancelDeployment() {
if (!deploymentId.value) return
canceling.value = true