|
@@ -0,0 +1,109 @@
|
|
|
|
|
+# DimensionWeightPicker 重设计
|
|
|
|
|
+
|
|
|
|
|
+## 1. 背景
|
|
|
|
|
+
|
|
|
|
|
+现有 `DimensionWeightPicker.vue` 采用 checkbox 选择维度 + slider 调整权重的组合,存在两个体验问题:
|
|
|
|
|
+
|
|
|
|
|
+1. checkbox + slider 双控件增加认知负担,交互路径不直观
|
|
|
|
|
+2. slider 可自由拖动超过 100%,总和无法约束,用户反复调整才能合规
|
|
|
|
|
+
|
|
|
|
|
+用户要求:**滑动条 + 数字输入框,拖动条表示对应维度分配比例,全部比例之和不超过 100%**。
|
|
|
|
|
+
|
|
|
|
|
+## 2. 设计方案
|
|
|
|
|
+
|
|
|
|
|
+### 2.1 交互规则
|
|
|
|
|
+
|
|
|
|
|
+- **无 checkbox**:设值 > 0 即视为启用,设为 0 即禁用
|
|
|
|
|
+- **滑动条上限动态锁定**:每个 slider 的 `max` = `100 - Σ(其他已启用维度的当前值)`
|
|
|
|
|
+ - 用户拖动到最大限度后无法继续,不会超 100%
|
|
|
|
|
+- **数字输入框同步**:与 slider 双向绑定,超限自动 clamp 到 max 值
|
|
|
|
|
+- **总和提示**:底部显示当前合计,超 100% 显示红色警告(实际不会发生)
|
|
|
|
|
+
|
|
|
|
|
+### 2.2 数据契约
|
|
|
|
|
+
|
|
|
|
|
+Props `value` 格式不变(向后兼容):
|
|
|
|
|
+```js
|
|
|
|
|
+value: [{ dimension: 'body', weight: 25, enabled: true }, ...]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+emit 格式也不变:
|
|
|
|
|
+```js
|
|
|
|
|
+this.$emit('input', [{ dimension: 'body', weight: 25, enabled: true }, ...])
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2.3 UI 布局
|
|
|
|
|
+
|
|
|
|
|
+每行:`[维度名称] [滑动条━━━━━━━━●━━━━] [数字输入]`
|
|
|
|
|
+- 维度名称含颜色标识(品牌五维色)
|
|
|
|
|
+- 滑动条宽度自适应
|
|
|
|
|
+- 数字输入框固定宽度 60px,末尾带 `%` 单位
|
|
|
|
|
+- 底部合计行 + 快捷预设按钮(保留)
|
|
|
|
|
+
|
|
|
|
|
+### 2.4 组件样式
|
|
|
|
|
+
|
|
|
|
|
+```vue
|
|
|
|
|
+身·土 [━━━━━━━━━━●━━━] 30% ← max=100-0=100
|
|
|
|
|
+智·金 [━━━━━━━━●━━━━━━] 20% ← max=100-30=70
|
|
|
|
|
+行·木 [━━━━━━━━━━━━━━━] 0% ← max=100-50=50(灰色禁用)
|
|
|
|
|
+富·水 [━━━━━━━━━━━━━━━] 0%
|
|
|
|
|
+心·火 [━━━━━━━━━━━━━━━] 0%
|
|
|
|
|
+ 合计: 50%
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2.5 预设快捷
|
|
|
|
|
+
|
|
|
|
|
+| 预设 | body | mind | action | wealth | heart |
|
|
|
|
|
+|------|------|------|--------|--------|-------|
|
|
|
|
|
+| 均衡 | 20 | 20 | 20 | 20 | 20 |
|
|
|
|
|
+| 偏身 | 40 | 15 | 15 | 15 | 15 |
|
|
|
|
|
+| 偏智 | 15 | 40 | 15 | 15 | 15 |
|
|
|
|
|
+| 偏行 | 15 | 15 | 40 | 15 | 15 |
|
|
|
|
|
+| 偏富 | 15 | 15 | 15 | 40 | 15 |
|
|
|
|
|
+| 偏心 | 15 | 15 | 15 | 15 | 40 |
|
|
|
|
|
+
|
|
|
|
|
+预设一键应用,重新计算每个 slider 的 max 值。
|
|
|
|
|
+
|
|
|
|
|
+## 3. 实现要点
|
|
|
|
|
+
|
|
|
|
|
+### 3.1 动态 max 计算
|
|
|
|
|
+
|
|
|
|
|
+```js
|
|
|
|
|
+getMaxForDim(code) {
|
|
|
|
|
+ const otherTotal = this.dimensions
|
|
|
|
|
+ .filter(d => d.code !== code && d.currentValue > 0)
|
|
|
|
|
+ .reduce((sum, d) => sum + d.currentValue, 0)
|
|
|
|
|
+ return 100 - otherTotal
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3.2 双向绑定处理
|
|
|
|
|
+
|
|
|
|
|
+- slider change → 更新 `currentValue` → recalculate all maxes → emit
|
|
|
|
|
+- input change → 更新 `currentValue` → recalculate all maxes → emit
|
|
|
|
|
+
|
|
|
|
|
+### 3.3 数字输入框校验
|
|
|
|
|
+
|
|
|
|
|
+- 输入 < 0 → clamp 到 0
|
|
|
|
|
+- 输入 > max → clamp 到 max
|
|
|
|
|
+- 输入非数字 → 忽略
|
|
|
|
|
+
|
|
|
|
|
+### 3.4 禁用状态
|
|
|
|
|
+
|
|
|
|
|
+`currentValue === 0` 的维度 slider 显示灰色且 `disabled=true`,其他维度正常可调。
|
|
|
|
|
+
|
|
|
|
|
+## 4. 影响范围
|
|
|
|
|
+
|
|
|
|
|
+- `cfc-web/src/components/DimensionWeightPicker.vue` — 重写核心实现
|
|
|
|
|
+- `cfc-web/src/views/admin/Activities.vue` — 用到该组件,无需改动
|
|
|
|
|
+- `cfc-web/src/views/admin/ArticleEdit.vue` — 用到该组件,无需改动
|
|
|
|
|
+- `cfc-web/src/views/admin/EnergyRuleManagement.vue` — 用到该组件,无需改动
|
|
|
|
|
+
|
|
|
|
|
+## 5. 成功标准
|
|
|
|
|
+
|
|
|
|
|
+- [x] 5 个维度各有一个 slider + 数字输入框
|
|
|
|
|
+- [x] 任意 slider 拖动不能超过 100%,动态 max 生效
|
|
|
|
|
+- [x] 数字输入框与 slider 双向同步
|
|
|
|
|
+- [x] 总和显示正确,超标时红色警告
|
|
|
|
|
+- [x] 预设快捷按钮正常工作
|
|
|
|
|
+- [x] 与父组件的 value props / emit 接口保持兼容
|
|
|
|
|
+- [x] 样式与现有 Element UI 风格一致
|