界面如下

代码如下
<template><view class="puzzle-container"><view class="puzzle-title">任务进度 {{completedCount}}/{{totalPieces}}</view><view class="puzzle-grid"><viewv-for="(piece, index) in puzzlePieces":key="index"class="puzzle-piece":class="{'unlocked': piece.unlocked,'locked': !piece.unlocked,'unlock-animation': animatingIndex === index}"@click="onPieceTap(index)"><imagev-if="piece.unlocked":src="piece.imageUrl"mode="aspectFill"class="piece-image"></image><imagev-elsesrc="@/static/images/form/close-image.png"class="lock-icon"></image><text class="piece-number">{{index + 1}}</text><view class="particle-container" v-if="animatingIndex === index"><viewclass="particle"v-for="particle in particles":key="particle.id":style="{left: particle.left + '%',top: particle.top + '%',backgroundColor: particle.color}"></view></view></view></view><uni-popup ref="completePopup" type="center"><view class="celebration-popup"><image src="/static/celebration.png" mode="widthFix"></image><text class="celebration-text">恭喜完成所有任务!</text><button @click="viewCompletePuzzle">查看完整拼图</button></view></uni-popup></view>
</template><script>
export default {data() {return {totalPieces: 20,puzzlePieces: [],completedCount: 0,animatingIndex: -1,particles: [],allCompleted: false}},created() {this.initPuzzle();},methods: {initPuzzle() {this.puzzlePieces = Array(this.totalPieces).fill().map((_, index) => ({index,unlocked: false,imageUrl: `../../static/pt/pt${index + 1}.png`}));this.unlockPiece(0);this.unlockPiece(1);this.unlockPiece(2);this.unlockPiece(3);this.unlockPiece(4);this.completedCount = 5;},unlockPiece(index) {if (index >= this.totalPieces || this.puzzlePieces[index].unlocked) return;this.$set(this.puzzlePieces, index, {...this.puzzlePieces[index],unlocked: true});this.animatingIndex = index;this.completedCount++;this.createParticles();if (this.completedCount === this.totalPieces) {this.allCompleted = true;setTimeout(() => {this.$refs.completePopup.open();}, 1000);}setTimeout(() => {this.animatingIndex = -1;}, 1000);},createParticles() {this.particles = [];const particles = [];for (let i = 0; i < 12; i++) {particles.push({id: i,left: Math.random() * 60 + 20,top: Math.random() * 60 + 20,color: `hsl(${Math.random() * 360}, 100%, 50%)`,'--tx': Math.random() * 100,'--ty': Math.random() * 100});}this.particles = particles;setTimeout(() => {this.particles = [];}, 1000);},onPieceTap(index) {if (!this.puzzlePieces[index].unlocked) {uni.showToast({title: `完成任务${index + 1}后解锁`,icon: 'none'});}},completeRandomTask() {const firstLockedIndex = this.puzzlePieces.findIndex(p => !p.unlocked);if (firstLockedIndex !== -1) {this.unlockPiece(firstLockedIndex);} else {uni.showToast({title: '所有拼图已解锁!',icon: 'success'});}},viewCompletePuzzle() {this.$refs.completePopup.close();uni.navigateTo({url: '/pages/puzzle-preview/puzzle-preview'});}}
}
</script><style lang="scss" scoped>
.puzzle-container {padding: 20rpx;box-sizing: border-box;
}.puzzle-title {text-align: center;font-size: 36rpx;margin-bottom: 30rpx;color: #333;
}.puzzle-grid {display: grid;grid-template-columns: repeat(5, 1fr); gap: 10rpx;
}.puzzle-piece {position: relative;aspect-ratio: 1; border-radius: 10rpx;overflow: hidden;display: flex;justify-content: center;align-items: center;background-color: #f5f5f5;&.unlocked {box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);}.piece-image, .lock-icon {width: 100%;height: 100%;}.lock-icon {width: 60% !important;height: 60% !important;opacity: 0.6;}.piece-number {position: absolute;bottom: 8rpx;right: 8rpx;font-size: 24rpx;color: #999;background-color: rgba(255, 255, 255, 0.7);border-radius: 50%;width: 36rpx;height: 36rpx;display: flex;justify-content: center;align-items: center;}
}
.unlock-animation {animation: unlockScale 0.6s ease-out;
}@keyframes unlockScale {0% { transform: scale(0.8); opacity: 0; }50% { transform: scale(1.1); }100% { transform: scale(1); opacity: 1; }
}
.particle-container {position: absolute;width: 100%;height: 100%;pointer-events: none;
}.particle {position: absolute;width: 10rpx;height: 10rpx;border-radius: 50%;animation: particleFly 1s ease-out forwards;
}@keyframes particleFly {to {transform: translate(calc((var(--tx, 0) - 50) * 1rpx),calc((var(--ty, 0) - 50) * 1rpx));opacity: 0;}
}
.celebration-popup {background: white;padding: 40rpx;border-radius: 20rpx;display: flex;flex-direction: column;align-items: center;image {width: 200rpx;margin-bottom: 20rpx;}.celebration-text {font-size: 36rpx;margin-bottom: 30rpx;color: #ff6b81;font-weight: bold;}button {background: #ff6b81;color: white;border: none;}
}
</style>