2 Commits

Author SHA1 Message Date
7e4524ae42 fix(warning): 预警字段被 field_permissions Default Deny 规则错误过滤
- MaterialBase 映射中新增 warningStatus/warningEnabled/warningRed/warningYellow/warningRedEmails/warningYellowEmails 字段
- 新增 _permits() 函数支持通配符权限匹配 (material_list:* 覆盖所有 material_list:xxx)
- 修复 apply_strict_rbac 使用 _permits 替代直接 in 检查

根因: field_permissions.py 的 STOCK_FIELD_RBAC_MAPPING 中没有预警字段映射,
apply_strict_rbac 的 Default Deny 规则会删除所有不在映射中的字段,导致前端永远收不到预警数据。
2026-08-11 13:28:47 +08:00
9c0414b802 fix(outbound): 出库备注改为必填,按单出库自动填充申请原因
- 备注字段新增 required 校验规则
- placeholder 从「可选填」改为「请填写出库原因」
- 按单出库模式选择申请单后,自动将申请原因填入备注
2026-08-07 15:58:59 +08:00
2 changed files with 31 additions and 4 deletions

View File

@ -20,6 +20,12 @@ STOCK_FIELD_RBAC_MAPPING = {
"referencePrice": "material_list:referencePrice",
"inventoryCount": "material_list:inventoryCount",
"availableCount": "material_list:availableCount",
"warningStatus": "material_list:view_warning",
"warningEnabled": "material_list:view_warning",
"warningRed": "material_list:view_warning",
"warningYellow": "material_list:view_warning",
"warningRedEmails": "material_list:view_warning",
"warningYellowEmails": "material_list:view_warning",
},
"StockBuy": {
"id": None, "request_id": None, "request_no": None,
@ -89,6 +95,21 @@ def _is_super_admin(user_permissions: list) -> bool:
return '*' in user_permissions or any(p.endswith(':*') for p in user_permissions)
def _permits(perm_code: str, user_permissions: list) -> bool:
"""检查用户权限列表是否覆盖指定的权限码(支持通配符匹配)"""
if perm_code is None:
return True # None = 公开字段
if perm_code in user_permissions:
return True # 精确匹配
# 通配符匹配: material_list:* 覆盖所有 material_list:xxx
for p in user_permissions:
if p.endswith(':*') and perm_code.startswith(p[:-2] + ':'):
return True
if '*' in user_permissions:
return True
return False
def apply_strict_rbac(item_dict: dict, table_name: str, user_permissions: list) -> dict:
"""
Default Deny 字段过滤器:
@ -112,7 +133,7 @@ def apply_strict_rbac(item_dict: dict, table_name: str, user_permissions: list)
del item_dict[key] # Default Deny
else:
perm_code = mapping[key]
if perm_code is not None and perm_code not in user_permissions:
if not _permits(perm_code, user_permissions):
if isinstance(item_dict[key], (int, float)):
item_dict[key] = 0
elif isinstance(item_dict[key], bool):

View File

@ -197,8 +197,8 @@
</el-col>
</el-row>
<el-form-item label="备注说明" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="可选填" />
<el-form-item label="备注说明" prop="remark" required>
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请填写出库原因" />
</el-form-item>
<el-form-item label="电子签名确认" required>
@ -332,7 +332,8 @@ const form = reactive({
const rules = {
outbound_type: [{ required: true, message: '请选择出库类型', trigger: 'change' }],
consumer_name: [{ required: true, message: '请输入领用人姓名', trigger: 'blur' }],
operator_name: [{ required: true, message: '请指定操作员', trigger: 'change' }]
operator_name: [{ required: true, message: '请指定操作员', trigger: 'change' }],
remark: [{ required: true, message: '请填写备注/出库原因', trigger: 'blur' }]
}
// 计算总金额
@ -382,8 +383,13 @@ const loadApprovalRequests = async () => {
const handleRequestChange = (val: number | null) => {
if (!val) {
selectedRequest.value = null
form.remark = ''
} else {
selectedRequest.value = approvalRequests.value.find(r => r.id === val) ?? null
// ★ 按单出库:自动将申请单的申请原因填入备注,用户可修改
if (selectedRequest.value?.remark) {
form.remark = selectedRequest.value.remark
}
}
// 切换申请单时清空购物车,防止已扫物品与新单据混淆
cartItems.value = []