| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- import { advanceApi, paymentApi, reimburseApi } from '@/api/bx'
- import { menuBadgeApi } from '@/api/pl'
- import { fetchPendingTasks } from '@/api/workflow'
- import {
- MENU_BADGE_CODES,
- MENU_BADGE_CODE_SET,
- PL_MENU_BADGE_CODES,
- type MenuBadgeCode
- } from '@/constants/menu-badge-codes'
- import { useMenuBadgeStore } from '@/store/modules/menu-badge'
- import { useMenuStore } from '@/store/modules/menu'
- import type { AppRouteRecord } from '@/types/router'
- function unwrapData<T = any>(res: unknown): T {
- return ((res as any)?.data ?? res) as T
- }
- /** 从侧栏菜单树收集 menuCode */
- export function collectMenuCodes(items: AppRouteRecord[]): Set<string> {
- const codes = new Set<string>()
- const walk = (list: AppRouteRecord[]) => {
- for (const item of list) {
- const code = String(item.meta?.menuCode || '').trim()
- if (code) codes.add(code)
- if (item.children?.length) walk(item.children)
- }
- }
- walk(items || [])
- return codes
- }
- /** 解析菜单项是否绑定数字角标 */
- export function resolveMenuBadgeCode(item: AppRouteRecord): MenuBadgeCode | undefined {
- const code = String(item.meta?.menuCode || '').trim()
- if (code && MENU_BADGE_CODE_SET.has(code)) {
- return code as MenuBadgeCode
- }
- const name = String(item.name || '')
- if (name === 'PlDocumentReminder') return MENU_BADGE_CODES.PL_DOCUMENT_REMINDER
- const path = String(item.path || '')
- if (path.endsWith('/document-reminder') || path === 'document-reminder') {
- return MENU_BADGE_CODES.PL_DOCUMENT_REMINDER
- }
- return undefined
- }
- export function resolveMenuBadgeText(item: AppRouteRecord, menuOpen = false): string {
- const badgeStore = useMenuBadgeStore()
- if (!badgeStore.loaded) return ''
- const menuCode = resolveMenuBadgeCode(item)
- if (menuCode) {
- return badgeStore.getBadgeText(menuCode)
- }
- const staticBadge = item.meta?.showTextBadge
- if (staticBadge && menuOpen) {
- return String(staticBadge)
- }
- return ''
- }
- function pickPlCodes(codes: Set<string>): string[] {
- return PL_MENU_BADGE_CODES.filter((code) => codes.has(code))
- }
- async function refreshPlMenuBadges(codes: Set<string>) {
- const badgeStore = useMenuBadgeStore()
- const plCodes = pickPlCodes(codes)
- if (!plCodes.length) {
- badgeStore.clearCounts([...PL_MENU_BADGE_CODES])
- return
- }
- try {
- const res = await menuBadgeApi.stats(plCodes)
- const data = unwrapData<{ counts?: Record<string, number> }>(res)
- badgeStore.setCounts(data?.counts || {})
- } catch {
- const zero: Record<string, number> = {}
- plCodes.forEach((code) => {
- zero[code] = 0
- })
- badgeStore.setCounts(zero)
- }
- }
- async function refreshBxApproveBadges(codes: Set<string>) {
- const badgeStore = useMenuBadgeStore()
- const needAdvance =
- codes.has(MENU_BADGE_CODES.BX_ADVANCE_APPROVE) || codes.has(MENU_BADGE_CODES.BX_VIEW_TODO)
- const needReimburse =
- codes.has(MENU_BADGE_CODES.BX_REIMBURSE_APPROVE) || codes.has(MENU_BADGE_CODES.BX_VIEW_TODO)
- let advancePending = 0
- let reimbursePending = 0
- const tasks: Promise<void>[] = []
- if (needAdvance) {
- tasks.push(
- advanceApi.pendingApprovalStats().then((res) => {
- const d = unwrapData(res)
- advancePending = Number(d?.pendingTotal ?? 0)
- if (codes.has(MENU_BADGE_CODES.BX_ADVANCE_APPROVE)) {
- badgeStore.setCount(MENU_BADGE_CODES.BX_ADVANCE_APPROVE, advancePending)
- }
- })
- )
- } else {
- badgeStore.clearCounts([MENU_BADGE_CODES.BX_ADVANCE_APPROVE])
- }
- if (needReimburse) {
- tasks.push(
- reimburseApi.pendingApprovalStats().then((res) => {
- const d = unwrapData(res)
- reimbursePending = Number(d?.pendingTotal ?? 0)
- if (codes.has(MENU_BADGE_CODES.BX_REIMBURSE_APPROVE)) {
- badgeStore.setCount(MENU_BADGE_CODES.BX_REIMBURSE_APPROVE, reimbursePending)
- }
- })
- )
- } else {
- badgeStore.clearCounts([MENU_BADGE_CODES.BX_REIMBURSE_APPROVE])
- }
- await Promise.allSettled(tasks)
- if (codes.has(MENU_BADGE_CODES.BX_VIEW_TODO)) {
- badgeStore.setCount(MENU_BADGE_CODES.BX_VIEW_TODO, advancePending + reimbursePending)
- } else {
- badgeStore.clearCounts([MENU_BADGE_CODES.BX_VIEW_TODO])
- }
- }
- async function refreshBxFinanceBadges(codes: Set<string>) {
- const badgeStore = useMenuBadgeStore()
- const tasks: Promise<void>[] = []
- if (codes.has(MENU_BADGE_CODES.BX_ADVANCE_ISSUE)) {
- tasks.push(
- paymentApi.advanceIssueStats().then((res) => {
- const d = unwrapData(res)
- badgeStore.setCount(MENU_BADGE_CODES.BX_ADVANCE_ISSUE, Number(d?.pendingCount ?? 0))
- })
- )
- } else {
- badgeStore.clearCounts([MENU_BADGE_CODES.BX_ADVANCE_ISSUE])
- }
- if (codes.has(MENU_BADGE_CODES.BX_PAYMENT)) {
- tasks.push(
- paymentApi.financeStats().then((res) => {
- const d = unwrapData(res)
- badgeStore.setCount(MENU_BADGE_CODES.BX_PAYMENT, Number(d?.pendingCount ?? 0))
- })
- )
- } else {
- badgeStore.clearCounts([MENU_BADGE_CODES.BX_PAYMENT])
- }
- await Promise.allSettled(tasks)
- }
- async function refreshWorkflowPendingBadge(codes: Set<string>) {
- const badgeStore = useMenuBadgeStore()
- if (!codes.has(MENU_BADGE_CODES.WORKFLOW_PENDING)) {
- badgeStore.clearCounts([MENU_BADGE_CODES.WORKFLOW_PENDING])
- return
- }
- try {
- const res = await fetchPendingTasks({ page: 1, pageSize: 1 })
- const data = unwrapData<{ total?: number }>(res)
- badgeStore.setCount(MENU_BADGE_CODES.WORKFLOW_PENDING, Number(data?.total ?? 0))
- } catch {
- badgeStore.setCount(MENU_BADGE_CODES.WORKFLOW_PENDING, 0)
- }
- }
- /** 按当前用户可见菜单刷新全部数字角标 */
- export async function refreshMenuBadges(menuList?: AppRouteRecord[]) {
- const menuStore = useMenuStore()
- const badgeStore = useMenuBadgeStore()
- const codes = collectMenuCodes(menuList ?? menuStore.menuList)
- if (!codes.size) {
- badgeStore.clearCounts()
- return
- }
- await Promise.allSettled([
- refreshPlMenuBadges(codes),
- refreshBxApproveBadges(codes),
- refreshBxFinanceBadges(codes),
- refreshWorkflowPendingBadge(codes)
- ])
- badgeStore.markLoaded()
- }
- /** @deprecated 请使用 refreshMenuBadges */
- export async function refreshPlDocumentMenuBadges() {
- await refreshMenuBadges()
- }
|