diff --git a/inventory-backend/app/api/v1/outbound.py b/inventory-backend/app/api/v1/outbound.py
index ae857e0..a7a48ba 100644
--- a/inventory-backend/app/api/v1/outbound.py
+++ b/inventory-backend/app/api/v1/outbound.py
@@ -1,7 +1,8 @@
from flask import Blueprint, request, jsonify
from app.services.outbound_service import OutboundService
-from flask_jwt_extended import jwt_required, get_jwt_identity
+from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
from app.utils.decorators import permission_required
+from app.services.auth_service import AuthService
import traceback
outbound_bp = Blueprint('outbound', __name__, url_prefix='/outbound')
@@ -46,8 +47,20 @@ def scan_barcode():
# --------------------------------------------------------
@outbound_bp.route('', methods=['POST'])
@jwt_required()
-@permission_required('outbound_selection:operation')
def create_outbound():
+ # 权限检查:需要 outbound_create:operation 或 outbound_selection:operation 之一
+ claims = get_jwt()
+ user_role = claims.get('role')
+ if not user_role:
+ return jsonify({'code': 403, 'msg': '未授权'}), 403
+
+ # 超级管理员直接放行
+ if user_role != 'super_admin':
+ perm_dict = AuthService.get_user_permissions(user_role)
+ perms = perm_dict.get('menus', []) + perm_dict.get('elements', [])
+ if ('outbound_create:operation' not in perms) and ('outbound_selection:operation' not in perms):
+ return jsonify({'code': 403, 'msg': '权限不足'}), 403
+
data = request.get_json()
if not data:
return jsonify({'code': 400, 'msg': '无有效数据'}), 400
diff --git a/inventory-web/src/views/outbound/create.vue b/inventory-web/src/views/outbound/create.vue
index 928c385..76911ed 100644
--- a/inventory-web/src/views/outbound/create.vue
+++ b/inventory-web/src/views/outbound/create.vue
@@ -17,10 +17,14 @@
-
+
点击开启全屏扫码
+
+
+ 无扫码权限
+
- 添加
+ 添加
@@ -64,13 +69,14 @@
:max="parseFloat(row.available_quantity)"
size="small"
style="width: 100px"
+ :disabled="!userStore.hasPermission('outbound_create:operation')"
/>
-
+
@@ -120,7 +126,7 @@
-
+
点击重签
@@ -130,11 +136,17 @@
点击此处进行全屏签名
+
- 清空
-
+ 清空
+
确认出库
@@ -205,6 +217,8 @@ import { getStockByBarcode, submitOutbound, getOutboundList } from '@/api/outbou
import { uploadFile } from '@/api/common/upload'
import { useUserStore } from '@/stores/user'
+const userStore = useUserStore()
+
// --- 状态定义 ---
const barcodeInput = ref('')
const cartItems = ref
([])
@@ -212,7 +226,6 @@ const loading = ref(false)
const showCamera = ref(false)
const barcodeRef = ref()
const formRef = ref()
-const userStore = useUserStore()
// 签名相关
const showSignatureDialog = ref(false)
@@ -292,6 +305,10 @@ const onScanSuccess = (code: string) => {
}
const handleManualInput = async () => {
+ if (!userStore.hasPermission('outbound_create:operation')) {
+ ElMessage.warning('无操作权限')
+ return
+ }
const code = barcodeInput.value.trim()
if (!code) return
@@ -355,10 +372,18 @@ const handleManualInput = async () => {
}
const removeFromCart = (index: number) => {
+ if (!userStore.hasPermission('outbound_create:operation')) {
+ ElMessage.warning('无操作权限')
+ return
+ }
cartItems.value.splice(index, 1)
}
const clearAll = () => {
+ if (!userStore.hasPermission('outbound_create:operation')) {
+ ElMessage.warning('无操作权限')
+ return
+ }
ElMessageBox.confirm('确定清空所有已选商品吗?', '提示', { type: 'warning' })
.then(() => {
cartItems.value = []
@@ -372,6 +397,10 @@ const clearAll = () => {
// --- 提交逻辑 ---
const submitForm = async () => {
+ if (!userStore.hasPermission('outbound_create:operation')) {
+ ElMessage.warning('无操作权限')
+ return
+ }
if (!formRef.value) return
if (cartItems.value.length === 0) return ElMessage.warning('请先添加商品')
@@ -427,7 +456,13 @@ const submitForm = async () => {
}
// --- 签名逻辑 (Canvas) ---
-const openSignatureDialog = () => { showSignatureDialog.value = true }
+const openSignatureDialog = () => {
+ if (!userStore.hasPermission('outbound_create:operation')) {
+ ElMessage.warning('无签名权限')
+ return
+ }
+ showSignatureDialog.value = true
+}
const initCanvas = async () => {
await nextTick()
@@ -618,4 +653,4 @@ onUnmounted(() => {
.sidebar-actions { flex-direction: row; width: 100%; gap: 10px; }
.sidebar-actions .el-button { flex: 1; height: 40px; }
}
-
\ No newline at end of file
+