diff --git a/inventory-backend/app/api/v1/purchase.py b/inventory-backend/app/api/v1/purchase.py index e270639..fe16b69 100644 --- a/inventory-backend/app/api/v1/purchase.py +++ b/inventory-backend/app/api/v1/purchase.py @@ -273,20 +273,23 @@ def batch_approve_purchase(): action = data.get('action', 'approve') reject_reason = data.get('reject_reason') - # 若传 batch_key(request_no 去掉末尾流水号的前缀),查出该批次所有待审批记录 + # 若传 batch_key(request_no 去掉末尾流水号的前缀),查出该批次对应状态的记录 if batch_key: from app.models.purchase import PurchaseRequest + # 完结本批 → 找「已通过(1)」的单;审批/驳回 → 找「待审批(0)」的单 + target_status = 1 if action == 'close' else 0 records = PurchaseRequest.query.filter( PurchaseRequest.request_no.like(f"{batch_key}-%"), - PurchaseRequest.status == 0 + PurchaseRequest.status == target_status ).all() ids = [r.id for r in records] if not ids: - return jsonify({'code': 400, 'msg': '该批次没有待审批的记录'}), 400 + status_text = '已通过' if action == 'close' else '待审批' + return jsonify({'code': 400, 'msg': f'该批次没有{status_text}的记录'}), 400 if not ids or not isinstance(ids, list): return jsonify({'code': 400, 'msg': 'ids 或 batch_key 不能为空'}), 400 - if action not in ('approve', 'reject'): + if action not in ('approve', 'reject', 'close'): return jsonify({'code': 400, 'msg': '无效的审批操作'}), 400 if action == 'reject' and not reject_reason: return jsonify({'code': 400, 'msg': '驳回时必须提供原因'}), 400 diff --git a/inventory-web/src/views/purchase/index.vue b/inventory-web/src/views/purchase/index.vue index 86f400a..235284b 100644 --- a/inventory-web/src/views/purchase/index.vue +++ b/inventory-web/src/views/purchase/index.vue @@ -58,9 +58,6 @@ 通过 驳回 - @@ -119,6 +116,10 @@ 审批本批 驳回本批 + + @@ -485,6 +486,34 @@ const handleApproveBatch = async (batchKey: string) => { } } +// ★ 批次内是否存在「已通过」的单(可完结) +const batchHasClosable = (row: any) => (row.items || []).some((it: any) => it.status === 1) + +// ★ 完结本批:一键完结批次内所有「已通过」记录(仿出库审批) +const handleCloseBatch = async (batchKey: string) => { + const batch = list.value.find(b => b.batchKey === batchKey) + const closable = batch ? (batch.items || []).filter((it: any) => it.status === 1) : [] + if (!closable.length) return ElMessage.warning('本批没有已通过记录可完结') + try { + await ElMessageBox.confirm( + `确定强制完结批次【${batchKey}】中 ${closable.length} 条已通过的记录吗?\n\n此操作不可恢复。`, + '⚠️ 完结本批确认', + { confirmButtonText: '确认完结', cancelButtonText: '取消', type: 'warning' } + ) + } catch { return } + + batchLoading.value = true + try { + const res: any = await batchApprovePurchase({ batch_key: batchKey, action: 'close' }) + ElMessage.success(res?.msg || '本批已完结') + await fetchData() + } catch (err: any) { + ElMessage.error(err?.msg || err?.message || '完结失败') + } finally { + batchLoading.value = false + } +} + // ★ 驳回本批:批次内所有待审批记录统一驳回 const rejectBatchKey = ref('') const rejectBatchDialogVisible = ref(false)