page.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. "use client";
  2. import {useEffect, useState} from "react";
  3. import {useRouter} from "next/navigation";
  4. import {ClearOutlined, DeleteOutlined, ReloadOutlined} from "@ant-design/icons";
  5. import {Button, Col, Flex, Form, Input, Row, Table, Tooltip,} from "antd";
  6. import {PageContainer, ProCard} from "@ant-design/pro-components";
  7. import {faFileLines, faFloppyDisk, faKey,} from "@fortawesome/free-solid-svg-icons";
  8. import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
  9. import {fetchApi} from "@/app/_modules/func";
  10. import globalMessage from "@/app/_modules/globalMessage";
  11. const { TextArea } = Input;
  12. //查询缓存API
  13. const queryCacheAPI = "/api/monitor/cache/getNames";
  14. //删除指定的缓存API
  15. const deleteCacheAPI = "/api/monitor/cache/clearCacheName";
  16. //查询缓存Key API
  17. const queryCacheKeyAPI = "/api/monitor/cache/getKeys";
  18. //查询缓存值API
  19. const queryValueAPI = "/api/monitor/cache/getValue";
  20. //删除指定的Key API
  21. const deleteKeyAPI = "/api/monitor/cache/clearCacheKey";
  22. //清空所有缓存API
  23. const clearAPI = "/api/monitor/cache/clearCacheAll";
  24. export default function CacheList() {
  25. const { push } = useRouter();
  26. //缓存列表加载状态
  27. const [isCacheLoading, setIsCacheLoading] = useState(false);
  28. //缓存数据
  29. const [cacheData, setCacheData] = useState([]);
  30. //查询缓存
  31. const queryCache = async () => {
  32. setIsCacheLoading(true);
  33. const body = await fetchApi(queryCacheAPI, push);
  34. if (body !== undefined) {
  35. if (body.code == 200) {
  36. setCacheData(body.data);
  37. }
  38. }
  39. setIsCacheLoading(false);
  40. };
  41. useEffect(() => {
  42. queryCache();
  43. }, []);
  44. //缓存列定义
  45. const cacheColumns = [
  46. {
  47. title: "序号",
  48. key: "index",
  49. width: "60px",
  50. render: (text: any, record: any, index: number) => `${index + 1}`,
  51. },
  52. {
  53. title: "缓存名称",
  54. dataIndex: "cacheName",
  55. ellipsis: true,
  56. },
  57. {
  58. title: "备注",
  59. dataIndex: "remark",
  60. },
  61. {
  62. title: "操作",
  63. key: "action",
  64. render: (text: any, record: any) => [
  65. <Button
  66. key="deleteBtn"
  67. type="link"
  68. danger
  69. icon={<DeleteOutlined />}
  70. onClick={() => deleteCache(record.cacheName)}
  71. ></Button>,
  72. ],
  73. },
  74. ];
  75. //缓存列表行点击
  76. const cacheRowClick = (record: any, index: any) => {
  77. return {
  78. onMouseDown: (event: any) => {
  79. setSelectedCache(record.cacheName);
  80. queryKeys(record.cacheName);
  81. },
  82. };
  83. };
  84. //删除指定的缓存
  85. const deleteCache = async (cacheName: string) => {
  86. const body = await fetchApi(`${deleteCacheAPI}/${cacheName}}`, push, {
  87. method: "DELETE",
  88. });
  89. if (body != undefined) {
  90. if (body.code == 200) {
  91. globalMessage.success(`清理缓存[${cacheName}]成功`);
  92. queryCache();
  93. } else {
  94. globalMessage.error(body.msg);
  95. }
  96. }
  97. };
  98. //选中的缓存
  99. const [selectedCache, setSelectedCache] = useState("");
  100. //key列表加载状态
  101. const [isKeyLoading, setIsKeyLoading] = useState(false);
  102. //key 数据
  103. const [keyData, setKeyData] = useState([]);
  104. //查询缓存对应的key
  105. const queryKeys = async (cacheName?: string) => {
  106. if (cacheName === undefined) {
  107. if (selectedCache === "") {
  108. return;
  109. }
  110. cacheName = selectedCache;
  111. }
  112. setIsKeyLoading(true);
  113. const body = await fetchApi(`${queryCacheKeyAPI}/${cacheName}`, push);
  114. if (body !== undefined) {
  115. if (body.code == 200) {
  116. setKeyData(body.data);
  117. }
  118. }
  119. setIsKeyLoading(false);
  120. };
  121. //key列定义
  122. const keyColumns = [
  123. {
  124. title: "序号",
  125. key: "index",
  126. width: "60px",
  127. render: (text: any, record: any, index: number) => `${index + 1}`,
  128. },
  129. {
  130. title: "缓存键名",
  131. key: "key",
  132. ellipsis: true,
  133. render: (text: any, record: string) => record.split(":")[1],
  134. },
  135. {
  136. title: "操作",
  137. key: "action",
  138. render: (text: any, record: any) => [
  139. <Button
  140. key="deleteBtn"
  141. type="link"
  142. danger
  143. icon={<DeleteOutlined />}
  144. onClick={() => deleteKey(record)}
  145. ></Button>,
  146. ],
  147. },
  148. ];
  149. //key列表行点击
  150. const keyRowClick = (record: any, index: any) => {
  151. return {
  152. onClick: (event: any) => {
  153. queryValue(record);
  154. },
  155. };
  156. };
  157. //删除指定的key
  158. const deleteKey = async (key: string) => {
  159. const body = await fetchApi(`${deleteKeyAPI}/${key}`, push, {
  160. method: "DELETE",
  161. });
  162. if (body != undefined) {
  163. if (body.code == 200) {
  164. globalMessage.success(`清理缓存键名[${key}]成功`);
  165. queryKeys();
  166. } else {
  167. globalMessage.error(body.msg);
  168. }
  169. }
  170. };
  171. //缓存值展示表单
  172. const [valueForm] = Form.useForm();
  173. //查询值
  174. const queryValue = async (key: any) => {
  175. const body = await fetchApi(
  176. `${queryValueAPI}/${selectedCache}/${key}`,
  177. push
  178. );
  179. if (body !== undefined) {
  180. if (body.code == 200) {
  181. valueForm?.setFieldsValue({
  182. cacheName: body.data.cacheName,
  183. cacheKey: body.data.cacheKey,
  184. cacheValue: body.data.cacheValue,
  185. });
  186. }
  187. }
  188. };
  189. //清空全部缓存
  190. const clearCache = async () => {
  191. const body = await fetchApi(clearAPI, push, {
  192. method: "DELETE",
  193. });
  194. if (body !== undefined) {
  195. if (body.code == 200) {
  196. globalMessage.success("清空全部缓存成功");
  197. } else {
  198. globalMessage.error(body.msg);
  199. }
  200. } else {
  201. globalMessage.error("清空全部缓存异常");
  202. }
  203. };
  204. return (
  205. <PageContainer title={false}>
  206. <Flex justify="flex-end" style={{ marginBottom: 16 }}>
  207. <Tooltip title="清空全部缓存">
  208. <Button
  209. icon={<ClearOutlined />}
  210. type="primary"
  211. onClick={clearCache}
  212. />
  213. </Tooltip>
  214. </Flex>
  215. <Row gutter={8}>
  216. <Col span={8}>
  217. <ProCard
  218. title={
  219. <>
  220. <FontAwesomeIcon icon={faFloppyDisk} />
  221. <span style={{ marginLeft: 6 }}>缓存列表</span>
  222. </>
  223. }
  224. extra={
  225. <Tooltip title="刷新">
  226. <a onClick={queryCache}>
  227. <ReloadOutlined />
  228. </a>
  229. </Tooltip>
  230. }
  231. style={{ height: "100%" }}
  232. headerBordered
  233. bordered
  234. hoverable
  235. >
  236. <div style={{ overflowX: "auto" }}>
  237. <Table
  238. dataSource={cacheData}
  239. columns={cacheColumns}
  240. loading={isCacheLoading}
  241. onRow={cacheRowClick}
  242. />
  243. </div>
  244. </ProCard>
  245. </Col>
  246. <Col span={8}>
  247. <ProCard
  248. title={
  249. <>
  250. <FontAwesomeIcon icon={faKey} />
  251. <span style={{ marginLeft: 6 }}>键名列表</span>
  252. </>
  253. }
  254. extra={
  255. <Tooltip title="刷新">
  256. <a onClick={() => queryKeys()}>
  257. <ReloadOutlined />
  258. </a>
  259. </Tooltip>
  260. }
  261. style={{ height: "100%" }}
  262. headerBordered
  263. bordered
  264. hoverable
  265. >
  266. <div style={{ overflowX: "auto" }}>
  267. <Table
  268. dataSource={keyData}
  269. columns={keyColumns}
  270. loading={isKeyLoading}
  271. onRow={keyRowClick}
  272. />
  273. </div>
  274. </ProCard>
  275. </Col>
  276. <Col span={8}>
  277. <ProCard
  278. title={
  279. <>
  280. <FontAwesomeIcon icon={faFileLines} />
  281. <span style={{ marginLeft: 6 }}>缓存内容</span>
  282. </>
  283. }
  284. style={{ height: "100%" }}
  285. headerBordered
  286. bordered
  287. hoverable
  288. >
  289. <Form layout="vertical" form={valueForm}>
  290. <Form.Item label="缓存名称" name="cacheName">
  291. <Input readOnly />
  292. </Form.Item>
  293. <Form.Item label="缓存键名" name="cacheKey">
  294. <Input readOnly />
  295. </Form.Item>
  296. <Form.Item label="缓存内容" name="cacheValue">
  297. <TextArea readOnly rows={8} />
  298. </Form.Item>
  299. </Form>
  300. </ProCard>
  301. </Col>
  302. </Row>
  303. </PageContainer>
  304. );
  305. }