skill-calorie 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/anomaly/common.d.ts +53 -0
- package/dist/analysis/anomaly/common.d.ts.map +1 -0
- package/dist/analysis/anomaly/common.js +69 -0
- package/dist/analysis/anomaly/common.js.map +1 -0
- package/dist/analysis/anomaly/diet.d.ts +8 -0
- package/dist/analysis/anomaly/diet.d.ts.map +1 -0
- package/dist/analysis/anomaly/diet.js +95 -0
- package/dist/analysis/anomaly/diet.js.map +1 -0
- package/dist/analysis/anomaly/exercise.d.ts +9 -0
- package/dist/analysis/anomaly/exercise.d.ts.map +1 -0
- package/dist/analysis/anomaly/exercise.js +116 -0
- package/dist/analysis/anomaly/exercise.js.map +1 -0
- package/dist/analysis/anomaly/index.d.ts +19 -0
- package/dist/analysis/anomaly/index.d.ts.map +1 -0
- package/dist/analysis/anomaly/index.js +51 -0
- package/dist/analysis/anomaly/index.js.map +1 -0
- package/dist/analysis/anomaly/overall.d.ts +13 -0
- package/dist/analysis/anomaly/overall.d.ts.map +1 -0
- package/dist/analysis/anomaly/overall.js +128 -0
- package/dist/analysis/anomaly/overall.js.map +1 -0
- package/dist/analysis/anomaly/overall2.d.ts +5 -0
- package/dist/analysis/anomaly/overall2.d.ts.map +1 -0
- package/dist/analysis/anomaly/overall2.js +94 -0
- package/dist/analysis/anomaly/overall2.js.map +1 -0
- package/dist/analysis/anomaly/weight.d.ts +8 -0
- package/dist/analysis/anomaly/weight.d.ts.map +1 -0
- package/dist/analysis/anomaly/weight.js +106 -0
- package/dist/analysis/anomaly/weight.js.map +1 -0
- package/dist/analysis/anomaly/weight2.d.ts +4 -0
- package/dist/analysis/anomaly/weight2.d.ts.map +1 -0
- package/dist/analysis/anomaly/weight2.js +59 -0
- package/dist/analysis/anomaly/weight2.js.map +1 -0
- package/dist/analysis/contraindications.d.ts +63 -0
- package/dist/analysis/contraindications.d.ts.map +1 -0
- package/dist/analysis/contraindications.js +121 -0
- package/dist/analysis/contraindications.js.map +1 -0
- package/dist/analysis/cross.d.ts +75 -0
- package/dist/analysis/cross.d.ts.map +1 -0
- package/dist/analysis/cross.js +283 -0
- package/dist/analysis/cross.js.map +1 -0
- package/dist/analysis/dashboard.d.ts +18 -0
- package/dist/analysis/dashboard.d.ts.map +1 -0
- package/dist/analysis/dashboard.js +48 -0
- package/dist/analysis/dashboard.js.map +1 -0
- package/dist/analysis/deficit.d.ts +44 -0
- package/dist/analysis/deficit.d.ts.map +1 -0
- package/dist/analysis/deficit.js +54 -0
- package/dist/analysis/deficit.js.map +1 -0
- package/dist/analysis/diet.d.ts +76 -0
- package/dist/analysis/diet.d.ts.map +1 -0
- package/dist/analysis/diet.js +164 -0
- package/dist/analysis/diet.js.map +1 -0
- package/dist/analysis/exercise.d.ts +98 -0
- package/dist/analysis/exercise.d.ts.map +1 -0
- package/dist/analysis/exercise.js +298 -0
- package/dist/analysis/exercise.js.map +1 -0
- package/dist/analysis/exerciseReview.d.ts +36 -0
- package/dist/analysis/exerciseReview.d.ts.map +1 -0
- package/dist/analysis/exerciseReview.js +50 -0
- package/dist/analysis/exerciseReview.js.map +1 -0
- package/dist/analysis/precision.d.ts +15 -0
- package/dist/analysis/precision.d.ts.map +1 -0
- package/dist/analysis/precision.js +38 -0
- package/dist/analysis/precision.js.map +1 -0
- package/dist/analysis/result.d.ts +15 -0
- package/dist/analysis/result.d.ts.map +1 -0
- package/dist/analysis/result.js +13 -0
- package/dist/analysis/result.js.map +1 -0
- package/dist/analysis/review.d.ts +118 -0
- package/dist/analysis/review.d.ts.map +1 -0
- package/dist/analysis/review.js +195 -0
- package/dist/analysis/review.js.map +1 -0
- package/dist/analysis/series.d.ts +42 -0
- package/dist/analysis/series.d.ts.map +1 -0
- package/dist/analysis/series.js +127 -0
- package/dist/analysis/series.js.map +1 -0
- package/dist/analysis/simulate.d.ts +43 -0
- package/dist/analysis/simulate.d.ts.map +1 -0
- package/dist/analysis/simulate.js +109 -0
- package/dist/analysis/simulate.js.map +1 -0
- package/dist/analysis/simulate2.d.ts +65 -0
- package/dist/analysis/simulate2.d.ts.map +1 -0
- package/dist/analysis/simulate2.js +173 -0
- package/dist/analysis/simulate2.js.map +1 -0
- package/dist/analysis/trend.d.ts +39 -0
- package/dist/analysis/trend.d.ts.map +1 -0
- package/dist/analysis/trend.js +48 -0
- package/dist/analysis/trend.js.map +1 -0
- package/dist/analysis/utils.d.ts +17 -0
- package/dist/analysis/utils.d.ts.map +1 -0
- package/dist/analysis/utils.js +52 -0
- package/dist/analysis/utils.js.map +1 -0
- package/dist/analysis/volatility.d.ts +43 -0
- package/dist/analysis/volatility.d.ts.map +1 -0
- package/dist/analysis/volatility.js +96 -0
- package/dist/analysis/volatility.js.map +1 -0
- package/dist/analysis/weight.d.ts +86 -0
- package/dist/analysis/weight.d.ts.map +1 -0
- package/dist/analysis/weight.js +219 -0
- package/dist/analysis/weight.js.map +1 -0
- package/dist/analysis/weightCompare.d.ts +63 -0
- package/dist/analysis/weightCompare.d.ts.map +1 -0
- package/dist/analysis/weightCompare.js +212 -0
- package/dist/analysis/weightCompare.js.map +1 -0
- package/dist/analysis/weightCompare2.d.ts +63 -0
- package/dist/analysis/weightCompare2.d.ts.map +1 -0
- package/dist/analysis/weightCompare2.js +211 -0
- package/dist/analysis/weightCompare2.js.map +1 -0
- package/dist/analysis/weightCompare3.d.ts +13 -0
- package/dist/analysis/weightCompare3.d.ts.map +1 -0
- package/dist/analysis/weightCompare3.js +199 -0
- package/dist/analysis/weightCompare3.js.map +1 -0
- package/dist/cli/cmd_read.d.ts +8 -0
- package/dist/cli/cmd_read.d.ts.map +1 -0
- package/dist/cli/cmd_read.js +719 -0
- package/dist/cli/cmd_read.js.map +1 -0
- package/dist/cli/keys.d.ts +333 -0
- package/dist/cli/keys.d.ts.map +1 -0
- package/dist/cli/keys.js +103 -0
- package/dist/cli/keys.js.map +1 -0
- package/dist/cli/write.d.ts +24 -0
- package/dist/cli/write.d.ts.map +1 -0
- package/dist/cli/write.js +832 -0
- package/dist/cli/write.js.map +1 -0
- package/dist/fetch/audit.d.ts +25 -0
- package/dist/fetch/audit.d.ts.map +1 -0
- package/dist/fetch/audit.js +46 -0
- package/dist/fetch/audit.js.map +1 -0
- package/dist/fetch/batch.d.ts +68 -0
- package/dist/fetch/batch.d.ts.map +1 -0
- package/dist/fetch/batch.js +183 -0
- package/dist/fetch/batch.js.map +1 -0
- package/dist/fetch/body.d.ts +89 -0
- package/dist/fetch/body.d.ts.map +1 -0
- package/dist/fetch/body.js +217 -0
- package/dist/fetch/body.js.map +1 -0
- package/dist/fetch/cli.d.ts +3 -0
- package/dist/fetch/cli.d.ts.map +1 -0
- package/dist/fetch/cli.js +195 -0
- package/dist/fetch/cli.js.map +1 -0
- package/dist/fetch/cross-skill.d.ts +29 -0
- package/dist/fetch/cross-skill.d.ts.map +1 -0
- package/dist/fetch/cross-skill.js +42 -0
- package/dist/fetch/cross-skill.js.map +1 -0
- package/dist/fetch/db.d.ts +5 -0
- package/dist/fetch/db.d.ts.map +1 -0
- package/dist/fetch/db.js +4 -0
- package/dist/fetch/db.js.map +1 -0
- package/dist/fetch/diet.d.ts +174 -0
- package/dist/fetch/diet.d.ts.map +1 -0
- package/dist/fetch/diet.js +239 -0
- package/dist/fetch/diet.js.map +1 -0
- package/dist/fetch/errors.d.ts +5 -0
- package/dist/fetch/errors.d.ts.map +1 -0
- package/dist/fetch/errors.js +8 -0
- package/dist/fetch/errors.js.map +1 -0
- package/dist/fetch/exercise.d.ts +72 -0
- package/dist/fetch/exercise.d.ts.map +1 -0
- package/dist/fetch/exercise.js +270 -0
- package/dist/fetch/exercise.js.map +1 -0
- package/dist/fetch/goal.d.ts +48 -0
- package/dist/fetch/goal.d.ts.map +1 -0
- package/dist/fetch/goal.js +73 -0
- package/dist/fetch/goal.js.map +1 -0
- package/dist/fetch/goalHistory.d.ts +24 -0
- package/dist/fetch/goalHistory.d.ts.map +1 -0
- package/dist/fetch/goalHistory.js +51 -0
- package/dist/fetch/goalHistory.js.map +1 -0
- package/dist/fetch/history.d.ts +28 -0
- package/dist/fetch/history.d.ts.map +1 -0
- package/dist/fetch/history.js +29 -0
- package/dist/fetch/history.js.map +1 -0
- package/dist/fetch/index.d.ts +23 -0
- package/dist/fetch/index.d.ts.map +1 -0
- package/dist/fetch/index.js +16 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/fetch/nutritionGoal.d.ts +115 -0
- package/dist/fetch/nutritionGoal.d.ts.map +1 -0
- package/dist/fetch/nutritionGoal.js +154 -0
- package/dist/fetch/nutritionGoal.js.map +1 -0
- package/dist/fetch/photos.d.ts +76 -0
- package/dist/fetch/photos.d.ts.map +1 -0
- package/dist/fetch/photos.js +193 -0
- package/dist/fetch/photos.js.map +1 -0
- package/dist/fetch/plan.d.ts +145 -0
- package/dist/fetch/plan.d.ts.map +1 -0
- package/dist/fetch/plan.js +258 -0
- package/dist/fetch/plan.js.map +1 -0
- package/dist/fetch/products.d.ts +62 -0
- package/dist/fetch/products.d.ts.map +1 -0
- package/dist/fetch/products.js +73 -0
- package/dist/fetch/products.js.map +1 -0
- package/dist/fetch/profile.d.ts +46 -0
- package/dist/fetch/profile.d.ts.map +1 -0
- package/dist/fetch/profile.js +105 -0
- package/dist/fetch/profile.js.map +1 -0
- package/dist/fetch/shapes.d.ts +41 -0
- package/dist/fetch/shapes.d.ts.map +1 -0
- package/dist/fetch/shapes.js +38 -0
- package/dist/fetch/shapes.js.map +1 -0
- package/dist/fetch/validate.d.ts +11 -0
- package/dist/fetch/validate.d.ts.map +1 -0
- package/dist/fetch/validate.js +64 -0
- package/dist/fetch/validate.js.map +1 -0
- package/dist/fetch/weight.d.ts +109 -0
- package/dist/fetch/weight.d.ts.map +1 -0
- package/dist/fetch/weight.js +210 -0
- package/dist/fetch/weight.js.map +1 -0
- package/dist/fetch/xunji-catalog.d.ts +17 -0
- package/dist/fetch/xunji-catalog.d.ts.map +1 -0
- package/dist/fetch/xunji-catalog.js +57 -0
- package/dist/fetch/xunji-catalog.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/kcal.d.ts +21 -0
- package/dist/kcal.d.ts.map +1 -0
- package/dist/kcal.js +27 -0
- package/dist/kcal.js.map +1 -0
- package/dist/migrate/migrate.d.ts +71 -0
- package/dist/migrate/migrate.d.ts.map +1 -0
- package/dist/migrate/migrate.js +450 -0
- package/dist/migrate/migrate.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +34 -0
- package/dist/paths.js.map +1 -0
- package/dist/render/analysisPlate.d.ts +49 -0
- package/dist/render/analysisPlate.d.ts.map +1 -0
- package/dist/render/analysisPlate.js +149 -0
- package/dist/render/analysisPlate.js.map +1 -0
- package/dist/render/bodyPlate.d.ts +55 -0
- package/dist/render/bodyPlate.d.ts.map +1 -0
- package/dist/render/bodyPlate.js +97 -0
- package/dist/render/bodyPlate.js.map +1 -0
- package/dist/render/diet.d.ts +47 -0
- package/dist/render/diet.d.ts.map +1 -0
- package/dist/render/diet.js +94 -0
- package/dist/render/diet.js.map +1 -0
- package/dist/render/envelope.d.ts +60 -0
- package/dist/render/envelope.d.ts.map +1 -0
- package/dist/render/envelope.js +111 -0
- package/dist/render/envelope.js.map +1 -0
- package/dist/render/errors.d.ts +10 -0
- package/dist/render/errors.d.ts.map +1 -0
- package/dist/render/errors.js +9 -0
- package/dist/render/errors.js.map +1 -0
- package/dist/render/exercise.d.ts +20 -0
- package/dist/render/exercise.d.ts.map +1 -0
- package/dist/render/exercise.js +32 -0
- package/dist/render/exercise.js.map +1 -0
- package/dist/render/goal.d.ts +24 -0
- package/dist/render/goal.d.ts.map +1 -0
- package/dist/render/goal.js +23 -0
- package/dist/render/goal.js.map +1 -0
- package/dist/render/goalExtra.d.ts +45 -0
- package/dist/render/goalExtra.d.ts.map +1 -0
- package/dist/render/goalExtra.js +94 -0
- package/dist/render/goalExtra.js.map +1 -0
- package/dist/render/goalPlate.d.ts +66 -0
- package/dist/render/goalPlate.d.ts.map +1 -0
- package/dist/render/goalPlate.js +110 -0
- package/dist/render/goalPlate.js.map +1 -0
- package/dist/render/health.d.ts +21 -0
- package/dist/render/health.d.ts.map +1 -0
- package/dist/render/health.js +41 -0
- package/dist/render/health.js.map +1 -0
- package/dist/render/help.d.ts +18 -0
- package/dist/render/help.d.ts.map +1 -0
- package/dist/render/help.js +58 -0
- package/dist/render/help.js.map +1 -0
- package/dist/render/home.d.ts +30 -0
- package/dist/render/home.d.ts.map +1 -0
- package/dist/render/home.js +73 -0
- package/dist/render/home.js.map +1 -0
- package/dist/render/html.d.ts +66 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +510 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/index.d.ts +47 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +26 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/insightPlate.d.ts +55 -0
- package/dist/render/insightPlate.d.ts.map +1 -0
- package/dist/render/insightPlate.js +97 -0
- package/dist/render/insightPlate.js.map +1 -0
- package/dist/render/library.d.ts +32 -0
- package/dist/render/library.d.ts.map +1 -0
- package/dist/render/library.js +54 -0
- package/dist/render/library.js.map +1 -0
- package/dist/render/photo.d.ts +101 -0
- package/dist/render/photo.d.ts.map +1 -0
- package/dist/render/photo.js +241 -0
- package/dist/render/photo.js.map +1 -0
- package/dist/render/planPlate.d.ts +40 -0
- package/dist/render/planPlate.d.ts.map +1 -0
- package/dist/render/planPlate.js +72 -0
- package/dist/render/planPlate.js.map +1 -0
- package/dist/render/profilePlate.d.ts +17 -0
- package/dist/render/profilePlate.d.ts.map +1 -0
- package/dist/render/profilePlate.js +18 -0
- package/dist/render/profilePlate.js.map +1 -0
- package/dist/render/ranking.d.ts +22 -0
- package/dist/render/ranking.d.ts.map +1 -0
- package/dist/render/ranking.js +63 -0
- package/dist/render/ranking.js.map +1 -0
- package/dist/render/receipt.d.ts +71 -0
- package/dist/render/receipt.d.ts.map +1 -0
- package/dist/render/receipt.js +65 -0
- package/dist/render/receipt.js.map +1 -0
- package/dist/render/weightPlate.d.ts +54 -0
- package/dist/render/weightPlate.d.ts.map +1 -0
- package/dist/render/weightPlate.js +110 -0
- package/dist/render/weightPlate.js.map +1 -0
- package/dist/schema.d.ts +25 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +281 -0
- package/dist/schema.js.map +1 -0
- package/dist/triggers/help-lookup.d.ts +28 -0
- package/dist/triggers/help-lookup.d.ts.map +1 -0
- package/dist/triggers/help-lookup.js +163 -0
- package/dist/triggers/help-lookup.js.map +1 -0
- package/dist/triggers/index.d.ts +24 -0
- package/dist/triggers/index.d.ts.map +1 -0
- package/dist/triggers/index.js +78 -0
- package/dist/triggers/index.js.map +1 -0
- package/dist/triggers/scene-01-home.d.ts +4 -0
- package/dist/triggers/scene-01-home.d.ts.map +1 -0
- package/dist/triggers/scene-01-home.js +13 -0
- package/dist/triggers/scene-01-home.js.map +1 -0
- package/dist/triggers/scene-02-diet.d.ts +4 -0
- package/dist/triggers/scene-02-diet.d.ts.map +1 -0
- package/dist/triggers/scene-02-diet.js +74 -0
- package/dist/triggers/scene-02-diet.js.map +1 -0
- package/dist/triggers/scene-03-weight.d.ts +4 -0
- package/dist/triggers/scene-03-weight.d.ts.map +1 -0
- package/dist/triggers/scene-03-weight.js +62 -0
- package/dist/triggers/scene-03-weight.js.map +1 -0
- package/dist/triggers/scene-04-exercise.d.ts +4 -0
- package/dist/triggers/scene-04-exercise.d.ts.map +1 -0
- package/dist/triggers/scene-04-exercise.js +43 -0
- package/dist/triggers/scene-04-exercise.js.map +1 -0
- package/dist/triggers/scene-05-workout.d.ts +4 -0
- package/dist/triggers/scene-05-workout.d.ts.map +1 -0
- package/dist/triggers/scene-05-workout.js +36 -0
- package/dist/triggers/scene-05-workout.js.map +1 -0
- package/dist/triggers/scene-06-goal.d.ts +4 -0
- package/dist/triggers/scene-06-goal.d.ts.map +1 -0
- package/dist/triggers/scene-06-goal.js +29 -0
- package/dist/triggers/scene-06-goal.js.map +1 -0
- package/dist/triggers/scene-07-profile.d.ts +4 -0
- package/dist/triggers/scene-07-profile.d.ts.map +1 -0
- package/dist/triggers/scene-07-profile.js +8 -0
- package/dist/triggers/scene-07-profile.js.map +1 -0
- package/dist/triggers/scene-08-body.d.ts +4 -0
- package/dist/triggers/scene-08-body.d.ts.map +1 -0
- package/dist/triggers/scene-08-body.js +17 -0
- package/dist/triggers/scene-08-body.js.map +1 -0
- package/dist/triggers/scene-09-photo.d.ts +4 -0
- package/dist/triggers/scene-09-photo.d.ts.map +1 -0
- package/dist/triggers/scene-09-photo.js +14 -0
- package/dist/triggers/scene-09-photo.js.map +1 -0
- package/dist/triggers/scene-10-analysis.d.ts +4 -0
- package/dist/triggers/scene-10-analysis.d.ts.map +1 -0
- package/dist/triggers/scene-10-analysis.js +180 -0
- package/dist/triggers/scene-10-analysis.js.map +1 -0
- package/dist/triggers/types.d.ts +66 -0
- package/dist/triggers/types.d.ts.map +1 -0
- package/dist/triggers/types.js +3 -0
- package/dist/triggers/types.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { sql } from './db.js';
|
|
2
|
+
import { FetchError } from './errors.js';
|
|
3
|
+
function todayStr() { return new Date().toISOString().slice(0, 10); }
|
|
4
|
+
function nowTime() { return new Date().toTimeString().slice(0, 8); }
|
|
5
|
+
function nowStamp() {
|
|
6
|
+
const d = new Date();
|
|
7
|
+
return `${d.toISOString().slice(0, 10)} ${d.toTimeString().slice(0, 8)}`;
|
|
8
|
+
}
|
|
9
|
+
/** MET 关键词表(顺序敏感,对照 _lookup_met 先后)。 */
|
|
10
|
+
const MET_RULES = [
|
|
11
|
+
{ keys: ['哑铃', '杠铃', '史密斯', '弯举', '推举', '推肩', '平举', '深蹲', '卧推', '划船', '硬拉', '飞鸟'], met: 5.0 },
|
|
12
|
+
{ keys: ['俯卧撑', '引体', '自重', '平板'], met: 3.8 },
|
|
13
|
+
{ keys: ['跑步机'], met: 7.5 },
|
|
14
|
+
{ keys: ['户外跑', '路跑'], met: 8.0 },
|
|
15
|
+
{ keys: ['慢跑', '快跑', '冲刺'], met: 9.0 },
|
|
16
|
+
{ keys: ['骑行', '自行车', '小黄车', '骑车'], met: 6.0 },
|
|
17
|
+
{ keys: ['跳绳'], met: 12.0 },
|
|
18
|
+
{ keys: ['椭圆机'], met: 5.5 },
|
|
19
|
+
{ keys: ['游泳'], met: 7.0 },
|
|
20
|
+
{ keys: ['hiit'], met: 8.5 },
|
|
21
|
+
{ keys: ['八段锦', '太极', '瑜伽', '拉伸', '冥想'], met: 2.5 },
|
|
22
|
+
{ keys: ['家务', '做饭', '洗衣', '打扫', '清洁'], met: 2.5 },
|
|
23
|
+
{ keys: ['走路', '散步'], met: 3.0 },
|
|
24
|
+
{ keys: ['通勤'], met: 2.5 },
|
|
25
|
+
{ keys: ['爬楼', '楼梯'], met: 4.0 },
|
|
26
|
+
];
|
|
27
|
+
export function lookupMet(exerciseType) {
|
|
28
|
+
if (!exerciseType)
|
|
29
|
+
return 3.0;
|
|
30
|
+
const et = exerciseType.toLowerCase();
|
|
31
|
+
for (const rule of MET_RULES) {
|
|
32
|
+
if (rule.keys.some((k) => et.includes(k.toLowerCase())))
|
|
33
|
+
return rule.met;
|
|
34
|
+
}
|
|
35
|
+
// 兜底“跑步”类(排除跑步机,已在上表先行命中)。
|
|
36
|
+
if (et.includes('跑'))
|
|
37
|
+
return 8.0;
|
|
38
|
+
return 3.0;
|
|
39
|
+
}
|
|
40
|
+
const STRENGTH_KEYS = ['哑铃', '杠铃', '史密斯', '弯举', '推举', '推肩', '平举', '前平举', '侧平举', '深蹲', '卧推', '划船', '硬拉', '飞鸟', '俯卧撑', '引体', '自重', '平板'];
|
|
41
|
+
const FLEX_KEYS = ['八段锦', '太极', '瑜伽', '拉伸', '冥想'];
|
|
42
|
+
const DAILY_KEYS = ['家务', '做饭', '洗衣', '打扫', '清洁', '通勤', '走路', '散步', '爬楼'];
|
|
43
|
+
export function inferCategory(exerciseType) {
|
|
44
|
+
if (!exerciseType)
|
|
45
|
+
return '有氧';
|
|
46
|
+
if (STRENGTH_KEYS.some((k) => exerciseType.includes(k)))
|
|
47
|
+
return '力量';
|
|
48
|
+
if (FLEX_KEYS.some((k) => exerciseType.includes(k)))
|
|
49
|
+
return '柔韧';
|
|
50
|
+
if (DAILY_KEYS.some((k) => exerciseType.includes(k)))
|
|
51
|
+
return '日常';
|
|
52
|
+
return '有氧';
|
|
53
|
+
}
|
|
54
|
+
export function estimateCaloriesMet(exerciseType, bodyWeight, durationMinutes, sets = 0) {
|
|
55
|
+
const met = lookupMet(exerciseType);
|
|
56
|
+
const category = inferCategory(exerciseType);
|
|
57
|
+
if (category === '有氧' || category === '柔韧' || category === '日常') {
|
|
58
|
+
if (!durationMinutes || durationMinutes <= 0)
|
|
59
|
+
return [0.0, met];
|
|
60
|
+
return [Math.round(met * bodyWeight * (durationMinutes / 60) * 10) / 10, met];
|
|
61
|
+
}
|
|
62
|
+
if (category === '力量') {
|
|
63
|
+
const s = sets <= 0 ? 1 : sets;
|
|
64
|
+
return [Math.round(met * bodyWeight * s * 0.05 * 10) / 10, met];
|
|
65
|
+
}
|
|
66
|
+
return [0.0, met];
|
|
67
|
+
}
|
|
68
|
+
export function estimateDifficultyMet(met) {
|
|
69
|
+
if (met === null || met === undefined || met <= 0)
|
|
70
|
+
return null;
|
|
71
|
+
if (met < 3)
|
|
72
|
+
return 'easy';
|
|
73
|
+
if (met < 6)
|
|
74
|
+
return 'normal';
|
|
75
|
+
return 'hard';
|
|
76
|
+
}
|
|
77
|
+
const HARD_WORDS = ['累死', '力竭', '极限', '干不动', '暴毙', '撑不住', '想死', '不行', '很累', '挺累', '暴汗', '喘', '气喘吁吁', '出汗多', '冲', '狠', 'hard', 'hiit'];
|
|
78
|
+
const EASY_WORDS = ['轻松', '没什么', '没感觉', '微微', '散步', 'easy', '很轻'];
|
|
79
|
+
const MID_WORDS = ['一般', '还行', '中等', '普通', '正常', '适中', '中等强度'];
|
|
80
|
+
/** 口语难度映射(老家原样口径:中等档返回 '中',非 'normal')。 */
|
|
81
|
+
export function parseUserDifficulty(userText) {
|
|
82
|
+
if (!userText)
|
|
83
|
+
return null;
|
|
84
|
+
const t = userText.toLowerCase();
|
|
85
|
+
if (HARD_WORDS.some((k) => t.includes(k.toLowerCase())))
|
|
86
|
+
return 'hard';
|
|
87
|
+
if (EASY_WORDS.some((k) => t.includes(k.toLowerCase())))
|
|
88
|
+
return 'easy';
|
|
89
|
+
if (MID_WORDS.some((k) => t.includes(k)))
|
|
90
|
+
return '中';
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
export function combinedCalories(userReported, estimated, warnAt = 0.5) {
|
|
94
|
+
if (userReported === null || userReported === undefined)
|
|
95
|
+
return [Math.round(estimated * 10) / 10, null, 0.0];
|
|
96
|
+
if (estimated <= 0)
|
|
97
|
+
return [Number(userReported), null, 0.0];
|
|
98
|
+
const deviation = Math.abs(Number(userReported) - estimated) / estimated;
|
|
99
|
+
const suffix = `你报 ${userReported}/AI ${Math.round(estimated * 10) / 10}/偏差 ${Math.trunc(deviation * 100)}%`;
|
|
100
|
+
if (deviation < 0.2)
|
|
101
|
+
return [Math.round(estimated * 10) / 10, suffix, deviation];
|
|
102
|
+
if (deviation < warnAt)
|
|
103
|
+
return [Math.round((Number(userReported) + estimated) / 2 * 10) / 10, `${suffix}/取中位`, deviation];
|
|
104
|
+
return [null, `${suffix}/需确认`, deviation];
|
|
105
|
+
}
|
|
106
|
+
export function estimateCaloriesFromTraining(totalVolumeKg) {
|
|
107
|
+
if (totalVolumeKg <= 0)
|
|
108
|
+
return 0.0;
|
|
109
|
+
return Math.round(totalVolumeKg * 0.08 * 10) / 10;
|
|
110
|
+
}
|
|
111
|
+
export function convertLoadKg(weightStr, unitStr) {
|
|
112
|
+
const w = parseFloat(String(weightStr));
|
|
113
|
+
if (!Number.isFinite(w))
|
|
114
|
+
return 0.0;
|
|
115
|
+
if (unitStr && String(unitStr).toLowerCase() === 'lbs')
|
|
116
|
+
return Math.round(w * 0.45359237 * 10) / 10;
|
|
117
|
+
return Math.round(w * 10) / 10;
|
|
118
|
+
}
|
|
119
|
+
export function resolveWindow(opts = {}) {
|
|
120
|
+
const now = opts.now ?? new Date();
|
|
121
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
122
|
+
const iso = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
123
|
+
const addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
|
|
124
|
+
const { window, days, fromDate, toDate } = opts;
|
|
125
|
+
if (window === 'today')
|
|
126
|
+
return [iso(today), iso(today)];
|
|
127
|
+
if (window === 'yesterday') {
|
|
128
|
+
const d = addDays(today, -1);
|
|
129
|
+
return [iso(d), iso(d)];
|
|
130
|
+
}
|
|
131
|
+
if (window === 'week') {
|
|
132
|
+
// 老家 weekday() 周一=0;JS getDay() 周日=0 → 换算。(JS+6)%7 即周一偏移。
|
|
133
|
+
const start = addDays(today, -((today.getDay() + 6) % 7));
|
|
134
|
+
return [iso(start), iso(today)];
|
|
135
|
+
}
|
|
136
|
+
if (window === 'last-week') {
|
|
137
|
+
const thisStart = addDays(today, -((today.getDay() + 6) % 7));
|
|
138
|
+
const end = addDays(thisStart, -1);
|
|
139
|
+
return [iso(addDays(end, -6)), iso(end)];
|
|
140
|
+
}
|
|
141
|
+
if (window === 'month')
|
|
142
|
+
return [iso(new Date(today.getFullYear(), today.getMonth(), 1)), iso(today)];
|
|
143
|
+
if (window === 'last-month') {
|
|
144
|
+
const first = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
145
|
+
const end = addDays(first, -1);
|
|
146
|
+
return [iso(new Date(end.getFullYear(), end.getMonth(), 1)), iso(end)];
|
|
147
|
+
}
|
|
148
|
+
if (days)
|
|
149
|
+
return [iso(addDays(today, -(days - 1))), iso(today)];
|
|
150
|
+
if (fromDate)
|
|
151
|
+
return [fromDate, toDate ?? iso(today)];
|
|
152
|
+
return [iso(today), iso(today)];
|
|
153
|
+
}
|
|
154
|
+
export function parseTimeStr(timeStr) {
|
|
155
|
+
if (!timeStr)
|
|
156
|
+
return nowTime();
|
|
157
|
+
if (/^\d{2}:\d{2}:\d{2}$/.test(timeStr))
|
|
158
|
+
return timeStr;
|
|
159
|
+
const m2 = /^(\d{2}):(\d{2})$/.exec(timeStr);
|
|
160
|
+
if (m2)
|
|
161
|
+
return `${m2[1]}:${m2[2]}:00`;
|
|
162
|
+
return nowTime();
|
|
163
|
+
}
|
|
164
|
+
const LIVE_COLS = 'date, time, exercise_type, duration_minutes, calories_burned, note, reps, category, difficulty, distance_km, avg_heart_rate, set_index, load_kg, steps, max_heart_rate, is_backfill';
|
|
165
|
+
export function addRecord(db, input) {
|
|
166
|
+
const time = parseTimeStr(input.timeStr);
|
|
167
|
+
const info = db.prepare(`INSERT INTO exercise_log (${LIVE_COLS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(input.date, time, input.exerciseType, input.minutes ?? null, input.caloriesBurned, input.note ?? '', input.reps ?? null, input.category ?? null, input.difficulty ?? null, input.distance ?? null, input.heartRate ?? null, input.setIndex ?? null, input.loadKg ?? null, input.steps ?? null, input.maxHeartRate ?? null, input.isBackfill ? 1 : 0);
|
|
168
|
+
const id = Number(info.lastInsertRowid);
|
|
169
|
+
return {
|
|
170
|
+
id,
|
|
171
|
+
record: {
|
|
172
|
+
id, date: input.date, time, exercise_type: input.exerciseType, duration_minutes: input.minutes ?? null,
|
|
173
|
+
calories_burned: input.caloriesBurned, note: input.note ?? '', reps: input.reps ?? null,
|
|
174
|
+
category: input.category ?? null, difficulty: input.difficulty ?? null, distance_km: input.distance ?? null,
|
|
175
|
+
avg_heart_rate: input.heartRate ?? null, max_heart_rate: input.maxHeartRate ?? null,
|
|
176
|
+
steps: input.steps ?? null, set_index: input.setIndex ?? null, load_kg: input.loadKg ?? null,
|
|
177
|
+
is_backfill: input.isBackfill ? 1 : 0,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
const KNOWN_EX_COLS = new Set([
|
|
182
|
+
'date', 'time', 'exercise_type', 'duration_minutes', 'calories_burned', 'note',
|
|
183
|
+
'reps', 'category', 'difficulty', 'distance_km', 'avg_heart_rate', 'max_heart_rate',
|
|
184
|
+
'steps', 'set_index', 'load_kg', 'is_backfill', 'is_deleted', 'xunji_localid', 'xunji_title',
|
|
185
|
+
]);
|
|
186
|
+
export function updateRecord(db, recordId, fields) {
|
|
187
|
+
const id = Number(recordId);
|
|
188
|
+
if (!Number.isInteger(id))
|
|
189
|
+
throw new FetchError('记录 ID 必须是数字');
|
|
190
|
+
const old = db.prepare('SELECT * FROM exercise_log WHERE id = ?').get(id);
|
|
191
|
+
if (!old)
|
|
192
|
+
throw new FetchError(`记录 ID ${id} 不存在`);
|
|
193
|
+
const sets = [];
|
|
194
|
+
const vals = [];
|
|
195
|
+
for (const [col, val] of Object.entries(fields)) {
|
|
196
|
+
if (!KNOWN_EX_COLS.has(col))
|
|
197
|
+
throw new FetchError(`未知字段: ${col}`);
|
|
198
|
+
sets.push(`${col} = ?`);
|
|
199
|
+
vals.push(sql(val));
|
|
200
|
+
}
|
|
201
|
+
if (sets.length) {
|
|
202
|
+
db.prepare(`UPDATE exercise_log SET ${sets.join(', ')}, updated_at = ? WHERE id = ?`)
|
|
203
|
+
.run(...vals, nowStamp(), id);
|
|
204
|
+
}
|
|
205
|
+
const row = db.prepare('SELECT * FROM exercise_log WHERE id = ?').get(id);
|
|
206
|
+
return { old, new: row };
|
|
207
|
+
}
|
|
208
|
+
function softDeleteWhere(db, where, params) {
|
|
209
|
+
const info = db.prepare(`UPDATE exercise_log SET is_deleted = 1, updated_at = ? WHERE ${where} AND COALESCE(is_deleted, 0) = 0`).run(nowStamp(), ...params);
|
|
210
|
+
return Number(info.changes);
|
|
211
|
+
}
|
|
212
|
+
export function deleteRecord(db, recordId) {
|
|
213
|
+
const id = Number(recordId);
|
|
214
|
+
if (!Number.isInteger(id))
|
|
215
|
+
throw new FetchError('记录 ID 必须是数字');
|
|
216
|
+
const row = db.prepare('SELECT * FROM exercise_log WHERE id = ?').get(id);
|
|
217
|
+
if (!row)
|
|
218
|
+
throw new FetchError(`记录 ID ${id} 不存在`);
|
|
219
|
+
db.prepare('UPDATE exercise_log SET is_deleted = 1, updated_at = ? WHERE id = ?').run(nowStamp(), id);
|
|
220
|
+
return row;
|
|
221
|
+
}
|
|
222
|
+
export function deleteDay(db, date) {
|
|
223
|
+
return softDeleteWhere(db, 'date = ?', [date]);
|
|
224
|
+
}
|
|
225
|
+
export function deleteRange(db, fromDate, toDate) {
|
|
226
|
+
return softDeleteWhere(db, 'date BETWEEN ? AND ?', [fromDate, toDate]);
|
|
227
|
+
}
|
|
228
|
+
export function updateDay(db, date, fields) {
|
|
229
|
+
const ids = db.prepare('SELECT id FROM exercise_log WHERE date = ? AND COALESCE(is_deleted, 0) = 0').all(date)
|
|
230
|
+
.map((r) => r.id);
|
|
231
|
+
const pairs = ids.map((id) => updateRecord(db, id, fields));
|
|
232
|
+
return { matched: ids.length, pairs };
|
|
233
|
+
}
|
|
234
|
+
export function copyYesterday(db, targetDate) {
|
|
235
|
+
const target = targetDate ?? todayStr();
|
|
236
|
+
const y = new Date(target + 'T00:00:00');
|
|
237
|
+
y.setDate(y.getDate() - 1);
|
|
238
|
+
const src = `${y.getFullYear()}-${String(y.getMonth() + 1).padStart(2, '0')}-${String(y.getDate()).padStart(2, '0')}`;
|
|
239
|
+
const rows = db.prepare('SELECT * FROM exercise_log WHERE date = ? AND COALESCE(is_deleted, 0) = 0').all(src);
|
|
240
|
+
let copied = 0, skipped = 0;
|
|
241
|
+
const out = [];
|
|
242
|
+
for (const r of rows) {
|
|
243
|
+
const hit = db.prepare('SELECT id FROM exercise_log WHERE date = ? AND exercise_type = ? AND calories_burned = ? AND duration_minutes = ? AND COALESCE(is_deleted, 0) = 0 LIMIT 1').get(target, sql(r.exercise_type), sql(r.calories_burned), sql(r.duration_minutes));
|
|
244
|
+
if (hit) {
|
|
245
|
+
skipped++;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const { id } = addRecord(db, {
|
|
249
|
+
date: target, exerciseType: String(r.exercise_type), caloriesBurned: Number(r.calories_burned),
|
|
250
|
+
minutes: r.duration_minutes, timeStr: r.time, note: String(r.note ?? ''),
|
|
251
|
+
reps: r.reps, category: r.category, difficulty: r.difficulty,
|
|
252
|
+
distance: r.distance_km, heartRate: r.avg_heart_rate,
|
|
253
|
+
maxHeartRate: r.max_heart_rate, steps: r.steps,
|
|
254
|
+
setIndex: r.set_index, loadKg: r.load_kg,
|
|
255
|
+
});
|
|
256
|
+
copied++;
|
|
257
|
+
out.push(db.prepare('SELECT * FROM exercise_log WHERE id = ?').get(id));
|
|
258
|
+
}
|
|
259
|
+
return { copied, skipped, rows: out };
|
|
260
|
+
}
|
|
261
|
+
export function batchAdd(db, items) {
|
|
262
|
+
const ids = [];
|
|
263
|
+
for (const it of items)
|
|
264
|
+
ids.push(addRecord(db, it).id);
|
|
265
|
+
return { added: ids.length, ids };
|
|
266
|
+
}
|
|
267
|
+
export function listWindow(db, start, end) {
|
|
268
|
+
return db.prepare('SELECT * FROM exercise_log WHERE date BETWEEN ? AND ? AND COALESCE(is_deleted, 0) = 0 ORDER BY date, time').all(start, end);
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=exercise.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exercise.js","sourceRoot":"","sources":["../../src/fetch/exercise.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** T4 #23 · goal_manager 取数+状态写(对照老家 scripts/goal_manager.py)。
|
|
2
|
+
*
|
|
3
|
+
* T3 范式:失败抛 FetchError,不 print(打印归 T11 CLI)。
|
|
4
|
+
* 一处有意偏离:老家无 daily_goal 行时 UPDATE 0 行后取 row['id'] 直接崩溃;
|
|
5
|
+
* TS 线先 ensureGoalRow(INSERT OR IGNORE 默认行),崩溃转显式可运行语义。
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
8
|
+
export interface PausedState {
|
|
9
|
+
paused: boolean;
|
|
10
|
+
pausedAt: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface PauseResult {
|
|
13
|
+
id: number;
|
|
14
|
+
updatedAt: string | null;
|
|
15
|
+
rowsAffected: number;
|
|
16
|
+
paused: true;
|
|
17
|
+
note: string;
|
|
18
|
+
restoreHint: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ResumeResult {
|
|
21
|
+
id: number;
|
|
22
|
+
updatedAt: string | null;
|
|
23
|
+
rowsAffected: number;
|
|
24
|
+
resumeState: string;
|
|
25
|
+
resumedAt: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** 单例行兜底(INSERT OR IGNORE,全默认列)。 */
|
|
28
|
+
export declare function ensureGoalRow(db: DatabaseSync): void;
|
|
29
|
+
export declare function getPausedState(db: DatabaseSync): PausedState;
|
|
30
|
+
export declare function pauseAllGoals(db: DatabaseSync): PauseResult;
|
|
31
|
+
export interface SetWeightGoalInput {
|
|
32
|
+
kg: unknown;
|
|
33
|
+
deadline?: unknown;
|
|
34
|
+
startKg?: unknown;
|
|
35
|
+
startDate?: unknown;
|
|
36
|
+
}
|
|
37
|
+
export interface SetWeightGoalResult {
|
|
38
|
+
weightGoal: number;
|
|
39
|
+
deadline: string | null;
|
|
40
|
+
startKg: number | null;
|
|
41
|
+
startDate: string | null;
|
|
42
|
+
updatedAt: string | null;
|
|
43
|
+
rowsAffected: number;
|
|
44
|
+
}
|
|
45
|
+
/** 定体重目标(对照老家 render_goal_weight --live:目标 kg 必填,截止/起点可选;ISO 日期校验)。 */
|
|
46
|
+
export declare function setWeightGoal(db: DatabaseSync, input: SetWeightGoalInput): SetWeightGoalResult;
|
|
47
|
+
export declare function resumeAllGoals(db: DatabaseSync): ResumeResult;
|
|
48
|
+
//# sourceMappingURL=goal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal.d.ts","sourceRoot":"","sources":["../../src/fetch/goal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,IAAI,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,oCAAoC;AACpC,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAEpD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAM5D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAiB3D;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CAwB9F;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,YAAY,CAgB7D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { FetchError } from './errors.js';
|
|
2
|
+
/** 单例行兜底(INSERT OR IGNORE,全默认列)。 */
|
|
3
|
+
export function ensureGoalRow(db) {
|
|
4
|
+
db.prepare('INSERT OR IGNORE INTO daily_goal (id) VALUES (1)').run();
|
|
5
|
+
}
|
|
6
|
+
export function getPausedState(db) {
|
|
7
|
+
const row = db.prepare('SELECT goal_paused, updated_at FROM daily_goal WHERE id = 1').get();
|
|
8
|
+
if (!row)
|
|
9
|
+
return { paused: false, pausedAt: null };
|
|
10
|
+
return { paused: row.goal_paused === 1, pausedAt: row.updated_at };
|
|
11
|
+
}
|
|
12
|
+
export function pauseAllGoals(db) {
|
|
13
|
+
ensureGoalRow(db);
|
|
14
|
+
const upd = db
|
|
15
|
+
.prepare('UPDATE daily_goal SET goal_paused = 1, updated_at = CURRENT_TIMESTAMP WHERE id = 1')
|
|
16
|
+
.run();
|
|
17
|
+
const row = db.prepare('SELECT id, updated_at FROM daily_goal WHERE id = 1').get();
|
|
18
|
+
if (!row)
|
|
19
|
+
throw new FetchError('pause 后 daily_goal#1 缺失');
|
|
20
|
+
return {
|
|
21
|
+
id: row.id,
|
|
22
|
+
updatedAt: row.updated_at,
|
|
23
|
+
rowsAffected: Number(upd.changes),
|
|
24
|
+
paused: true,
|
|
25
|
+
note: '记录照常,仅目标暂停(完成度显示不计入暂停期)',
|
|
26
|
+
restoreHint: '说「重启所有目标」即可恢复',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** 定体重目标(对照老家 render_goal_weight --live:目标 kg 必填,截止/起点可选;ISO 日期校验)。 */
|
|
30
|
+
export function setWeightGoal(db, input) {
|
|
31
|
+
const kg = typeof input.kg === 'number' ? input.kg : Number(String(input.kg ?? '').trim());
|
|
32
|
+
if (!Number.isFinite(kg) || kg <= 0 || kg > 500)
|
|
33
|
+
throw new FetchError('体重目标非法:' + JSON.stringify(input.kg) + '(须 0..500 正数 kg)');
|
|
34
|
+
const iso = (v, field) => {
|
|
35
|
+
if (v === undefined || v === null || v === '')
|
|
36
|
+
return null;
|
|
37
|
+
const s = String(v);
|
|
38
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(s))
|
|
39
|
+
throw new FetchError(field + ' 非法(须 YYYY-MM-DD):' + s);
|
|
40
|
+
return s;
|
|
41
|
+
};
|
|
42
|
+
const deadline = iso(input.deadline, 'deadline');
|
|
43
|
+
const startDate = iso(input.startDate, 'startDate');
|
|
44
|
+
let startKg = null;
|
|
45
|
+
if (input.startKg !== undefined && input.startKg !== null && input.startKg !== '') {
|
|
46
|
+
startKg = typeof input.startKg === 'number' ? input.startKg : Number(String(input.startKg).trim());
|
|
47
|
+
if (!Number.isFinite(startKg) || startKg <= 0 || startKg > 500)
|
|
48
|
+
throw new FetchError('起点体重非法:' + JSON.stringify(input.startKg));
|
|
49
|
+
}
|
|
50
|
+
ensureGoalRow(db);
|
|
51
|
+
const upd = db
|
|
52
|
+
.prepare('UPDATE daily_goal SET weight_goal = ?, goal_deadline = ?, start_weight = ?, start_date = ?, updated_at = CURRENT_TIMESTAMP WHERE id = 1')
|
|
53
|
+
.run(kg, deadline, startKg, startDate);
|
|
54
|
+
const row = db.prepare('SELECT updated_at FROM daily_goal WHERE id = 1').get();
|
|
55
|
+
return { weightGoal: kg, deadline, startKg, startDate, updatedAt: row?.updated_at ?? null, rowsAffected: Number(upd.changes) };
|
|
56
|
+
}
|
|
57
|
+
export function resumeAllGoals(db) {
|
|
58
|
+
ensureGoalRow(db);
|
|
59
|
+
const upd = db
|
|
60
|
+
.prepare('UPDATE daily_goal SET goal_paused = 0, updated_at = CURRENT_TIMESTAMP WHERE id = 1')
|
|
61
|
+
.run();
|
|
62
|
+
const row = db.prepare('SELECT id, updated_at FROM daily_goal WHERE id = 1').get();
|
|
63
|
+
if (!row)
|
|
64
|
+
throw new FetchError('resume 后 daily_goal#1 缺失');
|
|
65
|
+
return {
|
|
66
|
+
id: row.id,
|
|
67
|
+
updatedAt: row.updated_at,
|
|
68
|
+
rowsAffected: Number(upd.changes),
|
|
69
|
+
resumeState: '正常(未暂停)',
|
|
70
|
+
resumedAt: row.updated_at,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=goal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal.js","sourceRoot":"","sources":["../../src/fetch/goal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** T4 #23 · goal_history 取数(对照老家 scripts/goal_history.py)。
|
|
2
|
+
*
|
|
3
|
+
* 无独立历史表:food_log 按日聚合 vs daily_goal 单行目标,80%-120% 判定带。
|
|
4
|
+
* today 可注入(默认 UTC 日,与 T3 todayStr 同口径,便于单测钉死)。
|
|
5
|
+
*/
|
|
6
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
7
|
+
export type DayStatus = '完成' | '未完成' | '无记录';
|
|
8
|
+
export interface DayGoalStatus {
|
|
9
|
+
date: string;
|
|
10
|
+
calorieActual: number;
|
|
11
|
+
calorieGoal: number | null;
|
|
12
|
+
pct: number | null;
|
|
13
|
+
status: DayStatus;
|
|
14
|
+
}
|
|
15
|
+
export interface GoalHistory {
|
|
16
|
+
goalHistory: DayGoalStatus[];
|
|
17
|
+
completedCount: number;
|
|
18
|
+
incompleteCount: number;
|
|
19
|
+
calorieGoal: number | null;
|
|
20
|
+
}
|
|
21
|
+
export declare function todayISO(): string;
|
|
22
|
+
export declare function shiftISODate(iso: string, deltaDays: number): string;
|
|
23
|
+
export declare function listCompletedGoals(db: DatabaseSync, days?: number, today?: string): GoalHistory;
|
|
24
|
+
//# sourceMappingURL=goalHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goalHistory.d.ts","sourceRoot":"","sources":["../../src/fetch/goalHistory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAID,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAInE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,SAAK,EAAE,KAAK,GAAE,MAAmB,GAAG,WAAW,CAoCvG"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { FetchError } from './errors.js';
|
|
2
|
+
const round1 = (n) => Math.round(n * 10) / 10;
|
|
3
|
+
export function todayISO() {
|
|
4
|
+
return new Date().toISOString().slice(0, 10);
|
|
5
|
+
}
|
|
6
|
+
export function shiftISODate(iso, deltaDays) {
|
|
7
|
+
const t = Date.parse(iso + 'T12:00:00Z');
|
|
8
|
+
if (Number.isNaN(t))
|
|
9
|
+
throw new FetchError('日期非法: ' + iso);
|
|
10
|
+
return new Date(t + deltaDays * 86400000).toISOString().slice(0, 10);
|
|
11
|
+
}
|
|
12
|
+
export function listCompletedGoals(db, days = 30, today = todayISO()) {
|
|
13
|
+
if (!Number.isInteger(days) || days < 1)
|
|
14
|
+
throw new FetchError('days 须为正整数: ' + String(days));
|
|
15
|
+
const end = today;
|
|
16
|
+
const start = shiftISODate(today, -(days - 1));
|
|
17
|
+
const goal = db
|
|
18
|
+
.prepare('SELECT calorie_goal FROM daily_goal WHERE id = 1')
|
|
19
|
+
.get();
|
|
20
|
+
const calGoal = goal?.calorie_goal ?? null;
|
|
21
|
+
const rows = db
|
|
22
|
+
.prepare('SELECT date, COALESCE(SUM(calories), 0) AS cal FROM food_log WHERE date BETWEEN ? AND ? GROUP BY date')
|
|
23
|
+
.all(start, end);
|
|
24
|
+
const actual = new Map(rows.map((r) => [r.date, round1(r.cal)]));
|
|
25
|
+
const history = [];
|
|
26
|
+
let completed = 0;
|
|
27
|
+
let incomplete = 0;
|
|
28
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
29
|
+
const d = shiftISODate(today, -i);
|
|
30
|
+
const cal = actual.get(d);
|
|
31
|
+
if (cal === undefined) {
|
|
32
|
+
history.push({ date: d, calorieActual: 0, calorieGoal: calGoal, pct: 0, status: '无记录' });
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (calGoal) {
|
|
36
|
+
const pct = round1((cal / calGoal) * 100);
|
|
37
|
+
const status = pct >= 80 && pct <= 120 ? '完成' : '未完成';
|
|
38
|
+
if (status === '完成')
|
|
39
|
+
completed += 1;
|
|
40
|
+
else
|
|
41
|
+
incomplete += 1;
|
|
42
|
+
history.push({ date: d, calorieActual: cal, calorieGoal: calGoal, pct, status });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
incomplete += 1;
|
|
46
|
+
history.push({ date: d, calorieActual: cal, calorieGoal: calGoal, pct: null, status: '未完成' });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return { goalHistory: history, completedCount: completed, incompleteCount: incomplete, calorieGoal: calGoal };
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=goalHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goalHistory.js","sourceRoot":"","sources":["../../src/fetch/goalHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** T6 #25 · 取数:近日每日摄入聚合 vs 目标(老家 calorie_history.py 同口径,纯取数不打印)。
|
|
2
|
+
* 目标值经 T4 getNutritionGoal 单源读取。
|
|
3
|
+
*/
|
|
4
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
export interface DayIntake {
|
|
6
|
+
date: string;
|
|
7
|
+
calories: number;
|
|
8
|
+
protein: number;
|
|
9
|
+
carbs: number;
|
|
10
|
+
fat: number;
|
|
11
|
+
/** 剩余 = 目标 − 当日;目标未设时为 null */
|
|
12
|
+
remaining: number | null;
|
|
13
|
+
/** +N卡 / 达标 / 未设目标(老家同文案) */
|
|
14
|
+
status: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CalorieHistory {
|
|
17
|
+
days: number;
|
|
18
|
+
goal: number | null;
|
|
19
|
+
rows: DayIntake[];
|
|
20
|
+
}
|
|
21
|
+
/** 最近 N 天每日摄入(food_log 按 date 聚合倒序);空库返回空 rows,调用方阻断提示,不返“正常空数据”。 */
|
|
22
|
+
export declare function getCalorieHistory(db: DatabaseSync, days?: number, now?: Date): CalorieHistory;
|
|
23
|
+
/** 本地体重序列(跨技能合并的上游输入之一;food/weight 双序列对齐的 weight 侧)。 */
|
|
24
|
+
export declare function weightSeries(db: DatabaseSync): {
|
|
25
|
+
date: string;
|
|
26
|
+
weight_kg: number;
|
|
27
|
+
}[];
|
|
28
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../src/fetch/history.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAMD,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,SAAI,EAAE,GAAG,OAAa,GAAG,cAAc,CAmB9F;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,EAAE,EAAE,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,CAKpF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getNutritionGoal } from './nutritionGoal.js';
|
|
2
|
+
function fmtDate(d) {
|
|
3
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
4
|
+
}
|
|
5
|
+
/** 最近 N 天每日摄入(food_log 按 date 聚合倒序);空库返回空 rows,调用方阻断提示,不返“正常空数据”。 */
|
|
6
|
+
export function getCalorieHistory(db, days = 7, now = new Date()) {
|
|
7
|
+
const start = new Date(now);
|
|
8
|
+
start.setDate(start.getDate() - days);
|
|
9
|
+
const rows = db
|
|
10
|
+
.prepare(`SELECT date, SUM(calories) AS calories, SUM(protein) AS protein, SUM(carbs) AS carbs, SUM(fat) AS fat
|
|
11
|
+
FROM food_log WHERE date >= ? GROUP BY date ORDER BY date DESC`)
|
|
12
|
+
.all(fmtDate(start));
|
|
13
|
+
const goal = getNutritionGoal(db)?.calorie_goal ?? null;
|
|
14
|
+
return {
|
|
15
|
+
days,
|
|
16
|
+
goal,
|
|
17
|
+
rows: rows.map((r) => {
|
|
18
|
+
if (goal === null)
|
|
19
|
+
return { ...r, remaining: null, status: '未设目标' };
|
|
20
|
+
const remaining = Math.round(goal - r.calories);
|
|
21
|
+
return { ...r, remaining, status: remaining !== 0 ? `${remaining >= 0 ? '+' : ''}${remaining}卡` : '达标' };
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** 本地体重序列(跨技能合并的上游输入之一;food/weight 双序列对齐的 weight 侧)。 */
|
|
26
|
+
export function weightSeries(db) {
|
|
27
|
+
return db.prepare('SELECT date, weight_kg FROM weight_log ORDER BY date').all();
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/fetch/history.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAoBtD,SAAS,OAAO,CAAC,CAAO;IACtB,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACnH,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,iBAAiB,CAAC,EAAgB,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IAC5E,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;sEACgE,CACjE;SACA,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAsF,CAAC;IAC5G,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC;IACxD,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACnB,IAAI,IAAI,KAAK,IAAI;gBAAE,OAAO,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YACpE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;YAChD,OAAO,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3G,CAAC,CAAC;KACH,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAAC,EAAgB;IAC3C,OAAO,EAAE,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAC,GAAG,EAG1E,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** 取数层 barrel:T3 饮食 / 体重 / 运动 / 身体 / envelope 结构段 + T6 导入 / 历史 / 跨技能只读。 */
|
|
2
|
+
export { FetchError } from './errors.js';
|
|
3
|
+
export * from './diet.js';
|
|
4
|
+
export * from './weight.js';
|
|
5
|
+
export * from './exercise.js';
|
|
6
|
+
export * from './body.js';
|
|
7
|
+
export { CALORIE_SKILL, calorieKey, fetchPayload, KEYS } from './shapes.js';
|
|
8
|
+
export type { FetchPayload } from './shapes.js';
|
|
9
|
+
export { REQUIRED_FIELDS, OPTIONAL_FIELDS, NUMERIC_FIELDS, validateRecord } from './validate.js';
|
|
10
|
+
export type { ValidationResult } from './validate.js';
|
|
11
|
+
export { readJsonl, dedupeKey, checkDuplicate, importProducts, validateFile, dedupeReport, exportBySource, } from './batch.js';
|
|
12
|
+
export type { DuplicatePolicy, ImportStats, ImportResult, ImportFailure, ImportOptions } from './batch.js';
|
|
13
|
+
export { getCalorieHistory, weightSeries } from './history.js';
|
|
14
|
+
export type { DayIntake, CalorieHistory } from './history.js';
|
|
15
|
+
export { readSkill, requireOk } from './cross-skill.js';
|
|
16
|
+
export type { SkillEnvelope, ReadSkillOptions } from './cross-skill.js';
|
|
17
|
+
export { getProfile, setProfile, setActivityLevel, updateProfile, normalizeActivityLevel, normalizeGender, PROFILE_UPDATABLE, ACTIVITY_ALIASES } from './profile.js';
|
|
18
|
+
export type { ProfileRow, SetProfileInput } from './profile.js';
|
|
19
|
+
export { DEFAULT_CATALOG_PATH, loadCatalog, suggestSimilar, verifyMovementName, verifyMany } from './xunji-catalog.js';
|
|
20
|
+
export type { VerifyResult } from './xunji-catalog.js';
|
|
21
|
+
export { collectPlanNames, auditPlanNames } from './audit.js';
|
|
22
|
+
export type { AuditStatus, AuditReport } from './audit.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fetch/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACjG,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACL,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3G,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,sBAAsB,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrK,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACvH,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|