| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- <template>
- <div class="files-content card">
- <div class="content-header">
- <h2>📁 分享的文件</h2>
- <span class="file-count">{{ files.length }} 个文件</span>
- </div>
- <div class="files-list">
- <div
- v-for="file in files"
- :key="file.fileId"
- class="file-item"
- >
- <div class="file-info">
- <svg class="file-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
- <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
- <polyline points="13 2 13 9 20 9"></polyline>
- </svg>
- <div class="file-details">
- <p class="file-name">{{ file.fileName }}</p>
- <p class="file-size">{{ formatFileSize(file.fileSize) }}</p>
- </div>
- </div>
- <div class="file-actions">
- <!-- 预览按钮(仅图片和PDF) -->
- <button
- v-if="isPreviewable(file.mimeType)"
- class="btn-action btn-preview"
- @click="$emit('preview', file.fileId)"
- title="在新窗口预览"
- >
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
- <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
- <circle cx="12" cy="12" r="3"></circle>
- </svg>
- <span>预览</span>
- </button>
- <!-- 下载按钮 -->
- <button
- class="btn-action btn-download"
- @click="$emit('download', file.fileId, file.fileName)"
- title="下载文件"
- >
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
- <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
- <polyline points="7 10 12 15 17 10"></polyline>
- <line x1="12" y1="15" x2="12" y2="3"></line>
- </svg>
- <span>下载</span>
- </button>
- </div>
- </div>
- </div>
- <!-- 打包下载按钮 -->
- <button
- class="btn-download-all btn btn-primary btn-lg"
- @click="$emit('download-all')"
- :disabled="downloadingAll"
- >
- {{ downloadingAll ? '⏳ 正在打包...' : '📦 打包下载所有文件' }}
- </button>
- <div class="content-info">
- <p>创建时间:{{ formatTime(createdTime) }}</p>
- <p>过期时间:{{ formatTime(expirationTime) }}</p>
- <p>下载次数:{{ currentDownloadCount }}/{{ maxDownloadCount === -1 ? '无限制' : maxDownloadCount }}</p>
- </div>
- <!-- 删除资源按钮 -->
- <div class="content-actions">
- <button
- class="btn-delete"
- @click="$emit('delete')"
- title="删除此分享资源"
- >
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
- <polyline points="3 6 5 6 21 6"></polyline>
- <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
- </svg>
- <span>删除资源</span>
- </button>
- </div>
- </div>
- </template>
- <script setup>
- const props = defineProps({
- files: {
- type: Array,
- required: true
- },
- downloadingAll: {
- type: Boolean,
- default: false
- },
- createdTime: {
- type: String,
- default: ''
- },
- expirationTime: {
- type: String,
- default: ''
- },
- currentDownloadCount: {
- type: Number,
- default: 0
- },
- maxDownloadCount: {
- type: Number,
- default: -1
- }
- })
- defineEmits(['download', 'download-all', 'preview', 'delete'])
- // 判断文件是否可预览(图片或PDF)
- function isPreviewable(mimeType) {
- if (!mimeType) return false
- const previewableTypes = [
- // 图片类型
- 'image/jpeg',
- 'image/jpg',
- 'image/png',
- 'image/gif',
- 'image/webp',
- 'image/svg+xml',
- 'image/bmp',
- 'image/x-icon',
- // PDF类型
- 'application/pdf'
- ]
- return previewableTypes.includes(mimeType)
- }
- function formatFileSize(bytes) {
- if (bytes === 0) return '0 B'
- const k = 1024
- const sizes = ['B', 'KB', 'MB', 'GB']
- const i = Math.floor(Math.log(bytes) / Math.log(k))
- return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]
- }
- function formatTime(timeStr) {
- return new Date(timeStr).toLocaleString('zh-CN')
- }
- </script>
- <style lang="scss" scoped>
- @import '@/styles/variables.scss';
- .files-content {
- .content-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: $spacing-lg;
- h2 {
- color: $text-secondary;
- }
- .file-count {
- font-size: $font-size-sm;
- background: $bg-tertiary;
- padding: $spacing-xs $spacing-sm;
- border-radius: $radius-full;
- color: $text-muted;
- }
- }
- }
- .files-list {
- margin-bottom: $spacing-lg;
- }
- .file-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: $spacing-md;
- background: $bg-tertiary;
- border-radius: $radius-md;
- margin-bottom: $spacing-sm;
- }
- .file-info {
- display: flex;
- align-items: center;
- gap: $spacing-md;
- flex: 1;
- }
- .file-icon {
- width: 48px;
- height: 48px;
- color: $accent-color;
- }
- .file-details {
- flex: 1;
- min-width: 0; // 确保flex子项不会溢出
- .file-name {
- color: $text-primary;
- margin-bottom: $spacing-xs;
- word-break: break-word; // 长文件名自然换行
- overflow-wrap: break-word;
- white-space: normal; // 允许换行
- }
- .file-size {
- font-size: $font-size-sm;
- color: $text-muted;
- }
- }
- // 文件操作按钮容器
- .file-actions {
- display: flex;
- gap: $spacing-sm;
- align-items: center;
- flex-shrink: 0;
- }
- // 现代化按钮样式
- .btn-action {
- display: inline-flex;
- align-items: center;
- gap: $spacing-xs;
- padding: $spacing-sm $spacing-md;
- border-radius: $radius-md;
- border: none;
- font-size: $font-size-sm;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
- white-space: nowrap;
- svg {
- width: 18px;
- height: 18px;
- stroke-width: 2;
- }
- &:hover {
- transform: translateY(-1px);
- }
- &:active {
- transform: translateY(0);
- }
- }
- .btn-preview {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
- &:hover {
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
- background: linear-gradient(135deg, #7c8efc 0%, #8a5db8 100%);
- }
- }
- .btn-download {
- background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
- color: white;
- box-shadow: 0 2px 8px rgba(17, 153, 142, 0.3);
- &:hover {
- box-shadow: 0 4px 12px rgba(17, 153, 142, 0.4);
- background: linear-gradient(135deg, #14b89f 0%, #4fff8d 100%);
- }
- }
- .btn-download-all {
- width: 100%;
- margin-bottom: $spacing-lg;
- }
- .content-info {
- padding-top: $spacing-lg;
- border-top: 1px solid $border-color;
- p {
- font-size: $font-size-sm;
- color: $text-muted;
- margin-bottom: $spacing-xs;
- }
- }
- // 内容操作区
- .content-actions {
- margin-top: $spacing-md;
- display: flex;
- justify-content: flex-end;
- }
- // 删除按钮
- .btn-delete {
- display: inline-flex;
- align-items: center;
- gap: $spacing-xs;
- padding: $spacing-sm $spacing-md;
- background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%); // 红色渐变
- color: white;
- border: none;
- border-radius: $radius-md;
- font-size: $font-size-sm;
- font-weight: 500;
- cursor: pointer;
- box-shadow: 0 2px 8px rgba(238, 90, 111, 0.3);
- transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
- svg {
- width: 18px;
- height: 18px;
- stroke-width: 2;
- }
- &:hover {
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(238, 90, 111, 0.4);
- background: linear-gradient(135deg, #ff8787 0%, #ff6b6b 100%);
- }
- &:active {
- transform: translateY(0);
- }
- &:disabled {
- opacity: 0.6;
- cursor: not-allowed;
- transform: none !important;
- }
- }
- // 移动端优化
- @media (max-width: 768px) {
- .files-content {
- .content-header {
- flex-direction: column;
- align-items: flex-start;
- gap: $spacing-sm;
- margin-bottom: $spacing-md;
- h2 {
- font-size: $font-size-lg;
- }
- }
- }
- // 文件列表优化
- .file-item {
- flex-direction: column;
- align-items: stretch;
- gap: $spacing-sm;
- padding: $spacing-sm;
- .file-info {
- gap: $spacing-sm;
- }
- .file-icon {
- width: 36px;
- height: 36px;
- }
- .file-details {
- .file-name {
- font-size: $font-size-sm;
- }
- .file-size {
- font-size: $font-size-xs;
- }
- }
- .file-actions {
- justify-content: flex-end;
- gap: $spacing-xs;
- }
- }
- // 按钮优化
- .btn-action {
- padding: $spacing-xs $spacing-sm;
- font-size: $font-size-xs;
- svg {
- width: 16px;
- height: 16px;
- }
- span {
- // 在极小屏幕上隐藏文字,只显示图标
- @media (max-width: 480px) {
- display: none;
- }
- }
- }
- // 删除按钮移动端优化
- .btn-delete {
- padding: $spacing-xs $spacing-sm;
- font-size: $font-size-xs;
- svg {
- width: 16px;
- height: 16px;
- }
- span {
- // 在极小屏幕上隐藏文字,只显示图标
- @media (max-width: 480px) {
- display: none;
- }
- }
- }
- // 打包下载按钮优化
- .btn-download-all {
- padding: $spacing-sm $spacing-md;
- font-size: $font-size-base;
- }
- // 内容信息优化
- .content-info {
- p {
- font-size: $font-size-xs;
- }
- }
- }
- // 超小屏幕优化(<480px)
- @media (max-width: 480px) {
- .file-actions {
- .btn-action {
- padding: $spacing-xs;
- min-width: 36px; // 确保按钮可点击区域足够
- justify-content: center;
- span {
- display: none; // 只显示图标
- }
- }
- }
- }
- </style>
|