This commit is contained in:
zlwu committed 2026-08-01 17:29:37 +08:00
1 parent 06956b742b
commit e59b2aa6cb
104 files changed
+653227 -7621

No files matched your search

+30 -5
View File
@@ -684,15 +684,40 @@ async function handleToolbarSubmit() {
ElMessage.warning('请先勾选要提交的申请')
return
}
const validTargets = selectedRows.value.filter(isDraftEditable)
const skippedCount = selectedRows.value.length - validTargets.length
if (!validTargets.length) {
ElMessage.warning('所选申请均不是草稿或已驳回状态,无法提交审批')
return
}
if (skippedCount > 0) {
ElMessage.warning(
`已跳过 ${skippedCount} 条不可提交的申请(仅草稿或已驳回可提交),将继续提交其余 ${validTargets.length} 条`
)
}
loadingMap.submit = true
try {
for (const row of selectedRows.value) {
await advanceApi.submit(row.id)
const results = await Promise.allSettled(validTargets.map((row) => advanceApi.submit(row.id)))
const successCount = results.filter((item) => item.status === 'fulfilled').length
const failedCount = results.length - successCount
const skipText = skippedCount > 0 ? `,跳过 ${skippedCount} 条` : ''
if (successCount === 0) {
ElMessage.error(`提交失败${skipText}`)
return
}
if (failedCount > 0) {
ElMessage.warning(`成功提交 ${successCount} 条,失败 ${failedCount} 条${skipText}`)
} else if (successCount === 1 && skippedCount === 0) {
ElMessage.success('提交成功')
} else {
ElMessage.success(`成功提交 ${successCount} 条${skipText}`)
}
ElMessage.success('提交成功')
await refreshList()
} catch (e: any) {
ElMessage.error(e?.message || '提交失败')
} finally {
loadingMap.submit = false
}
@@ -420,6 +420,22 @@
destroy-on-close
:close-on-click-modal="false"
>
<el-alert
v-if="approveRows.length > 1"
type="success"
:closable="false"
show-icon
class="batch-action-alert batch-action-alert--success"
:title="`将${approveAction === 'approve' ? '审批通过' : '审批驳回'} ${approveRows.length} 条申请(使用同一审批意见)`"
/>
<el-alert
v-if="approveSkippedCount > 0"
type="error"
:closable="false"
show-icon
class="batch-action-alert batch-action-alert--danger"
:title="`已跳过 ${approveSkippedCount} 条不可审批的申请`"
/>
<el-form label-position="top" class="bx-dialog-form">
<div class="form-grid-2">
<el-form-item label="审批时间">
@@ -570,8 +586,32 @@ function formatNow() {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
const approveSkippedCount = ref(0)
function isApprovableRow(row?: any) {
if (!row) return false
return !row.status || row.status === 'pending'
}
function openApproveDialog(rows: any[], action: 'approve' | 'reject') {
approveRows.value = rows
const validRows = (rows || []).filter(isApprovableRow)
const skippedCount = (rows || []).length - validRows.length
if (!validRows.length) {
ElMessage.warning(
action === 'approve' ? '所选申请均不可审批通过' : '所选申请均不可驳回'
)
return
}
if (skippedCount > 0) {
ElMessage.warning(
`已跳过 ${skippedCount} 条不可审批的申请,将继续处理其余 ${validRows.length} 条`
)
}
approveRows.value = validRows
approveSkippedCount.value = skippedCount
approveAction.value = action
approvalOpinion.value = action === 'approve' ? '审批通过' : '审批驳回'
approveTime.value = formatNow()
@@ -742,22 +782,61 @@ const pendingSummaryMethod = amountSummary
const approvedSummaryMethod = amountSummary
async function handleConfirmApprove() {
if (!approveRows.value.length) {
ElMessage.warning('没有可审批的申请')
return
}
const key = approveAction.value === 'approve' ? 'approvePass' : 'approveReject'
loadingMap[key] = true
const apiFn = approveAction.value === 'approve' ? advanceApi.approve : advanceApi.reject
const msg = approveAction.value === 'approve' ? '审批通过成功' : '驳回成功'
const actionLabel = approveAction.value === 'approve' ? '审批通过' : '审批驳回'
try {
for (const row of approveRows.value) {
await apiFn(row.id, { approvalOpinion: approvalOpinion.value })
const results = await Promise.allSettled(
approveRows.value.map((row) => apiFn(row.id, { approvalOpinion: approvalOpinion.value }))
)
const successCount = results.filter((item) => item.status === 'fulfilled').length
const failedCount = results.length - successCount
const skipText = approveSkippedCount.value > 0 ? `,跳过 ${approveSkippedCount.value} 条` : ''
if (successCount === 0) {
ElMessage.error(`${actionLabel}失败${skipText}`)
return
}
ElMessage.success(approveRows.value.length > 1 ? `批量${msg}` : msg)
if (failedCount > 0) {
ElMessage.warning(`成功${actionLabel} ${successCount} 条,失败 ${failedCount} 条${skipText}`)
} else if (successCount === 1 && approveSkippedCount.value === 0) {
ElMessage.success(`${actionLabel}成功`)
} else {
ElMessage.success(`成功${actionLabel} ${successCount} 条${skipText}`)
}
dialogs.approve = false
await refreshPending()
await refreshMenuBadges(menuStore.menuList)
} catch (e: any) {
ElMessage.error(e?.message || '操作失败')
} finally {
loadingMap[key] = false
}
}
</script>
<style scoped lang="scss">
.batch-action-alert {
margin-bottom: 12px;
&--success {
:deep(.el-alert__title),
:deep(.el-alert__icon) {
color: var(--primary, #10b981);
}
}
&--danger {
:deep(.el-alert__title),
:deep(.el-alert__icon) {
color: #ef4444;
}
}
}
</style>
@@ -1107,13 +1107,22 @@ async function handleToolbarSubmit() {
ElMessage.warning('请先勾选要提交的报销单')
return
}
if (!selectedRows.value.every(isDraftEditable)) {
ElMessage.warning('仅草稿或已驳回的报销单可提交')
const validTargets = selectedRows.value.filter(isDraftEditable)
const skippedCount = selectedRows.value.length - validTargets.length
if (!validTargets.length) {
ElMessage.warning('所选报销单均不是草稿或已驳回状态,无法提交审批')
return
}
if (skippedCount > 0) {
ElMessage.warning(`已跳过 ${skippedCount} 条不可提交的报销单(仅草稿或已驳回可提交),将继续提交其余 ${validTargets.length} 条`)
}
// 按申请人分别校验发票余额(代申请时用申请人额度)
const needByApplicant = new Map<string, number>()
for (const row of selectedRows.value) {
for (const row of validTargets) {
const aid = String(row.applicantId || currentUserId())
needByApplicant.set(aid, (needByApplicant.get(aid) || 0) + Number(row.amount || 0))
}
@@ -1126,15 +1135,26 @@ async function handleToolbarSubmit() {
return
}
}
loadingMap.submit = true
try {
for (const row of selectedRows.value) {
await reimburseApi.submit(row.id)
const results = await Promise.allSettled(validTargets.map((row) => reimburseApi.submit(row.id)))
const successCount = results.filter((item) => item.status === 'fulfilled').length
const failedCount = results.length - successCount
const skipText = skippedCount > 0 ? `,跳过 ${skippedCount} 条` : ''
if (successCount === 0) {
ElMessage.error(`提交失败${skipText}`)
return
}
if (failedCount > 0) {
ElMessage.warning(`成功提交 ${successCount} 条,失败 ${failedCount} 条${skipText}`)
} else if (successCount === 1 && skippedCount === 0) {
ElMessage.success('提交成功')
} else {
ElMessage.success(`成功提交 ${successCount} 条${skipText}`)
}
ElMessage.success('提交成功')
await refreshList()
} catch (e: any) {
ElMessage.error(e?.message || '提交失败')
} finally {
loadingMap.submit = false
}
@@ -551,6 +551,22 @@
destroy-on-close
:close-on-click-modal="false"
>
<el-alert
v-if="approveRows.length > 1"
type="success"
:closable="false"
show-icon
class="batch-action-alert batch-action-alert--success"
:title="`将${approveAction === 'approve' ? '审批通过' : '审批驳回'} ${approveRows.length} 条报销单(使用同一审批意见)`"
/>
<el-alert
v-if="approveSkippedCount > 0"
type="error"
:closable="false"
show-icon
class="batch-action-alert batch-action-alert--danger"
:title="`已跳过 ${approveSkippedCount} 条不可审批的报销单`"
/>
<el-form label-position="top" class="bx-dialog-form">
<div class="form-grid-2">
<el-form-item label="审批时间">
@@ -741,8 +757,35 @@ function formatNow() {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
const approveSkippedCount = ref(0)
function isApprovableRow(row?: any) {
if (!row) return false
// 待审批列表中的单据;若状态已变则不可再审
return !row.status || row.status === 'pending'
}
function openApproveDialog(rows: any[], action: 'approve' | 'reject') {
approveRows.value = rows
const validRows = (rows || []).filter(isApprovableRow)
const skippedCount = (rows || []).length - validRows.length
if (!validRows.length) {
ElMessage.warning(
action === 'approve'
? '所选报销单均不可审批通过'
: '所选报销单均不可驳回'
)
return
}
if (skippedCount > 0) {
ElMessage.warning(
`已跳过 ${skippedCount} 条不可审批的报销单,将继续处理其余 ${validRows.length} 条`
)
}
approveRows.value = validRows
approveSkippedCount.value = skippedCount
approveAction.value = action
approvalOpinion.value = action === 'approve' ? '审批通过' : '审批驳回'
approveTime.value = formatNow()
@@ -943,20 +986,39 @@ async function openView(row: any) {
}
async function handleConfirmApprove() {
if (!approveRows.value.length) {
ElMessage.warning('没有可审批的报销单')
return
}
const key = approveAction.value === 'approve' ? 'approvePass' : 'approveReject'
loadingMap[key] = true
const apiFn = approveAction.value === 'approve' ? reimburseApi.approve : reimburseApi.reject
const msg = approveAction.value === 'approve' ? '审批通过成功' : '驳回成功'
const actionLabel = approveAction.value === 'approve' ? '审批通过' : '审批驳回'
try {
for (const row of approveRows.value) {
await apiFn(row.id, { approvalOpinion: approvalOpinion.value })
const results = await Promise.allSettled(
approveRows.value.map((row) => apiFn(row.id, { approvalOpinion: approvalOpinion.value }))
)
const successCount = results.filter((item) => item.status === 'fulfilled').length
const failedCount = results.length - successCount
const skipText = approveSkippedCount.value > 0 ? `,跳过 ${approveSkippedCount.value} 条` : ''
if (successCount === 0) {
ElMessage.error(`${actionLabel}失败${skipText}`)
return
}
ElMessage.success(approveRows.value.length > 1 ? `批量${msg}` : msg)
if (failedCount > 0) {
ElMessage.warning(`成功${actionLabel} ${successCount} 条,失败 ${failedCount} 条${skipText}`)
} else if (successCount === 1 && approveSkippedCount.value === 0) {
ElMessage.success(`${actionLabel}成功`)
} else {
ElMessage.success(`成功${actionLabel} ${successCount} 条${skipText}`)
}
dialogs.approve = false
await refreshPending()
await refreshMenuBadges(menuStore.menuList)
} catch (e: any) {
ElMessage.error(e?.message || '操作失败')
} finally {
loadingMap[key] = false
}
@@ -987,3 +1049,23 @@ function viewDetailSummary({ columns, data }: { columns: any[]; data: any[] }) {
return sums
}
</script>
<style scoped lang="scss">
.batch-action-alert {
margin-bottom: 12px;
&--success {
:deep(.el-alert__title),
:deep(.el-alert__icon) {
color: var(--primary, #10b981);
}
}
&--danger {
:deep(.el-alert__title),
:deep(.el-alert__icon) {
color: #ef4444;
}
}
}
</style>
+8 -6
View File
@@ -496,7 +496,7 @@ async function handleApprove(row: any) {
loadingMap[key] = true
try {
const api = row.bizType === '备用金' ? advanceApi : reimburseApi
await api.approve(row.id, { approvalOpinion: '' })
await api.approve(row.id, { approvalOpinion: '审批通过' })
ElMessage.success('审批通过')
await loadData()
await refreshSidebarBadges()
@@ -509,7 +509,7 @@ async function handleApprove(row: any) {
function openRejectDialog(row: any) {
currentRow.value = row
approveOpinion.value = ''
approveOpinion.value = '审批驳回'
dialogs.approve = true
}
@@ -518,7 +518,8 @@ async function handleDialogApprove() {
loadingMap.approvePass = true
try {
const api = currentRow.value.bizType === '备用金' ? advanceApi : reimburseApi
await api.approve(currentRow.value.id, { approvalOpinion: approveOpinion.value })
const opinion = approveOpinion.value.trim() || '审批通过'
await api.approve(currentRow.value.id, { approvalOpinion: opinion })
ElMessage.success('审批通过')
dialogs.approve = false
await loadData()
@@ -535,7 +536,8 @@ async function handleDialogReject() {
loadingMap.approveReject = true
try {
const api = currentRow.value.bizType === '备用金' ? advanceApi : reimburseApi
await api.reject(currentRow.value.id, { approvalOpinion: approveOpinion.value })
const opinion = approveOpinion.value.trim() || '审批驳回'
await api.reject(currentRow.value.id, { approvalOpinion: opinion })
ElMessage.success('已驳回')
dialogs.approve = false
await loadData()
@@ -562,7 +564,7 @@ async function handleBatchPass() {
try {
for (const row of selectedRows.value) {
const api = row.bizType === '备用金' ? advanceApi : reimburseApi
await api.approve(row.id, { approvalOpinion: '' })
await api.approve(row.id, { approvalOpinion: '审批通过' })
}
ElMessage.success('批量审批通过成功')
await loadData()
@@ -583,7 +585,7 @@ async function handleBatchReject() {
try {
for (const row of selectedRows.value) {
const api = row.bizType === '备用金' ? advanceApi : reimburseApi
await api.reject(row.id, { approvalOpinion: '' })
await api.reject(row.id, { approvalOpinion: '审批驳回' })
}
ElMessage.success('批量驳回成功')
await loadData()