فهرست منبع

chore: auto bump version and changelog [skip ci]

iwt 3 ماه پیش
والد
کامیت
28a1819cdb

+ 169 - 0
cfc-frontend/components/MicroActionCard.vue

@@ -0,0 +1,169 @@
+<template>
+  <view class="micro-action-card">
+    <view class="mac-header">
+      <text class="mac-title">☕️ 今天的小行动</text>
+      <text class="mac-status" v-if="completed">已完成 ✅</text>
+      <text class="mac-status" v-else>点击完成 +1能量</text>
+    </view>
+    <view class="mac-body">
+      <template v-if="loading">
+        <view class="mac-loading">
+          <text class="mac-loading-text">加载中...</text>
+        </view>
+      </template>
+      <template v-else-if="completed">
+        <view class="mac-done">
+          <view class="mac-done-icon">✓</view>
+          <text class="mac-done-text">今日微行动已完成</text>
+        </view>
+        <text class="mac-energy">+1 身能量</text>
+      </template>
+      <template v-else-if="!action">
+        <view class="mac-empty">
+          <text class="mac-empty-text">所有行动已就绪</text>
+        </view>
+      </template>
+      <template v-else>
+        <view class="mac-action-display">
+          <text class="mac-action-icon">{{ action.icon }}</text>
+          <text class="mac-action-name">{{ action.name }}</text>
+          <text class="mac-action-desc">{{ action.description }}</text>
+        </view>
+        <view class="mac-action-btn" @click="doComplete">
+          <text class="mac-btn-text">完成</text>
+        </view>
+      </template>
+    </view>
+  </view>
+</template>
+
+<script>
+import api from '@/utils/api.js'
+export default {
+  props: {
+    childId: { type: Number, default: null }
+  },
+  data: function() {
+    return {
+      action: null,
+      completed: false,
+      loading: false
+    }
+  },
+  created: function() {
+    this.loadTodayAction()
+  },
+  methods: {
+    loadTodayAction: function() {
+      if (!this.childId) return
+      var self = this
+      this.loading = true
+      api.microActionToday({ childId: self.childId }).then(function(res) {
+        self.loading = false
+        if (res.data) {
+          self.action = res.data.action
+          self.completed = res.data.completed
+        }
+      }).catch(function() {
+        self.loading = false
+        self.action = null
+      })
+    },
+    doComplete: function() {
+      if (!this.childId) {
+        uni.showToast({ title: '请先选择孩子', icon: 'none' })
+        return
+      }
+      if (!this.action) return
+      if (this.loading) return
+      var self = this
+      this.loading = true
+      api.microActionComplete({
+        childId: self.childId,
+        actionId: self.action.id
+      }).then(function(res) {
+        self.loading = false
+        if (res.code === 200) {
+          self.completed = true
+          uni.showToast({ title: '太棒了!+1能量', icon: 'none' })
+          self.$emit('completed')
+        }
+      }).catch(function(err) {
+        self.loading = false
+        // Error already shown by api.js interceptor
+      })
+    }
+  },
+  watch: {
+    childId: function() {
+      this.action = null
+      this.completed = false
+      this.loadTodayAction()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.micro-action-card {
+  background: linear-gradient(135deg, #FFF7ED, #FFEDD5);
+  border-radius: 20rpx;
+  padding: 24rpx;
+  margin: 20rpx 20rpx 0 20rpx;
+  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
+  border: 1rpx solid #FED7AA;
+}
+.mac-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 16rpx;
+}
+.mac-title { font-size: 28rpx; font-weight: 700; color: #9A3412; }
+.mac-status { font-size: 22rpx; color: #EA580C; }
+.mac-body { display: flex; flex-direction: column; align-items: center; }
+.mac-loading { padding: 20rpx 0; }
+.mac-loading-text { font-size: 24rpx; color: #999; }
+.mac-done {
+  display: flex;
+  align-items: center;
+  gap: 12rpx;
+  padding: 12rpx 0;
+}
+.mac-done-icon {
+  width: 48rpx;
+  height: 48rpx;
+  border-radius: 24rpx;
+  background: linear-gradient(135deg, #10B981, #34D399);
+  color: #fff;
+  font-size: 24rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.mac-done-text { font-size: 28rpx; color: #10B981; font-weight: 600; }
+.mac-energy { font-size: 22rpx; color: #999; margin-top: 6rpx; }
+.mac-empty { padding: 20rpx 0; }
+.mac-empty-text { font-size: 24rpx; color: #999; }
+.mac-action-display {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 12rpx 0;
+  gap: 8rpx;
+}
+.mac-action-icon { font-size: 72rpx; }
+.mac-action-name { font-size: 36rpx; font-weight: 700; color: #333; }
+.mac-action-desc { font-size: 24rpx; color: #888; text-align: center; }
+.mac-action-btn {
+  background: linear-gradient(135deg, #F97316, #FB923C);
+  color: #fff;
+  font-size: 28rpx;
+  font-weight: 600;
+  padding: 16rpx 80rpx;
+  border-radius: 40rpx;
+  margin-top: 16rpx;
+}
+.mac-action-btn:active { opacity: 0.8; }
+.mac-btn-text { color: #fff; }
+</style>

+ 11 - 1
cfc-frontend/pages/index/parent-index.vue

@@ -16,6 +16,12 @@
   :selectedMemberId="selectedMemberId"
   @select="onFamilyMemberSelect" />
 
+<!-- ===== 微行动卡片(P0:有效启动) ===== -->
+<MicroActionCard
+  v-if="selectedMemberId && selectedChild && selectedChild.id"
+  :childId="selectedChild.id"
+  @completed="onMicroActionCompleted" />
+
 <!-- ===== 家庭成员关系图谱 ===== -->
 <FamilyRelationGraph
   v-if="familyMembersVisible.length > 0"
@@ -367,9 +373,10 @@ import ContactCard from '../../components/ContactCard.vue'
 import ContactImport from '../../components/ContactImport.vue'
 import RecommendedFeed from '../../components/RecommendedFeed.vue'
 import FamilyMemberStrip from '../../components/FamilyMemberStrip.vue'
+import MicroActionCard from '../../components/MicroActionCard.vue'
 
 export default {
-  components: { PageBanner, RecommendedFeed, PlayfulCard, PlayfulButton, BaseBadge, BaseEmpty, BaseLoading, FamilyRelationGraph, WuxingSandbox, ContactCard, ContactImport, FamilyMemberStrip },
+  components: { PageBanner, RecommendedFeed, PlayfulCard, PlayfulButton, BaseBadge, BaseEmpty, BaseLoading, FamilyRelationGraph, WuxingSandbox, ContactCard, ContactImport, FamilyMemberStrip, MicroActionCard },
   data() {
     return {
       nickname: '',
@@ -758,6 +765,9 @@ export default {
     onFamilyMemberSelect(member) {
       this.selectedMemberId = member.id
     },
+    onMicroActionCompleted() {
+      this.loadData()
+    },
     goMemberDetail(member) {
       if (!member || !member.memberId) return
       uni.navigateTo({

+ 6 - 0
cfc-frontend/utils/api.js

@@ -1456,6 +1456,12 @@ export const getInsurancePlanning = () => {
 export const healthCheckinList = (data) => request('/api/health/checkin/list', 'POST', data)
 export const healthCheckinCreate = (data) => request('/api/health/checkin/create', 'POST', data)
 export const healthCheckinDelete = (id) => request('/api/health/checkin/delete', 'POST', { id })
+
+// ===== 寰鍔紙P0 鏈夋晥鍚姩锛� =====
+export const microActionList = () => request('/api/micro-action/list', 'POST', {})
+export const microActionToday = (data) => request('/api/micro-action/today', 'POST', data)
+export const microActionComplete = (data) => request('/api/micro-action/complete', 'POST', data)
+export const microActionCheckToday = (data) => request('/api/micro-action/check-today', 'POST', data)
 
 // ===== 娲诲姩妯″潡锛堢淮搴︾瓫閫夛級 =====
 export const getActivityList = (data) => request('/api/activity/list', 'POST', data)

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-cf447fb50d51396f0f3ab0cf3987190c5728f072
+4ec7f83b2aa8b9c113fabbe87645f554ecc8c3fc

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.480",
+  "version": "1.0.481",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.480",
+      "version": "1.0.481",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",