Files
zyt/INTERNAL_COST_PERMISSION_CONTROL.md
T
2026-04-10 14:43:58 +08:00

4.5 KiB
Raw Blame History

内部成本字段权限控制

需求说明

在业务订单列表中添加内部成本字段的显示,但只有指定角色的用户才能看到该字段。

权限配置

文件:server/config/project.php

// 处方业务订单 internal_cost 等财务字段:以下角色 ID + root 可见
'prescription_order_finance_roles' => [0, 3, 6],
  • 角色 0:超级管理员
  • 角色 3:管理员
  • 角色 6:药师

后端权限控制

文件:server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php

后端已经实现了权限控制逻辑:

public static function canViewInternalCost(array $adminInfo): bool
{
    if (!empty($adminInfo['root']) && (int) $adminInfo['root'] === 1) {
        return true;
    }
    $allow = Config::get('project.prescription_order_finance_roles', [0, 3]);
    $allow = array_map('intval', is_array($allow) ? $allow : []);
    $myRoles = array_map('intval', $adminInfo['role_id'] ?? []);

    return count(array_intersect($myRoles, $allow)) > 0;
}

public static function maskInternalCostIfNeeded(array &$row, array $adminInfo): void
{
    if (!self::canViewInternalCost($adminInfo)) {
        unset($row['internal_cost']);
    }
}

后端在返回数据前会自动移除 internal_cost 字段,如果用户没有权限。

前端权限控制

文件:admin/src/views/consumer/prescription/order_list.vue

1. 添加权限检查函数

import useUserStore from '@/stores/modules/user'

const userStore = useUserStore()

/** 与 server/config/project.php prescription_order_finance_roles 保持一致 */
const FINANCE_ROLE_IDS = [0, 3, 6]

/** 判断当前用户是否有查看财务字段(内部成本)的权限 */
const canViewFinanceFields = () => {
    const u = userStore.userInfo
    if (!u) return false
    if (Number(u.root) === 1) return true
    const ids = Array.isArray(u.role_ids) ? u.role_ids.map((n: unknown) => Number(n)) : []
    return FINANCE_ROLE_IDS.some((rid) => ids.includes(rid))
}

2. 在列表中添加权限控制

表格列(只有有权限的用户才能看到整列):

<el-table-column v-if="canViewFinanceFields()" label="内部成本" width="92">
    <template #default="{ row }">
        {{ row.internal_cost != null && row.internal_cost !== '' ? ${row.internal_cost}` : '—' }}
    </template>
</el-table-column>

金额信息弹出框(只有有权限的用户才能看到内部成本行):

<div v-if="canViewFinanceFields() && row.internal_cost != null && row.internal_cost !== ''" class="flex justify-between">
    <span class="text-gray-500">内部成本</span>
    <span class="font-medium text-orange-600">¥{{ formatMoney(row.internal_cost) }}</span>
</div>

权限控制层级

后端(第一层防护)

  1. PrescriptionOrderLogic::detail() 和列表方法中调用 maskInternalCostIfNeeded()
  2. 如果用户没有权限,直接从返回数据中移除 internal_cost 字段
  3. 前端收到的数据中不包含该字段

前端(第二层防护)

  1. 使用 v-if="canViewFinanceFields()" 控制整个表格列的显示
  2. 在弹出框中也使用 canViewFinanceFields() 控制内部成本行的显示
  3. 即使后端数据泄露,前端也不会显示

双重防护的优势

  1. 后端防护:确保数据安全,无权限用户无法获取敏感数据
  2. 前端防护:优化用户体验,无权限用户不会看到空白或无意义的列
  3. 配置同步:前端 FINANCE_ROLE_IDS 与后端配置保持一致

测试验证

有权限的用户(角色 0, 3, 6

  1. 登录系统
  2. 进入"消费者处方订单"列表
  3. 可以看到"内部成本"列
  4. 点击金额信息图标,弹出框中显示内部成本

无权限的用户(其他角色)

  1. 登录系统
  2. 进入"消费者处方订单"列表
  3. 看不到"内部成本"列
  4. 点击金额信息图标,弹出框中不显示内部成本

注意事项

  1. 配置同步:修改后端配置后,需要同步修改前端 FINANCE_ROLE_IDS 常量
  2. 缓存清除:修改配置后需要运行 php think clear 清除缓存
  3. 角色分配:确保用户的角色ID正确分配在数据库中
  4. 超级管理员root=1 的用户始终有权限查看所有字段

相关文件

  • server/config/project.php - 权限配置
  • server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php - 后端权限逻辑
  • admin/src/views/consumer/prescription/order_list.vue - 前端显示控制
  • admin/src/stores/modules/user.ts - 用户信息存储