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 = [
- 选择该观察者可查看的项目。未分配项目的观察者将无法查看任何数据。 + 选择该用户可查看的项目。未分配项目的用户将无法查看任何数据。开发者自己创建的项目会自动获得权限。