Browse Source

新增缓存管理界面。修改redis缓存分层级显示

Tony 4 years ago
parent
commit
870f75361d

+ 7 - 7
Admin.NET/Admin.NET.Core/Const/CacheConst.cs

@@ -8,27 +8,27 @@ public class CacheConst
     /// <summary>
     /// 用户缓存
     /// </summary>
-    public const string KeyUser = "user_";
+    public const string KeyUser = "user:";
 
     /// <summary>
     /// 菜单缓存
     /// </summary>
-    public const string KeyMenu = "menu_";
+    public const string KeyMenu = "menu:";
 
     /// <summary>
     /// 权限缓存
     /// </summary>
-    public const string KeyPermission = "permission_";
+    public const string KeyPermission = "permission:";
 
     /// <summary>
     /// 机构Id集合缓存
     /// </summary>
-    public const string KeyOrgIdList = "org_";
+    public const string KeyOrgIdList = "org:";
 
     /// <summary>
     /// 验证码缓存
     /// </summary>
-    public const string KeyVerCode = "verCode_";
+    public const string KeyVerCode = "verCode:";
 
     /// <summary>
     /// 所有缓存关键字集合
@@ -38,12 +38,12 @@ public class CacheConst
     /// <summary>
     /// 定时任务缓存
     /// </summary>
-    public const string KeyTimer = "timer";
+    public const string KeyTimer = "timer:";
 
     /// <summary>
     /// 在线用户缓存
     /// </summary>
-    public const string KeyOnlineUser = "onlineuser";
+    public const string KeyOnlineUser = "onlineuser:";
 
     /// <summary>
     /// 常量下拉框

+ 10 - 7
Admin.NET/Admin.NET.Core/Service/ConstSelector/ConstSelectorService.cs

@@ -6,10 +6,13 @@
 [ApiDescriptionSettings(Name = "常量下拉框", Order = 189)]
 public class ConstSelectorService : IDynamicApiController, ITransient
 {
-    private readonly IDistributedCache _cache;
-    public ConstSelectorService(IDistributedCache cache)
+    //private readonly IDistributedCache _cache;
+    private readonly ISysCacheService _sysCacheService;
+    public ConstSelectorService(IDistributedCache cache,
+        ISysCacheService sysCacheService)
     {
-        _cache = cache;
+        //_cache = cache;
+        _sysCacheService = sysCacheService;
     }
 
     /// <summary>
@@ -21,7 +24,7 @@ public class ConstSelectorService : IDynamicApiController, ITransient
     public async Task<List<SelectorDto>> GetAllConstSelector()
     {
         var key = $"{CacheConst.KeyConstSelector}AllSelector";
-        var json = await _cache.GetStringAsync(key);
+        var json = await _sysCacheService.GetStringAsync(key);
         if (!string.IsNullOrWhiteSpace(json))
         {
             return json.ToObject<List<SelectorDto>>();
@@ -32,7 +35,7 @@ public class ConstSelectorService : IDynamicApiController, ITransient
             Name = x.CustomAttributes.ToList().FirstOrDefault()?.ConstructorArguments.ToList().FirstOrDefault().Value?.ToString() ?? x.Name,
             Code = x.Name
         }).ToList();
-        await _cache.SetStringAsync(key, selectData.ToJson());
+        await _sysCacheService.SetStringAsync(key, selectData.ToJson());
         return selectData;
     }
 
@@ -46,7 +49,7 @@ public class ConstSelectorService : IDynamicApiController, ITransient
     public async Task<List<SelectorDto>> GetConstSelector(string typeName)
     {
         var key = $"{CacheConst.KeyConstSelector}{typeName.ToUpper()}";
-        var json = await _cache.GetStringAsync(key);
+        var json = await _sysCacheService.GetStringAsync(key);
         if (!string.IsNullOrWhiteSpace(json))
         {
             return json.ToObject<List<SelectorDto>>();
@@ -62,7 +65,7 @@ public class ConstSelectorService : IDynamicApiController, ITransient
                 Name = x.Name,
                 Code = isEnum ? (int)x.GetValue(BindingFlags.Instance) : x.GetValue(BindingFlags.Instance)
             }).ToList();
-        await _cache.SetStringAsync(key, selectData.ToJson());
+        await _sysCacheService.SetStringAsync(key, selectData.ToJson());
         return selectData;
     }
 

+ 15 - 0
Vben2/src/api/sys/admin.ts

@@ -137,6 +137,11 @@ enum Api {
   AllConstSelector = '/constSelector/allConstSelector',
   ConstSelector = '/constSelector/constSelector',
   AllConstSelectorWithOptions = '/constSelector/allConstSelectorWithOptions',
+
+  // 缓存接口
+  GetAllCacheKeys = '/sysCache/keyList',
+  GetStringAsync = '/sysCache/detail',
+  RemoveAsync = '/sysCache/remove',
 }
 
 ////////// 账号管理接口 //////////
@@ -437,3 +442,13 @@ export const getConstSelector = (typeName?: string) =>
 // 获取所有下拉框及选项
 export const getAllConstSelectorWithOptions = () =>
   defHttp.get<any>({ url: Api.AllConstSelectorWithOptions });
+
+////////// 缓存管理接口 //////////
+// 获取所有缓存列表
+export const getAllCacheKeys = () => defHttp.get<any>({ url: Api.GetAllCacheKeys });
+// 根据类名获取下拉框数据
+export const getCacheStringAsync = (cacheKey?: string) =>
+  defHttp.get<any>({ url: Api.GetStringAsync, params: { cacheKey } });
+// 获取所有下拉框及选项
+export const removeCacheAsync = (key?: string) =>
+  defHttp.get<any>({ url: Api.RemoveAsync, params: { key } });

+ 172 - 0
Vben2/src/views/sys/admin/cache/index.vue

@@ -0,0 +1,172 @@
+<template>
+  <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
+    <div class="m-4 mr-0 overflow-hidden bg-white w-1/4 xl:w-1/5" style="overflow: auto">
+      <BasicTree
+        title="缓存键列表"
+        toolbar
+        search
+        :clickRowToExpand="true"
+        :treeData="treeData"
+        :fieldNames="{ key: 'key', title: 'name' }"
+        @select="handleSelect"
+        ref="treeAction"
+      />
+    </div>
+    <div class="w-3/4 xl:w-4/5 m-4">
+      <div class="bg-white h-full">
+        <div class="p-4 text-right flex">
+          <div class="flex-1 text-left leading-8 font-300 text-lg">
+            当前键:{{ currentNode.key }}
+          </div>
+          <PopConfirmButton
+            title="确定要删除此缓存吗?"
+            ok-text="删除"
+            cancel-text="取消"
+            @confirm="onDeleteCache"
+            v-if="currentNode && currentNode.pid"
+            color="warning"
+          >
+            删除此缓存
+          </PopConfirmButton>
+          <PopConfirmButton
+            title="确定要清空此缓存吗?"
+            ok-text="删除"
+            cancel-text="取消"
+            @confirm="onEmptyCache"
+            v-if="currentNode && currentNode.pid == 0"
+            color="error"
+          >
+            清空此缓存
+          </PopConfirmButton>
+        </div>
+        <ScrollContainer ref="scrollRef" style="height: calc(100% - 64px)">
+          <div class="p-4 pt-0">
+            <JsonPreview v-if="isJson" :data="jsonData" />
+            <div v-else>{{ jsonData }}</div>
+          </div>
+        </ScrollContainer>
+      </div>
+    </div>
+  </PageWrapper>
+</template>
+<script lang="ts">
+  import { defineComponent, ref } from 'vue';
+  import { usePermission } from '/@/hooks/web/usePermission';
+  import { PageWrapper } from '/@/components/Page';
+  import { PopConfirmButton } from '/@/components/Button';
+
+  import { getAllCacheKeys, getCacheStringAsync, removeCacheAsync } from '/@/api/sys/admin';
+  import { BasicTree, TreeActionType, TreeItem } from '/@/components/Tree/index';
+  import { JsonPreview } from '/@/components/CodeEditor';
+  import { ScrollContainer } from '/@/components/Container/index';
+  import { useLoading } from '/@/components/Loading';
+
+  export default defineComponent({
+    name: 'OrgManagement',
+    components: {
+      PageWrapper,
+      BasicTree,
+      JsonPreview,
+      ScrollContainer,
+      PopConfirmButton,
+    },
+    setup() {
+      const { hasPermission } = usePermission();
+
+      const treeData = ref<TreeItem[]>([]);
+      const treeAction = ref<Nullable<TreeActionType>>(null);
+      const jsonData = ref<any>('');
+      const isJson = ref(true);
+      const currentNode = ref<any>({});
+      const [openFullLoading, closeFullLoading] = useLoading({
+        tip: '请稍后...',
+      });
+
+      async function fetch() {
+        let keys = await getAllCacheKeys();
+        let cacheData: any[] = [];
+        for (let i = 0; i < keys.length; i++) {
+          let keyArr = keys[i].split(':');
+          let p = keyArr[0];
+          let parentKey = keyArr.length > 0 ? `${p}:` : p;
+          if (cacheData.filter((x) => x.key == parentKey).length === 0) {
+            cacheData.push({
+              pid: 0,
+              children: [],
+              name: p,
+              key: parentKey,
+            });
+          }
+          if (keyArr.length > 1) {
+            let parent = cacheData.filter((x) => x.key == parentKey)[0] || {};
+            parent.children.push({
+              pid: p,
+              name: keyArr[1],
+              key: keys[i],
+            });
+          }
+        }
+        treeData.value = cacheData;
+        console.log(treeData);
+      }
+
+      async function handleSelect(keys, obj) {
+        if (obj == undefined || keys.length == 0) return;
+        console.log('select', keys[0], obj.selectedNodes[0]);
+        currentNode.value = obj.selectedNodes[0];
+
+        if ((currentNode.value?.pid || 0) == 0) {
+          jsonData.value = '';
+          isJson.value = false;
+          return;
+        }
+
+        var res = await getCacheStringAsync(keys[0]);
+        try {
+          jsonData.value = JSON.parse(res);
+          isJson.value = true;
+        } catch (error) {
+          isJson.value = false;
+          jsonData.value = res;
+        }
+      }
+
+      async function onDeleteCache() {
+        openFullLoading();
+        await removeCacheAsync(currentNode.value.key);
+        closeFullLoading();
+        currentNode.value = {};
+        isJson.value = false;
+        jsonData.value = '';
+        fetch();
+      }
+
+      async function onEmptyCache() {
+        openFullLoading();
+        for (let i = 0; i < currentNode.value.children.length; i++) {
+          const e = currentNode.value.children[i];
+          await removeCacheAsync(e.key);
+        }
+        closeFullLoading();
+        currentNode.value = {};
+        isJson.value = false;
+        jsonData.value = '';
+        fetch();
+      }
+
+      fetch();
+
+      return {
+        treeData,
+        treeAction,
+        jsonData,
+        hasPermission,
+        handleSelect,
+        isJson,
+        currentNode,
+        onDeleteCache,
+        onEmptyCache,
+      };
+    },
+  });
+</script>