保存
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/views/copilot/efficiency/assets/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/views/copilot/efficiency/assets/icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.0 KiB  | 
							
								
								
									
										38
									
								
								src/views/copilot/efficiency/components/BipvOutput.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/views/copilot/efficiency/components/BipvOutput.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: BipvOutput.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <DoubleRingWrapperVue data-source="BIPV产出" :period="period" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import DoubleRingWrapperVue from "./sub/ring/DoubleRingWrapper.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "BipvOutput",
 | 
			
		||||
  components: { DoubleRingWrapperVue },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.flex-1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stretch {
 | 
			
		||||
  align-self: stretch;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										106
									
								
								src/views/copilot/efficiency/components/ChipInvest.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/views/copilot/efficiency/components/ChipInvest.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: FtoInvest.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-10 08:59:28
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <BarChartBase
 | 
			
		||||
    :legend="legend"
 | 
			
		||||
    :series="series"
 | 
			
		||||
    :xAxis="xAxis"
 | 
			
		||||
    in="ChipInvest"
 | 
			
		||||
    class="chip-invest-chart"
 | 
			
		||||
  />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import BarChartBase from "./sub/bar/BarChartBase.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "ChipInvest",
 | 
			
		||||
  components: { BarChartBase },
 | 
			
		||||
  data() {
 | 
			
		||||
    // 城市数组的顺序必须是固定的
 | 
			
		||||
    const cities = ["瑞昌", "邯郸", "株洲", "佳木斯", "成都", "凯盛", "蚌埠"];
 | 
			
		||||
    return {
 | 
			
		||||
      xAxis: cities,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    legend() {
 | 
			
		||||
      switch (this.period) {
 | 
			
		||||
        case "日":
 | 
			
		||||
          return [{ label: "昨日", color: "#12f7f1" }];
 | 
			
		||||
        case "周":
 | 
			
		||||
          return [{ label: "本周", color: "#12f7f1" }];
 | 
			
		||||
        case "月": {
 | 
			
		||||
          const year = new Date().getFullYear();
 | 
			
		||||
          const month = new Date().getMonth() + 1;
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年${month}月`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年${month}月`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
        }
 | 
			
		||||
        case "年": {
 | 
			
		||||
          const year = new Date().getFullYear();
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    series() {
 | 
			
		||||
      const { chipInvest } = this.$store.getters.copilot.yield;
 | 
			
		||||
      let dataList = null;
 | 
			
		||||
      switch (this.period) {
 | 
			
		||||
        case "日":
 | 
			
		||||
        case "周":
 | 
			
		||||
          dataList = chipInvest?.current;
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          dataList = [];
 | 
			
		||||
          dataList[0] = chipInvest?.pervious;
 | 
			
		||||
          dataList[1] = chipInvest?.current;
 | 
			
		||||
      }
 | 
			
		||||
      return getTemplate(this.period, dataList);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getTemplate(period, dataList) {
 | 
			
		||||
  const year = new Date().getFullYear();
 | 
			
		||||
  const month = new Date().getMonth() + 1;
 | 
			
		||||
  return period == "日" || period == "周"
 | 
			
		||||
    ? [
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "日" ? "昨日" : "本周",
 | 
			
		||||
          data: dataList ?? [],
 | 
			
		||||
        },
 | 
			
		||||
      ]
 | 
			
		||||
    : [
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "年" ? `${year - 1}年` : `${year - 1}年${month}月`,
 | 
			
		||||
          data: dataList ? dataList[0] : [],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "年" ? `${year}年` : `${year}年${month}月`,
 | 
			
		||||
          data: dataList ? dataList[1] : [],
 | 
			
		||||
          // : Array.from({ length: 7 }, () => Math.floor(Math.random() * 1000)),
 | 
			
		||||
        },
 | 
			
		||||
      ];
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										38
									
								
								src/views/copilot/efficiency/components/ChipOutput.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/views/copilot/efficiency/components/ChipOutput.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: ChipOutput.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <DoubleRingWrapperVue data-source="芯片产出" :period="period" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import DoubleRingWrapperVue from "./sub/ring/DoubleRingWrapper.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "ChipOutput",
 | 
			
		||||
  components: { DoubleRingWrapperVue },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.flex-1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stretch {
 | 
			
		||||
  align-self: stretch;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										108
									
								
								src/views/copilot/efficiency/components/FtoInvest.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/views/copilot/efficiency/components/FtoInvest.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: FtoInvest.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-10 08:59:28
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <BarChartBase
 | 
			
		||||
    :legend="legend"
 | 
			
		||||
    :series="series"
 | 
			
		||||
    :xAxis="xAxis"
 | 
			
		||||
    in="ftoInvest"
 | 
			
		||||
    class="fto-chart"
 | 
			
		||||
  />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import BarChartBase from "./sub/bar/BarChartBase.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "FtoInvest",
 | 
			
		||||
  components: { BarChartBase },
 | 
			
		||||
  data() {
 | 
			
		||||
    // 城市数组的顺序必须是固定的
 | 
			
		||||
    const cities = ["瑞昌", "邯郸", "株洲", "佳木斯", "成都", "凯盛", "蚌埠"];
 | 
			
		||||
    return {
 | 
			
		||||
      xAxis: cities,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    legend() {
 | 
			
		||||
      switch (this.period) {
 | 
			
		||||
        case "日":
 | 
			
		||||
          return [{ label: "昨日", color: "#12f7f1" }];
 | 
			
		||||
        case "周":
 | 
			
		||||
          return [{ label: "本周", color: "#12f7f1" }];
 | 
			
		||||
        case "月": {
 | 
			
		||||
          const year = new Date().getFullYear();
 | 
			
		||||
          const month = new Date().getMonth() + 1;
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年${month}月`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年${month}月`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
        }
 | 
			
		||||
        case "年": {
 | 
			
		||||
          const year = new Date().getFullYear();
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
        }
 | 
			
		||||
        default:
 | 
			
		||||
          return [
 | 
			
		||||
            { label: `${year - 1}年`, color: "#12f7f1" },
 | 
			
		||||
            { label: `${year}年`, color: "#58adfa" },
 | 
			
		||||
          ];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    series() {
 | 
			
		||||
      const { ftoInvest } = this.$store.getters.copilot.yield;
 | 
			
		||||
      let dataList = null;
 | 
			
		||||
 | 
			
		||||
      switch (this.period) {
 | 
			
		||||
        case "日":
 | 
			
		||||
        case "周":
 | 
			
		||||
          dataList = ftoInvest?.current;
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          dataList = [];
 | 
			
		||||
          dataList[0] = ftoInvest?.pervious;
 | 
			
		||||
          dataList[1] = ftoInvest?.current;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return getTemplate(this.period, dataList);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getTemplate(period, dataList) {
 | 
			
		||||
  const year = new Date().getFullYear();
 | 
			
		||||
  const month = new Date().getMonth() + 1;
 | 
			
		||||
  return period == "日" || period == "周"
 | 
			
		||||
    ? [
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "日" ? "昨日" : "本周",
 | 
			
		||||
          data: dataList ?? [],
 | 
			
		||||
        },
 | 
			
		||||
      ]
 | 
			
		||||
    : [
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "年" ? `${year - 1}年` : `${year - 1}年${month}月`,
 | 
			
		||||
          data: dataList ? dataList[0] : [],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: period == "年" ? `${year}年` : `${year}年${month}月`,
 | 
			
		||||
          data: dataList ? dataList[1] : [],
 | 
			
		||||
          // : Array.from({ length: 7 }, () => Math.floor(Math.random() * 1000)),
 | 
			
		||||
        },
 | 
			
		||||
      ];
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										38
									
								
								src/views/copilot/efficiency/components/StdOutput.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/views/copilot/efficiency/components/StdOutput.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: StdOutput.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <DoubleRingWrapperVue data-source="标准组件产出" :period="period" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import DoubleRingWrapperVue from "./sub/ring/DoubleRingWrapper.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "StdOutput",
 | 
			
		||||
  components: { DoubleRingWrapperVue },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.flex-1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stretch {
 | 
			
		||||
  align-self: stretch;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										257
									
								
								src/views/copilot/efficiency/components/sub/bar/BarChartBase.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/views/copilot/efficiency/components/sub/bar/BarChartBase.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: BarChartBase.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-10 08:59:28
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <chart-container class="bar-chart-base">
 | 
			
		||||
    <div class="legend">
 | 
			
		||||
      <span
 | 
			
		||||
        v-for="item in legend"
 | 
			
		||||
        :key="item.label"
 | 
			
		||||
        class="legend-item"
 | 
			
		||||
        :style="{ fontSize: isFullscreen ? '0.58vw' : '0.54vw' }"
 | 
			
		||||
        >{{ item.label }}</span
 | 
			
		||||
      >
 | 
			
		||||
    </div>
 | 
			
		||||
    <div
 | 
			
		||||
      ref="chart"
 | 
			
		||||
      style="max-width: 50vw"
 | 
			
		||||
      :style="{ height: vHeight + 'vh' }"
 | 
			
		||||
    ></div>
 | 
			
		||||
  </chart-container>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import screenfull from "screenfull";
 | 
			
		||||
import ChartContainer from "../../../../components/ChartContainer.vue";
 | 
			
		||||
import chartMixin from "@/mixins/chart.js";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "BarChartBase",
 | 
			
		||||
  components: {
 | 
			
		||||
    ChartContainer,
 | 
			
		||||
  },
 | 
			
		||||
  mixins: [chartMixin],
 | 
			
		||||
  props: {
 | 
			
		||||
    vHeight: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: 34,
 | 
			
		||||
    },
 | 
			
		||||
    legend: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    xAxis: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    series: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    in: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      isFullscreen: false,
 | 
			
		||||
      actualOptions: null,
 | 
			
		||||
      options: {
 | 
			
		||||
        grid: {
 | 
			
		||||
          left: "5%",
 | 
			
		||||
          right: "4%",
 | 
			
		||||
          bottom: "3%",
 | 
			
		||||
          top: "15%",
 | 
			
		||||
          containLabel: true,
 | 
			
		||||
        },
 | 
			
		||||
        tooltip: {},
 | 
			
		||||
        xAxis: {
 | 
			
		||||
          axisTick: {
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
          axisLine: {
 | 
			
		||||
            lineStyle: {
 | 
			
		||||
              color: "#4561AE",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          axisLabel: {
 | 
			
		||||
            color: "#fff",
 | 
			
		||||
            fontSize: 12,
 | 
			
		||||
          },
 | 
			
		||||
          data: this.xAxis,
 | 
			
		||||
        },
 | 
			
		||||
        yAxis: {
 | 
			
		||||
          name: "单位/片",
 | 
			
		||||
          nameTextStyle: {
 | 
			
		||||
            color: "#fff",
 | 
			
		||||
            fontSize: 12,
 | 
			
		||||
          },
 | 
			
		||||
          axisTick: {
 | 
			
		||||
            show: false,
 | 
			
		||||
          },
 | 
			
		||||
          axisLabel: {
 | 
			
		||||
            color: "#fff",
 | 
			
		||||
            fontSize: 12,
 | 
			
		||||
          },
 | 
			
		||||
          axisLine: {
 | 
			
		||||
            show: true,
 | 
			
		||||
            lineStyle: {
 | 
			
		||||
              color: "#4561AE",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          splitLine: {
 | 
			
		||||
            lineStyle: {
 | 
			
		||||
              color: "#4561AE",
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        series: [
 | 
			
		||||
          {
 | 
			
		||||
            name: "", // this.series[0].name,
 | 
			
		||||
            type: "bar",
 | 
			
		||||
            barWidth: 12,
 | 
			
		||||
            itemStyle: {
 | 
			
		||||
              borderRadius: [10, 10, 0, 0],
 | 
			
		||||
              color: {
 | 
			
		||||
                type: "linear",
 | 
			
		||||
                x: 0,
 | 
			
		||||
                y: 0,
 | 
			
		||||
                x2: 0,
 | 
			
		||||
                y2: 1,
 | 
			
		||||
                colorStops: [
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 0,
 | 
			
		||||
                    color: "#12f7f1", // 0% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 0.35,
 | 
			
		||||
                    color: "#12f7f177", // 100% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 0.75,
 | 
			
		||||
                    color: "#12f7f133", // 100% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 1,
 | 
			
		||||
                    color: "transparent", // 100% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                ],
 | 
			
		||||
                global: false, // 缺省为 false
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            data: [], // this.series[0].data,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: "", // this.series[1].name,
 | 
			
		||||
            type: "bar",
 | 
			
		||||
            barWidth: 12,
 | 
			
		||||
            // tooltip: {
 | 
			
		||||
            //   valueFormatter: function (value) {
 | 
			
		||||
            //     return value + " ml";
 | 
			
		||||
            //   },
 | 
			
		||||
            // },
 | 
			
		||||
            itemStyle: {
 | 
			
		||||
              borderRadius: [10, 10, 0, 0],
 | 
			
		||||
              color: {
 | 
			
		||||
                type: "linear",
 | 
			
		||||
                x: 0,
 | 
			
		||||
                y: 0,
 | 
			
		||||
                x2: 0,
 | 
			
		||||
                y2: 1,
 | 
			
		||||
                colorStops: [
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 0,
 | 
			
		||||
                    color: "#57abf8", // 0% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    offset: 1,
 | 
			
		||||
                    color: "#364BFE66", // 100% 处的颜色
 | 
			
		||||
                  },
 | 
			
		||||
                ],
 | 
			
		||||
                global: false, // 缺省为 false
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            data: [], // this.series[1].data,
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    /** 全屏状态切换时,对柱子粗细和字体大小进行相应调整 */
 | 
			
		||||
    isFullscreen(val) {
 | 
			
		||||
      this.actualOptions.series.map((item) => {
 | 
			
		||||
        item.barWidth = val ? 18 : 12;
 | 
			
		||||
      });
 | 
			
		||||
      this.actualOptions.xAxis.axisLabel.fontSize = val ? 18 : 12;
 | 
			
		||||
      this.actualOptions.yAxis.axisLabel.fontSize = val ? 18 : 12;
 | 
			
		||||
      this.actualOptions.yAxis.nameTextStyle.fontSize = val ? 18 : 12;
 | 
			
		||||
      this.initOptions(this.actualOptions);
 | 
			
		||||
    },
 | 
			
		||||
    series(val) {
 | 
			
		||||
      if (!val) {
 | 
			
		||||
        this.initOptions(this.options);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const actualOptions = JSON.parse(JSON.stringify(this.options));
 | 
			
		||||
      actualOptions.series[0].data = val[0].data;
 | 
			
		||||
      actualOptions.series[0].name = val[0].name;
 | 
			
		||||
      actualOptions.series[1].data = val?.[1]?.data || [];
 | 
			
		||||
      actualOptions.series[1].name = val?.[1]?.name || "";
 | 
			
		||||
      this.actualOptions = actualOptions;
 | 
			
		||||
      this.initOptions(actualOptions);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.actualOptions = this.options;
 | 
			
		||||
    this.initOptions(this.options);
 | 
			
		||||
 | 
			
		||||
    if (screenfull.isEnabled) {
 | 
			
		||||
      screenfull.on("change", () => {
 | 
			
		||||
        this.isFullscreen = screenfull.isFullscreen;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.bar-chart-base {
 | 
			
		||||
  // position: relative;
 | 
			
		||||
 | 
			
		||||
  .legend {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 5.2vh;
 | 
			
		||||
    right: 1vw;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .legend-item {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    // font-size: 12px;
 | 
			
		||||
    margin-right: 0.67vw;
 | 
			
		||||
 | 
			
		||||
    &::before {
 | 
			
		||||
      content: "";
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 0.531vw;
 | 
			
		||||
      height: 0.531vw;
 | 
			
		||||
      background-color: #ccc;
 | 
			
		||||
      border-radius: 2px;
 | 
			
		||||
      margin-right: 0.22vw;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .legend-item:nth-child(1):before {
 | 
			
		||||
    background-color: #12f7f1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .legend-item:nth-child(2):before {
 | 
			
		||||
    background-color: #58adfa;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										149
									
								
								src/views/copilot/efficiency/components/sub/city/CityData.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								src/views/copilot/efficiency/components/sub/city/CityData.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: CityData.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="city-data">
 | 
			
		||||
    <div class="headquarter">
 | 
			
		||||
      <div class="inner-shadow w-1"></div>
 | 
			
		||||
      <div class="inner-shadow flex-1 flex">
 | 
			
		||||
        <CityName value="凯盛光伏" />
 | 
			
		||||
        <CityValue :value="headquarterValue" horizontal :period="period" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="inner-shadow w-1"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="city-item-container">
 | 
			
		||||
      <CityItem
 | 
			
		||||
        v-for="city in cities"
 | 
			
		||||
        :key="city.name"
 | 
			
		||||
        :location="city.name"
 | 
			
		||||
        :value="city.value"
 | 
			
		||||
        :period="period"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import CityItemVue from "./CityItem.vue";
 | 
			
		||||
import CityNameVue from "./CityName.vue";
 | 
			
		||||
import CityValueVue from "./CityValue.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "CityData",
 | 
			
		||||
  components: {
 | 
			
		||||
    CityItem: CityItemVue,
 | 
			
		||||
    CityName: CityNameVue,
 | 
			
		||||
    CityValue: CityValueVue,
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    dataSource: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: null,
 | 
			
		||||
    },
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    headquarterValue() {
 | 
			
		||||
      let getterName = "";
 | 
			
		||||
      switch (this.dataSource) {
 | 
			
		||||
        case "标准组件产出":
 | 
			
		||||
          getterName = "stdOutput";
 | 
			
		||||
          break;
 | 
			
		||||
        case "芯片产出":
 | 
			
		||||
          getterName = "chipOutput";
 | 
			
		||||
          break;
 | 
			
		||||
        case "BIPV产出":
 | 
			
		||||
          getterName = "bipvOutput";
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      return (
 | 
			
		||||
        "" + (this.$store.getters.copilot.yield[getterName]?.current?.[5] ?? 0)
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    cities() {
 | 
			
		||||
      let getterName = "";
 | 
			
		||||
      switch (this.dataSource) {
 | 
			
		||||
        case "标准组件产出":
 | 
			
		||||
          getterName = "stdOutput";
 | 
			
		||||
          break;
 | 
			
		||||
        case "芯片产出":
 | 
			
		||||
          getterName = "chipOutput";
 | 
			
		||||
          break;
 | 
			
		||||
        case "BIPV产出":
 | 
			
		||||
          getterName = "bipvOutput";
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      const _cities = [
 | 
			
		||||
        { name: "瑞昌", value: 0 },
 | 
			
		||||
        { name: "邯郸", value: 0 },
 | 
			
		||||
        { name: "株洲", value: 0 },
 | 
			
		||||
        { name: "佳木斯", value: 0 },
 | 
			
		||||
        { name: "成都", value: 0 },
 | 
			
		||||
        { name: "凯盛光伏", value: 0 },
 | 
			
		||||
        { name: "蚌埠兴科", value: 0 },
 | 
			
		||||
      ];
 | 
			
		||||
      this.$store.getters.copilot.yield[getterName]?.current?.forEach(
 | 
			
		||||
        (v, idx) => {
 | 
			
		||||
          _cities[idx].value = v ?? 0;
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
      // 删掉凯盛光伏
 | 
			
		||||
      _cities.splice(4, 1);
 | 
			
		||||
      return _cities;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {},
 | 
			
		||||
  methods: {},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.city-data {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.headquarter {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.w-1 {
 | 
			
		||||
  width: 70px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inner-shadow {
 | 
			
		||||
  box-shadow: inset 0 0 12px 2px #fff3;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.city-item-container {
 | 
			
		||||
  flex: 3;
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: repeat(2, 1fr);
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: CityItem.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="city-item inner-shadow">
 | 
			
		||||
    <CityName :value="location" />
 | 
			
		||||
    <CityValue :value="value + ''" :period="period" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import CityNameVue from "./CityName.vue";
 | 
			
		||||
import CityValueVue from "./CityValue.vue";
 | 
			
		||||
import GradientTextVue from "../gradient/GradientText.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "CityItem",
 | 
			
		||||
  components: {
 | 
			
		||||
    GradientTextVue,
 | 
			
		||||
    CityName: CityNameVue,
 | 
			
		||||
    CityValue: CityValueVue,
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    location: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "",
 | 
			
		||||
    },
 | 
			
		||||
    value: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: 0,
 | 
			
		||||
    },
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
  computed: {},
 | 
			
		||||
  mounted() {},
 | 
			
		||||
  methods: {},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.city-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.inner-shadow {
 | 
			
		||||
  box-shadow: inset 0 0 12px 2px #fff3;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: CityName.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-10 08:59:28
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="city-name">
 | 
			
		||||
    <img :src="Icon" alt="city icon" />
 | 
			
		||||
    <span>{{ value }}</span>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Icon from "../../../assets/icon.png";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "CityName",
 | 
			
		||||
  props: {
 | 
			
		||||
    value: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return { Icon };
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.city-name {
 | 
			
		||||
  min-width: 80px;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  padding: 0 8px;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
  /* width: 32px; */
 | 
			
		||||
  width: 1.543vw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span {
 | 
			
		||||
  /* font-size: 12px;   */
 | 
			
		||||
  font-size: 0.77vw;
 | 
			
		||||
  letter-spacing: 2px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										127
									
								
								src/views/copilot/efficiency/components/sub/city/CityValue.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								src/views/copilot/efficiency/components/sub/city/CityValue.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: CityValue.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-10 08:59:28
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="city-value" :class="[horizontal ? 'horizontal' : '']">
 | 
			
		||||
    <span class="hint" :class="[horizontal ? 'horizontal' : '']">{{
 | 
			
		||||
      period == "周" ? "本周产出" : "今日产出"
 | 
			
		||||
    }}</span>
 | 
			
		||||
    <span class="value" :class="[horizontal ? 'horizontal' : '']">{{
 | 
			
		||||
      value | numberFilter
 | 
			
		||||
    }}</span>
 | 
			
		||||
    <!-- <GradientTextVue :text="value" :size="horizontal ? 32 : 26" /> -->
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import GradientTextVue from "../gradient/GradientText.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "CityValue",
 | 
			
		||||
  components: { GradientTextVue },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
    value: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "",
 | 
			
		||||
    },
 | 
			
		||||
    horizontal: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  filters: {
 | 
			
		||||
    numberFilter(value) {
 | 
			
		||||
      if (value != null && !isNaN(parseInt(value))) {
 | 
			
		||||
        return parseInt(value).toLocaleString();
 | 
			
		||||
      } else {
 | 
			
		||||
        return value;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.city-value {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  padding: 0 8px;
 | 
			
		||||
  flex: 2;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.city-value.horizontal {
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.city-value::after {
 | 
			
		||||
  content: "";
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 1px;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background: linear-gradient(
 | 
			
		||||
    to bottom,
 | 
			
		||||
    transparent 20%,
 | 
			
		||||
    #fff 50%,
 | 
			
		||||
    transparent 80%
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.hint {
 | 
			
		||||
  margin: 0 0.77vw;
 | 
			
		||||
  font-size: 0.77vw;
 | 
			
		||||
  order: 2;
 | 
			
		||||
  /* margin: 0 12px;
 | 
			
		||||
  width: 32px;
 | 
			
		||||
  font-size: 12px; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
span.hint.horizontal {
 | 
			
		||||
  margin: 0 1.235vw;
 | 
			
		||||
  width: 1.543vw;
 | 
			
		||||
  order: 1;
 | 
			
		||||
  font-size: 0.77vw;
 | 
			
		||||
  /* margin: 0 12px;
 | 
			
		||||
  width: 32px;
 | 
			
		||||
  font-size: 12px; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.value {
 | 
			
		||||
  color: #4dd2fe;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 1.132vw;
 | 
			
		||||
  order: 1;
 | 
			
		||||
}
 | 
			
		||||
.value.horizontal {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  font-size: 1.543vw;
 | 
			
		||||
  order: 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
svg,
 | 
			
		||||
.value {
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  order: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.value.horizontal,
 | 
			
		||||
svg.horizontal {
 | 
			
		||||
  order: 2;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: GradientText.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-24 16:33:25
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <svg :height="size + 8" width="100%">
 | 
			
		||||
    <defs>
 | 
			
		||||
      <linearGradient id="smoke-text" x1="0%" y1="0%" x2="0%" y2="100%">
 | 
			
		||||
        <stop offset="0%" style="stop-color: #00fff4; stop-opacity: 1" />
 | 
			
		||||
        <stop offset="100%" style="stop-color: #37bdfe; stop-opacity: 1" />
 | 
			
		||||
      </linearGradient>
 | 
			
		||||
    </defs>
 | 
			
		||||
    <text
 | 
			
		||||
      x="0"
 | 
			
		||||
      :y="size"
 | 
			
		||||
      fill="url(#smoke-text)"
 | 
			
		||||
      :style="{
 | 
			
		||||
        fontSize: `${size}px`,
 | 
			
		||||
        letterSpacing: spacing || '2px',
 | 
			
		||||
        fontFamily: 'Calibri, Verdana, sans-serif',
 | 
			
		||||
      }"
 | 
			
		||||
    >
 | 
			
		||||
      {{ text | numberFilter }}
 | 
			
		||||
    </text>
 | 
			
		||||
  </svg>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: "GradientText",
 | 
			
		||||
  components: {},
 | 
			
		||||
  props: {
 | 
			
		||||
    text: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "Test",
 | 
			
		||||
    },
 | 
			
		||||
    spacing: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "1px",
 | 
			
		||||
    },
 | 
			
		||||
    size: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: 24,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  filters: {
 | 
			
		||||
    numberFilter(value) {
 | 
			
		||||
      if (value != null && !isNaN(parseInt(value))) {
 | 
			
		||||
        return parseInt(value).toLocaleString();
 | 
			
		||||
      } else {
 | 
			
		||||
        return value;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss"></style>
 | 
			
		||||
@@ -0,0 +1,221 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: DoubleRingChart.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 11:01:55
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="double-ring-chart">
 | 
			
		||||
    <div ref="chart" class="double-ring-chart__container"></div>
 | 
			
		||||
    <!-- style="{ height: vHeight + 'vh' }" -->
 | 
			
		||||
    <div class="double-ring-chart__legend">
 | 
			
		||||
      <div v-for="item in legendItems" :key="item.label" class="legend-item">
 | 
			
		||||
        <span class="legend-item__label">{{ item.label }}</span>
 | 
			
		||||
        <span class="legend-item__value">{{ item.value | numberFilter }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import chartMixin from "@/mixins/chart.js";
 | 
			
		||||
import fullscreenMixin from "@/mixins/fullscreen.js";
 | 
			
		||||
import getOptions from "../../../options/double-ring-chart-options";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "DoubleRingChart",
 | 
			
		||||
  mixins: [chartMixin, fullscreenMixin],
 | 
			
		||||
  props: {
 | 
			
		||||
    vHeight: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: 24,
 | 
			
		||||
    },
 | 
			
		||||
    factoryId: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
    dataSource: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: null,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {};
 | 
			
		||||
  },
 | 
			
		||||
  filters: {
 | 
			
		||||
    numberFilter(val) {
 | 
			
		||||
      if (!isNaN(val)) {
 | 
			
		||||
        return (+val).toLocaleString();
 | 
			
		||||
      }
 | 
			
		||||
      return 0;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    dataSourceField() {
 | 
			
		||||
      switch (this.dataSource) {
 | 
			
		||||
        case "标准组件产出":
 | 
			
		||||
          return "stdOutput";
 | 
			
		||||
        case "芯片产出":
 | 
			
		||||
          return "chipOutput";
 | 
			
		||||
        case "BIPV产出":
 | 
			
		||||
          return "bipvOutput";
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    valueTuple() {
 | 
			
		||||
      // [previousValue, currentValue, sumValue?]
 | 
			
		||||
      const getter = this.$store.getters.copilot.yield[this.dataSourceField];
 | 
			
		||||
      if (this.period === "日" || this.period === "周") {
 | 
			
		||||
        return [
 | 
			
		||||
          getter.previous[this.factoryId],
 | 
			
		||||
          getter.current[this.factoryId],
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
      // [100, 200, 200]
 | 
			
		||||
      return [
 | 
			
		||||
        getter.previous[this.factoryId],
 | 
			
		||||
        getter.current[this.factoryId],
 | 
			
		||||
        getter.target[this.factoryId],
 | 
			
		||||
      ];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    options() {
 | 
			
		||||
      const year = new Date().getFullYear();
 | 
			
		||||
      const month = new Date().getMonth() + 1;
 | 
			
		||||
      const vt = this.valueTuple;
 | 
			
		||||
      let titleValue =
 | 
			
		||||
          vt[0] != null && vt[2] != null && vt[2] !== 0
 | 
			
		||||
            ? `${vt[1] / vt[2]}%`
 | 
			
		||||
            : "0%",
 | 
			
		||||
        subtitle =
 | 
			
		||||
          this.period == "月" ? `${month}月累计产出` : `${year}年累计产出`;
 | 
			
		||||
 | 
			
		||||
      return getOptions({
 | 
			
		||||
        titleValue,
 | 
			
		||||
        subtitle,
 | 
			
		||||
        previousSum: this.valueTuple[0],
 | 
			
		||||
        currentSum: this.valueTuple[1],
 | 
			
		||||
        targetSum: this.valueTuple[2],
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    legendItems() {
 | 
			
		||||
      return calculateItems(this.period, this.valueTuple);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    legendItems() {
 | 
			
		||||
      this.initOptions(this.options);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.initOptions(this.options);
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    // fullscreen mixin 需要的回调
 | 
			
		||||
    fullscreenCallback(isFullscreen) {
 | 
			
		||||
      console.log("isFullscreen--->", isFullscreen);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function calculateItems(period, valueTuple) {
 | 
			
		||||
  let items = [];
 | 
			
		||||
  const today = new Date().getDate();
 | 
			
		||||
  const month = new Date().getMonth() + 1;
 | 
			
		||||
  const year = new Date().getFullYear();
 | 
			
		||||
  switch (period) {
 | 
			
		||||
    case "日":
 | 
			
		||||
      items = [
 | 
			
		||||
        { label: `${month}月${today}日累计`, value: valueTuple[1] },
 | 
			
		||||
        { label: `去年${month}月${today}日累计`, value: valueTuple[0] },
 | 
			
		||||
      ];
 | 
			
		||||
      break;
 | 
			
		||||
    case "周":
 | 
			
		||||
      items = [
 | 
			
		||||
        { label: `本周累计`, value: valueTuple[1] },
 | 
			
		||||
        { label: `去年本周累计`, value: valueTuple[0] },
 | 
			
		||||
      ];
 | 
			
		||||
      break;
 | 
			
		||||
    case "月":
 | 
			
		||||
      items = [
 | 
			
		||||
        { label: `${month}月累计`, value: valueTuple[1] },
 | 
			
		||||
        { label: `去年${month}月累计`, value: valueTuple[0] },
 | 
			
		||||
        { label: `${month}月目标`, value: valueTuple[2] },
 | 
			
		||||
      ];
 | 
			
		||||
      break;
 | 
			
		||||
    case "年":
 | 
			
		||||
      items = [
 | 
			
		||||
        { label: `${year}年累计`, value: valueTuple[1] },
 | 
			
		||||
        { label: `${year - 1}年累计`, value: valueTuple[0] },
 | 
			
		||||
        { label: `${year}年目标`, value: valueTuple[2] },
 | 
			
		||||
      ];
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return items;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.double-ring-chart {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.double-ring-chart__container {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  height: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.double-ring-chart__legend {
 | 
			
		||||
  padding: 12px;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  gap: 32px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item__label {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item__label::before {
 | 
			
		||||
  content: "";
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 12px;
 | 
			
		||||
  height: 12px;
 | 
			
		||||
  background: #ccc;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  top: 6px;
 | 
			
		||||
  left: -18px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item:nth-child(1) .legend-item__label::before {
 | 
			
		||||
  background: #12fff5;
 | 
			
		||||
}
 | 
			
		||||
.legend-item:nth-child(1) .legend-item__value {
 | 
			
		||||
  color: #12fff5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item:nth-child(2) .legend-item__label::before {
 | 
			
		||||
  background: #0f65ff;
 | 
			
		||||
}
 | 
			
		||||
.legend-item:nth-child(2) .legend-item__value {
 | 
			
		||||
  color: #0f65ff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.legend-item:nth-child(3) .legend-item__label::before {
 | 
			
		||||
  background: #003982;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,86 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: DoubleRingWrapper.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-17 09:55:12
 | 
			
		||||
    description: 
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="double-ring-wrapper">
 | 
			
		||||
    <template v-if="period == '月' || period == '年'">
 | 
			
		||||
      <copilot-select
 | 
			
		||||
        @update:active="handleActiveUpdate"
 | 
			
		||||
        :options="cityOptions"
 | 
			
		||||
      />
 | 
			
		||||
      <div class="flex-1 stretch">
 | 
			
		||||
        <DoubleRingChartVue
 | 
			
		||||
          :data-source="dataSource"
 | 
			
		||||
          :period="period"
 | 
			
		||||
          :factoryId="factoryId"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <CityData :data-source="dataSource" :period="period" />
 | 
			
		||||
    </template>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import CopilotSelect from "@/views/copilot/components/select.vue";
 | 
			
		||||
import DoubleRingChartVue from "./DoubleRingChart.vue";
 | 
			
		||||
import CityData from "../city/CityData.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "DoubleRingWrapper",
 | 
			
		||||
  components: { CopilotSelect, DoubleRingChartVue, CityData },
 | 
			
		||||
  props: {
 | 
			
		||||
    dataSource: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: null,
 | 
			
		||||
    },
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: "日",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      factoryId: 4, // 默认成都
 | 
			
		||||
      cityOptions: [
 | 
			
		||||
        "成都",
 | 
			
		||||
        "邯郸",
 | 
			
		||||
        "株洲",
 | 
			
		||||
        "瑞昌",
 | 
			
		||||
        "佳木斯",
 | 
			
		||||
        "凯盛光伏",
 | 
			
		||||
        "蚌埠兴科",
 | 
			
		||||
      ],
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleActiveUpdate(index) {
 | 
			
		||||
      this.factoryId = index;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.double-ring-wrapper {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  padding: 12px 24px;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 12px;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-1 {
 | 
			
		||||
  flex: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stretch {
 | 
			
		||||
  align-self: stretch;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,13 +1,16 @@
 | 
			
		||||
<!-- 
 | 
			
		||||
    filename: index.vue
 | 
			
		||||
    author: liubin
 | 
			
		||||
    date: 2024-04-16 14:40:15
 | 
			
		||||
    description: 效率驾驶舱
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: zhp
 | 
			
		||||
 * @Date: 2024-05-07 10:04:53
 | 
			
		||||
 * @LastEditTime: 2024-05-07 10:20:17
 | 
			
		||||
 * @LastEditors: zhp
 | 
			
		||||
 * @Description:
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="efficiency-copilot">
 | 
			
		||||
    <Container title="芯片良率" icon="chip2"></Container>
 | 
			
		||||
    <Container title="芯片良率" icon="chip2">
 | 
			
		||||
      <std-output :period="period" />
 | 
			
		||||
    </Container>
 | 
			
		||||
    <Container title="标准组件良率" icon="std"></Container>
 | 
			
		||||
    <Container title="芯片OEE" icon="chip"></Container>
 | 
			
		||||
    <Container title="转化效率" icon="cube"></Container>
 | 
			
		||||
@@ -16,9 +19,11 @@
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Container from "@/views/copilot/components/Container.vue";
 | 
			
		||||
import StdOutput from "./components/StdOutput.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "EfficiencyCopilot",
 | 
			
		||||
  components: { Container },
 | 
			
		||||
  components: { Container, StdOutput },
 | 
			
		||||
  props: {
 | 
			
		||||
    period: {
 | 
			
		||||
      type: String,
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,145 @@
 | 
			
		||||
export default ({
 | 
			
		||||
  titleValue,
 | 
			
		||||
  subtitle,
 | 
			
		||||
  previousSum,
 | 
			
		||||
  currentSum,
 | 
			
		||||
  targetSum,
 | 
			
		||||
}) => ({
 | 
			
		||||
  grid: {
 | 
			
		||||
    left: 0,
 | 
			
		||||
    right: 0,
 | 
			
		||||
    bottom: 0,
 | 
			
		||||
    top: 0,
 | 
			
		||||
    containLabel: true,
 | 
			
		||||
  },
 | 
			
		||||
  tooltip: {},
 | 
			
		||||
  title: {
 | 
			
		||||
    text: titleValue,
 | 
			
		||||
    left: "49%",
 | 
			
		||||
    top: "39%",
 | 
			
		||||
    textAlign: "center",
 | 
			
		||||
    textStyle: {
 | 
			
		||||
      fontWeight: 600,
 | 
			
		||||
      fontSize: 32,
 | 
			
		||||
      color: "#fffd",
 | 
			
		||||
    },
 | 
			
		||||
    subtext: `\u2002${subtitle}\u2002`,
 | 
			
		||||
    subtextStyle: {
 | 
			
		||||
      fontSize: 14,
 | 
			
		||||
      fontWeight: 100,
 | 
			
		||||
      color: "#fffd",
 | 
			
		||||
      align: "right",
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  series: [
 | 
			
		||||
    // 背景 series
 | 
			
		||||
    {
 | 
			
		||||
      type: "pie",
 | 
			
		||||
      name: "当前目标",
 | 
			
		||||
      radius: ["70%", "85%"],
 | 
			
		||||
      center: ["50%", "52%"],
 | 
			
		||||
      emptyCircleStyle: {
 | 
			
		||||
        color: "#042c5f33",
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    // 数据 series
 | 
			
		||||
    {
 | 
			
		||||
      type: "pie",
 | 
			
		||||
      radius: ["70%", "85%"],
 | 
			
		||||
      center: ["50%", "52%"],
 | 
			
		||||
      avoidLabelOvervlap: false,
 | 
			
		||||
      label: {
 | 
			
		||||
        show: false,
 | 
			
		||||
      },
 | 
			
		||||
      labelLine: {
 | 
			
		||||
        show: false,
 | 
			
		||||
      },
 | 
			
		||||
      data: [
 | 
			
		||||
        {
 | 
			
		||||
          value: currentSum,
 | 
			
		||||
          name: "当前累计产出",
 | 
			
		||||
          selected: false,
 | 
			
		||||
          itemStyle: {
 | 
			
		||||
            borderJoin: "round",
 | 
			
		||||
            borderCap: "round",
 | 
			
		||||
            borderWidth: 12,
 | 
			
		||||
            borderRadius: "50%",
 | 
			
		||||
            color: {
 | 
			
		||||
              type: "linear",
 | 
			
		||||
              x: 1,
 | 
			
		||||
              y: 0,
 | 
			
		||||
              x2: 0,
 | 
			
		||||
              y2: 1,
 | 
			
		||||
              colorStops: [
 | 
			
		||||
                { offset: 0, color: "#4CF0E811" },
 | 
			
		||||
                { offset: 1, color: "#4CF0E8" },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          value:
 | 
			
		||||
            targetSum > currentSum
 | 
			
		||||
              ? targetSum - currentSum
 | 
			
		||||
              : targetSum == 0
 | 
			
		||||
              ? currentSum == 0
 | 
			
		||||
                ? 1
 | 
			
		||||
                : 0
 | 
			
		||||
              : 0,
 | 
			
		||||
 | 
			
		||||
          name: "未达成累计",
 | 
			
		||||
          itemStyle: { color: "transparent" },
 | 
			
		||||
          label: { show: false },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
    // 数据 series2 - 2023累计
 | 
			
		||||
    {
 | 
			
		||||
      type: "pie",
 | 
			
		||||
      radius: ["55%", "70%"],
 | 
			
		||||
      center: ["50%", "52%"],
 | 
			
		||||
      avoidLabelOvervlap: false,
 | 
			
		||||
      label: {
 | 
			
		||||
        show: false,
 | 
			
		||||
      },
 | 
			
		||||
      labelLine: {
 | 
			
		||||
        show: false,
 | 
			
		||||
      },
 | 
			
		||||
      data: [
 | 
			
		||||
        {
 | 
			
		||||
          value: previousSum,
 | 
			
		||||
          name: "上期累计产出",
 | 
			
		||||
          selected: false,
 | 
			
		||||
          itemStyle: {
 | 
			
		||||
            borderJoin: "round",
 | 
			
		||||
            borderCap: "round",
 | 
			
		||||
            borderWidth: 12,
 | 
			
		||||
            borderRadius: "50%",
 | 
			
		||||
            color: {
 | 
			
		||||
              type: "linear",
 | 
			
		||||
              x: 1,
 | 
			
		||||
              y: 0,
 | 
			
		||||
              x2: 0,
 | 
			
		||||
              y2: 1,
 | 
			
		||||
              colorStops: [
 | 
			
		||||
                { offset: 0, color: "#1065ff66" },
 | 
			
		||||
                { offset: 1, color: "#1065ff" },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          value:
 | 
			
		||||
            targetSum > previousSum
 | 
			
		||||
              ? targetSum - previousSum
 | 
			
		||||
              : previousSum == 0
 | 
			
		||||
              ? 1
 | 
			
		||||
              : 0,
 | 
			
		||||
          name: "-",
 | 
			
		||||
          itemStyle: { color: "transparent" },
 | 
			
		||||
          label: { show: false },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user