Browse Source

调试页面校准接口

feature/layout_0214
zhangjiming 6 months ago
parent
commit
c7a85db9f7
  1. 185
      package-lock.json
  2. 1
      package.json
  3. 11
      src/App.vue
  4. 3
      src/main.ts
  5. 10
      src/services/debug/debugApi.ts
  6. 27
      src/services/sysConfig/sysConfig.ts
  7. 39
      src/stores/setting.ts
  8. 283
      src/views/debug/debug.vue

185
package-lock.json

@ -10,6 +10,7 @@
"dependencies": {
"axios": "^1.7.9",
"dayjs": "^1.11.13",
"element-plus": "^2.9.4",
"mitt": "^3.0.1",
"pinia": "^2.3.0",
"ramda": "^0.30.1",
@ -529,6 +530,24 @@
"dev": true,
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@ctrl/tinycolor": {
"version": "3.6.1",
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/@element-plus/icons-vue": {
"version": "2.3.1",
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
"integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==",
"license": "MIT",
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.24.2",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
@ -954,6 +973,31 @@
"node": ">=18"
}
},
"node_modules/@floating-ui/core": {
"version": "1.6.9",
"resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.6.9.tgz",
"integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==",
"license": "MIT",
"dependencies": {
"@floating-ui/utils": "^0.2.9"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.6.13",
"resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.6.13.tgz",
"integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
"license": "MIT",
"dependencies": {
"@floating-ui/core": "^1.6.0",
"@floating-ui/utils": "^0.2.9"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.9",
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.9.tgz",
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
"license": "MIT"
},
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz",
@ -1390,6 +1434,17 @@
"dev": true,
"license": "MIT"
},
"node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.7",
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
@ -1713,6 +1768,21 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==",
"license": "MIT"
},
"node_modules/@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/node": {
"version": "22.10.7",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.10.7.tgz",
@ -1872,6 +1942,12 @@
"@types/rx-lite": "*"
}
},
"node_modules/@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
"license": "MIT"
},
"node_modules/@vant/popperjs": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz",
@ -2224,6 +2300,42 @@
}
}
},
"node_modules/@vueuse/core": {
"version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"license": "MIT",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/alien-signals": {
"version": "0.4.14",
"resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-0.4.14.tgz",
@ -2298,6 +2410,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
"license": "MIT"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
@ -2785,6 +2903,32 @@
"dev": true,
"license": "ISC"
},
"node_modules/element-plus": {
"version": "2.9.4",
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.9.4.tgz",
"integrity": "sha512-sGnW0wd9zf6lEGixXV2gfwx3X6VTMkP52qTkX7zbURJ2oariyslrKTBh2txt1sdn1pUvj2l0KY3OfSXoZGmDOw==",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^2.3.1",
"@floating-ui/dom": "^1.0.1",
"@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"@types/lodash": "^4.14.182",
"@types/lodash-es": "^4.17.6",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.13",
"escape-html": "^1.0.3",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"lodash-unified": "^1.0.2",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
"peerDependencies": {
"vue": "^3.2.0"
}
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz",
@ -2865,6 +3009,12 @@
"node": ">=6"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
@ -3513,6 +3663,29 @@
"dev": true,
"license": "MIT"
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
},
"node_modules/lodash-unified": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==",
"license": "MIT",
"peerDependencies": {
"@types/lodash-es": "*",
"lodash": "*",
"lodash-es": "*"
}
},
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz",
@ -3532,6 +3705,12 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/memoize-one": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
"license": "MIT"
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz",
@ -3726,6 +3905,12 @@
"node": ">=0.10.0"
}
},
"node_modules/normalize-wheel-es": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==",
"license": "BSD-3-Clause"
},
"node_modules/npm-normalize-package-bin": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz",

1
package.json

@ -13,6 +13,7 @@
"dependencies": {
"axios": "^1.7.9",
"dayjs": "^1.11.13",
"element-plus": "^2.9.4",
"mitt": "^3.0.1",
"pinia": "^2.3.0",
"ramda": "^0.30.1",

11
src/App.vue

@ -2,7 +2,11 @@
import { useRouter } from "vue-router";
import { exceptionOb } from "./services/httpRequest";
import { createWebSocket, sharedWsUrl } from "./services/socket";
import { onMounted } from "vue";
import { getConfig } from "./services/sysConfig/sysConfig";
import { useSettingStore } from "./stores/setting";
const router = useRouter();
const settingStore = useSettingStore();
exceptionOb.subscribe(exp => {
if (exp === "invalidToken") {
@ -10,6 +14,13 @@ exceptionOb.subscribe(exp => {
}
});
onMounted(() => {
getConfig().then(res => {
if (res.success) {
settingStore.setConfigs(res.data);
}
});
});
</script>
<template>

3
src/main.ts

@ -4,6 +4,8 @@ import "./assets/style/tailwind.css";
import { createApp } from "vue";
import { createPinia } from "pinia";
import Vant from "vant";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import App from "./App.vue";
import router from "./router";
import "vant/lib/index.css";
@ -13,6 +15,7 @@ const app = createApp(App);
app.use(createPinia());
app.use(router);
app.use(Vant);
app.use(ElementPlus);
app.mount("#app");

10
src/services/debug/debugApi.ts

@ -5,7 +5,8 @@ export const CmdDescMap: { [k in DebugCmd]: string } = {
downTray: "降下托盘",
injectFluid: "注入溶液",
moveToActionArea: "移至操作区",
shakeUp: "摇匀",
startShakeUp: "开始摇匀",
stopShakeUp: "结束摇匀",
startHeat: "开始加热",
stopHeat: "停止加热",
keepHeat: "恒温",
@ -14,6 +15,8 @@ export const CmdDescMap: { [k in DebugCmd]: string } = {
moveToHeatArea: "移至加热区",
takeOffCap: "取下拍子",
putBackCap: "装回拍子",
openClaw: "张开夹爪",
closeClaw: "收合夹爪",
moveMachineArm: "移动机械臂",
moveTube: "移动试管",
};
@ -23,7 +26,8 @@ export type DebugCmd =
| "downTray" // 降下托盘
| "injectFluid" // 注入溶液
| "moveToActionArea" // 移至操作区
| "shakeUp" // 摇匀
| "startShakeUp" // 开始摇匀
| "stopShakeUp" // 结束摇匀
| "startHeat" // 开始加热
| "stopHeat" // 停止加热
| "keepHeat" // 恒温
@ -32,6 +36,8 @@ export type DebugCmd =
| "moveToHeatArea" // 移至加热区
| "takeOffCap" // 取下拍子
| "putBackCap" // 装回拍子
| "openClaw" // 张开夹爪
| "closeClaw" // 收合夹爪
| "moveMachineArm" // 移动机械臂
| "moveTube"; // 移动试管

27
src/services/sysConfig/sysConfig.ts

@ -0,0 +1,27 @@
import type { BaseResponse } from "../httpRequest";
import httpRequest from "../httpRequest";
export type ConfigCategory = "heat_area" | "solution_area" | "lid_area" | "sys_setting";
export type ConfigItem = {
id: number;
name: string;
code: ConfigCategory;
value: string;
children: {
id: number;
name: string;
code: string;
value: string;
valueObj?: { x: number; y: number; z: number };
}[];
};
export function getConfig() {
return httpRequest<BaseResponse<ConfigItem[]>>({ url: "/api/sys/getConfig" });
}
export function updateConfig(params: { id: number; value: string }[]) {
return httpRequest<BaseResponse>({ url: "/api/sys/updateConfig", method: "PUT", params });
}

39
src/stores/setting.ts

@ -0,0 +1,39 @@
import type { ConfigItem } from "@/services/sysConfig/sysConfig";
import { defineStore } from "pinia";
import { computed, ref } from "vue";
export const useSettingStore = defineStore("setting", () => {
const configs = ref<ConfigItem[] | undefined>();
const setConfigs = (usr: ConfigItem[]) => {
configs.value = usr;
};
const heatAreaConfig = computed(() => {
if (!configs.value) return [];
return (configs.value.find(c => c.code === "heat_area")?.children || []).map(c => {
const [x, y, z] = c.value.split(",");
return { ...c, valueObj: { x: +x, y: +y, z: +z } };
});
});
const actionAreaConfig = computed(() => {
if (!configs.value) return { valueObj: {x: 0, y: 0, z: 0}};
const c = configs.value.find(c => c.code === "solution_area")?.children[0];
const [x, y, z] = c!.value.split(",");
return { ...c, valueObj: { x: +x, y: +y, z: +z } };
});
const capAreaConfig = computed(() => {
if (!configs.value) return { valueObj: {x: 0, y: 0, z: 0}};
const c = configs.value.find(c => c.code === "lid_area")?.children[0];
const [x, y, z] = c!.value.split(",");
return { ...c, valueObj: { x: +x, y: +y, z: +z } };
});
const systemSetting = computed(() => {
if (!configs.value) return [];
return configs.value.find(c => c.code === "sys_setting")?.children || [];
});
return { heatAreaConfig, actionAreaConfig, capAreaConfig, systemSetting, setConfigs };
});

283
src/views/debug/debug.vue

@ -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">505050</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">505050</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>
Loading…
Cancel
Save