消息角标开发
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -21,4 +21,4 @@ src/.umi-production/
|
||||
EMBED_INTEGRATION.md
|
||||
embed-debug.html
|
||||
sdk_dist
|
||||
package-lock.json
|
||||
package-lock.json
|
||||
|
||||
12
src/app.tsx
12
src/app.tsx
@@ -20,15 +20,23 @@ import {
|
||||
patchRouteWithRemoteMenus,
|
||||
setRemoteMenu,
|
||||
} from './services/session';
|
||||
import {
|
||||
fetchAndUpdateBadge,
|
||||
patchMenuBadge,
|
||||
clearBadgeCount,
|
||||
} from './services/Management/interviewBadge';
|
||||
import { PageEnum } from './enums/pagesEnums';
|
||||
import { stringify } from 'querystring';
|
||||
import { message } from 'antd';
|
||||
import React from 'react';
|
||||
import { getProductionApiBaseUrl } from './utils/publicUrl';
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
const loginOut = async () => {
|
||||
clearSessionToken();
|
||||
setRemoteMenu(null);
|
||||
clearBadgeCount();
|
||||
const { search, pathname } = window.location;
|
||||
const urlParams = new URL(window.location.href).searchParams;
|
||||
/** 此方法会跳转到 redirect 参数所在的位置 */
|
||||
@@ -112,6 +120,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
|
||||
// content: initialState?.currentUser?.nickName,
|
||||
},
|
||||
// actionRef: layoutActionRef,
|
||||
postMenuData: (menuData: any[]) => patchMenuBadge(menuData),
|
||||
menu: {
|
||||
locale: false,
|
||||
// // 每当 initialState?.currentUser?.userid 发生修改时重新执行 request
|
||||
@@ -122,7 +131,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
|
||||
if (!initialState?.currentUser?.userId) {
|
||||
return [];
|
||||
}
|
||||
return getRemoteMenu();
|
||||
return getRemoteMenu() || [];
|
||||
},
|
||||
},
|
||||
footerRender: () => <Footer />,
|
||||
@@ -254,6 +263,7 @@ export async function render(oldRender: () => void) {
|
||||
try {
|
||||
const routers = await getRoutersInfo();
|
||||
setRemoteMenu(routers);
|
||||
await fetchAndUpdateBadge();
|
||||
} catch (error) {
|
||||
console.error('获取路由失败:', error);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useRef } from 'react';
|
||||
import { Tag } from 'antd';
|
||||
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
|
||||
import { getCmsInterviewList } from '@/services/Management/list';
|
||||
import { fetchAndUpdateBadge } from '@/services/Management/interviewBadge';
|
||||
|
||||
const interviewStatusMap: Record<string, { text: string; color: string }> = {
|
||||
pending: { text: '待确认', color: 'blue' },
|
||||
@@ -134,6 +135,7 @@ const InterviewList: React.FC = () => {
|
||||
pageNum: current,
|
||||
pageSize,
|
||||
});
|
||||
fetchAndUpdateBadge();
|
||||
return {
|
||||
data: response.rows || [],
|
||||
total: response.total || 0,
|
||||
|
||||
72
src/services/Management/interviewBadge.tsx
Normal file
72
src/services/Management/interviewBadge.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { getInterviewBadgeCount } from './list';
|
||||
|
||||
let badgeCount = 0;
|
||||
let subscribers: Array<(count: number) => void> = [];
|
||||
|
||||
/** 获取当前角标数量 */
|
||||
export function getBadgeCount(): number {
|
||||
return badgeCount;
|
||||
}
|
||||
|
||||
/** 订阅角标数量变化,返回取消订阅函数 */
|
||||
export function subscribeBadgeCount(fn: (count: number) => void): () => void {
|
||||
subscribers.push(fn);
|
||||
return () => {
|
||||
subscribers = subscribers.filter((s) => s !== fn);
|
||||
};
|
||||
}
|
||||
|
||||
function notifySubscribers() {
|
||||
subscribers.forEach((fn) => fn(badgeCount));
|
||||
}
|
||||
|
||||
/** 从接口获取并更新角标数量 */
|
||||
export async function fetchAndUpdateBadge() {
|
||||
try {
|
||||
const res = await getInterviewBadgeCount();
|
||||
if (res.code === 200 && res.data) {
|
||||
badgeCount = (res.data.jss ?? 0) + (res.data.jjs ?? 0);
|
||||
notifySubscribers();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取面试角标失败', e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 清除角标数量(退出登录时) */
|
||||
export function clearBadgeCount() {
|
||||
badgeCount = 0;
|
||||
notifySubscribers();
|
||||
}
|
||||
|
||||
/** 递归遍历菜单树,给面试列表菜单项的 name 注入红色角标 JSX */
|
||||
export function patchMenuBadge(menuData: any[]): any[] {
|
||||
if (!menuData) return menuData;
|
||||
return menuData.map((item: any) => {
|
||||
const patched: any = { ...item };
|
||||
if (item.path === 'interview-list' || (item.path && item.path.endsWith('/interview-list'))) {
|
||||
const originalName = item._originalName || item.name;
|
||||
patched._originalName = originalName;
|
||||
if (badgeCount > 0) {
|
||||
patched.name = (
|
||||
<span style={{ whiteSpace: 'nowrap' }}>
|
||||
{originalName}
|
||||
<span style={{ color: '#ff4d4f', fontWeight: 500, marginLeft: 4 }}>
|
||||
({badgeCount})
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
patched.name = originalName;
|
||||
}
|
||||
}
|
||||
if (item.routes) {
|
||||
patched.routes = patchMenuBadge(item.routes);
|
||||
}
|
||||
if (item.children) {
|
||||
patched.children = patchMenuBadge(item.children);
|
||||
}
|
||||
return patched;
|
||||
});
|
||||
}
|
||||
@@ -155,3 +155,16 @@ export async function getAppSkillList(params?: { userId?: number }) {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 面试消息角标 APIs ==========
|
||||
|
||||
/** 获取面试消息角标数量(后台管理端菜单角标) */
|
||||
export async function getInterviewBadgeCount() {
|
||||
return request<{
|
||||
msg: string;
|
||||
code: number;
|
||||
data: { total: number; jss: number; jjs: number };
|
||||
}>('/api/cms/interview/msyyhbs', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user