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

143 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 内部成本字段权限控制
## 需求说明
在业务订单列表中添加内部成本字段的显示,但只有指定角色的用户才能看到该字段。
## 权限配置
文件:`server/config/project.php`
```php
// 处方业务订单 internal_cost 等财务字段:以下角色 ID + root 可见
'prescription_order_finance_roles' => [0, 3, 6],
```
- 角色 0:超级管理员
- 角色 3:管理员
- 角色 6:药师
## 后端权限控制
文件:`server/app/adminapi/logic/tcm/PrescriptionOrderLogic.php`
后端已经实现了权限控制逻辑:
```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. 添加权限检查函数
```typescript
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. 在列表中添加权限控制
**表格列(只有有权限的用户才能看到整列):**
```vue
<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>
```
**金额信息弹出框(只有有权限的用户才能看到内部成本行):**
```vue
<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` - 用户信息存储