📱 优化移动端文件列表与触控体验

This commit is contained in:
2026-07-10 10:28:59 +08:00
parent 12738b874a
commit 7b2cfb4296
2 changed files with 108 additions and 7 deletions
+3 -3
View File
@@ -45,9 +45,9 @@ const isDarkMode = useInjectedDarkMode()
const sizeClasses = computed(() => {
const sizes = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-sm',
lg: 'px-6 py-3 text-base'
sm: 'min-h-11 px-3 py-2 text-sm sm:min-h-0 sm:py-1.5',
md: 'min-h-11 px-4 py-2 text-sm',
lg: 'min-h-12 px-6 py-3 text-base'
}
return sizes[props.size]
})
+105 -4
View File
@@ -36,17 +36,17 @@
</div>
<section
class="theme-2026-card theme-2026-card-hover mb-6 rounded-[30px] border p-4 shadow-md transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg"
class="theme-2026-card theme-2026-card-hover mb-4 rounded-[24px] border p-3 shadow-md transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg sm:mb-6 sm:rounded-[30px] sm:p-4"
:class="[panelClass, cardHoverClass]"
>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div class="flex items-center justify-between gap-3 sm:flex-row">
<div>
<h3 class="text-base font-semibold" :class="[primaryTextClass]">条件筛选</h3>
<p class="mt-1 text-xs" :class="[mutedTextClass]">
<p class="mt-1 hidden text-xs min-[360px]:block" :class="[mutedTextClass]">
{{ hasActiveFilters ? '已应用筛选条件' : '默认收起,需要时展开' }}
</p>
</div>
<div class="flex flex-wrap items-center gap-2 sm:justify-end">
<div class="flex shrink-0 flex-wrap items-center gap-2 sm:justify-end">
<BaseButton
v-if="hasActiveFilters"
variant="outline"
@@ -255,6 +255,106 @@
</div>
</section>
<section
class="theme-2026-card mb-5 overflow-hidden rounded-[24px] shadow-md md:hidden"
>
<div class="flex items-center justify-between gap-3 border-b px-4 py-3" :class="[isDarkMode ? 'border-gray-700' : 'border-[#d9e4e6]']">
<div>
<h3 class="text-base font-semibold" :class="[primaryTextClass]">{{ t('fileManage.allFiles') }}</h3>
<p class="mt-0.5 text-xs" :class="[mutedTextClass]">{{ t('fileManage.subtitle', { count: summary.totalFiles }) }}</p>
</div>
<button
type="button"
class="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl border"
:class="detailActionClass"
:disabled="isLoading"
:aria-label="t('fileManage.refresh')"
@click="refreshFileList"
>
<RefreshCwIcon class="h-5 w-5" :class="isLoading ? 'animate-spin' : ''" />
</button>
</div>
<div v-if="isLoading" class="flex items-center justify-center px-4 py-10 text-sm" :class="[mutedTextClass]">
<RefreshCwIcon class="mr-2 h-4 w-4 animate-spin" />
{{ t('common.loading') }}
</div>
<div v-else-if="hasLoadError" class="px-4 py-10 text-center">
<p class="text-sm font-medium" :class="[primaryTextClass]">{{ t('fileManage.loadError') }}</p>
<BaseButton class="mt-3" variant="secondary" @click="refreshFileList">{{ t('fileManage.refresh') }}</BaseButton>
</div>
<div v-else-if="tableData.length === 0" class="px-4 py-10 text-center text-sm" :class="[mutedTextClass]">
{{ hasActiveFilters ? t('fileManage.noMatches') : t('common.noData') }}
</div>
<div v-else class="divide-y" :class="[isDarkMode ? 'divide-gray-700' : 'divide-[#d9e4e6]']">
<article
v-for="file in tableData"
:key="file.id"
class="px-4 py-4"
:class="selectedFileIds.has(file.id) ? (isDarkMode ? 'bg-[#294047]/50' : 'bg-[#e5eeee]') : ''"
>
<div class="flex items-start gap-3">
<label class="flex h-11 w-11 shrink-0 cursor-pointer items-start justify-center pt-1">
<input
type="checkbox"
class="h-5 w-5 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
:checked="selectedFileIds.has(file.id)"
:disabled="isBatchActionRunning"
:aria-label="t('fileManage.selectFile', { name: file.displayName })"
@change="toggleFileSelection(file.id)"
/>
</label>
<button type="button" class="min-w-0 flex-1 text-left" @click="openFileDetail(file)">
<p class="line-clamp-2 break-all text-sm font-semibold leading-5" :class="[primaryTextClass]">
{{ file.displayName }}
</p>
<div class="mt-2 flex flex-wrap items-center gap-1.5">
<span
class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium"
:class="getStatusBadgeClass(file)"
>
{{ file.isExpiredFile ? t('fileManage.expired') : t('fileManage.active') }}
</span>
<span class="rounded-full px-2 py-0.5 text-xs font-medium" :class="getTypeBadgeClass(file)">
{{ getTypeLabel(file) }}
</span>
<span class="rounded-full px-2 py-0.5 text-xs font-medium" :class="getInsightBadgeClass(file.statusInsightSeverity)">
{{ file.displayHealthState }}
</span>
</div>
<div class="mt-2 grid grid-cols-2 gap-x-3 gap-y-1 text-xs" :class="[mutedTextClass]">
<span>{{ file.code }} · {{ file.displaySize }}</span>
<span class="text-right">{{ file.displayUsage }}</span>
<span class="col-span-2">{{ file.displayExpiredAt }}</span>
</div>
</button>
</div>
<div class="mt-3 grid grid-cols-3 gap-2 pl-14">
<button type="button" class="flex min-h-11 items-center justify-center rounded-lg border text-sm font-medium" :class="detailActionClass" @click="openFileDetail(file)">
<FileTextIcon class="mr-1.5 h-4 w-4" />{{ t('fileManage.detail') }}
</button>
<button type="button" class="flex min-h-11 items-center justify-center rounded-lg border text-sm font-medium" :class="detailActionClass" :disabled="Boolean(downloadingFileId)" @click="downloadFile(file)">
<DownloadIcon class="mr-1.5 h-4 w-4" />{{ file.isTextFile ? t('fileManage.exportText') : t('fileManage.downloadFile') }}
</button>
<button type="button" class="flex min-h-11 items-center justify-center rounded-lg border text-sm font-medium" :class="detailActionClass" @click="openEditModal(file)">
<PencilIcon class="mr-1.5 h-4 w-4" />{{ t('common.edit') }}
</button>
</div>
</article>
</div>
<div v-if="params.total > 0" class="border-t" :class="[isDarkMode ? 'border-gray-700' : 'border-[#d9e4e6]']">
<DataPagination
:current-page="params.page"
:page-size="params.size"
:total="params.total"
@page-change="handlePageChange"
@page-size-change="handlePageSizeChange"
/>
</div>
</section>
<div class="hidden md:block">
<DataTable :title="t('fileManage.allFiles')" :headers="fileTableHeaders">
<template #actions>
<BaseButton variant="secondary" :loading="isLoading" @click="refreshFileList">
@@ -582,6 +682,7 @@
/>
</template>
</DataTable>
</div>
<section
class="theme-2026-card theme-2026-card-hover mt-6 rounded-[30px] border p-4 shadow-md transition-all duration-200 hover:-translate-y-0.5 hover:shadow-lg"