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

<template>
<div class="graphite_home component-page overflow-auto" id="heatArea">
<div class="heat_area">
<div v-for="(item, index) in heatList" :key="item.id">
<HeatPosition
:heatInfo="{ ...item, index }"
:tubeIndex="index + 1"
@onSelectedTray="onSelectedTray"
@onSetHeatAreaTemp = "onSetHeatAreaTemp"
@onSelectCraft="(craftData)=>{onSelectCraft(item, craftData)}"
></HeatPosition>
</div>
<!--执行中状态的遮罩层-->
</div>
<!--拍照区-->
<div class="picture_area">
<!--加液区和拍照区可切换-->
<TakePickture></TakePickture>
<!-- <div v-else style="display: flex;justify-content: center;">
<div class="home_tube">
<div
class="inner-circle"
v-for="(tubeItem, index) in tubeList"
:key="index"
:style="{ background: tubeItem.color }"
></div>
</div>
</div> -->
<!--操作区-->
<div class="graphite_btn_container">
<van-button v-if="doorStatus" size="large" class="btn_size op_open_door" @click="onCloseDoor"
>关门</van-button
>
<van-button v-else size="large" class="btn_size op_open_door" @click="onOPenDoor"
>开门</van-button
>
<van-button size="large" class="btn_size op_start_task" @click="startTask"
>开始实验</van-button
>
<van-button size="large" class="btn_size op_stop_task" @click="onEndTask"
>结束实验</van-button
>
<van-button
size="large"
class="btn_size op_select_craft"
@click="onChooseCaft"
>{{ craftName }}</van-button
>
<van-button size="large" class="btn_size op_exec_craft" @click="onCraftStart()"
>{{ exeCraftName }}</van-button
>
<van-button
size="large"
class="btn_size op_add_liquid"
@click="onAddLiquid"
>添加溶液</van-button
>
<van-button v-if="!isSharking" size="large" class="btn_size op_shake_up" @click="onStartShakingTube">摇匀</van-button>
<van-button v-else size="large" class="btn_size op_shake_up" @click="onStopShakingTube">结束摇匀</van-button>
<van-button
size="large"
class="btn_size op_move_heat"
@click="onMoveToHeat"
>移至加热</van-button
>
<van-button size="large" class="btn_size op_move_act" @click="onMoveToOperationArea"
>移至加液</van-button
>
<van-button size="large" class="btn_size op_move_exception" @click="onMoveToSpecial"
>移至特殊</van-button
>
<van-button v-if="!isHeating" size="large" class="btn_size op_start_heat" @click="onStartHeat"
>开始加热</van-button
>
<van-button v-else size="large" class="btn_size op_start_heat" @click="onStopHeat"
>停止加热</van-button
>
<van-button size="large" class="btn_size op_up_tray" @click="onUpTray"
>抬起托盘</van-button
>
</div>
</div>
<van-overlay :show="liquidVisible" v-if="liquidVisible" style="z-index: 9999">
<div class="liquid">
<div class="addLiquid">
<AddLiquid
:currentSelectedTube="currentSelectedTube"
@cancel="liquidVisible = false"
@onAddSolution="onAddSolution"
></AddLiquid>
</div>
</div>
</van-overlay>
<!--选择工艺-->
<OverlayModal :visible="craftVisible">
<CraftList @changeVisible="changeVisible" @selectedCraft="onHandleSelectedCraft"></CraftList>
</OverlayModal>
<!--实验名称-->
<OverlayModal :visible="taskNameVisible">
<div class="task_name">
<div class="task_title">
开始新实验
</div>
<div class="task_name_content">
<div class='mt-3'>实验名称</div>
<div class="task_auto">
<input v-model="taskName" placeholder="实验名称" class="task_input" />
<div v-if="!taskName" style="color:red;font-size: 1rem;">请输入实验名称</div>
</div>
</div>
<br/>
<footer class="task_button">
<button class="btn-dark px-2 py-1 min-w-20" @click="onSave">保存</button>
<button class="cancel_btn" @click="onCancel">取消</button>
</footer>
</div>
</OverlayModal>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, onMounted, onUnmounted, watch } from "vue";
//@ts-ignore
import {ElMessage, ElMessageBox} from "element-plus";
import { createWebSocket, sharedWsUrl } from "@/services/socket";
import { HeatPosition, TakePickture, AddLiquid } from "./components";
import OverlayModal from "@/components/OverlayModal.vue";
import CraftList from "@/views/graphite/components/CraftList.vue";
import { injectFluid } from "@/services/task/task";
import { useStatusStore } from "@/stores/status";
import {getIngTask, saveTaskName, stopTask} from '@/services/task/task';
import {
CmdDescMap,
taskCmd,
type OperationCmd,
} from "@/services/globalCmd/globalCmd";
import { craftStart, craftStop } from "@/services/ore/oreManage";
import { getTxnRecord } from "@/services/txn";
import { useSettingStore } from "@/stores/setting";
import { useCraftStore } from "@/stores/craft";
const craftStore = useCraftStore()
const craftInfo = ref(craftStore.craftInfo)
const settingStore = useSettingStore();
const craftName = ref('选择工艺')
const exeCraftName = ref('执行工艺')
watch(()=>craftStore.craftInfo, (newVal)=>{
craftInfo.value = newVal
if(newVal?.status == 1){
craftName.value = '暂停工艺'
exeCraftName.value = '停止工艺'
}
})
//设备的全局状态
const statusStore = useStatusStore();
const heatAearStatusList = ref(statusStore.status?.heatArea || [])
const heatList: any = ref([]);
const craftVisible = ref(false);
let tubeList = reactive<any>([]);
const selectedColor = "#4F85FB";
const emptyColor = "#FFFFFF";
const taskName = ref('')
let globeStatus:any = 0;
onMounted(() => {
//6个加热区数据
heatList.value = settingStore.heatAreaConfig.map((item:any) => {
//添加一个字段,默认为未选中
item.isSelect = false;
heatAearStatusList.value.forEach((areaItem:any) => {
if(areaItem.hardwareId == item.hardwareId){
item = {
...item,
heatAearStatus:areaItem
}
}
})
return item;
});
//设备16个试管的基础数据
tubeBaseConfig();
//连接socket
const wsClient = createWebSocket(sharedWsUrl);
const subscription = wsClient.dataOb.subscribe((data) => {
if(!globeStatus){//为了只输入一行,不想后台一直打印此处日志 TODO
console.log('globeStatus====', data)
}
globeStatus = 1;
if (data.type === "cmd") {
const cmdInfo = getTxnRecord(data.data.commandId, "task");
if (cmdInfo) {
const command:any = cmdInfo.command;
//@ts-ignore
const cmdName = CmdDescMap[command];
const result = data.data.success
? "执行完毕"
: `执行失败 ${data.data.message}`;
ElMessage({
message: `${cmdName} ${result}`,
type: data.data.success ? "success" : "error",
});
}
}
});
wsClient.connect();
onUnmounted(() => {
subscription.unsubscribe();
});
});
//选中的托盘
const selectedTrayList = ref<any>([]);
const selectedTrayObj: any = {};
const onSelectedTray = (heatAreaItem: any, type:string) => {
heatList.value[heatAreaItem.index] = heatAreaItem;
//取消选中,已经存在selectedTrayList中
let ids = selectedTrayList.value.map((tube:any) =>tube.id)
if(type == 'isClick'){//点击加热区
if(ids.includes(heatAreaItem.id)){
heatAreaItem.isSelect = false;
selectedTrayList.value = selectedTrayList.value.filter((selectedItem:any) => selectedItem.id != heatAreaItem.id)
}else{
heatAreaItem.isSelect = true;
selectedTrayList.value.push(heatAreaItem)
}
}else{
heatAreaItem.isSelect = true;
}
heatList.value.forEach((item:any) => {
if(item.id == heatAreaItem.id){
item = heatAreaItem
onHeadleCraft(item)
}
})
console.log('hasCraftInfo---', hasCraftInfo.value)
};
//选择的加热区是否选择了工艺
let hasCraftInfo = ref(false)
const onHeadleCraft = (areaItem:any)=>{
if(areaItem.craftInfo){
hasCraftInfo.value = true;
}
}
//设置加热区温度
const onSetHeatAreaTemp = (dataInfo:any) => {
selectedTrayObj[dataInfo.id] = dataInfo;
selectedTrayList.value = Object.values(selectedTrayObj);
}
//加热区选择的工艺
const onSelectCraft = (item:any, craftInfo:any) => {
item.isSelect = true;
item.craftInfo = craftInfo
onSelectedTray(item,'isMove')
}
//开始执行工艺
const onCraftStart = () => {
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
//可能会选择多个加热区执行工艺, 批量发送指令
let hasCraft = true;
let len = selectedTrayList.value.length;
for(let i = 0; i < len; i++){
let item = selectedTrayList.value[i]
if(!item.craftInfo){
hasCraft = false;
ElMessage.error('选择的加热区未选择工艺')
break;
}
const params = {
craftId:null,
heatId: item.id
}
if(craftInfo.value?.status == 1){
craftStop(params).then(res => {
ElMessage.success('已停止执行工艺的指令')
})
return
}else{
params.craftId = item.craftInfo.id
craftStart(params).then(res => {
ElMessage.success('已执行工艺的指令')
})
}
}
if(hasCraft){
//给选择加热区heatList加一个正在执行工艺的标识
const selectedIds = selectedTrayList.value.map((item:any) => item.id)
heatList.value.forEach((item:any) => {
if(selectedIds.includes(item.id)){
item.executing_craft = true;
}
});
}
}
//停止工艺
const onCraftStop = () => {
}
const tubeBaseConfig = () => {
//默认为16个
for (let i = 0; i < 16; i++) {
tubeList.push({
id: i + 1,
color: "rgb(212, 212, 212)",
});
}
};
//添加溶液
const liquidVisible = ref(false);
const onAddLiquid = () => {
//检查加液区是否有试管。
const liquidArea = statusStore.status?.liquidArea
if(liquidArea){
liquidVisible.value = true;
}else{
ElMessage.error('加液区未检测到托盘,无法进行加液操作')
}
};
const onAddSolution = (data: any) => {
let ids = data.map((item: any) => item.id);
//批量发送加液指令
const params = {
injectFluids:data
}
injectFluid(params)
globeStatus = 0
// tubeList.forEach((item: any) => {
// if (ids.includes(item.id)) {
// item.default = defaultColor;
// item.color = defaultColor;
// item.isSelected = true;
// }
// });
};
const changeVisible = () => {
craftVisible.value = false;
};
//选择工艺
const onChooseCaft = () => {
//1、是否选择了加热区
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
craftVisible.value = true;
};
//选择的工艺
const onHandleSelectedCraft = (craftInfo:any) => {
selectedTrayList.value.forEach((item:any) => {
item.isSelect = true;
item.craftInfo = craftInfo
onSelectedTray(item,'isMove')
})
const selectedIds = selectedTrayList.value.map((item:any) => item.id)
heatList.value.forEach((item:any) => {
if(selectedIds.includes(item.id)){
item.craftInfo = craftInfo;
}
});
changeVisible();
}
const onChooseTube = (tubeItem: any, index: any) => {
if (!tubeItem.id) return;
//@ts-ignore
let list = [...tubeList];
for (let i = 0; i < list.length; i++) {
let item = list[i];
if (index == i) {
item.color = selectedColor;
item.isSelected = true;
} else {
item.color = item.default ? item.default : emptyColor;
item.isSelected = false;
}
}
tubeList = [...list];
};
//移至加热
const onMoveToHeat = () => {
//1、是否选择了加热区
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
//2、只能选择一个加热区
if (selectedTrayList.value.length != 1) {
ElMessage.error("只能选择一个加热区");
return;
}
let selectedDataItem = selectedTrayList.value[0];
//2、判断选择的加热区是否已经有了试管架, 加热区是否有试管是通过设备上报的数据获取的
let hardwareId = selectedDataItem.hardwareId;
// let trayStatus = heatAearStatusList.value[selectedDataItem.index].trayStatus;
let trayStatus
heatAearStatusList.value.forEach((item:any) => {
if(hardwareId == item.hardwareId){
trayStatus = item.trayStatus
}
})
// trayStatus: 0为无托盘,1为有托盘,2为托盘抬起
if (trayStatus == 1) {
ElMessage.error("选择的加热区已有试管架,重新选择加热区");
return;
}
//调用移至加热接口
const params = {
heatId: selectedDataItem.id,
};
const command: OperationCmd = "moveToHeatArea";
taskCmd({ command, params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
} else {
ElMessage.error(res.msg);
}
});
//指令完成成更新UI
let list = [...heatList.value];
list.forEach((item: any) => {
if (item.id == selectedDataItem.id) {
item.tubeList = JSON.parse(JSON.stringify(tubeList));
selectedDataItem.tubeList = JSON.parse(JSON.stringify(tubeList));
//标注该加热区是选中状态
item.isSelect = true;
}
});
tubeList.forEach((item:any) => {
item.color = '';
item.default = ''
});
heatList.value = [...list];
};
//移至加液区(操作区)
const currentSelectedTube = ref({})
const onMoveToOperationArea = () => {
//1、判断加液区是否有试管架(暂时获取不到这个状态)
//1、是否选择了试管架/加热区
if (!selectedTrayList.value.length) {
ElMessage.error("请选择加热区");
return false;
}
//2、只能选择一个试管架/加热区
if (selectedTrayList.value.length != 1) {
ElMessage.error("只能选择一个加热区");
return false;
}
let selectedDataItem = selectedTrayList.value[0];
currentSelectedTube.value = selectedDataItem
//3、选择的加热区有没有试管架
if(!selectedDataItem.tubeList || !selectedDataItem.tubeList.length){
ElMessage.error("选择的加热区没有试管架");
return false;
}
//4、发送移至加液区指令
const params = {
heatId: selectedDataItem.id
}
onSendCmd('moveToActionArea', params)
//更新UI
heatList.value.forEach((item:any) => {
if(item.id == selectedDataItem.id){
tubeList = [...item.tubeList]
}
})
onSelectedTray(selectedDataItem, 'isMove')
return true;
}
//移至特殊区域
const onMoveToSpecial = () => {
//检查是否设置了异常区域
const systemSetting = settingStore.systemSetting
let specialArea:any = {}
if(systemSetting && systemSetting.length){
systemSetting.forEach(item => {
if(item.code == "sys_setting_abnormal_area"){
specialArea = item;
}
})
if(!specialArea.id){
ElMessage.error('未设置异常区域,请在系统配置中设置')
return;
}
//是否选择了加热区的试管架
if (!selectedTrayList.value.length) {
ElMessage.error("请选择试管架");
return;
}
//2、只能选择一个试管架/加热区
if (selectedTrayList.value.length != 1) {
ElMessage.error("只能选择一个试管架");
return;
}
let selectedDataItem = selectedTrayList.value[0];
selectedDataItem.isSelect = false
onSelectedTray(selectedDataItem, 'isMove')
const params = {
heatId:selectedDataItem.id
}
onSendCmd('moveToActionArea', params)
}
}
//开始实验
const taskNameVisible = ref(false)
const taskId = ref()
const onSave = ()=> {
if(!taskName.value)return;
const params = {
name: taskName.value
}
saveTaskName(params).then(res => {
if(res.success){
taskId.value = res.data.id;
ElMessage.success('保存成功')
onCancel()
}else{
ElMessage.error(res.msg)
}
})
}
const startTask = async () => {
const res = await getIngTask();
if(res.data) {
ElMessageBox.confirm(`上一实验"${res.data.name}"未结束,是否结束并开始新的实验`, '提示', {
confirmButtonText: "确定",
cancelButtonText: "取消",
center: true,
}).then(() => {
stopTask({taskId: res.data.id}).then(res=> {
if(res.success){
ElMessage.success('实验已停止')
taskNameVisible.value = true;
}else{
ElMessage.error('实验停止失败')
}
}).catch(e=>{
ElMessage.error(e)
})
}).catch(() => {})
}else {
taskNameVisible.value = true
}
}
//结束实验
const onEndTask = () => {
const params = {
taskId: taskId.value
}
stopTask(params).then(res=> {
heatList.value.forEach((item:any) => {
item.executing_craft = false;
});
if(res.success){
ElMessage.success('实验已停止')
}else{
ElMessage.error('实验停止失败')
}
}).catch(e=>{
ElMessage.error(e)
})
}
const onCancel = ()=> {
taskNameVisible.value = false;
}
//开门
const doorStatus = ref(false)//开门状态 。true: 门已打开, false: 门未打开
const onOPenDoor = () => {
const params = {};
const command: OperationCmd = "openDoor";
taskCmd({ command, params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
doorStatus.value = true;
} else {
ElMessage.error(res.msg);
}
});
};
//关门
const onCloseDoor = () => {
const params = {};
const command: OperationCmd = "closeDoor";
taskCmd({ command, params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
doorStatus.value = false;
} else {
ElMessage.error(res.msg);
}
});
}
//开始加热
const isHeating = ref(false)
const onStartHeat = () => {
//选择的加热区
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
//判断选中的加热区是否有试管架
let existTubeRack = true;
//加热区是否设置了加热温度
let hasSetTemp = true;
selectedTrayList.value.forEach((item:any) => {
let tubeList = item.tubeList;
if(!tubeList || !tubeList.length){
existTubeRack = false;
}
if(!item.temperature){
hasSetTemp = false;
}
})
if(!existTubeRack){
ElMessage.error("选择的加热区未放置试管架,请重新选择")
return;
}
if(!hasSetTemp){
ElMessage.error("选择的加热区未设置温度,请设置温度")
return;
}
//后台批量发送指令
const cmdList:any = []
selectedTrayList.value.forEach((heatArea:any) => {
const params = {
heatId : heatArea.id,
temperature: heatArea.temperature
}
taskCmd({ command: 'startHeat', params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
isHeating.value = true;
} else {
ElMessage.error(res.msg);
}
});
})
// onSendCmd("startHeat", cmdList)
}
//停止加热
const onStopHeat = () => {
//选择的加热区
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
selectedTrayList.value.forEach((heatArea:any) => {
const params = {
heatId : heatArea.id,
}
taskCmd({ command: 'stopHeat', params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
isHeating.value = false;
} else {
ElMessage.error(res.msg);
}
});
})
}
//开始摇匀
const isSharking = ref(false)
const onStartShakingTube = () => {
const params = {}
taskCmd({ command:'startShakeUp', params}).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
isSharking.value = true;
} else {
ElMessage.error(res.msg);
}
});
}
//结束摇匀
const onStopShakingTube = () => {
const params = {}
taskCmd({ command:'stopShakeUp', params}).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
isSharking.value = false;
} else {
ElMessage.error(res.msg);
}
});
}
//抬起托盘
const onUpTray = () => {
if (!selectedTrayList.value.length) {
ElMessage.error("请选择目标加热区");
return;
}
//选择了多个加热区,可托起多个加热区试管加
selectedTrayList.value.forEach((heatAreaItem:any) => {
const params = {
heatId: heatAreaItem.id
}
taskCmd({ command:'upTray', params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
} else {
ElMessage.error(res.msg);
}
});
})
}
//修改加热区状态 selectedValue: 0 | 1 | 2; // 0为无托盘,1为有托盘,2为托盘抬起
const updateheatAearStatus = (selectedValue:any, heatId:string) => {
let heaterList = statusStore.status?.heatArea
if(heaterList){
heaterList.forEach((item:any) => {
if(item.heaterId == heatId){
item.trayStatus = selectedValue
}
})
const data:any = {
...statusStore.status,
heater:[...heaterList]
}
statusStore.setStatus(data)
}
}
const onSendCmd = (command:OperationCmd,params:any)=> {
//发送加热指令
taskCmd({ command, params }).then((res) => {
if (res.success) {
ElMessage.success("指令已发送,请稍等");
} else {
ElMessage.error(res.msg);
}
});
}
</script>
<style lang="scss" scoped>
@use "@/assets/style/mixin.scss" as *;
.graphite_home {
background: #f6f6f6;
display: flex;
// @media (min-width: $md) {
flex-direction: column;
align-items: stretch;
// }
.picture_area {
display: flex;
flex-direction: column-reverse;
margin: 0 12px;
}
@media (min-width: $lg) {
flex-direction: row;
align-items: start;
.picture_area {
display: flex;
flex-direction: column;
}
}
}
.heat_area {
margin: 5px 0;
background: #ffffff;
border-radius: 20px;
column-gap: 8px;
row-gap: 10px;
padding: 1.5rem 0.5rem;
min-width: 600px;
flex: 1 1 auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
> * {
justify-self: center;
align-self: center;
}
@media (min-width: $md) {
column-gap: 12px;
row-gap: 20px;
height: 47.5rem;
}
@media (min-width: $xl) {
padding: 4.5rem 1rem;
}
.craft_executing_modal {
position: absolute;
width: 10.5rem;
height: 18rem;
background: rgb(230, 230, 230);
opacity: 0.5;
z-index: 9999;
}
}
.picture_area {
display: flex;
flex-direction: column;
margin: 5px;
// margin-left: 1.25rem;
background: #ffffff;
border-radius: 20px;
padding: 0 1.5rem;
@media (min-width: $lg) {
flex: 1 1 180px;
}
@media (min-width: $xl) {
flex: 0 0 auto;
width: 27rem;
}
.graphite_btn_container {
margin: 2rem 0;
gap: 0.625rem;
display: grid;
@media (max-width: calc($md - 0.1px)) {
grid-template-columns: repeat(2, 1fr);
.op_open_door {
grid-column: 1/-1;
}
.op_up_tray {
grid-column: 1/-1;
}
}
@media (min-width: $md) and (max-width: calc($lg - 0.1px)) {
grid-template-columns: repeat(6, 1fr);
> * {
grid-column: span 3;
}
.op_open_door {
grid-column: 1/-1;
}
.op_move_heat {
grid-column: span 2;
}
.op_move_act {
grid-column: span 2;
}
.op_move_exception {
grid-column: span 2;
}
}
@media (min-width: $lg) and (max-width: calc($xl - 0.1px)) {
grid-template-columns: repeat(2, 1fr);
.op_open_door {
grid-column: 1/-1;
}
.op_up_tray {
grid-column: 1/-1;
}
}
@media (min-width: $xl) {
grid-template-columns: repeat(6, 1fr);
> * {
grid-column: span 3;
}
.op_open_door {
grid-column: 1/-1;
}
.op_move_heat {
grid-column: span 2;
}
.op_move_act {
grid-column: span 2;
}
.op_move_exception {
grid-column: span 2;
}
}
}
}
.btn_size {
height: 2.75rem;
color: #1989fa;
border: 1px solid #1989fa;
font-size: 1.25rem;
}
.liquid {
display: flex;
justify-content: center;
width: 100%;
height: 100%;
align-items: center;
.addLiquid {
width: 70.375rem;
height: 52rem;
background: #ffffff;
}
}
.home_tube {
width: 13rem;
height: 13rem;
background: #384d5d;
opacity: 1;
margin-top: 0.5rem;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.6rem;
padding-top: 0.2rem;
border-radius: 1.5rem;
.inner-circle {
border-radius: 50%;
width: 2.5rem;
height: 2.5rem;
background-color: rgb(212, 212, 212);
}
}
.task_name{
height:17.25rem;
width: 27.5rem;
background: #ffffff;
.task_title{
font-size: 1.25rem;
color: #40474E;
margin-left: 1.25rem;
margin-top: 1.875rem
}
.task_name_content{
margin-top:1.875rem;
margin-left: 1.5rem;
font-size: 1.25rem;
color: #40474E;
display: flex;
.task_input{
border: 1px solid #dcdcdc;
border-radius: 8px;
height: 3rem;
}
}
.task_button{
display: flex;
justify-content: center;
}
}
.cancel_btn{
border: 1px solid rgb(226, 226, 226);
width: 5rem;
margin-left: 2rem;
}
</style>