<template> 
 | 
  <div class="proccess-content"> 
 | 
    <div class="process-left"> 
 | 
      <div class="proccess-plan"> 
 | 
        <div class="header-title">工序计划进度</div> 
 | 
        <div class="table-content"> 
 | 
          <div class="table-head"> 
 | 
            <div class="table-head_item">物料名称</div> 
 | 
            <div class="table-head_item">物料编码</div> 
 | 
            <div class="table-head_item">计划数量</div> 
 | 
            <div class="table-head_item">良品数</div> 
 | 
            <div class="table-head_item">不良品数</div> 
 | 
            <div class="table-head_item">未完工数量</div> 
 | 
            <div class="table-head_item">不良率</div> 
 | 
          </div> 
 | 
          <div @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" class="tablel_container"> 
 | 
            <div ref="planContainer" class="scroll_container"> 
 | 
              <div v-for="(item, index) in listData" :key="item.id" class="scroll_item" 
 | 
                :class="index % 2 == 0 ? 'scroll_item scroll_item_bg1' : 'scroll_item scroll_item_bg2'"> 
 | 
                <div class="scroll_item_row">{{ item.name }}</div> 
 | 
                <div class="scroll_item_row">1</div> 
 | 
                <div class="scroll_item_row">2</div> 
 | 
                <div class="scroll_item_row">3</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
              </div> 
 | 
            </div> 
 | 
          </div> 
 | 
        </div> 
 | 
      </div> 
 | 
      <div class="today-yield"> 
 | 
        <div class="header-title">当日员工产量TOP10</div> 
 | 
        <div class="yield-content"> 
 | 
          <div class="yield-content-left"> 
 | 
            <div class="content_left_item1_content"> 
 | 
              <div class="content_left_item1_content_row" v-for="(item, index) in 5" :key="index"> 
 | 
                <div class="content_left_item1_content_row_name"> 
 | 
                  <div :class="index > 2 ? 'num bg1' : 'num bg2'">{{ index + 1 }}</div> 
 | 
                  <span>赵立{{ index }}</span> 
 | 
                </div> 
 | 
                <div class="content_left_item1_content_row_line"> 
 | 
                  <el-progress :show-text="false" :percentage="50"> 
 | 
                  </el-progress> 
 | 
                </div> 
 | 
                <div class="content_left_item1_content_row_num">342</div> 
 | 
              </div> 
 | 
            </div> 
 | 
          </div> 
 | 
          <div class="yield-content-left"> 
 | 
            <div class="content_left_item1_content"> 
 | 
              <div class="content_left_item1_content_row" v-for="(item, index) in 5" :key="index"> 
 | 
                <div class="content_left_item1_content_row_name"> 
 | 
                  <div class="num bg1">{{ index + 6 }}</div> 
 | 
                  <span>赵立{{ index }}</span> 
 | 
                </div> 
 | 
                <div class="content_left_item1_content_row_line"> 
 | 
                  <el-progress :show-text="false" :percentage="50"> 
 | 
                  </el-progress> 
 | 
                </div> 
 | 
                <div class="content_left_item1_content_row_num">342</div> 
 | 
              </div> 
 | 
            </div> 
 | 
          </div> 
 | 
        </div> 
 | 
  
 | 
      </div> 
 | 
    </div> 
 | 
    <div class="process-right"> 
 | 
      <div class="report-log"> 
 | 
        <div class="header-title">报工日志</div> 
 | 
        <div class="table-content"> 
 | 
          <div class="table-head"> 
 | 
            <div class="table-head_item">员工名称</div> 
 | 
            <div class="table-head_item">物料名称</div> 
 | 
            <div class="table-head_item">物料编码</div> 
 | 
            <div class="table-head_item">报工时间</div> 
 | 
            <div class="table-head_item">良品数</div> 
 | 
            <div class="table-head_item">不良品数</div> 
 | 
            <div class="table-head_item">不良率</div> 
 | 
          </div> 
 | 
          <div @mouseenter="handleMouseEnterReport" @mouseleave="handleMouseLeaveReport" class="tablel_container"> 
 | 
            <div ref="reportLogContainer" class="scroll_container"> 
 | 
              <div v-for="(item, index) in listData" :key="item.id" class="scroll_item" 
 | 
                :class="index % 2 == 0 ? 'scroll_item scroll_item_bg1' : 'scroll_item scroll_item_bg2'"> 
 | 
                <div class="scroll_item_row">{{ item.name }}</div> 
 | 
                <div class="scroll_item_row">1</div> 
 | 
                <div class="scroll_item_row">2</div> 
 | 
                <div class="scroll_item_row">3</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
                <div class="scroll_item_row">4</div> 
 | 
              </div> 
 | 
            </div> 
 | 
          </div> 
 | 
        </div> 
 | 
      </div> 
 | 
      <div class="bad-diagram"> 
 | 
        <div class="header-title">近7天不良品分布</div> 
 | 
        <div class="bad-content"> 
 | 
          <div id="day-distribution"></div> 
 | 
          <div id="type-distribution"></div> 
 | 
        </div> 
 | 
      </div> 
 | 
    </div> 
 | 
  </div> 
 | 
</template> 
 | 
  
 | 
<script setup> 
 | 
import { reactive, ref, onMounted, onBeforeUnmount, onUnmounted, nextTick } from 'vue' 
 | 
import * as echarts from 'echarts' 
 | 
let planTimer = ref(null) 
 | 
let reportTimer = ref(null) 
 | 
let planContainer = ref(null) 
 | 
let reportLogContainer = ref(null) 
 | 
let listData = reactive([ 
 | 
  { name: 'dom第一个' }, 
 | 
  { name: 'dom第二个' }, 
 | 
  { name: 'dom第三个' }, 
 | 
  { name: 'dom第四个' }, 
 | 
  { name: 'dom第五个' }, 
 | 
  { name: 'dom第六个' }, 
 | 
  { name: 'dom第七个' }, 
 | 
  { name: 'dom第八个' }, 
 | 
  { name: 'dom第九个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
  { name: 'dom第十个' }, 
 | 
]) 
 | 
let dayDistribution = reactive([ 
 | 
  { date: '8/1', num: '20' }, 
 | 
  { date: '8/2', num: '10' }, 
 | 
  { date: '8/3', num: '20' }, 
 | 
  { date: '8/4', num: '40' }, 
 | 
  { date: '8/5', num: '30' }, 
 | 
  { date: '8/6', num: '10' }, 
 | 
  { date: '8/7', num: '20' }, 
 | 
]) 
 | 
let typeDistribution = reactive([ 
 | 
  { name: '外观不良', num: 15 }, 
 | 
  { name: '有毛刺', num: 12 }, 
 | 
  { name: '尺寸不良', num: 22 }, 
 | 
  { name: '有划痕', num: 5 }, 
 | 
  { name: '其他', num: 2 }, 
 | 
  
 | 
]) 
 | 
// start() 
 | 
onBeforeUnmount(() => { 
 | 
  clearTimeout(planTimer.value) 
 | 
  clearTimeout(reportTimer.value) 
 | 
}) 
 | 
onMounted(() => { 
 | 
  nextTick(() => { 
 | 
    start() 
 | 
    reportStart() 
 | 
    setDayChart() 
 | 
    setTypeChart() 
 | 
  }) 
 | 
}) 
 | 
  
 | 
  
 | 
onUnmounted(() => { 
 | 
  clearTimeout(planTimer.value) 
 | 
  clearTimeout(reportTimer.value) 
 | 
}) 
 | 
  
 | 
function handleMouseEnter() { 
 | 
  clearTimeout(planTimer.value) 
 | 
} 
 | 
function handleMouseLeave() { 
 | 
  start() 
 | 
} 
 | 
  
 | 
function handleMouseEnterReport() { 
 | 
  clearTimeout(reportTimer.value) 
 | 
} 
 | 
function handleMouseLeaveReport() { 
 | 
  reportStart() 
 | 
} 
 | 
  
 | 
/** 
 | 
 * 工序计划 
 | 
 */ 
 | 
// 开启定时器 
 | 
function start() { 
 | 
  clearTimeout(planTimer.value) 
 | 
  // 定时器触发周期 
 | 
  // let speed = ref(100) 
 | 
  planTimer.value = setInterval(ListScroll, 100) 
 | 
} 
 | 
function ListScroll() { 
 | 
  let scrollDom = planContainer.value 
 | 
  // 判读组件是否渲染完成 
 | 
  if (scrollDom.offsetHeight == 0) { 
 | 
    scrollDom = planContainer.value 
 | 
  } else { 
 | 
    // 如果列表数量过少不进行滚动 
 | 
    if (scrollDom.children.length < 4) { 
 | 
      clearTimeout(planTimer.value) 
 | 
      return 
 | 
    } 
 | 
    // 组件进行滚动 
 | 
    scrollDom.scrollTop += 2 
 | 
    // 判断是否滚动到底部 
 | 
    if (scrollDom.scrollTop >= (scrollDom.scrollHeight - scrollDom.clientHeight)) { 
 | 
      // 获取组件第一个节点 
 | 
      let first = scrollDom.children[0] 
 | 
      // 删除节点 
 | 
      scrollDom.removeChild(first) 
 | 
      // 将该节点拼接到组件最后 
 | 
      scrollDom.append(first) 
 | 
    } 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * 报工日志 
 | 
 */ 
 | 
function reportStart() { 
 | 
  clearTimeout(reportTimer.value) 
 | 
  // 定时器触发周期 
 | 
  // let speed = ref(100) 
 | 
  reportTimer.value = setInterval(reportScroll, 100) 
 | 
} 
 | 
function reportScroll() { 
 | 
  let scrollDom = reportLogContainer.value 
 | 
  // 判读组件是否渲染完成 
 | 
  if (scrollDom.offsetHeight == 0) { 
 | 
    scrollDom = reportLogContainer.value 
 | 
  } else { 
 | 
    // 如果列表数量过少不进行滚动 
 | 
    if (scrollDom.children.length < 4) { 
 | 
      clearTimeout(reportTimer.value) 
 | 
      return 
 | 
    } 
 | 
    // 组件进行滚动 
 | 
    scrollDom.scrollTop += 2 
 | 
    // 判断是否滚动到底部 
 | 
    if (scrollDom.scrollTop >= (scrollDom.scrollHeight - scrollDom.clientHeight)) { 
 | 
      // 获取组件第一个节点 
 | 
      let first = scrollDom.children[0] 
 | 
      // 删除节点 
 | 
      scrollDom.removeChild(first) 
 | 
      // 将该节点拼接到组件最后 
 | 
      scrollDom.append(first) 
 | 
    } 
 | 
  } 
 | 
} 
 | 
/** 
 | 
 * 七日折线图 
 | 
 */ 
 | 
function setDayChart() { 
 | 
  let dayChartDom = document.getElementById('day-distribution'); 
 | 
  let myChart = echarts.init(dayChartDom); 
 | 
  let dateList = [] 
 | 
  let numList = [] 
 | 
  
 | 
  dayDistribution.forEach(item => { 
 | 
    dateList.push(item.date) 
 | 
    numList.push(item.num) 
 | 
  }) 
 | 
  let option; 
 | 
  option = { 
 | 
    title: { 
 | 
      text: '         近七日不良品总数:67', 
 | 
      textStyle: { 
 | 
        color: '#fff', 
 | 
        fontSize: 12 
 | 
      } 
 | 
    }, 
 | 
    xAxis: { 
 | 
      type: 'category', 
 | 
      boundaryGap: false, 
 | 
      splitLine: { 
 | 
        lineStyle: { 
 | 
          width: 0.5, 
 | 
          color: ['#fff'] 
 | 
        } 
 | 
      }, 
 | 
      axisLabel: { 
 | 
        textStyle: { 
 | 
          color: '#fff' 
 | 
        } 
 | 
      }, 
 | 
      data: dateList 
 | 
    }, 
 | 
  
 | 
    yAxis: { 
 | 
      type: 'value', 
 | 
      splitLine: { 
 | 
        lineStyle: { 
 | 
          width: 0.5, 
 | 
          color: ['#fff'] 
 | 
        } 
 | 
      }, 
 | 
      axisLabel: { 
 | 
        textStyle: { 
 | 
          color: '#fff' 
 | 
        } 
 | 
      } 
 | 
    }, 
 | 
    series: [ 
 | 
      { 
 | 
        data: numList, 
 | 
        type: 'line', 
 | 
        lineStyle: { 
 | 
          color: '#03D2B5', 
 | 
          width: 1 
 | 
        }, 
 | 
        areaStyle: { 
 | 
          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ 
 | 
            { 
 | 
              offset: 0, 
 | 
              color: 'rgba(3, 210, 181, .9)', 
 | 
            }, 
 | 
            { 
 | 
              offset: 1, 
 | 
              color: 'rgba(3, 210, 181, 0)', 
 | 
            } 
 | 
          ]) 
 | 
        } 
 | 
      } 
 | 
    ], 
 | 
  
 | 
    tooltip: { 
 | 
      trigger: 'axis' 
 | 
    }, 
 | 
    legend: { 
 | 
      name: '1adssad', 
 | 
      itemWidth: 10, 
 | 
      itemHeight: 10, 
 | 
      itemGap: 4, 
 | 
      textStyle: { 
 | 
        color: '#fff' 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
  
 | 
  option && myChart.setOption(option); 
 | 
} 
 | 
/** 
 | 
 * 不良类型分布 
 | 
 */ 
 | 
function setTypeChart() { 
 | 
  let dayChartDom = document.getElementById('type-distribution'); 
 | 
  let myChart = echarts.init(dayChartDom); 
 | 
  let legendData = [] 
 | 
  let seriesData = [] 
 | 
  typeDistribution.forEach(item => { 
 | 
    legendData.push(item.name) 
 | 
    seriesData.push({name:item.name, value:item.num}) 
 | 
  }) 
 | 
  let option = { 
 | 
    // title: { 
 | 
    //   text: '同名数量统计', 
 | 
    //   subtext: '纯属虚构', 
 | 
    //   left: 'center' 
 | 
    // }, 
 | 
    // tooltip: { 
 | 
    //   trigger: 'item', 
 | 
    //   formatter: '{a} <br/>{b} : {c} ({d}%)' 
 | 
    // }, 
 | 
    legend: { 
 | 
      show: false, 
 | 
      type: 'scroll', 
 | 
      orient: 'vertical', 
 | 
      right: 10, 
 | 
      top: 20, 
 | 
      bottom: 20, 
 | 
      data: legendData 
 | 
    }, 
 | 
    series: [ 
 | 
      { 
 | 
        // name: '姓名', 
 | 
        type: 'pie', 
 | 
  
 | 
        radius: ['60%', '70%'], 
 | 
        // avoidLabelOverlap: false, 
 | 
        itemStyle: { 
 | 
          borderRadius: 4, 
 | 
          borderColor: 'rgba(52, 88, 159, 0.4)', 
 | 
          borderWidth: 4 
 | 
        }, 
 | 
        center: ['50%', '50%'], 
 | 
        labelLine: { 
 | 
          show: false 
 | 
        }, 
 | 
        label: { 
 | 
          formatter:'{dot| } {title|{b} {c}}\n\n{per|{d}%}', 
 | 
          rich: { 
 | 
            title: { 
 | 
              color: '#fff' 
 | 
            }, 
 | 
            per: { 
 | 
              color: '#01D9FE' 
 | 
            }, 
 | 
            dot: { 
 | 
              backgroundColor: 'inherit', 
 | 
              width: 8, 
 | 
              height: 8, 
 | 
              borderRadius: 4 
 | 
            } 
 | 
          } 
 | 
        }, 
 | 
        // labelLayout: { 
 | 
        //   hideOverlap: true 
 | 
        // }, 
 | 
        endLabel: { 
 | 
          show: true, 
 | 
          distance: 5, 
 | 
          color: "red" 
 | 
        }, 
 | 
        data: seriesData, 
 | 
        emphasis: { 
 | 
          itemStyle: { 
 | 
            shadowBlur: 10, 
 | 
            shadowOffsetX: 0, 
 | 
            shadowColor: 'rgba(0, 0, 0, 1)' 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
    ] 
 | 
  } 
 | 
  option && myChart.setOption(option); 
 | 
} 
 | 
</script> 
 | 
  
 | 
<style lang="scss" scoped> 
 | 
.proccess-content { 
 | 
  display: flex; 
 | 
  
 | 
  .header-title { 
 | 
    background-image: url('@/assets/img/gongxu_title@2x.png'); 
 | 
    height: 28px; 
 | 
    width: 100%; 
 | 
    background-size: 100% 28px; 
 | 
    background-repeat: no-repeat; 
 | 
    padding-left: 34px; 
 | 
    font-size: 16px; 
 | 
    font-weight: bold; 
 | 
    color: #FFFFFF; 
 | 
    line-height: 26px; 
 | 
    text-shadow: 0px 0px 10px rgba(0, 24, 72, 0.75); 
 | 
  } 
 | 
  
 | 
  .process-left { 
 | 
    flex: 1; 
 | 
    margin-right: 20px; 
 | 
  
 | 
    .proccess-plan { 
 | 
      height: 460px; 
 | 
      background: linear-gradient(180deg, rgba(52, 88, 159, 0) 0%, rgba(0, 86, 255, 0.4) 100%); 
 | 
      margin-bottom: 20px; 
 | 
    } 
 | 
  
 | 
    .today-yield { 
 | 
      height: 222px; 
 | 
      background: linear-gradient(180deg, rgba(52, 88, 159, 0) 0%, rgba(0, 86, 255, 0.4) 100%); 
 | 
  
 | 
      .yield-content { 
 | 
        display: flex; 
 | 
  
 | 
        .yield-content-left { 
 | 
          flex: 1; 
 | 
  
 | 
          .content_left_item1_content { 
 | 
            width: 100%; 
 | 
            padding: 20px; 
 | 
            box-sizing: border-box; 
 | 
  
 | 
            .content_left_item1_content_row { 
 | 
              width: 100%; 
 | 
              display: flex; 
 | 
              align-items: center; 
 | 
              justify-content: space-between; 
 | 
              margin-bottom: 13px; 
 | 
  
 | 
              &:last-child { 
 | 
                margin: 0; 
 | 
              } 
 | 
  
 | 
              .content_left_item1_content_row_name { 
 | 
                flex-shrink: 0; 
 | 
                display: flex; 
 | 
                align-items: center; 
 | 
  
 | 
                span { 
 | 
                  font-size: 13px; 
 | 
                  font-family: SourceHanSansSC-Regular, SourceHanSansSC; 
 | 
                  font-weight: 400; 
 | 
                  color: #D2E0FF; 
 | 
                  margin-left: 9px; 
 | 
                } 
 | 
  
 | 
                .num { 
 | 
                  width: 20px; 
 | 
                  height: 20px; 
 | 
                  line-height: 20px; 
 | 
                  text-align: center; 
 | 
                  font-size: 12px; 
 | 
                  font-family: SourceHanSansSC-Medium, SourceHanSansSC; 
 | 
                  font-weight: 500; 
 | 
                  color: #FFFFFF; 
 | 
                } 
 | 
  
 | 
                .bg1 { 
 | 
                  background: url('@/assets/img/rank_blue@2x.png'); 
 | 
                  background-repeat: no-repeat; 
 | 
                  background-size: 100% 100%; 
 | 
                } 
 | 
  
 | 
                .bg2 { 
 | 
                  background: url('@/assets/img/rank_yellow@2x.png'); 
 | 
                  background-repeat: no-repeat; 
 | 
                  background-size: 100% 100%; 
 | 
                } 
 | 
              } 
 | 
  
 | 
              .content_left_item1_content_row_line { 
 | 
                flex: 1; 
 | 
                margin: 0 15px; 
 | 
  
 | 
                &::v-deep(.el-progress-bar__outer) { 
 | 
                  border-radius: 0%; 
 | 
                  background: rgba(255, 255, 255, 0.13); 
 | 
                } 
 | 
  
 | 
                &::v-deep(.el-progress-bar__inner) { 
 | 
                  border-radius: 0%; 
 | 
                  background: linear-gradient(270deg, #00B0FF 0%, #345BA3 100%); 
 | 
                } 
 | 
              } 
 | 
  
 | 
              .content_left_item1_content_row_num { 
 | 
                font-size: 13px; 
 | 
                font-family: SourceHanSansSC-Regular, SourceHanSansSC; 
 | 
                font-weight: 400; 
 | 
                color: #D2E0FF; 
 | 
              } 
 | 
            } 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
  
 | 
    } 
 | 
  } 
 | 
  
 | 
  .process-right { 
 | 
    flex: 1; 
 | 
  
 | 
    .report-log { 
 | 
      height: 460px; 
 | 
      background: linear-gradient(180deg, rgba(52, 88, 159, 0) 0%, rgba(0, 86, 255, 0.4) 100%); 
 | 
      margin-bottom: 20px; 
 | 
    } 
 | 
  
 | 
    .bad-diagram { 
 | 
      height: 222px; 
 | 
      background: linear-gradient(180deg, rgba(52, 88, 159, 0) 0%, rgba(0, 86, 255, 0.4) 100%); 
 | 
  
 | 
      .bad-content { 
 | 
        display: flex; 
 | 
        margin-top: 20px; 
 | 
  
 | 
        #day-distribution { 
 | 
          // padding: 20px; 
 | 
          box-sizing: border-box; 
 | 
          flex: 0.5; 
 | 
          height: 190px; 
 | 
        } 
 | 
  
 | 
        #type-distribution { 
 | 
          flex: 0.4; 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
} 
 | 
  
 | 
  
 | 
.table-content { 
 | 
  width: 100%; 
 | 
  height: 397px; 
 | 
  // height: 361px; 
 | 
  // height: ; 
 | 
  padding: 20px; 
 | 
  box-sizing: border-box; 
 | 
  
 | 
  .table-head { 
 | 
    width: 100%; 
 | 
    height: 36px; 
 | 
    display: flex; 
 | 
    align-items: center; 
 | 
    background: rgba(52, 88, 159, 0.5); 
 | 
  
 | 
    .table-head_item { 
 | 
      flex: 1; 
 | 
      height: 100%; 
 | 
      display: flex; 
 | 
      align-items: center; 
 | 
      justify-content: center; 
 | 
      font-size: 13px; 
 | 
      font-weight: 500; 
 | 
      color: #01D9FE; 
 | 
  
 | 
    } 
 | 
  } 
 | 
  
 | 
  .tablel_container { 
 | 
    width: 100%; 
 | 
    // height: calc(100% - 36px); 
 | 
    height: 361px; 
 | 
  
 | 
    .scroll_container { 
 | 
      width: 100%; 
 | 
      height: 100%; 
 | 
      overflow: hidden; 
 | 
      color: white; 
 | 
  
 | 
      .scroll_item_bg1 { 
 | 
        background: rgba(52, 88, 159, 0.2); 
 | 
      } 
 | 
  
 | 
      .scroll_item_bg2 { 
 | 
        background: rgba(52, 88, 159, 0.5); 
 | 
      } 
 | 
  
 | 
      .scroll_item { 
 | 
        width: 100%; 
 | 
        height: 36px; 
 | 
        display: flex; 
 | 
        align-items: center; 
 | 
        justify-content: center; 
 | 
        display: flex; 
 | 
        align-items: center; 
 | 
        justify-content: space-between; 
 | 
  
 | 
        .scroll_item_row { 
 | 
          flex: 1; 
 | 
          display: flex; 
 | 
          align-items: center; 
 | 
          justify-content: center; 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
}</style> 
 |