diff --git a/backend/models.py b/backend/models.py
index 372ee7a..f0a8ee9 100644
--- a/backend/models.py
+++ b/backend/models.py
@@ -13,7 +13,11 @@ import enum
ALL_PERMISSIONS = [
# 仪表盘
- ("dashboard:view", "查看仪表盘", "仪表盘"),
+ ("dashboard:view", "查看仪表盘(基础)", "仪表盘"),
+ ("dashboard:view_cost", "查看成本模块", "仪表盘"),
+ ("dashboard:view_waste", "查看损耗模块", "仪表盘"),
+ ("dashboard:view_profit", "查看盈亏模块", "仪表盘"),
+ ("dashboard:view_risk", "查看风险预警", "仪表盘"),
# 项目管理
("project:view", "查看项目", "项目管理"),
("project:create", "创建项目", "项目管理"),
@@ -38,6 +42,7 @@ ALL_PERMISSIONS = [
("cost_labor:create", "录入人力调整", "成本管理"),
# 用户与角色
("user:view", "查看用户列表", "用户与角色"),
+ ("user:view_cost", "查看成员薪资成本", "用户与角色"),
("user:manage", "管理用户", "用户与角色"),
("role:manage", "管理角色", "用户与角色"),
# 结算与效率
@@ -66,7 +71,7 @@ BUILTIN_ROLES = {
"主管": {
"description": "管理项目和成本,不可管理用户和角色",
"permissions": [
- "dashboard:view",
+ "dashboard:view", "dashboard:view_cost", "dashboard:view_waste", "dashboard:view_profit", "dashboard:view_risk",
"project:view", "project:create", "project:edit", "project:complete",
"submission:view", "submission:create",
"cost_ai:view", "cost_ai:create", "cost_ai:delete",
diff --git a/backend/routers/users.py b/backend/routers/users.py
index c03916d..9df766d 100644
--- a/backend/routers/users.py
+++ b/backend/routers/users.py
@@ -10,27 +10,32 @@ from auth import get_current_user, hash_password, require_permission
router = APIRouter(prefix="/api/users", tags=["用户管理"])
-def user_to_out(u: User) -> UserOut:
+def user_to_out(u: User, hide_cost: bool = False) -> UserOut:
return UserOut(
id=u.id, username=u.username, name=u.name,
phase_group=u.phase_group.value if hasattr(u.phase_group, 'value') else u.phase_group,
role_id=u.role_id, role_name=u.role_name, permissions=u.permissions,
- monthly_salary=u.monthly_salary,
- bonus=u.bonus or 0,
- social_insurance=u.social_insurance or 0,
- monthly_total_cost=u.monthly_total_cost,
- daily_cost=u.daily_cost,
+ monthly_salary=0 if hide_cost else u.monthly_salary,
+ bonus=0 if hide_cost else (u.bonus or 0),
+ social_insurance=0 if hide_cost else (u.social_insurance or 0),
+ monthly_total_cost=0 if hide_cost else u.monthly_total_cost,
+ daily_cost=0 if hide_cost else u.daily_cost,
is_active=u.is_active, created_at=u.created_at,
)
+def _can_view_cost(user: User) -> bool:
+ return "user:view_cost" in (user.permissions or [])
+
+
@router.get("", response_model=List[UserOut])
def list_users(
db: Session = Depends(get_db),
current_user: User = Depends(require_permission("user:view"))
):
+ hide = not _can_view_cost(current_user)
users = db.query(User).order_by(User.created_at.desc()).all()
- return [user_to_out(u) for u in users]
+ return [user_to_out(u, hide_cost=hide) for u in users]
@router.post("", response_model=UserOut)
@@ -95,4 +100,5 @@ def get_user(
user = db.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="用户不存在")
- return user_to_out(user)
+ hide = not _can_view_cost(current_user)
+ return user_to_out(user, hide_cost=hide)
diff --git a/frontend/src/components/Layout.vue b/frontend/src/components/Layout.vue
index bec14c3..4f73c9a 100644
--- a/frontend/src/components/Layout.vue
+++ b/frontend/src/components/Layout.vue
@@ -73,7 +73,7 @@ const menuItems = [
{ path: '/projects', label: '项目管理', icon: 'FolderOpened', perm: 'project:view' },
{ path: '/submissions', label: '内容提交', icon: 'EditPen', perm: 'submission:view' },
{ path: '/costs', label: '成本管理', icon: 'Money', perm: ['cost_ai:view', 'cost_outsource:view', 'cost_overhead:view', 'cost_labor:view'] },
- { path: '/users', label: '用户管理', icon: 'User', perm: 'user:manage' },
+ { path: '/users', label: '用户管理', icon: 'User', perm: 'user:view' },
{ path: '/roles', label: '角色管理', icon: 'Lock', perm: 'role:manage' },
]
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index da83176..ccbb5fe 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -12,7 +12,7 @@ const routes = [
{ path: 'projects/:id', name: 'ProjectDetail', component: () => import('../views/ProjectDetail.vue'), meta: { perm: 'project:view' } },
{ path: 'submissions', name: 'Submissions', component: () => import('../views/Submissions.vue'), meta: { perm: 'submission:view' } },
{ path: 'costs', name: 'Costs', component: () => import('../views/Costs.vue'), meta: { perm: ['cost_ai:view', 'cost_outsource:view', 'cost_overhead:view', 'cost_labor:view'] } },
- { path: 'users', name: 'Users', component: () => import('../views/Users.vue'), meta: { perm: 'user:manage' } },
+ { path: 'users', name: 'Users', component: () => import('../views/Users.vue'), meta: { perm: 'user:view' } },
{ path: 'users/:id/detail', name: 'MemberDetail', component: () => import('../views/MemberDetail.vue'), meta: { perm: 'user:view' } },
{ path: 'roles', name: 'Roles', component: () => import('../views/Roles.vue'), meta: { perm: 'role:manage' } },
{ path: 'settlement/:id', name: 'Settlement', component: () => import('../views/Settlement.vue'), meta: { perm: 'settlement:view' } },
diff --git a/frontend/src/views/Costs.vue b/frontend/src/views/Costs.vue
index 3b0cc2e..5837d89 100644
--- a/frontend/src/views/Costs.vue
+++ b/frontend/src/views/Costs.vue
@@ -62,6 +62,29 @@
+
+
+