智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

369 lines
11 KiB

<template>
<uni-popup ref="popup" type="center">
<view class="popup-container">
<view class="popup-header">
<view class="popup-title">{{ isEditing ? '编辑体测记录' : '新增体测记录' }}</view>
<view class="popup-close" @click="close"></view>
</view>
<view class="fitness-record-form">
<view class="form-section">
<view class="form-item">
<view class="form-label">测试日期</view>
<view class="form-input">
<input type="date" v-model="recordData.test_date" placeholder="请选择测试日期" />
</view>
</view>
<view class="form-item">
<view class="form-label">身高(cm)</view>
<view class="form-input">
<input type="number" v-model="recordData.height" placeholder="请输入身高" />
</view>
</view>
<view class="form-item">
<view class="form-label">体重(kg)</view>
<view class="form-input">
<input type="number" v-model="recordData.weight" placeholder="请输入体重" />
</view>
</view>
<view class="form-item">
<view class="form-label">体测报告</view>
<view class="file-upload-area">
<view class="upload-btn" @click="selectPDFFiles">
<view class="upload-icon">📁</view>
<view class="upload-text">选择PDF文件</view>
</view>
<!-- 已选择的PDF文件列表 -->
<view v-if="recordData.pdf_files && recordData.pdf_files.length > 0"
class="selected-files">
<view v-for="(pdf, index) in recordData.pdf_files" :key="index"
class="selected-file-item">
<view class="file-info" @click="previewPDF(pdf)">
<view class="file-icon">📄</view>
<view class="file-name">{{ pdf.name }}</view>
<view class="file-size">{{ formatFileSize(pdf.size) }}</view>
</view>
<view class="file-remove" @click="removePDFFile(index)">✕</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="popup-footer">
<view class="popup-btn cancel-btn" @click="close">取消</view>
<view class="popup-btn confirm-btn" @click="confirm">确认</view>
</view>
</view>
</uni-popup>
</template>
<script>
export default {
name: 'FitnessRecordPopup',
props: {
resourceId: {
type: String,
default: ''
}
},
data() {
return {
isVisible: false,
isEditing: false,
recordData: {
id: null,
test_date: '',
height: '',
weight: '',
pdf_files: []
}
}
},
methods: {
// 打开新增弹窗
openAdd() {
this.isEditing = false
this.resetData()
this.recordData.test_date = this.getCurrentDate()
this.isVisible = true
this.$refs.popup.open()
},
// 打开编辑弹窗
openEdit(record) {
this.isEditing = true
this.recordData = {
id: record.id,
test_date: record.test_date,
height: record.height,
weight: record.weight,
pdf_files: [...(record.pdf_files || [])]
}
this.isVisible = true
this.$refs.popup.open()
},
// 关闭弹窗
close() {
this.isVisible = false
this.$refs.popup.close()
this.resetData()
this.$emit('close')
},
// 重置数据
resetData() {
this.recordData = {
id: null,
test_date: '',
height: '',
weight: '',
pdf_files: []
}
},
// 确认保存
async confirm() {
try {
// 表单验证
if (!this.recordData.test_date) {
uni.showToast({
title: '请选择测试日期',
icon: 'none'
})
return
}
if (!this.recordData.height) {
uni.showToast({
title: '请输入身高',
icon: 'none'
})
return
}
if (!this.recordData.weight) {
uni.showToast({
title: '请输入体重',
icon: 'none'
})
return
}
uni.showLoading({
title: '保存中...',
mask: true
})
// 确保resource_id不为空
console.log('当前resourceId:', this.resourceId)
console.log('父组件传递的resourceId:', this.$props.resourceId)
if (!this.resourceId) {
uni.showToast({
title: '缺少学生资源ID,请稍后重试',
icon: 'none'
})
uni.hideLoading()
return
}
const params = {
resource_id: this.resourceId,
student_id: this.resourceId, // 添加student_id字段
test_date: this.recordData.test_date,
height: this.recordData.height,
weight: this.recordData.weight,
// 将PDF文件转换为服务器需要的格式
physical_test_report: this.recordData.pdf_files
.map(file => file.server_path || file.url)
.filter(path => path)
.join(',') // 用逗号连接多个文件路径
}
if (this.isEditing) {
params.id = this.recordData.id
}
console.log('保存体测记录参数:', params)
// 触发确认事件,将数据传递给父组件
this.$emit('confirm', {
isEditing: this.isEditing,
data: params
})
uni.hideLoading()
this.close()
} catch (error) {
console.error('保存体测记录失败:', error)
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
})
uni.hideLoading()
}
},
// 选择PDF文件
selectPDFFiles() {
uni.chooseFile({
count: 5,
type: 'file',
extension: ['pdf'],
success: async (res) => {
console.log('选择的文件:', res.tempFiles)
for (let file of res.tempFiles) {
if (file.type === 'application/pdf') {
try {
// 立即上传PDF文件到服务器
const uploadResult = await this.uploadPdfFile(file)
if (uploadResult && uploadResult.code === 1) {
const pdfFile = {
id: Date.now() + Math.random(),
name: file.name,
size: file.size,
url: uploadResult.data.file_url, // 使用服务器返回的URL
server_path: uploadResult.data.file_path, // 服务器路径
upload_time: uploadResult.data.upload_time
}
this.recordData.pdf_files.push(pdfFile)
} else {
uni.showToast({
title: uploadResult.msg || '文件上传失败',
icon: 'none'
})
}
} catch (error) {
console.error('上传PDF文件失败:', error)
uni.showToast({
title: '文件上传失败',
icon: 'none'
})
}
}
}
},
fail: (err) => {
console.error('选择文件失败:', err)
uni.showToast({
title: '选择文件失败',
icon: 'none'
})
}
})
},
// 上传PDF文件到服务器
async uploadPdfFile(file) {
const { Api_url } = require('@/common/config.js')
const token = uni.getStorageSync('token') || ''
return new Promise((resolve, reject) => {
uni.uploadFile({
url: Api_url + '/xy/physicalTest/uploadPdf', // 使用专门的PDF上传接口
filePath: file.path,
name: 'file',
header: {
'token': token
},
success: (res) => {
let response
try {
// 去除 BOM 字符并解析 JSON
response = JSON.parse(res.data.replace(/\ufeff/g, '') || '{}')
} catch (e) {
console.error('PDF上传响应解析失败:', e)
reject(e)
return
}
if (response.code === 1) {
resolve({
code: 1,
msg: '上传成功',
data: {
file_name: response.data.file_name || file.name,
file_path: response.data.file_path,
file_url: response.data.file_url || response.data.url,
file_size: file.size,
upload_time: new Date().toLocaleString()
}
})
} else if (response.code === 401) {
uni.showToast({ title: response.msg, icon: 'none' })
setTimeout(() => {
uni.navigateTo({ url: '/pages/student/login/login' })
}, 1000)
reject(response)
} else {
uni.showToast({ title: response.msg || 'PDF上传失败', icon: 'none' })
reject(response)
}
},
fail: (err) => {
console.error('PDF上传网络失败:', err)
uni.showToast({ title: err.errMsg || '网络异常', icon: 'none' })
reject(err)
}
})
})
},
// 移除PDF文件
removePDFFile(index) {
this.recordData.pdf_files.splice(index, 1)
},
// 预览PDF文件
previewPDF(pdf) {
console.log('预览PDF:', pdf)
// 使用uni.openDocument预览PDF
uni.openDocument({
filePath: pdf.url,
fileType: 'pdf',
showMenu: true,
success: (res) => {
console.log('PDF预览成功:', res)
},
fail: (err) => {
console.error('PDF预览失败:', err)
uni.showToast({
title: '预览失败',
icon: 'none'
})
}
})
},
// 获取当前日期
getCurrentDate() {
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
},
// 格式化文件大小
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 parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
}
}
</script>
<style lang="less" scoped>
@import './fitness-record-popup.less';
</style>