feat: 新增隐藏备注记录显示开关并简化设置与日志菜单文案
- 设置页「外观设置」新增「显示已隐藏备注的记录」开关,默认关闭,切换即时保存 - 新增 GET/PUT /api/setting/show-hidden-data 接口,用户级偏好持久化于 t_user_preference - 收支记录列表与 Excel 导出按该偏好过滤,关闭时排除已隐藏备注的记录 - 移除「备注关键字搜索时总是跳过隐藏记录」逻辑,改由该偏好统一控制,统计备注搜索同步放开 - 列表内隐藏备注后,偏好关闭时该行即时移除,当前页清空自动回退上一页 - 外观设置面板拆分为两个浅灰底分组,两个配置项区分更清晰 - 顶部用户菜单与设置/日志页标题由「系统设置/系统日志」简化为「设置/日志」,同步中英日三语
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
// 外观设置面板:配置「不计入统计」记录在收支记录列表中的展示样式
|
||||
// 外观设置面板:配置「不计入统计」记录在收支记录列表中的展示样式,以及是否显示已隐藏备注的记录
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import {
|
||||
useMessage, NCard, NSpace, NButton, NIcon, NText, NRadioGroup, NRadio,
|
||||
useMessage, NCard, NSpace, NButton, NIcon, NText, NRadioGroup, NRadio, NSwitch,
|
||||
} from 'naive-ui'
|
||||
import { ColorPaletteOutline, SaveOutline } from '@vicons/ionicons5'
|
||||
import { getExcludedDisplayStyle, updateExcludedDisplayStyle } from '../api/setting'
|
||||
import { getExcludedDisplayStyle, updateExcludedDisplayStyle, getShowHiddenData, updateShowHiddenData } from '../api/setting'
|
||||
|
||||
const message = useMessage()
|
||||
const { t } = useI18n()
|
||||
@@ -16,6 +16,11 @@ const style = ref<string>('strikethrough')
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
|
||||
/** 是否显示已隐藏备注的记录,默认不显示 */
|
||||
const showHiddenData = ref(false)
|
||||
const loadingHidden = ref(false)
|
||||
const savingHidden = ref(false)
|
||||
|
||||
/** 展示样式选项(随语言切换响应式更新) */
|
||||
const styleOptions = computed(() => [
|
||||
{ label: t('display.strikethrough'), value: 'strikethrough' },
|
||||
@@ -49,7 +54,41 @@ async function handleSave() {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadStyle)
|
||||
/** 加载「显示已隐藏备注记录」偏好,失败时保持默认不显示 */
|
||||
async function loadHiddenData() {
|
||||
loadingHidden.value = true
|
||||
try {
|
||||
const res: any = await getShowHiddenData()
|
||||
showHiddenData.value = !!res.data
|
||||
} catch (e: any) {
|
||||
// 静默处理,保持默认不显示
|
||||
} finally {
|
||||
loadingHidden.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 切换「显示已隐藏备注记录」偏好并即时保存,失败时回滚 */
|
||||
async function handleHiddenChange(value: string | number | boolean) {
|
||||
const next = value === true
|
||||
const previous = showHiddenData.value
|
||||
showHiddenData.value = next
|
||||
savingHidden.value = true
|
||||
try {
|
||||
const res: any = await updateShowHiddenData(next)
|
||||
showHiddenData.value = !!res.data
|
||||
message.success(t('display.hiddenDataSaved'))
|
||||
} catch (e: any) {
|
||||
showHiddenData.value = previous
|
||||
message.error(e.message || t('display.hiddenDataFailed'))
|
||||
} finally {
|
||||
savingHidden.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadStyle()
|
||||
loadHiddenData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -61,16 +100,14 @@ onMounted(loadStyle)
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
<NText depth="3" style="font-size: 12px;">{{ t('display.hint') }}</NText>
|
||||
|
||||
<div class="style-row">
|
||||
<div class="filter-label">{{ t('display.label') }}</div>
|
||||
<div class="config-group">
|
||||
<div class="group-title">{{ t('display.label') }}</div>
|
||||
<NText depth="3" style="font-size: 12px; display: block; margin-bottom: 8px;">{{ t('display.hint') }}</NText>
|
||||
<NRadioGroup v-model:value="style" :disabled="loading">
|
||||
<NRadio v-for="option in styleOptions" :key="option.value" :value="option.value">
|
||||
{{ option.label }}
|
||||
</NRadio>
|
||||
</NRadioGroup>
|
||||
</div>
|
||||
|
||||
<!-- 预览:按当前选择实时展示「不计入统计」记录的样式 -->
|
||||
<div class="preview">
|
||||
@@ -95,6 +132,20 @@ onMounted(loadStyle)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="config-group">
|
||||
<div class="group-title">{{ t('display.hiddenDataLabel') }}</div>
|
||||
<NSpace align="center" :size="12">
|
||||
<NSwitch
|
||||
:value="showHiddenData"
|
||||
:disabled="loadingHidden"
|
||||
:loading="savingHidden"
|
||||
@update:value="handleHiddenChange"
|
||||
/>
|
||||
<NText depth="3" style="font-size: 12px;">{{ t('display.hiddenDataHint') }}</NText>
|
||||
</NSpace>
|
||||
</div>
|
||||
|
||||
<NSpace justify="end" style="margin-top: 16px; width: 100%;">
|
||||
<NButton type="primary" :loading="saving" @click="handleSave">
|
||||
@@ -108,9 +159,20 @@ onMounted(loadStyle)
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.style-row {
|
||||
.config-group {
|
||||
padding: 12px 14px;
|
||||
background: #fafafc;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.config-group + .config-group {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.group-title {
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.filter-label {
|
||||
margin-bottom: 8px;
|
||||
color: #999;
|
||||
@@ -123,6 +185,7 @@ onMounted(loadStyle)
|
||||
border: 1px solid #efeff5;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
}
|
||||
.preview-head,
|
||||
.preview-row {
|
||||
|
||||
Reference in New Issue
Block a user