<template>
  <div class="main">
    <el-row>
      <re-col :value="24" :xs="24" :sm="24">
        <el-card shadow="never">
          <template #header>
            <div class="flex items-center justify-center">
              <IconifyIconOffline :icon="Monitor" />
              <span class="header-title">基本信息</span>
            </div>
          </template>
          <el-descriptions :column="4" border class="centered-descriptions">
            <el-descriptions-item align="center" label="Redis版本" :span="1">
              {{ cache.info?.redis_version || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="运行模式" :span="1">
              {{ cache.info?.redis_mode === "standalone" ? "单机" : "集群" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="端口" :span="1">
              {{ cache.info?.tcp_port || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="客户端数" :span="1">
              {{ cache.info?.connected_clients || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="运行时间(天)" :span="1">
              {{ cache.info?.uptime_in_days || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="使用内存" :span="1">
              {{ cache.info?.used_memory_human || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="使用CPU" :span="1">
              {{
                cache.info?.used_cpu_user_children !== undefined
                  ? parseFloat(cache.info.used_cpu_user_children).toFixed(2)
                  : "-"
              }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="内存配置" :span="1">
              {{ cache.info?.maxmemory_human || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="AOF是否开启" :span="1">
              {{ cache.info?.aof_enabled === "0" ? "否" : "是" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="RDB是否成功" :span="1">
              {{ cache.info?.rdb_last_bgsave_status || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="Key数量" :span="1">
              {{ cache.dbSize || "-" }}
            </el-descriptions-item>
            <el-descriptions-item
              align="center"
              label="网络入口/出口"
              :span="1"
            >
              {{
                cache.info
                  ? `${cache.info.instantaneous_input_kbps}kps/${cache.info.instantaneous_output_kbps}kps`
                  : "-"
              }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="内存使用率" :span="1">
              {{
                cache.info?.used_memory !== undefined &&
                cache.info?.maxmemory !== undefined &&
                cache.info.maxmemory > 0
                  ? (
                      (cache.info.used_memory / cache.info.maxmemory) *
                      100
                    ).toFixed(2) + "%"
                  : "-"
              }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="操作系统" :span="1">
              {{ cache.info?.os || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="架构位数" :span="1">
              {{ cache.info?.arch_bits || "-" }}
            </el-descriptions-item>
            <el-descriptions-item align="center" label="多路复用API" :span="1">
              {{ cache.info?.multiplexing_api || "-" }}
            </el-descriptions-item>
          </el-descriptions>
        </el-card>
      </re-col>

      <re-col :value="12" :xs="24" :sm="24">
        <el-card shadow="never">
          <template #header>
            <div class="flex items-center justify-center">
              <IconifyIconOffline :icon="PieChart" />
              <span class="header-title">命令统计</span>
            </div>
          </template>
          <div ref="commandstats" style="height: 420px" />
        </el-card>
      </re-col>

      <re-col :value="12" :xs="24" :sm="24">
        <el-card shadow="never">
          <template #header>
            <div class="flex items-center justify-center">
              <IconifyIconOffline :icon="Odometer" />
              <span class="header-title">内存信息</span>
            </div>
          </template>
          <div ref="usedmemory" style="height: 420px" />
        </el-card>
      </re-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: "MonitorCache"
});
import ReCol from "@/components/ReCol";
import { ref, onMounted, nextTick, reactive } from "vue";
import { getCachedMonitorInfoAPI } from "@/api/monitor";
import * as echarts from "echarts";
import Monitor from "@iconify-icons/ep/monitor";
import PieChart from "@iconify-icons/ep/pie-chart";
import Odometer from "@iconify-icons/ep/odometer";
import { onBeforeRouteLeave } from "vue-router";

const cache = reactive({
  commandStats: [] as { name: string; value: number }[],
  dbSize: 0,
  info: {
    redis_version: "",
    redis_mode: "",
    tcp_port: 0,
    connected_clients: 0,
    uptime_in_days: 0,
    used_memory_human: "",
    used_cpu_user_children: "",
    maxmemory_human: "",
    aof_enabled: "",
    rdb_last_bgsave_status: "",
    instantaneous_input_kbps: 0,
    instantaneous_output_kbps: 0,
    used_memory: 0,
    maxmemory: 0,
    os: "",
    arch_bits: 0,
    multiplexing_api: ""
  }
});

const commandstats = ref(null);
const usedmemory = ref(null);

const getCacheInfo = async () => {
  const res = await getCachedMonitorInfoAPI();
  if (res.success) {
    Object.assign(cache, res.data);

    nextTick(() => {
      initCommandStatsChart();
      initUsedMemoryChart();
    });
  }
};

const initCommandStatsChart = () => {
  const chart = echarts.init(commandstats.value);
  const commandData = cache.commandStats || [];
  const seriesData = commandData.map((cmd: any) => ({
    name: cmd.name,
    value: parseInt(cmd.value, 10)
  }));

  const option = {
    title: {
      text: "命令统计",
      left: "center"
    },
    tooltip: {
      trigger: "item",
      formatter: "{a} <br/>{b}: {c} ({d}%)"
    },
    legend: {
      orient: "vertical",
      left: "left"
    },
    series: [
      {
        name: "命令",
        type: "pie",
        radius: "50%",
        data: seriesData,
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: "rgba(0, 0, 0, 0.5)"
          }
        },
        label: {
          show: true,
          formatter: "{b}: {c} ({d}%)"
        }
      }
    ]
  };

  chart.setOption(option);
};

const initUsedMemoryChart = () => {
  const chart = echarts.init(usedmemory.value);
  const usedMemory = cache.info?.used_memory || 0;
  const maxMemory = cache.info?.maxmemory || 0;

  const option = {
    title: {
      text: "内存信息",
      left: "center"
    },
    tooltip: {
      formatter: "{b} <br/>{a} : " + cache.info.used_memory_human
    },
    series: [
      {
        name: "峰值",
        type: "gauge",
        min: 0,
        max: 1000,
        detail: {
          formatter: cache.info.used_memory_human
        },
        data: [
          {
            value: parseFloat(cache.info.used_memory_human),
            name: "内存消耗"
          }
        ]
      }
    ]
  };

  chart.setOption(option);
};
/**定时ID */
const timer = ref();
onMounted(async () => {
  await getCacheInfo();
  timer.value = setInterval(() => {
    getCacheInfo();
  }, 60000);
});
/**页面离开时清除定时器 */
onBeforeRouteLeave(() => {
  clearInterval(timer.value);
});
</script>

<style scoped lang="scss">
.icon {
  width: 1em;
  height: 1em;
  vertical-align: middle;
}

.header-title {
  margin-left: 0.5em;
  vertical-align: middle;
}

.centered-descriptions {
  :deep(.el-descriptions-item__container) {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  :deep(.el-descriptions-item__label) {
    text-align: center;
  }

  :deep(.el-descriptions-item__content) {
    text-align: center;
  }
}
</style>
