| | |
| | | <template> |
| | | <div class="workshop"> |
| | | <div class="eqp-row"> |
| | | <div v-for="(item, index) in eqps" :key="index"> |
| | | <div class="eqp-card"> |
| | | <div class="eqp-content"> |
| | | <div class="chart"> |
| | | <div> |
| | | <div class="progress"> |
| | | <div style=""> |
| | | <div>加热</div> |
| | | <div></div> |
| | | <span class="info-text">36</span> 分钟 |
| | | </div> |
| | | |
| | | <div style=" padding: 0 10px;width: 200px;height: 40px;"> |
| | | |
| | | <div style="padding-top: 10px"> |
| | | <Progress |
| | | :stroke-color="{ |
| | | from: '#108ee9', |
| | | to: '#87d068', |
| | | }" |
| | | :percent="55.9" |
| | | status="active" |
| | | :show-info="false"> |
| | | </Progress> |
| | | </div> |
| | | |
| | | </div> |
| | | |
| | | <div> |
| | | <div>预计 </div> |
| | | <div><span class="info-text">90</span> 分钟 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div style="height:50px; text-align: left; padding-left: 25px; display: flex;"> |
| | | <div class="herbInfo"> |
| | | <div>药材:<span class="info-text">当归</span></div> |
| | | <div>投料:<span class="info-text">16</span> 筐</div> |
| | | <div class="eqp-card" v-for="(item, index) in eqps" :key="index"> |
| | | <div class="eqp-content"> |
| | | <div class="chart"> |
| | | <div> |
| | | <div class="progress"> |
| | | <div style=""> |
| | | <div>加热</div> |
| | | <div></div> |
| | | <span class="info-text">{{ realTime.get(item.id)?.dryTime | 0 }}</span> 分钟 |
| | | </div> |
| | | <div class="herbInfo"> |
| | | <div>原始重量:<span class="info-text">160</span> Kg</div> |
| | | <div>实时重量:<span class="info-text">70</span> Kg</div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="eqpStatus"> |
| | | <div > <span class="info-text">运行</span> </div> |
| | | </div> |
| | | |
| | | </div> |
| | | <!-- <div :id="'chartDom' + item.id" class="chart"> </div> --> |
| | | <div class="info"> |
| | | <div class="leftInfo"> |
| | | <!-- <div class="herbName"> 当归 </div> --> |
| | | <div class="eqpName">{{ item.name }}</div> |
| | | <div style="padding: 0 10px; width: 200px; height: 40px"> |
| | | <div style="padding-top: 10px"> |
| | | <Progress |
| | | :stroke-color="{ |
| | | from: '#108ee9', |
| | | to: '#87d068', |
| | | }" |
| | | :percent="realTime.get(item.id)?.percent" |
| | | status="active" |
| | | :show-info="false" |
| | | /> |
| | | </div> |
| | | </div> |
| | | |
| | | <div> |
| | | <div>预计 </div> |
| | | <div |
| | | ><span class="info-text">{{ (realTime.get(item.id)?.dryTime + realTime.get(item.id)?.remain) | 0 }}</span> 分钟 |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="rightInfo"> |
| | | <div style="width: 120px" > |
| | | <div style=" height: 1px; |
| | | font-size: 10px; |
| | | text-align: center; |
| | | margin-top: 10px; |
| | | margin-bottom: -10px; ">初始:{{ (mois[0] * 100).toFixed(2) }}%</div> |
| | | <div :id="'moisture' + item.id" style="width: 110px; height: 187px"></div> |
| | | <div style="height: 1px; |
| | | font-size: 10px; |
| | | text-align: center; |
| | | margin-top: -25px;">目标:{{ (mois[2] * 100).toFixed(2) }}%</div> |
| | | <div style=" width: 110px; |
| | | text-align: center; |
| | | margin-top: 23px;">含水率</div> |
| | | <div style="height: 50px; text-align: left; padding-left: 25px; display: flex"> |
| | | <div class="herbInfo"> |
| | | <div |
| | | >药材:<span class="info-text">{{ realTime.get(item.id)?.herbName }}</span></div |
| | | > |
| | | <div |
| | | >投料:<span class="info-text">{{ realTime.get(item.id)?.feed | 0 }}</span> 筐</div |
| | | > |
| | | </div> |
| | | |
| | | <div class="tempChart" style="pointer-events: none; cursor: none;" :id="'tempDom' + item.id"> |
| | | <a-slider v-model:value="tempValue" |
| | | |
| | | :min="0" range :max="100" :marks="marks" vertical /> |
| | | <div>热风:<span class="info-text">{{ tempValue[0] }}</span> °C</div> |
| | | <div class="herbInfo"> |
| | | <div |
| | | >原始重量:<span class="info-text">{{ realTime.get(item.id)?.originWeight | 0 }}</span> Kg</div |
| | | > |
| | | <div |
| | | >实时重量:<span class="info-text">{{ realTime.get(item.id)?.yield | 0 }}</span> Kg</div |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="eqpStatus"> |
| | | <div> <span class="info-text">翻料</span> </div> |
| | | </div> |
| | | </div> |
| | | <!-- <div :id="'chartDom' + item.id" class="chart"> </div> --> |
| | | <div class="info"> |
| | | <div class="leftInfo"> |
| | | <div style="width: 120px"> |
| | | <div style="height: 1px; font-size: 10px; text-align: center; margin-top: 10px; margin-bottom: -10px" |
| | | >初始:{{ realTime.get(item.id)?.initial }}%</div |
| | | > |
| | | <div :id="'moisture' + item.id" style="width: 110px; height: 187px"></div> |
| | | <div style="height: 1px; font-size: 10px; text-align: center; margin-top: -25px">目标:{{ realTime.get(item.id)?.target }}%</div> |
| | | <div style="width: 110px; text-align: center; margin-top: 23px">含水率</div> |
| | | </div> |
| | | <!-- <div class="herbName"> 当归 </div> --> |
| | | <div style="flex: 1" @click="gotoEqp(item.id)" |
| | | ><div class="eqpName">{{ item.name }}</div></div |
| | | > |
| | | </div> |
| | | <div class="rightInfo"> |
| | | <div class="tempChart" style="pointer-events: none; cursor: none" :id="'tempDom' + item.id"> |
| | | <a-slider |
| | | v-if="realTime.get(item.id)" |
| | | v-model:value="realTime.get(item.id).tempValue" |
| | | :min="0" |
| | | range |
| | | :max="100" |
| | | :marks="marks" |
| | | vertical |
| | | /> |
| | | <div |
| | | >热风:<span class="info-text">{{ realTime.get(item.id)?.windTemp | 0 }}</span> °C</div |
| | | > |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onMounted, ref } from 'vue' |
| | | import { onMounted, ref, onUnmounted } from 'vue' |
| | | import { Progress } from 'ant-design-vue' |
| | | import * as echarts from 'echarts' |
| | | import 'echarts-liquidfill' |
| | | import { listAll } from '../api/DryEquipment.api' |
| | | import { dryEquipment } from '../dataDefine/DryEquipment.data' |
| | | import { router } from '/@/router' |
| | | import { defHttp } from '/@/utils/http/axios' |
| | | import { useUserStore } from '/@/store/modules/user' |
| | | |
| | | const eqps = ref([] as dryEquipment[]) |
| | | const mois = ref([0.3939,0.2112,0.11]) |
| | | const mois = ref([0, 0, 0]) |
| | | const userStore = useUserStore() |
| | | const Timer = ref() |
| | | |
| | | const tempValue = ref(<Record<number, number>>([70, 100])) |
| | | const realTime = ref(new Map()) |
| | | |
| | | const marks = ref<Record<number, any>>({ |
| | | 0: '0°C', |
| | |
| | | .then((result) => { |
| | | console.log(`output->result`, result) |
| | | eqps.value = result |
| | | setTimeout(initCharts, 1000) |
| | | setTimeout(initCharts, 500) |
| | | updateRealTime() |
| | | }) |
| | | .catch((err) => { |
| | | console.log(`output->err`, err) |
| | |
| | | |
| | | // var wetCharts: Map<string, echarts.ECharts> = new Map() |
| | | |
| | | var moistureCharts: Map<String, echarts.ECharts> = new Map() |
| | | var moistureCharts: Map<String, echarts.ECharts> = new Map() |
| | | |
| | | function initCharts() { |
| | | // console.log(`output->initChart`) |
| | | eqps.value.forEach((item) => { |
| | | // console.log(`output->item.id`, item.id) |
| | | let domId = 'moisture' + item.id |
| | | // console.log(`output->domId`, domId) |
| | | var chartDom: HTMLElement = document.getElementById(domId) as HTMLElement |
| | | // console.log(`output->chartDom`, chartDom) |
| | | let myChart = echarts.init(chartDom) |
| | | // var option |
| | | // option = { |
| | | // grid: { |
| | | // left: 30, |
| | | // top: 15, |
| | | // bottom: 13, |
| | | // right: 45 |
| | | // }, |
| | | // xAxis: { |
| | | // type: 'category', |
| | | // show: false, |
| | | // data: ['含水率'], |
| | | // axisLine: { |
| | | // show: false, |
| | | // }, |
| | | // axisTick: { |
| | | // show: false, |
| | | // } |
| | | // }, |
| | | // yAxis: { |
| | | // type: 'value', |
| | | |
| | | // axisLine: { |
| | | // show: false, |
| | | // }, |
| | | // min: 0, |
| | | // max: 100, |
| | | // axisTick: { |
| | | // show: true, |
| | | // }, |
| | | // splitLine: { |
| | | // show: false |
| | | // } |
| | | // }, |
| | | // series: [ |
| | | // { |
| | | // data: [20], |
| | | // type: 'bar', |
| | | // showBackground: true, |
| | | // backgroundStyle: { |
| | | // color: 'rgba(180, 180, 180, 0.2)' |
| | | // }, |
| | | // label: { |
| | | // show: true, |
| | | // }, |
| | | // barWidth: 20, |
| | | // markLine: { |
| | | // symbol: 'none', |
| | | // data: [ |
| | | // {symbol: 'none', |
| | | // xAxis:0, |
| | | // x:60, |
| | | // yAxis:60, |
| | | |
| | | // lineStyle:{ |
| | | // color: '#000', |
| | | // width:1, |
| | | |
| | | // }, |
| | | // label: { |
| | | // formatter: '初始\n'+ '{c}%' |
| | | // } |
| | | // }, |
| | | // {symbol: 'none', |
| | | // xAxis:0, |
| | | // x:60, |
| | | // yAxis:11, |
| | | |
| | | // lineStyle:{ |
| | | // color: '#000', |
| | | // width:1, |
| | | |
| | | // }, |
| | | // label: { |
| | | // formatter: '目标\n'+ '{c}%' |
| | | // } |
| | | // }, |
| | | function initCharts() { |
| | | // console.log(`output->initChart`) |
| | | eqps.value.forEach((item) => { |
| | | // console.log(`output->item.id`, item.id) |
| | | let domId = 'moisture' + item.id |
| | | // console.log(`output->domId`, domId) |
| | | var chartDom: HTMLElement = document.getElementById(domId) as HTMLElement |
| | | // console.log(`output->chartDom`, chartDom) |
| | | let myChart = echarts.init(chartDom) |
| | | // var option |
| | | // option = { |
| | | // grid: { |
| | | // left: 30, |
| | | // top: 15, |
| | | // bottom: 13, |
| | | // right: 45 |
| | | // }, |
| | | // xAxis: { |
| | | // type: 'category', |
| | | // show: false, |
| | | // data: ['含水率'], |
| | | // axisLine: { |
| | | // show: false, |
| | | // }, |
| | | // axisTick: { |
| | | // show: false, |
| | | // } |
| | | // }, |
| | | // yAxis: { |
| | | // type: 'value', |
| | | |
| | | |
| | | // // {yAxis: 0}, |
| | | // // {yAxis: 100} |
| | | // ] |
| | | // } |
| | | // }, |
| | | |
| | | // ] |
| | | // }; |
| | | const option = { |
| | | // axisLine: { |
| | | // show: false, |
| | | // }, |
| | | // min: 0, |
| | | // max: 100, |
| | | // axisTick: { |
| | | // show: true, |
| | | // }, |
| | | // splitLine: { |
| | | // show: false |
| | | // } |
| | | // }, |
| | | // series: [ |
| | | // { |
| | | // data: [20], |
| | | // type: 'bar', |
| | | // showBackground: true, |
| | | // backgroundStyle: { |
| | | // color: 'rgba(180, 180, 180, 0.2)' |
| | | // }, |
| | | // label: { |
| | | // show: true, |
| | | // }, |
| | | // barWidth: 20, |
| | | // markLine: { |
| | | // symbol: 'none', |
| | | // data: [ |
| | | // {symbol: 'none', |
| | | // xAxis:0, |
| | | // x:60, |
| | | // yAxis:60, |
| | | |
| | | series: [{ |
| | | type: 'liquidFill', |
| | | radius: '100%', |
| | | //waveAnimation: false, |
| | | amplitude: 3, |
| | | animationDuration: 5, |
| | | //animationDurationUpdate: 0, |
| | | data: mois.value, |
| | | shape: 'path://M828.817,706.209C828.817,881.725,686.98,1024,512,1024c-174.98,0-316.817-142.275-316.817-317.791C195.183,530.74,512,0,512,0s316.817,530.74,316.817,706.209z', |
| | | outline: { |
| | | show: false |
| | | }, |
| | | label: { |
| | | |
| | | // lineStyle:{ |
| | | // color: '#000', |
| | | // width:1, |
| | | |
| | | formatter: function(params) { |
| | | console.log(`output->params`,params,mois.value) |
| | | // }, |
| | | // label: { |
| | | // formatter: '初始\n'+ '{c}%' |
| | | // } |
| | | // }, |
| | | // {symbol: 'none', |
| | | // xAxis:0, |
| | | // x:60, |
| | | // yAxis:11, |
| | | |
| | | return '' |
| | | // +'初始'+(mois.value[0]*100).toFixed(2) + '%\n\n\n' |
| | | + (mois.value[1]*100).toFixed(2) + '%' |
| | | // + '\n\n\n目标'+(mois.value[2]*100).toFixed(2) + '%' |
| | | ; |
| | | // lineStyle:{ |
| | | // color: '#000', |
| | | // width:1, |
| | | |
| | | // }, |
| | | // label: { |
| | | // formatter: '目标\n'+ '{c}%' |
| | | // } |
| | | // }, |
| | | |
| | | // // {yAxis: 0}, |
| | | // // {yAxis: 100} |
| | | // ] |
| | | // } |
| | | // }, |
| | | |
| | | // ] |
| | | // }; |
| | | const option = { |
| | | series: [ |
| | | { |
| | | type: 'liquidFill', |
| | | radius: '100%', |
| | | //waveAnimation: false, |
| | | amplitude: 3, |
| | | animationDuration: 5, |
| | | //animationDurationUpdate: 0, |
| | | data: mois.value, |
| | | shape: |
| | | 'path://M828.817,706.209C828.817,881.725,686.98,1024,512,1024c-174.98,0-316.817-142.275-316.817-317.791C195.183,530.74,512,0,512,0s316.817,530.74,316.817,706.209z', |
| | | outline: { |
| | | show: false, |
| | | }, |
| | | label: { |
| | | formatter: function () { |
| | | //console.log(`output->params`,params,mois.value) |
| | | |
| | | return ( |
| | | '' + |
| | | // +'初始'+(mois.value[0]*100).toFixed(2) + '%\n\n\n' |
| | | (mois.value[1] * 100).toFixed(2) + |
| | | '%' |
| | | // + '\n\n\n目标'+(mois.value[2]*100).toFixed(2) + '%' |
| | | ) |
| | | }, |
| | | fontSize: 10, |
| | | //position: ['50%',(100-mois.value[1]*100).toFixed(2) + '%'], |
| | | }, |
| | | }, |
| | | fontSize: 10, |
| | | position: ['50%',(100-mois.value[1]*100).toFixed(2) + '%'], |
| | | |
| | | ], |
| | | } |
| | | |
| | | option && myChart.setOption(option) |
| | | moistureCharts.set(item.id, myChart) |
| | | }) |
| | | } |
| | | |
| | | function gotoEqp(id: string) { |
| | | router.push('/dashboard/eqp/' + id) |
| | | } |
| | | |
| | | function updateRealTime() { |
| | | console.log(`output->定时刷新数据`) |
| | | eqps.value.forEach((item) => { |
| | | queryRealTime(item) |
| | | }) |
| | | } |
| | | |
| | | function queryRealTime(eqp: dryEquipment) { |
| | | let tenantId = userStore.getTenant |
| | | let eqpCode = eqp.code |
| | | let queryRealTimeUrl = '/dry/real/getRealTimeData' |
| | | defHttp.get({ url: queryRealTimeUrl, params: { tenantid: tenantId, machineid: eqpCode } }).then((res) => { |
| | | console.log(`output->res`, res) |
| | | if (res && res.trendVo) { |
| | | res.tempValue = [res.windTemp, 100] |
| | | res.percent = ((res.dryTime / res.et) * 100).toFixed(2) |
| | | res.mois = [ |
| | | (res.trendVo.moisture / 100).toFixed(2), |
| | | (res.trendVo.moisture / 100 / 1.5).toFixed(2), |
| | | (res.trendVo.moisture / 100 / 3).toFixed(2), |
| | | ] |
| | | moistureCharts.get(eqp.id)?.setOption({ |
| | | series: [ |
| | | { |
| | | data: res.mois, |
| | | label: { |
| | | formatter: function () { |
| | | return res.trendVo.moisture + '%' |
| | | }, |
| | | fontSize: 10, |
| | | //position: ['50%',(100- res.trendVo.moisture)+ '%'], |
| | | }, |
| | | }, |
| | | ], |
| | | }) |
| | | } else { |
| | | res = { |
| | | tempValue: [0, 100], |
| | | percent: 0, |
| | | mois: [], |
| | | } |
| | | }] |
| | | }; |
| | | } |
| | | |
| | | option && myChart.setOption(option) |
| | | moistureCharts.set(item.id, myChart) |
| | | }) |
| | | } |
| | | |
| | | |
| | | realTime.value.set(eqp.id, res) |
| | | }) |
| | | } |
| | | |
| | | listAllEqp() |
| | | // DOM挂载完成后渲染图表 |
| | | onMounted(() => {}) |
| | | onMounted(() => { |
| | | Timer.value = setInterval(updateRealTime, 3000) |
| | | }) |
| | | |
| | | onUnmounted(() => { |
| | | clearInterval(Timer.value) |
| | | Timer.value = null |
| | | }) |
| | | </script> |
| | | |
| | | <style> |
| | | <style scoped> |
| | | .workshop { |
| | | } |
| | | .eqp-row { |
| | |
| | | width: 566px; |
| | | height: 400px; |
| | | padding: 6px 6px; |
| | | flex-grow: 0; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .eqp-content { |
| | |
| | | background-image: url('../../../assets/images/dry/ganzaoji-x.png'); |
| | | background-repeat: no-repeat; |
| | | background-size: 60% 60%; |
| | | background-position: 10px 150px; |
| | | background-position: 105px 150px; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | |
| | | display: flex; |
| | | text-align: center; |
| | | } |
| | | .progress { |
| | | padding:25px 25px; |
| | | :deep() .progress { |
| | | padding: 25px 25px; |
| | | |
| | | width: 360px; |
| | | display: flex; |
| | | } |
| | | .ant-progress-bg { |
| | | :deep() .ant-progress-bg { |
| | | height: 25px !important; |
| | | } |
| | | .eqpStatus { |
| | | width:170px; |
| | | background-position: 0 -10px; |
| | | background-image: url('../../../assets/images/dry/ganzaoji.gif'); |
| | | background-size: 100% 100%; |
| | | width: 170px; |
| | | background-position: 0 0px; |
| | | background-image: url('../../../assets/images/dry/refeng2.gif'); |
| | | background-size: 180px; |
| | | background-repeat: no-repeat; |
| | | display: inline-flex; |
| | | flex-direction: column-reverse; |
| | | padding: 15px; |
| | | |
| | | } |
| | | .info { |
| | | display: flex; |
| | | } |
| | | .leftInfo { |
| | | width: 335px; |
| | | width: 445px; |
| | | display: flex; |
| | | /* background: gray; */ |
| | | } |
| | | .rightInfo { |
| | |
| | | } |
| | | .eqpName { |
| | | margin-top: 68px; |
| | | margin-left: 174px; |
| | | margin-left: 150px; |
| | | width: 95px; |
| | | font-weight: bold; |
| | | text-align: center; |
| | | background-color: white; |
| | | height: 22px; |
| | | } |
| | | |
| | | .tempChart { |
| | | padding-top: 10px; |
| | | |
| | | |
| | | height: 150px; |
| | | width: 100px; |
| | | } |
| | | |
| | | .herbInfo { |
| | | width: 160px; |
| | | width: 160px; |
| | | } |
| | | .ant-slider-mark-text { |
| | | :deep() .ant-slider-mark-text { |
| | | padding-left: 15px; |
| | | font-size: 10px; |
| | | } |
| | | .ant-slider-mark-text::before { |
| | | :deep() .ant-slider-mark-text::before { |
| | | content: ''; |
| | | display: block; |
| | | width: 6px; |
| | |
| | | top: 10px; |
| | | left: 0px; |
| | | } |
| | | .ant-slider-rail { |
| | | :deep() .ant-slider-rail { |
| | | width: 6px !important; |
| | | border-radius: 6px 6px 0 0; |
| | | background: linear-gradient(to top, #ce0000 0%, #ce0000 40%, #ce0000 75%, rgb(160, 160, 160) 100%); |
| | | } |
| | | .ant-slider-track { |
| | | :deep() .ant-slider-track { |
| | | background: rgb(175, 175, 175); |
| | | |
| | | height: 20px; |
| | | width: 6px !important; |
| | | border-radius: 6px 6px 0 0; |
| | | } |
| | | .ant-slider-track:hover { |
| | | :deep() .ant-slider-track:hover { |
| | | } |
| | | .ant-slider-handle { |
| | | :deep() .ant-slider-handle { |
| | | display: none; |
| | | } |
| | | .ant-slider-dot { |
| | | :deep() .ant-slider-dot { |
| | | display: none; |
| | | } |
| | | .ant-slider-step { |
| | | :deep() .ant-slider-step { |
| | | width: 10px !important; |
| | | } |
| | | .ant-slider-step > :first-child { |
| | | :deep() .ant-slider-step > :first-child { |
| | | display: block !important; |
| | | width: 22px !important; |
| | | height: 22px !important; |