|
@@ -39,54 +39,17 @@
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<view class="card-detail-row" v-if="challenge.durationDays">
|
|
<view class="card-detail-row" v-if="challenge.durationDays">
|
|
|
- <text class="detail-label">⏱ 期限</text>
|
|
|
|
|
- <text class="detail-val">{{ challenge.durationDays }}天</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="card-detail-row" v-if="challenge.endDate">
|
|
|
|
|
- <text class="detail-label">📅 截止</text>
|
|
|
|
|
- <text class="detail-val">{{ formatDate(challenge.endDate) }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="card-detail-row" v-if="challenge.rewardPoints">
|
|
|
|
|
- <text class="detail-label">🏆 奖励</text>
|
|
|
|
|
- <text class="detail-val reward">+{{ challenge.rewardPoints }}分</text>
|
|
|
|
|
- <text class="detail-val badge" v-if="challenge.rewardBadge"> 🎖️ {{ challenge.rewardBadge }}</text>
|
|
|
|
|
- </view>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 打卡上报入口(active 挑战 + 有 childId) -->
|
|
|
|
|
- <view class="checkin-section" v-if="challenge.status === 'active'">
|
|
|
|
|
- <template v-if="!showInput">
|
|
|
|
|
- <view class="checkin-btn" @click="openInput">
|
|
|
|
|
- <text class="checkin-btn-text">上报进度</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </template>
|
|
|
|
|
- <template v-else>
|
|
|
|
|
- <view class="checkin-form">
|
|
|
|
|
- <input class="checkin-input" type="number" v-model="deltaValue" placeholder="输入本次数量" />
|
|
|
|
|
- <view class="checkin-submit" @click="submitProgress">
|
|
|
|
|
- <text class="checkin-btn-text">确认</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- <view class="checkin-cancel" @click="closeInput">
|
|
|
|
|
- <text class="checkin-cancel-text">取消</text>
|
|
|
|
|
- </view>
|
|
|
|
|
- </view>
|
|
|
|
|
- </template>
|
|
|
|
|
|
|
+ <text class="detail-label">⏱ {{ challenge.durationDays }}天</text>
|
|
|
|
|
+ <text class="detail-label" v-if="challenge.endDate">· 截止 {{ formatDate(challenge.endDate) }}</text>
|
|
|
|
|
+ <text class="detail-label reward" v-if="challenge.rewardPoints">· 🏆 +{{ challenge.rewardPoints }}分</text>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import { updateChallengeProgress } from '@/utils/api.js'
|
|
|
|
|
-
|
|
|
|
|
export default {
|
|
export default {
|
|
|
props: {
|
|
props: {
|
|
|
- challenge: { type: Object, default: null },
|
|
|
|
|
- childId: { type: Number, default: null }
|
|
|
|
|
- },
|
|
|
|
|
- data: function() {
|
|
|
|
|
- return {
|
|
|
|
|
- showInput: false,
|
|
|
|
|
- deltaValue: ''
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ challenge: { type: Object, default: null }
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|
|
|
statusClass: function() {
|
|
statusClass: function() {
|
|
@@ -119,39 +82,6 @@ export default {
|
|
|
if (target <= 0) return 0
|
|
if (target <= 0) return 0
|
|
|
var p = Math.round((value || 0) / target * 100)
|
|
var p = Math.round((value || 0) / target * 100)
|
|
|
return Math.min(p, 100)
|
|
return Math.min(p, 100)
|
|
|
- },
|
|
|
|
|
- openInput: function() {
|
|
|
|
|
- this.deltaValue = ''
|
|
|
|
|
- this.showInput = true
|
|
|
|
|
- },
|
|
|
|
|
- closeInput: function() {
|
|
|
|
|
- this.showInput = false
|
|
|
|
|
- this.deltaValue = ''
|
|
|
|
|
- },
|
|
|
|
|
- submitProgress: function() {
|
|
|
|
|
- var delta = parseInt(this.deltaValue, 10)
|
|
|
|
|
- if (!delta || delta <= 0) {
|
|
|
|
|
- uni.showToast({ title: '请输入本次数量', icon: 'none' })
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- if (!this.childId) {
|
|
|
|
|
- uni.showToast({ title: '请先选择家庭成员', icon: 'none' })
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
- var self = this
|
|
|
|
|
- updateChallengeProgress({
|
|
|
|
|
- challengeId: this.challenge.id,
|
|
|
|
|
- childId: this.childId,
|
|
|
|
|
- delta: delta
|
|
|
|
|
- }).then(function(res) {
|
|
|
|
|
- if (res.code === 200) {
|
|
|
|
|
- uni.showToast({ title: '上报成功!', icon: 'none' })
|
|
|
|
|
- self.closeInput()
|
|
|
|
|
- self.$emit('updated')
|
|
|
|
|
- }
|
|
|
|
|
- }).catch(function() {
|
|
|
|
|
- // api.js 拦截器已提示
|
|
|
|
|
- })
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -160,9 +90,9 @@ export default {
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
.challenge-card {
|
|
.challenge-card {
|
|
|
background: #fff;
|
|
background: #fff;
|
|
|
- border-radius: 20rpx;
|
|
|
|
|
- margin: 0 20rpx 20rpx 20rpx;
|
|
|
|
|
- padding: 24rpx;
|
|
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ margin: 0 20rpx 12rpx 20rpx;
|
|
|
|
|
+ padding: 14rpx 16rpx;
|
|
|
border-left: 6rpx solid #10B981;
|
|
border-left: 6rpx solid #10B981;
|
|
|
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
|
|
|
}
|
|
}
|
|
@@ -170,53 +100,53 @@ export default {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- margin-bottom: 8rpx;
|
|
|
|
|
|
|
+ margin-bottom: 4rpx;
|
|
|
}
|
|
}
|
|
|
.card-title {
|
|
.card-title {
|
|
|
- font-size: 28rpx;
|
|
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
font-weight: 700;
|
|
font-weight: 700;
|
|
|
color: #1E293B;
|
|
color: #1E293B;
|
|
|
}
|
|
}
|
|
|
.card-status {
|
|
.card-status {
|
|
|
- font-size: 22rpx;
|
|
|
|
|
- padding: 4rpx 12rpx;
|
|
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
|
|
+ padding: 2rpx 10rpx;
|
|
|
border-radius: 999rpx;
|
|
border-radius: 999rpx;
|
|
|
}
|
|
}
|
|
|
.status-active { background: #DCFCE7; color: #16A34A; }
|
|
.status-active { background: #DCFCE7; color: #16A34A; }
|
|
|
.status-completed { background: #F1F5F9; color: #64748B; }
|
|
.status-completed { background: #F1F5F9; color: #64748B; }
|
|
|
.card-desc {
|
|
.card-desc {
|
|
|
- font-size: 24rpx;
|
|
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
color: #64748B;
|
|
color: #64748B;
|
|
|
- line-height: 1.5;
|
|
|
|
|
- margin-bottom: 12rpx;
|
|
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ margin-bottom: 8rpx;
|
|
|
display: block;
|
|
display: block;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* 目标区 */
|
|
/* 目标区 */
|
|
|
.target-section {
|
|
.target-section {
|
|
|
background: #F8FAFC;
|
|
background: #F8FAFC;
|
|
|
- border-radius: 12rpx;
|
|
|
|
|
- padding: 16rpx;
|
|
|
|
|
- margin-bottom: 8rpx;
|
|
|
|
|
|
|
+ border-radius: 10rpx;
|
|
|
|
|
+ padding: 10rpx 12rpx;
|
|
|
|
|
+ margin-bottom: 6rpx;
|
|
|
}
|
|
}
|
|
|
.target-header {
|
|
.target-header {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- margin-bottom: 10rpx;
|
|
|
|
|
|
|
+ margin-bottom: 6rpx;
|
|
|
}
|
|
}
|
|
|
-.target-label { font-size: 24rpx; color: #475569; font-weight: 600; }
|
|
|
|
|
-.target-value { font-size: 28rpx; color: #10B981; font-weight: 700; }
|
|
|
|
|
|
|
+.target-label { font-size: 22rpx; color: #475569; font-weight: 600; }
|
|
|
|
|
+.target-value { font-size: 26rpx; color: #10B981; font-weight: 700; }
|
|
|
|
|
|
|
|
.card-progress {
|
|
.card-progress {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- gap: 12rpx;
|
|
|
|
|
- margin-top: 4rpx;
|
|
|
|
|
|
|
+ gap: 10rpx;
|
|
|
|
|
+ margin-top: 2rpx;
|
|
|
}
|
|
}
|
|
|
.progress-bar-bg {
|
|
.progress-bar-bg {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
- height: 12rpx;
|
|
|
|
|
|
|
+ height: 10rpx;
|
|
|
background: #E2E8F0;
|
|
background: #E2E8F0;
|
|
|
border-radius: 999rpx;
|
|
border-radius: 999rpx;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
@@ -228,25 +158,25 @@ export default {
|
|
|
transition: width 0.5s ease;
|
|
transition: width 0.5s ease;
|
|
|
}
|
|
}
|
|
|
.progress-text {
|
|
.progress-text {
|
|
|
- font-size: 22rpx;
|
|
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
color: #10B981;
|
|
color: #10B981;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
- min-width: 110rpx;
|
|
|
|
|
|
|
+ min-width: 90rpx;
|
|
|
text-align: right;
|
|
text-align: right;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* 成员进度 */
|
|
/* 成员进度 */
|
|
|
.member-list {
|
|
.member-list {
|
|
|
- margin-top: 4rpx;
|
|
|
|
|
|
|
+ margin-top: 2rpx;
|
|
|
}
|
|
}
|
|
|
.member-row {
|
|
.member-row {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 8rpx;
|
|
gap: 8rpx;
|
|
|
- margin-top: 8rpx;
|
|
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
}
|
|
}
|
|
|
.member-name {
|
|
.member-name {
|
|
|
- font-size: 22rpx;
|
|
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
color: #475569;
|
|
color: #475569;
|
|
|
width: 90rpx;
|
|
width: 90rpx;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
@@ -255,7 +185,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
.member-bar-wrap { flex: 1; }
|
|
.member-bar-wrap { flex: 1; }
|
|
|
.member-bar-bg {
|
|
.member-bar-bg {
|
|
|
- height: 10rpx;
|
|
|
|
|
|
|
+ height: 8rpx;
|
|
|
background: #E2E8F0;
|
|
background: #E2E8F0;
|
|
|
border-radius: 999rpx;
|
|
border-radius: 999rpx;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
@@ -266,63 +196,27 @@ export default {
|
|
|
border-radius: 999rpx;
|
|
border-radius: 999rpx;
|
|
|
}
|
|
}
|
|
|
.member-val {
|
|
.member-val {
|
|
|
- font-size: 20rpx;
|
|
|
|
|
|
|
+ font-size: 18rpx;
|
|
|
color: #64748B;
|
|
color: #64748B;
|
|
|
- min-width: 90rpx;
|
|
|
|
|
|
|
+ min-width: 80rpx;
|
|
|
text-align: right;
|
|
text-align: right;
|
|
|
}
|
|
}
|
|
|
.member-done {
|
|
.member-done {
|
|
|
- font-size: 24rpx;
|
|
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
color: #10B981;
|
|
color: #10B981;
|
|
|
font-weight: 700;
|
|
font-weight: 700;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* 详情行 */
|
|
|
|
|
|
|
+/* 详情行(合并为单行) */
|
|
|
.card-detail-row {
|
|
.card-detail-row {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- gap: 8rpx;
|
|
|
|
|
|
|
+ gap: 6rpx;
|
|
|
margin-top: 6rpx;
|
|
margin-top: 6rpx;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
}
|
|
}
|
|
|
-.detail-label { font-size: 24rpx; color: #94A3B8; }
|
|
|
|
|
-.detail-val { font-size: 24rpx; color: #334155; }
|
|
|
|
|
|
|
+.detail-label { font-size: 20rpx; color: #94A3B8; }
|
|
|
|
|
+.detail-val { font-size: 20rpx; color: #334155; }
|
|
|
.detail-val.reward { color: #F97316; font-weight: 600; }
|
|
.detail-val.reward { color: #F97316; font-weight: 600; }
|
|
|
.detail-val.badge { color: #6366F1; }
|
|
.detail-val.badge { color: #6366F1; }
|
|
|
-
|
|
|
|
|
-/* 打卡区 */
|
|
|
|
|
-.checkin-section {
|
|
|
|
|
- margin-top: 16rpx;
|
|
|
|
|
- border-top: 1rpx solid #F1F5F9;
|
|
|
|
|
- padding-top: 16rpx;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-btn {
|
|
|
|
|
- background: linear-gradient(135deg, #10B981, #34D399);
|
|
|
|
|
- border-radius: 40rpx;
|
|
|
|
|
- padding: 16rpx 0;
|
|
|
|
|
- text-align: center;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-btn:active { opacity: 0.8; }
|
|
|
|
|
-.checkin-btn-text { color: #fff; font-size: 26rpx; font-weight: 600; }
|
|
|
|
|
-.checkin-form {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- align-items: center;
|
|
|
|
|
- gap: 12rpx;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-input {
|
|
|
|
|
- flex: 1;
|
|
|
|
|
- height: 64rpx;
|
|
|
|
|
- background: #F1F5F9;
|
|
|
|
|
- border-radius: 12rpx;
|
|
|
|
|
- padding: 0 16rpx;
|
|
|
|
|
- font-size: 26rpx;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-submit {
|
|
|
|
|
- background: #10B981;
|
|
|
|
|
- border-radius: 12rpx;
|
|
|
|
|
- padding: 14rpx 24rpx;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-cancel {
|
|
|
|
|
- padding: 14rpx 16rpx;
|
|
|
|
|
-}
|
|
|
|
|
-.checkin-cancel-text { font-size: 24rpx; color: #94A3B8; }
|
|
|
|
|
</style>
|
|
</style>
|