feat: 体重管理v2页面优化,新增饮食运动详情页,代码精简重构
This commit is contained in:
@@ -95,7 +95,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.advice-food-item:last-child { margin-bottom: 0; }
|
||||
.advice-food-item__emoji { font-size: 22px; width: 28px; text-align: center; flex-shrink: 0; line-height: 1.2; }
|
||||
.advice-food-item__info { flex: 1; min-width: 0; }
|
||||
.advice-food-item__name { font-size: 13px; font-weight: 600; color: #333; }
|
||||
.advice-food-item__name { font-size: 13px; font-weight: 600; color: #333; display: flex; align-items: center; gap: 6px; }
|
||||
.advice-food-item__tag { font-size: 9px; font-weight: 600; padding: 1px 6px; border-radius: 6px; white-space: nowrap; line-height: 1.5; }
|
||||
.advice-food-item__tag--canteen { color: #d46b08; background: #fff7e6; }
|
||||
.advice-food-item__tag--ai { color: #0891b2; background: #ecfeff; }
|
||||
.advice-food-item__meta { font-size: 11px; color: #bbb; margin-top: 2px; }
|
||||
.advice-food-item__reason { font-size: 11px; color: #888; margin-top: 4px; line-height: 1.5; display: flex; align-items: flex-start; gap: 3px; }
|
||||
.advice-food-item__reason svg { flex-shrink: 0; margin-top: 1px; }
|
||||
@@ -621,21 +624,21 @@ var dayData = {
|
||||
intake: 1050, summary: '今日热量摄入合理,营养素搭配均衡。早餐提供了充足蛋白质,午餐以碳水为主,晚餐清淡适中。',
|
||||
meals: {
|
||||
breakfast: { kcal: 280, time: '07:30', items: [
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, reason: '优质蛋白质来源,富含卵磷脂,有助于大脑功能' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, reason: '补充钙质和蛋白质,250ml满足每日钙需求约30%' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×1', k: 80, reason: '全谷物碳水,富含膳食纤维,升糖指数低' }
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, tag: 'canteen', reason: '优质蛋白质来源,富含卵磷脂,有助于大脑功能' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, tag: 'ai', reason: '补充钙质和蛋白质,250ml满足每日钙需求约30%' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×1', k: 80, tag: 'canteen', reason: '全谷物碳水,富含膳食纤维,升糖指数低' }
|
||||
]},
|
||||
lunch: { kcal: 450, time: '12:00', items: [
|
||||
{ e: '🍚', n: '白米饭', m: '×1 · 约200g', k: 232, reason: '主食碳水来源,提供午后能量' },
|
||||
{ e: '🐔', n: '红烧鸡块', m: '×1 · 约150g', k: 140, reason: '鸡肉为低脂高蛋白,适合减脂期食用' },
|
||||
{ e: '🥬', n: '炒青菜', m: '×1', k: 78, reason: '绿叶蔬菜补充维生素和膳食纤维' }
|
||||
{ e: '🍚', n: '白米饭', m: '×1 · 约200g', k: 232, tag: 'canteen', reason: '主食碳水来源,提供午后能量' },
|
||||
{ e: '🐔', n: '红烧鸡块', m: '×1 · 约150g', k: 140, tag: 'canteen', reason: '鸡肉为低脂高蛋白,适合减脂期食用' },
|
||||
{ e: '🥬', n: '炒青菜', m: '×1', k: 78, tag: 'canteen', reason: '绿叶蔬菜补充维生素和膳食纤维' }
|
||||
]},
|
||||
dinner: { kcal: 260, time: '18:00', items: [
|
||||
{ e: '🥗', n: '蔬菜沙拉', m: '×1 · 约200g', k: 160, reason: '低热量高纤维,含多种维生素' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1', k: 100, reason: '复合碳水,富含β-胡萝卜素和膳食纤维' }
|
||||
{ e: '🥗', n: '蔬菜沙拉', m: '×1 · 约200g', k: 160, tag: 'canteen', reason: '低热量高纤维,含多种维生素' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1', k: 100, tag: 'canteen', reason: '复合碳水,富含β-胡萝卜素和膳食纤维' }
|
||||
]},
|
||||
snack: { kcal: 60, time: '15:30', items: [
|
||||
{ e: '🍌', n: '香蕉', m: '×1', k: 60, reason: '富含钾元素,有助于运动后恢复,天然甜味满足口欲' }
|
||||
{ e: '🍌', n: '香蕉', m: '×1', k: 60, tag: 'ai', reason: '富含钾元素,有助于运动后恢复,天然甜味满足口欲' }
|
||||
]}
|
||||
},
|
||||
macros: { carb: 140, carbT: 260, protein: 52, proteinT: 82, fat: 28, fatT: 60 },
|
||||
@@ -648,20 +651,20 @@ var dayData = {
|
||||
intake: 1120, summary: '今日摄入略高,但蛋白质充足。午餐牛肉面碳水含量偏高,建议增加蔬菜比例。',
|
||||
meals: {
|
||||
breakfast: { kcal: 350, time: '08:00', items: [
|
||||
{ e: '🥛', n: '豆浆', m: '×1 · 300ml', k: 90, reason: '植物蛋白来源,含大豆异黄酮,有益心血管' },
|
||||
{ e: '🥮', n: '肉包', m: '×2', k: 180, reason: '提供碳水和蛋白质,但注意控制量' },
|
||||
{ e: '🥚', n: '茶叶蛋', m: '×1', k: 80, reason: '便携蛋白来源,适合快节奏早餐' }
|
||||
{ e: '🥛', n: '豆浆', m: '×1 · 300ml', k: 90, tag: 'canteen', reason: '植物蛋白来源,含大豆异黄酮,有益心血管' },
|
||||
{ e: '🥮', n: '肉包', m: '×2', k: 180, tag: 'canteen', reason: '提供碳水和蛋白质,但注意控制量' },
|
||||
{ e: '🥚', n: '茶叶蛋', m: '×1', k: 80, tag: 'canteen', reason: '便携蛋白来源,适合快节奏早餐' }
|
||||
]},
|
||||
lunch: { kcal: 480, time: '12:20', items: [
|
||||
{ e: '🍜', n: '牛肉面', m: '×1 · 约400g', k: 380, reason: '牛肉提供优质蛋白和铁,但面条碳水偏高' },
|
||||
{ e: '🥒', n: '凉拌黄瓜', m: '×1', k: 100, reason: '爽口低卡蔬菜,平衡主食热量' }
|
||||
{ e: '🍜', n: '牛肉面', m: '×1 · 约400g', k: 380, tag: 'canteen', reason: '牛肉提供优质蛋白和铁,但面条碳水偏高' },
|
||||
{ e: '🥒', n: '凉拌黄瓜', m: '×1', k: 100, tag: 'canteen', reason: '爽口低卡蔬菜,平衡主食热量' }
|
||||
]},
|
||||
dinner: { kcal: 210, time: '18:30', items: [
|
||||
{ e: '🐟', n: '清蒸鱼', m: '×1 · 约150g', k: 130, reason: '鱼肉富含Omega-3脂肪酸,清蒸法低脂健康' },
|
||||
{ e: '🥦', n: '西兰花', m: '×1', k: 80, reason: '十字花科蔬菜,富含维生素C和抗氧化物质' }
|
||||
{ e: '🐟', n: '清蒸鱼', m: '×1 · 约150g', k: 130, tag: 'canteen', reason: '鱼肉富含Omega-3脂肪酸,清蒸法低脂健康' },
|
||||
{ e: '🥦', n: '西兰花', m: '×1', k: 80, tag: 'canteen', reason: '十字花科蔬菜,富含维生素C和抗氧化物质' }
|
||||
]},
|
||||
snack: { kcal: 80, time: '10:30', items: [
|
||||
{ e: '🥜', n: '坚果', m: '×1把 · 约20g', k: 80, reason: '含健康不饱和脂肪酸,适量有益心血管' }
|
||||
{ e: '🥜', n: '坚果', m: '×1把 · 约20g', k: 80, tag: 'ai', reason: '含健康不饱和脂肪酸,适量有益心血管' }
|
||||
]}
|
||||
},
|
||||
macros: { carb: 165, carbT: 260, protein: 44, proteinT: 82, fat: 34, fatT: 60 },
|
||||
@@ -674,22 +677,22 @@ var dayData = {
|
||||
intake: 980, summary: '今日热量控制优秀,蛋白质摄入充足,碳水偏低。饮食搭配非常健康,值得保持!',
|
||||
meals: {
|
||||
breakfast: { kcal: 220, time: '07:15', items: [
|
||||
{ e: '🥚', n: '水煮蛋', m: '×2', k: 160, reason: '两颗蛋提供约12g蛋白质,蛋黄含胆碱有益大脑' },
|
||||
{ e: '☕', n: '黑咖啡', m: '×1', k: 5, reason: '几乎零卡路里,咖啡因可提神并轻微促进代谢' },
|
||||
{ e: '🍞', n: '全麦吐司', m: '×1', k: 55, reason: '全谷物提供缓释碳水,配合蛋白质延长饱腹感' }
|
||||
{ e: '🥚', n: '水煮蛋', m: '×2', k: 160, tag: 'canteen', reason: '两颗蛋提供约12g蛋白质,蛋黄含胆碱有益大脑' },
|
||||
{ e: '☕', n: '黑咖啡', m: '×1', k: 5, tag: 'ai', reason: '几乎零卡路里,咖啡因可提神并轻微促进代谢' },
|
||||
{ e: '🍞', n: '全麦吐司', m: '×1', k: 55, tag: 'canteen', reason: '全谷物提供缓释碳水,配合蛋白质延长饱腹感' }
|
||||
]},
|
||||
lunch: { kcal: 420, time: '11:50', items: [
|
||||
{ e: '🍚', n: '杂粮饭', m: '×1 · 约180g', k: 200, reason: '杂粮升糖指数低于白米,膳食纤维更丰富' },
|
||||
{ e: '🐔', n: '鸡胸肉', m: '×1 · 约120g', k: 120, reason: '极低脂高蛋白,减脂增肌首选蛋白质来源' },
|
||||
{ e: '🥬', n: '蒜蓉菠菜', m: '×1', k: 100, reason: '菠菜富含铁和叶酸,蒜蓉增添风味且有益心血管' }
|
||||
{ e: '🍚', n: '杂粮饭', m: '×1 · 约180g', k: 200, tag: 'canteen', reason: '杂粮升糖指数低于白米,膳食纤维更丰富' },
|
||||
{ e: '🐔', n: '鸡胸肉', m: '×1 · 约120g', k: 120, tag: 'canteen', reason: '极低脂高蛋白,减脂增肌首选蛋白质来源' },
|
||||
{ e: '🥬', n: '蒜蓉菠菜', m: '×1', k: 100, tag: 'canteen', reason: '菠菜富含铁和叶酸,蒜蓉增添风味且有益心血管' }
|
||||
]},
|
||||
dinner: { kcal: 280, time: '17:40', items: [
|
||||
{ e: '🥗', n: '凯撒沙拉', m: '×1 · 约250g', k: 220, reason: '多种蔬菜搭配,含膳食纤维和维生素' },
|
||||
{ e: '🍎', n: '苹果', m: '×1', k: 60, reason: '苹果果胶有助于肠道健康,天然甜味代替甜点' }
|
||||
{ e: '🥗', n: '凯撒沙拉', m: '×1 · 约250g', k: 220, tag: 'canteen', reason: '多种蔬菜搭配,含膳食纤维和维生素' },
|
||||
{ e: '🍎', n: '苹果', m: '×1', k: 60, tag: 'ai', reason: '苹果果胶有助于肠道健康,天然甜味代替甜点' }
|
||||
]},
|
||||
snack: { kcal: 60, time: '15:00', items: [
|
||||
{ e: '🥒', n: '黄瓜', m: '×1根', k: 15, reason: '极低热量,富含水分和膳食纤维' },
|
||||
{ e: '🍅', n: '小番茄', m: '×5颗', k: 45, reason: '番茄红素抗氧化,天然维C补充' }
|
||||
{ e: '🥒', n: '黄瓜', m: '×1根', k: 15, tag: 'canteen', reason: '极低热量,富含水分和膳食纤维' },
|
||||
{ e: '🍅', n: '小番茄', m: '×5颗', k: 45, tag: 'ai', reason: '番茄红素抗氧化,天然维C补充' }
|
||||
]}
|
||||
},
|
||||
macros: { carb: 120, carbT: 260, protein: 58, proteinT: 82, fat: 22, fatT: 60 },
|
||||
@@ -702,21 +705,21 @@ var dayData = {
|
||||
intake: 1086, summary: '今日三餐搭配合理,蛋白质和碳水分配均衡。加餐选择苹果是不错的低热量选择,有助于控制总摄入。',
|
||||
meals: {
|
||||
breakfast: { kcal: 320, time: '07:20', items: [
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, reason: '优质完全蛋白质,含所有必需氨基酸,饱腹感强' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, reason: '补充钙质(约300mg)和维生素D,促进骨骼健康' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×2 · 约80g', k: 120, reason: '全谷物提供缓释能量,富含B族维生素和膳食纤维' }
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, tag: 'canteen', reason: '优质完全蛋白质,含所有必需氨基酸,饱腹感强' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, tag: 'ai', reason: '补充钙质(约300mg)和维生素D,促进骨骼健康' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×2 · 约80g', k: 120, tag: 'canteen', reason: '全谷物提供缓释能量,富含B族维生素和膳食纤维' }
|
||||
]},
|
||||
lunch: { kcal: 480, time: '12:10', items: [
|
||||
{ e: '🍚', n: '白米饭', m: '×1 · 约200g', k: 232, reason: '提供充足碳水能量,满足午后工作和代谢需求' },
|
||||
{ e: '🐔', n: '宫保鸡丁', m: '×1 · 约150g', k: 148, reason: '鸡肉低脂高蛋白,搭配花生提供健康不饱和脂肪' },
|
||||
{ e: '🥬', n: '清炒时蔬', m: '×1 · 约200g', k: 100, reason: '足量蔬菜补充膳食纤维,促进肠道蠕动' }
|
||||
{ e: '🍚', n: '白米饭', m: '×1 · 约200g', k: 232, tag: 'canteen', reason: '提供充足碳水能量,满足午后工作和代谢需求' },
|
||||
{ e: '🐔', n: '宫保鸡丁', m: '×1 · 约150g', k: 148, tag: 'canteen', reason: '鸡肉低脂高蛋白,搭配花生提供健康不饱和脂肪' },
|
||||
{ e: '🥬', n: '清炒时蔬', m: '×1 · 约200g', k: 100, tag: 'canteen', reason: '足量蔬菜补充膳食纤维,促进肠道蠕动' }
|
||||
]},
|
||||
dinner: { kcal: 220, time: '18:15', items: [
|
||||
{ e: '🥗', n: '鸡胸肉沙拉', m: '×1 · 约250g', k: 180, reason: '晚餐以蔬菜为主,鸡胸肉提供蛋白质但不过量' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1 · 约100g', k: 40, reason: '低GI碳水,蒸制方式无额外油脂,含丰富β-胡萝卜素' }
|
||||
{ e: '🥗', n: '鸡胸肉沙拉', m: '×1 · 约250g', k: 180, tag: 'canteen', reason: '晚餐以蔬菜为主,鸡胸肉提供蛋白质但不过量' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1 · 约100g', k: 40, tag: 'canteen', reason: '低GI碳水,蒸制方式无额外油脂,含丰富β-胡萝卜素' }
|
||||
]},
|
||||
snack: { kcal: 66, time: '15:30', items: [
|
||||
{ e: '🍎', n: '苹果', m: '×1 · 约200g', k: 66, reason: '天然果糖满足甜味需求,果胶增加饱腹感,热量可控' }
|
||||
{ e: '🍎', n: '苹果', m: '×1 · 约200g', k: 66, tag: 'ai', reason: '天然果糖满足甜味需求,果胶增加饱腹感,热量可控' }
|
||||
]}
|
||||
},
|
||||
macros: { carb: 155, carbT: 260, protein: 47, proteinT: 82, fat: 31, fatT: 60 },
|
||||
@@ -790,23 +793,23 @@ var DEFAULT_RECIPE_DATA = {
|
||||
summary: '暂无当日饮食记录,以下为推荐的均衡饮食示例,可参考搭配安排今日三餐。',
|
||||
meals: {
|
||||
breakfast: { kcal: 320, items: [
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, reason: '优质完全蛋白质,含所有必需氨基酸,饱腹感强' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, reason: '补充钙质(约300mg)和维生素D,促进骨骼健康' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×1 · 约40g', k: 120, reason: '全谷物提供缓释能量,富含B族维生素和膳食纤维' }
|
||||
{ e: '🥚', n: '水煮鸡蛋', m: '×1 · 约50g', k: 80, tag: 'canteen', reason: '优质完全蛋白质,含所有必需氨基酸,饱腹感强' },
|
||||
{ e: '🥛', n: '纯牛奶', m: '×1 · 250ml', k: 120, tag: 'ai', reason: '补充钙质(约300mg)和维生素D,促进骨骼健康' },
|
||||
{ e: '🍞', n: '全麦面包', m: '×1 · 约40g', k: 120, tag: 'canteen', reason: '全谷物提供缓释能量,富含B族维生素和膳食纤维' }
|
||||
]},
|
||||
lunch: { kcal: 480, items: [
|
||||
{ e: '🍚', n: '杂粮饭', m: '×1 · 约150g', k: 180, reason: '杂粮升糖指数低,膳食纤维丰富,有助于血糖稳定' },
|
||||
{ e: '🐔', n: '鸡胸肉', m: '×1 · 约120g', k: 150, reason: '极低脂高蛋白,是减脂增肌的首选蛋白来源' },
|
||||
{ e: '🥬', n: '清炒时蔬', m: '×1 · 约200g', k: 100, reason: '足量蔬菜补充膳食纤维,促进肠道蠕动' },
|
||||
{ e: '🍅', n: '小番茄', m: '×5颗', k: 50, reason: '番茄红素抗氧化,天然维C补充' }
|
||||
{ e: '🍚', n: '杂粮饭', m: '×1 · 约150g', k: 180, tag: 'canteen', reason: '杂粮升糖指数低,膳食纤维丰富,有助于血糖稳定' },
|
||||
{ e: '🐔', n: '鸡胸肉', m: '×1 · 约120g', k: 150, tag: 'canteen', reason: '极低脂高蛋白,是减脂增肌的首选蛋白来源' },
|
||||
{ e: '🥬', n: '清炒时蔬', m: '×1 · 约200g', k: 100, tag: 'canteen', reason: '足量蔬菜补充膳食纤维,促进肠道蠕动' },
|
||||
{ e: '🍅', n: '小番茄', m: '×5颗', k: 50, tag: 'ai', reason: '番茄红素抗氧化,天然维C补充' }
|
||||
]},
|
||||
dinner: { kcal: 280, items: [
|
||||
{ e: '🐟', n: '清蒸鱼', m: '×1 · 约150g', k: 150, reason: '鱼肉富含Omega-3脂肪酸,清蒸法低脂健康' },
|
||||
{ e: '🥦', n: '西兰花', m: '×1 · 约150g', k: 80, reason: '十字花科蔬菜,富含维生素C和抗氧化物质' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1 · 约100g', k: 50, reason: '低GI碳水,蒸制方式无额外油脂,富含β-胡萝卜素' }
|
||||
{ e: '🐟', n: '清蒸鱼', m: '×1 · 约150g', k: 150, tag: 'canteen', reason: '鱼肉富含Omega-3脂肪酸,清蒸法低脂健康' },
|
||||
{ e: '🥦', n: '西兰花', m: '×1 · 约150g', k: 80, tag: 'canteen', reason: '十字花科蔬菜,富含维生素C和抗氧化物质' },
|
||||
{ e: '🍠', n: '蒸红薯', m: '×1 · 约100g', k: 50, tag: 'canteen', reason: '低GI碳水,蒸制方式无额外油脂,富含β-胡萝卜素' }
|
||||
]},
|
||||
snack: { kcal: 60, items: [
|
||||
{ e: '🍎', n: '苹果', m: '×1 · 约200g', k: 60, reason: '天然果糖满足甜味需求,果胶增加饱腹感,热量可控' }
|
||||
{ e: '🍎', n: '苹果', m: '×1 · 约200g', k: 60, tag: 'ai', reason: '天然果糖满足甜味需求,果胶增加饱腹感,热量可控' }
|
||||
]}
|
||||
}
|
||||
};
|
||||
@@ -827,10 +830,16 @@ function renderRecipeTab(data) {
|
||||
kcalEl.textContent = md.kcal;
|
||||
var h = '';
|
||||
md.items.forEach(function(item) {
|
||||
var tagHtml = '';
|
||||
if (item.tag === 'canteen') {
|
||||
tagHtml = '<span class="advice-food-item__tag advice-food-item__tag--canteen">食堂提供</span>';
|
||||
} else if (item.tag === 'ai') {
|
||||
tagHtml = '<span class="advice-food-item__tag advice-food-item__tag--ai">AI推荐</span>';
|
||||
}
|
||||
h += '<div class="advice-food-item">' +
|
||||
'<div class="advice-food-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="advice-food-item__info">' +
|
||||
'<div class="advice-food-item__name">' + item.n + '</div>' +
|
||||
'<div class="advice-food-item__name">' + item.n + tagHtml + '</div>' +
|
||||
'<div class="advice-food-item__meta">' + item.m + '</div>' +
|
||||
'<div class="advice-food-item__reason"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#36cfc9" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>' + item.reason + '</div>' +
|
||||
'</div>' +
|
||||
|
||||
@@ -85,7 +85,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.recipe-btn { position: absolute; top: 44px; right: 8px; padding: 5px 12px; border-radius: 14px; border: none; background: linear-gradient(160deg, #36cfc9, #2db8b0); color: #fff; font-size: 11px; font-weight: 600; cursor: pointer; z-index: 5; box-shadow: 0 2px 6px rgba(54,207,201,0.3); }
|
||||
|
||||
/* ===== 营养素三列 ===== */
|
||||
.macros-row { display: flex; gap: 10px; padding: 0 4px 8px; }
|
||||
.macros-row { display: flex; gap: 10px; padding: 0 4px 8px; margin-top: -20px; }
|
||||
.macros-row.hidden { display: none; }
|
||||
.macro-col { flex: 1; padding: 8px 10px; background: #f7f8fa; border-radius: 10px; text-align: center; }
|
||||
.macro-col__name { font-size: 11px; color: #999; margin-bottom: 4px; }
|
||||
@@ -114,6 +114,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.meal-card__kcal--in span { color: #fa8c16; }
|
||||
.meal-card__kcal--out { color: #52c41a; }
|
||||
.meal-card__kcal--out span { color: #52c41a; }
|
||||
.meal-card__kcal .meal-card__kcal-target,
|
||||
.meal-card__kcal .meal-card__kcal-unit { font-size: 12px; font-weight: 400; color: #bbb; }
|
||||
.meal-card__expand { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #bbb; transition: transform .25s; }
|
||||
.meal-card__expand.open { transform: rotate(180deg); }
|
||||
|
||||
@@ -131,6 +133,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.meal-item__src--wechat { color: #597ef7; background: #f0f5ff; }
|
||||
.meal-item__meta { font-size: 11px; color: #bbb; margin-top: 1px; }
|
||||
.meal-item__kcal { font-size: 13px; font-weight: 700; color: #fa8c16; white-space: nowrap; flex-shrink: 0; }
|
||||
.meal-item__kcal-unit { font-size: 11px; font-weight: 400; color: #bbb; }
|
||||
.meal-item--exercise .meal-item__kcal { color: #52c41a; }
|
||||
.meal-empty { text-align: center; padding: 16px 0; color: #ccc; font-size: 13px; }
|
||||
|
||||
@@ -241,18 +244,10 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<circle cx="90" cy="135" r="5" fill="#bbb" stroke="#fff" stroke-width="2.5"/>
|
||||
<circle cx="250" cy="135" r="5" fill="#52c41a" stroke="#fff" stroke-width="2.5"/>
|
||||
|
||||
<!-- 左侧端点下方:饮食摄入 -->
|
||||
<text x="90" y="150" font-size="12" fill="#999" text-anchor="middle">饮食摄入</text>
|
||||
<text x="90" y="165" font-size="18" fill="#fa8c16" text-anchor="middle" font-weight="800"><tspan id="intakeText">1086</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1950 千卡</tspan></text>
|
||||
|
||||
<!-- 右侧端点下方:运动消耗 -->
|
||||
<text x="250" y="150" font-size="12" fill="#999" text-anchor="middle">运动消耗</text>
|
||||
<text x="250" y="165" font-size="18" fill="#52c41a" text-anchor="middle" font-weight="800"><tspan id="consumeText">820</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1000 千卡</tspan></text>
|
||||
|
||||
<!-- 中心 -->
|
||||
<text x="170" y="88" font-size="12" fill="#999" text-anchor="middle">吃动热量差</text>
|
||||
<text id="gapCenterVal" x="170" y="120" font-size="28" fill="#fa8c16" text-anchor="middle" font-weight="800">-364</text>
|
||||
<text x="170" y="137" font-size="11" fill="#bbb" text-anchor="middle">/ -500 千卡</text>
|
||||
<text x="170" y="88" font-size="12" fill="#999" text-anchor="middle">总摄入</text>
|
||||
<text id="gapCenterVal" x="170" y="120" font-size="28" fill="#fa8c16" text-anchor="middle" font-weight="800">1086</text>
|
||||
<text x="170" y="137" font-size="11" fill="#bbb" text-anchor="middle">/ 1950 千卡</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@@ -284,7 +279,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<span class="meal-card__name">早餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalBreakfast">320</span> kcal</span>
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalBreakfast">320</span><span class="meal-card__kcal-target" id="kcalBreakfastTarget">/500</span><span class="meal-card__kcal-unit"> 千卡</span></span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
@@ -326,7 +321,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<span class="meal-card__name">午餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalLunch">480</span> kcal</span>
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalLunch">480</span><span class="meal-card__kcal-target" id="kcalLunchTarget">/650</span><span class="meal-card__kcal-unit"> 千卡</span></span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
@@ -368,7 +363,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<span class="meal-card__name">晚餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalDinner">220</span> kcal</span>
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalDinner">220</span><span class="meal-card__kcal-target" id="kcalDinnerTarget">/550</span><span class="meal-card__kcal-unit"> 千卡</span></span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
@@ -402,7 +397,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<span class="meal-card__name">加餐</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalSnack">66</span> kcal</span>
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalSnack">66</span><span class="meal-card__kcal-target" id="kcalSnackTarget">/250</span><span class="meal-card__kcal-unit"> 千卡</span></span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
@@ -420,40 +415,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 运动卡片 ====== -->
|
||||
<div class="meal-card" id="cardExercise">
|
||||
<div class="meal-card__header" onclick="toggleMeal('exercise', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--exercise">🏃</div>
|
||||
<span class="meal-card__name">运动</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--out"><span id="kcalExercise">-320</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupExercise">
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🏃</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">户外跑步</div>
|
||||
<div class="meal-item__meta">5.2km · 32分钟</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-260 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🚶</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">步行</div>
|
||||
<div class="meal-item__meta">6800步 · 今日累计</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-60 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 饮食未记录缺省卡片 -->
|
||||
<div class="meal-card" id="cardEmptyDiet" style="display:none;">
|
||||
<div style="text-align:center;padding:24px 0;color:#ccc;">
|
||||
@@ -483,10 +444,6 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
加餐
|
||||
</button>
|
||||
<button class="toolbar__btn toolbar__btn--exercise" onclick="addMeal('exercise')">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
运动
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -776,9 +733,8 @@ function selectDay(el) {
|
||||
data = { intake: 0, consume: 0, gap: 0 };
|
||||
}
|
||||
|
||||
var gapAbs = Math.abs(data.gap);
|
||||
var maxGap = 500;
|
||||
var progress = data.gap === 0 ? 0 : Math.min(gapAbs / maxGap, 1);
|
||||
var targetIntake = 1950;
|
||||
var progress = data.intake === 0 ? 0 : Math.min(data.intake / targetIntake, 1);
|
||||
|
||||
var pt = arcPoint(progress);
|
||||
var arcD = 'M 90 135 A 80 80 0 0 1 ' + pt.x + ' ' + pt.y;
|
||||
@@ -786,21 +742,13 @@ function selectDay(el) {
|
||||
var gapArc = document.getElementById('gapArc');
|
||||
gapArc.setAttribute('d', arcD);
|
||||
|
||||
document.getElementById('intakeText').textContent = data.intake === 0 ? '--' : data.intake;
|
||||
document.getElementById('consumeText').textContent = data.consume === 0 ? '--' : data.consume;
|
||||
|
||||
var gapCenter = document.getElementById('gapCenterVal');
|
||||
gapCenter.textContent = data.gap === 0 ? '--' : ('-' + Math.abs(data.gap));
|
||||
gapCenter.textContent = data.intake === 0 ? '--' : data.intake;
|
||||
|
||||
var colorIntake = data.intake === 0 ? '#bbb' : '#fa8c16';
|
||||
var colorConsume = data.consume === 0 ? '#bbb' : '#52c41a';
|
||||
var colorGap = data.gap === 0 ? '#bbb' : '#fa8c16';
|
||||
document.getElementById('intakeText').setAttribute('fill', colorIntake);
|
||||
document.getElementById('consumeText').setAttribute('fill', colorConsume);
|
||||
gapCenter.setAttribute('fill', colorGap);
|
||||
gapCenter.setAttribute('fill', data.intake === 0 ? '#bbb' : '#fa8c16');
|
||||
|
||||
var rightDot = document.querySelector('.gauge-wrap svg circle[cy="135"][cx="250"]');
|
||||
rightDot.setAttribute('fill', data.gap === 0 ? '#bbb' : '#52c41a');
|
||||
rightDot.setAttribute('fill', data.intake === 0 ? '#bbb' : '#52c41a');
|
||||
|
||||
// 更新餐食卡片
|
||||
renderMeals(dateStr);
|
||||
@@ -819,6 +767,9 @@ function renderMeals(dateStr) {
|
||||
if (md && md.items && md.items.length > 0) hasAnyDiet = true;
|
||||
});
|
||||
|
||||
// ===== 各餐推荐千卡 =====
|
||||
var mealTargets = { breakfast: 500, lunch: 650, dinner: 550, snack: 250 };
|
||||
|
||||
if (hasAnyDiet) {
|
||||
// 有饮食记录:逐卡片显示/隐藏
|
||||
document.getElementById('cardEmptyDiet').style.display = 'none';
|
||||
@@ -827,6 +778,7 @@ function renderMeals(dateStr) {
|
||||
var card = document.getElementById('card' + cap);
|
||||
var container = document.getElementById('group' + cap);
|
||||
var kcalEl = document.getElementById('kcal' + cap);
|
||||
var kcalTargetEl = document.getElementById('kcal' + cap + 'Target');
|
||||
var md = meals ? meals[type] : null;
|
||||
|
||||
if (md && md.items && md.items.length > 0) {
|
||||
@@ -839,11 +791,12 @@ function renderMeals(dateStr) {
|
||||
html += '<div class="meal-item">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + '<span class="meal-item__src meal-item__src--' + src + '">' + srcLabel + '</span></div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
'<div class="meal-item__kcal">' + item.k + '<span class="meal-item__kcal-unit"> 千卡</span></div></div>';
|
||||
});
|
||||
container.innerHTML = html;
|
||||
container.style.display = '';
|
||||
kcalEl.textContent = md.kcal;
|
||||
kcalTargetEl.textContent = '/' + mealTargets[type];
|
||||
kcalEl.parentElement.style.display = '';
|
||||
} else {
|
||||
card.style.display = 'none';
|
||||
@@ -857,32 +810,6 @@ function renderMeals(dateStr) {
|
||||
document.getElementById('cardEmptyDiet').style.display = '';
|
||||
}
|
||||
|
||||
// 运动卡片独立处理
|
||||
var exCard = document.getElementById('cardExercise');
|
||||
var exContainer = document.getElementById('groupExercise');
|
||||
var exKcalEl = document.getElementById('kcalExercise');
|
||||
var exMd = meals ? meals['exercise'] : null;
|
||||
if (exMd && exMd.items && exMd.items.length > 0) {
|
||||
exCard.style.display = '';
|
||||
var html = '';
|
||||
exMd.items.forEach(function(item) {
|
||||
var srcTag = '';
|
||||
if (item.src) {
|
||||
srcTag = '<span class="meal-item__src meal-item__src--' + item.src + '">' + ({wearable:'穿戴',equip:'器械',wechat:'微信',manual:'自记'}[item.src] || item.src) + '</span>';
|
||||
}
|
||||
html += '<div class="meal-item meal-item--exercise">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + srcTag + '</div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
});
|
||||
exContainer.innerHTML = html;
|
||||
exContainer.style.display = '';
|
||||
exKcalEl.textContent = exMd.kcal;
|
||||
exKcalEl.parentElement.style.display = '';
|
||||
} else {
|
||||
exCard.style.display = 'none';
|
||||
}
|
||||
|
||||
// 更新营养素三列
|
||||
var macrosRow = document.getElementById('macrosRow');
|
||||
var macros = data && data.macros;
|
||||
|
||||
@@ -0,0 +1,790 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>吃动平衡 - 员工端 | 健康CQ原型 v2</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: #f0f2f5; display: flex; justify-content: center; align-items: flex-start; min-height: 100vh; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; }
|
||||
.phone-shell { width: 390px; height: 844px; background: #f5f7fa; border-radius: 44px; box-shadow: 0 20px 60px rgba(0,0,0,0.25), inset 0 0 0 2px #e0e0e0; overflow: hidden; display: flex; flex-direction: column; }
|
||||
|
||||
.status-bar { height: 44px; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; flex-shrink: 0; background: #fff; }
|
||||
.status-bar .time { font-size: 15px; font-weight: 700; color: #333; }
|
||||
.status-bar .icons { display: flex; gap: 6px; align-items: center; }
|
||||
.nav-bar { height: 44px; background: #fff; display: flex; align-items: center; padding: 0 16px; flex-shrink: 0; border-bottom: 1px solid #f0f0f0; }
|
||||
.nav-back { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #1a1a1a; }
|
||||
.nav-title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; color: #1a1a1a; }
|
||||
.nav-placeholder { width: 28px; height: 28px; }
|
||||
|
||||
.scroll-content { flex: 1; overflow-y: auto; background: #f5f7fa; }
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 周日历 ===== */
|
||||
.calendar-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 14px 12px 10px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); position: relative; }
|
||||
.calendar-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.calendar-card__arrow { width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #999; border-radius: 50%; transition: background .2s; user-select: none; }
|
||||
.calendar-card__arrow:hover { background: #f0f0f0; color: #333; }
|
||||
.calendar-card__range { font-size: 13px; font-weight: 600; color: #333; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; }
|
||||
.calendar-card__range svg { flex-shrink: 0; }
|
||||
.calendar-card__date-arrow { transition: transform .2s; }
|
||||
.calendar-card__date-arrow.open { transform: rotate(180deg); }
|
||||
|
||||
/* ===== 月历弹窗 ===== */
|
||||
.month-picker { position: absolute; top: 46px; left: 12px; right: 12px; z-index: 20; background: #fff; border-radius: 14px; padding: 12px 14px; box-shadow: 0 8px 30px rgba(0,0,0,0.15); display: none; }
|
||||
.month-picker.show { display: block; }
|
||||
.month-picker__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
|
||||
.month-picker__title { font-size: 14px; font-weight: 700; color: #1a1a1a; }
|
||||
.month-picker__nav { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #999; border-radius: 50%; font-size: 13px; }
|
||||
.month-picker__nav:hover { background: #f0f0f0; }
|
||||
.month-picker__weekdays { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 11px; color: #bbb; margin-bottom: 6px; }
|
||||
.month-picker__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
|
||||
.month-picker__day { padding: 6px 0; font-size: 13px; color: #333; border-radius: 8px; cursor: pointer; font-weight: 500; position: relative; }
|
||||
.month-picker__day:hover { background: #f5f5f5; }
|
||||
.month-picker__day--other { color: #ddd; }
|
||||
.month-picker__day--today { background: #e8fbfa; color: #36cfc9; font-weight: 700; }
|
||||
.month-picker__day--selected { background: #36cfc9; color: #fff; font-weight: 700; }
|
||||
/* 月历日期数字 + 进度圆环 */
|
||||
.month-picker__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; }
|
||||
.month-picker__ring-svg { position: absolute; inset: 0; width: 26px; height: 26px; }
|
||||
.cal-week { display: flex; gap: 4px; }
|
||||
.cal-day { flex: 1; text-align: center; padding: 8px 0 8px; border-radius: 12px; cursor: pointer; background: #f7f8fa; transition: background .2s; }
|
||||
.cal-day.active { background: #e8fbfa; }
|
||||
.cal-day.today .cal-day__num { color: #1a1a1a; font-weight: 800; }
|
||||
.cal-day.active .cal-day__num { color: #36cfc9; font-weight: 800; }
|
||||
.cal-day.active .cal-day__wd { color: #36cfc9; font-weight: 600; }
|
||||
.cal-day__wd { font-size: 10px; color: #999; margin-bottom: 4px; }
|
||||
/* 日期数字 + 进度圆环 */
|
||||
.cal-day__date-wrap { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; margin: 0 auto; }
|
||||
.cal-day__ring-svg { position: absolute; inset: 0; width: 30px; height: 30px; z-index: 1; }
|
||||
.cal-day__num { font-size: 15px; font-weight: 700; color: #333; position: relative; z-index: 2; }
|
||||
|
||||
/* ===== 月历进度图例 ===== */
|
||||
.month-picker__legend { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 14px; margin-top: 8px; padding-top: 8px; font-size: 11px; color: #666; }
|
||||
.month-picker__legend-item { display: inline-flex; align-items: center; gap: 4px; }
|
||||
.month-picker__legend-ring { width: 12px; height: 12px; border-radius: 50%; border: 2.5px solid #36cfc9; background: transparent; }
|
||||
|
||||
/* ===== 热量缺口标尺卡片 ===== */
|
||||
.gap-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.gap-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }
|
||||
.gap-card__title { font-size: 16px; font-weight: 800; color: #1a1a1a; }
|
||||
.gap-card__target { font-size: 12px; font-weight: 600; color: #36cfc9; }
|
||||
|
||||
/* ===== 标尺 SVG ===== */
|
||||
.gauge-wrap { width: 100%; margin-top: -30px; position: relative; }
|
||||
.gauge-wrap svg { width: 100%; height: auto; display: block; }
|
||||
.recipe-btn { position: absolute; top: 44px; padding: 5px 12px; border-radius: 14px; border: none; color: #fff; font-size: 11px; font-weight: 600; cursor: pointer; z-index: 5; }
|
||||
.recipe-btn--diet { left: 8px; background: linear-gradient(160deg, #36cfc9, #2db8b0); box-shadow: 0 2px 6px rgba(54,207,201,0.3); }
|
||||
.recipe-btn--exercise { right: 8px; background: linear-gradient(160deg, #ffb066, #ff8a3d); box-shadow: 0 2px 6px rgba(255,138,61,0.3); }
|
||||
|
||||
/* ===== 餐食卡片通用 ===== */
|
||||
.meal-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 14px 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.meal-card__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; cursor: pointer; }
|
||||
.meal-card__left { display: flex; align-items: center; gap: 8px; }
|
||||
.meal-card__icon { width: 28px; height: 28px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 14px; }
|
||||
.meal-card__icon--breakfast { background: #fff3e0; color: #fa8c16; }
|
||||
.meal-card__icon--lunch { background: #fff1f0; color: #ee6666; }
|
||||
.meal-card__icon--dinner { background: #f0f0ff; color: #5470c6; }
|
||||
.meal-card__icon--snack { background: #fffbe6; color: #fac858; }
|
||||
.meal-card__icon--exercise { background: #f0fff0; color: #52c41a; }
|
||||
.meal-card__name { font-size: 15px; font-weight: 700; color: #1a1a1a; }
|
||||
.meal-card__kcal { font-size: 13px; font-weight: 600; }
|
||||
.meal-card__kcal span { font-size: 17px; font-weight: 800; }
|
||||
.meal-card__kcal--in { color: #fa8c16; }
|
||||
.meal-card__kcal--in span { color: #fa8c16; }
|
||||
.meal-card__kcal--out { color: #52c41a; }
|
||||
.meal-card__kcal--out span { color: #52c41a; }
|
||||
.meal-card__expand { width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: #bbb; transition: transform .25s; }
|
||||
.meal-card__expand.open { transform: rotate(180deg); }
|
||||
|
||||
/* 食物列表 */
|
||||
.meal-items { display: flex; flex-direction: column; gap: 6px; }
|
||||
.meal-item { display: flex; align-items: center; padding: 6px 10px; background: #f7f8fa; border-radius: 8px; gap: 8px; }
|
||||
.meal-item__emoji { font-size: 18px; width: 24px; text-align: center; flex-shrink: 0; }
|
||||
.meal-item__info { flex: 1; min-width: 0; }
|
||||
.meal-item__name { font-size: 13px; color: #333; font-weight: 500; display: flex; align-items: center; gap: 6px; }
|
||||
.meal-item__src { font-size: 9px; font-weight: 600; padding: 1px 6px; border-radius: 6px; white-space: nowrap; line-height: 1.5; }
|
||||
.meal-item__src--auto { color: #1890ff; background: #e6f7ff; }
|
||||
.meal-item__src--manual { color: #fa8c16; background: #fff7e6; }
|
||||
.meal-item__src--wearable { color: #1890ff; background: #e6f7ff; }
|
||||
.meal-item__src--equip { color: #52c41a; background: #f6ffed; }
|
||||
.meal-item__src--wechat { color: #597ef7; background: #f0f5ff; }
|
||||
.meal-item__meta { font-size: 11px; color: #bbb; margin-top: 1px; }
|
||||
.meal-item__kcal { font-size: 13px; font-weight: 700; color: #fa8c16; white-space: nowrap; flex-shrink: 0; }
|
||||
.meal-item--exercise .meal-item__kcal { color: #52c41a; }
|
||||
.meal-empty { text-align: center; padding: 16px 0; color: #ccc; font-size: 13px; }
|
||||
|
||||
/* ===== 饮食子分组 ===== */
|
||||
.diet-sub { border-bottom: 1px solid #f5f5f5; }
|
||||
.diet-sub:last-child { border-bottom: none; }
|
||||
.diet-sub__header { display: flex; align-items: center; padding: 10px 0; cursor: pointer; gap: 8px; }
|
||||
.diet-sub__name { font-size: 14px; font-weight: 600; color: #1a1a1a; flex: 1; }
|
||||
.diet-sub__kcal { font-size: 13px; font-weight: 600; color: #fa8c16; }
|
||||
.diet-sub__empty { text-align: center; padding: 10px 0; color: #ccc; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="phone-shell">
|
||||
|
||||
<div class="status-bar">
|
||||
<span class="time">09:40</span>
|
||||
<div class="icons">
|
||||
<svg width="16" height="16" fill="none"><rect x="1" y="4" width="3" height="8" rx="1" fill="#333"/><rect x="5" y="3" width="3" height="9" rx="1" fill="#333"/><rect x="9" y="1" width="3" height="11" rx="1" fill="#333"/><rect x="13" y="0" width="3" height="12" rx="1" fill="#333" opacity=".3"/></svg>
|
||||
<svg width="16" height="16" fill="none"><path d="M8 3C5.5 3 3.2 4 1.5 5.5l1.4 1.4C4.3 5.5 6.1 5 8 5s3.7.5 5.1 1.9l1.4-1.4C12.8 4 10.5 3 8 3zm0 4c-1.4 0-2.6.5-3.5 1.3L6 9.8c.6-.5 1.3-.8 2-.8s1.4.3 2 .8l1.5-1.5C10.6 7.5 9.4 7 8 7zm0 4c-.6 0-1 .4-1 1s.4 1 1 1 1-.4 1-1-.4-1-1-1z" fill="#333"/></svg>
|
||||
<svg width="22" height="12" fill="none"><rect x=".5" y=".5" width="19" height="11" rx="2" stroke="#333"/><rect x="20" y="3.5" width="1.5" height="5" rx=".75" fill="#333"/><rect x="2" y="2" width="14" height="8" rx="1" fill="#333"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav-bar">
|
||||
<div class="nav-back" onclick="history.back()">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</div>
|
||||
<div class="nav-title">吃动平衡</div>
|
||||
<div class="nav-placeholder"></div>
|
||||
</div>
|
||||
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- ====== 本周7日日历 ====== -->
|
||||
<div class="calendar-card">
|
||||
<div class="calendar-card__header">
|
||||
<div class="calendar-card__arrow" id="calPrev" onclick="prevWeek()">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
||||
</div>
|
||||
<span class="calendar-card__range" onclick="toggleMonthPicker()">
|
||||
<span id="calRange">2026年7月23日</span>
|
||||
<svg class="calendar-card__date-arrow" id="dateArrow" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</span>
|
||||
<div class="calendar-card__arrow" id="calNext" onclick="nextWeek()">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 月历弹窗 -->
|
||||
<div class="month-picker" id="monthPicker">
|
||||
<div class="month-picker__header">
|
||||
<div class="month-picker__nav" onclick="event.stopPropagation();prevMonth()">◀</div>
|
||||
<span class="month-picker__title" id="monthPickerTitle">2026年7月</span>
|
||||
<div class="month-picker__nav" onclick="event.stopPropagation();nextMonth()">▶</div>
|
||||
</div>
|
||||
<div class="month-picker__weekdays">
|
||||
<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>
|
||||
</div>
|
||||
<div class="month-picker__grid" id="monthGrid"></div>
|
||||
<!-- 图例:来源颜色 -->
|
||||
<div class="month-picker__legend">
|
||||
<span class="month-picker__legend-item"><span class="month-picker__legend-ring"></span>推荐热量差 完成进度</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cal-week" id="calWeek"></div>
|
||||
|
||||
<div class="gauge-wrap">
|
||||
<button class="recipe-btn recipe-btn--diet" onclick="location.href='diet-advice-v2.html'">今日饮食建议</button>
|
||||
<button class="recipe-btn recipe-btn--exercise" onclick="location.href='exercise-advice-v2.html'">智能运动计划</button>
|
||||
<svg viewBox="0 0 340 170" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="gapGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="#ffc069"/>
|
||||
<stop offset="35%" stop-color="#fa8c16"/>
|
||||
<stop offset="100%" stop-color="#52c41a"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="glowGrad" cx="50%" cy="70%" r="55%">
|
||||
<stop offset="0%" stop-color="#e8fbfa" stop-opacity="0.3"/>
|
||||
<stop offset="100%" stop-color="#fff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="340" height="170" fill="url(#glowGrad)"/>
|
||||
|
||||
<!-- 灰色底轨 -->
|
||||
<path d="M 90 135 A 80 80 0 0 1 250 135"
|
||||
fill="none" stroke="#ebeef0" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- 进度弧 -->
|
||||
<path id="gapArc" d="M 90 135 A 80 80 0 0 1 222 75"
|
||||
fill="none" stroke="url(#gapGrad)" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- 刻度圆点 -->
|
||||
<circle cx="98" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="120" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="152" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="188" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="220" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="242" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
|
||||
<!-- 端点 -->
|
||||
<circle cx="90" cy="135" r="5" fill="#bbb" stroke="#fff" stroke-width="2.5"/>
|
||||
<circle cx="250" cy="135" r="5" fill="#52c41a" stroke="#fff" stroke-width="2.5"/>
|
||||
|
||||
<!-- 左侧端点下方:饮食摄入 -->
|
||||
<text x="90" y="150" font-size="12" fill="#999" text-anchor="middle">饮食摄入</text>
|
||||
<text x="90" y="165" font-size="18" fill="#fa8c16" text-anchor="middle" font-weight="800"><tspan id="intakeText">1086</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1950 千卡</tspan></text>
|
||||
|
||||
<!-- 右侧端点下方:运动消耗 -->
|
||||
<text x="250" y="150" font-size="12" fill="#999" text-anchor="middle">运动消耗</text>
|
||||
<text x="250" y="165" font-size="18" fill="#52c41a" text-anchor="middle" font-weight="800"><tspan id="consumeText">820</tspan><tspan font-size="10" font-weight="400" fill="#bbb">/1000 千卡</tspan></text>
|
||||
|
||||
<!-- 中心 -->
|
||||
<text x="170" y="88" font-size="12" fill="#999" text-anchor="middle">吃动热量差</text>
|
||||
<text id="gapCenterVal" x="170" y="120" font-size="28" fill="#fa8c16" text-anchor="middle" font-weight="800">-364</text>
|
||||
<text x="170" y="137" font-size="11" fill="#bbb" text-anchor="middle">/ -500 千卡</text>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ====== 饮食卡片(早餐·午餐·晚餐·加餐) ====== -->
|
||||
<div class="meal-card" id="cardDiet">
|
||||
<div class="meal-card__header">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--breakfast">🍽️</div>
|
||||
<span class="meal-card__name">饮食</span>
|
||||
</div>
|
||||
<span class="meal-card__kcal meal-card__kcal--in"><span id="kcalDiet">1086</span> kcal</span>
|
||||
</div>
|
||||
|
||||
<!-- 早餐 -->
|
||||
<div class="diet-sub" id="dietSubBreakfast">
|
||||
<div class="diet-sub__header" onclick="toggleDietSub('breakfast', this)">
|
||||
<div class="meal-card__icon meal-card__icon--breakfast" style="width:22px;height:22px;font-size:11px;">☀</div>
|
||||
<span class="diet-sub__name">早餐</span>
|
||||
<span class="diet-sub__kcal" id="kcalBreakfast">320</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupBreakfast">
|
||||
<div class="meal-item"><div class="meal-item__emoji">🥚</div><div class="meal-item__info"><div class="meal-item__name">水煮鸡蛋<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×1 · 约50g</div></div><div class="meal-item__kcal">80 kcal</div></div>
|
||||
<div class="meal-item"><div class="meal-item__emoji">🥛</div><div class="meal-item__info"><div class="meal-item__name">纯牛奶<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×1 · 250ml</div></div><div class="meal-item__kcal">120 kcal</div></div>
|
||||
<div class="meal-item"><div class="meal-item__emoji">🍞</div><div class="meal-item__info"><div class="meal-item__name">全麦面包<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×2 · 约80g</div></div><div class="meal-item__kcal">120 kcal</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 午餐 -->
|
||||
<div class="diet-sub" id="dietSubLunch">
|
||||
<div class="diet-sub__header" onclick="toggleDietSub('lunch', this)">
|
||||
<div class="meal-card__icon meal-card__icon--lunch" style="width:22px;height:22px;font-size:11px;">☀</div>
|
||||
<span class="diet-sub__name">午餐</span>
|
||||
<span class="diet-sub__kcal" id="kcalLunch">480</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupLunch">
|
||||
<div class="meal-item"><div class="meal-item__emoji">🍚</div><div class="meal-item__info"><div class="meal-item__name">白米饭<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×1 · 约200g</div></div><div class="meal-item__kcal">232 kcal</div></div>
|
||||
<div class="meal-item"><div class="meal-item__emoji">🐔</div><div class="meal-item__info"><div class="meal-item__name">宫保鸡丁<span class="meal-item__src meal-item__src--manual">自记</span></div><div class="meal-item__meta">×1 · 约150g</div></div><div class="meal-item__kcal">148 kcal</div></div>
|
||||
<div class="meal-item"><div class="meal-item__emoji">🥬</div><div class="meal-item__info"><div class="meal-item__name">清炒时蔬<span class="meal-item__src meal-item__src--manual">自记</span></div><div class="meal-item__meta">×1 · 约200g</div></div><div class="meal-item__kcal">100 kcal</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 晚餐 -->
|
||||
<div class="diet-sub" id="dietSubDinner">
|
||||
<div class="diet-sub__header" onclick="toggleDietSub('dinner', this)">
|
||||
<div class="meal-card__icon meal-card__icon--dinner" style="width:22px;height:22px;font-size:11px;">🌙</div>
|
||||
<span class="diet-sub__name">晚餐</span>
|
||||
<span class="diet-sub__kcal" id="kcalDinner">220</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupDinner">
|
||||
<div class="meal-item"><div class="meal-item__emoji">🥗</div><div class="meal-item__info"><div class="meal-item__name">鸡胸肉沙拉<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×1 · 约250g</div></div><div class="meal-item__kcal">180 kcal</div></div>
|
||||
<div class="meal-item"><div class="meal-item__emoji">🍠</div><div class="meal-item__info"><div class="meal-item__name">蒸红薯<span class="meal-item__src meal-item__src--auto">智记</span></div><div class="meal-item__meta">×1 · 约100g</div></div><div class="meal-item__kcal">40 kcal</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 加餐 -->
|
||||
<div class="diet-sub" id="dietSubSnack">
|
||||
<div class="diet-sub__header" onclick="toggleDietSub('snack', this)">
|
||||
<div class="meal-card__icon meal-card__icon--snack" style="width:22px;height:22px;font-size:11px;">🍎</div>
|
||||
<span class="diet-sub__name">加餐</span>
|
||||
<span class="diet-sub__kcal" id="kcalSnack">66</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupSnack">
|
||||
<div class="meal-item"><div class="meal-item__emoji">🍎</div><div class="meal-item__info"><div class="meal-item__name">苹果<span class="meal-item__src meal-item__src--manual">自记</span></div><div class="meal-item__meta">×1 · 约200g</div></div><div class="meal-item__kcal">66 kcal</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 暂无饮食记录 -->
|
||||
<div class="diet-sub__empty" id="dietEmpty" style="display:none;">暂无饮食记录</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 运动卡片 ====== -->
|
||||
<div class="meal-card" id="cardExercise">
|
||||
<div class="meal-card__header" onclick="toggleMeal('exercise', this)">
|
||||
<div class="meal-card__left">
|
||||
<div class="meal-card__icon meal-card__icon--exercise">🏃</div>
|
||||
<span class="meal-card__name">运动</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<span class="meal-card__kcal meal-card__kcal--out"><span id="kcalExercise">-320</span> kcal</span>
|
||||
<div class="meal-card__expand">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meal-items" id="groupExercise">
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🏃</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">户外跑步</div>
|
||||
<div class="meal-item__meta">5.2km · 32分钟</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-260 kcal</div>
|
||||
</div>
|
||||
<div class="meal-item meal-item--exercise">
|
||||
<div class="meal-item__emoji">🚶</div>
|
||||
<div class="meal-item__info">
|
||||
<div class="meal-item__name">步行</div>
|
||||
<div class="meal-item__meta">6800步 · 今日累计</div>
|
||||
</div>
|
||||
<div class="meal-item__kcal">-60 kcal</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="height: 20px; flex-shrink: 0;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/* ===== 日历数据(按日期存储) ===== */
|
||||
var dayData = {
|
||||
'2026-07-20': { intake: 1050, consume: 780, gap: -380, macros: {carb:140,carbT:260,protein:52,proteinT:82,fat:28,fatT:60}, meals: {
|
||||
breakfast: { source:'manual', kcal: 280, items: [{e:'🥚',n:'水煮鸡蛋',m:'×1',k:80},{e:'🥛',n:'纯牛奶',m:'×1 · 250ml',k:120},{e:'🍞',n:'全麦面包',m:'×1',k:80}] },
|
||||
lunch: { source:'auto', kcal: 450, items: [{e:'🍚',n:'白米饭',m:'×1 · 约200g',k:232},{e:'🐔',n:'红烧鸡块',m:'×1 · 约150g',k:140},{e:'🥬',n:'炒青菜',m:'×1',k:78}] },
|
||||
dinner: { source:'auto', kcal: 260, items: [{e:'🥗',n:'蔬菜沙拉',m:'×1 · 约200g',k:160},{e:'🍠',n:'蒸红薯',m:'×1',k:100}] },
|
||||
snack: { source:'manual', kcal: 60, items: [{e:'🍌',n:'香蕉',m:'×1',k:60}] },
|
||||
exercise: { kcal: -280, items: [{e:'🏃',n:'户外跑步',m:'4.5km · 28分钟',k:-200,src:'wearable'},{e:'🚶',n:'步行',m:'5500步',k:-80,src:'wechat'}] }
|
||||
}},
|
||||
'2026-07-21': { intake: 1120, consume: 790, gap: -330, macros: {carb:165,carbT:260,protein:44,proteinT:82,fat:34,fatT:60}, meals: {
|
||||
breakfast: { source:'manual', kcal: 350, items: [{e:'🥛',n:'豆浆',m:'×1 · 300ml',k:90},{e:'🥮',n:'肉包',m:'×2',k:180},{e:'🥚',n:'茶叶蛋',m:'×1',k:80}] },
|
||||
lunch: { source:'manual', kcal: 480, items: [{e:'🍜',n:'牛肉面',m:'×1 · 约400g',k:380},{e:'🥒',n:'凉拌黄瓜',m:'×1',k:100}] },
|
||||
dinner: { source:'manual', kcal: 210, items: [{e:'🐟',n:'清蒸鱼',m:'×1 · 约150g',k:130},{e:'🥦',n:'西兰花',m:'×1',k:80}] },
|
||||
snack: { source:'manual', kcal: 80, items: [{e:'🥜',n:'坚果',m:'×1把 · 约20g',k:80}] },
|
||||
exercise: { kcal: -250, items: [{e:'🚴',n:'骑行',m:'8km · 35分钟',k:-250,src:'equip'}] }
|
||||
}},
|
||||
'2026-07-22': { intake: 980, consume: 740, gap: -412, macros: {carb:120,carbT:260,protein:58,proteinT:82,fat:22,fatT:60}, meals: {
|
||||
breakfast: { source:'auto', kcal: 220, items: [{e:'🥚',n:'水煮蛋',m:'×2',k:160},{e:'☕',n:'黑咖啡',m:'×1',k:5},{e:'🍞',n:'全麦吐司',m:'×1',k:55}] },
|
||||
lunch: { source:'auto', kcal: 420, items: [{e:'🍚',n:'杂粮饭',m:'×1 · 约180g',k:200},{e:'🐔',n:'鸡胸肉',m:'×1 · 约120g',k:120},{e:'🥬',n:'蒜蓉菠菜',m:'×1',k:100}] },
|
||||
dinner: { source:'auto', kcal: 280, items: [{e:'🥗',n:'凯撒沙拉',m:'×1 · 约250g',k:220},{e:'🍎',n:'苹果',m:'×1',k:60}] },
|
||||
snack: { source:'auto', kcal: 60, items: [{e:'🥒',n:'黄瓜',m:'×1根',k:15},{e:'🍅',n:'小番茄',m:'×5颗',k:45}] },
|
||||
exercise: { kcal: -320, items: [{e:'🏊',n:'游泳',m:'40分钟',k:-260,src:'wearable'},{e:'🚶',n:'步行',m:'5000步',k:-60,src:'wechat'}] }
|
||||
}},
|
||||
'2026-07-23': { intake: 1086, consume: 820, gap: -364, macros: {carb:155,carbT:260,protein:47,proteinT:82,fat:31,fatT:60}, meals: {
|
||||
breakfast: { source:'auto', kcal: 320, items: [{e:'🥚',n:'水煮鸡蛋',m:'×1 · 约50g',k:80},{e:'🥛',n:'纯牛奶',m:'×1 · 250ml',k:120},{e:'🍞',n:'全麦面包',m:'×2 · 约80g',k:120}] },
|
||||
lunch: { source:'manual', kcal: 480, items: [{e:'🍚',n:'白米饭',m:'×1 · 约200g',k:232,src:'auto'},{e:'🐔',n:'宫保鸡丁',m:'×1 · 约150g',k:148},{e:'🥬',n:'清炒时蔬',m:'×1 · 约200g',k:100}] },
|
||||
dinner: { source:'auto', kcal: 220, items: [{e:'🥗',n:'鸡胸肉沙拉',m:'×1 · 约250g',k:180},{e:'🍠',n:'蒸红薯',m:'×1 · 约100g',k:40}] },
|
||||
snack: { source:'manual', kcal: 66, items: [{e:'🍎',n:'苹果',m:'×1 · 约200g',k:66}] },
|
||||
exercise: { kcal: -320, items: [{e:'🏃',n:'户外跑步',m:'5.2km · 32分钟',k:-260,src:'wearable'},{e:'🚶',n:'步行',m:'6800步 · 今日累计',k:-60,src:'wechat'}] }
|
||||
}},
|
||||
'2026-07-24': { intake: 0, consume: 0, gap: 0 },
|
||||
'2026-07-25': { intake: 0, consume: 0, gap: 0 },
|
||||
'2026-07-26': { intake: 0, consume: 0, gap: 0 }
|
||||
};
|
||||
|
||||
/* ===== 周导航 ===== */
|
||||
var WEEK_MS = 7 * 24 * 60 * 60 * 1000;
|
||||
var today = new Date(2026, 6, 23); // 2026-07-23
|
||||
var currentWeekStart = getMonday(today);
|
||||
|
||||
/* 获取某日期所在周的周一 */
|
||||
function getMonday(d) {
|
||||
var m = new Date(d);
|
||||
var day = m.getDay(); // 0=Sun, 1=Mon, ...
|
||||
var diff = day === 0 ? -6 : 1 - day;
|
||||
m.setDate(m.getDate() + diff);
|
||||
m.setHours(0, 0, 0, 0);
|
||||
return m;
|
||||
}
|
||||
|
||||
/* 格式化日期:YYYY-MM-DD */
|
||||
function fmtDate(d) {
|
||||
var y = d.getFullYear();
|
||||
var m = ('0' + (d.getMonth() + 1)).slice(-2);
|
||||
var day = ('0' + d.getDate()).slice(-2);
|
||||
return y + '-' + m + '-' + day;
|
||||
}
|
||||
|
||||
/* 格式化中文日期 */
|
||||
function fmtDateCN(d) {
|
||||
return d.getFullYear() + '年' + (d.getMonth() + 1) + '月' + d.getDate() + '日';
|
||||
}
|
||||
|
||||
/* 判断两个日期是否同一天 */
|
||||
function isSameDay(a, b) {
|
||||
return a.getFullYear() === b.getFullYear() &&
|
||||
a.getMonth() === b.getMonth() &&
|
||||
a.getDate() === b.getDate();
|
||||
}
|
||||
|
||||
/* 生成进度圆环 SVG */
|
||||
function ringSVG(progress) {
|
||||
var r = 13, cx = 15, cy = 15, size = 30;
|
||||
var circumference = 2 * Math.PI * r;
|
||||
var offset = circumference * (1 - Math.min(progress, 1));
|
||||
return '<svg class="cal-day__ring-svg" viewBox="0 0 ' + size + ' ' + size + '">' +
|
||||
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#e8e8e8" stroke-width="2.5"/>' +
|
||||
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#36cfc9" stroke-width="2.5" ' +
|
||||
'stroke-dasharray="' + circumference.toFixed(1) + '" stroke-dashoffset="' + offset.toFixed(1) + '" stroke-linecap="round" ' +
|
||||
'transform="rotate(-90 ' + cx + ' ' + cy + ')"/>' +
|
||||
'</svg>';
|
||||
}
|
||||
|
||||
/* 生成月历进度圆环 SVG(26×26 小尺寸) */
|
||||
function monthRingSVG(progress) {
|
||||
var r = 11, cx = 13, cy = 13, size = 26;
|
||||
var circumference = 2 * Math.PI * r;
|
||||
var offset = circumference * (1 - Math.min(progress, 1));
|
||||
return '<svg class="month-picker__ring-svg" viewBox="0 0 ' + size + ' ' + size + '">' +
|
||||
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#e8e8e8" stroke-width="2"/>' +
|
||||
'<circle cx="' + cx + '" cy="' + cy + '" r="' + r + '" fill="none" stroke="#36cfc9" stroke-width="2" ' +
|
||||
'stroke-dasharray="' + circumference.toFixed(1) + '" stroke-dashoffset="' + offset.toFixed(1) + '" stroke-linecap="round" ' +
|
||||
'transform="rotate(-90 ' + cx + ' ' + cy + ')"/>' +
|
||||
'</svg>';
|
||||
}
|
||||
|
||||
/* 渲染一周日历 */
|
||||
function renderWeek() {
|
||||
var container = document.getElementById('calWeek');
|
||||
container.innerHTML = '';
|
||||
|
||||
var weekDayChars = ['日', '一', '二', '三', '四', '五', '六'];
|
||||
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var d = new Date(currentWeekStart);
|
||||
d.setDate(d.getDate() + i);
|
||||
var dateStr = fmtDate(d);
|
||||
var wd = weekDayChars[d.getDay()];
|
||||
var dayNum = d.getDate();
|
||||
var isToday = isSameDay(d, today);
|
||||
|
||||
var dayEl = document.createElement('div');
|
||||
dayEl.className = 'cal-day' + (isToday ? ' today' : '');
|
||||
dayEl.setAttribute('data-date', dateStr);
|
||||
dayEl.setAttribute('data-wd', wd);
|
||||
dayEl.onclick = function() { selectDay(this); };
|
||||
|
||||
var data = dayData[dateStr];
|
||||
var hasData = data && data.intake !== 0;
|
||||
var progress = hasData ? Math.min(Math.abs(data.gap) / 500, 1) : 0;
|
||||
|
||||
dayEl.innerHTML =
|
||||
'<div class="cal-day__wd">' + wd + '</div>' +
|
||||
'<div class="cal-day__date-wrap">' +
|
||||
(hasData ? ringSVG(progress) : '') +
|
||||
'<span class="cal-day__num">' + dayNum + '</span>' +
|
||||
'</div>';
|
||||
|
||||
container.appendChild(dayEl);
|
||||
}
|
||||
|
||||
// 自动选中今天(如果在当前周),否则选中周一
|
||||
var firstDay = container.querySelector('.cal-day.today');
|
||||
if (!firstDay) firstDay = container.querySelector('.cal-day');
|
||||
if (firstDay) selectDay(firstDay);
|
||||
|
||||
// 箭头状态:未来周灰显右箭头
|
||||
var mondayOfThisWeek = getMonday(today);
|
||||
var nextArrow = document.getElementById('calNext');
|
||||
if (currentWeekStart.getTime() >= mondayOfThisWeek.getTime()) {
|
||||
nextArrow.style.opacity = '0.3';
|
||||
nextArrow.style.pointerEvents = 'none';
|
||||
} else {
|
||||
nextArrow.style.opacity = '1';
|
||||
nextArrow.style.pointerEvents = '';
|
||||
}
|
||||
}
|
||||
|
||||
function prevWeek() {
|
||||
currentWeekStart = new Date(currentWeekStart.getTime() - WEEK_MS);
|
||||
renderWeek();
|
||||
}
|
||||
|
||||
function nextWeek() {
|
||||
var mondayOfThisWeek = getMonday(today);
|
||||
if (currentWeekStart.getTime() >= mondayOfThisWeek.getTime()) return;
|
||||
currentWeekStart = new Date(currentWeekStart.getTime() + WEEK_MS);
|
||||
renderWeek();
|
||||
}
|
||||
|
||||
/* ===== 月历弹窗 ===== */
|
||||
var pickerYear = 2026;
|
||||
var pickerMonth = 6; // 0-based (July)
|
||||
|
||||
function toggleMonthPicker() {
|
||||
var picker = document.getElementById('monthPicker');
|
||||
var arrow = document.getElementById('dateArrow');
|
||||
var show = !picker.classList.contains('show');
|
||||
picker.classList.toggle('show', show);
|
||||
arrow.classList.toggle('open', show);
|
||||
if (show) {
|
||||
// 同步到当前选中日期所在月份
|
||||
var selDay = document.querySelector('.cal-day.active');
|
||||
if (selDay) {
|
||||
var d = selDay.getAttribute('data-date').split('-');
|
||||
pickerYear = parseInt(d[0]);
|
||||
pickerMonth = parseInt(d[1]) - 1;
|
||||
}
|
||||
renderMonthGrid();
|
||||
}
|
||||
}
|
||||
|
||||
function prevMonth() {
|
||||
if (pickerMonth === 0) { pickerMonth = 11; pickerYear--; }
|
||||
else { pickerMonth--; }
|
||||
renderMonthGrid();
|
||||
}
|
||||
|
||||
function nextMonth() {
|
||||
if (pickerMonth === 11) { pickerMonth = 0; pickerYear++; }
|
||||
else { pickerMonth++; }
|
||||
renderMonthGrid();
|
||||
}
|
||||
|
||||
function renderMonthGrid() {
|
||||
document.getElementById('monthPickerTitle').textContent = pickerYear + '年' + (pickerMonth + 1) + '月';
|
||||
var grid = document.getElementById('monthGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
var firstDay = new Date(pickerYear, pickerMonth, 1).getDay(); // 0=Sun
|
||||
var daysInMonth = new Date(pickerYear, pickerMonth + 1, 0).getDate();
|
||||
|
||||
// 填充上月尾巴
|
||||
var prevDays = new Date(pickerYear, pickerMonth, 0).getDate();
|
||||
for (var i = firstDay - 1; i >= 0; i--) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'month-picker__day month-picker__day--other';
|
||||
el.textContent = prevDays - i;
|
||||
grid.appendChild(el);
|
||||
}
|
||||
|
||||
// 当月日期
|
||||
var todayStr = fmtDate(today);
|
||||
var selDay = document.querySelector('.cal-day.active');
|
||||
var selStr = selDay ? selDay.getAttribute('data-date') : '';
|
||||
|
||||
for (var d = 1; d <= daysInMonth; d++) {
|
||||
var dateStr = pickerYear + '-' + ('0' + (pickerMonth + 1)).slice(-2) + '-' + ('0' + d).slice(-2);
|
||||
var el = document.createElement('div');
|
||||
var cls = 'month-picker__day';
|
||||
if (dateStr === todayStr) cls += ' month-picker__day--today';
|
||||
if (dateStr === selStr) cls += ' month-picker__day--selected';
|
||||
el.className = cls;
|
||||
// 有记录:日期数字外包进度圆环
|
||||
var data = dayData[dateStr];
|
||||
var hasData = data && data.intake !== 0;
|
||||
if (hasData) {
|
||||
var progress = Math.min(Math.abs(data.gap) / 500, 1);
|
||||
el.innerHTML = '<span class="month-picker__date-wrap">' +
|
||||
monthRingSVG(progress) +
|
||||
d + '</span>';
|
||||
} else {
|
||||
el.textContent = d;
|
||||
}
|
||||
el.onclick = (function(ds) { return function(e) { e.stopPropagation(); pickDay(ds); }; })(dateStr);
|
||||
grid.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
function pickDay(dateStr) {
|
||||
// 关闭弹窗
|
||||
document.getElementById('monthPicker').classList.remove('show');
|
||||
document.getElementById('dateArrow').classList.remove('open');
|
||||
|
||||
// 切换到该日期所在的周
|
||||
var parts = dateStr.split('-');
|
||||
var d = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
|
||||
currentWeekStart = getMonday(d);
|
||||
renderWeek();
|
||||
|
||||
// 选中该日
|
||||
var target = document.querySelector('.cal-day[data-date="' + dateStr + '"]');
|
||||
if (target) selectDay(target);
|
||||
}
|
||||
|
||||
// 点击外部关闭月历
|
||||
document.addEventListener('click', function(e) {
|
||||
var picker = document.getElementById('monthPicker');
|
||||
if (!picker.classList.contains('show')) return;
|
||||
if (!e.target.closest('.calendar-card__range') && !e.target.closest('#monthPicker')) {
|
||||
picker.classList.remove('show');
|
||||
document.getElementById('dateArrow').classList.remove('open');
|
||||
}
|
||||
});
|
||||
|
||||
/* ===== 计算弧线终点 ===== */
|
||||
// 半圆弧: cx=170, cy=135, r=80。左端点(90,135)角度π,右端点(250,135)角度0。
|
||||
// sweep=1 在 y-down SVG 中从左向右经顶部走。
|
||||
// 进度 progress: 0~1,对应角度 θ = π * (1 - progress)
|
||||
// x = 170 + 80 * cos(π*(1-p)), y = 135 - 80 * sin(π*(1-p))
|
||||
function arcPoint(progress) {
|
||||
var angle = Math.PI * (1 - progress);
|
||||
var x = 170 + 80 * Math.cos(angle);
|
||||
var y = 135 - 80 * Math.sin(angle);
|
||||
return { x: Math.round(x * 10) / 10, y: Math.round(y * 10) / 10 };
|
||||
}
|
||||
|
||||
/* ===== 选中日历天 ===== */
|
||||
function selectDay(el) {
|
||||
document.querySelectorAll('.cal-day').forEach(function(d) { d.classList.remove('active'); });
|
||||
el.classList.add('active');
|
||||
|
||||
var dateStr = el.getAttribute('data-date');
|
||||
|
||||
// 更新顶部日期显示为选中日期
|
||||
var parts = dateStr.split('-');
|
||||
document.getElementById('calRange').textContent = parts[0] + '年' + parseInt(parts[1]) + '月' + parseInt(parts[2]) + '日';
|
||||
|
||||
var data = dayData[dateStr];
|
||||
if (!data) {
|
||||
// 无数据日,清空显示
|
||||
data = { intake: 0, consume: 0, gap: 0 };
|
||||
}
|
||||
|
||||
var gapAbs = Math.abs(data.gap);
|
||||
var maxGap = 500;
|
||||
var progress = data.gap === 0 ? 0 : Math.min(gapAbs / maxGap, 1);
|
||||
|
||||
var pt = arcPoint(progress);
|
||||
var arcD = 'M 90 135 A 80 80 0 0 1 ' + pt.x + ' ' + pt.y;
|
||||
|
||||
var gapArc = document.getElementById('gapArc');
|
||||
gapArc.setAttribute('d', arcD);
|
||||
|
||||
document.getElementById('intakeText').textContent = data.intake === 0 ? '--' : data.intake;
|
||||
document.getElementById('consumeText').textContent = data.consume === 0 ? '--' : data.consume;
|
||||
|
||||
var gapCenter = document.getElementById('gapCenterVal');
|
||||
gapCenter.textContent = data.gap === 0 ? '--' : ('-' + Math.abs(data.gap));
|
||||
|
||||
var colorIntake = data.intake === 0 ? '#bbb' : '#fa8c16';
|
||||
var colorConsume = data.consume === 0 ? '#bbb' : '#52c41a';
|
||||
var colorGap = data.gap === 0 ? '#bbb' : '#fa8c16';
|
||||
document.getElementById('intakeText').setAttribute('fill', colorIntake);
|
||||
document.getElementById('consumeText').setAttribute('fill', colorConsume);
|
||||
gapCenter.setAttribute('fill', colorGap);
|
||||
|
||||
var rightDot = document.querySelector('.gauge-wrap svg circle[cy="135"][cx="250"]');
|
||||
rightDot.setAttribute('fill', data.gap === 0 ? '#bbb' : '#52c41a');
|
||||
|
||||
// 更新餐食卡片
|
||||
renderMeals(dateStr);
|
||||
}
|
||||
|
||||
/* ===== 渲染餐食卡片 ===== */
|
||||
function renderMeals(dateStr) {
|
||||
var data = dayData[dateStr];
|
||||
var meals = data && data.meals;
|
||||
var dietTypes = ['breakfast', 'lunch', 'dinner', 'snack'];
|
||||
|
||||
// 检查是否有任何饮食记录
|
||||
var hasAnyDiet = false;
|
||||
var totalKcal = 0;
|
||||
dietTypes.forEach(function(type) {
|
||||
var md = meals ? meals[type] : null;
|
||||
if (md && md.items && md.items.length > 0) hasAnyDiet = true;
|
||||
});
|
||||
|
||||
if (hasAnyDiet) {
|
||||
// 有饮食记录:显示各子分组
|
||||
document.getElementById('dietEmpty').style.display = 'none';
|
||||
dietTypes.forEach(function(type) {
|
||||
var cap = type.charAt(0).toUpperCase() + type.slice(1);
|
||||
var sub = document.getElementById('dietSub' + cap);
|
||||
var container = document.getElementById('group' + cap);
|
||||
var kcalEl = document.getElementById('kcal' + cap);
|
||||
var md = meals ? meals[type] : null;
|
||||
|
||||
if (md && md.items && md.items.length > 0) {
|
||||
sub.style.display = '';
|
||||
var html = '';
|
||||
md.items.forEach(function(item) {
|
||||
var src = item.src || md.source || 'manual';
|
||||
var srcLabel = src === 'auto' ? '智记' : '自记';
|
||||
html += '<div class="meal-item">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + '<span class="meal-item__src meal-item__src--' + src + '">' + srcLabel + '</span></div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
});
|
||||
container.innerHTML = html;
|
||||
container.style.display = '';
|
||||
kcalEl.textContent = md.kcal;
|
||||
totalKcal += md.kcal;
|
||||
} else {
|
||||
sub.style.display = 'none';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 无任何饮食记录:隐藏子分组,显示空状态
|
||||
dietTypes.forEach(function(type) {
|
||||
var sub = document.getElementById('dietSub' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||
if (sub) sub.style.display = 'none';
|
||||
});
|
||||
totalKcal = 0;
|
||||
document.getElementById('dietEmpty').style.display = '';
|
||||
}
|
||||
|
||||
// 更新饮食总热量
|
||||
document.getElementById('kcalDiet').textContent = totalKcal > 0 ? totalKcal : '--';
|
||||
|
||||
// 运动卡片独立处理
|
||||
var exCard = document.getElementById('cardExercise');
|
||||
var exContainer = document.getElementById('groupExercise');
|
||||
var exKcalEl = document.getElementById('kcalExercise');
|
||||
var exMd = meals ? meals['exercise'] : null;
|
||||
if (exMd && exMd.items && exMd.items.length > 0) {
|
||||
exCard.style.display = '';
|
||||
var html = '';
|
||||
exMd.items.forEach(function(item) {
|
||||
var srcTag = '';
|
||||
if (item.src) {
|
||||
srcTag = '<span class="meal-item__src meal-item__src--' + item.src + '">' + ({wearable:'穿戴',equip:'器械',wechat:'微信',manual:'自记'}[item.src] || item.src) + '</span>';
|
||||
}
|
||||
html += '<div class="meal-item meal-item--exercise">' +
|
||||
'<div class="meal-item__emoji">' + item.e + '</div>' +
|
||||
'<div class="meal-item__info"><div class="meal-item__name">' + item.n + srcTag + '</div><div class="meal-item__meta">' + item.m + '</div></div>' +
|
||||
'<div class="meal-item__kcal">' + item.k + ' kcal</div></div>';
|
||||
});
|
||||
exContainer.innerHTML = html;
|
||||
exContainer.style.display = '';
|
||||
exKcalEl.textContent = exMd.kcal;
|
||||
exKcalEl.parentElement.style.display = '';
|
||||
} else {
|
||||
exCard.style.display = 'none';
|
||||
}
|
||||
|
||||
}
|
||||
function toggleDietSub(type, headerEl) {
|
||||
var items = document.getElementById('group' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||
var expand = headerEl.querySelector('.meal-card__expand');
|
||||
if (items.style.display === 'none') {
|
||||
items.style.display = '';
|
||||
expand.classList.remove('open');
|
||||
} else {
|
||||
items.style.display = 'none';
|
||||
expand.classList.add('open');
|
||||
}
|
||||
}
|
||||
function toggleMeal(type, headerEl) {
|
||||
var items = document.getElementById('group' + type.charAt(0).toUpperCase() + type.slice(1));
|
||||
var expand = headerEl.querySelector('.meal-card__expand');
|
||||
if (items.style.display === 'none') {
|
||||
items.style.display = '';
|
||||
expand.classList.remove('open');
|
||||
} else {
|
||||
items.style.display = 'none';
|
||||
expand.classList.add('open');
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 初始化 ===== */
|
||||
renderWeek();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -28,7 +28,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.scroll-content::-webkit-scrollbar { display: none; }
|
||||
|
||||
/* ===== 计划卡片 ===== */
|
||||
.plan-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); }
|
||||
.plan-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); cursor: pointer; transition: transform .15s; }
|
||||
.plan-card__header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 10px; }
|
||||
.plan-card__name { font-size: 15px; font-weight: 700; color: #1a1a1a; flex: 1; min-width: 0; line-height: 1.4; }
|
||||
.plan-card__status { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 8px; white-space: nowrap; flex-shrink: 0; margin-left: 8px; }
|
||||
@@ -94,12 +94,12 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<div class="scroll-content">
|
||||
|
||||
<!-- ===== 活动计划列表 ===== -->
|
||||
<div id="tabActivity">
|
||||
<div class="plan-card">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年二季度体重管理活动</span>
|
||||
<span class="plan-card__status plan-card__status--active">进行中</span>
|
||||
</div>
|
||||
<div id="tabActivity">
|
||||
<div class="plan-card" onclick="location.href='goal-detail-v2.html?type=activity&state=signed'">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年二季度体重管理活动</span>
|
||||
<span class="plan-card__status plan-card__status--active">进行中</span>
|
||||
</div>
|
||||
<div class="plan-card__meta">
|
||||
<span>起止:<em>2026-04-01 ~ 2026-09-30</em></span>
|
||||
<span>机构:<em>公司机关</em></span>
|
||||
@@ -122,14 +122,14 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
<div class="plan-card__footer">
|
||||
<span class="plan-card__date">签署时间:2026-04-05 09:15</span>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=activity&state=signed">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=activity&state=signed" onclick="event.stopPropagation()">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="plan-card">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年一季度减重挑战赛</span>
|
||||
<span class="plan-card__status plan-card__status--done">已结束</span>
|
||||
<div class="plan-card" onclick="location.href='goal-detail-v2.html?type=activity&state=ended'">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年一季度减重挑战赛</span>
|
||||
<span class="plan-card__status plan-card__status--done">已结束</span>
|
||||
</div>
|
||||
<div class="plan-card__meta">
|
||||
<span>起止:<em>2026-01-01 ~ 2026-03-31</em></span>
|
||||
@@ -153,14 +153,14 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
<div class="plan-card__footer">
|
||||
<span class="plan-card__date">活动已结束 · 减重 7.7kg</span>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=activity&state=signed">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="plan-card__link" onclick="event.stopPropagation()" href="goal-detail-v2.html?type=activity&state=ended">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="plan-card">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">全员健康体重管理计划</span>
|
||||
<span class="plan-card__status plan-card__status--done">已结束</span>
|
||||
<div class="plan-card" onclick="location.href='goal-detail-v2.html?type=activity&state=ended'">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">全员健康体重管理计划</span>
|
||||
<span class="plan-card__status plan-card__status--done">已结束</span>
|
||||
</div>
|
||||
<div class="plan-card__meta">
|
||||
<span>起止:<em>2025-10-01 ~ 2026-06-30</em></span>
|
||||
@@ -184,19 +184,19 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
<div class="plan-card__footer">
|
||||
<span class="plan-card__date">活动已结束 · 减重 4.5kg</span>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=activity&state=signed">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="plan-card__link" onclick="event.stopPropagation()" href="goal-detail-v2.html?type=activity&state=ended">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
<div class="bottom-safe"></div>
|
||||
</div>
|
||||
|
||||
<!-- ===== 个人计划列表 ===== -->
|
||||
<div id="tabPersonal" class="hidden">
|
||||
<div class="plan-card">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年二季度个人减脂</span>
|
||||
<span class="plan-card__status plan-card__status--active">进行中</span>
|
||||
<!-- ===== 个人计划列表 ===== -->
|
||||
<div id="tabPersonal" class="hidden">
|
||||
<div class="plan-card" onclick="location.href='goal-detail-v2.html?type=personal&state=signed'">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2026年二季度个人减脂</span>
|
||||
<span class="plan-card__status plan-card__status--active">进行中</span>
|
||||
</div>
|
||||
<div class="plan-card__meta">
|
||||
<span>起止:<em>2026-04-01 ~ 2026-08-26</em></span>
|
||||
@@ -219,14 +219,14 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
<div class="plan-card__footer">
|
||||
<span class="plan-card__date">剩余 29 天</span>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=personal">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
<a class="plan-card__link" onclick="event.stopPropagation()" href="goal-detail-v2.html?type=personal&state=signed">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="plan-card">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2025年四季度塑形计划</span>
|
||||
<span class="plan-card__status plan-card__status--done">已完成</span>
|
||||
<div class="plan-card" onclick="location.href='goal-detail-v2.html?type=personal&state=ended'">
|
||||
<div class="plan-card__header">
|
||||
<span class="plan-card__name">2025年四季度塑形计划</span>
|
||||
<span class="plan-card__status plan-card__status--done">已完成</span>
|
||||
</div>
|
||||
<div class="plan-card__meta">
|
||||
<span>起止:<em>2025-10-01 ~ 2025-12-31</em></span>
|
||||
@@ -249,7 +249,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
<div class="plan-card__footer">
|
||||
<span class="plan-card__date">已完成 · 减重 7.5kg · 达成目标 ✅</span>
|
||||
<a class="plan-card__link" href="goal-detail-v2.html?type=personal">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
<a class="plan-card__link" onclick="event.stopPropagation()" href="goal-detail-v2.html?type=personal&state=ended">详情 <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -47,9 +47,38 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.goal-card__empty.show { display: block; }
|
||||
.goal-card__empty-icon { font-size: 40px; margin-bottom: 8px; }
|
||||
.goal-card__empty-text { font-size: 13px; }
|
||||
.goal-card__empty-link { display: inline-block; margin-top: 10px; font-size: 12px; color: #36cfc9; font-weight: 600; cursor: pointer; text-decoration: none; }
|
||||
|
||||
/* ===== 目标状态横幅 ===== */
|
||||
.goal-card__empty-link { display: inline-block; margin-top: 10px; font-size: 12px; color: #36cfc9; font-weight: 600; cursor: pointer; text-decoration: none; }
|
||||
|
||||
/* ===== 目标卡片:人物+波浪球+标尺 ===== */
|
||||
.goal-avatars { display: flex; align-items: center; justify-content: space-between; padding: 0 4px; margin: 4px 0 0; }
|
||||
.goal-avatar-side { width: 78px; position: relative; display: flex; flex-direction: column; align-items: center; }
|
||||
.goal-avatar__img { width: 64px; height: 96px; }
|
||||
.goal-avatar__img svg { width: 100%; height: 100%; display: block; }
|
||||
|
||||
.goal-ball-wrap { text-align: center; flex: 1; position: relative; }
|
||||
.goal-ball-wrap__top { font-size: 12px; color: #36cfc9; margin-bottom: 2px; position: absolute; top: 8px; left: 0; right: 0; z-index: 3; }
|
||||
.goal-ball { width: 150px; height: 150px; margin: 0 auto; border-radius: 50%; position: relative; overflow: hidden; box-shadow: 0 6px 20px rgba(54,207,201,0.18); }
|
||||
.goal-ball__bg { position: absolute; inset: 0; background: radial-gradient(circle at 50% 30%, #ffffff 0%, #e8fbfa 40%, #b6f0eb 100%); }
|
||||
.goal-ball__wave { position: absolute; bottom: 0; left: 0; right: 0; height: 58%; }
|
||||
.goal-ball__wave svg { width: 100%; height: 100%; display: block; }
|
||||
.goal-ball__rulers { position: absolute; inset: 0; pointer-events: none; }
|
||||
.goal-ball__rulers::before, .goal-ball__rulers::after { content: ''; position: absolute; top: 8px; bottom: 8px; width: 1px; background: repeating-linear-gradient(to bottom, rgba(54,207,201,0.4) 0 4px, transparent 4px 8px); }
|
||||
.goal-ball__rulers::before { left: 14px; }
|
||||
.goal-ball__rulers::after { right: 14px; }
|
||||
.goal-ball__content { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 2; padding-top: 18px; }
|
||||
.goal-ball__val { font-size: 36px; font-weight: 800; color: #1a1a1a; line-height: 1; }
|
||||
.goal-ball__val .goal-ball__unit { font-size: 12px; color: #333; font-weight: 500; margin-left: 2px; }
|
||||
.goal-ball__meta { font-size: 11px; color: #36a39f; margin-top: 2px; }
|
||||
|
||||
.goal-change-row { display: flex; justify-content: space-between; align-items: flex-start; margin-top: 14px; padding: 0 4px; }
|
||||
.goal-change-row__cell { text-align: center; flex: 1; }
|
||||
.goal-change-row__label { font-size: 13px; color: #999; margin-bottom: 4px; }
|
||||
.goal-change-row__val { font-size: 26px; font-weight: 800; color: #1a1a1a; line-height: 1; }
|
||||
.goal-change-row__val.negative { color: #36cfc9; }
|
||||
.goal-change-row__sub { font-size: 12px; color: #bbb; margin-top: 4px; }
|
||||
.goal-change-row__need { font-size: 12px; color: #faad14; margin-top: 4px; }
|
||||
|
||||
/* ===== 目标状态横幅 ===== */
|
||||
.goal-status { display: none; padding: 12px 14px; border-radius: 12px; margin-bottom: 0; }
|
||||
.goal-status.show { display: flex; align-items: flex-start; gap: 10px; }
|
||||
.goal-status__icon { font-size: 22px; flex-shrink: 0; }
|
||||
@@ -73,9 +102,8 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.goal-status--rejected .goal-status__text { color: #8c1a1a; }
|
||||
.goal-status--rejected .goal-status__btn { background: #ff4d4f; color: #fff; }
|
||||
|
||||
/* ===== 标尺 SVG ===== */
|
||||
.gauge-wrap { width: 100%; }
|
||||
.gauge-wrap svg { width: 100%; height: auto; display: block; }
|
||||
/* ===== 目标标尺容器 ===== */
|
||||
.gauge-wrap { width: 100%; }
|
||||
|
||||
/* ===== 吃记录卡片 ===== */
|
||||
.eat-card { background: #fff; border-radius: 16px; margin: 12px 12px 0; padding: 16px 16px 14px; box-shadow: 0 4px 14px rgba(0,0,0,0.04); cursor: pointer; }
|
||||
@@ -365,73 +393,83 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===== 半圆标尺(初始体重-左 | 当前体重-内 | 目标体重-右) ===== -->
|
||||
<div class="gauge-wrap" id="goalGauge">
|
||||
<svg viewBox="0 0 340 150" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="gaugeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stop-color="#2dd4bf"/>
|
||||
<stop offset="100%" stop-color="#5cdbd3"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="glowGrad" cx="50%" cy="80%" r="55%">
|
||||
<stop offset="0%" stop-color="#e8fbfa" stop-opacity="0.3"/>
|
||||
<stop offset="100%" stop-color="#fff" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<rect x="0" y="0" width="340" height="150" fill="url(#glowGrad)"/>
|
||||
|
||||
<!-- ======== 弧 ======== -->
|
||||
<!-- cx=170, cy=135, r=80, 左端点(90,135) 右端点(250,135) -->
|
||||
|
||||
<!-- 灰色底轨 -->
|
||||
<path d="M 90 135 A 80 80 0 0 1 250 135"
|
||||
fill="none" stroke="#ebeef0" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- 进度弧 62.3%,终点 (200, 61) -->
|
||||
<path d="M 90 135 A 80 80 0 0 1 200 61"
|
||||
fill="none" stroke="url(#gaugeGrad)" stroke-width="14" stroke-linecap="round"/>
|
||||
|
||||
<!-- ======== 刻度圆点 ======== -->
|
||||
<circle cx="98" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="120" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="152" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="188" cy="60" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="220" cy="75" r="2.5" fill="#cfcfcf"/>
|
||||
<circle cx="242" cy="103" r="2.5" fill="#cfcfcf"/>
|
||||
|
||||
<!-- 端点 -->
|
||||
<circle cx="90" cy="135" r="5" fill="#ff6b81" stroke="#fff" stroke-width="2.5"/>
|
||||
<circle cx="250" cy="135" r="5" fill="#36cfc9" stroke="#fff" stroke-width="2.5"/>
|
||||
|
||||
<!-- ======== 当前进度指示器 ======== -->
|
||||
<circle cx="200" cy="61" r="11" fill="#fff" stroke="#36cfc9" stroke-width="3"/>
|
||||
<circle cx="200" cy="61" r="5" fill="#36cfc9"/>
|
||||
<rect x="177" y="31" width="46" height="18" rx="9" fill="#36cfc9"/>
|
||||
<text x="200" y="44" font-size="10" fill="#fff" text-anchor="middle" font-weight="700">62.6</text>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- 左侧:初始体重(左对齐,距边缘 16) -->
|
||||
<!-- ============================================ -->
|
||||
<text x="16" y="90" font-size="12" fill="#999" text-anchor="start">初始体重</text>
|
||||
<text x="16" y="112" font-size="22" fill="#ff6b81" text-anchor="start" font-weight="800">73.5</text>
|
||||
<text x="16" y="127" font-size="10" fill="#bbb" text-anchor="start">BMI 28.6</text>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- 右侧:目标体重(右对齐,距边缘 16) -->
|
||||
<!-- ============================================ -->
|
||||
<text x="324" y="90" font-size="12" fill="#999" text-anchor="end">目标体重</text>
|
||||
<text x="324" y="112" font-size="22" fill="#36cfc9" text-anchor="end" font-weight="800">56.0</text>
|
||||
<text x="324" y="127" font-size="10" fill="#bbb" text-anchor="end">BMI 22.5</text>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- 中心:当前体重(半径居中) -->
|
||||
<!-- ============================================ -->
|
||||
<text x="170" y="90" font-size="12" fill="#999" text-anchor="middle">当前体重</text>
|
||||
<text x="170" y="122" font-size="34" fill="#1a1a1a" text-anchor="middle" font-weight="800">62.6</text>
|
||||
<text x="170" y="137" font-size="12" fill="#36cfc9" text-anchor="middle" font-weight="600">▼ 10.9</text>
|
||||
</svg>
|
||||
</div>
|
||||
<!-- ===== 人物+波浪球+标尺:初始体重-左 | 当前体重-球 | 目标体重-右 ===== -->
|
||||
<div class="gauge-wrap" id="goalGauge">
|
||||
<!-- 人物行:左小人 · 波浪球 · 右小人 -->
|
||||
<div class="goal-avatars">
|
||||
<!-- 左侧:初始体重 人物 -->
|
||||
<div class="goal-avatar-side">
|
||||
<div class="goal-avatar__img">
|
||||
<svg viewBox="0 0 64 80" fill="none">
|
||||
<circle cx="32" cy="13" r="10" fill="#FFD591"/>
|
||||
<path d="M14 30 Q14 24 20 24 L44 24 Q50 24 50 30 L50 50 Q50 56 44 56 L20 56 Q14 56 14 50 Z" fill="#FF4D4F"/>
|
||||
<rect x="10" y="22" width="10" height="14" rx="3" fill="#FF4D4F" transform="rotate(-20 15 28)"/>
|
||||
<rect x="44" y="22" width="10" height="14" rx="3" fill="#FF4D4F" transform="rotate(20 49 28)"/>
|
||||
<rect x="16" y="52" width="12" height="20" rx="3" fill="#1f1f1f"/>
|
||||
<rect x="36" y="52" width="12" height="20" rx="3" fill="#1f1f1f"/>
|
||||
<rect x="14" y="70" width="14" height="6" rx="2" fill="#fadb14"/>
|
||||
<rect x="36" y="70" width="14" height="6" rx="2" fill="#fadb14"/>
|
||||
<circle cx="27" cy="11" r="1.4" fill="#333"/>
|
||||
<circle cx="37" cy="11" r="1.4" fill="#333"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 中间:波浪球 -->
|
||||
<div class="goal-ball-wrap">
|
||||
<div class="goal-ball-wrap__top">当前体重</div>
|
||||
<div class="goal-ball">
|
||||
<div class="goal-ball__bg"></div>
|
||||
<div class="goal-ball__rulers"></div>
|
||||
<div class="goal-ball__wave">
|
||||
<svg viewBox="0 0 150 90" preserveAspectRatio="none">
|
||||
<path d="M0 30 Q25 12 50 30 Q75 48 100 30 Q125 12 150 30 L150 90 L0 90 Z" fill="#36cfc9" opacity="0.85"/>
|
||||
<path d="M0 40 Q25 22 50 40 Q75 58 100 40 Q125 22 150 40 L150 90 L0 90 Z" fill="#5cdbd3" opacity="0.55"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="goal-ball__content">
|
||||
<span class="goal-ball__val">62.6<span class="goal-ball__unit">公斤</span></span>
|
||||
<span class="goal-ball__meta">BMI 23.6</span>
|
||||
<span class="goal-ball__meta">体脂率:25.8%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧:目标体重 人物 -->
|
||||
<div class="goal-avatar-side">
|
||||
<div class="goal-avatar__img">
|
||||
<svg viewBox="0 0 64 80" fill="none">
|
||||
<circle cx="32" cy="13" r="10" fill="#FFD591"/>
|
||||
<path d="M14 30 Q14 24 20 24 L44 24 Q50 24 50 30 L50 50 Q50 56 44 56 L20 56 Q14 56 14 50 Z" fill="#36cfc9"/>
|
||||
<rect x="10" y="22" width="10" height="14" rx="3" fill="#36cfc9" transform="rotate(-20 15 28)"/>
|
||||
<rect x="44" y="22" width="10" height="14" rx="3" fill="#36cfc9" transform="rotate(20 49 28)"/>
|
||||
<rect x="16" y="52" width="12" height="20" rx="3" fill="#1f1f1f"/>
|
||||
<rect x="36" y="52" width="12" height="20" rx="3" fill="#1f1f1f"/>
|
||||
<rect x="14" y="70" width="14" height="6" rx="2" fill="#36cfc9"/>
|
||||
<rect x="36" y="70" width="14" height="6" rx="2" fill="#36cfc9"/>
|
||||
<circle cx="27" cy="11" r="1.4" fill="#333"/>
|
||||
<circle cx="37" cy="11" r="1.4" fill="#333"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 体重数据行:初始体重 · 体重变化 · 目标体重 -->
|
||||
<div class="goal-change-row">
|
||||
<div class="goal-change-row__cell">
|
||||
<div class="goal-change-row__label">初始体重</div>
|
||||
<div class="goal-change-row__val">73.5</div>
|
||||
<div class="goal-change-row__sub">BMI 28.6</div>
|
||||
</div>
|
||||
<div class="goal-change-row__cell">
|
||||
<div class="goal-change-row__label">体重变化</div>
|
||||
<div class="goal-change-row__val negative">-10.9 <span style="font-size:14px;">▼</span></div>
|
||||
<div class="goal-change-row__need">还要减 6.6</div>
|
||||
</div>
|
||||
<div class="goal-change-row__cell">
|
||||
<div class="goal-change-row__label">目标体重</div>
|
||||
<div class="goal-change-row__val">56.0</div>
|
||||
<div class="goal-change-row__sub">BMI 22.5</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 未设置目标时的空状态 -->
|
||||
<div class="goal-card__empty" id="goalEmpty">
|
||||
@@ -443,7 +481,7 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
</div>
|
||||
|
||||
<!-- ====== 热量缺口卡片 ====== -->
|
||||
<div class="gap-card" onclick="location.href='eat-detail-v2.html'">
|
||||
<div class="gap-card" onclick="location.href='eat-exercise-detail-v2.html'">
|
||||
<div class="gap-card__title"><span>吃动平衡</span><span><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#bbb" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span></div>
|
||||
|
||||
<!-- 本周日历 -->
|
||||
|
||||
@@ -86,10 +86,13 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
.summary-compare th { padding: 8px 6px; text-align: center; font-weight: 700; color: #999; font-size: 11px; border-bottom: 2px solid #f0f0f0; }
|
||||
.summary-compare td { padding: 9px 6px; text-align: center; color: #333; border-bottom: 1px solid #f5f5f5; }
|
||||
.summary-compare td:first-child { text-align: left; font-weight: 600; color: #666; padding-left: 4px; }
|
||||
.summary-compare tr:last-child td { border-bottom: none; }
|
||||
.summary-compare .val-down { color: #36cfc9; font-weight: 700; }
|
||||
.summary-compare .val-target { color: #faad14; font-weight: 700; }
|
||||
.summary-compare .val-achieved { color: #36cfc9; font-weight: 700; }
|
||||
.summary-compare tr:last-child td { border-bottom: none; }
|
||||
.summary-compare .val-down { color: #36cfc9; font-weight: 700; }
|
||||
.summary-compare .val-target { color: #faad14; font-weight: 700; }
|
||||
.summary-compare .val-achieved { color: #36cfc9; font-weight: 700; }
|
||||
/* 隐藏目标列 */
|
||||
.summary-compare.hide-target th:nth-child(4),
|
||||
.summary-compare.hide-target td:nth-child(4) { display: none; }
|
||||
|
||||
/* 标签 */
|
||||
.summary-tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 10px; font-weight: 600; margin-left: 4px; }
|
||||
@@ -136,20 +139,34 @@ body { background: #f0f2f5; display: flex; justify-content: center; align-items:
|
||||
<span class="overview-card__label">截止至 <span id="ovCutoff">2026-08-12</span></span>
|
||||
<span class="overview-card__label" id="ovDayWrap">第 <span id="ovDay">52</span> 天(共 <span id="ovTotal">180</span> 天)</span>
|
||||
</div>
|
||||
<div class="overview-metrics">
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">-10.9<span class="overview-metric__unit">kg</span></div>
|
||||
<div class="overview-metric__desc">已减体重</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">62<span class="overview-metric__unit">%</span></div>
|
||||
<div class="overview-metric__desc">目标进度</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">~1.5<span class="overview-metric__unit">月</span></div>
|
||||
<div class="overview-metric__desc">预计达成</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-metrics" id="ovMetricsActivity">
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">-10.9<span class="overview-metric__unit">kg</span></div>
|
||||
<div class="overview-metric__desc">已减体重</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">62<span class="overview-metric__unit">%</span></div>
|
||||
<div class="overview-metric__desc">目标进度</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">~1.5<span class="overview-metric__unit">月</span></div>
|
||||
<div class="overview-metric__desc">预计达成</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-metrics" id="ovMetricsNone" style="display:none;">
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">73.5<span class="overview-metric__unit">kg</span></div>
|
||||
<div class="overview-metric__desc">初始体重</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">62.6<span class="overview-metric__unit">kg</span></div>
|
||||
<div class="overview-metric__desc">当前体重</div>
|
||||
</div>
|
||||
<div class="overview-metric">
|
||||
<div class="overview-metric__val">-10.9<span class="overview-metric__unit">kg</span></div>
|
||||
<div class="overview-metric__desc">已减体重</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 非活动类型缺省 -->
|
||||
@@ -357,21 +374,35 @@ function applyPageType(type) {
|
||||
overviewEmpty.style.display = 'none';
|
||||
if (ovInfoRow) ovInfoRow.style.display = '';
|
||||
document.getElementById('ovDayWrap').style.display = '';
|
||||
document.getElementById('ovMetricsActivity').style.display = '';
|
||||
document.getElementById('ovMetricsNone').style.display = 'none';
|
||||
document.getElementById('summarySection').style.display = '';
|
||||
// 显示目标列
|
||||
var tables = document.querySelectorAll('.summary-compare');
|
||||
tables.forEach(function(t) { t.classList.remove('hide-target'); });
|
||||
} else if (type === 'personal') {
|
||||
navTitle.textContent = '个人减重目标标题';
|
||||
overviewCard.style.display = '';
|
||||
overviewEmpty.style.display = 'none';
|
||||
if (ovInfoRow) ovInfoRow.style.display = '';
|
||||
document.getElementById('ovDayWrap').style.display = '';
|
||||
document.getElementById('ovMetricsActivity').style.display = '';
|
||||
document.getElementById('ovMetricsNone').style.display = 'none';
|
||||
document.getElementById('summarySection').style.display = '';
|
||||
var tables2 = document.querySelectorAll('.summary-compare');
|
||||
tables2.forEach(function(t) { t.classList.remove('hide-target'); });
|
||||
} else {
|
||||
navTitle.textContent = '体重报告';
|
||||
overviewCard.style.display = '';
|
||||
overviewEmpty.style.display = 'none';
|
||||
if (ovInfoRow) ovInfoRow.style.display = 'none';
|
||||
if (ovInfoRow) ovInfoRow.style.display = '';
|
||||
document.getElementById('ovDayWrap').style.display = 'none';
|
||||
document.getElementById('summarySection').style.display = 'none';
|
||||
document.getElementById('ovMetricsActivity').style.display = 'none';
|
||||
document.getElementById('ovMetricsNone').style.display = '';
|
||||
document.getElementById('summarySection').style.display = '';
|
||||
// 隐藏目标列
|
||||
var tables3 = document.querySelectorAll('.summary-compare');
|
||||
tables3.forEach(function(t) { t.classList.add('hide-target'); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user