mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-12 02:21:06 +08:00
refactor: adjust TransferHistoryView layout offset and apply code style improvements
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { computed, ref, onMounted, onUnmounted } from 'vue'
|
||||
import { computed, ref, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import { usePWA } from '@/composables/usePWA'
|
||||
|
||||
/**
|
||||
@@ -35,19 +35,19 @@ export function useAvailableHeight(
|
||||
layoutPaddingBottom.value = parseFloat(style.paddingBottom) || 24
|
||||
}
|
||||
|
||||
// 测量 Footer Dock 的实际高度
|
||||
// .footer-nav-container 是 position:fixed, padding-block-end 含 env(safe-area-inset-bottom)
|
||||
// offsetHeight 是元素自身的渲染高度(含 padding),即 Dock 遮挡的区域大小
|
||||
if (appMode.value) {
|
||||
const footerEl = document.querySelector('.footer-nav-container') as HTMLElement | null
|
||||
footerDockMeasuredHeight.value = footerEl ? footerEl.offsetHeight : 70
|
||||
} else {
|
||||
footerDockMeasuredHeight.value = 0
|
||||
}
|
||||
// 直接查询 Footer Dock DOM,无论 appMode 状态
|
||||
// Dock 通过 Teleport 挂载到 body,存在即测量,不存在即为 0
|
||||
const footerEl = document.querySelector('.footer-nav-container') as HTMLElement | null
|
||||
footerDockMeasuredHeight.value = footerEl ? footerEl.offsetHeight : 0
|
||||
}
|
||||
|
||||
// appMode 异步变化时(PWA 检测完成、屏幕尺寸变化等),Dock 会出现/消失
|
||||
// 需要等 DOM 更新后重新测量
|
||||
watch(appMode, () => {
|
||||
nextTick(updateMeasurements)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// 初始测量(nextTick 确保 DOM 已渲染)
|
||||
nextTick(updateMeasurements)
|
||||
|
||||
window.addEventListener('resize', updateMeasurements)
|
||||
@@ -72,7 +72,7 @@ export function useAvailableHeight(
|
||||
// 布局底部 padding
|
||||
const bottomPadding = layoutPaddingBottom.value
|
||||
|
||||
// 底部 Dock 栏遮挡高度(appMode 下通过 DOM 测量,含 safe-area-inset-bottom)
|
||||
// 底部 Dock 栏遮挡高度(通过 DOM 测量,含 safe-area-inset-bottom)
|
||||
const footerDockHeight = footerDockMeasuredHeight.value
|
||||
|
||||
const available = vh - topPadding - bottomPadding - footerDockHeight - componentOffset
|
||||
|
||||
@@ -23,8 +23,8 @@ const display = useDisplay()
|
||||
const { appMode } = usePWA()
|
||||
|
||||
// 计算列表可用高度
|
||||
// componentOffset = VCardItem搜索栏(80) + VDivider(1) + 分页栏(52) + VCard边距(4) = 137
|
||||
const { availableHeight } = useAvailableHeight(137, 300)
|
||||
// componentOffset = VCardItem搜索栏(68) + VDivider(1) + 分页栏(40) + VCard边距(2) = 111
|
||||
const { availableHeight } = useAvailableHeight(125, 300)
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -51,21 +51,21 @@ const redoTargetStorage = ref<string>()
|
||||
// 已选中的数据
|
||||
const selected = ref<TransferHistory[]>([])
|
||||
|
||||
const getNum = (s?: string) => (s ? parseInt(s.replace(/[^0-9]/g, ''), 10) || 0 : 0);
|
||||
const getNum = (s?: string) => (s ? parseInt(s.replace(/[^0-9]/g, ''), 10) || 0 : 0)
|
||||
|
||||
function sortByTitle(a: TransferHistory, b: TransferHistory) {
|
||||
if (a.type !== b.type) {
|
||||
return (a.type ?? '').localeCompare(b.type ?? '');
|
||||
return (a.type ?? '').localeCompare(b.type ?? '')
|
||||
}
|
||||
if (a.title !== b.title) {
|
||||
return (a.title ?? '').toLocaleLowerCase().localeCompare((b.title ?? '').toLocaleLowerCase());
|
||||
return (a.title ?? '').toLocaleLowerCase().localeCompare((b.title ?? '').toLocaleLowerCase())
|
||||
}
|
||||
if (a.type === '电视剧') {
|
||||
if (a.seasons !== b.seasons) {
|
||||
return getNum(a.seasons) - getNum(b.seasons);
|
||||
return getNum(a.seasons) - getNum(b.seasons)
|
||||
}
|
||||
if (a.episodes !== b.episodes) {
|
||||
return getNum(a.episodes) - getNum(b.episodes);
|
||||
return getNum(a.episodes) - getNum(b.episodes)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
@@ -231,10 +231,13 @@ async function loadStorages() {
|
||||
|
||||
// 存储字典
|
||||
const storageDict = computed(() => {
|
||||
return storages.value.reduce((dict, item) => {
|
||||
dict[item.type] = item.name
|
||||
return dict
|
||||
}, {} as Record<string, string>)
|
||||
return storages.value.reduce(
|
||||
(dict, item) => {
|
||||
dict[item.type] = item.name
|
||||
return dict
|
||||
},
|
||||
{} as Record<string, string>,
|
||||
)
|
||||
})
|
||||
|
||||
// 转移方式字典
|
||||
@@ -247,8 +250,6 @@ const TransferDict: { [key: string]: string } = {
|
||||
rclone_move: t('transferHistory.transferMode.rclone_move'),
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 分页提示
|
||||
const pageTip = computed(() => {
|
||||
const begin = itemsPerPage.value * (currentPage.value - 1) + 1
|
||||
@@ -488,23 +489,26 @@ function ensureNumber(value: any, defaultValue: number = 0) {
|
||||
|
||||
// 按标题分组后的选中数量统计,键为标题,值为对应分组的选中数
|
||||
const selectedCountsGroupedByTitle = computed(() => {
|
||||
return selected.value.reduce((acc, item) => {
|
||||
const title = item.title || '';
|
||||
acc[title] = (acc[title] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<string, number>);
|
||||
});
|
||||
return selected.value.reduce(
|
||||
(acc, item) => {
|
||||
const title = item.title || ''
|
||||
acc[title] = (acc[title] || 0) + 1
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, number>,
|
||||
)
|
||||
})
|
||||
|
||||
// 控制分组内所有子项的选中状态
|
||||
const toggleGroupSelection = (checked: boolean | null, items: readonly any[]) => {
|
||||
const values = items.map(item => item.value);
|
||||
const values = items.map(item => item.value)
|
||||
if (checked) {
|
||||
selected.value = [...new Set([...selected.value, ...values])];
|
||||
selected.value = [...new Set([...selected.value, ...values])]
|
||||
} else {
|
||||
const itemsSet = new Set(values);
|
||||
selected.value = selected.value.filter(item => !itemsSet.has(item));
|
||||
const itemsSet = new Set(values)
|
||||
selected.value = selected.value.filter(item => !itemsSet.has(item))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 初始加载数据
|
||||
onMounted(() => {
|
||||
@@ -579,7 +583,7 @@ onMounted(() => {
|
||||
<VCheckbox
|
||||
:model-value="selectedCountsGroupedByTitle[item.value] == item.items.length"
|
||||
:indeterminate="selectedCountsGroupedByTitle[item.value] < item.items.length"
|
||||
@update:modelValue="(checked) => toggleGroupSelection(checked, item.items)"
|
||||
@update:modelValue="checked => toggleGroupSelection(checked, item.items)"
|
||||
/>
|
||||
{{ item.value }}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user