Procházet zdrojové kódy

fix: add sendWorkflow and getTodayTasks(Long) overload, pull remote changes

Xiaogang Liao před 3 měsíci
rodič
revize
831b09f7c9

+ 4 - 0
cfc-backend/src/main/java/com/etotem/cfc/service/AIService.java

@@ -232,6 +232,10 @@ public class AIService {
      * @param userId     用户标识
      * @return workflow outputs
      */
+    public Map<String, Object> sendWorkflow(String workflowId, Map<String, Object> inputs) {
+        return runWorkflow(workflowId, inputs, "system");
+    }
+
     public Map<String, Object> runWorkflow(String workflowId, Map<String, Object> inputs, String userId) {
         String url = difyBaseUrl + "/workflows/run";
         Map<String, Object> body = new LinkedHashMap<>();

+ 21 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/EnergyService.java

@@ -95,9 +95,11 @@ public class EnergyService {
                         .ne(User::getRole, "child")  // 排除以child角色为主的账号(用children表管理)
         );
         // 过滤掉单纯是 teacher/admin 角色且不是 parent 角色的用户
+        // 注意:用户可能拥有多角色(如 parent + teacher),切换到 teacher 时 role 字段为 teacher,
+        // 但只要 roles 列表中包含 parent,仍应作为家庭家长参与能量计算
         List<User> familyParents = new ArrayList<>();
         for (User u : parents) {
-            if (u.getRole() != null && ("parent".equals(u.getRole()))) {
+            if (hasParentRole(u)) {
                 familyParents.add(u);
             }
         }
@@ -1067,6 +1069,24 @@ public class EnergyService {
         return score != null ? score : 0;
     }
 
+    private boolean hasParentRole(User user) {
+        if (user.getRole() != null && "parent".equals(user.getRole())) {
+            return true;
+        }
+        String rolesStr = user.getRoles();
+        if (rolesStr == null || rolesStr.isEmpty()) {
+            return false;
+        }
+        String normalized = rolesStr.replace("[", "").replace("]", "")
+                .replace("\"", "").replace(" ", "");
+        for (String r : normalized.split(",")) {
+            if ("parent".equals(r.trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private EnergySandboxDTO buildEmptyDTO() {
         EnergySandboxDTO dto = new EnergySandboxDTO();
         dto.setBodyScore(0);

+ 25 - 13
cfc-frontend/components/DimensionActivities.vue

@@ -49,14 +49,14 @@
                   <text class="meta-text">{{ act._timeText }}</text>
                 </view>
                 <view class="card-badges" v-if="act._badges && act._badges.length">
-                  <text
+                  <view
                     class="card-badge"
                     v-for="badge in act._badges"
                     :key="badge.name"
-                    :style="{ color: badge.color, borderColor: badge.color + '40' }"
+                    :style="{ borderColor: badge.color }"
                   >
-                    {{ badge.name }}
-                  </text>
+                    <text class="badge-icon">{{ badge.icon }}</text>
+                  </view>
                 </view>
               </view>
               <view class="card-bottom">
@@ -141,7 +141,7 @@ export default {
         var result = []
         for (var key in obj) {
           if (obj[key] > 0 && DIMENSION_MAP[key]) {
-            result.push({ name: DIMENSION_MAP[key].name, color: DIMENSION_MAP[key].color, weight: obj[key] })
+            result.push({ name: DIMENSION_MAP[key].name, color: DIMENSION_MAP[key].color, icon: DIMENSION_MAP[key].icon, weight: obj[key] })
           }
         }
         return result
@@ -266,7 +266,7 @@ export default {
 
 .activity-swiper {
   width: 100%;
-  height: 160rpx;
+  height: 210rpx;
 }
 
 .activity-swiper .swiper-slide {
@@ -311,21 +311,23 @@ export default {
   opacity: 0.8;
 }
 
-/* 封面图 — 占满卡片高度 */
+/* 封面图 — 占总宽度1/3,占满卡片高度 */
 .card-cover-img {
-  width: 200rpx;
+  width: 33.33%;
   height: 100%;
   flex-shrink: 0;
   background: #F1F5F9;
 }
 
-/* 右侧信息区 */
+/* 右侧信息区 — 文字右对齐 */
 .card-info {
   flex: 1;
   padding: 16rpx;
   display: flex;
   flex-direction: column;
   justify-content: space-between;
+  align-items: flex-end;
+  text-align: right;
   min-width: 0;
 }
 
@@ -347,6 +349,7 @@ export default {
   display: flex;
   flex-direction: row;
   align-items: center;
+  justify-content: flex-end;
   margin-bottom: 8rpx;
 }
 
@@ -375,11 +378,19 @@ export default {
 }
 
 .card-badge {
+  width: 36rpx;
+  height: 36rpx;
+  border-radius: 50%;
+  border: 2rpx solid;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: transparent;
+}
+
+.badge-icon {
   font-size: 20rpx;
-  padding: 4rpx 12rpx;
-  border-radius: 20rpx;
-  border: 1rpx solid;
-  font-weight: 500;
+  line-height: 1;
 }
 
 /* 底部:状态 + 价格 */
@@ -387,6 +398,7 @@ export default {
   display: flex;
   flex-direction: row;
   align-items: center;
+  justify-content: flex-end;
   gap: 12rpx;
 }
 

+ 5 - 4
cfc-frontend/pages/shop/order-list/order-list.vue

@@ -401,15 +401,16 @@ export default {
   padding: 0;
   border-bottom: 1rpx solid #eee;
   white-space: nowrap;
-  height: 88rpx;
+  height: 96rpx;
 }
 .tab {
   display: inline-flex;
   align-items: center;
   justify-content: center;
   flex-direction: column;
-  padding: 0 24rpx;
-  height: 88rpx;
+  padding: 8rpx 24rpx;
+  height: 96rpx;
+  box-sizing: border-box;
   position: relative;
 }
 .tab-label {
@@ -437,7 +438,7 @@ export default {
 }
 .order-list {
   flex: 1;
-  height: calc(100vh - 88rpx - 104rpx);
+  height: calc(100vh - 96rpx - 104rpx);
 }
 .loading-wrap,
 .empty-wrap {

+ 8 - 2
cfc-frontend/pages/wealth-sub/checkin.vue

@@ -19,10 +19,10 @@
         <text class="weekday" v-for="(w, i) in weekdays" :key="i">{{ w }}</text>
       </view>
       <view class="calendar-days">
-        <view class="day-cell empty" v-for="(e, i) in emptyDays" :key="'e' + i"></view>
+        <view class="day-cell empty" v-for="(e, i) in emptyDays" :key="getEmptyKey(i)"></view>
         <view
           v-for="(day, i) in daysInMonth"
-          :key="'d' + i"
+          :key="getDayKey(i)"
           class="day-cell"
           :class="{
             checked: checkinDates[day],
@@ -404,6 +404,12 @@ export default {
     formatDate: function(dateStr) {
       if (!dateStr) return ''
       return dateStr.substring(0, 16).replace('T', ' ')
+    },
+    getEmptyKey: function(i) {
+      return 'e' + i
+    },
+    getDayKey: function(i) {
+      return 'd' + i
     }
   }
 }

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-7a6d82694368737a7fcfcc3d0730cda9026900b5
+63ab45ce10e6b6a131f7c5b383eb3d79108f2f8a

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.648",
+  "version": "1.0.649",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 16 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,22 @@
 
 ---
 
+## v1.0.649 (2026-07-29)
+
+### Bug 修复
+- 推荐商品和活动价格显示到分
+- allow tracking screenshots in web/articles/ via .gitignore
+
+### 新功能
+- 文章详情页完整功能 — 自动完成阅读+评论系统+AI答题
+- add gut microbiota-obesity article with 3 reference screenshots + track HRW sleep screenshots
+- 过渡页最少800ms最多3s — 集中计时到tab-transition组件
+- 完整记账功能 — 收支管理+分类统计+月度概览
+
+### 文档
+- 文章详情页功能补充设计 — 自动完成阅读+评论系统+AI答题
+
+
 ## v1.0.648 (2026-07-29)
 
 ### Bug 修复

+ 17 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.648
+> 当前版本: v1.0.649
 
 ## 历史版本
 
@@ -8,6 +8,22 @@
 
 ---
 
+## v1.0.649 (2026-07-29)
+
+### Bug 修复
+- 推荐商品和活动价格显示到分
+- allow tracking screenshots in web/articles/ via .gitignore
+
+### 新功能
+- 文章详情页完整功能 — 自动完成阅读+评论系统+AI答题
+- add gut microbiota-obesity article with 3 reference screenshots + track HRW sleep screenshots
+- 过渡页最少800ms最多3s — 集中计时到tab-transition组件
+- 完整记账功能 — 收支管理+分类统计+月度概览
+
+### 文档
+- 文章详情页功能补充设计 — 自动完成阅读+评论系统+AI答题
+
+
 ## v1.0.648 (2026-07-29)
 
 ### Bug 修复

+ 1 - 0
docs/superpowers/specs/2026-07-30-service-role-apply-design.md

@@ -0,0 +1 @@
+# 服务角色统一申请设计