From 6db74ed7bf5e56554d497ea4f6b692d5b7d78793 Mon Sep 17 00:00:00 2001
From: caojia <1301869380@qq.com>
Date: Tue, 22 Sep 2026 13:59:04 +0800
Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E7=BB=A7=E7=BB=AD=E7=94=9F?=
=?UTF-8?q?=E6=88=90=E7=AC=A6=E5=90=88=E2=80=9C=E5=8F=96=E6=B6=88=E9=9C=80?=
=?UTF-8?q?=E4=BA=8C=E6=AC=A1=E7=A1=AE=E8=AE=A4=E2=80=9D=E7=9A=84=E7=8E=B0?=
=?UTF-8?q?=E6=9C=89=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BD=86=E5=BC=B9=E7=AA=97?=
=?UTF-8?q?=E7=8A=B6=E6=80=81=E6=B2=A1=E6=9C=89=E8=B7=9F=E9=9A=8F=E4=BB=BB?=
=?UTF-8?q?=E5=8A=A1=E5=AE=8C=E6=88=90=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0?=
=?UTF-8?q?=EF=BC=8C=E5=B1=9E=E4=BA=8E=E4=BA=A4=E4=BA=92=E7=AB=9E=E6=80=81?=
=?UTF-8?q?=E9=97=AE=E9=A2=98=20=E5=B7=B2=E4=BF=AE=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
bms-front/src/views/ar/bill/index.vue | 82 +++++++++++++++++++++++++--
1 file changed, 76 insertions(+), 6 deletions(-)
diff --git a/bms-front/src/views/ar/bill/index.vue b/bms-front/src/views/ar/bill/index.vue
index 1a129f47..566bbdce 100644
--- a/bms-front/src/views/ar/bill/index.vue
+++ b/bms-front/src/views/ar/bill/index.vue
@@ -3,7 +3,7 @@
+ :disabled="!canCancelActiveGenerateTask" @click="cancelActiveGenerateTask">
{{ generateProgressText }}
@@ -50,6 +50,16 @@
+
+ 账单正在后台生成,确定取消当前任务吗?
+
+ 暂不取消
+ {{ cancelConfirmLoading ? '取消中' : '确定取消' }}
+
+
@@ -83,13 +93,27 @@ const generateTasks = reactive(new Map())
const activeGenerateTasks = computed(() => Array.from(generateTasks.values()))
const activeGenerateTask = computed(() => activeGenerateTasks.value[0])
const generateStatusVisible = computed(() => activeGenerateTasks.value.length > 0)
+const cancelConfirmVisible = ref(false)
+const cancelConfirmLoading = ref(false)
+const cancelConfirmTaskId = ref()
+const cancelConfirmTask = computed(() => cancelConfirmTaskId.value ? generateTasks.get(cancelConfirmTaskId.value) : null)
+const canCancelActiveGenerateTask = computed(() => ['WAITING', 'RUNNING'].includes(activeGenerateTask.value?.status))
+const cancelConfirmDisabled = computed(() => {
+ return cancelConfirmLoading.value || !['WAITING', 'RUNNING'].includes(cancelConfirmTask.value?.status)
+})
const generateStatusTitle = computed(() => {
const status = activeGenerateTask.value?.status
if (status === 'WAITING') return '账单排队中'
+ if (status === 'SUCCESS') return '账单生成完成'
+ if (status === 'FAILED') return '账单生成失败'
+ if (status === 'CANCELED') return '账单已取消'
if (status === 'CANCEL_REQUESTED') return '账单取消中'
return '账单生成中'
})
const generateStatusTooltip = computed(() => {
+ if (['SUCCESS', 'FAILED', 'CANCELED'].includes(activeGenerateTask.value?.status)) {
+ return '任务状态已更新'
+ }
return activeGenerateTask.value?.status === 'CANCEL_REQUESTED'
? '正在清理已生成的账单数据,请稍候'
: '点击取消当前账单生成任务'
@@ -107,6 +131,8 @@ const generateProgressDegree = computed(() => {
const generateStatusSummary = computed(() => {
const task = activeGenerateTask.value
if (!task) return '任务提交中'
+ if (task.status === 'FAILED') return '任务执行失败'
+ if (task.status === 'CANCELED') return '任务已取消'
if (task.status === 'CANCEL_REQUESTED') return '正在清理数据'
if (task.status === 'WAITING') return '等待后台处理'
if (Number(task.totalCount) > 0) return `${Number(task.processedCount || 0)} / ${Number(task.totalCount)} 条`
@@ -164,6 +190,7 @@ function startGeneratePolling(taskId) {
function finishGenerateTask(taskId, task) {
stopGeneratePolling(taskId)
+ closeCancelConfirm(taskId)
if (generateFinishTimers.has(taskId)) return
// 即使后台很快返回 SUCCESS,也延迟清理浮层,保证用户能看到结果反馈。
const visibleSince = generateVisibleSince.get(taskId) || Date.now()
@@ -200,12 +227,50 @@ function stopGeneratePolling(taskId) {
function cancelActiveGenerateTask() {
const task = activeGenerateTask.value
- if (!task?.taskId) return
- proxy.$modal.confirm('账单正在后台生成,确定取消当前任务吗?').then(() => cancelArBillGenerateTask(task.taskId)).then(res => {
+ if (!task?.taskId || !canCancelActiveGenerateTask.value) return
+ cancelConfirmTaskId.value = task.taskId
+ cancelConfirmLoading.value = false
+ cancelConfirmVisible.value = true
+}
+
+async function confirmCancelActiveGenerateTask() {
+ const taskId = cancelConfirmTaskId.value
+ const task = taskId ? generateTasks.get(taskId) : null
+ if (!taskId || !['WAITING', 'RUNNING'].includes(task?.status)) {
+ cancelConfirmVisible.value = false
+ return
+ }
+ cancelConfirmLoading.value = true
+ try {
+ const res = await cancelArBillGenerateTask(taskId)
const updated = res.data
- if (updated) generateTasks.set(updated.taskId, updated)
- proxy.$modal.msgSuccess('已提交取消请求')
- }).catch(() => {})
+ let cancellationSubmitted = true
+ if (updated?.taskId) {
+ generateTasks.set(updated.taskId, updated)
+ if (['SUCCESS', 'FAILED', 'CANCELED'].includes(updated.status)) {
+ finishGenerateTask(updated.taskId, updated)
+ cancellationSubmitted = false
+ }
+ }
+ cancelConfirmVisible.value = false
+ if (cancellationSubmitted) proxy.$modal.msgSuccess('已提交取消请求')
+ } catch (error) {
+ // 请求失败时保留弹窗,允许用户重新确认;全局请求拦截器负责展示错误信息。
+ } finally {
+ cancelConfirmLoading.value = false
+ }
+}
+
+function closeCancelConfirm(taskId) {
+ if (cancelConfirmTaskId.value !== taskId) return
+ cancelConfirmVisible.value = false
+ cancelConfirmLoading.value = false
+ cancelConfirmTaskId.value = undefined
+}
+
+function handleCancelConfirmClosed() {
+ cancelConfirmLoading.value = false
+ cancelConfirmTaskId.value = undefined
}
function loadActiveGenerateTasks() {
@@ -390,6 +455,11 @@ function statusType(value) { return AR_BILL_STATUS_TYPES[value] || 'info' }
.ar-bill-page .amount { color: #f56c6c; font-weight: 600; }
.ar-bill-page .written { color: #67c23a; }
.ar-bill-page .unwritten { color: #e6a23c; }
+.ar-bill-page .cancel-generate-message {
+ margin: 0;
+ color: var(--el-text-color-primary);
+ line-height: 1.7;
+}
.ar-bill-page .generate-status-float {
position: fixed;