diff --git a/bms-front/src/views/ar/bill/index.vue b/bms-front/src/views/ar/bill/index.vue
index dde2a09c..7cbf4a7b 100644
--- a/bms-front/src/views/ar/bill/index.vue
+++ b/bms-front/src/views/ar/bill/index.vue
@@ -16,6 +16,7 @@
确认
作废
导出
+ 去核销
@@ -33,6 +34,7 @@ import { AR_BILL_STATUS, AR_BILL_STATUS_OPTIONS, AR_BILL_STATUS_TYPES } from '@/
const { proxy } = getCurrentInstance()
const route = useRoute()
+const router = useRouter()
const tableRef = ref()
// 从客户余额页“查看账单”跳入时,按当前客户预筛选(重置后仍保留该条件)
const defaultSearchParams = computed(() => ({
@@ -48,7 +50,7 @@ const columns = [
{ label: '账单截止日', prop: 'billPeriodEnd', minWidth: 120, formatter: row => `截至 ${date(row.billPeriodEnd)}` }, { label: '订单数', prop: 'orderCount', width: 80 },
{ label: '应收总额', prop: 'totalAmount', width: 120, align: 'right', slot: 'totalAmount' }, { label: '已核销', prop: 'writtenOffAmount', width: 110, align: 'right', slot: 'writtenOffAmount' },
{ label: '未核销', prop: 'unwrittenAmount', width: 110, align: 'right', slot: 'unwrittenAmount' }, { label: '状态', prop: 'status', width: 110, slot: 'status' },
- { label: '账单日期', prop: 'billDate', width: 120, formatter: row => date(row.billDate) }, { label: '操作', prop: 'action', width: 260, fixed: 'right', slot: 'action', showInToolbar: false }
+ { label: '账单日期', prop: 'billDate', width: 120, formatter: row => date(row.billDate) }, { label: '操作', prop: 'action', width: 330, fixed: 'right', slot: 'action', showInToolbar: false }
]
const searchColumns = [
{ label: '账单号', prop: 'billNo', component: 'input', placeholder: '账单号', width: '180px' }, { label: '账单名称', prop: 'billName', component: 'input', placeholder: '账单名称', width: '180px' }, { label: '客户名称', prop: 'customerId', component: 'input', placeholder: '请选择客户', width: '220px' }, { label: '客户编码', prop: 'customerCode', component: 'input', placeholder: '客户编码', width: '140px' },
@@ -62,6 +64,24 @@ function confirmBill(row) { proxy.$modal.confirm(`确认账单「${row.billNo}
function voidBill(row) { proxy.$prompt(`请输入账单「${row.billNo}」的作废原因`, '作废账单', { inputPattern: /\S+/, inputErrorMessage: '作废原因不能为空' }).then(({ value }) => voidArBill(row.arBillId, { remark: value })).then(() => { proxy.$modal.msgSuccess('账单已作废'); tableRef.value.refresh(); viewBill(row) }).catch(() => {}) }
function exportBill(row) { if (!row?.arBillId) return; exportArBill(row.arBillId).then(res => { proxy.$modal.msgSuccess('导出成功'); tableRef.value.refresh(); if (detailOpen.value) viewBill(row); if (res.data?.exportId) downloadExport(res.data) }) }
function downloadExport(row) { downloadArBillExport(row.exportId).then(blob => saveAs(blob, row.fileName || `账单_${row.exportId}.xlsx`)) }
+function canGoWriteoff(row) {
+ if (!row?.customerId) return false
+ const canWriteoffStatus = row.status === AR_BILL_STATUS.CONFIRMED
+ || row.status === AR_BILL_STATUS.PARTIAL_WRITTEN_OFF
+ return canWriteoffStatus && Number(row.unwrittenAmount) > 0
+}
+function goWriteoff(row) {
+ if (!canGoWriteoff(row)) return
+ router.push({
+ path: '/customersupplier/customer-money/index',
+ query: {
+ customerId: row.customerId,
+ customerName: row.customerName || '',
+ customerCode: row.customerCode || '',
+ tab: 'billWriteoff'
+ }
+ })
+}
function date(value) { return value ? String(value).slice(0, 10) : '-' }
function money(value) { const num = Number(value); return Number.isNaN(num) ? '-' : num.toFixed(2) }
function statusText(value) { return statusOptions.find(item => item.value === value)?.label || value || '-' }
diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue
index 78e645a2..c02d32ef 100644
--- a/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue
+++ b/bms-front/src/views/customersuppliermanagement/customerinfo/customermoney/index.vue
@@ -1847,7 +1847,7 @@ function initPage() {
// 重置页面状态,避免上一个客户的数据残留
customer.value = {}
accountList.value = []
- activeTab.value = 'receipt'
+ activeTab.value = route.query.tab === 'billWriteoff' ? 'billWriteoff' : 'receipt'
receiptDialog.visible = false
viewDialog.visible = false
viewDialog.data = null