| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- <template>
- <view class="fun-task-item" :class="{ completed: task.status === 'completed', urgent: isUrgent }">
- <view class="task-icon">{{ getCategoryIcon() }}</view>
- <view class="task-content">
- <view class="task-title">{{ task.title }}</view>
- <view class="task-meta">
- <text class="points-badge">+{{ task.points }}分</text>
- <text class="deadline">{{ getTimeLeft() }}</text>
- </view>
- </view>
- <view class="task-action">
- <button v-if="task.status === 'pending'" class="complete-btn" @click="$emit('complete')">
- <text class="btn-icon">✨</text>
- <text>完成</text>
- </button>
- <view v-else class="completed-badge">
- <text class="check-icon">✅</text>
- <text>已完成</text>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- name: 'FunTaskItem',
- props: {
- task: { type: Object, required: true }
- },
- computed: {
- isUrgent() {
- if (this.task.status === 'completed') return false
- if (!this.task.deadline) return false
- const deadline = new Date(this.task.deadline)
- const now = new Date()
- const hoursLeft = (deadline - now) / (1000 * 60 * 60)
- return hoursLeft < 2
- }
- },
- methods: {
- getCategoryIcon() {
- const icons = {
- '学习类': '📚',
- '生活类': '🏠',
- '运动类': '⚽',
- '其他': '⭐'
- }
- return icons[this.task.category] || '📝'
- },
- getTimeLeft() {
- if (!this.task.deadline) return ''
- const deadline = new Date(this.task.deadline)
- const now = new Date()
- const diff = deadline - now
- if (diff < 0) return '已超时'
- const hours = Math.floor(diff / (1000 * 60 * 60))
- const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))
- if (hours > 24) {
- const days = Math.floor(hours / 24)
- return `${days}天后`
- }
- if (hours > 0) return `${hours}小时后`
- return `${minutes}分钟后`
- }
- }
- }
- </script>
- <style scoped>
- .fun-task-item {
- display: flex;
- align-items: center;
- background: var(--surface, #ffffff);
- border-radius: var(--radius-md, 20rpx);
- padding: 24rpx;
- margin-bottom: 20rpx;
- border: 2rpx solid var(--border, #FED7AA);
- box-shadow: var(--shadow-sm);
- transition: transform 0.15s ease;
- }
- .fun-task-item:active { transform: scale(0.98); }
- .fun-task-item.completed { opacity: 0.65; background: #FEF2F2; border-color: #FECACA; }
- .fun-task-item.urgent { border: 2rpx solid var(--color-error, #EF4444); animation: pulse-urgent 1.5s infinite; }
- @keyframes pulse-urgent { 0%, 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0.3); } 50% { box-shadow: 0 0 0 12rpx rgba(239,68,68,0); } }
- .task-icon { font-size: 44rpx; width: 72rpx; height: 72rpx; background: rgba(249,115,22,0.1); border-radius: 16rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; }
- .task-content { flex: 1; }
- .task-title { font-size: 28rpx; font-weight: 600; color: var(--text, #3D2E1E); margin-bottom: 8rpx; }
- .task-meta { display: flex; align-items: center; gap: 16rpx; }
- .points-badge { background: linear-gradient(135deg, #FEF3C7, #FDE68A); color: #92400E; font-size: 22rpx; padding: 4rpx 14rpx; border-radius: 20rpx; font-weight: 700; }
- .deadline { font-size: 22rpx; color: var(--muted, #94A3B8); }
- .task-action { margin-left: 16rpx; }
- .complete-btn { display: flex; align-items: center; background: linear-gradient(135deg, var(--color-primary, #F97316), #FB923C); color: #fff; border: none; border-radius: 30rpx; padding: 14rpx 28rpx; font-size: 24rpx; font-weight: 600; box-shadow: 0 4rpx 8rpx rgba(249,115,22,0.3); }
- .complete-btn:active { transform: scale(0.95); opacity: 0.9; }
- .btn-icon { margin-right: 6rpx; }
- .completed-badge { display: flex; align-items: center; background: rgba(34,197,94,0.1); color: var(--color-success, #22C55E); padding: 12rpx 20rpx; border-radius: 30rpx; font-size: 24rpx; font-weight: 600; }
- .check-icon { margin-right: 6rpx; }
- </style>
|