page.tsx 8.4 KB

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