881 lines
21 KiB
Vue
881 lines
21 KiB
Vue
<template>
|
||
<view class="attachment-page">
|
||
<!-- 赛事信息卡片 -->
|
||
<view class="event-info-card">
|
||
<view class="event-title">{{ competitionName || '赛事名称' }}</view>
|
||
<view class="event-time-row">
|
||
<view class="time-item">
|
||
<text class="time-label">开始时间</text>
|
||
<text class="time-value">{{ startTime || '待定' }}</text>
|
||
</view>
|
||
<view class="time-divider"></view>
|
||
<view class="time-item">
|
||
<text class="time-label">结束时间</text>
|
||
<text class="time-value">{{ endTime || '待定' }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view class="loading-state" v-if="loading">
|
||
<view class="loading-spinner"></view>
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
|
||
<!-- 附件列表 -->
|
||
<view class="attachments-section" v-if="!loading && attachments.length > 0">
|
||
<view class="section-header">
|
||
<text class="section-title">{{ pageTitle }}文件</text>
|
||
<text class="section-count">共{{ attachments.length }}个文件</text>
|
||
</view>
|
||
|
||
<view class="attachments-list">
|
||
<view
|
||
class="attachment-item"
|
||
v-for="(file, index) in attachments"
|
||
:key="index"
|
||
>
|
||
<!-- 文件图标 -->
|
||
<view class="file-icon" :class="'icon-' + file.fileType">
|
||
<text class="icon-text">{{ getFileIconText(file.fileType) }}</text>
|
||
</view>
|
||
|
||
<!-- 文件信息 -->
|
||
<view class="file-content">
|
||
<text class="file-name">{{ file.fileName }}</text>
|
||
<view class="file-meta">
|
||
<text class="meta-item">{{ file.fileSize }}</text>
|
||
<text class="meta-dot" v-if="file.uploadTime">·</text>
|
||
<text class="meta-item" v-if="file.uploadTime">{{ file.uploadTime }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮 -->
|
||
<view class="file-actions">
|
||
<view class="action-btn preview-btn" @click="previewFile(file)">
|
||
<text class="action-text">预览</text>
|
||
</view>
|
||
<view class="action-btn download-btn" @click="downloadFile(file)">
|
||
<text class="action-text">下载</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view class="empty-state" v-if="!loading && attachments.length === 0">
|
||
<image class="empty-image" src="/static/images/empty.png" mode="aspectFit" />
|
||
<text class="empty-title">暂无{{ pageTitle }}文件</text>
|
||
<text class="empty-desc">相关文件正在整理中,请稍后查看</text>
|
||
</view>
|
||
|
||
<!-- PDF预览弹窗 (仅H5) -->
|
||
<!-- #ifdef H5 -->
|
||
<view class="preview-modal" v-if="showPreview" @click="closePreview">
|
||
<view class="preview-container" @click.stop>
|
||
<view class="preview-header">
|
||
<text class="preview-title">{{ previewFileName }}</text>
|
||
<view class="preview-close" @click="closePreview">
|
||
<text class="close-icon">×</text>
|
||
</view>
|
||
</view>
|
||
<view class="preview-body">
|
||
<iframe
|
||
:src="previewUrl"
|
||
class="preview-iframe"
|
||
frameborder="0"
|
||
></iframe>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import competitionAPI from '@/api/competition.js'
|
||
|
||
// 页面类型配置
|
||
const PAGE_CONFIG = {
|
||
'info': { title: '信息发布', type: 'info' },
|
||
'rules': { title: '赛事规程', type: 'rules' },
|
||
'schedule': { title: '活动日程', type: 'schedule' },
|
||
'score': { title: '成绩公告', type: 'results' },
|
||
'results': { title: '成绩公告', type: 'results' },
|
||
'awards': { title: '奖牌榜', type: 'medals' },
|
||
'medals': { title: '奖牌榜', type: 'medals' },
|
||
'photos': { title: '图片直播', type: 'photos' }
|
||
}
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
loading: true,
|
||
pageType: 'rules',
|
||
pageTitle: '赛事规程',
|
||
competitionId: '',
|
||
competitionName: '',
|
||
startTime: '',
|
||
endTime: '',
|
||
attachments: [],
|
||
// H5预览相关
|
||
showPreview: false,
|
||
previewUrl: '',
|
||
previewFileName: ''
|
||
}
|
||
},
|
||
onLoad(options) {
|
||
// 获取页面类型
|
||
if (options.type && PAGE_CONFIG[options.type]) {
|
||
this.pageType = options.type
|
||
this.pageTitle = PAGE_CONFIG[options.type].title
|
||
}
|
||
|
||
// 获取赛事ID
|
||
if (options.competitionId || options.eventId) {
|
||
this.competitionId = options.competitionId || options.eventId
|
||
}
|
||
|
||
// 获取赛事名称
|
||
if (options.name) {
|
||
this.competitionName = decodeURIComponent(options.name)
|
||
}
|
||
|
||
// 获取比赛时间
|
||
if (options.startTime) {
|
||
this.startTime = decodeURIComponent(options.startTime)
|
||
}
|
||
if (options.endTime) {
|
||
this.endTime = decodeURIComponent(options.endTime)
|
||
}
|
||
|
||
// 设置导航栏标题
|
||
uni.setNavigationBarTitle({
|
||
title: this.pageTitle
|
||
})
|
||
|
||
// 加载数据
|
||
this.loadData()
|
||
},
|
||
methods: {
|
||
/**
|
||
* 加载数据
|
||
*/
|
||
async loadData() {
|
||
this.loading = true
|
||
try {
|
||
// 如果没有赛事信息,先获取赛事详情
|
||
if (!this.startTime || !this.endTime) {
|
||
await this.loadCompetitionInfo()
|
||
}
|
||
// 加载附件列表
|
||
await this.loadAttachments()
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 加载赛事信息
|
||
*/
|
||
async loadCompetitionInfo() {
|
||
try {
|
||
const res = await competitionAPI.getCompetitionDetail(this.competitionId)
|
||
if (res) {
|
||
this.competitionName = res.name || res.title || this.competitionName
|
||
this.startTime = this.formatDate(res.startTime || res.competitionStartTime)
|
||
this.endTime = this.formatDate(res.endTime || res.competitionEndTime)
|
||
}
|
||
} catch (err) {
|
||
console.error('加载赛事信息失败:', err)
|
||
// 使用模拟数据
|
||
this.startTime = '2025.12.12'
|
||
this.endTime = '2025.12.14'
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 加载附件列表
|
||
*/
|
||
async loadAttachments() {
|
||
try {
|
||
// 使用 PAGE_CONFIG 映射的 type 值
|
||
const attachmentType = PAGE_CONFIG[this.pageType]?.type || this.pageType
|
||
console.log('=== 加载附件 ===')
|
||
console.log('competitionId:', this.competitionId)
|
||
console.log('pageType:', this.pageType)
|
||
console.log('attachmentType (发送给后端):', attachmentType)
|
||
|
||
const res = await competitionAPI.getAttachments({
|
||
competitionId: this.competitionId,
|
||
type: attachmentType
|
||
})
|
||
|
||
console.log('API返回结果:', res)
|
||
console.log('API返回结果类型:', typeof res)
|
||
console.log('是否为数组:', Array.isArray(res))
|
||
|
||
// 兼容不同的返回格式
|
||
let attachmentList = []
|
||
if (Array.isArray(res)) {
|
||
attachmentList = res
|
||
} else if (res && res.records && Array.isArray(res.records)) {
|
||
// 分页格式
|
||
attachmentList = res.records
|
||
} else if (res && typeof res === 'object') {
|
||
// 可能是单个对象,转为数组
|
||
attachmentList = [res]
|
||
}
|
||
|
||
console.log('处理后的附件列表:', attachmentList)
|
||
|
||
if (attachmentList.length > 0) {
|
||
this.attachments = attachmentList.map(file => ({
|
||
id: file.id,
|
||
fileName: file.fileName || file.name,
|
||
fileUrl: file.fileUrl || file.url,
|
||
fileSize: this.formatFileSize(file.fileSize || file.size),
|
||
fileType: this.getFileType(file.fileName || file.name),
|
||
uploadTime: this.formatDate(file.uploadTime || file.createTime)
|
||
}))
|
||
console.log('附件加载成功,共', this.attachments.length, '个文件')
|
||
} else {
|
||
console.log('没有附件数据,显示空状态')
|
||
this.attachments = []
|
||
}
|
||
} catch (err) {
|
||
console.error('=== 加载附件失败 ===')
|
||
console.error('错误详情:', err)
|
||
console.error('错误消息:', err.message)
|
||
console.error('错误代码:', err.code)
|
||
// 显示空状态,不使用模拟数据,方便调试
|
||
this.attachments = []
|
||
// 如果需要模拟数据,取消下面的注释
|
||
// this.loadMockData()
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 加载模拟数据
|
||
*/
|
||
loadMockData() {
|
||
const mockDataMap = {
|
||
'info': [
|
||
{ id: '1', fileName: '2025年郑州武术大赛通知.pdf', fileUrl: '', fileSize: '1.2 MB', fileType: 'pdf', uploadTime: '2025-12-20' }
|
||
],
|
||
'rules': [
|
||
{ id: '1', fileName: '2025年郑州武术大赛竞赛规程.pdf', fileUrl: '', fileSize: '2.5 MB', fileType: 'pdf', uploadTime: '2025-12-18' },
|
||
{ id: '2', fileName: '参赛报名表.pdf', fileUrl: '', fileSize: '156 KB', fileType: 'pdf', uploadTime: '2025-12-18' }
|
||
],
|
||
'schedule': [
|
||
{ id: '1', fileName: '比赛日程安排表.pdf', fileUrl: '', fileSize: '890 KB', fileType: 'pdf', uploadTime: '2025-12-19' }
|
||
],
|
||
'score': [
|
||
{ id: '1', fileName: '比赛成绩公告.pdf', fileUrl: '', fileSize: '1.8 MB', fileType: 'pdf', uploadTime: '2025-12-25' }
|
||
],
|
||
'results': [
|
||
{ id: '1', fileName: '比赛成绩公告.pdf', fileUrl: '', fileSize: '1.8 MB', fileType: 'pdf', uploadTime: '2025-12-25' }
|
||
],
|
||
'awards': [
|
||
{ id: '1', fileName: '奖牌榜统计.pdf', fileUrl: '', fileSize: '520 KB', fileType: 'pdf', uploadTime: '2025-12-25' }
|
||
],
|
||
'medals': [
|
||
{ id: '1', fileName: '奖牌榜统计.pdf', fileUrl: '', fileSize: '520 KB', fileType: 'pdf', uploadTime: '2025-12-25' }
|
||
],
|
||
'photos': [
|
||
{ id: '1', fileName: '比赛精彩瞬间.pdf', fileUrl: '', fileSize: '15.6 MB', fileType: 'pdf', uploadTime: '2025-12-25' }
|
||
]
|
||
}
|
||
|
||
this.attachments = mockDataMap[this.pageType] || []
|
||
},
|
||
|
||
/**
|
||
* 预览文件
|
||
*/
|
||
previewFile(file) {
|
||
if (!file.fileUrl) {
|
||
uni.showToast({
|
||
title: '文件暂不可用',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// #ifdef H5
|
||
// H5端:根据文件类型选择预览方式
|
||
if (file.fileType === 'pdf') {
|
||
// 方案1: 直接在新标签页打开PDF(浏览器内置PDF阅读器)
|
||
window.open(file.fileUrl, '_blank')
|
||
|
||
// 方案2: 使用微软 Office Online Viewer(备选,需要公网可访问)
|
||
// const msViewerUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(file.fileUrl)}`
|
||
// window.open(msViewerUrl, '_blank')
|
||
|
||
// 方案3: 使用内嵌弹窗(如果服务器支持)
|
||
// this.previewFileName = file.fileName
|
||
// this.previewUrl = file.fileUrl
|
||
// this.showPreview = true
|
||
} else if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(file.fileType)) {
|
||
// 图片使用弹窗显示
|
||
this.previewFileName = file.fileName
|
||
this.previewUrl = file.fileUrl
|
||
this.showPreview = true
|
||
} else if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(file.fileType)) {
|
||
// Office 文档使用微软在线预览
|
||
const msViewerUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(file.fileUrl)}`
|
||
window.open(msViewerUrl, '_blank')
|
||
} else {
|
||
// 其他文件类型,在新窗口打开
|
||
window.open(file.fileUrl, '_blank')
|
||
}
|
||
return
|
||
// #endif
|
||
|
||
// #ifndef H5
|
||
// 非H5端使用下载+打开文档的方式
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
|
||
uni.downloadFile({
|
||
url: file.fileUrl,
|
||
success: (res) => {
|
||
uni.hideLoading()
|
||
if (res.statusCode === 200) {
|
||
uni.openDocument({
|
||
filePath: res.tempFilePath,
|
||
fileType: file.fileType,
|
||
showMenu: true,
|
||
success: () => {
|
||
console.log('打开文档成功')
|
||
},
|
||
fail: (err) => {
|
||
console.error('打开文档失败:', err)
|
||
uni.showToast({
|
||
title: '无法预览此文件',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: '文件加载失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading()
|
||
console.error('下载失败:', err)
|
||
uni.showToast({
|
||
title: '下载失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
// #endif
|
||
},
|
||
|
||
/**
|
||
* 关闭预览弹窗
|
||
*/
|
||
closePreview() {
|
||
this.showPreview = false
|
||
this.previewUrl = ''
|
||
this.previewFileName = ''
|
||
},
|
||
|
||
/**
|
||
* 下载文件
|
||
*/
|
||
downloadFile(file) {
|
||
if (!file.fileUrl) {
|
||
uni.showToast({
|
||
title: '文件暂不可用',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
uni.showLoading({
|
||
title: '下载中...'
|
||
})
|
||
|
||
uni.downloadFile({
|
||
url: file.fileUrl,
|
||
success: (res) => {
|
||
uni.hideLoading()
|
||
if (res.statusCode === 200) {
|
||
// #ifdef MP-WEIXIN
|
||
// 微信小程序保存文件
|
||
uni.saveFile({
|
||
tempFilePath: res.tempFilePath,
|
||
success: (saveRes) => {
|
||
uni.showToast({
|
||
title: '下载成功',
|
||
icon: 'success'
|
||
})
|
||
},
|
||
fail: () => {
|
||
// 保存失败则打开文档
|
||
uni.openDocument({
|
||
filePath: res.tempFilePath,
|
||
fileType: file.fileType,
|
||
showMenu: true
|
||
})
|
||
}
|
||
})
|
||
// #endif
|
||
|
||
// #ifdef H5
|
||
// H5端打开新窗口下载
|
||
window.open(file.fileUrl)
|
||
uni.showToast({
|
||
title: '开始下载',
|
||
icon: 'success'
|
||
})
|
||
// #endif
|
||
|
||
// #ifdef APP-PLUS
|
||
// APP端保存到相册或文件
|
||
uni.saveFile({
|
||
tempFilePath: res.tempFilePath,
|
||
success: (saveRes) => {
|
||
uni.showToast({
|
||
title: '下载成功',
|
||
icon: 'success'
|
||
})
|
||
},
|
||
fail: () => {
|
||
uni.openDocument({
|
||
filePath: res.tempFilePath,
|
||
fileType: file.fileType,
|
||
showMenu: true
|
||
})
|
||
}
|
||
})
|
||
// #endif
|
||
} else {
|
||
uni.showToast({
|
||
title: '下载失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
uni.hideLoading()
|
||
console.error('下载失败:', err)
|
||
uni.showToast({
|
||
title: '下载失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
/**
|
||
* 获取文件类型
|
||
*/
|
||
getFileType(fileName) {
|
||
if (!fileName) return 'pdf'
|
||
const ext = fileName.split('.').pop().toLowerCase()
|
||
return ext
|
||
},
|
||
|
||
/**
|
||
* 获取文件图标文字
|
||
*/
|
||
getFileIconText(fileType) {
|
||
const iconMap = {
|
||
'pdf': 'PDF',
|
||
'doc': 'DOC',
|
||
'docx': 'DOC',
|
||
'xls': 'XLS',
|
||
'xlsx': 'XLS',
|
||
'ppt': 'PPT',
|
||
'pptx': 'PPT',
|
||
'txt': 'TXT',
|
||
'jpg': 'IMG',
|
||
'jpeg': 'IMG',
|
||
'png': 'IMG',
|
||
'zip': 'ZIP',
|
||
'rar': 'RAR'
|
||
}
|
||
return iconMap[fileType] || 'FILE'
|
||
},
|
||
|
||
/**
|
||
* 格式化文件大小
|
||
*/
|
||
formatFileSize(bytes) {
|
||
if (!bytes || bytes === 0) return '0 B'
|
||
if (typeof bytes === 'string') return bytes
|
||
|
||
const k = 1024
|
||
const sizes = ['B', 'KB', 'MB', 'GB']
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||
return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i]
|
||
},
|
||
|
||
/**
|
||
* 格式化日期
|
||
*/
|
||
formatDate(dateStr) {
|
||
if (!dateStr) return ''
|
||
const date = new Date(dateStr)
|
||
if (isNaN(date.getTime())) return dateStr
|
||
const year = date.getFullYear()
|
||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||
const day = String(date.getDate()).padStart(2, '0')
|
||
return `${year}.${month}.${day}`
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.attachment-page {
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
// 赛事信息卡片
|
||
.event-info-card {
|
||
background: #fff;
|
||
margin: 20rpx;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.event-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 24rpx;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.event-time-row {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #f8f8f8;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.time-item {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.time-label {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.time-value {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.time-divider {
|
||
width: 1rpx;
|
||
height: 60rpx;
|
||
background: #e0e0e0;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
// 加载状态
|
||
.loading-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 120rpx 0;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
border: 4rpx solid #f0f0f0;
|
||
border-top-color: #C93639;
|
||
border-radius: 50%;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
.loading-text {
|
||
margin-top: 20rpx;
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
// 附件区域
|
||
.attachments-section {
|
||
margin: 20rpx;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
padding: 0 10rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.section-count {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.attachments-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
// 附件项
|
||
.attachment-item {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
padding: 24rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||
}
|
||
|
||
// 文件图标
|
||
.file-icon {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
background: #C93639;
|
||
}
|
||
|
||
.file-icon.icon-pdf {
|
||
background: #E74C3C;
|
||
}
|
||
|
||
.file-icon.icon-doc,
|
||
.file-icon.icon-docx {
|
||
background: #3498DB;
|
||
}
|
||
|
||
.file-icon.icon-xls,
|
||
.file-icon.icon-xlsx {
|
||
background: #27AE60;
|
||
}
|
||
|
||
.file-icon.icon-ppt,
|
||
.file-icon.icon-pptx {
|
||
background: #E67E22;
|
||
}
|
||
|
||
.file-icon.icon-jpg,
|
||
.file-icon.icon-jpeg,
|
||
.file-icon.icon-png {
|
||
background: #9B59B6;
|
||
}
|
||
|
||
.icon-text {
|
||
font-size: 22rpx;
|
||
font-weight: bold;
|
||
color: #fff;
|
||
}
|
||
|
||
// 文件内容
|
||
.file-content {
|
||
flex: 1;
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.file-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8rpx;
|
||
}
|
||
|
||
.meta-item {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.meta-dot {
|
||
font-size: 24rpx;
|
||
color: #ccc;
|
||
}
|
||
|
||
// 操作按钮
|
||
.file-actions {
|
||
flex-shrink: 0;
|
||
display: flex;
|
||
gap: 12rpx;
|
||
}
|
||
|
||
.action-btn {
|
||
padding: 12rpx 24rpx;
|
||
border-radius: 30rpx;
|
||
transition: all 0.3s;
|
||
|
||
&:active {
|
||
opacity: 0.8;
|
||
transform: scale(0.95);
|
||
}
|
||
}
|
||
|
||
.preview-btn {
|
||
background: #C93639;
|
||
|
||
.action-text {
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
.download-btn {
|
||
background: #fff;
|
||
border: 1rpx solid #C93639;
|
||
|
||
.action-text {
|
||
color: #C93639;
|
||
}
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 24rpx;
|
||
font-weight: 500;
|
||
}
|
||
|
||
// 空状态
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 120rpx 60rpx;
|
||
}
|
||
|
||
.empty-image {
|
||
width: 200rpx;
|
||
height: 200rpx;
|
||
margin-bottom: 30rpx;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.empty-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.empty-desc {
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
text-align: center;
|
||
}
|
||
|
||
// PDF预览弹窗样式
|
||
.preview-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.7);
|
||
z-index: 9999;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.preview-container {
|
||
width: 95%;
|
||
height: 90%;
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.preview-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24rpx 30rpx;
|
||
background: #C93639;
|
||
color: #fff;
|
||
}
|
||
|
||
.preview-title {
|
||
font-size: 32rpx;
|
||
font-weight: 500;
|
||
flex: 1;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
padding-right: 20rpx;
|
||
}
|
||
|
||
.preview-close {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.close-icon {
|
||
font-size: 40rpx;
|
||
color: #fff;
|
||
line-height: 1;
|
||
}
|
||
|
||
.preview-body {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.preview-iframe {
|
||
width: 100%;
|
||
height: 100%;
|
||
border: none;
|
||
}
|
||
</style>
|