mirror of
https://github.com/kuaifan/dootask.git
synced 2026-08-13 00:08:32 +00:00
插件应用菜单来自 appstore installed(不含 count/dot),原先只有自定义微 应用经 microapp_menu 注入角标,导致插件角标只能靠实时 WS、刷新即丢。 - 新增 GET api/apps/badge/list(用户 token 鉴权)返回 userBadges 快照 (插件 + 自定义统一覆盖),前端 updateMicroAppsStatus 拉取后 hydrateMap - appBadges store hydrate -> hydrateMap(按角标 map 初始化,不再依赖 menu_items) - 删除已冗余的 Badge::attachMenuBadges(调用 + 方法定义)
137 lines
4.2 KiB
JavaScript
Vendored
137 lines
4.2 KiB
JavaScript
Vendored
import Vue from 'vue'
|
||
|
||
// 无角标时的共享只读对象,避免 badge getter 每次调用都新建对象
|
||
const EMPTY_BADGE = Object.freeze({count: 0, dot: false})
|
||
|
||
/**
|
||
* 应用菜单角标(插件 / 自定义微应用)
|
||
*
|
||
* 结构:map[app_id][menu_key] = { count, dot }
|
||
* - menu_key 为空串表示该应用的第一个菜单
|
||
* - 初始值由 updateMicroAppsStatus 通过 hydrateMap 填充(apps/badge/list 一次返回插件 + 自定义全部角标)
|
||
* - 运行时由 websocket 消息 appBadge 经 set 增量更新
|
||
*/
|
||
export default {
|
||
namespaced: true,
|
||
|
||
state: () => ({
|
||
map: {},
|
||
}),
|
||
|
||
mutations: {
|
||
/**
|
||
* 增量设置单个菜单角标
|
||
* @param state
|
||
* @param appid
|
||
* @param menu_key
|
||
* @param count
|
||
* @param dot
|
||
*/
|
||
set(state, {appid, menu_key, count, dot}) {
|
||
if (!appid) {
|
||
return
|
||
}
|
||
const key = menu_key || ''
|
||
if (!state.map[appid]) {
|
||
Vue.set(state.map, appid, {})
|
||
}
|
||
Vue.set(state.map[appid], key, {
|
||
count: Number(count) || 0,
|
||
dot: !!dot,
|
||
})
|
||
},
|
||
|
||
/**
|
||
* 由后端角标快照整体初始化(apps/badge/list 返回,含插件 + 自定义微应用)
|
||
* @param state
|
||
* @param map 形如 { app_id: { menu_key: {count, dot} } }
|
||
*/
|
||
hydrateMap(state, map) {
|
||
const next = {}
|
||
if (map && typeof map === 'object') {
|
||
Object.keys(map).forEach(appid => {
|
||
const menus = map[appid]
|
||
if (!appid || !menus || typeof menus !== 'object') {
|
||
return
|
||
}
|
||
Object.keys(menus).forEach(key => {
|
||
const item = menus[key] || {}
|
||
const count = Number(item.count) || 0
|
||
const dot = !!item.dot
|
||
if (count > 0 || dot) {
|
||
if (!next[appid]) {
|
||
next[appid] = {}
|
||
}
|
||
next[appid][key || ''] = {count, dot}
|
||
}
|
||
})
|
||
})
|
||
}
|
||
state.map = next
|
||
},
|
||
|
||
/**
|
||
* 清除某应用某菜单的角标
|
||
*/
|
||
clearMenu(state, {appid, menu_key}) {
|
||
const key = menu_key || ''
|
||
if (appid && state.map[appid]) {
|
||
Vue.delete(state.map[appid], key)
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 清除某应用全部角标(卸载/更新时)
|
||
*/
|
||
clearApp(state, appid) {
|
||
if (appid && state.map[appid]) {
|
||
Vue.delete(state.map, appid)
|
||
}
|
||
},
|
||
},
|
||
|
||
getters: {
|
||
/**
|
||
* 取单个菜单角标
|
||
* @returns {function(appid, menuKey): {count, dot}}
|
||
*/
|
||
badge: (state) => (appid, menuKey) => {
|
||
return (state.map[appid] && state.map[appid][menuKey || '']) || EMPTY_BADGE
|
||
},
|
||
|
||
/**
|
||
* 所有应用角标数字之和
|
||
*/
|
||
totalCount: (state) => {
|
||
let total = 0
|
||
Object.keys(state.map).forEach(appid => {
|
||
Object.keys(state.map[appid]).forEach(key => {
|
||
total += Number(state.map[appid][key].count) || 0
|
||
})
|
||
})
|
||
return total
|
||
},
|
||
|
||
/**
|
||
* 是否存在任一红点
|
||
*/
|
||
anyDot: (state) => {
|
||
return Object.keys(state.map).some(appid => {
|
||
return Object.keys(state.map[appid]).some(key => !!state.map[appid][key].dot)
|
||
})
|
||
},
|
||
|
||
/**
|
||
* 父『应用』入口聚合数字:工作报告未读 + 所有插件角标数字之和
|
||
*/
|
||
applicationCount: (state, getters, rootState) => {
|
||
return (Number(rootState.reportUnreadNumber) || 0) + getters.totalCount
|
||
},
|
||
|
||
/**
|
||
* 父『应用』入口聚合红点:总数为 0 时,任一插件存在红点则显示
|
||
*/
|
||
applicationDot: (state, getters) => getters.anyDot,
|
||
},
|
||
}
|