// pages/registration/registration.js
|
const app = getApp()
|
const { graphqlRequest } = require('../../lib/utils')
|
const { uploadFile, chooseAndUploadImage } = require('../../lib/upload')
|
const cosUtil = require('../../lib/cosUtil')
|
|
Page({
|
data: {
|
activityId: '',
|
activity: null,
|
loading: false,
|
|
// 表单数据
|
formData: {
|
name: '',
|
phone: '',
|
gender: null,
|
birthDate: '',
|
education: '',
|
regionId: null,
|
projectName: '',
|
description: '',
|
introduction: '',
|
avatarUrl: '',
|
avatarMediaId: ''
|
},
|
|
// 表单验证
|
errors: {},
|
|
// 选择器数据
|
genderOptions: ['男', '女'],
|
genderIndex: -1,
|
educationOptions: ['高中', '大专', '本科', '硕士', '博士'],
|
educationIndex: -1,
|
regions: [],
|
regionIndex: -1,
|
today: new Date().toISOString().split('T')[0], // 今天的日期,用于限制生日选择
|
isSubmitting: false,
|
|
// 头像上传状态
|
avatarUploading: false,
|
avatarUploadProgress: 0,
|
|
// 本地头像临时文件
|
localAvatarPath: '', // 本地选择的头像文件路径,提交时才上传
|
|
// 附件上传
|
attachments: [], // 附件列表
|
maxAttachments: 8, // 最大附件数量
|
|
// 文件类型配置
|
fileTypeConfig: {
|
image: {
|
extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp'],
|
maxSize: 10 * 1024 * 1024, // 10MB
|
icon: '🖼️'
|
},
|
video: {
|
extensions: ['mp4', 'avi', 'mov', 'wmv', 'flv', '3gp'],
|
maxSize: 200 * 1024 * 1024, // 200MB
|
icon: '🎬'
|
},
|
pdf: {
|
extensions: ['pdf'],
|
maxSize: 50 * 1024 * 1024, // 50MB
|
icon: '📄'
|
},
|
word: {
|
extensions: ['doc', 'docx'],
|
maxSize: 50 * 1024 * 1024, // 50MB
|
icon: '📝'
|
},
|
excel: {
|
extensions: ['xls', 'xlsx'],
|
maxSize: 50 * 1024 * 1024, // 50MB
|
icon: '📊'
|
},
|
ppt: {
|
extensions: ['ppt', 'pptx'],
|
maxSize: 50 * 1024 * 1024, // 50MB
|
icon: '📽️'
|
},
|
text: {
|
extensions: ['txt'],
|
maxSize: 10 * 1024 * 1024, // 10MB
|
icon: '📄'
|
}
|
}
|
},
|
|
onLoad(options) {
|
console.log('📥 registration页面接收到的参数:', options)
|
if (options.activityId || options.id) {
|
const activityId = options.activityId || options.id
|
console.log('🎯 设置activityId:', activityId)
|
this.setData({
|
activityId: activityId
|
})
|
this.loadActivityInfo()
|
} else {
|
console.log('❌ 没有接收到activityId参数')
|
}
|
|
// 从全局数据获取用户信息预填充
|
this.prefillUserInfo()
|
|
// 加载区域数据
|
this.loadRegions()
|
},
|
|
// 加载活动信息
|
async loadActivityInfo() {
|
try {
|
this.setData({ loading: true })
|
|
const query = `
|
query GetActivity($id: ID!) {
|
activity(id: $id) {
|
id
|
name
|
description
|
signupDeadline
|
matchTime
|
address
|
playerMax
|
state
|
}
|
}
|
`
|
|
console.log('🔍 查询活动信息,activityId:', this.data.activityId)
|
const result = await graphqlRequest(query, { id: this.data.activityId })
|
console.log('📊 GraphQL查询结果:', result)
|
|
if (result && result.activity) {
|
console.log('✅ 活动信息加载成功:', result.activity)
|
this.setData({
|
activity: result.activity
|
})
|
|
// 根据活动要求初始化表单
|
this.initFormByRequirements()
|
} else {
|
// 活动不存在或查询失败
|
wx.showModal({
|
title: '提示',
|
content: '活动信息不存在或已失效',
|
showCancel: false,
|
success: () => {
|
wx.navigateBack()
|
}
|
})
|
}
|
} catch (error) {
|
console.error('加载活动信息失败:', error)
|
wx.showModal({
|
title: '网络错误',
|
content: '加载活动信息失败,请检查网络连接',
|
confirmText: '重试',
|
cancelText: '返回',
|
success: (res) => {
|
if (res.confirm) {
|
this.loadActivityInfo()
|
} else {
|
wx.navigateBack()
|
}
|
}
|
})
|
} finally {
|
this.setData({ loading: false })
|
}
|
},
|
|
// 加载区域数据
|
async loadRegions() {
|
try {
|
console.log('🔄 开始加载区域数据...')
|
const query = `
|
query {
|
allRegions {
|
id
|
name
|
pid
|
leafFlag
|
}
|
}
|
`
|
|
const result = await graphqlRequest(query)
|
console.log('📊 区域数据查询结果:', result)
|
|
if (result && result.allRegions) {
|
console.log(`📍 总区域数量: ${result.allRegions.length}`)
|
// 只显示leaf_flag=true的区域(叶子节点区域)
|
const leafRegions = result.allRegions.filter(region => region.leafFlag === true)
|
console.log(`🍃 叶子节点区域数量: ${leafRegions.length}`)
|
console.log('🍃 叶子节点区域列表:', leafRegions.map(r => `${r.name}(${r.id})`))
|
|
this.setData({
|
regions: leafRegions
|
})
|
console.log('✅ 区域数据设置完成')
|
} else {
|
console.warn('⚠️ 未获取到区域数据')
|
}
|
} catch (error) {
|
console.error('❌ 加载区域数据失败:', error)
|
// 区域数据加载失败不影响主要功能,只记录错误
|
}
|
},
|
|
// 预填充用户信息
|
prefillUserInfo() {
|
const userInfo = app.globalData.userInfo
|
if (userInfo) {
|
this.setData({
|
'formData.name': userInfo.name || '',
|
'formData.phone': userInfo.phone || '',
|
'formData.email': userInfo.email || ''
|
})
|
}
|
},
|
|
// 根据活动要求初始化表单
|
initFormByRequirements() {
|
const { activity } = this.data
|
if (!activity) return
|
|
// 基本表单验证规则初始化
|
const errors = {}
|
this.setData({ errors })
|
},
|
|
// 表单输入处理
|
onInputChange(e) {
|
const { field } = e.currentTarget.dataset
|
const { value } = e.detail
|
|
this.setData({
|
[`formData.${field}`]: value
|
})
|
|
// 清除该字段的错误状态
|
if (this.data.errors[field]) {
|
this.setData({
|
[`errors.${field}`]: false
|
})
|
}
|
|
// 实时验证
|
this.validateField(field, value)
|
},
|
|
// 性别选择
|
onGenderChange(e) {
|
const index = e.detail.value
|
this.setData({
|
genderIndex: index,
|
'formData.gender': index
|
})
|
},
|
|
// 学历选择
|
onEducationChange(e) {
|
const index = e.detail.value
|
this.setData({
|
educationIndex: index,
|
'formData.education': this.data.educationOptions[index]
|
})
|
},
|
|
// 区域选择
|
onRegionChange(e) {
|
const index = e.detail.value
|
const region = this.data.regions[index]
|
this.setData({
|
regionIndex: index,
|
'formData.regionId': region ? region.id : null
|
})
|
},
|
|
// 生日选择
|
onBirthDateChange(e) {
|
const birthDate = e.detail.value
|
this.setData({
|
'formData.birthDate': birthDate
|
})
|
|
// 清除该字段的错误状态
|
if (this.data.errors.birthDate) {
|
this.setData({
|
'errors.birthDate': false
|
})
|
}
|
},
|
|
// 获取手机号授权
|
async onGetPhoneNumber(e) {
|
console.log('获取手机号授权:', e.detail)
|
|
if (e.detail.errMsg === 'getPhoneNumber:ok') {
|
try {
|
console.log('=== 手机号获取调试信息 ===')
|
console.log('微信返回的code:', e.detail.code)
|
console.log('code长度:', e.detail.code ? e.detail.code.length : 0)
|
|
let phoneNumber = null
|
|
// 使用新版API直接通过code获取手机号
|
if (e.detail.code) {
|
console.log('🚀 使用新版API获取手机号')
|
console.log('code:', e.detail.code)
|
|
// 调用新版API直接通过code获取手机号
|
const response = await graphqlRequest(`
|
mutation GetPhoneNumberByCode($code: String!) {
|
getPhoneNumberByCode(code: $code) {
|
phoneNumber
|
purePhoneNumber
|
countryCode
|
}
|
}
|
`, {
|
code: e.detail.code
|
})
|
|
if (response.getPhoneNumberByCode) {
|
phoneNumber = response.getPhoneNumberByCode.phoneNumber
|
console.log('✅ 新版API获取手机号成功:', phoneNumber)
|
} else {
|
throw new Error('获取手机号失败,请重试')
|
}
|
} else {
|
throw new Error('缺少获取手机号所需的code参数')
|
}
|
|
if (phoneNumber) {
|
this.setData({
|
'formData.phone': phoneNumber
|
})
|
|
// 清除手机号错误状态
|
if (this.data.errors.phone) {
|
this.setData({
|
'errors.phone': false
|
})
|
}
|
|
console.log('✅ 手机号获取成功:', phoneNumber)
|
wx.showToast({
|
title: '手机号获取成功',
|
icon: 'success'
|
})
|
} else {
|
throw new Error('获取手机号失败')
|
}
|
} catch (error) {
|
console.error('获取手机号失败:', error)
|
wx.showToast({
|
title: '获取手机号失败',
|
icon: 'error'
|
})
|
}
|
} else {
|
console.log('用户拒绝授权手机号')
|
wx.showToast({
|
title: '需要手机号授权',
|
icon: 'none'
|
})
|
}
|
},
|
|
|
|
// 清除手机号
|
onClearPhone() {
|
this.setData({
|
'formData.phone': ''
|
})
|
},
|
|
// 选择头像(只做本地预览,不立即上传)
|
async onChooseAvatar() {
|
try {
|
const res = await wx.chooseMedia({
|
count: 1,
|
mediaType: ['image'],
|
sourceType: ['album', 'camera'],
|
sizeType: ['compressed']
|
})
|
|
if (res.tempFiles && res.tempFiles.length > 0) {
|
const tempFile = res.tempFiles[0]
|
|
// 检查文件类型 - 使用文件扩展名判断,因为iOS下fileType属性可能不存在
|
const getFileExtension = (filePath) => {
|
return filePath.split('.').pop().toLowerCase()
|
}
|
|
const fileExtension = getFileExtension(tempFile.tempFilePath)
|
const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp']
|
|
if (!allowedExtensions.includes(fileExtension)) {
|
wx.showToast({
|
title: '请选择JPG、PNG或WebP格式的图片',
|
icon: 'none',
|
duration: 3000
|
})
|
return
|
}
|
|
// 检查文件大小(限制为5MB)
|
if (tempFile.size > 5 * 1024 * 1024) {
|
wx.showToast({
|
title: '图片大小不能超过5MB',
|
icon: 'none',
|
duration: 3000
|
})
|
return
|
}
|
|
// 检查图片尺寸
|
try {
|
const imageInfo = await wx.getImageInfo({
|
src: tempFile.tempFilePath
|
})
|
|
// 建议最小尺寸为200x200
|
if (imageInfo.width < 200 || imageInfo.height < 200) {
|
const result = await wx.showModal({
|
title: '图片尺寸提示',
|
content: '建议上传尺寸不小于200x200的图片,当前图片尺寸为' + imageInfo.width + 'x' + imageInfo.height + ',是否继续?',
|
confirmText: '继续',
|
cancelText: '重新选择'
|
})
|
|
if (!result.confirm) {
|
return
|
}
|
}
|
} catch (imageError) {
|
console.warn('获取图片信息失败:', imageError)
|
}
|
|
// 只保存本地路径,用于预览,不立即上传
|
this.setData({
|
localAvatarPath: tempFile.tempFilePath
|
})
|
|
// 清除错误状态
|
if (this.data.errors.avatar) {
|
this.setData({
|
'errors.avatar': false
|
})
|
}
|
|
wx.showToast({
|
title: '头像选择成功,提交时将自动上传',
|
icon: 'success',
|
duration: 2000
|
})
|
}
|
} catch (error) {
|
console.error('头像选择失败:', error)
|
|
wx.showToast({
|
title: '头像选择失败,请重试',
|
icon: 'none',
|
duration: 3000
|
})
|
}
|
},
|
|
// 删除头像
|
async onDeleteAvatar() {
|
try {
|
const hasLocalAvatar = !!this.data.localAvatarPath
|
const hasUploadedAvatar = !!this.data.formData.avatarUrl
|
|
const result = await wx.showModal({
|
title: '删除头像',
|
content: hasLocalAvatar ? '确定要删除当前选择的头像吗?' : '确定要删除当前头像吗?删除后需要重新选择。',
|
confirmText: '删除',
|
confirmColor: '#ff4757',
|
cancelText: '取消'
|
})
|
|
if (result.confirm) {
|
// 如果是本地头像,直接清空
|
if (hasLocalAvatar) {
|
this.setData({
|
localAvatarPath: ''
|
})
|
|
wx.showToast({
|
title: '头像已删除',
|
icon: 'success'
|
})
|
return
|
}
|
|
// 如果是已上传的头像,需要删除服务器文件
|
if (hasUploadedAvatar) {
|
// 显示删除进度
|
wx.showLoading({
|
title: '正在删除...',
|
mask: true
|
})
|
|
// 如果有COS文件,尝试删除
|
if (this.data.formData.avatarMediaId) {
|
try {
|
await cosUtil.deleteFile(this.data.formData.avatarMediaId)
|
} catch (deleteError) {
|
console.warn('删除COS文件失败:', deleteError)
|
// 即使删除COS文件失败,也继续清空本地数据
|
}
|
}
|
|
// 清空头像数据
|
this.setData({
|
'formData.avatarUrl': '',
|
'formData.avatarMediaId': ''
|
})
|
|
wx.hideLoading()
|
wx.showToast({
|
title: '头像已删除',
|
icon: 'success'
|
})
|
}
|
}
|
} catch (error) {
|
console.error('删除头像失败:', error)
|
wx.hideLoading()
|
wx.showToast({
|
title: '删除失败,请重试',
|
icon: 'none',
|
duration: 2000
|
})
|
}
|
},
|
|
// 选择附件
|
async onChooseAttachment() {
|
try {
|
if (this.data.attachments.length >= this.data.maxAttachments) {
|
wx.showToast({
|
title: `最多只能上传${this.data.maxAttachments}个附件`,
|
icon: 'none'
|
})
|
return
|
}
|
|
const result = await wx.chooseMessageFile({
|
count: this.data.maxAttachments - this.data.attachments.length,
|
type: 'all'
|
})
|
|
if (result.tempFiles && result.tempFiles.length > 0) {
|
for (const file of result.tempFiles) {
|
await this.uploadAttachment(file)
|
}
|
}
|
} catch (error) {
|
console.error('选择附件失败:', error)
|
if (error.errMsg && !error.errMsg.includes('cancel')) {
|
wx.showToast({
|
title: '选择文件失败',
|
icon: 'none'
|
})
|
}
|
}
|
},
|
|
// 添加附件(不立即上传)
|
async uploadAttachment(file) {
|
try {
|
// 验证文件
|
const validation = this.validateAttachment(file)
|
if (!validation.valid) {
|
wx.showToast({
|
title: validation.message,
|
icon: 'none',
|
duration: 3000
|
})
|
return
|
}
|
|
// 创建附件对象(只保存本地信息,不上传)
|
const attachment = {
|
id: Date.now() + Math.random(),
|
name: file.name,
|
size: file.size,
|
sizeText: this.formatFileSize(file.size),
|
type: validation.type,
|
path: file.path,
|
uploading: false,
|
uploaded: false,
|
progress: 0,
|
error: null,
|
url: '',
|
mediaId: ''
|
}
|
|
// 添加到附件列表
|
const attachments = [...this.data.attachments, attachment]
|
this.setData({ attachments })
|
|
wx.showToast({
|
title: '文件已添加',
|
icon: 'success'
|
})
|
|
} catch (error) {
|
console.error('处理附件失败:', error)
|
wx.showToast({
|
title: '处理失败',
|
icon: 'error'
|
})
|
}
|
},
|
|
// 上传所有附件
|
async uploadAllAttachments() {
|
const attachments = this.data.attachments.filter(attachment => !attachment.uploaded)
|
|
if (attachments.length === 0) {
|
return // 没有需要上传的附件
|
}
|
|
wx.showLoading({
|
title: '正在上传附件...',
|
mask: true
|
})
|
|
try {
|
for (let i = 0; i < attachments.length; i++) {
|
const attachment = attachments[i]
|
|
// 更新上传状态
|
const updatedAttachments = this.data.attachments.map(item => {
|
if (item.id === attachment.id) {
|
return { ...item, uploading: true, progress: 0 }
|
}
|
return item
|
})
|
this.setData({ attachments: updatedAttachments })
|
|
try {
|
const uploadResult = await cosUtil.uploadFile(attachment.path, {
|
onProgress: (progress) => {
|
// 更新上传进度
|
const progressAttachments = this.data.attachments.map(item => {
|
if (item.id === attachment.id) {
|
return { ...item, progress: Math.round(progress.percent) }
|
}
|
return item
|
})
|
this.setData({ attachments: progressAttachments })
|
}
|
})
|
|
// 上传成功
|
const successAttachments = this.data.attachments.map(item => {
|
if (item.id === attachment.id) {
|
return {
|
...item,
|
uploading: false,
|
uploaded: true,
|
progress: 100,
|
url: uploadResult.url,
|
mediaId: uploadResult.key,
|
error: null
|
}
|
}
|
return item
|
})
|
this.setData({ attachments: successAttachments })
|
|
} catch (uploadError) {
|
console.error('上传附件失败:', uploadError)
|
|
// 更新错误状态
|
const errorAttachments = this.data.attachments.map(item => {
|
if (item.id === attachment.id) {
|
return {
|
...item,
|
uploading: false,
|
uploaded: false,
|
error: '上传失败'
|
}
|
}
|
return item
|
})
|
this.setData({ attachments: errorAttachments })
|
|
throw new Error(`附件 ${attachment.name} 上传失败`)
|
}
|
}
|
|
} finally {
|
wx.hideLoading()
|
}
|
},
|
|
// 删除附件
|
async onDeleteAttachment(e) {
|
try {
|
const index = e.currentTarget.dataset.index
|
const attachment = this.data.attachments[index]
|
|
const result = await wx.showModal({
|
title: '删除附件',
|
content: `确定要删除"${attachment.name}"吗?`,
|
confirmText: '删除',
|
confirmColor: '#ff4757',
|
cancelText: '取消'
|
})
|
|
if (result.confirm) {
|
wx.showLoading({
|
title: '正在删除...',
|
mask: true
|
})
|
|
// 如果有COS文件,尝试删除
|
if (attachment.mediaId) {
|
try {
|
await cosUtil.deleteFile(attachment.mediaId)
|
} catch (deleteError) {
|
console.warn('删除COS文件失败:', deleteError)
|
}
|
}
|
|
// 从列表中移除
|
const attachments = this.data.attachments.filter((_, i) => i !== index)
|
this.setData({ attachments })
|
|
wx.hideLoading()
|
wx.showToast({
|
title: '删除成功',
|
icon: 'success'
|
})
|
}
|
} catch (error) {
|
console.error('删除附件失败:', error)
|
wx.hideLoading()
|
wx.showToast({
|
title: '删除失败',
|
icon: 'error'
|
})
|
}
|
},
|
|
// 验证附件
|
validateAttachment(file) {
|
const fileName = file.name.toLowerCase()
|
const fileExtension = fileName.split('.').pop()
|
const fileSize = file.size
|
|
// 查找文件类型
|
let fileType = 'other'
|
let config = null
|
|
for (const [type, typeConfig] of Object.entries(this.data.fileTypeConfig)) {
|
if (typeConfig.extensions.includes(fileExtension)) {
|
fileType = type
|
config = typeConfig
|
break
|
}
|
}
|
|
if (!config) {
|
return {
|
valid: false,
|
message: `不支持的文件格式:${fileExtension.toUpperCase()}`
|
}
|
}
|
|
// 检查文件大小
|
if (fileSize > config.maxSize) {
|
return {
|
valid: false,
|
message: `文件过大,${fileType === 'video' ? '视频' : fileType === 'image' ? '图片' : '文档'}文件不能超过${this.formatFileSize(config.maxSize)}`
|
}
|
}
|
|
return {
|
valid: true,
|
type: fileType,
|
config: config
|
}
|
},
|
|
// 格式化文件大小
|
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(1)) + ' ' + sizes[i]
|
},
|
|
// 字段验证
|
validateField(field, value) {
|
let isValid = true
|
let errorMsg = ''
|
|
switch (field) {
|
case 'phone':
|
const phoneReg = /^1[3-9]\d{9}$/
|
if (value && !phoneReg.test(value)) {
|
isValid = false
|
errorMsg = '请输入正确的手机号'
|
}
|
break
|
case 'avatar':
|
// 如果活动要求头像,则验证头像是否已上传
|
if (this.data.activity && this.data.activity.requireAvatar) {
|
if (!this.data.formData.avatarUrl || !this.data.formData.avatarMediaId) {
|
isValid = false
|
errorMsg = '请上传头像'
|
}
|
}
|
break
|
case 'email':
|
const emailReg = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
if (value && !emailReg.test(value)) {
|
isValid = false
|
errorMsg = '请输入正确的邮箱地址'
|
}
|
break
|
case 'idCard':
|
const idCardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/
|
if (value && !idCardReg.test(value)) {
|
isValid = false
|
errorMsg = '请输入正确的身份证号'
|
}
|
break
|
}
|
|
if (!isValid) {
|
this.setData({
|
[`errors.${field}`]: errorMsg
|
})
|
}
|
|
return isValid
|
},
|
|
|
|
// 表单验证
|
validateForm() {
|
const { formData } = this.data;
|
const errors = {};
|
|
// 必填字段验证
|
if (!formData.name.trim()) {
|
errors.name = '请输入姓名';
|
}
|
|
if (!formData.phone.trim()) {
|
errors.phone = '请输入手机号';
|
} else if (!/^1[3-9]\d{9}$/.test(formData.phone)) {
|
errors.phone = '请输入正确的手机号';
|
}
|
|
if (formData.gender === null) {
|
errors.gender = '请选择性别';
|
}
|
|
// 区域验证(可选)
|
// 暂时不强制要求区域选择
|
|
// 头像验证(可选)
|
// 暂时不强制要求头像上传
|
|
if (!formData.projectName.trim()) {
|
errors.projectName = '请输入项目名称';
|
}
|
|
if (!formData.description.trim()) {
|
errors.description = '请输入项目描述';
|
}
|
|
this.setData({ errors });
|
return Object.keys(errors).length === 0;
|
},
|
|
// 提交前上传头像
|
async uploadAvatarBeforeSubmit() {
|
if (!this.data.localAvatarPath) {
|
return
|
}
|
|
try {
|
// 显示上传进度
|
this.setData({
|
avatarUploading: true,
|
avatarUploadProgress: 0
|
})
|
|
// 上传到COS
|
const uploadResult = await cosUtil.uploadAvatar(this.data.localAvatarPath, {
|
onProgress: (progress) => {
|
this.setData({
|
avatarUploadProgress: Math.round(progress.percent)
|
})
|
}
|
})
|
|
// 上传成功,更新表单数据
|
this.setData({
|
'formData.avatarUrl': uploadResult.url,
|
'formData.avatarMediaId': uploadResult.key,
|
localAvatarPath: '', // 清空本地路径
|
avatarUploading: false,
|
avatarUploadProgress: 0
|
})
|
|
console.log('头像上传成功:', uploadResult)
|
|
} catch (error) {
|
this.setData({
|
avatarUploading: false,
|
avatarUploadProgress: 0
|
})
|
|
console.error('头像上传失败:', error)
|
|
// 根据错误类型显示不同的提示
|
let errorMessage = '头像上传失败'
|
if (error.message) {
|
if (error.message.includes('网络')) {
|
errorMessage = '网络连接失败,请检查网络后重试'
|
} else if (error.message.includes('权限')) {
|
errorMessage = '上传权限不足,请联系管理员'
|
} else if (error.message.includes('空间')) {
|
errorMessage = '存储空间不足,请稍后重试'
|
}
|
}
|
|
throw new Error(errorMessage)
|
}
|
},
|
|
async onSubmit() {
|
if (this.data.isSubmitting) return
|
|
// 表单验证
|
if (!this.validateForm()) {
|
wx.showToast({
|
title: '请检查表单信息',
|
icon: 'none'
|
})
|
return
|
}
|
|
this.setData({ isSubmitting: true })
|
|
try {
|
const { formData } = this.data
|
|
// 使用页面参数中的activityId,而不是从activity对象中获取
|
const activityId = this.data.activityId
|
|
// 准备提交数据(不包含文件)
|
const submitData = {
|
activityId,
|
playerInfo: {
|
name: formData.name,
|
phone: formData.phone,
|
gender: formData.gender,
|
birthDate: formData.birthDate,
|
education: formData.education,
|
introduction: formData.introduction,
|
avatarMediaId: null // 先不传头像
|
},
|
regionId: formData.regionId,
|
projectName: formData.projectName,
|
description: formData.description
|
}
|
|
// 第一步:先提交注册数据到后台,获得注册ID
|
const result = await this.submitRegistration(submitData)
|
|
if (result.success && result.registrationId) {
|
// 第二步:使用返回的ID信息上传头像和附件
|
await this.uploadFilesAfterRegistration({
|
registrationId: result.registrationId,
|
playerId: result.playerId,
|
userId: result.userId,
|
activityPlayerId: result.activityPlayerId
|
})
|
|
wx.showToast({
|
title: '报名成功',
|
icon: 'success'
|
})
|
|
setTimeout(() => {
|
wx.navigateBack()
|
}, 1500)
|
} else {
|
throw new Error(result.message || '提交失败')
|
}
|
|
} catch (error) {
|
console.error('提交失败:', error)
|
wx.showToast({
|
title: error.message || '提交失败,请重试',
|
icon: 'none'
|
})
|
} finally {
|
this.setData({ isSubmitting: false })
|
}
|
},
|
|
// 提交报名数据到后端(不包含文件)
|
async submitRegistration(submitData) {
|
const mutation = `
|
mutation SubmitActivityRegistration($input: ActivityRegistrationInput!) {
|
submitActivityRegistration(input: $input) {
|
success
|
message
|
registrationId
|
playerId
|
userId
|
activityPlayerId
|
}
|
}
|
`;
|
|
const input = {
|
activityId: parseInt(submitData.activityId),
|
playerInfo: {
|
name: submitData.playerInfo.name,
|
phone: submitData.playerInfo.phone,
|
gender: submitData.playerInfo.gender || 0,
|
birthDate: submitData.playerInfo.birthDate || null,
|
education: submitData.playerInfo.education || '',
|
introduction: submitData.playerInfo.introduction || '',
|
avatarMediaId: null // 先不传头像
|
},
|
regionId: submitData.regionId || null,
|
projectName: submitData.projectName || '',
|
description: submitData.description || '',
|
attachmentMediaIds: [] // 先不传附件
|
};
|
|
const result = await graphqlRequest(mutation, { input });
|
|
if (result && result.submitActivityRegistration) {
|
return result.submitActivityRegistration;
|
} else {
|
throw new Error('提交失败');
|
}
|
},
|
|
// 注册成功后上传文件
|
async uploadFilesAfterRegistration(idInfo) {
|
try {
|
// 上传头像(如果有)
|
if (this.data.localAvatarPath) {
|
await this.uploadAvatarWithRegistrationId(idInfo)
|
}
|
|
// 上传附件(如果有)
|
if (this.data.attachments.length > 0) {
|
await this.uploadAttachmentsWithRegistrationId(idInfo)
|
}
|
} catch (error) {
|
console.error('文件上传失败:', error)
|
// 文件上传失败不影响注册成功,只是提示用户
|
wx.showToast({
|
title: '文件上传失败,但报名已成功',
|
icon: 'none',
|
duration: 3000
|
})
|
}
|
},
|
|
// 使用注册ID上传头像
|
async uploadAvatarWithRegistrationId(idInfo) {
|
try {
|
this.setData({
|
avatarUploading: true,
|
avatarUploadProgress: 0
|
})
|
|
// 第一步:上传到COS
|
const uploadResult = await cosUtil.uploadAvatar(this.data.localAvatarPath, 'avatar.jpg', (progress) => {
|
this.setData({
|
avatarUploadProgress: Math.round(progress.percent)
|
})
|
})
|
|
// 第二步:保存媒体记录到数据库
|
await this.saveMediaRecord({
|
targetType: 7, // USER_AVATAR
|
targetId: idInfo.userId,
|
url: uploadResult.url,
|
fileName: uploadResult.fileName || 'avatar.jpg',
|
fileSize: uploadResult.fileSize,
|
mediaType: 1 // 图片
|
})
|
|
this.setData({
|
avatarUploading: false,
|
avatarUploadProgress: 0
|
})
|
|
console.log('头像上传成功:', uploadResult)
|
} catch (error) {
|
this.setData({
|
avatarUploading: false,
|
avatarUploadProgress: 0
|
})
|
console.error('头像上传失败:', error)
|
throw error
|
}
|
},
|
|
// 使用注册ID上传附件
|
async uploadAttachmentsWithRegistrationId(idInfo) {
|
for (let i = 0; i < this.data.attachments.length; i++) {
|
const attachment = this.data.attachments[i]
|
if (!attachment.uploaded && attachment.localPath) {
|
try {
|
// 第一步:上传到COS
|
const uploadResult = await cosUtil.uploadFile(attachment.localPath, 'attachment', attachment.name || 'attachment', (progress) => {
|
this.setData({
|
[`attachments[${i}].uploadProgress`]: Math.round(progress.percent)
|
})
|
})
|
|
// 第二步:保存媒体记录到数据库
|
await this.saveMediaRecord({
|
targetType: 5, // ACTIVITY_PLAYER_SUBMISSION
|
targetId: idInfo.activityPlayerId,
|
url: uploadResult.url,
|
fileName: uploadResult.fileName || attachment.name,
|
fileSize: uploadResult.fileSize,
|
mediaType: this.getMediaType(attachment.name) // 根据文件扩展名判断类型
|
})
|
|
// 更新附件状态
|
this.setData({
|
[`attachments[${i}].uploaded`]: true,
|
[`attachments[${i}].mediaId`]: uploadResult.key,
|
[`attachments[${i}].url`]: uploadResult.url,
|
[`attachments[${i}].uploadProgress`]: 0
|
})
|
|
console.log(`附件${i + 1}上传成功:`, uploadResult)
|
} catch (error) {
|
console.error(`附件${i + 1}上传失败:`, error)
|
throw error
|
}
|
}
|
}
|
},
|
|
// 保存媒体记录到数据库
|
async saveMediaRecord(mediaData) {
|
const mutation = `
|
mutation SaveMedia($input: MediaInput!) {
|
saveMedia(input: $input) {
|
id
|
url
|
fileName
|
}
|
}
|
`
|
|
const variables = {
|
input: {
|
targetType: mediaData.targetType,
|
targetId: mediaData.targetId,
|
url: mediaData.url,
|
fileName: mediaData.fileName,
|
fileSize: mediaData.fileSize,
|
mediaType: mediaData.mediaType
|
}
|
}
|
|
try {
|
const result = await app.graphqlRequest(mutation, variables)
|
console.log('媒体记录保存成功:', result.saveMedia)
|
return result.saveMedia
|
} catch (error) {
|
console.error('媒体记录保存失败:', error)
|
throw error
|
}
|
},
|
|
// 根据文件名获取媒体类型
|
getMediaType(fileName) {
|
if (!fileName) return 1 // 默认图片
|
|
const ext = fileName.toLowerCase().split('.').pop()
|
const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']
|
const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv']
|
const audioExts = ['mp3', 'wav', 'aac', 'flac', 'ogg']
|
const docExts = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']
|
|
if (imageExts.includes(ext)) return 1 // 图片
|
if (videoExts.includes(ext)) return 2 // 视频
|
if (audioExts.includes(ext)) return 3 // 音频
|
if (docExts.includes(ext)) return 4 // 文档
|
|
return 5 // 其他
|
}
|
|
})
|