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,16 @@
|
|
|
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
|
+
// T6 #25 · 批量导入 / 近日 history / 跨技能只读 / 训记 catalog / 计划审计
|
|
9
|
+
export { REQUIRED_FIELDS, OPTIONAL_FIELDS, NUMERIC_FIELDS, validateRecord } from './validate.js';
|
|
10
|
+
export { readJsonl, dedupeKey, checkDuplicate, importProducts, validateFile, dedupeReport, exportBySource, } from './batch.js';
|
|
11
|
+
export { getCalorieHistory, weightSeries } from './history.js';
|
|
12
|
+
export { readSkill, requireOk } from './cross-skill.js';
|
|
13
|
+
export { getProfile, setProfile, setActivityLevel, updateProfile, normalizeActivityLevel, normalizeGender, PROFILE_UPDATABLE, ACTIVITY_ALIASES } from './profile.js';
|
|
14
|
+
export { DEFAULT_CATALOG_PATH, loadCatalog, suggestSimilar, verifyMovementName, verifyMany } from './xunji-catalog.js';
|
|
15
|
+
export { collectPlanNames, auditPlanNames } from './audit.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","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;AAE5E,yDAAyD;AACzD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEjG,OAAO,EACL,SAAS,EACT,SAAS,EACT,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,sBAAsB,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErK,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEvH,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/** T4 #23 · nutrition_goal 取数+写数(对照老家 scripts/nutrition_goal.py)。
|
|
2
|
+
*
|
|
3
|
+
* 读:getNutritionGoal(无行回 null,老家 Row-or-None 同义)。
|
|
4
|
+
* 写:setNutritionGoal(4 参必填 + 饮水可选 + 自洽 diff 回传,不 print)。
|
|
5
|
+
* 算:recommendNutritionGoal / recommendWaterGoal(纯算式对照;activity 系数与
|
|
6
|
+
* 体重缺省走注入(T5 analysis / T3 weight_log 归属,缺省标记 missing,不静默编造)。
|
|
7
|
+
*/
|
|
8
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
9
|
+
export interface NutritionGoalRow {
|
|
10
|
+
id: number;
|
|
11
|
+
calorie_goal: number;
|
|
12
|
+
protein_goal: number | null;
|
|
13
|
+
carbs_goal: number | null;
|
|
14
|
+
fat_goal: number | null;
|
|
15
|
+
weight_goal: number | null;
|
|
16
|
+
goal_deadline: string | null;
|
|
17
|
+
water_goal: number | null;
|
|
18
|
+
updated_at: string | null;
|
|
19
|
+
}
|
|
20
|
+
export interface SetGoalInput {
|
|
21
|
+
calorie: unknown;
|
|
22
|
+
protein: unknown;
|
|
23
|
+
carbs: unknown;
|
|
24
|
+
fat: unknown;
|
|
25
|
+
water?: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface SetGoalResult {
|
|
28
|
+
calorieGoal: number;
|
|
29
|
+
proteinGoal: number;
|
|
30
|
+
carbsGoal: number;
|
|
31
|
+
fatGoal: number;
|
|
32
|
+
waterGoal: number | null;
|
|
33
|
+
diffKcal: number;
|
|
34
|
+
consistent: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function getNutritionGoal(db: DatabaseSync): NutritionGoalRow | null;
|
|
37
|
+
export declare function setNutritionGoal(db: DatabaseSync, input: SetGoalInput): SetGoalResult;
|
|
38
|
+
export declare const NUTRI_PROFILES: {
|
|
39
|
+
readonly cut: {
|
|
40
|
+
readonly calorieAdj: -500;
|
|
41
|
+
readonly proteinGPerKg: 2;
|
|
42
|
+
readonly waterMlPerKg: 35;
|
|
43
|
+
readonly fatPct: 0.25;
|
|
44
|
+
};
|
|
45
|
+
readonly maintain: {
|
|
46
|
+
readonly calorieAdj: 0;
|
|
47
|
+
readonly proteinGPerKg: 1.6;
|
|
48
|
+
readonly waterMlPerKg: 30;
|
|
49
|
+
readonly fatPct: 0.3;
|
|
50
|
+
};
|
|
51
|
+
readonly bulk: {
|
|
52
|
+
readonly calorieAdj: 400;
|
|
53
|
+
readonly proteinGPerKg: 1.8;
|
|
54
|
+
readonly waterMlPerKg: 30;
|
|
55
|
+
readonly fatPct: 0.25;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
export type NutriProfile = keyof typeof NUTRI_PROFILES;
|
|
59
|
+
export declare const NUTRI_PROFILE_LABELS: Record<NutriProfile, string>;
|
|
60
|
+
export declare const NUTRI_PROFILE_WEEKLY_RATE: Record<NutriProfile, number>;
|
|
61
|
+
export interface RecommendInput {
|
|
62
|
+
profile?: NutriProfile;
|
|
63
|
+
weightKg?: number | null;
|
|
64
|
+
heightCm?: number | null;
|
|
65
|
+
age?: number | null;
|
|
66
|
+
gender?: string | null;
|
|
67
|
+
activityFactor?: number | null;
|
|
68
|
+
}
|
|
69
|
+
export interface RecommendResult {
|
|
70
|
+
profile: NutriProfile;
|
|
71
|
+
profileLabel: string;
|
|
72
|
+
tdee: number;
|
|
73
|
+
bmr: number;
|
|
74
|
+
calorieGoal: number;
|
|
75
|
+
proteinGoal: number;
|
|
76
|
+
carbsGoal: number;
|
|
77
|
+
fatGoal: number;
|
|
78
|
+
waterGoal: number;
|
|
79
|
+
weeklyRateKg: number;
|
|
80
|
+
basis: {
|
|
81
|
+
weightKg: number;
|
|
82
|
+
heightCm: number;
|
|
83
|
+
age: number;
|
|
84
|
+
gender: string;
|
|
85
|
+
};
|
|
86
|
+
planReasons: string[];
|
|
87
|
+
missing: string[];
|
|
88
|
+
selfCheck: {
|
|
89
|
+
calculatedKcal: number;
|
|
90
|
+
diffKcal: number;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export declare function latestWeightKg(db: DatabaseSync): number | null;
|
|
94
|
+
export declare function recommendNutritionGoal(db: DatabaseSync, opts?: RecommendInput): RecommendResult;
|
|
95
|
+
export interface WaterRecommendInput {
|
|
96
|
+
weightKg?: number | null;
|
|
97
|
+
season?: '夏' | '冬' | null;
|
|
98
|
+
month?: number | null;
|
|
99
|
+
}
|
|
100
|
+
export declare function recommendWaterGoal(db: DatabaseSync, opts?: WaterRecommendInput): {
|
|
101
|
+
weightKg: number;
|
|
102
|
+
season: '夏' | '冬';
|
|
103
|
+
mlPerKg: number;
|
|
104
|
+
recommendedWaterMl: number;
|
|
105
|
+
oldWaterGoal: number | null;
|
|
106
|
+
basis: string;
|
|
107
|
+
};
|
|
108
|
+
export declare function updateWaterGoal(db: DatabaseSync, waterGoal: unknown): {
|
|
109
|
+
id: number;
|
|
110
|
+
updatedAt: string | null;
|
|
111
|
+
rowsAffected: number;
|
|
112
|
+
oldWaterGoal: number | null;
|
|
113
|
+
newWaterGoal: number;
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=nutritionGoal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nutritionGoal.d.ts","sourceRoot":"","sources":["../../src/fetch/nutritionGoal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { FetchError } from './errors.js';
|
|
2
|
+
function toInt(v, field) {
|
|
3
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' && v.trim() !== '' ? Number(v) : NaN;
|
|
4
|
+
if (!Number.isFinite(n))
|
|
5
|
+
throw new FetchError(field + '必须是数字');
|
|
6
|
+
return Math.trunc(n);
|
|
7
|
+
}
|
|
8
|
+
export function getNutritionGoal(db) {
|
|
9
|
+
const row = db.prepare('SELECT * FROM daily_goal WHERE id = 1').get();
|
|
10
|
+
return row ?? null;
|
|
11
|
+
}
|
|
12
|
+
export function setNutritionGoal(db, input) {
|
|
13
|
+
if (input.protein === undefined || input.carbs === undefined || input.fat === undefined) {
|
|
14
|
+
throw new FetchError('goal 必须 4 个参数全传(热量/蛋白/碳水/脂肪)');
|
|
15
|
+
}
|
|
16
|
+
const calorie = toInt(input.calorie, '热量目标');
|
|
17
|
+
const protein = toInt(input.protein, '蛋白质目标');
|
|
18
|
+
const carbs = toInt(input.carbs, '碳水目标');
|
|
19
|
+
const fat = toInt(input.fat, '脂肪目标');
|
|
20
|
+
if (calorie <= 0)
|
|
21
|
+
throw new FetchError('热量目标必须为正数');
|
|
22
|
+
if (protein < 0 || carbs < 0 || fat < 0)
|
|
23
|
+
throw new FetchError('营养目标不能为负数');
|
|
24
|
+
let water = null;
|
|
25
|
+
if (input.water !== undefined && input.water !== null) {
|
|
26
|
+
water = toInt(input.water, '饮水目标');
|
|
27
|
+
if (water < 0)
|
|
28
|
+
throw new FetchError('饮水目标不能为负数');
|
|
29
|
+
}
|
|
30
|
+
const diff = protein * 4 + carbs * 4 + fat * 9 - calorie;
|
|
31
|
+
if (water !== null) {
|
|
32
|
+
db.prepare('INSERT OR REPLACE INTO daily_goal (id, calorie_goal, protein_goal, carbs_goal, fat_goal, water_goal, updated_at)' +
|
|
33
|
+
' VALUES (1, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)').run(calorie, protein, carbs, fat, water);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
db.prepare('INSERT OR REPLACE INTO daily_goal (id, calorie_goal, protein_goal, carbs_goal, fat_goal, updated_at)' +
|
|
37
|
+
' VALUES (1, ?, ?, ?, ?, CURRENT_TIMESTAMP)').run(calorie, protein, carbs, fat);
|
|
38
|
+
}
|
|
39
|
+
const row = getNutritionGoal(db);
|
|
40
|
+
return {
|
|
41
|
+
calorieGoal: calorie,
|
|
42
|
+
proteinGoal: protein,
|
|
43
|
+
carbsGoal: carbs,
|
|
44
|
+
fatGoal: fat,
|
|
45
|
+
waterGoal: row?.water_goal ?? water,
|
|
46
|
+
diffKcal: diff,
|
|
47
|
+
consistent: Math.abs(diff) <= 50,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export const NUTRI_PROFILES = {
|
|
51
|
+
cut: { calorieAdj: -500, proteinGPerKg: 2.0, waterMlPerKg: 35, fatPct: 0.25 },
|
|
52
|
+
maintain: { calorieAdj: 0, proteinGPerKg: 1.6, waterMlPerKg: 30, fatPct: 0.3 },
|
|
53
|
+
bulk: { calorieAdj: 400, proteinGPerKg: 1.8, waterMlPerKg: 30, fatPct: 0.25 },
|
|
54
|
+
};
|
|
55
|
+
export const NUTRI_PROFILE_LABELS = { cut: '减脂', maintain: '维持', bulk: '增肌' };
|
|
56
|
+
export const NUTRI_PROFILE_WEEKLY_RATE = { cut: 0.5, maintain: 0.0, bulk: 0.4 };
|
|
57
|
+
export function latestWeightKg(db) {
|
|
58
|
+
const row = db
|
|
59
|
+
.prepare('SELECT weight_kg FROM weight_log ORDER BY date DESC, id DESC LIMIT 1')
|
|
60
|
+
.get();
|
|
61
|
+
return row?.weight_kg ?? null;
|
|
62
|
+
}
|
|
63
|
+
export function recommendNutritionGoal(db, opts = {}) {
|
|
64
|
+
const profile = opts.profile ?? 'cut';
|
|
65
|
+
const p = NUTRI_PROFILES[profile];
|
|
66
|
+
if (!p)
|
|
67
|
+
throw new FetchError('profile 非法(cut/maintain/bulk): ' + String(opts.profile));
|
|
68
|
+
const missing = [];
|
|
69
|
+
let weight = opts.weightKg ?? latestWeightKg(db);
|
|
70
|
+
const prof = db
|
|
71
|
+
.prepare('SELECT age, gender, height_cm, activity_level FROM user_profile WHERE id = 1')
|
|
72
|
+
.get();
|
|
73
|
+
let height = opts.heightCm ?? prof?.height_cm ?? null;
|
|
74
|
+
let age = opts.age ?? prof?.age ?? null;
|
|
75
|
+
let gender = opts.gender ?? prof?.gender ?? null;
|
|
76
|
+
if (!prof)
|
|
77
|
+
missing.push('年龄', '性别', '身高');
|
|
78
|
+
else {
|
|
79
|
+
if (prof.age === null || prof.age === undefined)
|
|
80
|
+
missing.push('年龄');
|
|
81
|
+
if (!prof.gender)
|
|
82
|
+
missing.push('性别');
|
|
83
|
+
if (prof.height_cm === null || prof.height_cm === undefined)
|
|
84
|
+
missing.push('身高');
|
|
85
|
+
}
|
|
86
|
+
if (weight === null || weight === undefined)
|
|
87
|
+
missing.push('体重');
|
|
88
|
+
const w = weight ?? 70.0;
|
|
89
|
+
const h = height ?? 175.0;
|
|
90
|
+
const a = age ?? 30;
|
|
91
|
+
const g = gender ?? 'male';
|
|
92
|
+
const factor = opts.activityFactor ?? 1.55;
|
|
93
|
+
const bmr = 10 * w + 6.25 * h - 5 * a + (g === 'male' ? 5 : -161);
|
|
94
|
+
const tdee = bmr * factor;
|
|
95
|
+
const cal = Math.trunc(tdee + p.calorieAdj);
|
|
96
|
+
const protein = Math.trunc(w * p.proteinGPerKg);
|
|
97
|
+
const fat = Math.trunc((cal * p.fatPct) / 9);
|
|
98
|
+
const carbs = Math.max(Math.trunc((cal - protein * 4 - fat * 9) / 4), 0);
|
|
99
|
+
const water = Math.trunc(w * p.waterMlPerKg);
|
|
100
|
+
const calculated = protein * 4 + carbs * 4 + fat * 9;
|
|
101
|
+
const diff = calculated - cal;
|
|
102
|
+
const reasons = [
|
|
103
|
+
NUTRI_PROFILE_LABELS[profile] + '模板:TDEE ' + Math.trunc(tdee) + ' 卡 × 热量调整 ' + (p.calorieAdj >= 0 ? '+' : '') + p.calorieAdj + ' 卡 → 每日 ' + cal + ' 卡',
|
|
104
|
+
'蛋白 ' + protein + ' g(体重 ' + w.toFixed(1) + ' kg × ' + p.proteinGPerKg + ' g/kg)',
|
|
105
|
+
'脂肪 ' + fat + ' g(占热量 ' + Math.trunc(p.fatPct * 100) + '%)· 碳水 ' + carbs + ' g(余量)',
|
|
106
|
+
'饮水 ' + water + ' ml(体重 × ' + p.waterMlPerKg + ' ml/kg)',
|
|
107
|
+
'预计每周减重速率 ' + NUTRI_PROFILE_WEEKLY_RATE[profile].toFixed(1) + ' kg(Δ' + cal + ' - TDEE ' + Math.trunc(tdee) + ')',
|
|
108
|
+
];
|
|
109
|
+
if (Math.abs(diff) > 50)
|
|
110
|
+
reasons.push('⚠️ 自洽性校验:宏量换算 ' + calculated + ' 卡,与热量目标差 ' + (diff >= 0 ? '+' : '') + diff + ' 卡(>50 建议复核)');
|
|
111
|
+
return {
|
|
112
|
+
profile,
|
|
113
|
+
profileLabel: NUTRI_PROFILE_LABELS[profile],
|
|
114
|
+
tdee: Math.trunc(tdee),
|
|
115
|
+
bmr: Math.trunc(bmr),
|
|
116
|
+
calorieGoal: cal,
|
|
117
|
+
proteinGoal: protein,
|
|
118
|
+
carbsGoal: carbs,
|
|
119
|
+
fatGoal: fat,
|
|
120
|
+
waterGoal: water,
|
|
121
|
+
weeklyRateKg: NUTRI_PROFILE_WEEKLY_RATE[profile],
|
|
122
|
+
basis: { weightKg: Math.round(w * 10) / 10, heightCm: h, age: a, gender: g },
|
|
123
|
+
planReasons: reasons,
|
|
124
|
+
missing,
|
|
125
|
+
selfCheck: { calculatedKcal: calculated, diffKcal: diff },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export function recommendWaterGoal(db, opts = {}) {
|
|
129
|
+
const w = opts.weightKg ?? latestWeightKg(db) ?? 70.0;
|
|
130
|
+
const month = opts.month ?? new Date().getMonth() + 1;
|
|
131
|
+
const season = opts.season ?? (month >= 6 && month <= 9 ? '夏' : '冬');
|
|
132
|
+
const mlPerKg = season === '夏' ? 35 : 30;
|
|
133
|
+
const old = getNutritionGoal(db)?.water_goal ?? null;
|
|
134
|
+
return {
|
|
135
|
+
weightKg: Math.round(w * 10) / 10,
|
|
136
|
+
season,
|
|
137
|
+
mlPerKg,
|
|
138
|
+
recommendedWaterMl: Math.trunc(w * mlPerKg),
|
|
139
|
+
oldWaterGoal: old,
|
|
140
|
+
basis: '体重 ' + w.toFixed(1) + ' kg × ' + mlPerKg + ' ml/kg(' + (season === '夏' ? '夏季偏高' : '冬季常规') + ')',
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
export function updateWaterGoal(db, waterGoal) {
|
|
144
|
+
const water = toInt(waterGoal, '饮水目标');
|
|
145
|
+
if (water < 0)
|
|
146
|
+
throw new FetchError('饮水目标不能为负数');
|
|
147
|
+
const old = getNutritionGoal(db)?.water_goal ?? null;
|
|
148
|
+
const upd = db
|
|
149
|
+
.prepare('UPDATE daily_goal SET water_goal = ?, updated_at = CURRENT_TIMESTAMP WHERE id = 1')
|
|
150
|
+
.run(water);
|
|
151
|
+
const row = db.prepare('SELECT id, updated_at FROM daily_goal WHERE id = 1').get();
|
|
152
|
+
return { id: row?.id ?? 1, updatedAt: row?.updated_at ?? null, rowsAffected: Number(upd.changes), oldWaterGoal: old, newWaterGoal: water };
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=nutritionGoal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nutritionGoal.js","sourceRoot":"","sources":["../../src/fetch/nutritionGoal.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgCzC,SAAS,KAAK,CAAC,CAAU,EAAE,KAAa;IACtC,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACjG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAgB;IAC/C,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,EAAkC,CAAC;IACtG,OAAO,GAAG,IAAI,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,EAAgB,EAAE,KAAmB;IACpE,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QACxF,MAAM,IAAI,UAAU,CAAC,8BAA8B,CAAC,CAAC;IACvD,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrC,IAAI,OAAO,IAAI,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3E,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACtD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACnC,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,OAAO,CAAC;IACzD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,EAAE,CAAC,OAAO,CACR,kHAAkH;YAChH,+CAA+C,CAClD,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,EAAE,CAAC,OAAO,CACR,sGAAsG;YACpG,4CAA4C,CAC/C,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACjC,OAAO;QACL,WAAW,EAAE,OAAO;QACpB,WAAW,EAAE,OAAO;QACpB,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,GAAG,EAAE,UAAU,IAAI,KAAK;QACnC,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;KACjC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAC7E,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE;IAC9E,IAAI,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;CACrE,CAAC;AAEX,MAAM,CAAC,MAAM,oBAAoB,GAAiC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC5G,MAAM,CAAC,MAAM,yBAAyB,GAAiC,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AA4B9G,MAAM,UAAU,cAAc,CAAC,EAAgB;IAC7C,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,sEAAsE,CAAC;SAC/E,GAAG,EAA8C,CAAC;IACrD,OAAO,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,EAAgB,EAAE,OAAuB,EAAE;IAChF,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IACtC,MAAM,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,iCAAiC,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IACvF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CAAC,8EAA8E,CAAC;SACvF,GAAG,EAAwH,CAAC;IAC/H,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,SAAS,IAAI,IAAI,CAAC;IACtD,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC;IACxC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,MAAM,IAAI,IAAI,CAAC;IACjD,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;SACrC,CAAC;QACJ,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,MAAM,IAAI,IAAI,CAAC;IACzB,MAAM,CAAC,GAAG,MAAM,IAAI,KAAK,CAAC;IAC1B,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC;IACpB,MAAM,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC;IAC3C,MAAM,GAAG,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,OAAO,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,OAAO,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,UAAU,GAAG,GAAG,CAAC;IAC9B,MAAM,OAAO,GAAG;QACd,oBAAoB,CAAC,OAAO,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,GAAG,UAAU,GAAG,GAAG,GAAG,IAAI;QACtJ,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,CAAC,aAAa,GAAG,QAAQ;QACjF,KAAK,GAAG,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ;QACnF,KAAK,GAAG,KAAK,GAAG,WAAW,GAAG,CAAC,CAAC,YAAY,GAAG,SAAS;QACxD,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG;KAClH,CAAC;IACF,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,GAAG,UAAU,GAAG,YAAY,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,GAAG,cAAc,CAAC,CAAC;IACrI,OAAO;QACL,OAAO;QACP,YAAY,EAAE,oBAAoB,CAAC,OAAO,CAAC;QAC3C,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QACtB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QACpB,WAAW,EAAE,GAAG;QAChB,WAAW,EAAE,OAAO;QACpB,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,yBAAyB,CAAC,OAAO,CAAC;QAChD,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;QAC5E,WAAW,EAAE,OAAO;QACpB,OAAO;QACP,SAAS,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;KAC1D,CAAC;AACJ,CAAC;AAQD,MAAM,UAAU,kBAAkB,CAAC,EAAgB,EAAE,OAA4B,EAAE;IAGjF,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,cAAc,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,CAAC,EAAE,UAAU,IAAI,IAAI,CAAC;IACrD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE;QACjC,MAAM;QACN,OAAO;QACP,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC;QAC3C,YAAY,EAAE,GAAG;QACjB,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG;KACxG,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAAgB,EAAE,SAAkB;IAGlE,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,CAAC,EAAE,UAAU,IAAI,IAAI,CAAC;IACrD,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,mFAAmF,CAAC;SAC5F,GAAG,CAAC,KAAK,CAAC,CAAC;IACd,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,oDAAoD,CAAC,CAAC,GAAG,EAEnE,CAAC;IACd,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,IAAI,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC7I,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** T4 #23 · body_photo_tracker 取数+写数(对照老家 scripts/body_photo_tracker.py)。
|
|
2
|
+
*
|
|
3
|
+
* 铁律:照片二进制只存路径 + 元数据(body_photos.photo_path 仅文件名,目录由
|
|
4
|
+
* CALORIE_PHOTOS_DIR 解析;缺失直接抛,不静默落盘)。gif 规划器只出任务描述
|
|
5
|
+
* (planGif),不跑图像处理。getLatestWeight 归 T3(weight_log),此处不碰。
|
|
6
|
+
*/
|
|
7
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
8
|
+
export declare const TAG_SEP = ",";
|
|
9
|
+
export declare const TAG_MAX_LEN = 20;
|
|
10
|
+
export declare const TAG_MAX_COUNT = 10;
|
|
11
|
+
/** '正面, 侧面' → ['正面', '侧面'](去空白/去空项/去重保序)。 */
|
|
12
|
+
export declare function parseTags(tagStr: string | null | undefined): string[];
|
|
13
|
+
export declare function serializeTags(tags: string[]): string;
|
|
14
|
+
/** 硬规则:非空 + 单个 ≤20 + 数量 ≤10(非法即抛)。 */
|
|
15
|
+
export declare function validateTags(tags: string[]): string[];
|
|
16
|
+
export declare function tagsContain(tagStr: string | null | undefined, tag: string): boolean;
|
|
17
|
+
/** 照片目录解析:显式传参 > CALORIE_PHOTOS_DIR;缺失抛(不静默落盘)。 */
|
|
18
|
+
export declare function resolvePhotosDir(dir?: string | null): string;
|
|
19
|
+
export interface PhotoRow {
|
|
20
|
+
id: number;
|
|
21
|
+
date: string;
|
|
22
|
+
time: string | null;
|
|
23
|
+
photo_path: string;
|
|
24
|
+
tag: string;
|
|
25
|
+
note: string | null;
|
|
26
|
+
created_at: string | null;
|
|
27
|
+
tag_list: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function getPhotoRow(db: DatabaseSync, id: number): PhotoRow | null;
|
|
30
|
+
export interface ListPhotosFilter {
|
|
31
|
+
days?: number;
|
|
32
|
+
tag?: string | null;
|
|
33
|
+
dateFrom?: string | null;
|
|
34
|
+
dateTo?: string | null;
|
|
35
|
+
limit?: number | null;
|
|
36
|
+
today?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function listPhotos(db: DatabaseSync, filter?: ListPhotosFilter): PhotoRow[];
|
|
39
|
+
export declare function daysSinceTagPhoto(db: DatabaseSync, tag: string, beforeDate: string): number | null;
|
|
40
|
+
export interface AddPhotosInput {
|
|
41
|
+
srcPaths: string[];
|
|
42
|
+
tag: string;
|
|
43
|
+
note?: string;
|
|
44
|
+
today?: string;
|
|
45
|
+
nowTime?: string;
|
|
46
|
+
}
|
|
47
|
+
/** 添加照片:文件复制进目录 + 落库(仅文件名入库)。不存在的源文件跳过。 */
|
|
48
|
+
export declare function addPhotos(db: DatabaseSync, photosDir: string, input: AddPhotosInput): Array<{
|
|
49
|
+
id: number;
|
|
50
|
+
file: string;
|
|
51
|
+
}>;
|
|
52
|
+
export declare function deletePhoto(db: DatabaseSync, photosDir: string, id: number): {
|
|
53
|
+
deleted: boolean;
|
|
54
|
+
fileDeleted: boolean;
|
|
55
|
+
};
|
|
56
|
+
export declare function updateTag(db: DatabaseSync, id: number, newTag: string): boolean;
|
|
57
|
+
/** 追加标签(判重);返回新增标签数(不存在的照片回 0)。 */
|
|
58
|
+
export declare function tagAdd(db: DatabaseSync, id: number, tag: string): number;
|
|
59
|
+
/** 移除单个标签(至少保留 1 个;一次只删 1 个)。 */
|
|
60
|
+
export declare function tagRemove(db: DatabaseSync, id: number, tag: string): boolean;
|
|
61
|
+
export interface GifPlanInput {
|
|
62
|
+
tag: string;
|
|
63
|
+
dateFrom?: string | null;
|
|
64
|
+
dateTo?: string | null;
|
|
65
|
+
days?: number | null;
|
|
66
|
+
}
|
|
67
|
+
/** gif 规划器:只出任务描述(起止、张数、标签),不跑图像处理、不碰二进制。 */
|
|
68
|
+
export declare function planGif(db: DatabaseSync, input: GifPlanInput): {
|
|
69
|
+
task: 'generate_gif';
|
|
70
|
+
tag: string;
|
|
71
|
+
dateFrom: string | null;
|
|
72
|
+
dateTo: string | null;
|
|
73
|
+
photoCount: number;
|
|
74
|
+
photoIds: number[];
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=photos.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photos.d.ts","sourceRoot":"","sources":["../../src/fetch/photos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { basename, join, resolve } from 'node:path';
|
|
3
|
+
import { FetchError } from './errors.js';
|
|
4
|
+
export const TAG_SEP = ',';
|
|
5
|
+
export const TAG_MAX_LEN = 20;
|
|
6
|
+
export const TAG_MAX_COUNT = 10;
|
|
7
|
+
/** '正面, 侧面' → ['正面', '侧面'](去空白/去空项/去重保序)。 */
|
|
8
|
+
export function parseTags(tagStr) {
|
|
9
|
+
const seen = new Set();
|
|
10
|
+
const out = [];
|
|
11
|
+
for (const t of String(tagStr ?? '').split(TAG_SEP)) {
|
|
12
|
+
const s = t.trim();
|
|
13
|
+
if (!s || seen.has(s))
|
|
14
|
+
continue;
|
|
15
|
+
seen.add(s);
|
|
16
|
+
out.push(s);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
export function serializeTags(tags) {
|
|
21
|
+
return tags.join(TAG_SEP);
|
|
22
|
+
}
|
|
23
|
+
/** 硬规则:非空 + 单个 ≤20 + 数量 ≤10(非法即抛)。 */
|
|
24
|
+
export function validateTags(tags) {
|
|
25
|
+
if (tags.length === 0)
|
|
26
|
+
throw new FetchError('标签必填,当前是空列表');
|
|
27
|
+
for (const t of tags) {
|
|
28
|
+
if (t.length > TAG_MAX_LEN)
|
|
29
|
+
throw new FetchError('标签太长(' + t.length + ' > ' + TAG_MAX_LEN + '): ' + t);
|
|
30
|
+
}
|
|
31
|
+
if (tags.length > TAG_MAX_COUNT)
|
|
32
|
+
throw new FetchError('标签数量太多(' + tags.length + ' > ' + TAG_MAX_COUNT + ')');
|
|
33
|
+
return tags;
|
|
34
|
+
}
|
|
35
|
+
export function tagsContain(tagStr, tag) {
|
|
36
|
+
return parseTags(tagStr).includes(tag);
|
|
37
|
+
}
|
|
38
|
+
/** 照片目录解析:显式传参 > CALORIE_PHOTOS_DIR;缺失抛(不静默落盘)。 */
|
|
39
|
+
export function resolvePhotosDir(dir) {
|
|
40
|
+
const raw = dir ?? process.env.CALORIE_PHOTOS_DIR ?? '';
|
|
41
|
+
if (!raw)
|
|
42
|
+
throw new FetchError('照片目录未配置:请传参或设置 CALORIE_PHOTOS_DIR');
|
|
43
|
+
mkdirSync(raw, { recursive: true });
|
|
44
|
+
return resolve(raw);
|
|
45
|
+
}
|
|
46
|
+
const PHOTO_COLS = 'id, date, time, photo_path, tag, note, created_at';
|
|
47
|
+
function toRow(r) {
|
|
48
|
+
return { ...r, tag_list: parseTags(r.tag) };
|
|
49
|
+
}
|
|
50
|
+
export function getPhotoRow(db, id) {
|
|
51
|
+
const row = db.prepare('SELECT ' + PHOTO_COLS + ' FROM body_photos WHERE id = ?').get(id);
|
|
52
|
+
return row ? toRow(row) : null;
|
|
53
|
+
}
|
|
54
|
+
function todayISO() {
|
|
55
|
+
return new Date().toISOString().slice(0, 10);
|
|
56
|
+
}
|
|
57
|
+
function shiftISODate(iso, deltaDays) {
|
|
58
|
+
const t = Date.parse(iso + 'T12:00:00Z');
|
|
59
|
+
if (Number.isNaN(t))
|
|
60
|
+
throw new FetchError('日期非法: ' + iso);
|
|
61
|
+
return new Date(t + deltaDays * 86400000).toISOString().slice(0, 10);
|
|
62
|
+
}
|
|
63
|
+
export function listPhotos(db, filter = {}) {
|
|
64
|
+
const days = filter.days ?? 7;
|
|
65
|
+
const where = [];
|
|
66
|
+
const params = [];
|
|
67
|
+
if (filter.dateFrom) {
|
|
68
|
+
where.push('date >= ?');
|
|
69
|
+
params.push(filter.dateFrom);
|
|
70
|
+
}
|
|
71
|
+
if (filter.dateTo) {
|
|
72
|
+
where.push('date <= ?');
|
|
73
|
+
params.push(filter.dateTo);
|
|
74
|
+
}
|
|
75
|
+
if (!filter.dateFrom && !filter.dateTo) {
|
|
76
|
+
where.push('date >= ?');
|
|
77
|
+
params.push(shiftISODate(filter.today ?? todayISO(), -days));
|
|
78
|
+
}
|
|
79
|
+
const rows = db
|
|
80
|
+
.prepare('SELECT ' + PHOTO_COLS + ' FROM body_photos WHERE ' + where.join(' AND ') + ' ORDER BY date DESC, time DESC')
|
|
81
|
+
.all(...params);
|
|
82
|
+
let out = rows.map(toRow);
|
|
83
|
+
if (filter.tag)
|
|
84
|
+
out = out.filter((r) => tagsContain(r.tag, filter.tag));
|
|
85
|
+
const limit = filter.limit ?? 100;
|
|
86
|
+
if (limit)
|
|
87
|
+
out = out.slice(0, limit);
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
export function daysSinceTagPhoto(db, tag, beforeDate) {
|
|
91
|
+
const rows = db
|
|
92
|
+
.prepare('SELECT id, tag, date FROM body_photos WHERE date < ? ORDER BY date DESC, time DESC')
|
|
93
|
+
.all(beforeDate);
|
|
94
|
+
for (const r of rows) {
|
|
95
|
+
if (tagsContain(r.tag, tag)) {
|
|
96
|
+
const delta = Math.round((Date.parse(beforeDate + 'T12:00:00Z') - Date.parse(r.date + 'T12:00:00Z')) / 86400000);
|
|
97
|
+
return delta >= 0 ? delta : null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
/** 添加照片:文件复制进目录 + 落库(仅文件名入库)。不存在的源文件跳过。 */
|
|
103
|
+
export function addPhotos(db, photosDir, input) {
|
|
104
|
+
const tags = validateTags(parseTags(input.tag));
|
|
105
|
+
const serialized = serializeTags(tags);
|
|
106
|
+
const today = input.today ?? todayISO();
|
|
107
|
+
const now = input.nowTime ?? new Date().toTimeString().slice(0, 8);
|
|
108
|
+
const cnt = db.prepare('SELECT COUNT(*) AS n FROM body_photos WHERE date = ?').get(today);
|
|
109
|
+
const added = [];
|
|
110
|
+
let i = 0;
|
|
111
|
+
for (const srcPath of input.srcPaths) {
|
|
112
|
+
if (!existsSync(srcPath))
|
|
113
|
+
continue;
|
|
114
|
+
const ext = srcPath.slice(srcPath.lastIndexOf('.')).toLowerCase();
|
|
115
|
+
const destName = today + '_' + String(cnt.n + i + 1).padStart(3, '0') + ext;
|
|
116
|
+
cpSync(srcPath, join(photosDir, destName));
|
|
117
|
+
const run = db
|
|
118
|
+
.prepare('INSERT INTO body_photos (date, time, photo_path, tag, note) VALUES (?, ?, ?, ?, ?)')
|
|
119
|
+
.run(today, now, destName, serialized, input.note ?? '');
|
|
120
|
+
added.push({ id: Number(run.lastInsertRowid), file: destName });
|
|
121
|
+
i += 1;
|
|
122
|
+
}
|
|
123
|
+
return added;
|
|
124
|
+
}
|
|
125
|
+
export function deletePhoto(db, photosDir, id) {
|
|
126
|
+
const row = db.prepare('SELECT photo_path FROM body_photos WHERE id = ?').get(id);
|
|
127
|
+
if (!row)
|
|
128
|
+
return { deleted: false, fileDeleted: false };
|
|
129
|
+
db.prepare('DELETE FROM body_photos WHERE id = ?').run(id);
|
|
130
|
+
const file = join(photosDir, basename(row.photo_path));
|
|
131
|
+
if (existsSync(file)) {
|
|
132
|
+
rmSync(file);
|
|
133
|
+
return { deleted: true, fileDeleted: true };
|
|
134
|
+
}
|
|
135
|
+
return { deleted: true, fileDeleted: false };
|
|
136
|
+
}
|
|
137
|
+
export function updateTag(db, id, newTag) {
|
|
138
|
+
const row = db.prepare('SELECT id FROM body_photos WHERE id = ?').get(id);
|
|
139
|
+
if (!row)
|
|
140
|
+
return false;
|
|
141
|
+
const serialized = serializeTags(validateTags(parseTags(newTag)));
|
|
142
|
+
db.prepare('UPDATE body_photos SET tag = ? WHERE id = ?').run(serialized, id);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
/** 追加标签(判重);返回新增标签数(不存在的照片回 0)。 */
|
|
146
|
+
export function tagAdd(db, id, tag) {
|
|
147
|
+
const photo = getPhotoRow(db, id);
|
|
148
|
+
if (!photo)
|
|
149
|
+
return 0;
|
|
150
|
+
const tags = validateTags(parseTags(tag));
|
|
151
|
+
const existing = [...photo.tag_list];
|
|
152
|
+
let added = 0;
|
|
153
|
+
for (const t of tags) {
|
|
154
|
+
if (existing.includes(t))
|
|
155
|
+
continue;
|
|
156
|
+
existing.push(t);
|
|
157
|
+
added += 1;
|
|
158
|
+
}
|
|
159
|
+
if (added === 0)
|
|
160
|
+
return 0;
|
|
161
|
+
db.prepare('UPDATE body_photos SET tag = ? WHERE id = ?').run(serializeTags(existing), id);
|
|
162
|
+
return added;
|
|
163
|
+
}
|
|
164
|
+
/** 移除单个标签(至少保留 1 个;一次只删 1 个)。 */
|
|
165
|
+
export function tagRemove(db, id, tag) {
|
|
166
|
+
const photo = getPhotoRow(db, id);
|
|
167
|
+
if (!photo)
|
|
168
|
+
return false;
|
|
169
|
+
const tags = parseTags(tag);
|
|
170
|
+
if (tags.length !== 1)
|
|
171
|
+
throw new FetchError('删标签一次只删 1 个,收到 ' + tags.length + ' 个');
|
|
172
|
+
const existing = [...photo.tag_list];
|
|
173
|
+
const rm = tags[0];
|
|
174
|
+
if (!existing.includes(rm))
|
|
175
|
+
return false;
|
|
176
|
+
if (existing.length <= 1)
|
|
177
|
+
throw new FetchError('每张照片至少保留 1 个标签');
|
|
178
|
+
db.prepare('UPDATE body_photos SET tag = ? WHERE id = ?').run(serializeTags(existing.filter((t) => t !== rm)), id);
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
/** gif 规划器:只出任务描述(起止、张数、标签),不跑图像处理、不碰二进制。 */
|
|
182
|
+
export function planGif(db, input) {
|
|
183
|
+
const photos = listPhotos(db, { tag: input.tag, dateFrom: input.dateFrom, dateTo: input.dateTo, days: input.days ?? 30, limit: null });
|
|
184
|
+
return {
|
|
185
|
+
task: 'generate_gif',
|
|
186
|
+
tag: input.tag,
|
|
187
|
+
dateFrom: photos.length > 0 ? photos[photos.length - 1].date : null,
|
|
188
|
+
dateTo: photos.length > 0 ? photos[0].date : null,
|
|
189
|
+
photoCount: photos.length,
|
|
190
|
+
photoIds: photos.map((p) => p.id),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=photos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"photos.js","sourceRoot":"","sources":["../../src/fetch/photos.ts"],"names":[],"mappings":"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"}
|