Browse Source

feature/险峰项目大屏

dengrui 10 tháng trước cách đây
mục cha
commit
7dcd47f5e5

+ 1 - 0
package.json

@@ -41,6 +41,7 @@
   },
   "dependencies": {
     "@element-plus/icons-vue": "^2.3.1",
+    "@kjgl77/datav-vue3": "^1.7.3",
     "@smallwei/avue": "^3.3.3",
     "@types/smallwei__avue": "^3.0.5",
     "@vueup/vue-quill": "1.0.0-alpha.40",

+ 56 - 0
src/api/bigScreen/index.ts

@@ -0,0 +1,56 @@
+import request from "@/utils/request";
+//数据大屏接口
+//报故缺陷分布
+export function getFaultBug(data: string) {
+  return request({
+    url: "/api/v1/process/census/fault/bug",
+    method: "post",
+    data,
+  });
+}
+//报故统计
+export function getFaultCount(data: string) {
+  return request({
+    url: "/api/v1/process/census/fault/count",
+    method: "post",
+    data,
+  });
+}
+//报故处理跟踪
+export function getFaultTrack(data: string) {
+  return request({
+    url: "/api/v1/process/census/fault/track",
+    method: "post",
+    data,
+  });
+}
+//不合格品统计
+export function getCensusNonconforming(data: string) {
+  return request({
+    url: "/api/v1/process/census/nonconforming",
+    method: "post",
+    data,
+  });
+}
+//产品合格率
+export function getQualifiedRate(data: string) {
+  return request({
+    url: "/api/v1/process/census/qualified/rate",
+    method: "post",
+    data,
+  });
+}
+//工位任务分布
+export function getStationTaskInfo() {
+  return request({
+    url: "/api/v1/process/census/stationTaskInfo",
+    method: "post",
+  });
+}
+//下线情况
+export function getOffLineInfo() {
+  return request({
+    url: "/api/v1/process/census/productLineOffLineInfo",
+    method: "post",
+  });
+}

+ 2 - 1
src/main.ts

@@ -5,6 +5,7 @@ import print from "vue3-print-nb";
 import { setupStore } from "@/store";
 import { setupDirective } from "@/directive";
 import { setupElIcons, setupI18n, setupPermission } from "@/plugins";
+import DataVVue3 from "@kjgl77/datav-vue3";
 // 本地SVG图标
 import "virtual:svg-icons-register";
 
@@ -34,4 +35,4 @@ setupEleAvue(app);
 
 app.component("VueQrcode", VueQrcode);
 
-app.use(router).use(print).mount("#app");
+app.use(router).use(print).use(DataVVue3).mount("#app");

+ 201 - 7
src/views/report/statistics/screens/capacity/index.vue

@@ -1,15 +1,128 @@
 <template>
   <div class="screen-container">
-    <common-header title="工位任务分布" />
-    <div class="screen-content"></div>
+    <common-header title="产品下线情况" />
+    <div class="screen-content">
+      <div class="chartsCarouselBox itemBackgroud">
+        <div class="carouselHeader tableStyle">
+          <div class="a1 center1Text">产品名称</div>
+          <div class="a2 center1Text">今日下线</div>
+          <div class="a2 center1Text">总下线</div>
+          <div class="a2 center1Text">总需求数</div>
+          <div class="a2 center1Text">当前良率</div>
+          <div class="a2 center1Text">单批划分</div>
+          <div class="a2 center1Text">完成批数</div>
+          <div class="a2 center1Text">试验预约数</div>
+        </div>
+        <div class="carouselBody">
+          <TransitionGroup name="list" tag="ul">
+            <li
+              class="carouselItem tableStyle"
+              :key="item"
+              style="height: 9.6vh"
+              v-for="item in showDatas"
+            >
+              <div class="a1 infoBackgroud centerText textComent">
+                {{ item.materialName }}
+              </div>
+              <div class="a2 infoBackgroud centerText textComent">
+                {{ item.todayNum }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.allOffNum }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.orderNum }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.rate }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.batchNum }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.completeBatch }}
+              </div>
+              <div
+                class="a2 infoBackgroud centerText textComent"
+                style="font-weight: bolder"
+              >
+                {{ item.testNum }}
+              </div>
+            </li>
+          </TransitionGroup>
+        </div>
+      </div>
+    </div>
   </div>
 </template>
 
-<script lang="ts" setup>
+<script setup>
 import CommonHeader from "@/views/report/statistics/screens/common-header.vue";
+import { getOffLineInfo } from "@/api/bigScreen";
+const datas = ref([]);
+const borderRef = ref(null);
+const showDatas = ref([]);
+const interval1 = ref(null);
+const sum1 = ref(1);
+const setShowData1 = (num, time) => {
+  sum1.value = num;
+  if (datas.value.length > num) {
+    const dataA = JSON.parse(JSON.stringify(datas.value));
+    showDatas.value = dataA.splice(0, num);
+    interval1.value = setInterval(async () => {
+      await showDatas.value.push(datas.value[sum1.value % datas.value.length]);
+      showDatas.value.splice(0, 1);
+      sum1.value = sum1.value + 1;
+    }, time);
+  } else {
+    showDatas.value = datas.value;
+  }
+};
+const getListData = async () => {
+  const { data } = await getOffLineInfo();
+  datas.value = [...data, ...data, ...data];
+};
+onMounted(async () => {
+  borderRef.value?.initWH();
+  await getListData();
+  setShowData1(8, 3000);
+});
+onUnmounted(() => {
+  if (interval1.value) {
+    clearInterval(interval1.value);
+  }
+});
 </script>
 
 <style lang="scss" scoped>
+.list-move,
+.list-enter-active,
+.list-leave-active {
+  transition: all 0.5s ease;
+}
+.list-enter-from,
+.list-leave-to {
+  opacity: 0;
+  transform: translateY(-4.6vh);
+}
+.list-leave-active {
+  position: absolute;
+}
 .screen-container {
   width: 100vw;
   height: 100vh;
@@ -17,11 +130,92 @@ import CommonHeader from "@/views/report/statistics/screens/common-header.vue";
   background-size: cover;
   background-position: center;
 }
-
+.itemBackgroud {
+  background-color: rgba(0, 0, 0, 0.6);
+}
 .screen-content {
   width: 100vw;
-  height: calc(100vh - 96px - 18px);
-  margin-top: 18px;
-  border: 2px solid red;
+  height: 88vh;
+  margin-top: 2vh;
+  padding: 0 2vh;
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  position: relative;
+}
+.tableStyle {
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  .left {
+    width: 66%;
+  }
+  .middle {
+    width: 19%;
+  }
+  .right {
+    width: 13%;
+  }
+}
+.centerText {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 3vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  line-height: 9.6vh;
+  text-align: center;
+  padding: 0 1vh;
+}
+.center1Text {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 2vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 0.3vh;
+}
+.infoBackgroud {
+  background-color: rgba(255, 255, 255, 0.05);
+}
+.textComent {
+  white-space: nowrap; /* 不允许换行 */
+  overflow: hidden; /* 超出长度时隐藏 */
+  text-overflow: ellipsis; /* 超出部分显示省略号 */
+}
+.chartsCarouselBox {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  padding: 2vh;
+  .carouselHeader {
+    height: calc(3vh);
+    line-height: 3vh;
+    margin-bottom: 0.5vh;
+    .a1 {
+      width: 25vw;
+    }
+    .a2 {
+      width: 9.9vw;
+    }
+  }
+  .carouselBody {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+
+    .carouselItem {
+      margin-bottom: 0.5vh;
+      width: 96vw;
+      .a1 {
+        width: 25vw;
+        display: inline-block;
+      }
+      .a2 {
+        width: 9.9vw;
+      }
+    }
+  }
 }
 </style>

+ 5 - 6
src/views/report/statistics/screens/common-header.vue

@@ -15,13 +15,12 @@ defineProps({
 .screen-header {
   display: flex;
   justify-content: center;
-  align-items: end;
-  height: $screen-header-height;
-  padding-bottom: 15px;
-  font-weight: 500;
-  font-size: 49px;
+  align-items: center;
+  height: 8vh;
+  font-weight: 600;
+  font-size: 5.6vh;
   color: #ffffff;
-  line-height: 58px;
+  line-height: 5.8vh;
   background-image: url("@/assets/images/screen_header1.png");
   background-size: 100% 100%;
   background-position: center;

+ 549 - 5
src/views/report/statistics/screens/quality/index.vue

@@ -2,18 +2,425 @@
   <div class="screen-container">
     <common-header title="质量统计" />
     <div class="screen-content">
-      <TitleHeader :title="aaa" />
+      <div class="infoItem">
+        <div class="infoItemHeader itemBackgroud">
+          <TitleHeader title="报故统计" />
+          <div class="chartsBox">
+            <div id="charts1"></div>
+          </div>
+        </div>
+        <div class="infoItemBody itemBackgroud">
+          <TitleHeader title="报故缺陷项分布" />
+          <div class="chartsBox">
+            <div id="charts3"></div>
+          </div>
+        </div>
+      </div>
+      <div class="infoItem">
+        <div class="infoItemHeader itemBackgroud">
+          <TitleHeader title="不合格品统计" />
+          <div class="chartsBox">
+            <div id="charts2"></div>
+          </div>
+        </div>
+        <div class="infoItemBody itemBackgroud">
+          <TitleHeader title="报故处理跟踪" />
+          <div class="chartsCarouselBox">
+            <div class="carouselHeader tableStyle">
+              <div class="left center1Text">产品名称</div>
+              <div class="middle center1Text">状态</div>
+              <div class="right center1Text">报故数量</div>
+            </div>
+            <div class="carouselBody">
+              <TransitionGroup name="list" tag="ul">
+                <li
+                  class="carouselItem tableStyle"
+                  :key="item"
+                  style="height: 4.3vh"
+                  v-for="item in showData1"
+                >
+                  <div class="left infoBackgroud centerText textComent">
+                    {{ item.materialName }}
+                  </div>
+                  <div class="middle infoBackgroud centerText textComent">
+                    {{ item.currentState }}
+                  </div>
+                  <div
+                    class="right infoBackgroud centerText textComent"
+                    style="font-weight: bolder"
+                  >
+                    {{ item.unqualifiedNum }}
+                  </div>
+                </li>
+              </TransitionGroup>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div
+        class="infoItem itemBackgroud"
+        style="justify-content: flex-start; padding: 0.8vw"
+      >
+        <TitleHeader title="产品合格率" />
+        <div class="chartsCarouselBox">
+          <div class="carouselBody" style="padding: 2vh 0">
+            <TransitionGroup name="list" tag="ul">
+              <li
+                class="carouselItem table1Style"
+                :key="item"
+                v-for="item in showData2"
+                style="height: 8vh"
+              >
+                <div class="left infoBackgroud centerText">
+                  <div class="line">
+                    <div class="box">
+                      <div class="box1"></div>
+                    </div>
+                    <div class="titleTextBox textComent">
+                      {{ item.materialName }}
+                    </div>
+                  </div>
+                  <div class="line">
+                    <div class="title1TextBox textComent">
+                      {{ item.materialModel }}
+                    </div>
+                  </div>
+                </div>
+                <div class="middle infoBackgroud centerText textComent">
+                  {{ item.rate }}
+                </div>
+              </li>
+            </TransitionGroup>
+          </div>
+        </div>
+      </div>
     </div>
   </div>
 </template>
 
-<script lang="ts" setup>
+<script setup>
 import CommonHeader from "@/views/report/statistics/screens/common-header.vue";
 import TitleHeader from "../titleHeader.vue";
-const aaa = ref("你在构建什打无无大武当");
+import {
+  getFaultBug,
+  getFaultCount,
+  getFaultTrack,
+  getCensusNonconforming,
+  getQualifiedRate,
+} from "@/api/bigScreen";
+import * as echarts from "echarts";
+const charts1 = shallowRef(null);
+const charts2 = shallowRef(null);
+const charts3 = shallowRef(null);
+//存放接口数据
+//报故统计
+const chartsData1 = ref({});
+//不合格品统计
+const chartsData2 = ref([]);
+//报故缺陷分布
+const chartsData3 = ref({});
+//报故处理跟踪
+const data1 = ref([]);
+const showData1 = ref([]);
+const sum1 = ref(1);
+const interval1 = ref(null);
+const setShowData1 = (num, time) => {
+  sum1.value = num;
+  if (data1.value.length > num) {
+    const dataA = JSON.parse(JSON.stringify(data1.value));
+    showData1.value = dataA.splice(0, num);
+    interval1.value = setInterval(async () => {
+      await showData1.value.push(data1.value[sum1.value % data1.value.length]);
+      showData1.value.splice(0, 1);
+      sum1.value = sum1.value + 1;
+    }, time);
+  } else {
+    showData1.value = data1.value;
+  }
+};
+//产品合格率
+const data2 = ref([]);
+const showData2 = ref([]);
+const sum2 = ref(1);
+const interval2 = ref(null);
+const fontSize = ref(0);
+const setFontSize = () => {
+  fontSize.value = (window.innerHeight / 100) * 1.55;
+};
+const setShowData2 = (num, time) => {
+  sum2.value = num;
+  if (data2.value.length > num) {
+    const dataA = JSON.parse(JSON.stringify(data2.value));
+    showData2.value = dataA.splice(0, num);
+    interval2.value = setInterval(async () => {
+      await showData2.value.push(data2.value[sum2.value % data2.value.length]);
+      showData2.value.splice(0, 1);
+      sum2.value = sum2.value + 1;
+    }, time);
+  } else {
+    showData2.value = data2.value;
+  }
+};
+const getData1 = async () => {
+  //报故缺陷项分布
+  const { data } = await getFaultBug();
+  chartsData3.value = data;
+};
+const getData2 = async () => {
+  //报故统计
+  const { data } = await getFaultCount();
+  chartsData1.value = data;
+};
+const getData3 = async () => {
+  //报故处理跟踪
+  const { data } = await getFaultTrack();
+  data1.value = data;
+  setShowData1(9, 2500);
+};
+const getData4 = async () => {
+  //不合格品统计
+  const { data } = await getCensusNonconforming();
+  chartsData2.value = data;
+};
+const getData5 = async () => {
+  //产品合格率
+  const { data } = await getQualifiedRate();
+  data2.value = data;
+  setShowData2(8, 4000);
+};
+const getData = async () => {
+  await getData1();
+  await getData2();
+  await getData3();
+  await getData4();
+  await getData5();
+};
+const option1 = {
+  xAxis: {
+    type: "category",
+    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  grid: {
+    left: "8%",
+    right: "3%",
+    top: "10%",
+    bottom: "10%",
+  },
+  yAxis: {
+    type: "value",
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  series: [
+    {
+      data: [820, 932, 901, 934, 1290, 1330, 1320],
+      type: "line",
+      symbol: "none",
+      itemStyle: {
+        color: "#BCB62E80",
+      },
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {
+            offset: 0,
+            color: "#BCB62E80",
+          },
+          {
+            offset: 1,
+            color: "#BCB62E20",
+          },
+        ]),
+      },
+    },
+  ],
+  textStyle: {
+    fontSize: 999,
+  },
+};
+
+const option2 = {
+  xAxis: {
+    type: "category",
+    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  grid: {
+    left: "8%",
+    right: "3%",
+    top: "10%",
+    bottom: "10%",
+  },
+  yAxis: {
+    type: "value",
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  textStyle: {
+    fontSize: 999,
+  },
+  series: [
+    {
+      data: [820, 932, 901, 934, 1290, 0, 700],
+      type: "line",
+      symbol: "none",
+      itemStyle: {
+        color: "#D7565680",
+      },
+
+      areaStyle: {
+        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+          {
+            offset: 0,
+            color: "#D7565680",
+          },
+          {
+            offset: 1,
+            color: "#D7565620",
+          },
+        ]),
+      },
+    },
+  ],
+};
+const option3 = {
+  textStyle: {
+    fontSize: 99,
+  },
+  yAxis: {
+    type: "category",
+    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  grid: {
+    left: "18%",
+    right: "7%",
+    top: "10%",
+    bottom: "10%",
+  },
+  xAxis: {
+    type: "value",
+    axisLabel: {
+      fontSize: 12,
+    },
+  },
+  series: [
+    {
+      data: [120, 200, 150, 80, 70, 110, 130],
+      type: "bar",
+      itemStyle: {
+        color: "#daf4ff",
+      },
+      barWidth: "15%",
+    },
+  ],
+};
+const setChart3Option = () => {
+  const op3 = { ...option3 };
+  if (chartsData3.value && charts3.value) {
+    op3.series[0].data = chartsData3.value.countList;
+    op3.yAxis.data = chartsData3.value.bugNameList;
+    op3.yAxis.axisLabel.fontSize = fontSize.value;
+    op3.xAxis.axisLabel.fontSize = fontSize.value;
+    charts3.value.setOption(op3, true);
+  }
+};
+const setChart2Option = () => {
+  const op2 = { ...option2 };
+  if (chartsData1.value && charts1.value) {
+    op2.series[0].data = chartsData1.value.countList;
+    op2.xAxis.data = chartsData1.value.monthList;
+    op2.yAxis.axisLabel.fontSize = fontSize.value;
+    op2.xAxis.axisLabel.fontSize = fontSize.value;
+    charts1.value.setOption(op2, true);
+  }
+};
+const setChart1Option = () => {
+  const op1 = { ...option1 };
+  if (chartsData2.value && charts2.value) {
+    op1.series[0].data = chartsData2.value.countList;
+    op1.xAxis.data = chartsData2.value.monthList;
+    op1.yAxis.axisLabel.fontSize = fontSize.value;
+    op1.xAxis.axisLabel.fontSize = fontSize.value;
+    charts2.value.setOption(op1, true);
+  }
+};
+onMounted(async () => {
+  setFontSize();
+  charts1.value = echarts.init(document.getElementById("charts1"));
+  charts2.value = echarts.init(document.getElementById("charts2"));
+  charts3.value = echarts.init(document.getElementById("charts3"));
+  await getData();
+});
+onUnmounted(() => {
+  if (interval1.value) {
+    clearInterval(interval1.value);
+  }
+  if (interval2.value) {
+    clearInterval(interval2.value);
+  }
+});
+watch(
+  [() => chartsData3.value, () => chartsData1.value, () => chartsData2.value],
+  () => {
+    setChart3Option();
+    setChart2Option();
+    setChart1Option();
+  },
+  { deep: true }
+);
 </script>
 
 <style lang="scss" scoped>
+#charts1 {
+  width: 100%;
+  height: 100%;
+  transform-origin: center center; /* 设置变换的原点为元素中心 */
+  position: absolute;
+}
+#charts2 {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+}
+#charts3 {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  transform-origin: center center; /* 设置变换的原点为元素中心 */
+  transform: scale(1.1); /* 放大1.5倍 */
+}
+.list-move,
+.list-enter-active,
+.list-leave-active {
+  transition: all 0.5s ease;
+}
+.list-enter-from,
+.list-leave-to {
+  opacity: 0;
+  transform: translateY(-4.6vh);
+}
+.list-leave-active {
+  position: absolute;
+}
+.list1-leave-active {
+  transition: all 0.5s ease;
+}
+.list1-leave-to {
+  opacity: 0;
+  transform: translateY(-8vh);
+}
+.list1-leave-active {
+  position: absolute;
+}
 .screen-container {
   width: 100vw;
   height: 100vh;
@@ -21,11 +428,148 @@ const aaa = ref("你在构建什打无无大武当");
   background-size: cover;
   background-position: center;
 }
-
+.itemBackgroud {
+  background-color: rgba(0, 0, 0, 0.6);
+}
+.infoBackgroud {
+  background-color: rgba(255, 255, 255, 0.05);
+}
 .screen-content {
   width: 100vw;
   height: calc(100vh - 96px - 18px);
   margin-top: 18px;
-  border: 2px solid red;
+  display: flex;
+  justify-content: space-evenly;
+  .infoItem {
+    width: 31vw;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    .infoItemHeader {
+      height: 36%;
+      display: flex;
+      flex-direction: column;
+      padding: 0.8vw;
+      width: 100%;
+      .chartsBox {
+        flex: 1;
+        position: relative;
+      }
+    }
+    .infoItemBody {
+      width: 100%;
+      height: 60%;
+      display: flex;
+      flex-direction: column;
+      padding: 0.8vw;
+      .chartsBox {
+        flex: 1;
+        position: relative;
+      }
+    }
+  }
+}
+.chartsCarouselBox {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  .carouselHeader {
+    height: calc(2vh);
+    line-height: 2vh;
+    margin-bottom: 0.5vh;
+  }
+  .carouselBody {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    .carouselItem {
+      margin-bottom: 0.5vh;
+      width: calc(31vw - 1.6vw);
+    }
+  }
+}
+.centerText {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 1.8vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 0.3vh;
+}
+.center1Text {
+  color: rgba(255, 255, 255, 0.8);
+  font-size: 1.4vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 0.3vh;
+}
+.tableStyle {
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  .left {
+    width: 66%;
+  }
+  .middle {
+    width: 19%;
+  }
+  .right {
+    width: 13%;
+  }
+}
+.table1Style {
+  display: flex;
+  justify-content: space-between;
+  width: 100%;
+  margin-bottom: 2vh !important;
+  .left {
+    width: calc(80% - 0.5vh);
+    padding: 1vh 2vh 1vh 3vh;
+    display: flex;
+    flex-direction: column;
+    .line {
+      width: 100%;
+      flex: 1;
+      display: flex;
+      align-items: center;
+      .box {
+        height: 1.8vh;
+        width: 1.8vh;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background-color: rgba(255, 255, 255, 0.1);
+        .box1 {
+          height: 0.8vh;
+          width: 0.8vh;
+          background-color: rgba(255, 255, 255, 1);
+        }
+      }
+      .titleTextBox {
+        font-size: 2vh;
+        color: white;
+        font-weight: bold;
+        flex: 1;
+        margin-left: 0.5vh;
+      }
+      .title1TextBox {
+        font-size: 1.4vh;
+        color: #ffffff60;
+        flex: 1;
+        margin-left: calc(1.8vh + 2px);
+      }
+    }
+  }
+  .middle {
+    width: 20%;
+  }
+}
+.textComent {
+  white-space: nowrap; /* 不允许换行 */
+  overflow: hidden; /* 超出长度时隐藏 */
+  text-overflow: ellipsis; /* 超出部分显示省略号 */
 }
 </style>

+ 288 - 64
src/views/report/statistics/screens/tasks/index.vue

@@ -1,78 +1,296 @@
 <template>
-  <v-scale-screen height="100%" width="100%">
-    <div class="screen-container">
-      <common-header title="工位任务分布" />
-      <div class="screen-content">
-        <div v-for="(item, index) in data" :key="index" class="grid-item">
-          <title-header title="入库检料" />
-          <div class="grid-bottom">
-            <div class="left-info">
-              <div
-                class="box"
-                style="
-                  display: flex;
-                  flex-direction: column;
-                  justify-content: center;
-                "
-              >
-                <div class="title">工位名称</div>
-                <div class="code">工位代码</div>
-              </div>
-              <div class="box">
-                <div>
-                  <span class="com-num">完成数量/</span>
-                  <span class="plan-num">计划数量</span>
-                </div>
-                <div class="desc">任务描述</div>
+  <div class="screen-container">
+    <common-header title="工位任务分布" />
+    <TransitionGroup name="list" tag="ul" class="screen-content">
+      <li v-for="(item, index) in showdatas" :key="item" class="grid-item">
+        <title-header :title="item.stationName" />
+        <div class="grid-bottom">
+          <div class="left-info">
+            <div
+              class="box"
+              style="
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+              "
+            >
+              <div class="title">{{ item.materialName }}</div>
+              <div class="code">{{ item.materialModel }}</div>
+            </div>
+            <div class="box">
+              <div style="display: flex; align-items: center">
+                <!-- <span class="com-num">{{ item.num }}</span> -->
+                <dv-digital-flop
+                  :config="completeNumConfigs[index]"
+                  class="flop"
+                />
+                <span class="plan-num">/</span>
+                <dv-digital-flop :config="taskNumConfigs[index]" class="flop" />
               </div>
+              <div class="desc">完成数量 / 计划数量</div>
             </div>
-            <div class="right-chart">dd</div>
+          </div>
+          <div class="right-chart">
+            <dv-water-level-pond
+              :config="{
+                data: [setPondNumber(item.rate)],
+                shape: 'round',
+              }"
+              :key="sum1"
+              style="width: 16vh; height: 16vh"
+            />
           </div>
         </div>
-      </div>
-    </div>
-  </v-scale-screen>
+      </li>
+    </TransitionGroup>
+  </div>
 </template>
 
-<script lang="ts" setup>
+<script setup>
 import CommonHeader from "@/views/report/statistics/screens/common-header.vue";
 import TitleHeader from "@/views/report/statistics/screens/titleHeader.vue";
-import VScaleScreen from "v-scale-screen";
+import { getStationTaskInfo } from "@/api/bigScreen";
+const fontSize = ref(0);
+
+const setPondNumber = (str) => {
+  const number = Number(str).toFixed(2);
+  if (number == 1) {
+    return 100;
+  } else {
+    let str = number.toString(); // "0.18"
+    let truncated = parseInt(
+      str.substring(str.indexOf(".") + 1, str.indexOf(".") + 3)
+    );
+    return truncated;
+  }
+};
 
-const data = ref([{}, {}, {}, {}, {}, {}, {}, {}]);
+const setFontSize = () => {
+  fontSize.value = (window.innerHeight / 100) * 4;
+};
+const datas = ref([]);
+const showdatas = ref([]);
+const getData = async () => {
+  const { data } = await getStationTaskInfo();
+  datas.value = [...data, ...data];
+};
+const interval1 = ref(null);
+const sum1 = ref(1);
+const setShowDatas = async (time, num) => {
+  if (datas.value.length > 9) {
+    sum1.value = num;
+    const dataA = JSON.parse(JSON.stringify(datas.value));
+    showdatas.value = dataA.splice(0, num);
+    setNumber(2000);
+    interval1.value = setInterval(async () => {
+      await showdatas.value.push(datas.value[sum1.value % datas.value.length]);
+      showdatas.value.splice(0, 1);
+      setNumber(0);
+      sum1.value = sum1.value + 1;
+    }, time);
+  } else {
+    showdatas.value = datas.value.value;
+  }
+};
+const completeNumConfigs = ref([
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+    },
+  },
+]);
+
+const taskNumConfigs = ref([
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+  {
+    number: [0],
+    style: {
+      fontSize: fontSize,
+      fill: "#ffffff",
+    },
+  },
+]);
+const setTimeOutFnc = (array, num, time) => {
+  setTimeout(() => {
+    array.number = [num];
+  }, time);
+};
+const setNumber = (time) => {
+  showdatas.value.forEach((item, index) => {
+    setTimeOutFnc(completeNumConfigs.value[index], item.completeNum, time);
+    setTimeOutFnc(taskNumConfigs.value[index], item.taskNum, time);
+  });
+};
+onUnmounted(() => {
+  if (interval1.value) {
+    clearInterval(interval1.value);
+  }
+});
+onMounted(async () => {
+  setFontSize();
+  await getData();
+  setShowDatas(10000, 9);
+});
 </script>
 
 <style lang="scss" scoped>
+.list-move,
+.list-enter-active {
+  transition: all 2s ease;
+}
+.list-leave-active {
+  transition: all 2s ease;
+}
+.list-enter-from {
+  transform: translateX(40vw);
+}
+.list-leave-to {
+  opacity: 0;
+  height: 0;
+  transform: translateX(-40vw);
+}
+.list-leave-active {
+  position: absolute;
+}
+:deep(.dv-water-pond-level) {
+  text {
+    font-size: 4vh;
+  }
+}
 .screen-container {
-  width: 100%;
-  min-width: 1620px;
+  width: 100vw;
   height: 100vh;
   background-image: url("@/assets/images/screen_bg_task.png");
   background-size: cover;
   background-position: center;
+  overflow: hidden;
+}
+.flop {
+  width: 10vh;
+  height: 6vh;
+  display: block;
+  font-size: 4vh;
 }
-
 .screen-content {
-  width: 100%;
-  //height: 100%;
-  height: calc(100% - $screen-header-height - 18px);
-  margin-top: 18px;
-  padding: 0 32px;
-
-  display: grid;
-  grid-template-columns: repeat(3, 1fr);
-  grid-template-rows: repeat(3, 1fr);
-  gap: 25px;
-
-  overflow-y: auto;
-
+  height: 88vh;
+  margin-top: 2vh;
+  padding: 0 2vh;
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
   .grid-item {
     height: 100%;
     display: flex;
     flex-direction: column;
     background: rgba(0, 0, 0, 0.5);
-    border-radius: 8px 8px 8px 8px;
-    padding: 16px;
+    border-radius: 2vh;
+    padding: 2vh;
+    width: 31vw;
+    height: 25vh;
 
     .grid-bottom {
       display: flex;
@@ -85,46 +303,53 @@ const data = ref([{}, {}, {}, {}, {}, {}, {}, {}]);
         flex-direction: column;
         justify-content: space-between;
         align-items: start;
-        padding: 0px 18px;
+        padding: 0px 1vh;
         height: 100%;
-        width: 60%;
+        width: 65%;
 
         .box {
           height: 50%;
+          width: 100%;
         }
 
         .title {
           font-weight: 500;
-          font-size: 24px;
+          font-size: 3vh;
           color: #ffffff;
-          line-height: 20px;
+          line-height: 3vh;
+          width: 100%;
+          display: block;
+          white-space: nowrap; /* 不允许换行 */
+          overflow: hidden; /* 超出长度时隐藏 */
+          text-overflow: ellipsis; /* 超出部分显示省略号 */
         }
 
         .code {
           font-weight: 400;
-          font-size: 17px;
-          color: #fff8;
-          line-height: 17px;
-          margin-top: 12px;
+          font-size: 2vh;
+          color: #fff9;
+          line-height: 2vh;
+          margin-top: 1vh;
         }
 
         .com-num {
           font-weight: 500;
-          font-size: 30px;
+          font-size: 2vh;
           color: #55d1aa;
         }
 
         .plan-num {
           font-weight: 500;
-          font-size: 30px;
+          font-size: 4vh;
           color: #fff;
         }
 
         .desc {
           font-weight: 400;
-          font-size: 16px;
+          font-size: 2vh;
           color: #ffffff;
-          line-height: 17px;
+          line-height: 2vh;
+          padding-left: 1.4vh;
         }
       }
 
@@ -132,9 +357,8 @@ const data = ref([{}, {}, {}, {}, {}, {}, {}, {}]);
         display: flex;
         justify-content: center;
         align-items: center;
-        padding-right: 28px;
         height: 100%;
-        flex: 1;
+        width: 35%;
       }
     }
   }