📱 优化移动端文件列表与触控体验
This commit is contained in:
@@ -45,9 +45,9 @@ const isDarkMode = useInjectedDarkMode()
|
|||||||
|
|
||||||
const sizeClasses = computed(() => {
|
const sizeClasses = computed(() => {
|
||||||
const sizes = {
|
const sizes = {
|
||||||
sm: 'px-3 py-1.5 text-sm',
|
sm: 'min-h-11 px-3 py-2 text-sm sm:min-h-0 sm:py-1.5',
|
||||||
md: 'px-4 py-2 text-sm',
|
md: 'min-h-11 px-4 py-2 text-sm',
|
||||||
lg: 'px-6 py-3 text-base'
|
lg: 'min-h-12 px-6 py-3 text-base'
|
||||||
}
|
}
|
||||||
return sizes[props.size]
|
return sizes[props.size]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,17 +36,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section
|
<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]"
|
: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>
|
<div>
|
||||||
<h3 class="text-base font-semibold" :class="[primaryTextClass]">条件筛选</h3>
|
<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 ? '已应用筛选条件' : '默认收起,需要时展开' }}
|
{{ hasActiveFilters ? '已应用筛选条件' : '默认收起,需要时展开' }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</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
|
<BaseButton
|
||||||
v-if="hasActiveFilters"
|
v-if="hasActiveFilters"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -255,6 +255,106 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</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">
|
<DataTable :title="t('fileManage.allFiles')" :headers="fileTableHeaders">
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<BaseButton variant="secondary" :loading="isLoading" @click="refreshFileList">
|
<BaseButton variant="secondary" :loading="isLoading" @click="refreshFileList">
|
||||||
@@ -582,6 +682,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
</div>
|
||||||
|
|
||||||
<section
|
<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"
|
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"
|
||||||
|
|||||||
Reference in New Issue
Block a user