diff --git a/src/components/dashboard/SendPanel.vue b/src/components/dashboard/SendPanel.vue index 0a06dd3..af00248 100644 --- a/src/components/dashboard/SendPanel.vue +++ b/src/components/dashboard/SendPanel.vue @@ -25,7 +25,7 @@ const { variables: globalVars, setVariable: setGlobalVar, importFromBindings } = // ─── State ───────────────────────────────────────────────────── const selectedConnectionId = ref('') -const selectedPresetId = ref('') +const selectedPresetIds = ref([]) const topic = ref('') const payload = ref('') const qos = ref<0 | 1 | 2>(0) @@ -40,6 +40,8 @@ const responseTopic = ref('') const correlationData = ref('') const sending = ref(false) const showGlobalVarMgr = ref(false) +const batchMode = ref(false) +const batchProgress = ref<{ presetName: string; status: 'pending' | 'sending' | 'success' | 'error'; message?: string }[]>([]) // ─── Computed ────────────────────────────────────────────────── @@ -47,8 +49,12 @@ const connectedConnections = computed(() => props.connections.filter((c) => c.status === 'connected'), ) +const selectedPresets = computed(() => + props.presets.filter((p) => selectedPresetIds.value.includes(p.id)), +) + const selectedPreset = computed(() => - props.presets.find((p) => p.id === selectedPresetId.value), + props.presets.find((p) => p.id === selectedPresetIds.value[selectedPresetIds.value.length - 1]), ) const presetVariables = computed(() => { @@ -67,7 +73,7 @@ const presetVariables = computed(() => { // ─── Watch preset ────────────────────────────────────────────── watch(selectedPreset, (preset) => { - if (preset) { + if (preset && !batchMode.value) { topic.value = preset.topic payload.value = preset.payloadTemplate qos.value = preset.qos @@ -78,7 +84,6 @@ watch(selectedPreset, (preset) => { const topicVars = extractVariables(preset.topic) const allVars = [...new Set([...presetVars, ...topicVars])] for (const v of allVars) { - // Auto-fill from global variables first, then keep existing newBindings[v] = globalVars.value[v] ?? variableBindings.value[v] ?? '' } variableBindings.value = newBindings @@ -86,63 +91,111 @@ watch(selectedPreset, (preset) => { } }) -// ─── Send ────────────────────────────────────────────────────── +// ─── Send Single ─────────────────────────────────────────────── -async function send() { - if (!selectedConnectionId.value) { - ElMessage.warning('请先选择一个连接') - return - } - if (!topic.value.trim()) { - ElMessage.warning('请输入主题') - return - } - if (!payload.value.trim()) { - ElMessage.warning('请输入消息内容') - return - } +function getPublishDto(preset?: Preset): PublishDto { + const t = preset?.topic ?? topic.value + const p = preset?.payloadTemplate ?? payload.value + const q = preset?.qos ?? qos.value + const r = preset?.retain ?? retain.value + const up = preset ? JSON.parse(JSON.stringify(preset.userProperties)) : userProperties.value - const resolvedTopic = resolveTemplate(topic.value, variableBindings.value) - const resolvedPayload = resolveTemplate(payload.value, variableBindings.value) - const resolvedProps = resolveUserProperties(userProperties.value, variableBindings.value) + const resolvedTopic = resolveTemplate(t, variableBindings.value) + const resolvedPayload = resolveTemplate(p, variableBindings.value) + const resolvedProps = resolveUserProperties(up, variableBindings.value) - // Save current bindings to global variables - importFromBindings(variableBindings.value) - - const publishDto: PublishDto = { + return { connection_id: selectedConnectionId.value, topic: resolvedTopic, payload: resolvedPayload, - qos: qos.value, - retain: retain.value, + qos: q, + retain: r, user_properties: resolvedProps, content_type: contentType.value || null, message_expiry_interval: messageExpiryInterval.value, response_topic: responseTopic.value || null, correlation_data: correlationData.value || null, } +} + +async function sendSingle(preset?: Preset) { + if (!selectedConnectionId.value) { + ElMessage.warning('请先选择一个连接') + return false + } + const dto = getPublishDto(preset) + if (!dto.topic.trim()) { ElMessage.warning('请输入主题'); return false } + if (!dto.payload.trim()) { ElMessage.warning('请输入消息内容'); return false } - sending.value = true try { - await mqttPublish(publishDto) - ElMessage.success('消息已发送') - emit('sent', publishDto) + await mqttPublish(dto) + emit('sent', dto) + return true } catch (e: any) { ElMessage.error(`发送失败: ${e}`) - } finally { - sending.value = false + return false } } +async function send() { + importFromBindings(variableBindings.value) + sending.value = true + if (batchMode.value && selectedPresets.value.length > 0) { + // Batch send all selected presets + batchProgress.value = selectedPresets.value.map((p) => ({ + presetName: p.name, + status: 'pending' as const, + })) + for (let i = 0; i < selectedPresets.value.length; i++) { + const preset = selectedPresets.value[i] + batchProgress.value[i].status = 'sending' + try { + const dto = getPublishDto(preset) + if (!dto.topic.trim()) { + batchProgress.value[i].status = 'error' + batchProgress.value[i].message = '主题为空' + continue + } + if (!dto.payload.trim()) { + batchProgress.value[i].status = 'error' + batchProgress.value[i].message = 'Payload 为空' + continue + } + await mqttPublish(dto) + emit('sent', dto) + batchProgress.value[i].status = 'success' + } catch (e: any) { + batchProgress.value[i].status = 'error' + batchProgress.value[i].message = String(e) + } + } + const successCount = batchProgress.value.filter((p) => p.status === 'success').length + const errorCount = batchProgress.value.filter((p) => p.status === 'error').length + ElMessage.success(`批量发送完成: ${successCount} 成功, ${errorCount} 失败`) + } else { + // Single send + const ok = await sendSingle() + if (ok) ElMessage.success('消息已发送') + } + sending.value = false +} + // ─── Save as global variable when a binding value changes ────── function onBindingChange(name: string, value: string) { variableBindings.value = { ...variableBindings.value, [name]: value } - // Auto-save to global if value is non-empty if (value.trim()) { setGlobalVar(name, value) } } + +function toggleBatchMode() { + batchMode.value = !batchMode.value + if (!batchMode.value) { + selectedPresetIds.value = [] + batchProgress.value = [] + } +}