New file |
| | |
| | | <template> |
| | | <div class="task-control-modal"> |
| | | <BaseModal v-model="modelData" :wider="false"> |
| | | <template #title>新任务</template> |
| | | <div class="modal-content"> |
| | | <div v-if="!messageError" class="content-title"> |
| | | <div class="content-title-item">当前任务:{{ task?.Procedure.procedure.procedureName || '' }}</div> |
| | | <div class="content-title-item"> |
| | | 生产数量: |
| | | <div class="leaf-shape box"> |
| | | {{ task?.Order?.amount || 0 }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="!!messageError" class="content-tips"> |
| | | <div class="error-t"> |
| | | <span v-if="messageError === '下发成功!'" class="el-icon-success color_success"></span> |
| | | <span v-else class="el-icon-error color_error"></span> |
| | | </div> |
| | | <div class="error-m"> |
| | | {{ messageError }} |
| | | </div> |
| | | <div class="font_size_20 color_fff" style="text-align: center; width: 100%; margin: 10px 0"> |
| | | <span v-if="messageError === '下发成功!'" style="font-size: 30px"></span> |
| | | <span v-else>请重试</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-else class="content-scroll"> |
| | | <div class="scroll-container"> |
| | | <el-scrollbar always class="scroller"> |
| | | <template v-if="task"> |
| | | <div class="info"> |
| | | <div class="info-item">订单编号:{{ task.Order.orderId || '' }}</div> |
| | | <div class="info-item">工单编号:{{ task.Order.workOrderId || '' }}</div> |
| | | <div class="info-item">产品名称:{{ task.Order.productName || '' }}</div> |
| | | <div class="info-item">数量:{{ task.Order.amount || 0 }}{{ task.Order.unit }}</div> |
| | | <div class="info-item">交货日期:{{ task.Order.deliverDate || '' }}</div> |
| | | <div class="info-item">工时: {{ task.Procedure.procedure.workHours || '' }}</div> |
| | | <div class="info-item"> |
| | | 计划时间: {{ formatDate(task.Procedure.startTime) || '' }} |
| | | - |
| | | {{ formatDate(task.Procedure.endTime) }} |
| | | </div> |
| | | |
| | | <div class="info-item">客户名称:{{ task.Order.customer || '' }}</div> |
| | | <div class="info-item info-item-two">通道: {{ CHANNEL_NAME_MAP[task.Channel] || '' }}</div> |
| | | |
| | | <div class="info-item info-item-two">参数要求:{{ task.Order.parameter || '' }}</div> |
| | | |
| | | <div class="info-item-two"> |
| | | <div style="color: #4efefa; font-size: 18px; margin-bottom: 10px; margin-top: 20px">工艺参数</div> |
| | | <div v-for="(item, index) in craftParams" :key="index" class="info-item info-item-two"> |
| | | {{ item.Key }}:{{ item.Value || '' }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="title-auto-box"></div> |
| | | <div v-if="getCraftParamsErrMsg" class="process-err-tip"> |
| | | <div class="tip-icon"> |
| | | <span class="el-icon-error color_error"></span> |
| | | </div> |
| | | <div class="tip-content">提示: {{ getCraftParamsErrMsg }}</div> |
| | | </div> |
| | | |
| | | <div v-if="countdown30s.countdownStatus.value === 'running'" class="countdown"> |
| | | {{ countdown30s.formattedTime.value }} |
| | | </div> |
| | | |
| | | <!-- <div v-if="showBtn === 2 || showBtn === 3" class="process-box">--> |
| | | <!-- <div--> |
| | | <!-- style="--> |
| | | <!-- color: red;--> |
| | | <!-- font-size: 26px;--> |
| | | <!-- width: 100%;--> |
| | | <!-- text-align: center;--> |
| | | <!-- margin-bottom: 15px;--> |
| | | <!-- line-height: 35px;--> |
| | | <!-- "--> |
| | | <!-- :class="showBtn === 3 && isLoading ? 'margin-top-10px' : 'margin-top-40px'"--> |
| | | <!-- >--> |
| | | <!-- <div v-if="showBtn === 2 || (showBtn === 3 && !isLoading)" class="gif-box">--> |
| | | <!-- <template v-if="showBtn === 2">--> |
| | | <!-- <div class="gif">--> |
| | | <!-- <img src="../../public/shan.gif" />--> |
| | | <!-- </div>--> |
| | | <!-- </template>--> |
| | | <!-- <template v-if="showBtn === 3 && !isLoading">--> |
| | | <!-- <div class="gif">--> |
| | | <!-- <span class="yuandian"></span>--> |
| | | <!-- </div>--> |
| | | <!-- </template>--> |
| | | <!-- <div class="gif-right">--> |
| | | <!-- <div>----- 剩余时间 -----</div>--> |
| | | <!-- <div>--> |
| | | <!-- <span>00:{{ countdown30s.formattedTime }}</span>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- {{ message }}--> |
| | | <!-- </div>--> |
| | | <!-- <template v-if="showBtn === 3 && isLoading">--> |
| | | <!-- <div class="progress-item">--> |
| | | <!-- <span>{{ (+num / 30) * 100 }}%</span>--> |
| | | <!-- <el-progress--> |
| | | <!-- style="width: calc(100% - 50px); float: right"--> |
| | | <!-- define-back-color="#CDC6C6"--> |
| | | <!-- color="#00cc66"--> |
| | | <!-- text-color="#fff"--> |
| | | <!-- :text-inside="true"--> |
| | | <!-- :stroke-width="20"--> |
| | | <!-- :percentage="(+num / 30) * 100"--> |
| | | <!-- ></el-progress>--> |
| | | <!-- </div>--> |
| | | <!-- </template>--> |
| | | <!-- </div>--> |
| | | </template> |
| | | </el-scrollbar> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="btn"> |
| | | <BigButton bg-color="#4765c0" @click="closeModal">暂缓生产</BigButton> |
| | | <BigButton |
| | | v-if="countdown30s.countdownStatus.value !== 'complete'" |
| | | color="#0d0d0d" |
| | | :disabled="countdown30s.countdownStatus.value === 'running'" |
| | | @click="startCountdown30s" |
| | | > |
| | | 生产准备 |
| | | </BigButton> |
| | | <BigButton v-if="countdown30s.countdownStatus.value === 'complete'" bg-color="#4efefa" @click="startProduce"> |
| | | 开始生产 |
| | | </BigButton> |
| | | </div> |
| | | </template> |
| | | </BaseModal> |
| | | </div> |
| | | </template> |
| | | <script setup lang="ts"> |
| | | import type { CraftParam, Task } from '@/api/task' |
| | | import { useDateFormat, useVModel } from '@vueuse/core' |
| | | import { computed, ref, toRefs, watch } from 'vue' |
| | | import BigButton from '@/views/dashboard/components/BigButton.vue' |
| | | import { CHANNEL_NAME_MAP } from '@/common/constants' |
| | | import { getCraftParams, sendProcessParams } from '@/api' |
| | | import { useCountDown } from '@/common/composable' |
| | | import { storeToRefs } from 'pinia' |
| | | import { useTasksStore } from '@/stores/tasks' |
| | | |
| | | export interface TaskControlModalProps { |
| | | task?: Task |
| | | /** 是否展示模态框 */ |
| | | modelValue: boolean |
| | | } |
| | | const props = withDefaults(defineProps<TaskControlModalProps>(), { |
| | | task: undefined, |
| | | modelValue: false |
| | | }) |
| | | const emit = defineEmits<{ |
| | | 'update:modelValue': [show: boolean] |
| | | }>() |
| | | |
| | | const modelData = useVModel(props, 'modelValue', emit) |
| | | function closeModal() { |
| | | modelData.value = false |
| | | } |
| | | const { task } = toRefs(props) |
| | | |
| | | const messageError = ref('') |
| | | |
| | | /** |
| | | * 格式化时间戳 |
| | | * @param timestamp 后端返的10位时间戳 |
| | | */ |
| | | function formatDate(timestamp?: number) { |
| | | if (!timestamp) { |
| | | return '--' |
| | | } |
| | | const time = useDateFormat(timestamp * 1000, 'YYYY-MM-DD', { locales: 'zh-cn' }) |
| | | return time.value |
| | | } |
| | | |
| | | // 工艺参数 |
| | | const craftParams = ref<CraftParam[]>() |
| | | // 获取工艺参数失败信息 |
| | | const getCraftParamsErrMsg = ref('') |
| | | |
| | | /** |
| | | * 获取当前展示的任务的工艺参数 |
| | | */ |
| | | function getTaskProduceParams(taskId?: number) { |
| | | if (taskId) { |
| | | craftParams.value = [] |
| | | getCraftParamsErrMsg.value = '' |
| | | getCraftParams({ id: taskId }).then( |
| | | (res) => { |
| | | craftParams.value = res.data.Params ?? [] |
| | | getCraftParamsErrMsg.value = '' |
| | | // TODO: 处理各个按钮显隐 |
| | | // this.getInfo() |
| | | console.log('processParams', craftParams.value) |
| | | }, |
| | | (err) => { |
| | | console.error(err) |
| | | craftParams.value = [] |
| | | getCraftParamsErrMsg.value = '获取工艺参数失败!' |
| | | } |
| | | ) |
| | | } |
| | | } |
| | | |
| | | watch(modelData, () => { |
| | | // 弹窗显示时获取工艺参数 |
| | | if (modelData.value) { |
| | | getTaskProduceParams(task?.value?.Procedure?.ID) |
| | | } |
| | | }) |
| | | |
| | | const countdown30s = useCountDown(3) |
| | | |
| | | function startCountdown30s() { |
| | | countdown30s.startCountdown() |
| | | } |
| | | |
| | | /** |
| | | * 下发工艺参数 |
| | | */ |
| | | function startProduce() { |
| | | if (task.value?.Procedure?.ID) { |
| | | message.value = '工艺参数下发中...' |
| | | |
| | | isLoading.value = true |
| | | sendProcessParams({ |
| | | procedureId: task.value.Procedure.ID |
| | | }) |
| | | .then( |
| | | (res) => { |
| | | console.log(res) |
| | | messageError.value = '下发成功' |
| | | }, |
| | | (err) => { |
| | | console.error(err) |
| | | messageError.value = err.msg ? err.msg : '抱歉,工序下发失败!' |
| | | } |
| | | ) |
| | | .finally(() => { |
| | | isLoading.value = false |
| | | }) |
| | | } |
| | | } |
| | | |
| | | const { channels } = storeToRefs(useTasksStore()) |
| | | const safeProduce = computed(() => { |
| | | if (task?.value?.Channel) { |
| | | return channels?.value?.[task.value.Channel]?.Prompt?.safeProduce |
| | | } |
| | | return '' |
| | | }) |
| | | const message = ref(safeProduce.value) |
| | | const isLoading = ref(false) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .modal-content { |
| | | height: 550px; |
| | | } |
| | | .content-scroll { |
| | | height: 400px; |
| | | overflow: hidden; |
| | | } |
| | | :deep(.el-dialog__body) { |
| | | padding: 0 20px; |
| | | } |
| | | .btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | } |
| | | .content-title { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 10px 40px; |
| | | } |
| | | .content-title-item { |
| | | width: 50%; |
| | | font-size: 20px; |
| | | color: #4efefa; |
| | | } |
| | | |
| | | .leaf-shape { |
| | | position: relative; |
| | | display: inline-block; |
| | | width: 140px; |
| | | height: 46px; |
| | | border-radius: 23px 0 23px 0; |
| | | text-align: center; |
| | | line-height: 46px; |
| | | color: #fff; |
| | | background: url('/leaf-shape.png') no-repeat center center / cover; |
| | | } |
| | | .scroll-container { |
| | | margin: 0 auto; |
| | | padding: 10px 20px; |
| | | width: calc(100% - 40px); |
| | | height: 400px; |
| | | } |
| | | .info { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | background-color: #0e246a; |
| | | padding: 10px 20px; |
| | | } |
| | | .info-item { |
| | | width: 50%; |
| | | height: 35px; |
| | | line-height: 35px; |
| | | font-size: 16px; |
| | | color: #fff; |
| | | } |
| | | .info-item-two { |
| | | width: 100%; |
| | | } |
| | | </style> |