Explorar el Código

fix(admin): DimensionWeightPicker 拖动时按比例重新分配维持100%

问题:
1. 拖动某维度时其他维度同向变化
2. 各维度独立0-100, 总和未保持100%

修复: onWeightChange(changedCode) 将 100-newValue 按比例分配到
其他维度, 确保总和恒为100%。移除 getMaxForDim / getRemaining。
Xiaogang Liao hace 2 meses
padre
commit
16ad646875

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-7b88b1ff37fc78e42ee0cc71cbea4ccc03f99aa1
+804e5044c6e070e90eda0257b8664919b495ff84

+ 46 - 0
cfc-web/CHANGELOG.md

@@ -1,6 +1,52 @@
 # 更新日志 (Changelog)
 
 此文件记录所有构建版本的变更。
+## v1.0.2 (2026-07-05)
+
+### 新功能
+- update food-list.vue with full nutrition fields and recommendation index display
+- 自动版本号递增 + CHANGELOG.md 生成
+- add /api/health/foods/by-family endpoint and health report trigger for food index
+- add FoodRecommendController with index/history/by-family endpoints
+- add FoodRecommendService sourcing index from report scores
+- update Foods.vue table columns and dialog fields with full nutrition input
+- add FoodRecommendIndex and FoodRecommendIdxLog entities with mappers
+- add food_recommend_idx and food_recommend_idx_log tables, fix kcalPer100g JSON mapping
+- 订单详情页 + 订单/商品管理完善
+
+### Bug 修复
+- 环境配置更新
+- action/index.vue 集成 WuxingSandbox 能量沙盘
+- index.vue 闪屏逻辑优化 + api.js 中文注释编码修复
+- DatabaseInitializer 添加 family_member_id 和 role_override 列迁移
+- E2E tests for deployed admin at cfc.iwintrue.com/admin
+
+### 重构
+- TabTransition 动态化 - 数据就绪后才自动消失
+- 合并工作台至首页,删除独立路由和菜单
+
+### 其他
+- - scripts/generate-changelog.js: 从 git log 分类生成变更日志
+- - vue.config.js: 注入 VUE_APP_VERSION / VUE_APP_BUILD_TIME
+- - Dashboard.vue: 版本显示动态化 + 变更日志弹窗
+- 
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
+- 
+- - Fix playwright.config.js baseURL and viewport for desktop admin
+- - Add dev:h5/build:h5 scripts to cfc-frontend package.json
+- - Fix config.js truncated API URLs
+- - Add ensureLoggedIn() helper with auto-login flow for admin tests
+- 
+- - 删除 Layout.vue 侧边栏'工作台'菜单项
+- - 删除 TeacherDashboard.vue(内容已完整集成在 Dashboard.vue)
+- - fix: StatsController.java teacher_status 查询字段修复
+- 
+
+
 ## v1.0.1 (2026-07-05)
 
 ### 新功能

+ 1 - 1
cfc-web/package.json

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

+ 60 - 25
cfc-web/src/components/DimensionWeightPicker.vue

@@ -6,20 +6,18 @@
         <el-slider
           v-model="dim.currentValue"
           :min="0"
-          :max="getMaxForDim(dim.code)"
-          :disabled="dim.currentValue === 0 && getRemaining() === 0"
+          :max="100"
           class="dim-slider"
-          @change="onWeightChange"
+          @change="onWeightChange(dim.code)"
         />
         <el-input-number
           v-model="dim.currentValue"
           :min="0"
-          :max="getMaxForDim(dim.code)"
-          :disabled="dim.currentValue === 0 && getRemaining() === 0"
+          :max="100"
           :controls="false"
           size="mini"
           class="dim-input"
-          @change="onWeightChange"
+          @change="onWeightChange(dim.code)"
         />
         <span class="dim-unit">%</span>
       </div>
@@ -92,25 +90,62 @@ export default {
     }
   },
   methods: {
-    getMaxForDim(code) {
-      const otherTotal = this.dimensions
-        .filter(d => d.code !== code && (d.currentValue || 0) > 0)
-        .reduce((s, d) => s + (d.currentValue || 0), 0)
-      return Math.max(0, 100 - otherTotal)
-    },
-    getRemaining() {
-      return 100 - this.sum
-    },
-    onWeightChange() {
-      this.dimensions.forEach(d => {
-        const max = this.getMaxForDim(d.code)
-        if (d.currentValue > max) {
-          d.currentValue = max
+    onWeightChange(changedCode) {
+      // 1. Clamp the changed dimension
+      const changed = this.dimensions.find(function(d) { return d.code === changedCode })
+      if (changed) {
+        changed.currentValue = Math.max(0, Math.min(100, changed.currentValue))
+      }
+      var remaining = 100 - this.sum
+      if (remaining === 0) {
+        this.emitValue()
+        return
+      }
+      var others = this.dimensions.filter(function(d) { return d.code !== changedCode })
+      if (remaining > 0) {
+        // 需要把剩余分配到其他维度
+        var otherTotal = others.reduce(function(s, d) { return s + (d.currentValue || 0) }, 0)
+        if (otherTotal === 0) {
+          // 所有其他维度为 0,平分剩余
+          var rest = remaining
+          others.forEach(function(d, i) {
+            d.currentValue = (i === others.length - 1) ? rest : Math.floor(remaining / others.length)
+            if (i < others.length - 1) rest = remaining - d.currentValue
+          })
+        } else {
+          var distSum = 0
+          others.forEach(function(d, i) {
+            if (i === others.length - 1) {
+              d.currentValue = Math.max(0, remaining - distSum)
+            } else {
+              var share = Math.max(0, Math.round((d.currentValue / otherTotal) * remaining))
+              d.currentValue = share
+              distSum += share
+            }
+          })
         }
-        if (d.currentValue < 0) {
-          d.currentValue = 0
+      } else {
+        // 超过 100,需要从其他维度扣除
+        var excess = -remaining
+        var otherTotal2 = others.reduce(function(s, d) { return s + (d.currentValue || 0) }, 0)
+        if (otherTotal2 > 0) {
+          var cutSum = 0
+          others.forEach(function(d, i) {
+            if (i === others.length - 1) {
+              d.currentValue = Math.max(0, (d.currentValue || 0) - (excess - cutSum))
+            } else {
+              var cut = Math.min(d.currentValue || 0, Math.round((d.currentValue / otherTotal2) * excess))
+              d.currentValue = Math.max(0, (d.currentValue || 0) - cut)
+              cutSum += cut
+            }
+          })
         }
-      })
+      }
+      // 最后修正浮点误差
+      var finalSum = this.dimensions.reduce(function(s, d) { return s + (d.currentValue || 0) }, 0)
+      if (finalSum !== 100 && others.length > 0) {
+        others[0].currentValue += 100 - finalSum
+      }
       this.emitValue()
     },
     emitValue() {
@@ -122,10 +157,10 @@ export default {
       this.$emit('input', weights)
     },
     applyPreset(preset) {
-      this.dimensions.forEach(d => {
+      this.dimensions.forEach(function(d) {
         d.currentValue = preset.weights[d.code] || 0
       })
-      this.onWeightChange()
+      this.emitValue()
     }
   }
 }