feat: 采购申请完结功能移到批次主行,与出库审批一致

- 移除展开行内的单条完结按钮(需点开),改为主行'完结本批'直接可见
- 后端 batch-approve 支持 action=close(批次内已通过→已完结)
- 超管/库管在主行操作列即可看到并完结
This commit is contained in:
yueli
2026-09-01 16:21:48 +08:00
parent 8c554fdd3b
commit 4e09860b36
2 changed files with 39 additions and 7 deletions

View File

@ -273,20 +273,23 @@ def batch_approve_purchase():
action = data.get('action', 'approve')
reject_reason = data.get('reject_reason')
# 若传 batch_keyrequest_no 去掉末尾流水号的前缀),查出该批次所有待审批记录
# 若传 batch_keyrequest_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

View File

@ -58,9 +58,6 @@
<el-button type="success" link size="small" @click="handleApprove(it)">通过</el-button>
<el-button type="danger" link size="small" @click="openRejectDialog(it)">驳回</el-button>
</template>
<template v-else-if="it.status === 1 && canClose">
<el-button type="danger" plain link size="small" @click="handleCloseRequest(it)">完结</el-button>
</template>
</template>
</el-table-column>
</el-table>
@ -119,6 +116,10 @@
<el-button type="success" link size="small" :loading="batchLoading" @click="handleApproveBatch(row.batchKey)">审批本批</el-button>
<el-button type="danger" link size="small" :loading="batchLoading" @click="openRejectBatchDialog(row.batchKey)">驳回本批</el-button>
</template>
<!-- 完结本批批次内已通过的单库管可直接完结仿出库审批主行可见 -->
<template v-if="batchHasClosable(row) && canClose">
<el-button type="danger" plain link size="small" :loading="batchLoading" @click="handleCloseBatch(row.batchKey)">完结本批</el-button>
</template>
</template>
</el-table-column>
</el-table>
@ -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)