<template>
  <div class="dashbord">
    <div class="chart-group">
      <el-card>
        <SubTitle title="设备运行" />
        <div class="chart-content">
          <img class="positionImg" src="@/assets/images/position.png" alt="" />
        </div>
      </el-card>
    </div>
    <div class="chart-group">
      <el-card>
        <SubTitle title="项目情况" />
        <div class="chart-content">
          <BaseChart width="100%" height="100%" :option="projectOption" />
        </div>
      </el-card>
      <el-card>
        <SubTitle title="设备总览" />
        <div class="chart-content">
          <BaseChart width="100%" height="100%" :option="equipOption" />
        </div>
      </el-card>
      <el-card>
        <SubTitle title="巡检人员" />
        <div class="chart-content">
          <div class="check-summary">
            <div>
              <img src="@/assets/images/home/banzu.svg" alt="" />
              <div class="check-name">
                <div>8</div>
                <div>班组</div>
              </div>
            </div>
            <div>
              <img src="@/assets/images/home/person.svg" alt="" />
              <div class="check-name">
                <div>40</div>
                <div>巡检人员</div>
              </div>
            </div>
          </div>
          <div class="check-rank">
            <div>当月巡检排名</div>
            <CustomTabs v-model:active="checkActive" :tabs="checkTabs" />
          </div>
          <el-table :data="tableData" style="width: 100%; margin-top: 10px" max-height="180">
            <el-table-column prop="name" label="巡检员">
              <template #default="scope">
                {{ `${scope.$index + 1}、${scope.row.name}` }}
              </template>
            </el-table-column>

            <el-table-column prop="group" label="所在班组" />
            <el-table-column prop="num" label="数量" />
          </el-table>
        </div>
      </el-card>
      <el-card>
        <SubTitle title="设备故障" />
        <div class="chart-content">
          <div style="display: flex; justify-content: flex-end; margin-top: 10px">
            <CustomTabs v-model:active="faultActive" :tabs="faultTabs" />
          </div>
          <BaseChart width="100%" height="100%" :option="rankOption" />
        </div>
      </el-card>
    </div>
  </div>
</template>
<script setup lang="ts">
import CustomTabs from './components/CustomTabs.vue';
const checkTabs = [
  {
    name: '按巡检设备数',
    value: '1'
  },
  {
    name: '按发现故障数',
    value: '2'
  }
];
const faultTabs = [
  {
    name: '按设备类型',
    value: '1'
  },
  {
    name: '按故障类型',
    value: '2'
  }
];
const checkActive = ref('1');
const faultActive = ref('1');
const tableData = [
  {
    name: '王刚',
    group: '班组4',
    num: '123'
  },
  {
    name: '李思',
    group: '班组2',
    num: '88'
  },
  {
    name: '张伟',
    group: '班组3',
    num: '65'
  },
  {
    name: '张强',
    group: '班组1',
    num: '54'
  }
];
function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, height) {
  // 计算
  let midRatio = (startRatio + endRatio) / 2;

  let startRadian = startRatio * Math.PI * 2;
  let endRadian = endRatio * Math.PI * 2;
  let midRadian = midRatio * Math.PI * 2;

  // 如果只有一个扇形，则不实现选中效果。
  if (startRatio === 0 && endRatio === 1) {
    isSelected = false;
  }

  // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
  k = typeof k !== 'undefined' ? k : 1 / 3;

  // 计算选中效果分别在 x 轴、y 轴方向上的位移（未选中，则位移均为 0）
  let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
  let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;

  // 计算高亮效果的放大比例（未高亮，则比例为 1）
  let hoverRate = isHovered ? 1.05 : 1;

  // 返回曲面参数方程
  return {
    u: {
      min: -Math.PI,
      max: Math.PI * 3,
      step: Math.PI / 32
    },

    v: {
      min: 0,
      max: Math.PI * 2,
      step: Math.PI / 20
    },

    x: function (u, v) {
      if (u < startRadian) {
        return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
    },

    y: function (u, v) {
      if (u < startRadian) {
        return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      if (u > endRadian) {
        return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
      }
      return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
    },

    z: function (u, v) {
      if (u < -Math.PI * 0.5) {
        return Math.sin(u);
      }
      if (u > Math.PI * 2.5) {
        return Math.sin(u);
      }
      return Math.sin(v) > 0 ? 0.2 * height : -1;
    }
  };
}

// 生成模拟 3D 饼图的配置项
function getPie3D(pieData, internalDiameterRatio) {
  let series = [];
  let sumValue = 0;
  let startValue = 0;
  let endValue = 0;
  let legendData = [];
  let k = typeof internalDiameterRatio !== 'undefined' ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;

  // 为每一个饼图数据，生成一个 series-surface 配置
  for (let i = 0; i < pieData.length; i++) {
    sumValue += pieData[i].value;

    let seriesItem = {
      name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name,
      type: 'surface',
      parametric: true,
      wireframe: {
        show: false
      },
      pieData: pieData[i],
      pieStatus: {
        selected: false,
        hovered: false,
        k: k
      }
    };

    if (typeof pieData[i].itemStyle != 'undefined') {
      let itemStyle = {};

      typeof pieData[i].itemStyle.color != 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null;
      typeof pieData[i].itemStyle.opacity != 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;

      seriesItem.itemStyle = itemStyle;
    }
    series.push(seriesItem);
  }

  // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
  // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
  for (let i = 0; i < series.length; i++) {
    endValue = startValue + series[i].pieData.value;
    console.log(series[i]);
    series[i].pieData.startRatio = startValue / sumValue;
    series[i].pieData.endRatio = endValue / sumValue;
    series[i].parametricEquation = getParametricEquation(
      series[i].pieData.startRatio,
      series[i].pieData.endRatio,
      false,
      false,
      k,
      series[i].pieData.value
    );

    startValue = endValue;

    legendData.push(series[i].name);
  }

  // // 补充一个透明的圆环，用于支撑高亮功能的近似实现。
  series.push({
    name: 'mouseoutSeries',
    type: 'surface',
    parametric: true,
    wireframe: {
      show: false
    },
    itemStyle: {
      opacity: 0.1,
      color: '#8997DE'
    },
    parametricEquation: {
      u: {
        min: 0,
        max: Math.PI * 2,
        step: Math.PI / 20
      },
      v: {
        min: 0,
        max: Math.PI,
        step: Math.PI / 20
      },
      x: function (u, v) {
        return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2;
      },
      y: function (u, v) {
        return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2;
      },
      z: function (u, v) {
        return Math.cos(v) > 0 ? -0.5 : -5;
      }
    }
  });

  // // 补充一个透明的圆环，用于支撑高亮功能的近似实现。
  series.push({
    name: 'mouseoutSeries',
    type: 'surface',
    parametric: true,
    wireframe: {
      show: false
    },
    itemStyle: {
      opacity: 0.1,
      color: '#8997DE'
    },
    parametricEquation: {
      u: {
        min: 0,
        max: Math.PI * 2,
        step: Math.PI / 20
      },
      v: {
        min: 0,
        max: Math.PI,
        step: Math.PI / 20
      },
      x: function (u, v) {
        return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2;
      },
      y: function (u, v) {
        return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2;
      },
      z: function (u, v) {
        return Math.cos(v) > 0 ? -5 : -7;
      }
    }
  });
  series.push({
    name: 'mouseoutSeries',
    type: 'surface',
    parametric: true,
    wireframe: {
      show: false
    },
    itemStyle: {
      opacity: 0.1,
      color: '#8997DE'
    },

    parametricEquation: {
      u: {
        min: 0,
        max: Math.PI * 2,
        step: Math.PI / 20
      },
      v: {
        min: 0,
        max: Math.PI,
        step: Math.PI / 20
      },
      x: function (u, v) {
        return ((Math.sin(v) * Math.sin(u) + Math.sin(u)) / Math.PI) * 2.2;
      },
      y: function (u, v) {
        return ((Math.sin(v) * Math.cos(u) + Math.cos(u)) / Math.PI) * 2.2;
      },
      z: function (u, v) {
        return Math.cos(v) > 0 ? -7 : -7;
      }
    }
  });
  return series;
}

let colors = ['#085AC7', '#24525E', '#C3972E'];
let xData = ['运营', '施工', '结束'];
let yData = [568, 175, 396];
// 传入数据生成 option
let optionsData = [];
let total = 0;
yData.forEach((v) => {
  total += v;
});
for (let i = 0; i < xData.length; i++) {
  optionsData.push({
    name: xData[i],
    value: yData[i],
    itemStyle: {
      color: colors[i],
      opacity: 0.7
    }
  });
}

const series = getPie3D(optionsData, 0.8);
const projectOption = computed(() => {
  return {
    legend: {
      tooltip: {
        show: true
      },
      data: xData,
      orient: 'vertial',
      bottom: '5%',
      left: 'center',
      itemGap: 14,
      itemHeight: 10,
      itemWidth: 15,
      formatter: (name) => {
        const res = optionsData.filter((n) => {
          return n.name === name;
        });
        if (!res.length) return;
        return `${name}  ${res[0].value}个  ${res[0].value ? ((res[0].value / total) * 100).toFixed(2) : 0}%`;
      }
    },
    animation: true,
    tooltip: {
      formatter: (params) => {
        if (params.seriesName !== 'mouseoutSeries' && params.seriesName !== 'pie2d') {
          return `${params.seriesName}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>${projectOption.value.series[params.seriesIndex].pieData.value}个`;
        }
      },
      textStyle: {
        fontSize: 12
      }
    },
    xAxis3D: {
      min: -1,
      max: 1
    },
    yAxis3D: {
      min: -1,
      max: 1
    },
    zAxis3D: {
      min: -1,
      max: 1
    },
    grid3D: {
      show: false,
      boxHeight: 0.5,
      top: '-10%',
      viewControl: {
        distance: 240,
        alpha: 30,
        beta: 10,
        autoRotate: true // 自动旋转
      }
    },

    series: series
  };
});
const equipData = ref<any>([
  {
    name: '报废',
    value: 1546
  },
  {
    name: '维修中',
    value: 189
  },
  {
    name: '故障',
    value: 1452
  },
  {
    name: '其他',
    value: 189
  },
  {
    name: '正在运行',
    value: 600
  },
  {
    name: '停役',
    value: 200
  }
]);
const color = ['#1990FF', '#8543E0', '#30C25B', '#16C2C2', '#FACC14', '#F04864'];
equipData.value.forEach((item, index) => {
  const tag = index % 6;
  item.itemStyle = {
    color: color[tag] || ''
  };
});
let equipTotal = 0;
equipData.value.forEach((v) => {
  equipTotal += v.value;
});
const equipOption = computed(() => {
  return {
    legend: {
      show: true,
      left: '0%',
      bottom: '5%',
      itemGap: 10,
      borderRadius: 5,
      itemWidth: 10,
      icon: 'circle',
      itemHeight: 10,
      data: equipData.value,
      formatter: function (name) {
        const res = equipData.value.filter((n) => {
          return n.name === name;
        });
        if (!res.length) return;
        return `${name}  ${res[0].value ? ((res[0].value / equipTotal) * 100).toFixed(2) : 0}%  ${res[0].value}`;
      }
    },
    tooltip: {
      trigger: 'item',
      backgroundColor: 'rgba(13,5,30,.6)',
      borderWidth: 1,
      borderColor: '#32A1FF',
      padding: 5,
      textStyle: {
        color: '#fff'
      },
      formatter: (params) => {
        return `${params.name}<br/>${params.marker}${params.value}`;
      }
    },
    title: {
      show: true,
      text: '设备总数',
      itemGap: 5, //主副标题之间的距离
      left: 'center',
      top: '28%',
      textStyle: {
        fontSize: 13,
        color: '#9E9E9E',
        fontWeight: 'normal'
      },
      subtext: '4226',
      subtextStyle: {
        fontSize: 18,
        fontWeight: 500,
        color: '#333'
      }
    },
    series: [
      {
        name: '',
        type: 'pie',
        radius: ['40%', '60%'],
        center: ['50%', '35%'],
        itemStyle: {
          borderWidth: 2, //描边线宽
          borderColor: '#fff'
        },
        label: {
          show: false
        },
        labelLine: {},
        data: equipData.value
      }
    ]
  };
});

const rankData = [
  { name: '设备类型一', value: 323 },
  { name: '设备类型二', value: 108 },
  { name: '设备类型三', value: 95 },
  { name: '设备类型四', value: 43 },
  { name: '设备类型五', value: 10 }
]; // 类别
let rankTotal = 0; // 数据总数
rankData.forEach((v) => {
  rankTotal += v.value;
});
const rankOption = computed(() => {
  return {
    grid: {
      left: '5%',
      top: '3%', // 设置条形图的边距
      right: '12%',
      bottom: '15%'
    },
    xAxis: {
      splitLine: {
        show: false,
        lineStyle: {
          color: 'rgba(255,255,255,0.2)',
          type: 'dashed'
        }
      },
      axisLine: {
        show: false
      },
      axisLabel: {
        show: false,
        color: '#ABBFE3'
      },
      axisTick: {
        show: false
      }
    },
    yAxis: [
      {
        type: 'category',
        inverse: true,
        data: rankData.map((item) => item.name),
        axisLine: {
          show: false
        },
        axisTick: {
          show: false
        },
        axisLabel: {
          show: true,
          textStyle: {
            verticalAlign: 'bottom',
            color: '#000',
            fontSize: 12,
            fontFamily: 'Microsoft YaHei',
            align: 'left',
            padding: [0, 0, 9, 5]
          },
          formatter: (name, index) => {
            const _index = index + 1;
            return `NO${_index}. ${name}`;
          }
        },
        offset: 0
      }
    ],
    series: [
      {
        // 内
        type: 'bar',
        barWidth: 10,
        barCateGoryGap: 20,
        legendHoverLink: false,
        silent: true,
        itemStyle: {
          normal: {
            barBorderRadius: 10,
            color: {
              type: 'linear',
              x: 0,
              y: 0,
              x2: 1,
              y2: 0,
              colorStops: [
                {
                  offset: 0,
                  color: '#FFFFFF' // 0% 处的颜色
                },
                {
                  offset: 1,
                  color: '#0768FF' // 100% 处的颜色
                }
              ]
            }
          }
        },
        label: {
          normal: {
            show: false,
            position: '[0, 0, 15, 10]',
            formatter: '{b}',
            textStyle: {
              color: '#fff',
              fontSize: 14
            }
          }
        },
        data: rankData,
        z: 2,
        animationEasing: 'elasticOut'
      },
      {
        // 外边框
        type: 'pictorialBar',
        symbol: 'rect',
        symbolBoundingData: rankTotal,
        itemStyle: {
          barBorderRadius: 10,
          normal: {
            color: 'none'
          }
        },
        label: {
          normal: {
            padding: [0, 10, 0, 14],
            formatter: (params) => {
              return params.data;
            },
            color: '#03FF00',
            fontWeight: 'bold',
            position: 'right',
            distance: 1, // 向右偏移位置
            show: true
          }
        },
        data: rankData.map((item) => item.value),
        z: 0,
        animationEasing: 'elasticOut'
      },
      {
        name: '外框',
        type: 'bar',
        barCateGoryGap: 20,
        barGap: '-100%', // 设置外框粗细
        data: new Array(rankData.length).fill(rankTotal),
        barWidth: 10,
        itemStyle: {
          normal: {
            barBorderRadius: [0, 6, 6, 0],
            color: '#F2F2F2'
          },
          emphasis: {
            barBorderRadius: [0, 6, 6, 0],
            color: '#F2F2F2'
          }
        },
        z: 0
      }
    ]
  };
});
</script>
<style lang="scss" scoped>
.positionImg {
  width: 100%;
  height: 100%;
  padding: 10px 0;
}

.chart-group {
  display: flex;
  margin-top: 5px;

  :deep(.el-card__body) {
    height: 100%;
    padding: 15px 10px !important;
  }

  .el-card {
    flex: 1;
    height: 350px;
    background: #fff;

    &:not(:first-child) {
      margin-left: 5px;
    }
  }

  .chart-content {
    height: calc(100% - 10px);
    margin-top: 5px;
    border-top: 1px solid #eaebee;
  }
}

.check-summary {
  display: flex;
  margin-top: 10px;

  >div {
    flex: 1;
    padding: 5px 10px;
    display: flex;
    background: #fafbfc;
    border: 1px solid #e4e5e9;
    border-radius: 4px;

    &:not(:first-child) {
      margin-left: 10px;
    }

    img {
      height: 40px;
    }

    .check-name {
      margin-left: 10px;

      div:first-child {
        font-size: 16px;
        font-weight: 500;
      }

      div:last-child {
        font-size: 14px;
      }
    }
  }
}

.check-rank {
  margin-top: 10px;
  display: flex;
  justify-content: space-between;

  >div:first-child {
    font-size: 14px;
  }
}
</style>
