石墨仪设备 前端仓库
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.

996 lines
25 KiB

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