diff --git a/inventory-web/src/views/purchase/index.vue b/inventory-web/src/views/purchase/index.vue
index 4da8dcf..018326d 100644
--- a/inventory-web/src/views/purchase/index.vue
+++ b/inventory-web/src/views/purchase/index.vue
@@ -17,62 +17,89 @@
-
-
- 已选 {{ selectedRows.length }} 条待审批申请
- 批量通过
- 批量驳回
- 取消选择
-
+
+
+
+
+
+
+
批次明细({{ row.itemCount }} 项)
+
+
+
+
+
+
+
+
+ {{ it.unit_price ? '¥' + Number(it.unit_price).toFixed(2) : '-' }}
+
+
+
+
+ {{ it.total_price ? '¥' + Number(it.total_price).toFixed(2) : '-' }}
+
+
+
+
+ {{ it.status_text }}
+
+
+
+
+ 详情
+
+ 通过
+ 驳回
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
- {{ row.unit_price ? '¥' + Number(row.unit_price).toFixed(2) : '-' }}
-
-
-
-
- {{ row.total_price ? '¥' + Number(row.total_price).toFixed(2) : '-' }}
-
-
-
-
- {{ row.tax_rate != null ? row.tax_rate + '%' : '-' }}
-
-
-
-
-
-
-
-
- {{ getBatchKey(row.request_no) }}
+
+ {{ row.batchKey }}
- -
-
+
- {{ row.status_text }}
+ {{ row.itemCount }} 项
-
+
- 详情
- 整批
-
- 通过
- 驳回
+ ¥{{ Number(row.totalAmount).toFixed(2) }}
+
+
+
+
+
+
+
+
+ {{ text }}
+
+
+ 混合
+
+ 待审批 {{ row.pendingCount }} 项
+
+
+
+
+
+ 查看整批
+
+
+ 审批本批
+ 驳回本批
@@ -349,6 +376,22 @@
+
+
+
+
+ {{ rejectBatchKey }}
+
+
+
+
+
+
+ 取消
+ 确认驳回本批
+
+
+
@@ -400,6 +443,60 @@ const clearSelection = () => {
selectedRows.value = []
}
+// ★ 审批本批:一键通过批次内所有待审批记录
+const handleApproveBatch = async (batchKey: string) => {
+ const batch = list.value.find(b => b.batchKey === batchKey)
+ if (!batch || batch.pendingCount === 0) return ElMessage.warning('本批没有待审批记录')
+ try {
+ await ElMessageBox.confirm(
+ `确定通过批次【${batchKey}】的 ${batch.pendingCount} 条待审批记录吗?`,
+ '审批本批',
+ { confirmButtonText: '全部通过', cancelButtonText: '取消', type: 'info' }
+ )
+ } catch { return }
+
+ batchLoading.value = true
+ try {
+ const res: any = await batchApprovePurchase({ batch_key: batchKey, action: 'approve' })
+ ElMessage.success(res?.msg || '本批已全部通过')
+ await fetchData()
+ } catch (err: any) {
+ ElMessage.error(err?.msg || '审批失败')
+ } finally {
+ batchLoading.value = false
+ }
+}
+
+// ★ 驳回本批:批次内所有待审批记录统一驳回
+const rejectBatchKey = ref('')
+const rejectBatchDialogVisible = ref(false)
+const rejectBatchReason = ref('')
+
+const openRejectBatchDialog = (batchKey: string) => {
+ rejectBatchKey.value = batchKey
+ rejectBatchReason.value = ''
+ rejectBatchDialogVisible.value = true
+}
+
+const confirmRejectBatch = async () => {
+ if (!rejectBatchReason.value.trim()) { ElMessage.warning('请填写驳回原因'); return }
+ batchLoading.value = true
+ try {
+ const res: any = await batchApprovePurchase({
+ batch_key: rejectBatchKey.value,
+ action: 'reject',
+ reject_reason: rejectBatchReason.value
+ })
+ ElMessage.success(res?.msg || '本批已驳回')
+ rejectBatchDialogVisible.value = false
+ await fetchData()
+ } catch (err: any) {
+ ElMessage.error(err?.msg || '驳回失败')
+ } finally {
+ batchLoading.value = false
+ }
+}
+
// 批量通过
const handleBatchApprove = async () => {
if (selectedRows.value.length === 0) return
@@ -617,8 +714,36 @@ const fetchData = async () => {
if (filterStatus.value !== '') params.status = filterStatus.value
const res: any = await getPurchaseList(params)
- list.value = res.data?.items || []
+ const items = res.data?.items || []
total.value = res.data?.total || 0
+
+ // ★ 按批次分组:同批次(单号去末尾-批内序号)聚合为一行
+ const groupMap = new Map()
+ items.forEach(item => {
+ const key = getBatchKey(item.request_no) || '独立'
+ if (!groupMap.has(key)) groupMap.set(key, [])
+ groupMap.get(key)!.push(item)
+ })
+
+ list.value = Array.from(groupMap.entries()).map(([batchKey, batchItems]) => {
+ const totalAmount = batchItems.reduce((sum, it) => sum + (Number(it.total_price) || 0), 0)
+ const pendingCount = batchItems.filter(it => it.status === 0).length
+ // 状态汇总:全通过=1,全驳回=2,混合/待审=0
+ const statuses = new Set(batchItems.map(it => it.status))
+ let summaryStatus = batchItems[0]?.status ?? 0
+ if (statuses.size > 1) summaryStatus = 0 // 混合状态按待审处理
+ return {
+ batchKey,
+ items: batchItems,
+ itemCount: batchItems.length,
+ totalAmount,
+ pendingCount,
+ summaryStatus,
+ requesterName: batchItems[0]?.requester_name || '',
+ purchaseDate: batchItems[0]?.purchase_date || '',
+ statusTexts: batchItems.map(it => it.status_text).filter((v, i, a) => a.indexOf(v) === i)
+ }
+ })
} catch (err: any) {
ElMessage.error(err?.msg || '加载失败')
} finally {
@@ -626,6 +751,7 @@ const fetchData = async () => {
}
}
+
const fetchApprovers = async () => {
try {
const res: any = await getPurchaseApprovers()