更新缓存和文件分类

This commit is contained in:
李志强 2025-11-06 17:12:13 +08:00
parent 873a2e297a
commit f4244c09b9
6 changed files with 171 additions and 23 deletions

View File

@ -103,23 +103,62 @@ const activeBgColor = computed(() => {
// //
const transformMenuData = (menus) => { const transformMenuData = (menus) => {
// if (!menus || menus.length === 0) {
const functionPageKeywords = ['/detail', '/add', '/edit', '/delete', '/create', '/update', '/category', '/tag']; console.warn('菜单数据为空');
return [];
}
// console.log('原始菜单数据:', menus);
//
//
const functionPageKeywords = ['/detail', '/add', '/edit', '/delete', '/create', '/update'];
//
const hiddenSubMenuPaths = ['/apps/knowledge/category', '/apps/knowledge/tag'];
//
const isFunctionPage = (path) => { const isFunctionPage = (path) => {
if (!path) return false; if (!path) return false;
const lowerPath = path.toLowerCase(); const lowerPath = path.toLowerCase();
return functionPageKeywords.some(keyword => lowerPath.includes(keyword)); //
// /apps/knowledge/detail
// /apps/knowledge
return functionPageKeywords.some(keyword => {
// /keyword/ /keyword
return lowerPath.endsWith(keyword) ||
lowerPath.includes(`/${keyword}/`) ||
lowerPath.endsWith(`/${keyword}`);
});
};
//
const isHiddenSubMenu = (path) => {
if (!path) return false;
const lowerPath = path.toLowerCase();
return hiddenSubMenuPaths.some(hiddenPath => {
return lowerPath === hiddenPath || lowerPath.startsWith(hiddenPath + '/');
});
}; };
// menu_type=1 // menu_type=1
const allMenus = menus const allMenus = menus
.filter(menu => { .filter(menu => {
// API // API
if (menu.menuType !== 1) return false; if (menu.menuType !== 1 && menu.menuType !== undefined) {
// console.log('过滤掉非页面菜单:', menu);
if (isFunctionPage(menu.path)) return false; return false;
}
//
if (isFunctionPage(menu.path)) {
console.log('过滤掉功能页面:', menu.path);
return false;
}
//
if (isHiddenSubMenu(menu.path)) {
console.log('过滤掉隐藏的子菜单:', menu.path);
return false;
}
return true; return true;
}) })
.map(menu => ({ .map(menu => ({
@ -133,16 +172,19 @@ const transformMenuData = (menus) => {
children: [] children: []
})); }));
console.log('过滤后的菜单数据:', allMenus);
// //
const menuMap = new Map(); const menuMap = new Map();
allMenus.forEach(menu => { allMenus.forEach(menu => {
menuMap.set(menu.id, menu); menuMap.set(menu.id, menu);
}); });
// //
//
const rootMenus = []; const rootMenus = [];
allMenus.forEach(menu => { allMenus.forEach(menu => {
if (menu.parentId === 0) { if (menu.parentId === 0 || !menu.parentId) {
// //
rootMenus.push(menu); rootMenus.push(menu);
} else { } else {
@ -154,10 +196,16 @@ const transformMenuData = (menus) => {
parent.children = []; parent.children = [];
} }
parent.children.push(menu); parent.children.push(menu);
} else {
//
//
console.warn('菜单的父菜单不存在将作为根菜单显示。菜单ID:', menu.id, '父菜单ID:', menu.parentId, '菜单路径:', menu.path);
rootMenus.push(menu);
} }
// menu_type=2
} }
}); });
console.log('构建后的菜单树:', rootMenus);
// order // order
const sortMenus = (menus) => { const sortMenus = (menus) => {

View File

@ -193,6 +193,33 @@ const handleCommand = async (command) => {
// //
menuStore.resetMenus(); menuStore.resetMenus();
// menu_cache_
const menuCacheKeys: string[] = [];
// localStorage
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key && key.startsWith('menu_cache_')) {
menuCacheKeys.push(key);
}
}
// localStorage menu_cache_
menuCacheKeys.forEach(key => {
localStorage.removeItem(key);
});
// sessionStorage
const sessionMenuCacheKeys: string[] = [];
for (let i = 0; i < sessionStorage.length; i++) {
const key = sessionStorage.key(i);
if (key && key.startsWith('menu_cache_')) {
sessionMenuCacheKeys.push(key);
}
}
// sessionStorage menu_cache_
sessionMenuCacheKeys.forEach(key => {
sessionStorage.removeItem(key);
});
// tabs store // tabs store
const { useTabsStore } = await import('@/stores'); const { useTabsStore } = await import('@/stores');
const tabsStore = useTabsStore(); const tabsStore = useTabsStore();

View File

@ -26,21 +26,17 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="description" label="描述" min-width="250" show-overflow-tooltip /> <el-table-column prop="description" label="描述" min-width="250" show-overflow-tooltip />
<el-table-column prop="file_count" label="文件数量" width="120" sortable> <el-table-column prop="file_count" label="文件数量" width="120" sortable align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-badge :value="row.file_count || 0" :max="999" class="item"> <span>{{ row.file_count || 0 }} </span>
<el-button size="small" text type="primary">
{{ row.file_count || 0 }} 个文件
</el-button>
</el-badge>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="sort_order" label="排序" width="100" sortable> <el-table-column prop="sort_order" label="排序" width="100" sortable align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-tag type="info">{{ row.sort_order || 0 }}</el-tag> <el-tag type="info">{{ row.sort_order || 0 }}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="状态" width="100"> <el-table-column label="状态" width="100" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-switch <el-switch
v-model="row.status" v-model="row.status"
@ -51,7 +47,7 @@
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="180" fixed="right"> <el-table-column label="操作" width="180" fixed="right" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-button size="small" type="primary" @click="editCategory(row)"> <el-button size="small" type="primary" @click="editCategory(row)">
编辑 编辑

View File

@ -51,7 +51,7 @@
详情 详情
</el-button> </el-button>
<el-button <el-button
v-if="row.roleCode !== 'system_admin' && row.roleCode !== 'admin' && row.roleCode !== 'user'" v-if="row.default !== 1 && row.default !== 2"
size="small" size="small"
type="primary" type="primary"
link link
@ -60,7 +60,7 @@
编辑 编辑
</el-button> </el-button>
<el-button <el-button
v-if="row.roleCode !== 'system_admin' && row.roleCode !== 'admin' && row.roleCode !== 'user'" v-if="row.default !== 1 && row.default !== 2"
size="small" size="small"
type="danger" type="danger"
link link

View File

@ -127,9 +127,19 @@ func (c *RoleController) GetRoleByTenantId() {
return return
} }
// 获取当前登录用户类型从JWT中间件获取
userType, _ := c.Ctx.Input.GetData("userType").(string)
isEmployee := userType == "employee"
// 转换为前端需要的格式,确保包含 tenantId 和 default 字段 // 转换为前端需要的格式,确保包含 tenantId 和 default 字段
// 如果是租户登录employee过滤掉 default=1 的角色
roleList := make([]map[string]interface{}, 0) roleList := make([]map[string]interface{}, 0)
for _, role := range roles { for _, role := range roles {
// 如果是租户登录,且角色的 default=1则跳过不显示
if isEmployee && role.Default == 1 {
continue
}
roleList = append(roleList, map[string]interface{}{ roleList = append(roleList, map[string]interface{}{
"roleId": role.RoleId, "roleId": role.RoleId,
"tenantId": role.TenantId, "tenantId": role.TenantId,

View File

@ -99,6 +99,7 @@ func DeleteMenu(id int) error {
} }
// GetTenantMenus 根据角色ID获取租户菜单只返回该角色有权限的菜单且只返回页面菜单menu_type=1 // GetTenantMenus 根据角色ID获取租户菜单只返回该角色有权限的菜单且只返回页面菜单menu_type=1
// 注意:会自动包含所有父菜单,即使父菜单不在权限列表中
func GetTenantMenus(roleId int) ([]map[string]interface{}, error) { func GetTenantMenus(roleId int) ([]map[string]interface{}, error) {
o := orm.NewOrm() o := orm.NewOrm()
@ -141,7 +142,73 @@ func GetTenantMenus(roleId int) ([]map[string]interface{}, error) {
return nil, err return nil, err
} }
// 4. 转换为map格式 // 4. 收集所有需要查询的父菜单ID递归查找所有父菜单
parentIds := make(map[int]bool)
var findParents func(pid int)
findParents = func(pid int) {
if pid == 0 || parentIds[pid] {
return
}
parentIds[pid] = true
// 查询父菜单
var parentMenu Menu
err := o.Raw("SELECT id, parent_id FROM yz_menus WHERE id = ? AND delete_time IS NULL AND menu_type = 1", pid).QueryRow(&parentMenu.Id, &parentMenu.ParentId)
if err == nil && parentMenu.Id > 0 {
// 继续查找父菜单的父菜单
if parentMenu.ParentId > 0 {
findParents(parentMenu.ParentId)
}
}
}
// 为每个菜单查找其父菜单
for _, m := range menus {
if m.ParentId > 0 {
findParents(m.ParentId)
}
}
// 5. 如果存在父菜单,查询所有父菜单
if len(parentIds) > 0 {
parentIdList := make([]int, 0, len(parentIds))
for pid := range parentIds {
parentIdList = append(parentIdList, pid)
}
// 构建父菜单查询
parentPlaceholders := make([]string, len(parentIdList))
parentArgs := make([]interface{}, len(parentIdList)+1)
for i, id := range parentIdList {
parentPlaceholders[i] = "?"
parentArgs[i] = id
}
parentArgs[len(parentIdList)] = 1 // menu_type=1
parentQuery := "SELECT id, name, path, parent_id, icon, `order`, status, component_path, is_external, external_url, menu_type, permission " +
"FROM yz_menus " +
"WHERE id IN (" + strings.Join(parentPlaceholders, ",") + ") " +
"AND delete_time IS NULL " +
"AND menu_type = ? " +
"ORDER BY `order`, id"
var parentMenus []*Menu
_, err = o.Raw(parentQuery, parentArgs...).QueryRows(&parentMenus)
if err == nil && len(parentMenus) > 0 {
// 将父菜单添加到结果中(去重)
menuMap := make(map[int]*Menu)
for _, m := range menus {
menuMap[m.Id] = m
}
for _, pm := range parentMenus {
if _, exists := menuMap[pm.Id]; !exists {
menus = append(menus, pm)
menuMap[pm.Id] = pm
}
}
}
}
// 6. 转换为map格式
result := make([]map[string]interface{}, 0, len(menus)) result := make([]map[string]interface{}, 0, len(menus))
for _, m := range menus { for _, m := range menus {
item := map[string]interface{}{ item := map[string]interface{}{