|
|
@ -1,85 +1,191 @@ |
|
|
|
<template> |
|
|
|
<div class="component-page overflow-auto p-4 text-title"> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>加热区编号:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="输入加热区编号" /> |
|
|
|
<label>异常区编号:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="指定异常区编号" /> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('upTray')">抬起托盘</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('downTray')">降下托盘</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('takeOffCap')">取下拍子</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('putBackCap')">装回拍子</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('moveToActionArea')">移至操作区(加热、摇匀、拍照)</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('moveToUnusual')">移至异常区</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('moveToHeatArea')">(从操作区)移至加热区</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="component-page p-4 text-title"> |
|
|
|
<el-tabs type="border-card"> |
|
|
|
<el-tab-pane label="复合动作"> |
|
|
|
<div class="tabFrame"> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>加热区编号:</label> |
|
|
|
<el-select v-model="selectedArea" placeholder="Select" style="width: 200px"> |
|
|
|
<el-option |
|
|
|
v-for="item in areaOptions" |
|
|
|
:key="item.value" |
|
|
|
:label="item.label" |
|
|
|
:value="item.value" /> |
|
|
|
</el-select> |
|
|
|
<!-- <label>托盘高度:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" /> |
|
|
|
<span>mm</span> --> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('takeOffCap')">取下拍子</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('putBackCap')">装回拍子</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('moveToActionArea')"> |
|
|
|
移至操作区(加液、摇匀、拍照) |
|
|
|
</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('moveToHeatArea')"> |
|
|
|
(从操作区)移至加热区 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label for="">加液枪编号:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="输入加液枪编号" /> |
|
|
|
<label for="">注入量:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="输入注入量" /> |
|
|
|
<span>ml</span> |
|
|
|
<label for="">当前容量:</label> |
|
|
|
<span class="text-warn">50</span> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('injectFluid')">注入溶液</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>加热区编号:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="输入加热区编号" /> |
|
|
|
<label>温度:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" placeholder="输入温度" /> |
|
|
|
<span>℃</span> |
|
|
|
<label for="">当前温度:</label> |
|
|
|
<span class="text-warn">50</span> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('startHeat')">开始加热</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('stopHeat')">停止加热</button> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('keepHeat')">恒温</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4"> |
|
|
|
<label>源位置:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" /> |
|
|
|
<label>目标位置:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" /> |
|
|
|
</div> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('moveTube')">移动试管</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
<el-tab-pane label="单一动作"> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>加热区编号:</label> |
|
|
|
<el-select v-model="selectedAreaForHeat" placeholder="Select" style="width: 200px"> |
|
|
|
<el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|
|
|
</el-select> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('upTray')">抬起托盘</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('downTray')">降下托盘</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
X:<input type="number" v-model="x" class="rounded-sm px-1 w-16" /> Y:<input |
|
|
|
type="number" |
|
|
|
v-model="y" |
|
|
|
class="rounded-sm px-1 w-16" /> |
|
|
|
Z:<input type="number" v-model="z" class="rounded-sm px-1 w-16" /> |
|
|
|
<label for="">当前位置:</label> |
|
|
|
<span class="text-warn">50,50,50</span> |
|
|
|
</div> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('moveMachineArm')">移动机械臂</button> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('openClaw')">张开夹爪</button> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('closeClaw')">收合夹爪</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label for="">加液泵编号:</label> |
|
|
|
<input type="number" v-model="pumpId" class="rounded-sm px-2" placeholder="输入加液泵编号" /> |
|
|
|
<label for="">注入量:</label> |
|
|
|
<input type="number" v-model="pumpAmount" class="rounded-sm px-2" placeholder="输入注入量" /> |
|
|
|
<span>ml</span> |
|
|
|
<label for="">当前容量:</label> |
|
|
|
<span class="text-warn">50</span> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('injectFluid')">注入溶液</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>加热区编号:</label> |
|
|
|
<el-select v-model="selectedAreaForHeat" placeholder="Select" style="width: 200px"> |
|
|
|
<el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" /> |
|
|
|
</el-select> |
|
|
|
<label>温度:</label> |
|
|
|
<input type="number" v-model="heatTemperature" class="rounded-sm px-2" placeholder="输入温度" /> |
|
|
|
<span>℃</span> |
|
|
|
<label for="">当前温度:</label> |
|
|
|
<span class="text-warn">50</span> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('startHeat')">开始加热</button> |
|
|
|
<button class="btn-light px-2 py-1" @click="onCmdClick('stopHeat')">停止加热</button> |
|
|
|
<!-- <button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('keepHeat')">恒温</button> --> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="frame"> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('shakeUp')">摇匀</button> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('takePhoto')">拍照</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
X:<input type="number" class="rounded-sm px-1 w-16" /> Y:<input type="number" class="rounded-sm px-1 w-16" /> |
|
|
|
Z:<input type="number" class="rounded-sm px-1 w-16" /> |
|
|
|
<label for="">当前位置:</label> |
|
|
|
<span class="text-warn">50,50,50</span> |
|
|
|
</div> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('moveMachineArm')">移动机械臂</button> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4"> |
|
|
|
<label>源位置:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" /> |
|
|
|
<label>目标位置:</label> |
|
|
|
<input type="number" class="rounded-sm px-2" /> |
|
|
|
</div> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('moveTube')">移动试管</button> |
|
|
|
</div> |
|
|
|
<div class="frame"> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<label>摇匀速度:</label> |
|
|
|
<input type="number" v-model="shakeUpSpeed" class="rounded-sm px-2" /> |
|
|
|
</div> |
|
|
|
<div class="flex gap-4 flex-wrap"> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('startShakeUp')">开始摇匀</button> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('stopShakeUp')">结束摇匀</button> |
|
|
|
<button class="btn-light px-2 py-1 min-w-20" @click="onCmdClick('takePhoto')">拍照</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
<el-tab-pane label="校准"> |
|
|
|
<h1 class="text-lg font-medium py-2">加热区坐标:</h1> |
|
|
|
<div |
|
|
|
v-for="config in settingStore.heatAreaConfig" |
|
|
|
:key="config.code" |
|
|
|
class="flex items-center gap-4 flex-wrap mb-2"> |
|
|
|
<p class="min-w-6">{{ config.name }}</p> |
|
|
|
<span>X:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="config.valueObj.x" /> |
|
|
|
<span>Y:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="config.valueObj.y" /> |
|
|
|
<span>Z:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="config.valueObj.z" /> |
|
|
|
</div> |
|
|
|
<h1 class="text-lg font-medium py-2">操作区(加液、摇匀、拍照)坐标:</h1> |
|
|
|
<div class="flex items-center gap-4 flex-wrap mb-2"> |
|
|
|
<span>X:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.actionAreaConfig.valueObj.x" /> |
|
|
|
<span>Y:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.actionAreaConfig.valueObj.y" /> |
|
|
|
<span>Z:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.actionAreaConfig.valueObj.z" /> |
|
|
|
</div> |
|
|
|
<h1 class="text-lg font-medium py-2">拍子区坐标:</h1> |
|
|
|
<div class="flex items-center gap-4 flex-wrap mb-2"> |
|
|
|
<span>X:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.capAreaConfig.valueObj.x" /> |
|
|
|
<span>Y:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.capAreaConfig.valueObj.y" /> |
|
|
|
<span>Z:</span> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" v-model="settingStore.capAreaConfig.valueObj.z" /> |
|
|
|
</div> |
|
|
|
<h1 class="text-lg font-medium py-1">加液:</h1> |
|
|
|
<div class="flex items-center gap-4 flex-wrap"> |
|
|
|
<p>1毫升对应</p> |
|
|
|
<input type="number" class="rounded-sm px-1 w-16" /> 步 |
|
|
|
</div> |
|
|
|
<footer class="flex justify-end mt-4"> |
|
|
|
<button class="btn-dark px-2 py-1 min-w-20" @click="saveConfig">保存</button> |
|
|
|
</footer> |
|
|
|
</el-tab-pane> |
|
|
|
</el-tabs> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
<script setup lang="ts"> |
|
|
|
import { CmdDescMap, debugCmd, type DebugCmd } from "@/services/debug/debugApi"; |
|
|
|
import { createWebSocket, sharedWsUrl } from "@/services/socket"; |
|
|
|
import { updateConfig } from "@/services/sysConfig/sysConfig"; |
|
|
|
import { useSettingStore } from "@/stores/setting"; |
|
|
|
import { showToast } from "vant"; |
|
|
|
import { onMounted, onUnmounted } from "vue"; |
|
|
|
import { computed, onMounted, onUnmounted, ref } from "vue"; |
|
|
|
|
|
|
|
const settingStore = useSettingStore(); |
|
|
|
|
|
|
|
const selectedArea = ref(""); |
|
|
|
const selectedAreaForHeat = ref(""); |
|
|
|
const heatTemperature = ref(0); |
|
|
|
|
|
|
|
const x = ref(0); |
|
|
|
const y = ref(0); |
|
|
|
const z = ref(0); |
|
|
|
|
|
|
|
const pumpId = ref(1); |
|
|
|
const pumpAmount = ref(10); |
|
|
|
|
|
|
|
const shakeUpSpeed = ref(5); |
|
|
|
|
|
|
|
const areaOptions = computed(() => { |
|
|
|
return settingStore.heatAreaConfig.map(c => ({ label: c.name, value: c.id })); |
|
|
|
}); |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
const wsClient = createWebSocket(sharedWsUrl); |
|
|
@ -107,8 +213,31 @@ function onCmdClick(command: DebugCmd) { |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
function saveConfig() { |
|
|
|
const heatCfg = settingStore.heatAreaConfig.map(c => ({ |
|
|
|
id: c.id, |
|
|
|
value: `${c.valueObj.x},${c.valueObj.y},${c.valueObj.z}`, |
|
|
|
})); |
|
|
|
const actionCfg = { |
|
|
|
id: settingStore.actionAreaConfig.id || 0, |
|
|
|
value: `${settingStore.actionAreaConfig.valueObj.x},${settingStore.actionAreaConfig.valueObj.y},${settingStore.actionAreaConfig.valueObj.z}`, |
|
|
|
}; |
|
|
|
const capCfg = { |
|
|
|
id: settingStore.capAreaConfig.id || 0, |
|
|
|
value: `${settingStore.capAreaConfig.valueObj.x},${settingStore.capAreaConfig.valueObj.y},${settingStore.capAreaConfig.valueObj.z}`, |
|
|
|
}; |
|
|
|
updateConfig([...heatCfg, actionCfg, capCfg]).then(res => { |
|
|
|
if (res.success) { |
|
|
|
showToast("保存成功"); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
|
|
.tabFrame { |
|
|
|
overflow: auto; |
|
|
|
height: calc(100vh - var(--headerHeight) - var(--footerHeight) - 90px); |
|
|
|
} |
|
|
|
.frame { |
|
|
|
border-bottom: solid 1px #ddd; |
|
|
|
padding: 1rem 0.5rem; |
|
|
@ -116,9 +245,9 @@ function onCmdClick(command: DebugCmd) { |
|
|
|
flex-direction: column; |
|
|
|
align-items: start; |
|
|
|
gap: 1rem; |
|
|
|
input { |
|
|
|
background-color: #f5f5f5; |
|
|
|
height: 1.75rem; |
|
|
|
} |
|
|
|
} |
|
|
|
input { |
|
|
|
background-color: #f5f5f5; |
|
|
|
height: 1.75rem; |
|
|
|
} |
|
|
|
</style> |