page.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. "use client";
  2. import { useEffect, useRef, useState } from "react";
  3. import { useRouter } from "next/navigation";
  4. import { PageContainer, ProCard } from "@ant-design/pro-components";
  5. import { fetchApi } from "@/app/_modules/func";
  6. import {
  7. faServer,
  8. faChartPie,
  9. faGaugeHigh,
  10. } from "@fortawesome/free-solid-svg-icons";
  11. import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
  12. import { Statistic, Col, Row, Flex } from "antd";
  13. import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
  14. import { Doughnut } from "react-chartjs-2";
  15. import CountUp from "react-countup";
  16. import ReactSpeedometer from "react-d3-speedometer";
  17. ChartJS.register(ArcElement, Tooltip, Legend);
  18. //查询API
  19. const queryAPI = "/api/monitor/cache";
  20. //图表相关定义
  21. type ChartDataSet = {
  22. label: string;
  23. data: string[];
  24. backgroundColor: string[];
  25. };
  26. type ChartDataType = {
  27. labels: string[];
  28. datasets: Array<ChartDataSet>;
  29. };
  30. export default function Cache() {
  31. const { push } = useRouter();
  32. const [data, setData] = useState(undefined as any);
  33. const [commandChartData, setCommandChartData] = useState<ChartDataType>(
  34. {} as ChartDataType
  35. );
  36. //查询数据
  37. const queryData = async () => {
  38. const body = await fetchApi(queryAPI, push);
  39. if (body !== undefined) {
  40. if (body.code == 200) {
  41. setData(body.data);
  42. parseCommandChart(body.data.commandStats);
  43. }
  44. }
  45. };
  46. //处理命令图表数据
  47. const parseCommandChart = (commandStats: any[]) => {
  48. const labels: Array<string> = new Array<string>();
  49. const datas: Array<string> = new Array<string>();
  50. commandStats.forEach((item) => {
  51. labels.push(item.name);
  52. datas.push(item.value);
  53. });
  54. const commandSet: ChartDataSet = {
  55. label: "数量",
  56. data: datas,
  57. backgroundColor: [
  58. "#66BB6A",
  59. "#FFA726",
  60. "#42A5F5",
  61. "#EC407A",
  62. "#78909C",
  63. "#FF7043",
  64. "#26A69A",
  65. "#9575CD",
  66. "#FFB74D",
  67. ],
  68. };
  69. const commandData: ChartDataType = {
  70. labels: labels,
  71. datasets: [commandSet],
  72. };
  73. setCommandChartData(commandData);
  74. };
  75. const options = {
  76. plugins: {
  77. tooltip: {
  78. callbacks: {
  79. label: function (context: any) {
  80. let label = context.dataset.label || "";
  81. if (label) {
  82. label += ": ";
  83. }
  84. label +=
  85. context.parsed +
  86. "(" +
  87. Math.round(
  88. (context.parsed * 100) /
  89. context.dataset.data.reduce(
  90. (a: string, b: string) => parseInt(a) + parseInt(b),
  91. 0
  92. )
  93. ) +
  94. "%)";
  95. return label;
  96. },
  97. },
  98. },
  99. },
  100. };
  101. const speedParentRef = useRef<HTMLDivElement>(null);
  102. useEffect(() => {
  103. queryData();
  104. window.addEventListener("resize", handleResize);
  105. setDaynamicWidth();
  106. return () => {
  107. window.removeEventListener("resize", handleResize);
  108. };
  109. }, [speedParentRef]);
  110. //数字展示的动态效果
  111. const formatter = (value: any) => (
  112. <CountUp end={parseInt(value)} separator="," />
  113. );
  114. //超小屏的边界值
  115. const xsScreenWidth = 768;
  116. //界面两个ProCard横向布局空白空间宽度
  117. const spaceTotalWidth = 212;
  118. //侧边栏展开占据的宽度
  119. const siderExpand = 214;
  120. //计算初始的速度表宽度
  121. const setDaynamicWidth = () => {
  122. const screenWidth = window.innerWidth;
  123. if (screenWidth < xsScreenWidth) {
  124. setParentWidth((screenWidth - spaceTotalWidth) / 2);
  125. } else if (screenWidth >= xsScreenWidth) {
  126. setParentWidth((screenWidth - spaceTotalWidth - siderExpand) / 2);
  127. }
  128. };
  129. //速度表绘制的宽度值
  130. const [speedWidth, setParentWidth] = useState(0);
  131. //处理屏幕变化时,速度表宽度动态变化
  132. const handleResize = () => {
  133. if (speedParentRef.current) {
  134. setParentWidth(speedParentRef.current.clientWidth);
  135. } else {
  136. console.log("no current");
  137. }
  138. };
  139. return (
  140. <PageContainer title={false}>
  141. {data !== undefined && (
  142. <>
  143. <ProCard
  144. title={
  145. <>
  146. <FontAwesomeIcon icon={faServer} />
  147. <span style={{ marginLeft: 6 }}>基本信息</span>
  148. </>
  149. }
  150. direction="row"
  151. headerBordered
  152. bordered
  153. hoverable
  154. >
  155. <ProCard>
  156. <Statistic title="Redis版本" value={data.info.redis_version} />
  157. <Statistic
  158. title="运行模式"
  159. value={data.info.redis_mode == "standalone" ? "单机" : "集群"}
  160. />
  161. <Statistic
  162. title="端口"
  163. value={data.info.tcp_port}
  164. groupSeparator=""
  165. />
  166. <Statistic
  167. title="客户端数"
  168. value={data.info.connected_clients}
  169. formatter={formatter}
  170. />
  171. </ProCard>
  172. <ProCard>
  173. <Statistic
  174. title="运行天数"
  175. value={data.info.uptime_in_days}
  176. formatter={formatter}
  177. />
  178. <Statistic title="使用内存" value={data.info.used_memory_human} />
  179. <Statistic
  180. title="使用CPU"
  181. value={data.info.used_cpu_user_children}
  182. precision={2}
  183. />
  184. <Statistic title="内存配置" value={data.info.maxmemory_human} />
  185. </ProCard>
  186. <ProCard>
  187. <Statistic
  188. title="AOF是否开启"
  189. value={data.info.aof_enabled == "0" ? "否" : "是"}
  190. />
  191. <Statistic
  192. title="RDB是否成功"
  193. value={data.info.rdb_last_bgsave_status}
  194. />
  195. <Statistic
  196. title="Key数量"
  197. value={data.dbSize}
  198. formatter={formatter}
  199. />
  200. <Statistic
  201. title="网络入口/出口"
  202. value={`${data.info.instantaneous_input_kbps}kps/${data.info.instantaneous_output_kbps}kps`}
  203. />
  204. </ProCard>
  205. </ProCard>
  206. <Row gutter={16} style={{ marginTop: 16 }}>
  207. <Col span={12}>
  208. <ProCard
  209. title={
  210. <>
  211. <FontAwesomeIcon icon={faChartPie} />
  212. <span style={{ marginLeft: 6 }}>命令统计</span>
  213. </>
  214. }
  215. style={{ height: "100%" }}
  216. headerBordered
  217. bordered
  218. hoverable
  219. >
  220. <Flex justify="center">
  221. <Doughnut data={commandChartData} options={options} />
  222. </Flex>
  223. </ProCard>
  224. </Col>
  225. <Col span={12}>
  226. <ProCard
  227. title={
  228. <>
  229. <FontAwesomeIcon icon={faGaugeHigh} />
  230. <span style={{ marginLeft: 6 }}>内存信息</span>
  231. </>
  232. }
  233. style={{ height: "100%" }}
  234. headerBordered
  235. bordered
  236. hoverable
  237. >
  238. <Flex justify="center" ref={speedParentRef}>
  239. <ReactSpeedometer
  240. key={speedWidth}
  241. width={speedWidth}
  242. currentValueText={`内存消耗:${data.info.used_memory_human}`}
  243. value={parseFloat(data.info.used_memory_human)}
  244. needleColor="#1677ff"
  245. segmentColors={[
  246. "#82C182",
  247. "#A3D972",
  248. "#F5D061",
  249. "#FF9933",
  250. "#FF6666",
  251. ]}
  252. />
  253. </Flex>
  254. </ProCard>
  255. </Col>
  256. </Row>
  257. </>
  258. )}
  259. </PageContainer>
  260. );
  261. }