From e224a07a47eb9058d303bef2fb116d683b920a24 Mon Sep 17 00:00:00 2001 From: dxc Date: Wed, 11 Mar 2026 13:28:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A7=E9=A2=84=E8=AD=A6?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E8=AE=BE=E7=BD=AE=E4=BA=A4=E4=BA=92=EF=BC=8C?= =?UTF-8?q?=E5=BC=95=E5=85=A5=E6=89=B9=E9=87=8F=E6=93=8D=E4=BD=9C=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E5=88=87=E6=8D=A2=EF=BC=8C=E6=8F=90=E5=8D=87=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E6=95=B4=E6=B4=81=E5=BA=A6=E4=B8=8E=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- inventory-backend/app/api/v1/inbound/base.py | 3 +- .../app/services/inbound/base_service.py | 5 + inventory-web/src/views/material/list.vue | 96 +++++++++++++++---- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/inventory-backend/app/api/v1/inbound/base.py b/inventory-backend/app/api/v1/inbound/base.py index 3457771..50b0bae 100644 --- a/inventory-backend/app/api/v1/inbound/base.py +++ b/inventory-backend/app/api/v1/inbound/base.py @@ -123,7 +123,8 @@ def get_list(): 'orderByColumn': request.args.get('orderByColumn', ''), 'isAsc': request.args.get('isAsc', None), 'advancedFilters': advanced_filters_list, - 'enableWarningSort': request.args.get('enableWarningSort', 'false').lower() == 'true' + 'enableWarningSort': request.args.get('enableWarningSort', 'false').lower() == 'true', + 'has_stock': request.args.get('has_stock', '') } user_permissions = get_current_user_permissions() diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py index ae880b5..0c85933 100644 --- a/inventory-backend/app/services/inbound/base_service.py +++ b/inventory-backend/app/services/inbound/base_service.py @@ -198,6 +198,11 @@ class MaterialBaseService: # 必须使用 filter() 而非 filter_by(),因为 query 是 join 后的复杂查询 query = query.filter(MaterialBase.is_enabled == is_active) + # 【新增】:库存状态筛选 (has_stock) + has_stock = filters.get('has_stock') + if has_stock and str(has_stock).lower() in ['true', '1', 'yes']: + query = query.filter(total_inv > 0) + # 3. 高级动态筛选 advanced_filters = filters.get('advancedFilters', []) if advanced_filters: diff --git a/inventory-web/src/views/material/list.vue b/inventory-web/src/views/material/list.vue index e11de5e..ab654c6 100644 --- a/inventory-web/src/views/material/list.vue +++ b/inventory-web/src/views/material/list.vue @@ -62,6 +62,17 @@ + + + + + 搜索 重置 - - 批量设置预警 - + 新增 @@ -154,6 +182,7 @@ + @@ -534,10 +565,11 @@ interface QueryParams { category: string; type: string; company: string; - isEnabled?: boolean; // 已修改为布尔值可选 + isEnabled?: boolean; orderByColumn: string; isAsc: string | undefined; advancedFilters?: any[]; + has_stock?: string; } interface CascaderOption { @@ -551,6 +583,7 @@ const loading = ref(false); const exportLoading = ref(false); // 导出加载状态 const total = ref(0); const tableData = ref([]); +const tableRef = ref>(); const submitLoading = ref(false); const tableSize = ref<'large' | 'default' | 'small'>('large'); const advancedFilterVisible = ref(false); @@ -589,6 +622,24 @@ const cameraDialogVisible = ref(false); const cameraRef = ref | null>(null); const currentCameraField = ref<'generalImage' | 'generalManual'>('generalImage'); +// 复选框选中数据 +const selectedItems = ref([]); +const handleSelectionChange = (selection: MaterialBaseVO[]) => { + selectedItems.value = selection; +}; + +// 批量操作模式 +const isBatchMode = ref(false); +const enterBatchMode = () => { + selectedItems.value = []; + isBatchMode.value = true; +}; +const exitBatchMode = () => { + selectedItems.value = []; + tableRef.value?.clearSelection(); // 清除表格勾选状态 + isBatchMode.value = false; +}; + // 预警设置相关 const warningDialog = reactive({ visible: false, @@ -701,7 +752,8 @@ const queryParams = reactive({ isEnabled: undefined, orderByColumn: '', isAsc: undefined, - advancedFilters: [] + advancedFilters: [], + has_stock: '' }); // --- 弹窗与表单相关 --- @@ -920,6 +972,10 @@ const resetQuery = () => { queryParams.isEnabled = undefined; queryParams.orderByColumn = ''; queryParams.isAsc = undefined; + queryParams.has_stock = ''; + selectedItems.value = []; + tableRef.value?.clearSelection(); + isBatchMode.value = false; handleQuery(); }; @@ -1098,16 +1154,15 @@ const handleDelete = (row: MaterialBaseVO) => { // 批量设置预警 const handleBatchSetWarning = () => { - // 获取已选择的行(如果有选中的行则使用选中的行,否则使用当前页所有行) - const selectedRows = tableData.value.filter((row: MaterialBaseVO) => (row as any)._checked); - if (selectedRows.length > 0) { - warningDialog.selectedIds = selectedRows.map((row: MaterialBaseVO) => row.id); - warningDialog.selectedCount = selectedRows.length; - } else { - warningDialog.selectedIds = tableData.value.map((row: MaterialBaseVO) => row.id); - warningDialog.selectedCount = tableData.value.length; + if (selectedItems.value.length === 0) { + ElMessage.warning('请先勾选需要设置预警的物料'); + return; } + // 使用已选中的行 + warningDialog.selectedIds = selectedItems.value.map((row: MaterialBaseVO) => row.id); + warningDialog.selectedCount = selectedItems.value.length; + // 重置表单 warningForm.isEnabled = false; warningForm.redThreshold = undefined; @@ -1149,6 +1204,9 @@ const submitWarning = async () => { await batchSetWarning(data); ElMessage.success('预警设置成功'); warningDialog.visible = false; + selectedItems.value = []; // 清除选中状态 + tableRef.value?.clearSelection(); // 清除表格勾选状态 + isBatchMode.value = false; // 退出批量模式 getList(); } catch (error: any) { ElMessage.error(error?.msg || '设置失败');