@@ -218,9 +218,15 @@ const batchIncludeInStats = ref<'null' | 'true' | 'false'>('null') // 批量设
const batchAddTagIds = ref < number [ ] > ( [ ] ) // 批量添加的标签
const batchRemoveTagIds = ref < number [ ] > ( [ ] ) // 批量移除的标签
const batching = ref ( false ) // 批量设置提交状态
// 当前表格是否包含收入/支出记录,用于按需展示批量分类项
const hasIncomeRecords = computed ( ( ) => transactions . value . some ( ( tx ) => tx . type === 'INCOME' ) )
const hasExpenseRecords = computed ( ( ) => transactions . value . some ( ( tx ) => tx . type === 'EXPENSE' ) )
// 一键设置目标记录快照:有勾选时取勾选记录,否则取当前表格展示的记录
const batchTargets = ref < TransactionItem [ ] > ( [ ] )
// 目标记录是否来自勾选,用于作用范围提示文案
const batchFromSelection = ref ( false )
// 目标记录ID列表
const batchTargetIds = computed ( ( ) => batchTargets . value . map ( ( tx ) => tx . id ) )
// 一键设置目标中是否包含收入/支出记录,用于按需展示批量分类项
const hasIncomeRecords = computed ( ( ) => batchTargets . value . some ( ( tx ) => tx . type === 'INCOME' ) )
const hasExpenseRecords = computed ( ( ) => batchTargets . value . some ( ( tx ) => tx . type === 'EXPENSE' ) )
// 批量设置计入统计选项
const batchStatsOptions = computed ( ( ) => [
@@ -943,13 +949,13 @@ async function loadAiConfig() {
/** 请求 AI 建议:对当前表格展示的记录生成分类与标签建议 */
async function handleAiSuggest ( ) {
if ( transactions . value . length === 0 ) {
if ( batchTargetIds . value . length === 0 ) {
message . warning ( t ( 'transaction.noRecordsToSet' ) )
return
}
aiLoading . value = true
try {
const ids = transactions . value . map ( ( tx ) => tx . id )
const ids = batchTargetIds . value
const res : any = await suggestByAi ( ids , aiScope . value )
aiSuggestions . value = res . data || [ ]
if ( aiSuggestions . value . length === 0 ) {
@@ -1896,12 +1902,19 @@ function renderTagsCell(row: AiSuggestion) {
return items . length > 0 ? h ( NSpace , { size : 4 , wrap : true } , { default : ( ) => items } ) : '-'
}
/** 打开批量设置分类弹窗 */
/** 打开批量设置分类弹窗:有勾选时作用于勾选记录,否则作用于当前表格展示的记录 */
function handleBatchOpen ( ) {
if ( transactions . value . length === 0 ) {
// 勾选记录均属于当前页,按ID过滤当前页即可得到目标记录
const hasSelection = checkedTransactionIds . value . length > 0
const targets = hasSelection
? transactions . value . filter ( ( tx ) => checkedTransactionIds . value . includes ( tx . id ) )
: [ ... transactions . value ]
if ( targets . length === 0 ) {
message . warning ( t ( 'transaction.noRecordsToSet' ) )
return
}
batchTargets . value = targets
batchFromSelection . value = hasSelection
batchExpenseCategoryId . value = null
batchIncomeCategoryId . value = null
batchIncludeInStats . value = 'null'
@@ -1920,7 +1933,7 @@ async function handleBatchSubmit() {
}
batching . value = true
try {
const ids = transactions . value . map ( ( tx ) => tx . id )
const ids = batchTargetIds . value
if ( hasCategoryOrStats ) {
await batchUpdateCategory ( {
ids ,
@@ -2024,15 +2037,6 @@ onBeforeUnmount(() => {
< span style = "color: #999; font-size: 13px;" > { { t ( 'transaction.sortLabel' ) } } < / span >
< NSelect v -model :value = "sortValue" :options = "sortOptions" style = "width: 170px;" / >
< NDivider vertical style = "margin: 0 4px;" / >
< NButton v-if = "!selectionMode" @click="enterSelectionMode" > {{ t ( ' transaction.batchMode ' ) }} < / NButton >
< NButton v-else @click ="exitSelectionMode" > {{ t ( ' transaction.exitBatchMode ' ) }} < / NButton >
< NButton @click ="handleBatchOpen" > {{ t ( ' transaction.batchSet ' ) }} < / NButton >
< NButton v-if = "checkedTransactionIds.length > 0" type="error" @click="handleBatchDelete" >
{{ t ( ' transaction.batchDelete ' ) }}
< / NButton >
< NButton v-if = "checkedTransactionIds.length >= 2" type="primary" ghost @click="handleCreateRelation" >
{{ t ( ' transaction.relation.createFromSelection ' ) }}
< / NButton >
< NButton @click ="showImportModal = true" > {{ t ( ' transaction.importBill ' ) }} < / NButton >
< NButton @click ="goChannelManage" > {{ t ( ' channel.manageEntry ' ) }} < / NButton >
< NButton :loading = "exporting" @click ="handleExport" > {{ t ( ' transaction.exportExcel ' ) }} < / NButton >
@@ -2199,6 +2203,19 @@ onBeforeUnmount(() => {
< / div >
< / NCard >
< ! - - 表格右上角 : 批量操作按钮 - - >
< NSpace justify = "end" align = "center" :size = "12" style = "margin-bottom: 8px;" :wrap = "true" >
< NButton v-if = "!selectionMode" @click="enterSelectionMode" > {{ t ( ' transaction.batchMode ' ) }} < / NButton >
< NButton v-else @click ="exitSelectionMode" > {{ t ( ' transaction.exitBatchMode ' ) }} < / NButton >
< NButton @click ="handleBatchOpen" > {{ t ( ' transaction.batchSet ' ) }} < / NButton >
< NButton v-if = "checkedTransactionIds.length > 0" type="error" @click="handleBatchDelete" >
{{ t ( ' transaction.batchDelete ' ) }}
< / NButton >
< NButton v-if = "checkedTransactionIds.length >= 2" type="primary" ghost @click="handleCreateRelation" >
{{ t ( ' transaction.relation.createFromSelection ' ) }}
< / NButton >
< / NSpace >
< ! - - 表格信息栏 ( 右上角 ) - - >
< NSpace justify = "end" align = "center" :size = "12" style = "margin-bottom: 8px;" >
< span style = "color: #999; font-size: 12px;" >
@@ -2349,7 +2366,9 @@ onBeforeUnmount(() => {
<NForm>
<NFormItem :label=" t ( 'transaction.batchScope' ) ">
<span style=" color : # 999 ; font - size : 12 px ; ">
{{ t('transaction.batchScopeHint', { count: transactions.length }) }}
{{ batchFromSelection
? t('transaction.batchScopeHintSelected', { count: batchTargets.length })
: t('transaction.batchScopeHintPage', { count: batchTargets.length }) }}
</span>
</NFormItem>
<NFormItem v-if=" aiEnabled " :label=" t ( 'ai.suggestButton' ) ">