feat: 收支记录批量操作按钮移至表格右上角并优化一键设置作用范围
将批量相关按钮从页头工具栏集中到列表右上角,并让一键设置优先作用于勾选记录、未勾选时作用于当前页全部记录,同时补充区分来源的作用范围提示文案。 变更内容: - 将「批量操作/退出批量、一键设置、批量删除、建立关系」移至列表右上角(分页统计信息上方) - 一键设置以打开弹窗时的目标快照为准:有勾选时作用于勾选记录,未勾选时作用于当前页全部记录 - 作用范围提示区分「已勾选」与「未勾选(当前表格展示)」两种文案 - 新增中英日三语文案 batchScopeHintSelected / batchScopeHintPage,移除旧 batchScopeHint 说明: - 顺带移除 LoginRequest 未使用的 Size 导入与 AiSuggestionServiceImpl 未使用的 BigDecimal 导入
This commit is contained in:
@@ -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: 12px;">
|
||||
{{ 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')">
|
||||
|
||||
Reference in New Issue
Block a user