R18-4/R21-2: 收口企微脱敏通知与 Portal 搜索摘要
这个提交包含在:
@@ -139,6 +139,9 @@ function buildQuickLinks({ request, featureEnabled }) {
|
||||
if (featureEnabled.todoBoard) {
|
||||
items.push({ key: "todo", title: "待办", href: "/todos" });
|
||||
}
|
||||
if (featureEnabled.projectDomain) {
|
||||
items.push({ key: "projects", title: "项目", href: "/projects" });
|
||||
}
|
||||
if (request.employee.permissionCodes.includes("system.users") || request.employee.permissionCodes.includes("system.settings")) {
|
||||
items.push({ key: "people", title: "人员管理", href: "/people" });
|
||||
items.push({ key: "workspace", title: "工作区设置", href: "/system/workspace" });
|
||||
@@ -186,6 +189,7 @@ async function portalRoutes(fastify) {
|
||||
employeeLifecycle: await evaluateOptionalFlag(fastify, request, FEATURE_FLAG_KEYS.employeeLifecycle),
|
||||
todoBoard: await evaluateOptionalFlag(fastify, request, FEATURE_FLAG_KEYS.todoBoard),
|
||||
paymentBatch: await evaluateOptionalFlag(fastify, request, FEATURE_FLAG_KEYS.paymentBatch),
|
||||
projectDomain: await evaluateOptionalFlag(fastify, request, FEATURE_FLAG_KEYS.projectDomain),
|
||||
};
|
||||
|
||||
const [
|
||||
@@ -202,6 +206,10 @@ async function portalRoutes(fastify) {
|
||||
assetReturnPendingCount,
|
||||
activeEmployeeCount,
|
||||
login7dCount,
|
||||
myProjectCount,
|
||||
overdueProjectMilestoneCount,
|
||||
highPriorityProjectTaskCount,
|
||||
openProjectRiskCount,
|
||||
] = await Promise.all([
|
||||
fastify.prisma.workflowTask.count({ where: { status: "pending", OR: assigneeFilters } }),
|
||||
fastify.prisma.reimbursementForm.count({ where: { OR: [{ owner_id: request.employee.id }, { submitter_id: request.employee.id }] } }),
|
||||
@@ -260,6 +268,69 @@ async function portalRoutes(fastify) {
|
||||
distinct: ["employee_id"],
|
||||
}).then((rows) => rows.length)
|
||||
: Promise.resolve(0),
|
||||
featureEnabled.projectDomain
|
||||
? fastify.prisma.project.count({
|
||||
where: fastify.hasPermission(request.employee, "project.view_all") || fastify.hasPermission(request.employee, "project.manage") || fastify.hasPermission(request.employee, "*")
|
||||
? {}
|
||||
: {
|
||||
OR: [
|
||||
{ owner_employee_id: request.employee.id },
|
||||
{ manager_employee_id: request.employee.id },
|
||||
{ members: { some: { employee_id: request.employee.id, left_at: null } } },
|
||||
],
|
||||
},
|
||||
})
|
||||
: Promise.resolve(0),
|
||||
featureEnabled.projectDomain
|
||||
? fastify.prisma.projectMilestone.count({
|
||||
where: {
|
||||
status: { in: ["pending", "in_progress", "delayed"] },
|
||||
due_date: { lt: new Date() },
|
||||
project: fastify.hasPermission(request.employee, "project.view_all") || fastify.hasPermission(request.employee, "project.manage") || fastify.hasPermission(request.employee, "*")
|
||||
? undefined
|
||||
: {
|
||||
OR: [
|
||||
{ owner_employee_id: request.employee.id },
|
||||
{ manager_employee_id: request.employee.id },
|
||||
{ members: { some: { employee_id: request.employee.id, left_at: null } } },
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
: Promise.resolve(0),
|
||||
featureEnabled.projectDomain
|
||||
? fastify.prisma.projectTask.count({
|
||||
where: {
|
||||
status: { in: ["todo", "doing", "blocked"] },
|
||||
priority: { in: ["high", "urgent"] },
|
||||
project: fastify.hasPermission(request.employee, "project.view_all") || fastify.hasPermission(request.employee, "project.manage") || fastify.hasPermission(request.employee, "*")
|
||||
? undefined
|
||||
: {
|
||||
OR: [
|
||||
{ owner_employee_id: request.employee.id },
|
||||
{ manager_employee_id: request.employee.id },
|
||||
{ members: { some: { employee_id: request.employee.id, left_at: null } } },
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
: Promise.resolve(0),
|
||||
featureEnabled.projectDomain
|
||||
? fastify.prisma.projectRisk.count({
|
||||
where: {
|
||||
status: { not: "closed" },
|
||||
project: fastify.hasPermission(request.employee, "project.view_all") || fastify.hasPermission(request.employee, "project.manage") || fastify.hasPermission(request.employee, "*")
|
||||
? undefined
|
||||
: {
|
||||
OR: [
|
||||
{ owner_employee_id: request.employee.id },
|
||||
{ manager_employee_id: request.employee.id },
|
||||
{ members: { some: { employee_id: request.employee.id, left_at: null } } },
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
: Promise.resolve(0),
|
||||
]);
|
||||
|
||||
const todayPresence = featureEnabled.presenceBoard
|
||||
@@ -328,6 +399,10 @@ async function portalRoutes(fastify) {
|
||||
href: "/workflow/tasks",
|
||||
severity: pendingTaskCount > 0 ? "warning" : "normal",
|
||||
});
|
||||
if (featureEnabled.projectDomain) {
|
||||
cards.push({ key: "project_milestones", title: "逾期里程碑", value: overdueProjectMilestoneCount, href: "/projects", severity: overdueProjectMilestoneCount > 0 ? "warning" : "normal" });
|
||||
cards.push({ key: "project_risks", title: "项目风险", value: openProjectRiskCount, href: "/projects", severity: openProjectRiskCount > 0 ? "high" : "normal" });
|
||||
}
|
||||
} else {
|
||||
cards.push({
|
||||
key: "my_todos",
|
||||
@@ -353,6 +428,9 @@ async function portalRoutes(fastify) {
|
||||
href: "/weekly-reports",
|
||||
severity: myWeeklyReport?.status === "submitted" ? "normal" : "warning",
|
||||
});
|
||||
if (featureEnabled.projectDomain) {
|
||||
cards.push({ key: "my_projects", title: "我的项目", value: myProjectCount, href: "/projects", severity: highPriorityProjectTaskCount > 0 ? "warning" : "normal" });
|
||||
}
|
||||
}
|
||||
|
||||
if (featureEnabled.paymentBatch && riskCount > 0) {
|
||||
@@ -423,6 +501,15 @@ async function portalRoutes(fastify) {
|
||||
href: "/todos",
|
||||
}
|
||||
: null,
|
||||
projectSummary: featureEnabled.projectDomain
|
||||
? {
|
||||
myCount: myProjectCount,
|
||||
overdueMilestonesCount: overdueProjectMilestoneCount,
|
||||
highPriorityTaskCount: highPriorityProjectTaskCount,
|
||||
openRiskCount: openProjectRiskCount,
|
||||
href: "/projects",
|
||||
}
|
||||
: null,
|
||||
peopleLifecycle: featureEnabled.employeeLifecycle && isManagerView
|
||||
? {
|
||||
onboardingCount,
|
||||
|
||||
在新工单中引用
屏蔽一个用户