+
+
+
+
+
+
+ {isMemberListExpanded && (
+
+ {(group.members?.length || 0) === 0 ? (
+
当前未配置人员
+ ) : (
+
+ {group.members?.map((member) => {
+ const memberMeta = [member.departmentName, member.positionTitle].filter(Boolean).join(' · ')
+ return (
+ -
+ {member.displayName}
+ {memberMeta && {memberMeta}}
+
+ )
+ })}
+
+ )}
+
+ )}
+
)
})}
diff --git a/lib/__tests__/performance-survey-position-admin.test.ts b/lib/__tests__/performance-survey-position-admin.test.ts
index fa122bf..3405d05 100644
--- a/lib/__tests__/performance-survey-position-admin.test.ts
+++ b/lib/__tests__/performance-survey-position-admin.test.ts
@@ -299,6 +299,54 @@ describe('performance survey position admin', () => {
expect(prisma.performanceSurveyEmployeeProfile.findMany).not.toHaveBeenCalled()
})
+ test('岗位管理配置返回每个岗位的具体人员名单', async () => {
+ ;(prisma.performanceSurveyPositionGroup.findMany as jest.Mock).mockResolvedValue([{
+ id: 'group-creative',
+ code: 'ai_planning_creative',
+ name: 'AI策划-创意部',
+ sortOrder: 10,
+ isActive: true,
+ isSystem: true,
+ archivedAt: null,
+ archiveReason: null,
+ rules: [],
+ plans: [],
+ _count: { surveys: 1, manualAssignments: 1 },
+ }])
+ ;(prisma.performanceSurveyTemplate.findMany as jest.Mock).mockResolvedValue([])
+ ;(prisma.performanceSurveyEmployeeProfile.findMany as jest.Mock).mockResolvedValue([{
+ id: 'employee-ruolan',
+ displayName: '若兰',
+ departmentName: '品牌创意B部',
+ departmentPath: '集团/品牌中心/品牌创意B部',
+ positionTitle: '营销策划主管',
+ departmentMemberships: [],
+ }])
+ ;(prisma.performanceSurveyEmployeePositionAssignment.findMany as jest.Mock).mockResolvedValue([{
+ id: 'assignment-ruolan',
+ employeeProfileId: 'employee-ruolan',
+ assignmentType: 'position',
+ positionGroupId: 'group-creative',
+ status: 'active',
+ startMonth: '2026-07',
+ endMonth: null,
+ createdAt: new Date('2026-07-01T00:00:00.000Z'),
+ }])
+
+ await expect(getPerformanceSurveyPositionAdminConfig('2026-07', 'positions')).resolves.toMatchObject({
+ groups: [{
+ id: 'group-creative',
+ memberCount: 1,
+ members: [{
+ id: 'employee-ruolan',
+ displayName: '若兰',
+ departmentName: '品牌创意B部',
+ positionTitle: '营销策划主管',
+ }],
+ }],
+ })
+ })
+
test('复制模板会创建独立模板和完整草稿版本', async () => {
const definition = structuredClone(DEFAULT_PERFORMANCE_SURVEY_TEMPLATES[0])
;(prisma.performanceSurveyTemplateVersion.findUnique as jest.Mock).mockResolvedValue({
diff --git a/lib/__tests__/performance-survey-service-policy.test.ts b/lib/__tests__/performance-survey-service-policy.test.ts
index 8e0eeef..5777981 100644
--- a/lib/__tests__/performance-survey-service-policy.test.ts
+++ b/lib/__tests__/performance-survey-service-policy.test.ts
@@ -623,7 +623,7 @@ describe('performance survey service policies', () => {
expect(cell.rawMaxTotal).toBe(20)
})
- test('公共看板关系查询继续应用领导组织范围及部门和人员筛选', async () => {
+ test('M级系统管理员查看公共看板时不再叠加领导组织范围', async () => {
;(ensurePerformanceSurveyEmployeeProfileForUser as jest.Mock).mockResolvedValue({
...baseEmployee,
levelType: 'M',
@@ -640,26 +640,14 @@ describe('performance survey service policies', () => {
const employeeWhere = (prisma.performanceSurveyTarget.findMany as jest.Mock).mock.calls[0][0]
.where.employeeProfile.is
- expect(employeeWhere.AND).toEqual(expect.arrayContaining([
- {
- OR: [
- { departmentPath: '集团A/品牌中心/策划部' },
- { departmentPath: { startsWith: '集团A/品牌中心/策划部/' } },
- {
- departmentMemberships: {
- some: {
- OR: [
- { departmentPath: '集团A/品牌中心/策划部' },
- { departmentPath: { startsWith: '集团A/品牌中心/策划部/' } },
- ],
- },
- },
- },
- ],
- },
+ expect(employeeWhere).toEqual({
+ AND: [
+ expect.objectContaining({ OR: expect.any(Array) }),
{ id: 'employee-public' },
- ]))
+ ],
+ })
expect(JSON.stringify(employeeWhere)).toContain('集团A/品牌中心')
+ expect(JSON.stringify(employeeWhere)).not.toContain('集团A/品牌中心/策划部')
expect(getPerformanceSurveyAccountProfileWhere).not.toHaveBeenCalled()
})
diff --git a/lib/performance-survey-position-config.ts b/lib/performance-survey-position-config.ts
index 5fce5df..aaf5436 100644
--- a/lib/performance-survey-position-config.ts
+++ b/lib/performance-survey-position-config.ts
@@ -1043,9 +1043,15 @@ export async function getPerformanceSurveyPositionAdminConfig(
),
}))
const memberCountByGroup = new Map