<template>
|
<div class="task-orchestration">
|
<div class="panel-header">
|
<div>
|
<h3>多设备测试编排</h3>
|
<p v-if="group">当前设备组:{{ group.groupName }}({{ group.deviceCount || '-' }} 台设备)</p>
|
<p v-else class="warning">请先在左侧选择一个设备组</p>
|
<p v-if="group && loadDeviceName" class="sub-info">上大车设备:{{ loadDeviceName }}</p>
|
</div>
|
<div class="action-buttons">
|
<el-button
|
type="danger"
|
plain
|
:disabled="!group || !loadDeviceId || loadDeviceLoading"
|
:loading="clearLoading"
|
@click="handleClearPlc"
|
>
|
<el-icon><Delete /></el-icon>
|
清空PLC
|
</el-button>
|
<el-button type="primary" :disabled="!group" :loading="loading" @click="handleSubmit">
|
<el-icon><Promotion /></el-icon>
|
启动测试
|
</el-button>
|
</div>
|
</div>
|
|
<el-form :model="form" label-width="120px">
|
<el-form-item label="玻璃ID列表">
|
<el-input
|
v-model="glassIdsInput"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入玻璃条码,支持多行或逗号分隔"
|
/>
|
</el-form-item>
|
<el-form-item label="位置编码">
|
<el-input v-model="form.positionCode" placeholder="例如:POS1" />
|
</el-form-item>
|
<el-form-item label="存储位置">
|
<el-input-number v-model="form.storagePosition" :min="1" :max="200" />
|
</el-form-item>
|
<el-form-item label="执行间隔 (ms)">
|
<el-input-number v-model="form.executionInterval" :min="100" :max="10000" />
|
</el-form-item>
|
</el-form>
|
</div>
|
</template>
|
|
<script setup>
|
import { computed, reactive, ref, watch } from 'vue'
|
import { ElMessage } from 'element-plus'
|
import { Delete, Promotion } from '@element-plus/icons-vue'
|
import { multiDeviceTaskApi } from '@/api/device/multiDeviceTask'
|
import { deviceGroupApi, deviceInteractionApi } from '@/api/device/deviceManagement'
|
|
const props = defineProps({
|
group: {
|
type: Object,
|
default: null
|
}
|
})
|
|
const emit = defineEmits(['task-started'])
|
|
const form = reactive({
|
positionCode: '',
|
storagePosition: null,
|
executionInterval: 1000
|
})
|
|
const glassIdsInput = ref('')
|
const loading = ref(false)
|
const clearLoading = ref(false)
|
const loadDeviceId = ref(null)
|
const loadDeviceName = ref('')
|
const loadDeviceLoading = ref(false)
|
|
watch(
|
() => props.group,
|
() => {
|
glassIdsInput.value = ''
|
fetchLoadDevice()
|
}
|
)
|
|
const glassIds = computed(() => {
|
if (!glassIdsInput.value) return []
|
return glassIdsInput.value
|
.split(/[\n,,]/)
|
.map((item) => item.trim())
|
.filter((item) => item.length > 0)
|
})
|
|
const fetchLoadDevice = async () => {
|
loadDeviceId.value = null
|
loadDeviceName.value = ''
|
if (!props.group) {
|
return
|
}
|
const groupId = props.group.id || props.group.groupId
|
if (!groupId) {
|
return
|
}
|
loadDeviceLoading.value = true
|
try {
|
const response = await deviceGroupApi.getGroupDevices(groupId)
|
const rawList = response?.data
|
const deviceList = Array.isArray(rawList)
|
? rawList
|
: Array.isArray(rawList?.records)
|
? rawList.records
|
: Array.isArray(rawList?.data)
|
? rawList.data
|
: []
|
const targetDevice =
|
deviceList.find((item) => (item.deviceType || '').toUpperCase() === 'LOAD_VEHICLE') ||
|
deviceList[0]
|
if (targetDevice && targetDevice.id) {
|
loadDeviceId.value = targetDevice.id
|
loadDeviceName.value = targetDevice.deviceName || targetDevice.deviceCode || `ID: ${targetDevice.id}`
|
}
|
} catch (error) {
|
console.error('加载设备信息失败:', error)
|
ElMessage.error(error?.message || '获取设备信息失败')
|
} finally {
|
loadDeviceLoading.value = false
|
}
|
}
|
|
const handleSubmit = async () => {
|
if (!props.group) {
|
ElMessage.warning('请先选择设备组')
|
return
|
}
|
if (glassIds.value.length === 0) {
|
ElMessage.warning('请至少输入一个玻璃ID')
|
return
|
}
|
try {
|
loading.value = true
|
await multiDeviceTaskApi.startTask({
|
groupId: props.group.id || props.group.groupId,
|
parameters: {
|
glassIds: glassIds.value,
|
positionCode: form.positionCode || null,
|
storagePosition: form.storagePosition,
|
executionInterval: form.executionInterval
|
}
|
})
|
ElMessage.success('任务已启动')
|
emit('task-started')
|
} catch (error) {
|
ElMessage.error(error?.message || '任务启动失败')
|
} finally {
|
loading.value = false
|
}
|
}
|
|
const handleClearPlc = async () => {
|
if (!props.group) {
|
ElMessage.warning('请先选择设备组')
|
return
|
}
|
if (!loadDeviceId.value) {
|
ElMessage.warning('未找到上大车设备,无法清空PLC')
|
return
|
}
|
try {
|
clearLoading.value = true
|
const response = await deviceInteractionApi.executeOperation({
|
deviceId: loadDeviceId.value,
|
operation: 'clearGlass',
|
params: {
|
positionCode: form.positionCode || null
|
}
|
})
|
if (response?.code !== 200) {
|
throw new Error(response?.message || 'PLC清空失败')
|
}
|
const result = response?.data
|
if (result?.success) {
|
ElMessage.success(result?.message || 'PLC已清空')
|
glassIdsInput.value = ''
|
} else {
|
throw new Error(result?.message || 'PLC清空失败')
|
}
|
} catch (error) {
|
console.error('清空PLC失败:', error)
|
ElMessage.error(error?.message || 'PLC清空失败')
|
} finally {
|
clearLoading.value = false
|
}
|
}
|
</script>
|
|
<style scoped>
|
.task-orchestration {
|
background: #fff;
|
border-radius: 12px;
|
padding: 20px;
|
box-shadow: 0 8px 32px rgba(15, 18, 63, 0.08);
|
}
|
|
.panel-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 16px;
|
}
|
|
.panel-header h3 {
|
margin: 0;
|
}
|
|
.panel-header p {
|
margin: 4px 0 0;
|
color: #909399;
|
font-size: 13px;
|
}
|
|
.panel-header .warning {
|
color: #f56c6c;
|
}
|
|
.panel-header .sub-info {
|
margin-top: 4px;
|
color: #606266;
|
font-size: 12px;
|
}
|
|
.action-buttons {
|
display: flex;
|
gap: 12px;
|
align-items: center;
|
}
|
</style>
|