账单异步生成优化
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<el-col :span="8"><el-form-item label="客户" prop="customerId"><customer-select v-model="generateForm.customerId" placeholder="请选择客户" @change="handleCustomerChange" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="币种" prop="currency"><el-select v-model="generateForm.currency" placeholder="请选择币种" style="width: 100%;" @change="handleCurrencyChange"><el-option label="人民币 CNY" value="CNY" /><el-option label="美元 USD" value="USD" /></el-select></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="账单截止日" prop="cutoffDate"><el-date-picker v-model="generateForm.cutoffDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择账单截止日" style="width: 100%;" @change="resetPreview" /></el-form-item></el-col>
|
||||
<el-col :span="8"><el-form-item label="订单/运单号"><el-input v-model="generateForm.orderOrTrackingNo" placeholder="请输入订单号或运单号" clearable /></el-form-item></el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div class="payee-card" v-loading="bankAccountLoading">
|
||||
@@ -18,14 +19,47 @@
|
||||
<span v-else class="payee-empty">当前币种尚未配置公司默认收款账户</span>
|
||||
</div>
|
||||
<div class="preview-toolbar">
|
||||
<span v-if="previewSearched" class="preview-summary">可选 {{ previewRows.length }} 条订单,已选 <b>{{ selectedRows.length }}</b> 条,应收合计 <b>{{ money(selectedAmount) }}</b></span>
|
||||
<span v-if="previewSearched" class="preview-summary">可选 {{ previewTotal }} 条订单,已选 <b>{{ displaySelectedCount }}</b> 条,应收合计 <b>{{ money(displaySelectedAmount) }}</b></span>
|
||||
<span v-else class="preview-summary">请选择客户、币种和账单截止日后查询可生成的计费订单</span>
|
||||
<el-button type="primary" plain :loading="previewLoading" :disabled="!bankAccount" @click="queryGeneratePreview">查询</el-button>
|
||||
</div>
|
||||
<div v-if="previewSearched" class="preview-selection-toolbar">
|
||||
<el-tooltip content="全选全部查询结果" placement="top">
|
||||
<el-checkbox
|
||||
:model-value="allSelected"
|
||||
:disabled="!previewTotal"
|
||||
aria-label="全选全部查询结果"
|
||||
@change="handleSelectAllChange"
|
||||
>
|
||||
<el-icon><Select /></el-icon>
|
||||
</el-checkbox>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="切换手动选择" placement="top">
|
||||
<el-checkbox
|
||||
:model-value="selectionMode === AR_BILL_SELECTION_MODE.EXPLICIT"
|
||||
:disabled="!previewTotal || selectionMode === AR_BILL_SELECTION_MODE.EXPLICIT"
|
||||
aria-label="切换手动选择"
|
||||
@change="handleManualModeChange"
|
||||
>
|
||||
<el-icon><Refresh /></el-icon>
|
||||
</el-checkbox>
|
||||
</el-tooltip>
|
||||
<el-badge v-if="allSelected" :value="excludedRows.length" :hidden="!excludedRows.length" class="exclude-order-badge">
|
||||
<el-tooltip content="选择排除订单" placement="top">
|
||||
<el-button circle text :icon="Search" aria-label="选择排除订单" @click="openExcludeDialog" />
|
||||
</el-tooltip>
|
||||
</el-badge>
|
||||
</div>
|
||||
<div v-if="allSelected && excludedRows.length" class="excluded-order-preview">
|
||||
<span class="excluded-order-title">排除订单:</span>
|
||||
<el-tag v-for="row in excludedRows" :key="row.billId" closable size="small" @close="removeExcludedRow(row.billId)">
|
||||
{{ row.orderNo || row.trackingNo || row.billId }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<el-table ref="previewTableRef" v-loading="previewLoading" :data="previewRows" row-key="billId" border stripe max-height="400" empty-text="暂无符合条件的计费订单" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="50" fixed="left" />
|
||||
<el-table-column type="selection" width="50" fixed="left" :selectable="isMainRowSelectable" />
|
||||
<el-table-column prop="orderNo" label="订单号" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="trackingNo" label="跟踪号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="trackingNo" label="运单号" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" min-width="130" show-overflow-tooltip />
|
||||
<el-table-column prop="bizDate" label="业务日期" width="105" :formatter="formatDateColumn" />
|
||||
<el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip />
|
||||
@@ -35,20 +69,59 @@
|
||||
<el-table-column prop="incomeTotal" label="应收金额" width="110" align="right" :formatter="formatNumberColumn" />
|
||||
<el-table-column prop="currency" label="币种" width="75" />
|
||||
</el-table>
|
||||
<el-pagination
|
||||
v-if="previewTotal > 0"
|
||||
class="preview-pagination"
|
||||
:current-page="previewPageNum"
|
||||
:page-size="previewPageSize"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="previewTotal"
|
||||
@current-change="handlePreviewPageChange"
|
||||
/>
|
||||
<template #footer>
|
||||
<span class="generate-footer-summary">已选 {{ selectedRows.length }} 条订单 · {{ money(selectedAmount) }}</span>
|
||||
<el-button type="primary" :loading="generateLoading" :disabled="!bankAccount || !previewSearched || !selectedRows.length" @click="submitGenerate">生成账单</el-button>
|
||||
<span class="generate-footer-summary">已选 {{ displaySelectedCount }} 条订单 · {{ money(displaySelectedAmount) }}</span>
|
||||
<el-button type="primary" :loading="generateLoading" :disabled="!bankAccount || !previewSearched || !displaySelectedCount" @click="submitGenerate">生成账单</el-button>
|
||||
<el-button @click="dialogOpen = false">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="excludeDialogOpen" title="选择排除订单" width="1100px" append-to-body destroy-on-close @close="handleExcludeDialogClose">
|
||||
<div class="exclude-toolbar">
|
||||
<el-input v-model="excludeKeyword" clearable placeholder="请输入订单号或运单号" class="exclude-search-input" />
|
||||
<el-button type="primary" :loading="excludeLoading" @click="queryExcludeRows">查询</el-button>
|
||||
</div>
|
||||
<el-table ref="excludeTableRef" v-loading="excludeLoading" :data="excludeRowsPage" row-key="billId" border stripe max-height="420" empty-text="暂无符合条件的订单" @selection-change="handleExcludeSelectionChange">
|
||||
<el-table-column type="selection" width="50" fixed="left" />
|
||||
<el-table-column prop="orderNo" label="订单号" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column prop="trackingNo" label="运单号" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="customerName" label="客户" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="bizDate" label="业务日期" width="120" :formatter="formatDateColumn" />
|
||||
<el-table-column prop="incomeTotal" label="应收金额" width="130" align="right" :formatter="formatNumberColumn" />
|
||||
<el-table-column prop="currency" label="币种" width="80" />
|
||||
</el-table>
|
||||
<el-pagination
|
||||
v-if="excludeTotal > 0"
|
||||
class="exclude-pagination"
|
||||
:current-page="excludePageNum"
|
||||
:page-size="excludePageSize"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="excludeTotal"
|
||||
@current-change="handleExcludePageChange"
|
||||
/>
|
||||
<template #footer>
|
||||
<span class="generate-footer-summary">已选择 {{ excludeDraftRows.length }} 条排除订单</span>
|
||||
<el-button @click="cancelExcludeSelection">取消</el-button>
|
||||
<el-button type="primary" @click="confirmExcludeSelection">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="billNameOpen" title="填写账单名称" width="520px" append-to-body destroy-on-close>
|
||||
<el-form ref="billNameFormRef" :model="billNameForm" :rules="billNameRules" label-width="90px">
|
||||
<el-form-item label="账单名称" prop="billName">
|
||||
<el-input v-model="billNameForm.billName" maxlength="100" show-word-limit placeholder="请输入账单名称" clearable @keyup.enter="confirmGenerate" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="bill-name-summary">已选择 {{ selectedRows.length }} 条订单,应收合计 {{ money(selectedAmount) }}</div>
|
||||
<div class="bill-name-summary">已选择 {{ displaySelectedCount }} 条订单,应收合计 {{ money(displaySelectedAmount) }}</div>
|
||||
<template #footer>
|
||||
<el-button @click="billNameOpen = false">取消</el-button>
|
||||
<el-button type="primary" :loading="generateLoading" @click="confirmGenerate">确认生成</el-button>
|
||||
@@ -59,6 +132,8 @@
|
||||
|
||||
<script setup name="GenerateBillDialog">
|
||||
import { getDefaultArBankAccount, previewArBill, generateArBill } from '@/api/ar/bill'
|
||||
import { Refresh, Search, Select } from '@element-plus/icons-vue'
|
||||
import { AR_BILL_SELECTION_MODE } from '@/constants/ar/enums'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
@@ -78,14 +153,39 @@ const generateLoading = ref(false)
|
||||
const previewLoading = ref(false)
|
||||
const previewSearched = ref(false)
|
||||
const previewRows = ref([])
|
||||
const previewTotal = ref(0)
|
||||
const previewTotalAmount = ref(0)
|
||||
const previewPageNum = ref(1)
|
||||
// 主预览列表固定每页 5 条;Map 负责保存跨页勾选结果。
|
||||
const previewPageSize = 5
|
||||
const previewTableRef = ref()
|
||||
const selectedRows = ref([])
|
||||
const selectedRowMap = new Map()
|
||||
// 选择模式只保存编码,提交时由后端枚举再次校验。
|
||||
const selectionMode = ref(AR_BILL_SELECTION_MODE.EXPLICIT)
|
||||
const excludedRows = ref([])
|
||||
const excludedRowMap = new Map()
|
||||
const excludeDialogOpen = ref(false)
|
||||
const excludeLoading = ref(false)
|
||||
const excludeKeyword = ref('')
|
||||
const excludeRowsPage = ref([])
|
||||
const excludeTotal = ref(0)
|
||||
const excludePageNum = ref(1)
|
||||
// 全选后的排除弹窗也按 5 条分页,查询条件固定继承主弹窗条件。
|
||||
const excludePageSize = 5
|
||||
const excludeTableRef = ref()
|
||||
const excludeDraftRows = ref([])
|
||||
let excludeDraftMap = new Map()
|
||||
let excludeDialogConfirmed = false
|
||||
let syncingExcludeSelection = false
|
||||
const previewQuery = ref(null)
|
||||
let syncingPageSelection = false
|
||||
const bankAccountLoading = ref(false)
|
||||
const bankAccount = ref(null)
|
||||
const generateRequestId = ref('')
|
||||
const generateFormRef = ref()
|
||||
const billNameFormRef = ref()
|
||||
const generateForm = reactive({ customerId: '', customerCode: '', cutoffDate: '', currency: 'CNY' })
|
||||
const generateForm = reactive({ customerId: '', customerCode: '', customerName: '', cutoffDate: '', currency: 'CNY', orderOrTrackingNo: '' })
|
||||
const billNameForm = reactive({ billName: '' })
|
||||
const generateRules = {
|
||||
customerId: [{ required: true, message: '客户不能为空', trigger: 'change' }],
|
||||
@@ -94,6 +194,12 @@ const generateRules = {
|
||||
}
|
||||
const billNameRules = { billName: [{ required: true, message: '请输入账单名称', trigger: 'blur' }] }
|
||||
const selectedAmount = computed(() => selectedRows.value.reduce((sum, row) => sum + (Number(row.incomeTotal) || 0), 0))
|
||||
const excludedAmount = computed(() => excludedRows.value.reduce((sum, row) => sum + (Number(row.incomeTotal) || 0), 0))
|
||||
const allSelected = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED)
|
||||
const displaySelectedCount = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED
|
||||
? Math.max(previewTotal.value - excludedRows.value.length, 0) : selectedRows.value.length)
|
||||
const displaySelectedAmount = computed(() => selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED
|
||||
? Math.max(Number(previewTotalAmount.value || 0) - excludedAmount.value, 0) : selectedAmount.value)
|
||||
|
||||
watch(() => props.modelValue, visible => {
|
||||
if (visible) {
|
||||
@@ -101,8 +207,9 @@ watch(() => props.modelValue, visible => {
|
||||
}
|
||||
})
|
||||
|
||||
// 每次打开生成弹窗都重新建立一次查询快照,避免复用上一次的选中订单。
|
||||
function openGenerate() {
|
||||
Object.assign(generateForm, { customerId: '', customerCode: '', cutoffDate: '', currency: 'CNY' })
|
||||
Object.assign(generateForm, { customerId: '', customerCode: '', customerName: '', cutoffDate: '', currency: 'CNY', orderOrTrackingNo: '' })
|
||||
Object.assign(billNameForm, { billName: '' })
|
||||
billNameOpen.value = false
|
||||
resetPreview()
|
||||
@@ -113,6 +220,7 @@ function openGenerate() {
|
||||
|
||||
function handleCustomerChange(_, item) {
|
||||
generateForm.customerCode = item?.customerCode || ''
|
||||
generateForm.customerName = item?.customerName || ''
|
||||
resetPreview()
|
||||
}
|
||||
|
||||
@@ -131,9 +239,21 @@ function loadDefaultBankAccount() {
|
||||
})
|
||||
}
|
||||
|
||||
// 条件变化后清理预览和跨页选中状态;用户点击查询时重新加载第一页。
|
||||
function resetPreview() {
|
||||
previewRows.value = []
|
||||
previewTotal.value = 0
|
||||
previewTotalAmount.value = 0
|
||||
previewPageNum.value = 1
|
||||
selectedRows.value = []
|
||||
selectedRowMap.clear()
|
||||
selectionMode.value = AR_BILL_SELECTION_MODE.EXPLICIT
|
||||
excludedRows.value = []
|
||||
excludedRowMap.clear()
|
||||
excludeDraftRows.value = []
|
||||
excludeDraftMap = new Map()
|
||||
excludeDialogOpen.value = false
|
||||
previewQuery.value = null
|
||||
previewSearched.value = false
|
||||
generateRequestId.value = ''
|
||||
nextTick(() => previewTableRef.value?.clearSelection())
|
||||
@@ -143,41 +263,225 @@ function buildGenerateQuery() {
|
||||
return {
|
||||
customerId: Number(generateForm.customerId),
|
||||
customerCode: generateForm.customerCode?.trim() || undefined,
|
||||
customerName: generateForm.customerName?.trim() || undefined,
|
||||
billPeriodEnd: generateForm.cutoffDate,
|
||||
currency: generateForm.currency || undefined
|
||||
currency: generateForm.currency || undefined,
|
||||
orderOrTrackingNo: generateForm.orderOrTrackingNo?.trim() || undefined
|
||||
}
|
||||
}
|
||||
|
||||
// 任务请求携带完整筛选快照;全选模式只提交排除 ID,后台按条件游标扫描其余订单。
|
||||
function buildGenerateRequest(requestId) {
|
||||
return {
|
||||
...buildGenerateQuery(),
|
||||
...(previewQuery.value || buildGenerateQuery()),
|
||||
billName: billNameForm.billName.trim(),
|
||||
sourceBillIds: selectedRows.value.map(row => row.billId),
|
||||
selectionMode: selectionMode.value,
|
||||
sourceBillIds: selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED ? [] : selectedRows.value.map(row => row.billId),
|
||||
excludedSourceBillIds: selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED ? Array.from(excludedRowMap.keys()) : [],
|
||||
requestId
|
||||
}
|
||||
}
|
||||
|
||||
function buildPreviewQuery(pageNum = previewPageNum.value, pageSize = previewPageSize) {
|
||||
return { ...(previewQuery.value || buildGenerateQuery()), pageNum, pageSize }
|
||||
}
|
||||
|
||||
// 查询按钮是预览入口,后端返回当前页、总数和全量金额合计。
|
||||
function queryGeneratePreview() {
|
||||
generateFormRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
const query = buildGenerateQuery()
|
||||
resetPreview()
|
||||
previewLoading.value = true
|
||||
previewArBill(buildGenerateQuery()).then(res => {
|
||||
previewRows.value = res.rows || []
|
||||
previewSearched.value = true
|
||||
}).finally(() => {
|
||||
previewLoading.value = false
|
||||
})
|
||||
previewQuery.value = query
|
||||
fetchPreview()
|
||||
})
|
||||
}
|
||||
|
||||
function fetchPreview() {
|
||||
previewLoading.value = true
|
||||
previewArBill(buildPreviewQuery()).then(res => {
|
||||
syncingPageSelection = true
|
||||
previewRows.value = res.rows || []
|
||||
previewTotal.value = Number(res.total) || 0
|
||||
previewTotalAmount.value = Number(res.totalAmount) || 0
|
||||
previewSearched.value = true
|
||||
nextTick(syncPageSelection)
|
||||
}).finally(() => {
|
||||
previewLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handlePreviewPageChange(page) {
|
||||
previewPageNum.value = page
|
||||
fetchPreview()
|
||||
}
|
||||
|
||||
// 当前页变化只更新当前页 ID,selectedRowMap 因此可以跨页保留手动选择。
|
||||
function handleSelectionChange(rows) {
|
||||
selectedRows.value = rows
|
||||
if (syncingPageSelection || selectionMode.value === AR_BILL_SELECTION_MODE.ALL_MATCHED) return
|
||||
const currentPageIds = new Set(previewRows.value.map(row => row.billId))
|
||||
currentPageIds.forEach(billId => selectedRowMap.delete(billId))
|
||||
rows.forEach(row => selectedRowMap.set(row.billId, row))
|
||||
selectedRows.value = Array.from(selectedRowMap.values())
|
||||
if (!generateLoading.value) generateRequestId.value = ''
|
||||
}
|
||||
|
||||
// 全选后主表复选框全部禁用,用户通过排除弹窗维护“不生成”的订单。
|
||||
function handleSelectAllChange(checked) {
|
||||
if (!checked) {
|
||||
switchToManualMode()
|
||||
return
|
||||
}
|
||||
selectionMode.value = AR_BILL_SELECTION_MODE.ALL_MATCHED
|
||||
excludedRows.value = []
|
||||
excludedRowMap.clear()
|
||||
selectedRowMap.clear()
|
||||
selectedRows.value = []
|
||||
if (!generateLoading.value) generateRequestId.value = ''
|
||||
nextTick(syncPageSelection)
|
||||
}
|
||||
|
||||
function handleManualModeChange(checked) {
|
||||
if (checked) switchToManualMode()
|
||||
}
|
||||
|
||||
// 从全选切回手动选择时清除排除集合,恢复主表跨页勾选流程。
|
||||
function switchToManualMode() {
|
||||
selectionMode.value = AR_BILL_SELECTION_MODE.EXPLICIT
|
||||
excludedRows.value = []
|
||||
excludedRowMap.clear()
|
||||
selectedRowMap.clear()
|
||||
selectedRows.value = []
|
||||
if (!generateLoading.value) generateRequestId.value = ''
|
||||
nextTick(syncPageSelection)
|
||||
}
|
||||
|
||||
function isMainRowSelectable() {
|
||||
return selectionMode.value !== AR_BILL_SELECTION_MODE.ALL_MATCHED
|
||||
}
|
||||
|
||||
function syncExcludedRows() {
|
||||
excludedRows.value = Array.from(excludedRowMap.values())
|
||||
}
|
||||
|
||||
function syncExcludeDraftRows() {
|
||||
excludeDraftRows.value = Array.from(excludeDraftMap.values())
|
||||
}
|
||||
|
||||
// 排除弹窗继承客户、币种、截止日和主关键字,只额外允许订单号/运单号 OR 查询。
|
||||
function openExcludeDialog() {
|
||||
if (!allSelected.value) return
|
||||
excludeDialogConfirmed = false
|
||||
excludeDraftMap = new Map(excludedRowMap)
|
||||
syncExcludeDraftRows()
|
||||
excludeKeyword.value = ''
|
||||
excludePageNum.value = 1
|
||||
excludeRowsPage.value = []
|
||||
excludeTotal.value = 0
|
||||
excludeDialogOpen.value = true
|
||||
fetchExcludeRows()
|
||||
}
|
||||
|
||||
function buildExcludeQuery() {
|
||||
return {
|
||||
...(previewQuery.value || {}),
|
||||
excludeOrderOrTrackingNo: excludeKeyword.value?.trim() || undefined,
|
||||
pageNum: excludePageNum.value,
|
||||
pageSize: excludePageSize
|
||||
}
|
||||
}
|
||||
|
||||
function queryExcludeRows() {
|
||||
excludePageNum.value = 1
|
||||
fetchExcludeRows()
|
||||
}
|
||||
|
||||
function fetchExcludeRows() {
|
||||
if (!previewQuery.value) return
|
||||
excludeLoading.value = true
|
||||
previewArBill(buildExcludeQuery()).then(res => {
|
||||
syncingExcludeSelection = true
|
||||
excludeRowsPage.value = res.rows || []
|
||||
excludeTotal.value = Number(res.total) || 0
|
||||
nextTick(syncExcludePageSelection)
|
||||
}).finally(() => {
|
||||
excludeLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleExcludePageChange(page) {
|
||||
excludePageNum.value = page
|
||||
fetchExcludeRows()
|
||||
}
|
||||
|
||||
// 排除弹窗使用独立 Map 保存跨页选择,关闭或翻页不会丢失已勾选订单。
|
||||
function handleExcludeSelectionChange(rows) {
|
||||
if (syncingExcludeSelection) return
|
||||
const currentPageIds = new Set(excludeRowsPage.value.map(row => row.billId))
|
||||
currentPageIds.forEach(billId => excludeDraftMap.delete(billId))
|
||||
rows.forEach(row => excludeDraftMap.set(row.billId, row))
|
||||
syncExcludeDraftRows()
|
||||
}
|
||||
|
||||
function syncExcludePageSelection() {
|
||||
if (!excludeTableRef.value) {
|
||||
syncingExcludeSelection = false
|
||||
return
|
||||
}
|
||||
syncingExcludeSelection = true
|
||||
excludeTableRef.value.clearSelection()
|
||||
excludeRowsPage.value.forEach(row => {
|
||||
if (excludeDraftMap.has(row.billId)) excludeTableRef.value.toggleRowSelection(row, true)
|
||||
})
|
||||
syncingExcludeSelection = false
|
||||
}
|
||||
|
||||
function confirmExcludeSelection() {
|
||||
excludedRowMap.clear()
|
||||
excludeDraftMap.forEach((row, billId) => excludedRowMap.set(billId, row))
|
||||
syncExcludedRows()
|
||||
if (!generateLoading.value) generateRequestId.value = ''
|
||||
excludeDialogConfirmed = true
|
||||
excludeDialogOpen.value = false
|
||||
}
|
||||
|
||||
function removeExcludedRow(billId) {
|
||||
excludedRowMap.delete(billId)
|
||||
excludeDraftMap.delete(billId)
|
||||
syncExcludeDraftRows()
|
||||
syncExcludedRows()
|
||||
if (!generateLoading.value) generateRequestId.value = ''
|
||||
}
|
||||
|
||||
function cancelExcludeSelection() {
|
||||
excludeDialogConfirmed = false
|
||||
excludeDialogOpen.value = false
|
||||
}
|
||||
|
||||
function handleExcludeDialogClose() {
|
||||
if (!excludeDialogConfirmed) {
|
||||
excludeDraftMap = new Map(excludedRowMap)
|
||||
syncExcludeDraftRows()
|
||||
}
|
||||
excludeDialogConfirmed = false
|
||||
}
|
||||
|
||||
// 翻页后把 Map 中的选择同步回 Element Plus 当前页复选框。
|
||||
function syncPageSelection() {
|
||||
if (!previewTableRef.value) {
|
||||
syncingPageSelection = false
|
||||
return
|
||||
}
|
||||
syncingPageSelection = true
|
||||
previewTableRef.value.clearSelection()
|
||||
previewRows.value.forEach(row => {
|
||||
if (selectedRowMap.has(row.billId)) previewTableRef.value.toggleRowSelection(row, true)
|
||||
})
|
||||
syncingPageSelection = false
|
||||
}
|
||||
|
||||
function submitGenerate() {
|
||||
if (!previewSearched.value || !selectedRows.value.length) {
|
||||
if (!previewSearched.value || !displaySelectedCount.value) {
|
||||
proxy.$modal.msgError('请至少选择一条计费订单')
|
||||
return
|
||||
}
|
||||
@@ -186,13 +490,14 @@ function submitGenerate() {
|
||||
nextTick(() => billNameFormRef.value?.clearValidate())
|
||||
}
|
||||
|
||||
// 最终只提交异步任务,不在浏览器等待几十万条订单明细生成完成。
|
||||
function confirmGenerate() {
|
||||
billNameFormRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
if (!generateRequestId.value) generateRequestId.value = createRequestId()
|
||||
generateLoading.value = true
|
||||
generateArBill(buildGenerateRequest(generateRequestId.value)).then(res => {
|
||||
proxy.$modal.msgSuccess('账单生成成功')
|
||||
proxy.$modal.msgSuccess('账单生成任务已提交,后台正在生成')
|
||||
billNameOpen.value = false
|
||||
dialogOpen.value = false
|
||||
emit('success', res.data)
|
||||
@@ -219,6 +524,16 @@ function createRequestId() { return globalThis.crypto?.randomUUID?.() || `ar-${D
|
||||
.preview-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 18px 0 10px; padding: 10px 14px; border-radius: 6px; background: var(--el-fill-color-light); color: var(--el-text-color-regular); }
|
||||
.preview-summary { flex: 1; font-size: 14px; }
|
||||
.preview-summary b { color: var(--el-color-primary); }
|
||||
.preview-selection-toolbar { display: flex; align-items: center; gap: 6px; min-height: 32px; padding-left: 8px; }
|
||||
.preview-selection-toolbar :deep(.el-checkbox) { margin-right: 6px; }
|
||||
.preview-selection-toolbar :deep(.el-checkbox__label) { display: inline-flex; align-items: center; padding-left: 4px; font-size: 16px; }
|
||||
.exclude-order-badge { margin-left: 4px; }
|
||||
.excluded-order-preview { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; max-height: 64px; margin: 0 0 8px; padding: 4px 8px; overflow-y: auto; border-radius: 4px; background: var(--el-fill-color-light); }
|
||||
.excluded-order-title { color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
.exclude-toolbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
|
||||
.exclude-search-input { width: 360px; }
|
||||
.exclude-pagination { justify-content: flex-end; margin: 12px 0 4px; }
|
||||
.preview-pagination { justify-content: flex-end; margin: 12px 0 4px; }
|
||||
.bill-name-summary { margin: -4px 0 8px 90px; color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
.generate-footer-summary { margin-right: auto; color: var(--el-text-color-secondary); font-size: 13px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user