index.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <script lang="ts" setup>
  2. import { onBeforeMount, ref } from 'vue'
  3. import * as RedisApi from '@/api/infra/redis'
  4. import { DICT_TYPE } from '@/utils/dict'
  5. import * as echarts from 'echarts'
  6. import { RedisKeyInfo, RedisMonitorInfoVO } from '@/api/infra/redis/types'
  7. import {
  8. ElRow,
  9. ElCard,
  10. ElCol,
  11. ElTable,
  12. ElTableColumn,
  13. ElScrollbar,
  14. ElDescriptions,
  15. ElDescriptionsItem,
  16. ElMessage
  17. } from 'element-plus'
  18. const cache = ref<RedisMonitorInfoVO>()
  19. const keyListLoad = ref(true)
  20. const keyList = ref<RedisKeyInfo[]>([])
  21. // 基本信息
  22. const readRedisInfo = async () => {
  23. const data = await RedisApi.getCacheApi()
  24. cache.value = data
  25. loadEchartOptions(data.commandStats)
  26. const redisKeysInfo = await RedisApi.getKeyDefineListApi()
  27. keyList.value = redisKeysInfo
  28. keyListLoad.value = false //加载完成
  29. }
  30. // 图表
  31. const commandStatsRef = ref<HTMLElement>()
  32. const usedmemory = ref<HTMLDivElement>()
  33. const loadEchartOptions = (stats) => {
  34. const commandStats = [] as any[]
  35. const nameList = [] as string[]
  36. stats.forEach((row) => {
  37. commandStats.push({
  38. name: row.command,
  39. value: row.calls
  40. })
  41. nameList.push(row.command)
  42. })
  43. const commandStatsInstance = echarts.init(commandStatsRef.value!, 'macarons')
  44. commandStatsInstance.setOption({
  45. title: {
  46. text: '命令统计',
  47. left: 'center'
  48. },
  49. tooltip: {
  50. trigger: 'item',
  51. formatter: '{a} <br/>{b} : {c} ({d}%)'
  52. },
  53. legend: {
  54. type: 'scroll',
  55. orient: 'vertical',
  56. right: 30,
  57. top: 10,
  58. bottom: 20,
  59. data: nameList,
  60. textStyle: {
  61. color: '#a1a1a1'
  62. }
  63. },
  64. series: [
  65. {
  66. name: '命令',
  67. type: 'pie',
  68. radius: [20, 120],
  69. center: ['40%', '60%'],
  70. data: commandStats,
  71. roseType: 'radius',
  72. label: {
  73. show: true
  74. },
  75. emphasis: {
  76. label: {
  77. show: true
  78. },
  79. itemStyle: {
  80. shadowBlur: 10,
  81. shadowOffsetX: 0,
  82. shadowColor: 'rgba(0, 0, 0, 0.5)'
  83. }
  84. }
  85. }
  86. ]
  87. })
  88. const usedMemoryInstance = echarts.init(usedmemory.value!, 'macarons')
  89. usedMemoryInstance.setOption({
  90. title: {
  91. text: '内存使用情况',
  92. left: 'center'
  93. },
  94. tooltip: {
  95. formatter: '{b} <br/>{a} : ' + cache.value!.info.used_memory_human
  96. },
  97. series: [
  98. {
  99. name: '峰值',
  100. type: 'gauge',
  101. min: 0,
  102. max: 100,
  103. progress: {
  104. show: true
  105. },
  106. detail: {
  107. formatter: cache.value!.info.used_memory_human
  108. },
  109. data: [
  110. {
  111. value: parseFloat(cache.value!.info.used_memory_human),
  112. name: '内存消耗'
  113. }
  114. ]
  115. }
  116. ]
  117. })
  118. }
  119. const dialogVisible = ref(false)
  120. const keyTemplate = ref('')
  121. const cacheKeys = ref()
  122. const cacheForm = ref<{
  123. key: string
  124. value: string
  125. }>({
  126. key: '',
  127. value: ''
  128. })
  129. const openKeyTemplate = async (row: RedisKeyInfo) => {
  130. keyTemplate.value = row.keyTemplate
  131. cacheKeys.value = await RedisApi.getKeyListApi(row.keyTemplate)
  132. dialogVisible.value = true
  133. }
  134. const handleDeleteKey = async (row) => {
  135. RedisApi.deleteKeyApi(row)
  136. ElMessage.success('删除成功')
  137. }
  138. const handleDeleteKeys = async (row) => {
  139. RedisApi.deleteKeysApi(row)
  140. ElMessage.success('删除成功')
  141. }
  142. const handleKeyValue = async (row) => {
  143. const res = await RedisApi.getKeyValueApi(row)
  144. cacheForm.value = res
  145. }
  146. onBeforeMount(() => {
  147. readRedisInfo()
  148. })
  149. </script>
  150. <template>
  151. <el-scrollbar height="calc(100vh - 88px - 40px - 50px)">
  152. <el-row>
  153. <el-col :span="24" class="card-box" shadow="hover">
  154. <el-card>
  155. <el-descriptions title="基本信息" :column="6" border>
  156. <el-descriptions-item label="Redis版本 :">
  157. {{ cache?.info?.redis_version }}
  158. </el-descriptions-item>
  159. <el-descriptions-item label="运行模式 :">
  160. {{ cache?.info?.redis_mode == 'standalone' ? '单机' : '集群' }}
  161. </el-descriptions-item>
  162. <el-descriptions-item label="端口 :">
  163. {{ cache?.info?.tcp_port }}
  164. </el-descriptions-item>
  165. <el-descriptions-item label="客户端数 :">
  166. {{ cache?.info?.connected_clients }}
  167. </el-descriptions-item>
  168. <el-descriptions-item label="运行时间(天) :">
  169. {{ cache?.info?.uptime_in_days }}
  170. </el-descriptions-item>
  171. <el-descriptions-item label="使用内存 :">
  172. {{ cache?.info?.used_memory_human }}
  173. </el-descriptions-item>
  174. <el-descriptions-item label="使用CPU :">
  175. {{ cache?.info ? parseFloat(cache?.info?.used_cpu_user_children).toFixed(2) : '' }}
  176. </el-descriptions-item>
  177. <el-descriptions-item label="内存配置 :">
  178. {{ cache?.info?.maxmemory_human }}
  179. </el-descriptions-item>
  180. <el-descriptions-item label="AOF是否开启 :">
  181. {{ cache?.info?.aof_enabled == '0' ? '否' : '是' }}
  182. </el-descriptions-item>
  183. <el-descriptions-item label="RDB是否成功 :">
  184. {{ cache?.info?.rdb_last_bgsave_status }}
  185. </el-descriptions-item>
  186. <el-descriptions-item label="Key数量 :">
  187. {{ cache?.dbSize }}
  188. </el-descriptions-item>
  189. <el-descriptions-item label="网络入口/出口 :">
  190. {{ cache?.info?.instantaneous_input_kbps }}kps/
  191. {{ cache?.info?.instantaneous_output_kbps }}kps
  192. </el-descriptions-item>
  193. </el-descriptions>
  194. </el-card>
  195. </el-col>
  196. <el-col :span="12" style="margin-top: 10px">
  197. <el-card :gutter="12" shadow="hover">
  198. <div ref="commandStatsRef" style="height: 350px"></div>
  199. </el-card>
  200. </el-col>
  201. <el-col :span="12" style="margin-top: 10px">
  202. <el-card style="margin-left: 10px" :gutter="12" shadow="hover">
  203. <div ref="usedmemory" style="height: 350px"></div>
  204. </el-card>
  205. </el-col>
  206. </el-row>
  207. <el-row style="margin-top: 10px">
  208. <el-col :span="24" class="card-box" shadow="hover">
  209. <el-card>
  210. <el-table
  211. v-loading="keyListLoad"
  212. :data="keyList"
  213. row-key="id"
  214. @row-click="openKeyTemplate"
  215. >
  216. <el-table-column prop="keyTemplate" label="Key 模板" width="200" />
  217. <el-table-column prop="keyType" label="Key 类型" width="100" />
  218. <el-table-column prop="valueType" label="Value 类型" />
  219. <el-table-column prop="timeoutType" label="超时时间" width="200">
  220. <template #default="{ row }">
  221. <DictTag :type="DICT_TYPE.INFRA_REDIS_TIMEOUT_TYPE" :value="row?.timeoutType" />
  222. <span v-if="row?.timeout > 0">({{ row?.timeout / 1000 }} 秒)</span>
  223. </template>
  224. </el-table-column>
  225. <el-table-column prop="memo" label="备注" />
  226. </el-table>
  227. </el-card>
  228. </el-col>
  229. </el-row>
  230. </el-scrollbar>
  231. <XModal v-model="dialogVisible" :title="keyTemplate + ' 模板'" width="60%" maxHeight="800px">
  232. <el-row>
  233. <el-col :span="14" style="margin-top: 10px">
  234. <el-card shadow="always">
  235. <template #header>
  236. <div class="card-header">
  237. <span>键名列表</span>
  238. </div>
  239. </template>
  240. <el-table :data="cacheKeys" style="width: 100%" @row-click="handleKeyValue">
  241. <el-table-column label="缓存键名" align="center" :show-overflow-tooltip="true">
  242. <template #default="{ row }">
  243. {{ row }}
  244. </template>
  245. </el-table-column>
  246. <el-table-column label="操作" align="right" width="60">
  247. <template #default="{ row }">
  248. <el-button link type="primary" @click="handleDeleteKey(row)">
  249. <Icon icon="ep:delete" />
  250. </el-button>
  251. </template>
  252. </el-table-column>
  253. </el-table>
  254. </el-card>
  255. </el-col>
  256. <el-col :span="10" style="margin-top: 10px">
  257. <el-card shadow="always">
  258. <template #header>
  259. <div class="card-header">
  260. <span>缓存内容</span>
  261. <el-button
  262. link
  263. type="primary"
  264. @click="handleDeleteKeys(keyTemplate)"
  265. style="float: right; padding: 3px 0"
  266. >
  267. <Icon icon="ep:refresh" />清理全部
  268. </el-button>
  269. </div>
  270. </template>
  271. <el-descriptions :column="1">
  272. <el-descriptions-item label="缓存键名:">{{ cacheForm.key }}</el-descriptions-item>
  273. <el-descriptions-item label="缓存内容:">{{ cacheForm.value }}</el-descriptions-item>
  274. </el-descriptions>
  275. </el-card>
  276. </el-col>
  277. </el-row>
  278. </XModal>
  279. </template>
  280. <style scoped>
  281. .redis {
  282. height: 600px;
  283. max-height: 860px;
  284. }
  285. </style>