import { View, Text, Button, Image, Input, Textarea, Picker } from '@tarojs/components' import Taro, { useLoad, useShareAppMessage, useShareTimeline, useRouter } from '@tarojs/taro' import { useState } from 'react' import { getProjectDetail, createProject, updateProject, uploadProjectFile, submitProject, uploadMedia, getCompetitions } from '../../api' import './project.scss' export default function ProjectEdit() { const [project, setProject] = useState({ title: '', description: '', team_info: '', files: [] }) const [competitionId, setCompetitionId] = useState('') const [competitions, setCompetitions] = useState([]) const [loading, setLoading] = useState(false) const [isEdit, setIsEdit] = useState(false) const router = useRouter() useLoad((options) => { fetchCompetitions() const { id, competitionId } = options if (id) { setIsEdit(true) fetchProject(id) } else if (competitionId) { setCompetitionId(competitionId) } }) /** * 配置并监听分享给朋友的功能 */ useShareAppMessage(() => { const id = project?.id || router.params.id || '' const compId = competitionId || router.params.competitionId || '' return { title: project?.title || '提交作品', path: `/pages/competition/project?id=${id}&competitionId=${compId}`, imageUrl: project?.cover_image_url || project?.display_cover_image || '' } }) /** * 配置并监听分享到朋友圈的功能 */ useShareTimeline(() => { const id = project?.id || router.params.id || '' const compId = competitionId || router.params.competitionId || '' return { title: project?.title || '提交作品', query: `id=${id}&competitionId=${compId}`, imageUrl: project?.cover_image_url || project?.display_cover_image || '' } }) const fetchCompetitions = async () => { try { const res = await getCompetitions() if (res && res.results) { setCompetitions(res.results) } } catch (e) { console.error('获取比赛列表失败', e) } } const fetchProject = async (id) => { setLoading(true) try { const res = await getProjectDetail(id) setProject(res) setCompetitionId(res.competition) } catch (e) { Taro.showToast({ title: '加载项目失败', icon: 'none' }) } finally { setLoading(false) } } const handleInput = (key, value) => { setProject(prev => ({ ...prev, [key]: value })) } const handleUploadCover = async () => { try { const { tempFilePaths } = await Taro.chooseImage({ count: 1 }) if (!tempFilePaths.length) return Taro.showLoading({ title: '上传中...' }) const res = await uploadMedia(tempFilePaths[0], 'image') handleInput('cover_image_url', res.file) // 假设返回 { file: 'url...' } Taro.hideLoading() } catch (e) { Taro.hideLoading() Taro.showToast({ title: '上传失败', icon: 'none' }) } } const handleUploadFile = async () => { if (!project.id) { Taro.showToast({ title: '请先保存草稿再上传附件', icon: 'none' }) return } try { const res = await Taro.chooseMessageFile({ count: 1, type: 'file' }) const tempFiles = res.tempFiles if (!tempFiles.length) return Taro.showLoading({ title: '上传中...' }) const file = tempFiles[0] // @ts-ignore const result = await uploadProjectFile(file.path, project.id, file.name) // Update file list setProject(prev => ({ ...prev, files: [...(prev.files || []), result] })) Taro.hideLoading() Taro.showToast({ title: '上传成功', icon: 'success' }) } catch (e) { Taro.hideLoading() console.error(e) Taro.showToast({ title: '上传失败', icon: 'none' }) } } const handleDeleteFile = (fileId) => { // API call to delete file not implemented yet? Or just remove from list? // Usually we should call delete API. For now just remove from UI. // Ideally we should have deleteProjectFile API. // But user only asked to "optimize upload". setProject(prev => ({ ...prev, files: prev.files.filter(f => f.id !== fileId) })) } const handleSave = async (submit = false) => { if (!project.title) { Taro.showToast({ title: '请输入项目标题', icon: 'none' }) return } setLoading(true) try { const data = { competition: competitionId, title: project.title, description: project.description, team_info: project.team_info, cover_image_url: project.cover_image_url } let res if (isEdit) { res = await updateProject(project.id, data) } else { res = await createProject(data) } if (submit) { await submitProject(res.id) Taro.showToast({ title: '提交成功', icon: 'success' }) setTimeout(() => Taro.navigateBack(), 1500) } else { Taro.showToast({ title: '保存成功', icon: 'success' }) if (!isEdit) { // 创建变编辑 setIsEdit(true) setProject(res) } } } catch (e) { Taro.showToast({ title: e.message || '操作失败', icon: 'none' }) } finally { setLoading(false) } } if (loading && !project.id && isEdit) return 加载中... return ( 所属比赛 { const idx = Number(e.detail.value) const selected = competitions[idx] if (selected) { setCompetitionId(String(selected.id)) } }} > {competitions.find(c => String(c.id) === String(competitionId))?.title || '请选择比赛'} 项目标题 handleInput('title', e.detail.value)} /> 封面图 {project.cover_image_url || project.display_cover_image ? ( ) : ( 点击上传封面 )} 项目介绍