shebeizhuangtai.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. <template>
  2. <el-dialog
  3. :model-value="modelValue"
  4. fullscreen
  5. :title="props.title"
  6. destroy-on-close
  7. :before-close="() => emits('update:modelValue', false )"
  8. >
  9. <el-row>
  10. <el-col :span="20">
  11. <el-row
  12. style="height: 20vh"
  13. >
  14. <v-chart
  15. class="chart1"
  16. autoresize
  17. :option="option1"
  18. />
  19. </el-row>
  20. <el-row
  21. style="height: 20vh"
  22. >
  23. <v-chart
  24. class="chart2"
  25. autoresize
  26. :option="option2"
  27. />
  28. </el-row>
  29. <el-row
  30. style="height: 20vh"
  31. >
  32. <v-chart
  33. class="chart3"
  34. autoresize
  35. :option="option3"
  36. />
  37. </el-row>
  38. <el-col style="height: 10vh; text-align: center; margin-top: 10px">
  39. <el-button
  40. class="btn-right"
  41. style="background: #5B79D7;"
  42. @click="prevClick"
  43. >
  44. 上一班次
  45. </el-button>
  46. <span
  47. style="font-size: 26px;vertical-align: middle;margin: 20px"
  48. >当前班次:{{ currentFrequency }}</span>
  49. <el-button
  50. class="btn-right"
  51. @click="nextClick"
  52. style="background: #5B79D7;"
  53. >
  54. 下一班次
  55. </el-button>
  56. </el-col>
  57. </el-col>
  58. <el-col :span="4">
  59. <div
  60. style="font-size: 22px; margin-left: 30px"
  61. >设备状态:</div><br>
  62. <el-button
  63. class="btn-right"
  64. :class="{ 'active': activeBtn === '待单'}"
  65. @click="handleBtnActive"
  66. >待单</el-button><br>
  67. <el-button
  68. class="btn-right"
  69. :class="{ 'active': activeBtn === '维修' }"
  70. @click="handleBtnActive"
  71. >维修</el-button><br>
  72. <el-button
  73. class="btn-right"
  74. :class="{ 'active': activeBtn === '保养' }"
  75. @click="handleBtnActive"
  76. >保养</el-button><br>
  77. <el-button
  78. class="btn-right"
  79. :class="{ 'active': activeBtn === '测试' }"
  80. @click="handleBtnActive"
  81. >测试</el-button><br>
  82. <el-button
  83. class="btn-right"
  84. :class="{ 'active': activeBtn === '打样' }"
  85. @click="handleBtnActive"
  86. >打样</el-button><br>
  87. <el-button
  88. class="btn-right"
  89. :class="{ 'active': activeBtn === '待料' }"
  90. @click="handleBtnActive"
  91. >待料</el-button><br>
  92. <el-button
  93. class="btn-right"
  94. :class="{ 'active': activeBtn === '装版' }"
  95. @click="handleBtnActive"
  96. >装版</el-button><br>
  97. <el-button
  98. class="btn-right"
  99. :class="{ 'active': activeBtn === '生产' }"
  100. @click="handleBtnActive"
  101. >生产</el-button><br>
  102. </el-col>
  103. </el-row>
  104. </el-dialog>
  105. </template>
  106. <script>
  107. export default {
  108. name: 'Shebeizhuangtai',
  109. }
  110. // 机台数据详情
  111. import service from '@/utils/request'
  112. const getMachineDetail = (params) => {
  113. return service({
  114. url: '/mes_server/facility/MachineDetail',
  115. method: 'get',
  116. params
  117. })
  118. }
  119. const setMachineStatus = (data) => {
  120. return service({
  121. url:'/mes_server/reporting_work/setMachineStatus',
  122. method: 'post',
  123. data
  124. })
  125. }
  126. </script>
  127. <script setup>
  128. import { use } from 'echarts/core'
  129. import { CanvasRenderer } from 'echarts/renderers'
  130. import { BarChart, LineChart, PieChart, ScatterChart } from 'echarts/charts'
  131. import { GridComponent, LegendComponent, TitleComponent, TooltipComponent } from 'echarts/components'
  132. import VChart, { THEME_KEY } from 'vue-echarts'
  133. import { defineEmits, defineProps, provide, ref } from 'vue'
  134. const props = defineProps(['modelValue', 'title','formData'])
  135. const emits = defineEmits(['update:modelValue'])
  136. use([
  137. CanvasRenderer,
  138. PieChart,
  139. BarChart,
  140. LineChart,
  141. ScatterChart,
  142. GridComponent,
  143. TitleComponent,
  144. TooltipComponent,
  145. LegendComponent,
  146. ])
  147. // provide(THEME_KEY, 'dark')
  148. const currentFrequency = ref()
  149. const timeDifference=ref([0,0,0,0,0,0,0,0])
  150. const timeRow=ref([])
  151. const timeData=ref([])
  152. const activeBtn = ref(null)
  153. const handleBtnActive = async(e) => {
  154. if(activeBtn.value == e.target.innerText){
  155. console.log(props.formData)
  156. }else{
  157. const response = await setMachineStatus({
  158. machine:props.formData.machine.split('#')[0],
  159. order:props.formData.工单编号,
  160. yjno:props.formData.印件号,
  161. gy_name:props.formData.工序名称.split('【')[0],
  162. class:props.formData.class,
  163. status:e.target.innerText,
  164. production_now:props.formData.production_now,
  165. production_all:props.formData.production_all
  166. });
  167. if(response.code === 0){
  168. activeBtn.value = e.target.innerText
  169. }
  170. }
  171. }
  172. const prevClick = async() => {
  173. if(currentFrequency.value.split(' ')[1].substring(0,2)=='08'){
  174. let previousDay = new Date(currentFrequency.value); // 创建一个表示当前时间的Date对象
  175. previousDay.setDate(previousDay.getDate() - 1); // 将日期设置为前一天
  176. let year = previousDay.getFullYear();
  177. let month = previousDay.getMonth() + 1;
  178. let day = previousDay.getDate();
  179. currentFrequency.value=`${year}-${month}-${day} 20:30:00`
  180. console.log(currentFrequency.value); // 输出前一天日期
  181. }else{
  182. let now = currentFrequency.value.split(' ')[0]
  183. currentFrequency.value=`${now} 08:30:00`
  184. }
  185. GetMachineDetail()
  186. }
  187. const nextClick = async() => {
  188. if(currentFrequency.value.split(' ')[1].substring(0,2)=='20'){
  189. let nextDay = new Date(currentFrequency.value); // 创建一个表示当前时间的Date对象
  190. nextDay.setDate(nextDay.getDate() + 1); // 将日期设置为后一天
  191. let year = nextDay.getFullYear();
  192. let month = nextDay.getMonth() + 1;
  193. let day = nextDay.getDate();
  194. currentFrequency.value=`${year}-${month}-${day} 08:30:00`
  195. }else{
  196. let now = currentFrequency.value.split(' ')[0]
  197. currentFrequency.value=`${now} 20:30:00`
  198. }
  199. GetMachineDetail()
  200. }
  201. const GetMachineDetail = async() => {
  202. timeDifference.value=[0,0,0,0,0,0,0,0]
  203. timeRow.value=[]
  204. timeData.value=[]
  205. const data = []
  206. for (let i = 510; i <= 1230; i++) { // 08:30 到 20:30 的分钟数范围
  207. const hours = Math.floor(i / 60)
  208. const minutes = i % 60
  209. const time = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes)
  210. data.push([time, 0])
  211. }
  212. const response = await getMachineDetail({machine:props.formData.machine,start:currentFrequency.value});
  213. if (response.code === 0) {
  214. response.data.timeDifference.map(item=>{
  215. switch(item.状态) {
  216. case '维修':
  217. timeDifference.value[1]=item.时间?item.时间:0;
  218. break;
  219. case '保养':
  220. timeDifference.value[2]=item.时间?item.时间:0;
  221. break;
  222. case '测试':
  223. timeDifference.value[3]=item.时间?item.时间:0;
  224. break;
  225. case '打样':
  226. timeDifference.value[4]=item.时间?item.时间:0;
  227. break;
  228. case '待料':
  229. timeDifference.value[5]=item.时间?item.时间:0;
  230. break;
  231. case '装版':
  232. timeDifference.value[6]=item.时间?item.时间:0;
  233. break;
  234. case '生产':
  235. timeDifference.value[7]=item.时间?item.时间:0;
  236. break;
  237. case '':
  238. timeDifference.value[0]=item.时间?item.时间:0;
  239. break;
  240. default:
  241. }
  242. })
  243. response.data.row.map(item=>{
  244. data.map(items=>{
  245. if(item.时间.split(' ')[1]==items[0]){
  246. items[1]=item.产能
  247. }
  248. return items
  249. })
  250. })
  251. option1.value = {
  252. xAxis: {
  253. data: ['待单', '维修', '保养', '测试', '打样', '待料', '装版', '生产'],
  254. },
  255. yAxis: {
  256. name: '状态时长(小时)',
  257. nameLocation: 'end',
  258. nameGap: 5,
  259. nameTextStyle: {
  260. align: 'left',
  261. verticalAlign: 'bottom',
  262. },
  263. },
  264. grid: {
  265. left: '8%',
  266. right: '2%',
  267. top: '22%',
  268. bottom: '15%',
  269. },
  270. series: {
  271. type: 'bar',
  272. label: {
  273. show: true,
  274. position: 'top',
  275. },
  276. data: timeDifference.value,
  277. },
  278. textStyle: {
  279. fontWeight: 'bolder',
  280. fontSize: 16,
  281. },
  282. }
  283. option2.value={
  284. xAxis: {
  285. type: 'category',
  286. axisLabel: {
  287. interval: 59, // 控制显示的刻度标签间隔,每小时一个
  288. },
  289. },
  290. yAxis: {
  291. name: '实时产量',
  292. nameLocation: 'end',
  293. nameGap: 5,
  294. nameTextStyle: {
  295. align: 'left',
  296. verticalAlign: 'bottom',
  297. }
  298. },
  299. grid: {
  300. left: '8%',
  301. right: '2%',
  302. top: '22%',
  303. bottom: '15%',
  304. },
  305. tooltip: {
  306. trigger: 'axis'
  307. },
  308. series: {
  309. name: '速度',
  310. type: 'line',
  311. data: data,
  312. },
  313. textStyle: {
  314. fontWeight: 'bolder',
  315. fontSize: 16,
  316. },
  317. }
  318. response.data.首件.map(item=>{
  319. timeData.value.push([item.split(' ')[1].substring(0,5),'首件与过程'])
  320. })
  321. response.data.自检.map(item=>{
  322. timeData.value.push([item.split(' ')[1].substring(0,5),'机台检验'])
  323. })
  324. response.data.IPQC.map(item=>{
  325. timeData.value.push([item.split(' ')[1].substring(0,5),'IPQC检验'])
  326. })
  327. option3.value = {
  328. xAxis: {
  329. // type: 'value',
  330. data: xAxisData,
  331. axisLabel: {
  332. interval: 59, // 控制显示的刻度标签间隔,每小时一个
  333. },
  334. },
  335. yAxis: {
  336. name: '检验时间',
  337. nameLocation: 'end',
  338. nameGap: 5,
  339. nameTextStyle: {
  340. align: 'left',
  341. verticalAlign: 'bottom'
  342. },
  343. axisLine: {
  344. show: true,
  345. },
  346. data: ['IPQC检验', '机台检验', '首件与过程'],
  347. },
  348. tooltip: {
  349. trigger: 'item'
  350. },
  351. grid: {
  352. left: '8%',
  353. right: '2%',
  354. top: '22%',
  355. bottom: '15%',
  356. },
  357. series: {
  358. type: 'scatter',
  359. symbol: 'arrow',
  360. symbolSize: 20,
  361. label: {
  362. show: true,
  363. position: 'right',
  364. formatter: '{@value}' // 点旁边显示label,这里使用name: '横坐标'这样写也可以,鼠标移入出现提示。
  365. },
  366. data: timeData.value,
  367. },
  368. textStyle: {
  369. fontWeight: 'bolder',
  370. fontSize: 16,
  371. },
  372. }
  373. }
  374. }
  375. const option1 = ref({
  376. xAxis: {
  377. data: ['待单', '维修', '保养', '测试', '打样', '待料', '装版', '生产'],
  378. },
  379. yAxis: {
  380. name: '状态时长(小时)',
  381. nameLocation: 'end',
  382. nameGap: 5,
  383. nameTextStyle: {
  384. align: 'left',
  385. verticalAlign: 'bottom',
  386. },
  387. },
  388. grid: {
  389. left: '8%',
  390. right: '2%',
  391. top: '22%',
  392. bottom: '15%',
  393. },
  394. series: {
  395. type: 'bar',
  396. label: {
  397. show: true,
  398. position: 'top',
  399. },
  400. data: timeDifference.value,
  401. },
  402. textStyle: {
  403. fontWeight: 'bolder',
  404. fontSize: 16,
  405. },
  406. })
  407. // 生成横坐标(每分钟一个点,显示时间格式为 "HH:mm")
  408. const data = []
  409. for (let i = 510; i <= 1230; i++) { // 08:30 到 20:30 的分钟数范围
  410. const hours = Math.floor(i / 60)
  411. const minutes = i % 60
  412. const time = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes)
  413. data.push([time, 0])
  414. }
  415. const Worklist = async () => {
  416. let now = new Date();
  417. let year = now.getFullYear();
  418. let month = now.getMonth() + 1;
  419. let day = now.getDate();
  420. let hour = now.getHours();
  421. let minute = now.getMinutes();
  422. let second = now.getSeconds();
  423. if(hour>=20){
  424. currentFrequency.value=`${year}-${month}-${day} 20:30:00`
  425. }else{
  426. currentFrequency.value=`${year}-${month}-${day} 08:30:00`
  427. }
  428. activeBtn.value=props.formData['status']
  429. GetMachineDetail()
  430. }
  431. Worklist()
  432. const xAxisData = data.map(item => item?.[0])
  433. const option2 = ref({
  434. xAxis: {
  435. type: 'category',
  436. axisLabel: {
  437. interval: 59, // 控制显示的刻度标签间隔,每小时一个
  438. },
  439. },
  440. yAxis: {
  441. name: '实时产量',
  442. nameLocation: 'end',
  443. nameGap: 5,
  444. nameTextStyle: {
  445. align: 'left',
  446. verticalAlign: 'bottom',
  447. }
  448. },
  449. grid: {
  450. left: '8%',
  451. right: '2%',
  452. top: '22%',
  453. bottom: '15%',
  454. },
  455. tooltip: {
  456. trigger: 'axis'
  457. },
  458. series: {
  459. name: '速度',
  460. type: 'line',
  461. data: data,
  462. },
  463. textStyle: {
  464. fontWeight: 'bolder',
  465. fontSize: 16,
  466. },
  467. })
  468. const option3 = ref({
  469. xAxis: {
  470. // type: 'value',
  471. data: xAxisData,
  472. axisLabel: {
  473. interval: 59, // 控制显示的刻度标签间隔,每小时一个
  474. },
  475. },
  476. yAxis: {
  477. name: '检验时间',
  478. nameLocation: 'end',
  479. nameGap: 5,
  480. nameTextStyle: {
  481. align: 'left',
  482. verticalAlign: 'bottom'
  483. },
  484. axisLine: {
  485. show: true,
  486. },
  487. data: ['IPQC检验', '机台检验', '首件与过程'],
  488. },
  489. tooltip: {
  490. trigger: 'item'
  491. },
  492. grid: {
  493. left: '8%',
  494. right: '2%',
  495. top: '22%',
  496. bottom: '15%',
  497. },
  498. series: {
  499. type: 'scatter',
  500. symbol: 'arrow',
  501. symbolSize: 20,
  502. label: {
  503. show: true,
  504. position: 'right',
  505. formatter: '{@value}' // 点旁边显示label,这里使用name: '横坐标'这样写也可以,鼠标移入出现提示。
  506. },
  507. data: timeData.value,
  508. },
  509. textStyle: {
  510. fontWeight: 'bolder',
  511. fontSize: 16,
  512. },
  513. })
  514. </script>
  515. <style scoped>
  516. .active {
  517. background-color: #528B34 !important;
  518. }
  519. .btn-right {
  520. width: 100px;
  521. height: 50px;
  522. margin-bottom: 5px;
  523. margin-left: 30px;
  524. color: #FFFFFF;
  525. background-color: #C6BEC4;
  526. font-size: 20px;
  527. font-style: italic;
  528. }
  529. </style>