fix: 修复赛事规程下载文件无后缀问题

- event-rules页面H5环境使用a标签download属性指定文件名
- 修复api.config.js生产环境API地址配置
- 优化多个页面的附件展示

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
DevOps
2025-12-26 15:45:30 +08:00
parent 9c063a9779
commit 541c770f27
6 changed files with 606 additions and 495 deletions

View File

@@ -1,5 +1,27 @@
<template>
<view class="event-info-page">
<!-- 附件下载区 -->
<view class="attachments-section" v-if="attachments.length > 0">
<view class="section-title">
<text class="title-icon">📎</text>
<text class="title-text">相关附件</text>
</view>
<view class="attachments-list">
<view class="attachment-item" v-for="(file, index) in attachments" :key="index" @click="downloadFile(file)">
<view class="file-info">
<text class="file-icon">{{ getFileIcon(file.fileType) }}</text>
<view class="file-details">
<text class="file-name">{{ file.fileName }}</text>
<text class="file-size">{{ file.fileSize }}</text>
</view>
</view>
<view class="download-btn">
<text class="download-icon"></text>
</view>
</view>
</view>
</view>
<!-- 信息列表 -->
<view class="info-list">
<view class="info-item" v-for="(item, index) in infoList" :key="index" @click="handleItemClick(item)">
@@ -13,7 +35,7 @@
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="infoList.length === 0">
<view class="empty-state" v-if="infoList.length === 0 && attachments.length === 0">
<text class="empty-text">暂无信息发布</text>
</view>
</view>
@@ -21,21 +43,57 @@
<script>
import infoAPI from '@/api/info.js'
import competitionAPI from '@/api/competition.js'
export default {
data() {
return {
eventId: '',
infoList: []
infoList: [],
attachments: []
};
},
onLoad(options) {
if (options.eventId) {
this.eventId = options.eventId
this.loadInfoList(options.eventId)
this.loadAttachments(options.eventId)
}
},
methods: {
/**
* 加载附件列表
*/
async loadAttachments(eventId) {
try {
const res = await competitionAPI.getAttachments({
competitionId: eventId,
type: 'info'
})
let list = []
if (res && Array.isArray(res)) {
list = res
} else if (res && res.records) {
list = res.records
} else if (res && res.data && Array.isArray(res.data)) {
list = res.data
}
if (list.length > 0) {
this.attachments = list.map(file => ({
id: file.id,
fileName: file.fileName || file.name,
fileUrl: file.fileUrl || file.url,
fileSize: this.formatFileSize(file.fileSize || file.size),
fileType: file.fileType || this.getFileType(file.fileName || file.name)
}))
}
} catch (err) {
console.error('加载附件失败:', err)
}
},
/**
* 加载信息发布列表
*/
@@ -50,11 +108,6 @@ export default {
list = res
}
// 如果后端没有数据,使用模拟数据
if (list.length === 0) {
list = this.getMockData()
}
// 数据映射
this.infoList = list.map(item => ({
id: item.id,
@@ -66,81 +119,100 @@ export default {
}))
} catch (err) {
console.error('加载信息列表失败:', err)
// 加载失败时使用模拟数据
const list = this.getMockData()
this.infoList = list.map(item => ({
id: item.id,
type: this.getInfoType(item.info_type || item.type),
typeText: this.getInfoTypeText(item.info_type || item.type),
title: item.title,
desc: item.content,
time: this.formatTime(item.publishTime)
}))
}
},
/**
* 获取模拟数据
* 下载文件
*/
getMockData() {
return [
{
id: 1,
info_type: 3,
title: '重要通知:赛事报名截止时间变更',
content: '由于场馆调整本次赛事报名截止时间延长至2025年12月20日请各位选手抓紧时间报名。如有疑问请联系赛事组委会。',
publishTime: '2025-01-10 09:00:00'
downloadFile(file) {
const fileExt = file.fileType || this.getFileType(file.fileName) || 'pdf'
// #ifdef H5
const link = document.createElement('a')
link.href = file.fileUrl
link.download = file.fileName
link.target = '_blank'
link.style.display = 'none'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
uni.showToast({
title: '开始下载',
icon: 'success'
})
return
// #endif
// #ifndef H5
uni.showLoading({ title: '准备下载' })
uni.downloadFile({
url: file.fileUrl,
success: (res) => {
if (res.statusCode === 200) {
uni.openDocument({
filePath: res.tempFilePath,
fileType: fileExt,
success: () => {
uni.hideLoading()
uni.showToast({ title: '打开成功', icon: 'success' })
},
fail: (err) => {
uni.hideLoading()
console.error('打开文件失败:', err)
uni.showToast({ title: '打开失败', icon: 'none' })
}
})
}
},
{
id: 2,
info_type: 1,
title: '参赛选手须知',
content: '请各位参赛选手提前1小时到达比赛场地进行检录携带身份证原件及复印件。比赛期间请遵守赛场纪律服从裁判判决。',
publishTime: '2025-01-09 14:30:00'
},
{
id: 3,
info_type: 2,
title: '比赛场地及交通指引',
content: '本次赛事在市体育中心举行地址XX市XX区XX路100号。可乘坐地铁2号线至体育中心站下车或乘坐公交车88路、99路至体育中心站。场馆提供免费停车位。',
publishTime: '2025-01-08 16:00:00'
},
{
id: 4,
info_type: 1,
title: '赛前训练安排通知',
content: '为方便各位选手熟悉场地组委会安排在比赛前一天12月24日下午14:00-17:00开放场地供选手训练。请需要训练的选手提前联系组委会预约。',
publishTime: '2025-01-07 10:20:00'
},
{
id: 5,
info_type: 2,
title: '比赛流程及注意事项',
content: '比赛采用淘汰赛制分为预赛、半决赛和决赛三个阶段。每场比赛时长为5分钟选手需提前做好热身准备。比赛过程中严禁使用违禁器材。',
publishTime: '2025-01-06 11:45:00'
},
{
id: 6,
info_type: 1,
title: '医疗保障及安全提示',
content: '赛事现场配备专业医疗团队和救护车,设有医疗服务点。建议选手自备常用药品,如有特殊疾病请提前告知组委会。比赛前请充分热身,避免受伤。',
publishTime: '2025-01-05 15:10:00'
},
{
id: 7,
info_type: 3,
title: '关于赛事直播安排的通知',
content: '本次赛事将进行全程网络直播届时可通过官方网站和APP观看。精彩瞬间将在赛后剪辑发布敬请期待',
publishTime: '2025-01-04 13:00:00'
},
{
id: 8,
info_type: 2,
title: '志愿者招募公告',
content: '赛事组委会现招募志愿者50名负责现场引导、秩序维护、后勤保障等工作。有意者请扫描海报二维码报名报名截止时间为12月15日。',
publishTime: '2025-01-03 09:30:00'
fail: (err) => {
uni.hideLoading()
console.error('下载失败:', err)
uni.showToast({ title: '下载失败', icon: 'none' })
}
]
})
// #endif
},
/**
* 获取文件类型
*/
getFileType(fileName) {
if (!fileName) return 'pdf'
const ext = fileName.split('.').pop().toLowerCase()
return ext
},
/**
* 获取文件图标
*/
getFileIcon(fileType) {
const iconMap = {
'pdf': '📕',
'doc': '📘',
'docx': '📘',
'xls': '📗',
'xlsx': '📗',
'ppt': '📙',
'pptx': '📙',
'txt': '📄',
'zip': '📦',
'rar': '📦'
}
return iconMap[fileType] || '📄'
},
/**
* 格式化文件大小
*/
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(2) + ' ' + sizes[i]
},
/**
@@ -190,7 +262,6 @@ export default {
},
handleItemClick(item) {
// 跳转到信息详情页
uni.navigateTo({
url: `/pages/event-info-detail/event-info-detail?id=${item.id}&type=${item.type}&typeText=${encodeURIComponent(item.typeText)}&title=${encodeURIComponent(item.title)}&content=${encodeURIComponent(item.desc)}&time=${encodeURIComponent(item.time)}`
})
@@ -206,6 +277,103 @@ export default {
padding: 20rpx 30rpx;
}
// 区块标题
.section-title {
display: flex;
align-items: center;
gap: 10rpx;
margin-bottom: 20rpx;
padding: 0 10rpx;
}
.title-icon {
font-size: 32rpx;
}
.title-text {
font-size: 30rpx;
font-weight: bold;
color: #333333;
}
// 附件下载区
.attachments-section {
margin-bottom: 30rpx;
}
.attachments-list {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.attachment-item {
background-color: #fff;
border-radius: 16rpx;
padding: 25rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
transition: all 0.3s;
&:active {
background-color: #f8f8f8;
transform: scale(0.98);
}
}
.file-info {
display: flex;
align-items: center;
gap: 20rpx;
flex: 1;
min-width: 0;
}
.file-icon {
font-size: 48rpx;
flex-shrink: 0;
}
.file-details {
display: flex;
flex-direction: column;
gap: 8rpx;
flex: 1;
min-width: 0;
}
.file-name {
font-size: 28rpx;
color: #333333;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-size {
font-size: 24rpx;
color: #999999;
}
.download-btn {
width: 60rpx;
height: 60rpx;
background-color: #C93639;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.download-icon {
font-size: 32rpx;
color: #fff;
}
.info-list {
display: flex;
flex-direction: column;