222 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<!--
 | 
						|
    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: `${year-1}年${month}月${today}日累计`, value: valueTuple[0] },
 | 
						|
      ];
 | 
						|
      break;
 | 
						|
    case "周":
 | 
						|
      items = [
 | 
						|
        { label: `本周累计`, value: valueTuple[1] },
 | 
						|
        { label: `${year-1}年本周累计`, value: valueTuple[0] },
 | 
						|
      ];
 | 
						|
      break;
 | 
						|
    case "月":
 | 
						|
      items = [
 | 
						|
        { label: `${month}月累计`, value: valueTuple[1] },
 | 
						|
        { label: `${year-1}年${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>
 |