共 {{ cancelBatch.previewTotal }} 个待执行任务将被取消{{ cancelBatch.previewTotal > cancelBatch.preview.length ? `(仅列出前 ${cancelBatch.preview.length} 个)` : '' }}:
@@ -114,6 +114,16 @@ export default { cancelBatch: { open: false, previewLoading: false, submitting: false, preview: [], previewTotal: 0 } } }, + computed: { + isAdmin() { return (this.$store.getters.roles || []).includes('admin') }, + // #387:采购员未选设备时不能批量取消(服务端同样拒绝);管理员不受限。 + cancelNeedsDevice() { return !this.isAdmin && !this.query.deviceId }, + cancelDeviceLabel() { + if (!this.query.deviceId) return '全部设备(含未指定设备)' + const found = this.deviceFilterOptions.find(item => item.id === this.query.deviceId) + return `设备「${found ? found.name : this.query.deviceId}」` + } + }, created() { this.getList(); this.refreshPendingCancelCount(); this.loadDeviceFilterOptions() }, watch: { // `[必须]` 取消范围必须与眼前的列表一致,三个筛选项都要联动。少了 Goods ID @@ -135,20 +145,21 @@ export default { // 取消范围只对「状态筛选为空或恰好是待执行」才有意义:其它状态下这个筛选 // 条件里不可能存在待执行任务,角标应该直接显示 0 并禁用按钮,而不是拿一个 // 与实际可取消数量无关的数字误导采购员。 - // 批量取消接口不支持设备维度;选了设备筛选时禁用,避免取消范围超出眼前列表。 - cancelScopeStatus() { if (this.query.deviceId) return null; return this.query.status === '' || this.query.status === 'pending' ? 'pending' : null }, + // #387:设备维度也参与取消范围;采购员必须先选设备,且服务端只允许取消本人设备的任务。 + cancelScopeStatus() { return this.query.status === '' || this.query.status === 'pending' ? 'pending' : null }, async refreshPendingCancelCount() { const status = this.cancelScopeStatus() - if (!status) { this.pendingCancelCount = 0; return } - const r = await listCollectionTasks({ page: 1, pageSize: 1, status, source: this.query.source || undefined, goodsId: this.query.goodsId || undefined }) + if (!status || this.cancelNeedsDevice) { this.pendingCancelCount = 0; return } + const r = await listCollectionTasks({ page: 1, pageSize: 1, status, deviceId: this.query.deviceId || undefined, source: this.query.source || undefined, goodsId: this.query.goodsId || undefined }) this.pendingCancelCount = r.data.total }, async openCancelBatch() { + if (this.cancelNeedsDevice) { ElMessage.warning('请先在「设备」筛选中选择要取消任务的设备'); return } const status = this.cancelScopeStatus() if (!status) return this.cancelBatch = { open: true, previewLoading: true, submitting: false, preview: [], previewTotal: 0 } try { - const r = await listCollectionTasks({ page: 1, pageSize: 50, status, source: this.query.source || undefined, goodsId: this.query.goodsId || undefined }) + const r = await listCollectionTasks({ page: 1, pageSize: 50, status, deviceId: this.query.deviceId || undefined, source: this.query.source || undefined, goodsId: this.query.goodsId || undefined }) this.cancelBatch.preview = r.data.items this.cancelBatch.previewTotal = r.data.total } finally { this.cancelBatch.previewLoading = false } @@ -158,7 +169,7 @@ export default { if (!status) return this.cancelBatch.submitting = true try { - const response = await batchCancelCollectionTasks({ source: this.query.source || undefined, status, goodsId: this.query.goodsId || undefined }) + const response = await batchCancelCollectionTasks({ source: this.query.source || undefined, status, deviceId: this.query.deviceId || undefined, goodsId: this.query.goodsId || undefined }) const skippedText = response.data.skipped?.length ? `,${response.data.skipped.length} 个因执行中或已被设备领取而跳过(任务号:${response.data.skipped.map(item => item.taskId).join('、')})` : '' ElMessage.success(`已取消 ${response.data.cancelledCount} 个任务${skippedText}`) if (response.data.hasMore) {