石墨仪设备 前端仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

972 lines
24 KiB

6 months ago
5 months ago
5 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
5 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
5 months ago
5 months ago
6 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
5 months ago
6 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
  1. <template>
  2. <div class="graphite_home component-page overflow-auto" id="heatArea">
  3. <div class="heat_area">
  4. <div v-for="(item, index) in heatList" :key="item.id">
  5. <HeatPosition
  6. :heatInfo="{ ...item, index }"
  7. :tubeIndex="index + 1"
  8. @onSelectedTray="onSelectedTray"
  9. @onSetHeatAreaTemp="onSetHeatAreaTemp"
  10. @onSelectCraft="
  11. craftData => {
  12. onSelectCraft(item, craftData);
  13. }
  14. "></HeatPosition>
  15. </div>
  16. <!--执行中状态的遮罩层-->
  17. </div>
  18. <!--拍照区-->
  19. <div class="picture_area">
  20. <!--加液区和拍照区可切换-->
  21. <TakePickture></TakePickture>
  22. <!-- <div v-else style="display: flex;justify-content: center;">
  23. <div class="home_tube">
  24. <div
  25. class="inner-circle"
  26. v-for="(tubeItem, index) in tubeList"
  27. :key="index"
  28. :style="{ background: tubeItem.color }"
  29. ></div>
  30. </div>
  31. </div> -->
  32. <!--操作区-->
  33. <div class="graphite_btn_container">
  34. <van-button v-if="doorStatus" size="large" class="btn_size op_open_door" @click="onCloseDoor">关门</van-button>
  35. <van-button v-else size="large" class="btn_size op_open_door" @click="onOPenDoor">开门</van-button>
  36. <van-button size="large" class="btn_size op_start_task" @click="startTask">开始实验</van-button>
  37. <van-button size="large" class="btn_size op_stop_task" @click="onEndTask">结束实验</van-button>
  38. <van-button size="large" class="btn_size op_select_craft" @click="onChooseCaft">{{ craftName }}</van-button>
  39. <van-button size="large" class="btn_size op_exec_craft" @click="onCraftStart()">{{ exeCraftName }}</van-button>
  40. <van-button size="large" class="btn_size op_add_liquid" @click="onAddLiquid">添加溶液</van-button>
  41. <van-button v-if="!isSharking" size="large" class="btn_size op_shake_up" @click="onStartShakingTube"
  42. >摇匀</van-button
  43. >
  44. <van-button v-else size="large" class="btn_size op_shake_up" @click="onStopShakingTube">结束摇匀</van-button>
  45. <van-button size="large" class="btn_size op_move_heat" @click="onMoveToHeat">移至加热</van-button>
  46. <van-button size="large" class="btn_size op_move_act" @click="onMoveToOperationArea">移至加液</van-button>
  47. <van-button size="large" class="btn_size op_move_exception" @click="onMoveToSpecial">移至特殊</van-button>
  48. <van-button v-if="!isHeating" size="large" class="btn_size op_start_heat" @click="onStartHeat"
  49. >开始加热</van-button
  50. >
  51. <van-button v-else size="large" class="btn_size op_start_heat" @click="onStopHeat">停止加热</van-button>
  52. <van-button size="large" class="btn_size op_up_tray" @click="onUpTray">抬起托盘</van-button>
  53. </div>
  54. </div>
  55. <van-overlay :show="liquidVisible" v-if="liquidVisible" style="z-index: 9999">
  56. <div class="liquid">
  57. <div class="addLiquid">
  58. <AddLiquid
  59. :currentSelectedTube="currentSelectedTube"
  60. @cancel="liquidVisible = false"
  61. @onAddSolution="onAddSolution"></AddLiquid>
  62. </div>
  63. </div>
  64. </van-overlay>
  65. <!--选择工艺-->
  66. <OverlayModal :visible="craftVisible">
  67. <CraftList @changeVisible="changeVisible" @selectedCraft="onHandleSelectedCraft"></CraftList>
  68. </OverlayModal>
  69. <!--实验名称-->
  70. <OverlayModal :visible="taskNameVisible">
  71. <div class="task_name">
  72. <div class="task_title">开始新实验</div>
  73. <div class="task_name_content">
  74. <div class="mt-3">实验名称</div>
  75. <div class="task_auto">
  76. <input v-model="taskName" placeholder="实验名称" class="task_input" />
  77. <div v-if="!taskName" style="color: red; font-size: 1rem">请输入实验名称</div>
  78. </div>
  79. </div>
  80. <br />
  81. <footer class="task_button">
  82. <button class="btn-dark px-2 py-1 min-w-20" @click="onSave">保存</button>
  83. <button class="cancel_btn" @click="onCancel">取消</button>
  84. </footer>
  85. </div>
  86. </OverlayModal>
  87. </div>
  88. </template>
  89. <script lang="ts" setup>
  90. import { ref, reactive, onMounted, onUnmounted, watch } from "vue";
  91. //@ts-ignore
  92. import { ElMessage, ElMessageBox } from "element-plus";
  93. import { createWebSocket, sharedWsUrl } from "@/services/socket";
  94. import { HeatPosition, TakePickture, AddLiquid } from "./components";
  95. import OverlayModal from "@/components/OverlayModal.vue";
  96. import CraftList from "@/views/graphite/components/CraftList.vue";
  97. import { injectFluid } from "@/services/task/task";
  98. import { setOnGoingStatus, useStatusStore } from "@/stores/status";
  99. import { getIngTask, saveTaskName, stopTask } from "@/services/task/task";
  100. import { CmdDescMap, taskCmd, type OperationCmd } from "@/services/globalCmd/globalCmd";
  101. import { craftStart, craftStop } from "@/services/ore/oreManage";
  102. import { getTxnRecord } from "@/services/txn";
  103. import { useSettingStore } from "@/stores/setting";
  104. import { useCraftStore } from "@/stores/craft";
  105. const craftStore = useCraftStore();
  106. const craftInfo = ref(craftStore.craftInfo);
  107. const settingStore = useSettingStore();
  108. const craftName = ref("选择工艺");
  109. const exeCraftName = ref("执行工艺");
  110. watch(
  111. () => craftStore.craftInfo,
  112. newVal => {
  113. craftInfo.value = newVal;
  114. if (newVal?.status == 1) {
  115. craftName.value = "暂停工艺";
  116. exeCraftName.value = "停止工艺";
  117. }
  118. }
  119. );
  120. //设备的全局状态
  121. const statusStore = useStatusStore();
  122. const heatAearStatusList = ref(statusStore.status?.heatArea || []);
  123. const heatList: any = ref([]);
  124. const craftVisible = ref(false);
  125. let tubeList = reactive<any>([]);
  126. const selectedColor = "#4F85FB";
  127. const emptyColor = "#FFFFFF";
  128. const taskName = ref("");
  129. let globeStatus: any = 0;
  130. onMounted(() => {
  131. //6个加热区数据
  132. heatList.value = settingStore.heatAreaConfig.map((item: any) => {
  133. //添加一个字段,默认为未选中
  134. item.isSelect = false;
  135. heatAearStatusList.value.forEach((areaItem: any) => {
  136. if (areaItem.hardwareId == item.hardwareId) {
  137. item = {
  138. ...item,
  139. heatAearStatus: areaItem,
  140. };
  141. }
  142. });
  143. return item;
  144. });
  145. //设备16个试管的基础数据
  146. tubeBaseConfig();
  147. //连接socket
  148. const wsClient = createWebSocket(sharedWsUrl);
  149. const subscription = wsClient.dataOb.subscribe(data => {
  150. if (!globeStatus) {
  151. //为了只输入一行,不想后台一直打印此处日志 TODO
  152. console.log("globeStatus====", data);
  153. }
  154. globeStatus = 1;
  155. if (data.type === "cmd") {
  156. const cmdInfo = getTxnRecord(data.data.commandId, "task");
  157. if (cmdInfo) {
  158. const command: any = cmdInfo.command;
  159. //@ts-ignore
  160. const cmdName = CmdDescMap[command];
  161. const result = data.data.success ? "执行完毕" : `执行失败 ${data.data.message}`;
  162. ElMessage({
  163. message: `${cmdName} ${result}`,
  164. type: data.data.success ? "success" : "error",
  165. });
  166. }
  167. }
  168. });
  169. wsClient.connect();
  170. onUnmounted(() => {
  171. subscription.unsubscribe();
  172. });
  173. });
  174. //选中的托盘
  175. const selectedTrayList = ref<any>([]);
  176. const selectedTrayObj: any = {};
  177. const onSelectedTray = (heatAreaItem: any, type: string) => {
  178. heatList.value[heatAreaItem.index] = heatAreaItem;
  179. //取消选中,已经存在selectedTrayList中
  180. let ids = selectedTrayList.value.map((tube: any) => tube.id);
  181. if (type == "isClick") {
  182. //点击加热区
  183. if (ids.includes(heatAreaItem.id)) {
  184. heatAreaItem.isSelect = false;
  185. selectedTrayList.value = selectedTrayList.value.filter((selectedItem: any) => selectedItem.id != heatAreaItem.id);
  186. } else {
  187. heatAreaItem.isSelect = true;
  188. selectedTrayList.value.push(heatAreaItem);
  189. }
  190. } else {
  191. heatAreaItem.isSelect = true;
  192. }
  193. heatList.value.forEach((item: any) => {
  194. if (item.id == heatAreaItem.id) {
  195. item = heatAreaItem;
  196. onHeadleCraft(item);
  197. }
  198. });
  199. console.log("hasCraftInfo---", hasCraftInfo.value);
  200. };
  201. //选择的加热区是否选择了工艺
  202. let hasCraftInfo = ref(false);
  203. const onHeadleCraft = (areaItem: any) => {
  204. if (areaItem.craftInfo) {
  205. hasCraftInfo.value = true;
  206. }
  207. };
  208. //设置加热区温度
  209. const onSetHeatAreaTemp = (dataInfo: any) => {
  210. selectedTrayObj[dataInfo.id] = dataInfo;
  211. selectedTrayList.value = Object.values(selectedTrayObj);
  212. };
  213. //加热区选择的工艺
  214. const onSelectCraft = (item: any, craftInfo: any) => {
  215. item.isSelect = true;
  216. item.craftInfo = craftInfo;
  217. onSelectedTray(item, "isMove");
  218. };
  219. //开始执行工艺
  220. const onCraftStart = () => {
  221. if (!selectedTrayList.value.length) {
  222. ElMessage.error("请选择目标加热区");
  223. return;
  224. }
  225. //可能会选择多个加热区执行工艺, 批量发送指令
  226. let hasCraft = true;
  227. let len = selectedTrayList.value.length;
  228. for (let i = 0; i < len; i++) {
  229. let item = selectedTrayList.value[i];
  230. if (!item.craftInfo) {
  231. hasCraft = false;
  232. ElMessage.error("选择的加热区未选择工艺");
  233. break;
  234. }
  235. const params = {
  236. craftId: null,
  237. heatId: item.id,
  238. };
  239. if (craftInfo.value?.status == 1) {
  240. craftStop(params).then(res => {
  241. ElMessage.success("已停止执行工艺的指令");
  242. });
  243. return;
  244. } else {
  245. params.craftId = item.craftInfo.id;
  246. craftStart(params).then(res => {
  247. ElMessage.success("已执行工艺的指令");
  248. });
  249. }
  250. }
  251. if (hasCraft) {
  252. //给选择加热区heatList加一个正在执行工艺的标识
  253. const selectedIds = selectedTrayList.value.map((item: any) => item.id);
  254. heatList.value.forEach((item: any) => {
  255. if (selectedIds.includes(item.id)) {
  256. item.executing_craft = true;
  257. }
  258. });
  259. }
  260. };
  261. //停止工艺
  262. const onCraftStop = () => {};
  263. const tubeBaseConfig = () => {
  264. //默认为16个
  265. for (let i = 0; i < 16; i++) {
  266. tubeList.push({
  267. id: i + 1,
  268. color: "rgb(212, 212, 212)",
  269. });
  270. }
  271. };
  272. //添加溶液
  273. const liquidVisible = ref(false);
  274. const onAddLiquid = () => {
  275. //检查加液区是否有试管。
  276. const liquidArea = statusStore.status?.liquidArea;
  277. if (liquidArea) {
  278. liquidVisible.value = true;
  279. } else {
  280. ElMessage.error("加液区未检测到托盘,无法进行加液操作");
  281. }
  282. };
  283. const onAddSolution = (data: any) => {
  284. let ids = data.map((item: any) => item.id);
  285. //批量发送加液指令
  286. const params = {
  287. injectFluids: data,
  288. };
  289. injectFluid(params).then(res => {
  290. if (res.success) {
  291. setOnGoingStatus("injecting");
  292. } else {
  293. ElMessage.error(res.msg);
  294. }
  295. });
  296. globeStatus = 0;
  297. // tubeList.forEach((item: any) => {
  298. // if (ids.includes(item.id)) {
  299. // item.default = defaultColor;
  300. // item.color = defaultColor;
  301. // item.isSelected = true;
  302. // }
  303. // });
  304. };
  305. const changeVisible = () => {
  306. craftVisible.value = false;
  307. };
  308. //选择工艺
  309. const onChooseCaft = () => {
  310. //1、是否选择了加热区
  311. if (!selectedTrayList.value.length) {
  312. ElMessage.error("请选择目标加热区");
  313. return;
  314. }
  315. craftVisible.value = true;
  316. };
  317. //选择的工艺
  318. const onHandleSelectedCraft = (craftInfo: any) => {
  319. selectedTrayList.value.forEach((item: any) => {
  320. item.isSelect = true;
  321. item.craftInfo = craftInfo;
  322. onSelectedTray(item, "isMove");
  323. });
  324. const selectedIds = selectedTrayList.value.map((item: any) => item.id);
  325. heatList.value.forEach((item: any) => {
  326. if (selectedIds.includes(item.id)) {
  327. item.craftInfo = craftInfo;
  328. }
  329. });
  330. changeVisible();
  331. };
  332. const onChooseTube = (tubeItem: any, index: any) => {
  333. if (!tubeItem.id) return;
  334. //@ts-ignore
  335. let list = [...tubeList];
  336. for (let i = 0; i < list.length; i++) {
  337. let item = list[i];
  338. if (index == i) {
  339. item.color = selectedColor;
  340. item.isSelected = true;
  341. } else {
  342. item.color = item.default ? item.default : emptyColor;
  343. item.isSelected = false;
  344. }
  345. }
  346. tubeList = [...list];
  347. };
  348. //移至加热
  349. const onMoveToHeat = () => {
  350. //1、是否选择了加热区
  351. if (!selectedTrayList.value.length) {
  352. ElMessage.error("请选择目标加热区");
  353. return;
  354. }
  355. //2、只能选择一个加热区
  356. if (selectedTrayList.value.length != 1) {
  357. ElMessage.error("只能选择一个加热区");
  358. return;
  359. }
  360. let selectedDataItem = selectedTrayList.value[0];
  361. //2、判断选择的加热区是否已经有了试管架, 加热区是否有试管是通过设备上报的数据获取的
  362. let hardwareId = selectedDataItem.hardwareId;
  363. // let trayStatus = heatAearStatusList.value[selectedDataItem.index].trayStatus;
  364. let trayStatus;
  365. heatAearStatusList.value.forEach((item: any) => {
  366. if (hardwareId == item.hardwareId) {
  367. trayStatus = item.trayStatus;
  368. }
  369. });
  370. // trayStatus: 0为无托盘,1为有托盘,2为托盘抬起
  371. if (trayStatus == 1) {
  372. ElMessage.error("选择的加热区已有试管架,重新选择加热区");
  373. return;
  374. }
  375. //调用移至加热接口
  376. const params = {
  377. heatId: selectedDataItem.id,
  378. };
  379. const command: OperationCmd = "moveToHeatArea";
  380. taskCmd({ command, params }).then(res => {
  381. if (res.success) {
  382. // ElMessage.success("指令已发送,请稍等");
  383. setOnGoingStatus("movingToHeat");
  384. } else {
  385. ElMessage.error(res.msg);
  386. }
  387. });
  388. //指令完成成更新UI
  389. let list = [...heatList.value];
  390. list.forEach((item: any) => {
  391. if (item.id == selectedDataItem.id) {
  392. item.tubeList = JSON.parse(JSON.stringify(tubeList));
  393. selectedDataItem.tubeList = JSON.parse(JSON.stringify(tubeList));
  394. //标注该加热区是选中状态
  395. item.isSelect = true;
  396. }
  397. });
  398. tubeList.forEach((item: any) => {
  399. item.color = "";
  400. item.default = "";
  401. });
  402. heatList.value = [...list];
  403. };
  404. //移至加液区(操作区)
  405. const currentSelectedTube = ref({});
  406. const onMoveToOperationArea = () => {
  407. //1、判断加液区是否有试管架(暂时获取不到这个状态)
  408. //1、是否选择了试管架/加热区
  409. if (!selectedTrayList.value.length) {
  410. ElMessage.error("请选择加热区");
  411. return false;
  412. }
  413. //2、只能选择一个试管架/加热区
  414. if (selectedTrayList.value.length != 1) {
  415. ElMessage.error("只能选择一个加热区");
  416. return false;
  417. }
  418. let selectedDataItem = selectedTrayList.value[0];
  419. currentSelectedTube.value = selectedDataItem;
  420. //3、选择的加热区有没有试管架
  421. if (!selectedDataItem.tubeList || !selectedDataItem.tubeList.length) {
  422. ElMessage.error("选择的加热区没有试管架");
  423. return false;
  424. }
  425. //4、发送移至加液区指令
  426. const params = {
  427. heatId: selectedDataItem.id,
  428. };
  429. onSendCmd("moveToActionArea", params);
  430. //更新UI
  431. heatList.value.forEach((item: any) => {
  432. if (item.id == selectedDataItem.id) {
  433. tubeList = [...item.tubeList];
  434. }
  435. });
  436. onSelectedTray(selectedDataItem, "isMove");
  437. return true;
  438. };
  439. //移至特殊区域
  440. const onMoveToSpecial = () => {
  441. //检查是否设置了异常区域
  442. const systemSetting = settingStore.systemSetting;
  443. let specialArea: any = {};
  444. if (systemSetting && systemSetting.length) {
  445. systemSetting.forEach(item => {
  446. if (item.code == "sys_setting_abnormal_area") {
  447. specialArea = item;
  448. }
  449. });
  450. if (!specialArea.id) {
  451. ElMessage.error("未设置异常区域,请在系统配置中设置");
  452. return;
  453. }
  454. //是否选择了加热区的试管架
  455. if (!selectedTrayList.value.length) {
  456. ElMessage.error("请选择试管架");
  457. return;
  458. }
  459. //2、只能选择一个试管架/加热区
  460. if (selectedTrayList.value.length != 1) {
  461. ElMessage.error("只能选择一个试管架");
  462. return;
  463. }
  464. let selectedDataItem = selectedTrayList.value[0];
  465. selectedDataItem.isSelect = false;
  466. onSelectedTray(selectedDataItem, "isMove");
  467. const params = {
  468. heatId: selectedDataItem.id,
  469. };
  470. onSendCmd("moveToActionArea", params);
  471. }
  472. };
  473. //开始实验
  474. const taskNameVisible = ref(false);
  475. const taskId = ref();
  476. const onSave = () => {
  477. if (!taskName.value) return;
  478. const params = {
  479. name: taskName.value,
  480. };
  481. saveTaskName(params).then(res => {
  482. if (res.success) {
  483. taskId.value = res.data.id;
  484. ElMessage.success("保存成功");
  485. onCancel();
  486. } else {
  487. ElMessage.error(res.msg);
  488. }
  489. });
  490. };
  491. const startTask = async () => {
  492. const res = await getIngTask();
  493. if (res.data) {
  494. ElMessageBox.confirm(`上一实验"${res.data.name}"未结束,是否结束并开始新的实验`, "提示", {
  495. confirmButtonText: "确定",
  496. cancelButtonText: "取消",
  497. center: true,
  498. })
  499. .then(() => {
  500. stopTask({ taskId: res.data.id })
  501. .then(res => {
  502. if (res.success) {
  503. ElMessage.success("实验已停止");
  504. taskNameVisible.value = true;
  505. } else {
  506. ElMessage.error("实验停止失败");
  507. }
  508. })
  509. .catch(e => {
  510. ElMessage.error(e);
  511. });
  512. })
  513. .catch(() => {});
  514. } else {
  515. taskNameVisible.value = true;
  516. }
  517. };
  518. //结束实验
  519. const onEndTask = () => {
  520. const params = {
  521. taskId: taskId.value,
  522. };
  523. stopTask(params)
  524. .then(res => {
  525. heatList.value.forEach((item: any) => {
  526. item.executing_craft = false;
  527. });
  528. if (res.success) {
  529. ElMessage.success("实验已停止");
  530. } else {
  531. ElMessage.error("实验停止失败");
  532. }
  533. })
  534. .catch(e => {
  535. ElMessage.error(e);
  536. });
  537. };
  538. const onCancel = () => {
  539. taskNameVisible.value = false;
  540. };
  541. //开门
  542. const doorStatus = ref(false); //开门状态 。true: 门已打开, false: 门未打开
  543. const onOPenDoor = () => {
  544. const params = {};
  545. const command: OperationCmd = "openDoor";
  546. taskCmd({ command, params }).then(res => {
  547. if (res.success) {
  548. // ElMessage.success("指令已发送,请稍等");
  549. doorStatus.value = true;
  550. setOnGoingStatus("doorOpening");
  551. } else {
  552. ElMessage.error(res.msg);
  553. }
  554. });
  555. };
  556. //关门
  557. const onCloseDoor = () => {
  558. const params = {};
  559. const command: OperationCmd = "closeDoor";
  560. taskCmd({ command, params }).then(res => {
  561. if (res.success) {
  562. // ElMessage.success("指令已发送,请稍等");
  563. doorStatus.value = false;
  564. setOnGoingStatus("doorClosing");
  565. } else {
  566. ElMessage.error(res.msg);
  567. }
  568. });
  569. };
  570. //开始加热
  571. const isHeating = ref(false);
  572. const onStartHeat = () => {
  573. //选择的加热区
  574. if (!selectedTrayList.value.length) {
  575. ElMessage.error("请选择目标加热区");
  576. return;
  577. }
  578. //判断选中的加热区是否有试管架
  579. let existTubeRack = true;
  580. //加热区是否设置了加热温度
  581. let hasSetTemp = true;
  582. selectedTrayList.value.forEach((item: any) => {
  583. let tubeList = item.tubeList;
  584. if (!tubeList || !tubeList.length) {
  585. existTubeRack = false;
  586. }
  587. if (!item.temperature) {
  588. hasSetTemp = false;
  589. }
  590. });
  591. if (!existTubeRack) {
  592. ElMessage.error("选择的加热区未放置试管架,请重新选择");
  593. return;
  594. }
  595. if (!hasSetTemp) {
  596. ElMessage.error("选择的加热区未设置温度,请设置温度");
  597. return;
  598. }
  599. //后台批量发送指令
  600. const cmdList: any = [];
  601. selectedTrayList.value.forEach((heatArea: any) => {
  602. const params = {
  603. heatId: heatArea.id,
  604. temperature: heatArea.temperature,
  605. };
  606. taskCmd({ command: "startHeat", params }).then(res => {
  607. if (res.success) {
  608. // ElMessage.success("指令已发送,请稍等");
  609. isHeating.value = true;
  610. } else {
  611. ElMessage.error(res.msg);
  612. }
  613. });
  614. });
  615. // onSendCmd("startHeat", cmdList)
  616. };
  617. //停止加热
  618. const onStopHeat = () => {
  619. //选择的加热区
  620. if (!selectedTrayList.value.length) {
  621. ElMessage.error("请选择目标加热区");
  622. return;
  623. }
  624. selectedTrayList.value.forEach((heatArea: any) => {
  625. const params = {
  626. heatId: heatArea.id,
  627. };
  628. taskCmd({ command: "stopHeat", params }).then(res => {
  629. if (res.success) {
  630. // ElMessage.success("指令已发送,请稍等");
  631. isHeating.value = false;
  632. } else {
  633. ElMessage.error(res.msg);
  634. }
  635. });
  636. });
  637. };
  638. //开始摇匀
  639. const isSharking = ref(false);
  640. const onStartShakingTube = () => {
  641. const params = {};
  642. taskCmd({ command: "startShakeUp", params }).then(res => {
  643. if (res.success) {
  644. // ElMessage.success("指令已发送,请稍等");
  645. isSharking.value = true;
  646. setOnGoingStatus("shaking");
  647. } else {
  648. ElMessage.error(res.msg);
  649. }
  650. });
  651. };
  652. //结束摇匀
  653. const onStopShakingTube = () => {
  654. const params = {};
  655. taskCmd({ command: "stopShakeUp", params }).then(res => {
  656. if (res.success) {
  657. // ElMessage.success("指令已发送,请稍等");
  658. isSharking.value = false;
  659. } else {
  660. ElMessage.error(res.msg);
  661. }
  662. });
  663. };
  664. //抬起托盘
  665. const onUpTray = () => {
  666. if (!selectedTrayList.value.length) {
  667. ElMessage.error("请选择目标加热区");
  668. return;
  669. }
  670. //选择了多个加热区,可托起多个加热区试管加
  671. selectedTrayList.value.forEach((heatAreaItem: any) => {
  672. const params = {
  673. heatId: heatAreaItem.id,
  674. };
  675. taskCmd({ command: "upTray", params }).then(res => {
  676. if (res.success) {
  677. // ElMessage.success("指令已发送,请稍等");
  678. } else {
  679. ElMessage.error(res.msg);
  680. }
  681. });
  682. });
  683. };
  684. //修改加热区状态 selectedValue: 0 | 1 | 2; // 0为无托盘,1为有托盘,2为托盘抬起
  685. const updateheatAearStatus = (selectedValue: any, heatId: string) => {
  686. let heaterList = statusStore.status?.heatArea;
  687. if (heaterList) {
  688. heaterList.forEach((item: any) => {
  689. if (item.heaterId == heatId) {
  690. item.trayStatus = selectedValue;
  691. }
  692. });
  693. const data: any = {
  694. ...statusStore.status,
  695. heater: [...heaterList],
  696. };
  697. statusStore.setStatus(data);
  698. }
  699. };
  700. const onSendCmd = (command: OperationCmd, params: any) => {
  701. //发送加热指令
  702. taskCmd({ command, params }).then(res => {
  703. if (res.success) {
  704. // ElMessage.success("指令已发送,请稍等");
  705. setOnGoingStatus("movingToAct");
  706. } else {
  707. ElMessage.error(res.msg);
  708. }
  709. });
  710. };
  711. </script>
  712. <style lang="scss" scoped>
  713. @use "@/assets/style/mixin.scss" as *;
  714. .graphite_home {
  715. background: #f6f6f6;
  716. display: flex;
  717. // @media (min-width: $md) {
  718. flex-direction: column;
  719. align-items: stretch;
  720. // }
  721. .picture_area {
  722. display: flex;
  723. flex-direction: column-reverse;
  724. margin: 0 12px;
  725. }
  726. @media (min-width: $lg) {
  727. flex-direction: row;
  728. align-items: start;
  729. .picture_area {
  730. display: flex;
  731. flex-direction: column;
  732. }
  733. }
  734. }
  735. .heat_area {
  736. margin: 5px 0;
  737. background: #ffffff;
  738. border-radius: 20px;
  739. column-gap: 8px;
  740. row-gap: 10px;
  741. padding: 1.5rem 0.5rem;
  742. min-width: 600px;
  743. flex: 1 1 auto;
  744. display: grid;
  745. grid-template-columns: repeat(3, 1fr);
  746. > * {
  747. justify-self: center;
  748. align-self: center;
  749. }
  750. @media (min-width: $md) {
  751. column-gap: 12px;
  752. row-gap: 20px;
  753. height: 47.5rem;
  754. }
  755. @media (min-width: $xl) {
  756. padding: 4.5rem 1rem;
  757. }
  758. .craft_executing_modal {
  759. position: absolute;
  760. width: 10.5rem;
  761. height: 18rem;
  762. background: rgb(230, 230, 230);
  763. opacity: 0.5;
  764. z-index: 9999;
  765. }
  766. }
  767. .picture_area {
  768. display: flex;
  769. flex-direction: column;
  770. margin: 5px;
  771. // margin-left: 1.25rem;
  772. background: #ffffff;
  773. border-radius: 20px;
  774. padding: 0 1.5rem;
  775. @media (min-width: $lg) {
  776. flex: 1 1 180px;
  777. }
  778. @media (min-width: $xl) {
  779. flex: 0 0 auto;
  780. width: 27rem;
  781. }
  782. .graphite_btn_container {
  783. margin: 2rem 0;
  784. gap: 0.625rem;
  785. display: grid;
  786. @media (max-width: calc($md - 0.1px)) {
  787. grid-template-columns: repeat(2, 1fr);
  788. .op_open_door {
  789. grid-column: 1/-1;
  790. }
  791. .op_up_tray {
  792. grid-column: 1/-1;
  793. }
  794. }
  795. @media (min-width: $md) and (max-width: calc($lg - 0.1px)) {
  796. grid-template-columns: repeat(6, 1fr);
  797. > * {
  798. grid-column: span 3;
  799. }
  800. .op_open_door {
  801. grid-column: 1/-1;
  802. }
  803. .op_move_heat {
  804. grid-column: span 2;
  805. }
  806. .op_move_act {
  807. grid-column: span 2;
  808. }
  809. .op_move_exception {
  810. grid-column: span 2;
  811. }
  812. }
  813. @media (min-width: $lg) and (max-width: calc($xl - 0.1px)) {
  814. grid-template-columns: repeat(2, 1fr);
  815. .op_open_door {
  816. grid-column: 1/-1;
  817. }
  818. .op_up_tray {
  819. grid-column: 1/-1;
  820. }
  821. }
  822. @media (min-width: $xl) {
  823. grid-template-columns: repeat(6, 1fr);
  824. > * {
  825. grid-column: span 3;
  826. }
  827. .op_open_door {
  828. grid-column: 1/-1;
  829. }
  830. .op_move_heat {
  831. grid-column: span 2;
  832. }
  833. .op_move_act {
  834. grid-column: span 2;
  835. }
  836. .op_move_exception {
  837. grid-column: span 2;
  838. }
  839. }
  840. }
  841. }
  842. .btn_size {
  843. height: 2.75rem;
  844. color: #1989fa;
  845. border: 1px solid #1989fa;
  846. font-size: 1.25rem;
  847. }
  848. .liquid {
  849. display: flex;
  850. justify-content: center;
  851. width: 100%;
  852. height: 100%;
  853. align-items: center;
  854. .addLiquid {
  855. width: 70.375rem;
  856. height: 52rem;
  857. background: #ffffff;
  858. }
  859. }
  860. .home_tube {
  861. width: 13rem;
  862. height: 13rem;
  863. background: #384d5d;
  864. opacity: 1;
  865. margin-top: 0.5rem;
  866. display: flex;
  867. flex-wrap: wrap;
  868. justify-content: center;
  869. gap: 0.6rem;
  870. padding-top: 0.2rem;
  871. border-radius: 1.5rem;
  872. .inner-circle {
  873. border-radius: 50%;
  874. width: 2.5rem;
  875. height: 2.5rem;
  876. background-color: rgb(212, 212, 212);
  877. }
  878. }
  879. .task_name {
  880. height: 17.25rem;
  881. width: 27.5rem;
  882. background: #ffffff;
  883. .task_title {
  884. font-size: 1.25rem;
  885. color: #40474e;
  886. margin-left: 1.25rem;
  887. margin-top: 1.875rem;
  888. }
  889. .task_name_content {
  890. margin-top: 1.875rem;
  891. margin-left: 1.5rem;
  892. font-size: 1.25rem;
  893. color: #40474e;
  894. display: flex;
  895. .task_input {
  896. border: 1px solid #dcdcdc;
  897. border-radius: 8px;
  898. height: 3rem;
  899. }
  900. }
  901. .task_button {
  902. display: flex;
  903. justify-content: center;
  904. }
  905. }
  906. .cancel_btn {
  907. border: 1px solid rgb(226, 226, 226);
  908. width: 5rem;
  909. margin-left: 2rem;
  910. }
  911. </style>