Artifact 90b9af6495a3b5d5310d75c217127e1cc0821ed37ba13921e9db5877265046c0:
- File
backend/src/rbac.gleam
— part of check-in
[bee9efb316]
at
2026-10-23 06:37:04
on branch trunk
— 同一仓库内移库,并留下波次已占用的数量
- 把一个批次从源库位转到启用的目标库位,库存立刻变更 - 未完成波次占用的数量不能移走,撤销波次后才能继续移 - 移库记录留在本地,不写回来肯 (user: pluto size: 4670)
import database.{type Param, IntParam} import gleam/list import gleam/string pub type Scope { AllWarehouses Warehouses(List(Int)) } pub type Permission { Permission(code: String, name: String) } pub type Role { Role( code: String, name: String, terminals: List(String), permissions: List(String), ) } pub const sys_admin = "ROLE_SYS_ADMIN" pub const terminals = ["web", "desktop", "mobile", "miniapp"] pub const sync_view = "sync.view" pub const sync_run = "sync.run" pub const warehouse_view = "warehouse.view" pub const location_view = "location.view" pub const location_manage = "location.manage" pub const product_view = "product.view" pub const order_view = "order.view" pub const wave_manage = "wave.manage" pub const inbound_view = "inbound.view" pub const receiving_execute = "receiving.execute" pub const putaway_execute = "putaway.execute" pub const picking_execute = "picking.execute" pub const shipment_execute = "shipment.execute" pub const inventory_view = "inventory.view" pub const move_execute = "move.execute" pub const user_manage = "user.manage" pub const audit_view = "audit.view" pub fn permissions() -> List(Permission) { [ Permission(sync_view, "查看同步状态与来肯连接"), Permission(sync_run, "手动触发来肯同步"), Permission(warehouse_view, "查看仓库"), Permission(location_view, "查看库位"), Permission(location_manage, "规划、新增、停用库位"), Permission(product_view, "查看商品"), Permission(order_view, "查看销售订单与出库记录"), Permission(wave_manage, "波次组单与撤销"), Permission(inbound_view, "查看采购单、采购入库单与批次码"), Permission(receiving_execute, "收货验货"), Permission(putaway_execute, "上架"), Permission(picking_execute, "拣货"), Permission(shipment_execute, "出库扣减库存"), Permission(inventory_view, "查看库存"), Permission(move_execute, "移库"), Permission(user_manage, "用户、角色与仓库授权管理"), Permission(audit_view, "查看审计日志"), ] } pub fn roles() -> List(Role) { let all = list.map(permissions(), fn(p) { p.code }) [ Role(sys_admin, "超级管理员", ["web", "desktop"], all), Role("ROLE_WH_MANAGER", "仓库主管", ["web", "desktop", "miniapp"], [ sync_view, warehouse_view, location_view, location_manage, product_view, order_view, inbound_view, receiving_execute, putaway_execute, picking_execute, wave_manage, shipment_execute, inventory_view, move_execute, ]), Role("ROLE_ORDER_CLERK", "制单/调度员", ["web", "desktop"], [ sync_view, sync_run, warehouse_view, location_view, product_view, order_view, wave_manage, inbound_view, inventory_view, ]), Role("ROLE_PACKER", "打包复核员", ["desktop"], [ warehouse_view, location_view, product_view, order_view, picking_execute, shipment_execute, inventory_view, ]), Role("ROLE_OPERATOR", "库内作业员", ["mobile", "miniapp"], [ warehouse_view, location_view, product_view, order_view, inbound_view, receiving_execute, putaway_execute, picking_execute, inventory_view, move_execute, ]), ] } pub fn find_role(code: String) -> Result(Role, Nil) { list.find(roles(), fn(role) { role.code == code }) } pub fn permissions_of(role_codes: List(String)) -> List(String) { role_codes |> list.filter_map(find_role) |> list.flat_map(fn(role) { role.permissions }) |> list.unique } pub fn terminal_allowed(role_codes: List(String), terminal: String) -> Bool { role_codes |> list.filter_map(find_role) |> list.any(fn(role) { list.contains(role.terminals, terminal) }) } pub fn scope_for(role_codes: List(String), warehouse_ids: List(Int)) -> Scope { case list.contains(role_codes, sys_admin) { True -> AllWarehouses False -> Warehouses(warehouse_ids) } } pub fn allows(scope: Scope, warehouse_id: Int) -> Bool { case scope { AllWarehouses -> True Warehouses(ids) -> list.contains(ids, warehouse_id) } } /// 生成 `column IN (...)` 过滤条件,SQLite 与 PostgreSQL 通用。 pub fn sql_filter(scope: Scope, column: String) -> #(String, List(Param)) { case scope { AllWarehouses -> #("1 = 1", []) Warehouses([]) -> #("1 = 0", []) Warehouses(ids) -> #( column <> " IN (" <> string.join(list.map(ids, fn(_) { "?" }), ", ") <> ")", list.map(ids, IntParam), ) } }