From feb305c4547104c624e9e4e9cf8ba19616a12e6d Mon Sep 17 00:00:00 2001 From: zyc <1439655764@qq.com> Date: Tue, 14 Apr 2026 11:33:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=9D=83=E9=99=90):=20=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E8=80=85=E4=B9=9F=E6=94=AF=E6=8C=81=E9=A1=B9=E7=9B=AE=E7=BA=A7?= =?UTF-8?q?=E6=9D=83=E9=99=90=EF=BC=8C=E5=88=9B=E5=BB=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=8E=B7=E5=BE=97=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 开发者与观察者统一逻辑:未分配项目则无法查看数据 - 开发者创建项目时自动获得该项目的查看权限 - 管理员可在用户管理页面为开发者分配项目 Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/src/routes/projects.ts | 14 +++++++++++++- backend/src/services/permissions.ts | 10 +++++----- frontend/src/views/Admin.vue | 6 +++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/backend/src/routes/projects.ts b/backend/src/routes/projects.ts index 23ec65b..4f456fb 100644 --- a/backend/src/routes/projects.ts +++ b/backend/src/routes/projects.ts @@ -3,7 +3,7 @@ import { zValidator } from '@hono/zod-validator'; import { z } from 'zod'; import { v4 as uuid } from 'uuid'; import { db } from '../db/index'; -import { projects, sprintSnapshots, milestones, taskSnapshots, gitCommits, gitPRs, users, objectives, keyResults, projectRepos, krLogs } from '../db/schema'; +import { projects, sprintSnapshots, milestones, taskSnapshots, gitCommits, gitPRs, users, objectives, keyResults, projectRepos, krLogs, userProjectPermissions } from '../db/schema'; import { eq, and, desc, gte, inArray } from 'drizzle-orm'; import { requireRole } from '../middleware/role'; import { AppError } from '../middleware/error-handler'; @@ -44,6 +44,7 @@ projectRoutes.post('/projects', requireRole('admin', 'manager', 'developer'), zValidator('json', createProjectSchema), async (c) => { + const user = c.get('user'); const data = c.req.valid('json'); const id = uuid(); const now = new Date(); @@ -55,6 +56,17 @@ projectRoutes.post('/projects', createdAt: now, updatedAt: now, }); + + // 开发者创建项目时自动获得该项目的查看权限 + if (user.role === 'developer') { + await db.insert(userProjectPermissions).values({ + id: uuid(), + userId: user.sub, + projectId: id, + createdAt: now, + }); + } + return c.json({ code: 0, data: { id }, message: 'success' }, 201); } ); diff --git a/backend/src/services/permissions.ts b/backend/src/services/permissions.ts index e7f5925..026f42a 100644 --- a/backend/src/services/permissions.ts +++ b/backend/src/services/permissions.ts @@ -4,13 +4,13 @@ import { userProjectPermissions } from '../db/schema'; import type { JWTPayload } from '../middleware/auth'; /** - * 获取观察者(viewer)可查看的项目 ID 列表。 - * - viewer 角色:返回 user_project_permissions 中分配的项目 ID 列表 - * - 其他角色:返回 null,表示可查看所有项目 + * 获取用户可查看的项目 ID 列表。 + * - admin / manager:返回 null,表示可查看所有项目 + * - viewer / developer:返回已分配的项目 ID 列表(未分配则为空数组,即无权查看) */ export async function getAllowedProjectIds(user: JWTPayload): Promise { - if (user.role !== 'viewer') { - return null; // 非 viewer,不做项目级过滤 + if (user.role !== 'viewer' && user.role !== 'developer') { + return null; // admin / manager 不做项目级过滤 } const perms = await db.select({ projectId: userProjectPermissions.projectId }) diff --git a/frontend/src/views/Admin.vue b/frontend/src/views/Admin.vue index 8cd9c02..25192e8 100644 --- a/frontend/src/views/Admin.vue +++ b/frontend/src/views/Admin.vue @@ -68,7 +68,7 @@ const userColumns = [ { title: '可查看项目', key: 'allowedProjects', width: 120, render: (row: any) => { - if (row.role !== 'viewer') return '-'; + if (row.role !== 'viewer' && row.role !== 'developer') return '-'; const count = (row.allowedProjectIds || []).length; return count > 0 ? `${count} 个项目` : '未分配'; }, @@ -81,7 +81,7 @@ const userColumns = [ title: '操作', key: 'actions', width: 180, render: (row: any) => { const buttons = []; - if (row.role === 'viewer') { + if (row.role === 'viewer' || row.role === 'developer') { buttons.push(h( NButton, { size: 'tiny', type: 'info', onClick: () => openProjectPermModal(row), style: 'margin-right: 8px' }, @@ -340,7 +340,7 @@ const roleOptions = [
- 选择该观察者可查看的项目。未分配项目的观察者将无法查看任何数据。 + 选择该用户可查看的项目。未分配项目的用户将无法查看任何数据。开发者自己创建的项目会自动获得权限。