@@ -8,11 +8,18 @@
<!-- 孕期专题 · 生娃计算器(孕期首页「其他妈妈也在搜」第 1 条入口)。主色 #18A058, 浅底 #EAF7F0。
<!-- 孕期专题 · 生娃计算器(孕期首页「其他妈妈也在搜」第 1 条入口)。主色 #18A058, 浅底 #EAF7F0。
2026 - 11 - 01 v5( 在 v4 三条路线 + 养娃账单小票上继续改):
2026 - 11 - 01 v5( 在 v4 三条路线 + 养娃账单小票上继续改):
① 首屏大标题「生娃计算器」+ 副标题;三张路线卡带 01/02/03 序号;结果揭晓前全程不出现任何金额;
① 首屏大标题「生娃计算器」+ 副标题;三张路线卡带 01/02/03 序号;结果揭晓前全程不出现任何金额;
② 问题(按所选阶段出现):你是女生/男生 → 算哪一段(多选,默认全部)→ 城市 → 头胎二胎 → 0~ 3 岁谁带 → 上学路线 → 课外班 → 家庭月收入(可跳过);
② 问题(按所选阶段出现):算哪一段(多选,默认全部)→ 城市 → 头胎二胎 → 0~ 3 岁谁带 → 上学路线 → 课外班 → 家庭月收入(可跳过);
③ 账单只列所选阶段,每段 12~ 24 项明细, 单项取中间值、小计合计能加对; 1/2/3 岁累计只在含 0~ 1 / 1~ 3 岁时显示;
③ 账单只列所选阶段,每段 12~ 24 项明细, 单项取中间值、小计合计能加对; 1/2/3 岁累计只在含 0~ 1 / 1~ 3 岁时显示;
④ 填了收入:账单里给「≈ 你家 X 个月 / X 年收入」+ 所选阶段平均每月占收入比例条;收尾卡、生成卡片呼应一句;收 入只存本机;
④ 填了收入:账单里给「≈ 你家 X 个月 / X 年收入」+ 所选阶段平均每月占收入比例条;收入只存本机;
⑤ 收尾卡、复制、生成卡片、 推荐工具、打印动画同 v4;
⑤ 推荐工具、打印动画同 v4(收尾卡、复制、生成卡片 v7 已删) ;
⑥ v6( 11 - 01) : 账单下加「保存账单图片」, canvas 把整张小票画成长图(宽 750, 高按内容, 超 15800px 先压行高再整体缩小),复用卡片弹层、长图可滚动。改价格只改脚本里的 COST 表。
⑥ v6( 11 - 01) : 账单下加「保存账单图片」, canvas 把整张小票画成长图(宽 750, 高按内容, 超 15800px 先压行高再整体缩小),复用卡片弹层、长图可滚动。改价格只改脚本里的 COST 表。
⑦ v7( 2026 - 11 - 01, 用户: 题少了加几道、去掉男女题、给妈妈的话只留提示) :
· 去掉「你是女生/男生」题及所有按性别换说法的文案;
· 新增 4 题并接进计算:在哪类医院(公立普通/公立特需/私立 → 产检、B 超、分娩、病房、筛查、住院餐、生育保险报销)、
顺产还是剖宫产(顺产/剖宫产/还不确定 → 分娩费、无痛或镇痛泵、报销额)、月子打算(家人/月嫂/月子中心 → 月子主项、月子餐食材)、
喂养方式(母乳为主/混合/奶粉 → 0~ 1 岁奶粉量、1~ 3 岁奶粉、吸奶器/催乳/哺乳内衣);医院、月子跟路线默认,分娩、喂养默认「还不确定」「混合」;
· 现在的题序:算哪一段 → 城市 → 头胎二胎 → 医院 → 顺产剖宫产 → 月子 → 喂养 → 0~ 3 岁谁带 → 上学路线 → 课外班 → 家庭月收入(按所选阶段出现);
· 「写在账单后面 / 给妈妈的话」整块删掉( 换一句、复制发给妈妈、生成卡片、drawCard 都删了),只留一行浅色小提示;卡片弹层只给「保存账单图片」用。
存储 localStorage「mmbox.huafei.v5」( 兼容读取 v4) 。推荐工具走 ../_shared/tools.js; 自成一页: 不引 app.js;
存储 localStorage「mmbox.huafei.v5」( 兼容读取 v4) 。推荐工具走 ../_shared/tools.js; 自成一页: 不引 app.js;
返回走 history.back 或相对路径 ../../ 并带回 search + hash。v4 备份 /tmp/huafei5/huafei - v4 - before - v5.html。 -->
返回走 history.back 或相对路径 ../../ 并带回 search + hash。v4 备份 /tmp/huafei5/huafei - v4 - before - v5.html。 -->
< style >
< style >
@@ -156,7 +163,6 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
. qh { margin-top : 4 px ; font-size : 24 px ; font-weight : 800 ; line-height : 1.35 ; color : var ( - - h ) }
. qh { margin-top : 4 px ; font-size : 24 px ; font-weight : 800 ; line-height : 1.35 ; color : var ( - - h ) }
. qs { margin-top : 4 px ; font-size : 13.5 px ; color : var ( - - s ) }
. qs { margin-top : 4 px ; font-size : 13.5 px ; color : var ( - - s ) }
. opts { margin-top : 20 px ; display : flex ; flex-direction : column ; gap : 10 px }
. opts { margin-top : 20 px ; display : flex ; flex-direction : column ; gap : 10 px }
. opts . two { flex-direction : row }
. opts . hide2 { display : none }
. opts . hide2 { display : none }
. opt { display : flex ; align-items : center ; gap : 12 px ; width : 100 % ; min-height : 70 px ; padding : 12 px 14 px ; border-radius : 18 px ; border : 1.5 px solid var ( - - line ) ; background : #fff ; text-align : left ; transition : border-color .15 s , background .15 s , transform .15 s }
. opt { display : flex ; align-items : center ; gap : 12 px ; width : 100 % ; min-height : 70 px ; padding : 12 px 14 px ; border-radius : 18 px ; border : 1.5 px solid var ( - - line ) ; background : #fff ; text-align : left ; transition : border-color .15 s , background .15 s , transform .15 s }
. opt : active { transform : scale ( .98 ) }
. opt : active { transform : scale ( .98 ) }
@@ -172,13 +178,6 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
. opt . on . oi { background : var ( - - c ) ; color : #fff }
. opt . on . oi { background : var ( - - c ) ; color : #fff }
. opt . on . rd { border-color : var ( - - c ) ; background : var ( - - c ) }
. opt . on . rd { border-color : var ( - - c ) ; background : var ( - - c ) }
. opt . on . rd :: after { content : "" ; width : 8 px ; height : 8 px ; border-radius : 50 % ; background : #fff }
. opt . on . rd :: after { content : "" ; width : 8 px ; height : 8 px ; border-radius : 50 % ; background : #fff }
/* 第 1 题:两张大卡 */
. opts . two . opt { flex : 1 ; min-width : 0 ; flex-direction : column ; align-items : center ; justify-content : center ; gap : 8 px ; min-height : 188 px ; padding : 18 px 10 px ; text-align : center }
. opts . two . opt . oi { width : 76 px ; height : 76 px ; border-radius : 50 % }
. opts . two . opt . oi . ic { width : 40 px ; height : 40 px ; stroke-width : 1.5 }
. opts . two . opt b { font-size : 18 px }
. opts . two . opt . rd { position : absolute ; opacity : 0 }
. opts . two . opt { position : relative }
. qa { display : flex ; align-items : center ; justify-content : space-between ; gap : 10 px ; margin-top : 20 px }
. qa { display : flex ; align-items : center ; justify-content : space-between ; gap : 10 px ; margin-top : 20 px }
. prev { display : inline-flex ; align-items : center ; gap : 2 px ; padding : 8 px 4 px ; font-size : 14 px ; color : var ( - - s ) }
. prev { display : inline-flex ; align-items : center ; gap : 2 px ; padding : 8 px 4 px ; font-size : 14 px ; color : var ( - - s ) }
. prev . ic { width : 18 px ; height : 18 px }
. prev . ic { width : 18 px ; height : 18 px }
@@ -250,26 +249,8 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
. racts { display : flex ; gap : 10 px ; margin-top : 10 px }
. racts { display : flex ; gap : 10 px ; margin-top : 10 px }
. racts . btn { flex : 1 ; height : 44 px ; font-size : 15 px }
. racts . btn { flex : 1 ; height : 44 px ; font-size : 15 px }
/* ============ 情感 收尾 ============ */
/* ============ 收尾一行小提示 ============ */
. mom { position : relative ; margin-top : 34 px ; padding : 24 px 20 px 20 px ; border-radius : 26 px ; background : linear-gradient ( 170 deg , var ( - - warm ) 0 % , #FFFBF6 60 % , #fff 100 % ) ; border : 1 px solid #F6E7D6 ; overflow : hidden }
. hint { margin-top : 22 px ; font-size : 12.5 px ; line-height : 1.6 ; color : #B4936F ; text-align : center }
. mom . art { position : absolute ; right : 14 px ; top : 16 px ; width : 74 px ; height : 74 px ; opacity : .9 }
. mom . k { font-size : 12 px ; font-weight : 700 ; letter-spacing : .18 em ; color : var ( - - wt ) }
. mom h3 { margin-top : 8 px ; font-size : 25 px ; font-weight : 800 ; line-height : 1.35 ; color : var ( - - h ) }
. mom p { margin-top : 10 px ; font-size : 15 px ; line-height : 1.85 ; color : #5B5249 }
. mom p b { color : var ( - - h ) }
. mom p em { white-space : nowrap ; font-style : normal ; font-weight : 800 ; color : var ( - - wt ) }
. mom . say { margin-top : 14 px ; font-size : 17 px ; font-weight : 700 ; line-height : 1.7 ; color : var ( - - h ) }
. mom . say q { quotes : none ; display : inline ; background : linear-gradient ( transparent 60 % , rgba ( 244 , 196 , 140 , .45 ) 0 ) }
. msg { position : relative ; margin-top : 16 px ; padding : 14 px 14 px 12 px ; border-radius : 18 px ; background : #fff ; border : 1 px solid #F3E3D0 }
. msg . q { font-size : 14.5 px ; line-height : 1.75 ; color : var ( - - h ) ; min-height : 51 px }
. msg . ft { display : flex ; align-items : center ; justify-content : space-between ; margin-top : 8 px }
. msg . dt { display : flex ; gap : 5 px }
. msg . dt i { width : 6 px ; height : 6 px ; border-radius : 50 % ; background : #EAD8C3 ; transition : all .2 s }
. msg . dt i . on { width : 16 px ; border-radius : 9 px ; background : var ( - - wt ) }
. msg . sw { display : inline-flex ; align-items : center ; gap : 4 px ; height : 30 px ; padding : 0 10 px ; border-radius : 99 px ; background : var ( - - warm ) ; font-size : 13 px ; font-weight : 600 ; color : var ( - - wt ) }
. msg . sw . ic { width : 15 px ; height : 15 px }
. macts { display : flex ; flex-direction : column ; gap : 10 px ; margin-top : 14 px }
. macts . btn . w { background : #fff ; color : var ( - - c ) ; border : 1 px solid var ( - - c ) ; box-shadow : none }
. blk { margin-top : 30 px }
. blk { margin-top : 30 px }
. note { margin-top : 16 px ; font-size : 12 px ; color : var ( - - s ) ; line-height : 1.65 ; text-align : center }
. note { margin-top : 16 px ; font-size : 12 px ; color : var ( - - s ) ; line-height : 1.65 ; text-align : center }
@@ -296,14 +277,20 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
< symbol id = "i-check" viewBox = "0 0 24 24" > < path d = "M5 12.5l4.5 4.5L19 7.5" / > < / symbol >
< symbol id = "i-check" viewBox = "0 0 24 24" > < path d = "M5 12.5l4.5 4.5L19 7.5" / > < / symbol >
< symbol id = "i-refresh" viewBox = "0 0 24 24" > < path d = "M20 11a8 8 0 0 0-14.3-4.9L4 8M4 4v4h4M4 13a8 8 0 0 0 14.3 4.9L20 16M20 20v-4h-4" / > < / symbol >
< symbol id = "i-refresh" viewBox = "0 0 24 24" > < path d = "M20 11a8 8 0 0 0-14.3-4.9L4 8M4 4v4h4M4 13a8 8 0 0 0 14.3 4.9L20 16M20 20v-4h-4" / > < / symbol >
< symbol id = "i-edit" viewBox = "0 0 24 24" > < path d = "M4 20h4L19 9l-4-4L4 16z" / > < path d = "M13.5 6.5l4 4" / > < / symbol >
< symbol id = "i-edit" viewBox = "0 0 24 24" > < path d = "M4 20h4L19 9l-4-4L4 16z" / > < path d = "M13.5 6.5l4 4" / > < / symbol >
< symbol id = "i-copy" viewBox = "0 0 24 24" > < rect x = "8.5" y = "8.5" width = "11.5" height = "11.5" rx = "2.5" / > < path d = "M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5" / > < / symbol >
< symbol id = "i-img" viewBox = "0 0 24 24" > < rect x = "3.5" y = "4" width = "17" height = "16" rx = "3" / > < circle cx = "9" cy = "9.5" r = "1.8" / > < path d = "M4 17l4.5-4.5 3.5 3.5 2.5-2.5L20 18.5" / > < / symbol >
< symbol id = "i-img" viewBox = "0 0 24 24" > < rect x = "3.5" y = "4" width = "17" height = "16" rx = "3" / > < circle cx = "9" cy = "9.5" r = "1.8" / > < path d = "M4 17l4.5-4.5 3.5 3.5 2.5-2.5L20 18.5" / > < / symbol >
< symbol id = "i-hand" viewBox = "0 0 24 24" > < path d = "M9 11V5.5a1.5 1.5 0 0 1 3 0V11M12 10V4.5a1.5 1.5 0 0 1 3 0V11M15 10.5V6a1.5 1.5 0 0 1 3 0v8c0 4-2.5 6.5-6 6.5-2.6 0-4.2-1.3-5.6-3.6L4.3 13.6a1.5 1.5 0 0 1 2.5-1.6L9 14.5V8.5" / > < / symbol >
< symbol id = "i-hand" viewBox = "0 0 24 24" > < path d = "M9 11V5.5a1.5 1.5 0 0 1 3 0V11M12 10V4.5a1.5 1.5 0 0 1 3 0V11M15 10.5V6a1.5 1.5 0 0 1 3 0v8c0 4-2.5 6.5-6 6.5-2.6 0-4.2-1.3-5.6-3.6L4.3 13.6a1.5 1.5 0 0 1 2.5-1.6L9 14.5V8.5" / > < / symbol >
< symbol id = "i-leaf" viewBox = "0 0 24 24" > < path d = "M5 19c0-8 5-14 15-15-1 10-7 15-15 15z" / > < path d = "M5 19l8-8" / > < / symbol >
< symbol id = "i-leaf" viewBox = "0 0 24 24" > < path d = "M5 19c0-8 5-14 15-15-1 10-7 15-15 15z" / > < path d = "M5 19l8-8" / > < / symbol >
< symbol id = "o-shield2" viewBox = "0 0 24 24" > < path d = "M12 3l7 3v5c0 5-3 8-7 10-4-2-7-5-7-10V6z" / > < path d = "M9 12l2 2 4-4" / > < / symbol >
< symbol id = "o-shield2" viewBox = "0 0 24 24" > < path d = "M12 3l7 3v5c0 5-3 8-7 10-4-2-7-5-7-10V6z" / > < path d = "M9 12l2 2 4-4" / > < / symbol >
<!-- 选项图标 -->
<!-- 选项图标 -->
< symbol id = "o-girl " viewBox = "0 0 24 24" > < circle cx = "12" cy = "8.5" r = "4" / > < path d = "M8 8.5c0-3.5 1.5-5.5 4-5.5s4 2 4 5.5v3.8M8 8.5v3.8" / > < path d = "M5.5 21c.7-3.6 3.2-5.8 6.5-5.8s5.8 2.2 6.5 5. 8" / > < / symbol >
< symbol id = "o-hosp " viewBox = "0 0 24 24" > < path d = "M3 21h18M5 21V8h14v13M9 21v-4h6v4" / > < path d = "M12 10v5M9.5 12.5h5" / > < path d = "M9 8V4.5h6V 8" / > < / symbol >
< symbol id = "o-boy " viewBox = "0 0 24 24" > < circle cx = "12" cy = "9" r = "4" / > < path d = "M8.2 7.8c1.2.2 3.4-.2 4.8-1.8.8 1.2 2 1.8 2.8 1.8" / > < path d = "M5.5 21c.7-3.6 3.2-5.8 6.5-5.8s5.8 2.2 6.5 5.8 " / > < / symbol >
< symbol id = "o-star " viewBox = "0 0 24 24" > < path d = "M3 21h12M5 21V9h8v12M8 12.5h2M8 16h2" / > < path d = "M18 3.5l1.2 2.5 2.6.4-1.9 1.8.5 2.6-2.4-1.3-2.4 1.3.5-2.6-1.9-1.8 2.6-.4z " / > < / symbol >
< symbol id = "o-gem" viewBox = "0 0 24 24" > < path d = "M6.5 4h11L21 9l-9 11L3 9z" / > < path d = "M3 9h18M9.5 4L8 9l4 11 4-11-1.5-5" / > < / symbol >
< symbol id = "o-heart" viewBox = "0 0 24 24" > < path d = "M12 20c-5-3.6-8.5-7-8.5-11 0-2.7 2-4.7 4.5-4.7 1.7 0 3.1.9 4 2.4.9-1.5 2.3-2.4 4-2.4 2.5 0 4.5 2 4.5 4.7 0 4-3.5 7.4-8.5 11z" / > < / symbol >
< symbol id = "o-med" viewBox = "0 0 24 24" > < rect x = "3.5" y = "6.5" width = "17" height = "13" rx = "3" / > < path d = "M9 6.5V4.5h6v2M12 10v6M9 13h6" / > < / symbol >
< symbol id = "o-ask" viewBox = "0 0 24 24" > < circle cx = "12" cy = "12" r = "9" / > < path d = "M9.5 9.5a2.5 2.5 0 1 1 3.6 2.2c-.7.4-1.1.9-1.1 1.8v.5" / > < path d = "M12 17v.2" / > < / symbol >
< symbol id = "o-drop" viewBox = "0 0 24 24" > < path d = "M12 3.5c3.5 4.3 6 7.6 6 10.8a6 6 0 0 1-12 0c0-3.2 2.5-6.5 6-10.8z" / > < path d = "M9.2 14.5a2.9 2.9 0 0 0 2.6 2.8" / > < / symbol >
< symbol id = "o-mix" viewBox = "0 0 24 24" > < path d = "M7 3.5c2.3 2.8 4 5 4 7.2a4 4 0 0 1-8 0c0-2.2 1.7-4.4 4-7.2z" / > < path d = "M15 8h4M15.5 8v3l-1 1.5V20h5.5v-7.5l-1-1.5V8" / > < / symbol >
< symbol id = "o-bottle" viewBox = "0 0 24 24" > < path d = "M10 2.5h4M10.5 2.5v2.5L9 6.5h6l-1.5-1.5V2.5" / > < path d = "M8 9l1-2.5h6L16 9v10.5a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2z" / > < path d = "M8 12.5h3M8 15.5h3M8 18.5h3" / > < / symbol >
< symbol id = "o-bldg" viewBox = "0 0 24 24" > < path d = "M3 21h18M5 21V9l5-3v15M10 21V3l9 4v14M13.5 9h2M13.5 12.5h2M13.5 16h2M7 12h1M7 15.5h1" / > < / symbol >
< symbol id = "o-bldg" viewBox = "0 0 24 24" > < path d = "M3 21h18M5 21V9l5-3v15M10 21V3l9 4v14M13.5 9h2M13.5 12.5h2M13.5 16h2M7 12h1M7 15.5h1" / > < / symbol >
< symbol id = "o-bldg2" viewBox = "0 0 24 24" > < path d = "M3 21h18M5 21V10h6v11M11 21V6h8v15M14 9.5h2M14 13h2M14 16.5h2M7.5 13.5h1M7.5 17h1" / > < / symbol >
< symbol id = "o-bldg2" viewBox = "0 0 24 24" > < path d = "M3 21h18M5 21V10h6v11M11 21V6h8v15M14 9.5h2M14 13h2M14 16.5h2M7.5 13.5h1M7.5 17h1" / > < / symbol >
< symbol id = "o-house" viewBox = "0 0 24 24" > < path d = "M3.5 11L12 4l8.5 7M6 9.5V20h12V9.5" / > < path d = "M10 20v-5h4v5" / > < / symbol >
< symbol id = "o-house" viewBox = "0 0 24 24" > < path d = "M3.5 11L12 4l8.5 7M6 9.5V20h12V9.5" / > < path d = "M10 20v-5h4v5" / > < / symbol >
@@ -381,32 +368,18 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
< button class = "btn ghost press" id = "reAns" > < svg class = "ic" > < use href = "#i-edit" xlink:href = "#i-edit" / > < / svg > 改一下答案< / button >
< button class = "btn ghost press" id = "reAns" > < svg class = "ic" > < use href = "#i-edit" xlink:href = "#i-edit" / > < / svg > 改一下答案< / button >
< / div >
< / div >
< div class = "mom fu" id = "mom" >
< p class = "hint" > 账单算完了,也记得和家人说说心里话。< / p >
< svg class = "art" viewBox = "0 0 80 80" aria-hidden = "true" > < circle cx = "40" cy = "40" r = "38" fill = "#FFEBD6" / > < path d = "M40 60c-9-6.3-16-12.4-16-20.2 0-5 3.7-8.8 8.3-8.8 3.3 0 6 1.8 7.7 4.6 1.7-2.8 4.4-4.6 7.7-4.6 4.6 0 8.3 3.8 8.3 8.8C56 47.6 49 53.7 40 60z" fill = "#F7B98A" stroke = "#C9824A" stroke-width = "2" stroke-linejoin = "round" / > < path d = "M40 60v8M36 66c1.5-1.8 2.8-2.5 4-2.5s2.5.7 4 2.5" fill = "none" stroke = "#18A058" stroke-width = "2" stroke-linecap = "round" / > < path d = "M33.5 38.5c.6-1.8 2-3 3.8-3.2" fill = "none" stroke = "#fff" stroke-width = "2" stroke-linecap = "round" / > < / svg >
< div class = "k" > 写在账单后面< / div >
< h3 id = "momH" > < / h3 >
< p id = "momP" > < / p >
< p class = "say" > 如果可以的话,今天对她说一句:< br > < q > 妈,辛苦了。< / q > < / p >
< div class = "msg" >
< div class = "q" id = "msgQ" > < / div >
< div class = "ft" > < span class = "dt" id = "msgDt" > < / span > < button class = "sw press" id = "msgSw" > < svg class = "ic" > < use href = "#i-refresh" xlink:href = "#i-refresh" / > < / svg > 换一句< / button > < / div >
< / div >
< div class = "macts" >
< button class = "btn press" id = "copyBtn" > < svg class = "ic" > < use href = "#i-copy" xlink:href = "#i-copy" / > < / svg > 复制这句话,发给妈妈< / button >
< button class = "btn w press" id = "cardBtn" > < svg class = "ic" > < use href = "#i-img" xlink:href = "#i-img" / > < / svg > 生成卡片< / button >
< / div >
< / div >
< div id = "tools" class = "fu" > < / div >
< div id = "tools" class = "fu" > < / div >
< p class = "note" > < b > 估算区间,仅供参考。< / b > 按 2025~ 2026 年国内常见公开行情粗算,单项取中间值;收入只用来做对比,只存在你的手机上;按有生育保险估报销,不含早产、大病、住院等意外支出,不计通胀和房子;各地各家差别很大,看个大概就好。< / p >
< p class = "note" > < b > 估算区间,仅供参考。< / b > 按 2025~ 2026 年国内常见公开行情粗算,单项取中间值;收入只用来做对比,只存在你的手机上;按有生育保险估报销、剖宫产按无并发症估 ,不含早产、大病、住院等意外支出,不计通胀和房子;各地各家差别很大,看个大概就好。< / p >
< / section >
< / section >
< / div >
< / div >
< div class = "mask" id = "mask" >
< div class = "mask" id = "mask" >
< div class = "mwrap" id = "mwrap" > < img id = "maskImg" alt = "给妈妈的卡片 " > < / div >
< div class = "mwrap" id = "mwrap" > < img id = "maskImg" alt = "我的养娃账单 " > < / div >
< p > < svg class = "ic" > < use href = "#i-hand" xlink:href = "#i-hand" / > < / svg > < span id = "maskTip" > 长按图片,保存或发给妈妈 < / span > < / p >
< p > < svg class = "ic" > < use href = "#i-hand" xlink:href = "#i-hand" / > < / svg > < span id = "maskTip" > 长按图片,保存到相册 < / span > < / p >
< div class = "row" > < a id = "dlBtn" download = "给妈妈的卡片 .png" hidden > 下载图片< / a > < button id = "maskClose" > 关闭< / button > < / div >
< div class = "row" > < a id = "dlBtn" download = "养娃账单 .png" hidden > 下载图片< / a > < button id = "maskClose" > 关闭< / button > < / div >
< / div >
< / div >
< div class = "toast" id = "toast" > < / div >
< div class = "toast" id = "toast" > < / div >
@@ -418,11 +391,11 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
/* ================= 路线 ================= */
/* ================= 路线 ================= */
var ROUTES = [
var ROUTES = [
{ id : 'rich' , badge : 'b-rich' , who : '我是大富豪' , how : '富养娃' , line : '钱能解决的,都不让娃将就' ,
{ id : 'rich' , badge : 'b-rich' , who : '我是大富豪' , how : '富养娃' , line : '钱能解决的,都不让娃将就' ,
tags : [ '私立高端产检' , '月子中心' , '育儿嫂' , '国际学校' ] , def : { care : 2 , school : 2 , extra : 2 } } ,
tags : [ '私立高端产检' , '月子中心' , '育儿嫂' , '国际学校' ] , def : { hosp : 2 , yuezi : 2 , care: 2 , school : 2 , extra : 2 } } ,
{ id : 'mid' , badge : 'b-mid' , who : '我是中产家' , how : '从容养' , line : '不卷也不亏待,日子过得舒展' ,
{ id : 'mid' , badge : 'b-mid' , who : '我是中产家' , how : '从容养' , line : '不卷也不亏待,日子过得舒展' ,
tags : [ '公立特需' , '月嫂' , '托班' , '适度早教' ] , def : { care : 1 , school : 0 , extra : 1 } } ,
tags : [ '公立特需' , '月嫂' , '托班' , '适度早教' ] , def : { hosp : 1 , yuezi : 1 , care: 1 , school : 0 , extra : 1 } } ,
{ id : 'low' , badge : 'b-low' , who : '我是普通人' , how : '量力养' , line : '能省则省,爱一点不少' ,
{ id : 'low' , badge : 'b-low' , who : '我是普通人' , how : '量力养' , line : '能省则省,爱一点不少' ,
tags : [ '公立医院' , '家人坐月子' , '老人帮带' , '能省则省' ] , def : { care : 0 , school : 0 , extra : 0 } }
tags : [ '公立医院' , '家人坐月子' , '老人帮带' , '能省则省' ] , def : { hosp : 0 , yuezi : 0 , care: 0 , school : 0 , extra : 0 } }
] ;
] ;
function tierOf ( r ) { return [ 2 , 1 , 0 ] [ r ] ; } // 档次 T: 0 量力 / 1 从容 / 2 富养
function tierOf ( r ) { return [ 2 , 1 , 0 ] [ r ] ; } // 档次 T: 0 量力 / 1 从容 / 2 富养
@@ -444,14 +417,23 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
/* ================= 问题(按所选阶段出现) ================= */
/* ================= 问题(按所选阶段出现) ================= */
var QS = [
var QS = [
{ k : 'sex' , h : '先认识一下,你是…' , s : '账单最后,有句话想对你说' , two : 1 , o : [
[ '女生' , '我是准妈妈' , 'girl' ] , [ '男生' , '我是准爸爸' , 'boy' ] ] } ,
{ k : 'st' , type : 'stage' , h : '这次想算哪一段?' , s : '默认从怀孕算到 18 岁,也可以只算其中几段' } ,
{ k : 'st' , type : 'stage' , h : '这次想算哪一段?' , s : '默认从怀孕算到 18 岁,也可以只算其中几段' } ,
{ k : 'city' , h : '你家在哪类城市?' , s : '月嫂、托班、学费都跟着城市走' , o : [
{ k : 'city' , h : '你家在哪类城市?' , s : '月嫂、托班、学费都跟着城市走' , o : [
[ '一线城市' , '北京、上海、广州、深圳' , 'bldg' ] , [ '新一线及省会' , '成都、杭州、武汉、各省会' , 'bldg2' ] ,
[ '一线城市' , '北京、上海、广州、深圳' , 'bldg' ] , [ '新一线及省会' , '成都、杭州、武汉、各省会' , 'bldg2' ] ,
[ '普通地级市' , '三四线城市' , 'house' ] , [ '县城及乡镇' , '县城、镇上' , 'tree' ] ] } ,
[ '普通地级市' , '三四线城市' , 'house' ] , [ '县城及乡镇' , '县城、镇上' , 'tree' ] ] } ,
{ k : 'kid' , h : '这是第几个宝宝?' , s : '老大的东西能接着用' , if : function ( st ) { return has ( st , [ 0 , 1 , 2 , 3 , 4 ] ) ; } , o : [
{ k : 'kid' , h : '这是第几个宝宝?' , s : '老大的东西能接着用' , if : function ( st ) { return has ( st , [ 0 , 1 , 2 , 3 , 4 ] ) ; } , o : [
[ '头胎' , '推车、衣服、玩具都要新添置' , 'one' ] , [ '二胎及以上' , '大件和衣物能复用一部分' , 'layers' ] ] } ,
[ '头胎' , '推车、衣服、玩具都要新添置' , 'one' ] , [ '二胎及以上' , '大件和衣物能复用一部分' , 'layers' ] ] } ,
{ k : 'hosp' , h : '打算在哪类医院产检、生娃?' , s : '产检和分娩的费用,主要看医院' , if : function ( st ) { return has ( st , [ 0 , 1 ] ) ; } , o : [
[ '公立医院普通门诊' , '建档产检、普通病房,医保能报' , 'hosp' ] , [ '公立医院特需' , '特需门诊、单间病房,自费多一些' , 'star' ] ,
[ '私立妇产医院' , '产检分娩套餐、VIP 病房' , 'gem' ] ] } ,
{ k : 'birth' , h : '预计顺产还是剖宫产?' , s : '剖宫产手术费更高、要多住几天' , d : 2 , if : function ( st ) { return has ( st , [ 1 ] ) ; } , o : [
[ '顺产' , '一般住院 2~ 3 天,可选无痛' , 'heart' ] , [ '剖宫产' , '一般住院 4~ 6 天,手术和麻醉另算' , 'med' ] ,
[ '还不确定' , '按顺产估,再留一点剖宫产的差价' , 'ask' ] ] } ,
{ k : 'yuezi' , h : '月子打算怎么坐?' , s : '坐月子是生娃前后最大的一笔' , if : function ( st ) { return has ( st , [ 2 ] ) ; } , o : [
[ '家里人照顾' , '家人做月子餐、帮带宝宝' , 'family' ] , [ '请月嫂到家' , '26 天住家月嫂' , 'nurse' ] ,
[ '住月子中心' , '28 天,吃住护理都包' , 'bldg2' ] ] } ,
{ k : 'feed' , h : '宝宝打算怎么喂?' , s : '第一年奶粉花多少,差别就在这' , d : 1 , if : function ( st ) { return has ( st , [ 2 , 3 ] ) ; } , o : [
[ '母乳为主' , '偶尔补一点奶粉' , 'drop' ] , [ '混合喂养' , '母乳加奶粉' , 'mix' ] , [ '奶粉喂养' , '主要喝奶粉' , 'bottle' ] ] } ,
{ k : 'care' , h : '0~ 3 岁,白天谁带娃?' , s : '产假结束后的安排,差别很大' , if : function ( st ) { return has ( st , [ 3 , 4 , 5 ] ) ; } , o : [
{ k : 'care' , h : '0~ 3 岁,白天谁带娃?' , s : '产假结束后的安排,差别很大' , if : function ( st ) { return has ( st , [ 3 , 4 , 5 ] ) ; } , o : [
[ '老人或自己带' , '给老人一点补贴, 3 岁上幼儿园' , 'family' ] , [ '家里带, 2 岁上托班' , '第 3 年交托班费' , 'flag' ] ,
[ '老人或自己带' , '给老人一点补贴, 3 岁上幼儿园' , 'family' ] , [ '家里带, 2 岁上托班' , '第 3 年交托班费' , 'flag' ] ,
[ '请育儿嫂' , '住家或白班阿姨,带到上幼儿园' , 'nurse' ] , [ '1 岁半上托育园' , '全日托,按月费算' , 'school' ] ] } ,
[ '请育儿嫂' , '住家或白班阿姨,带到上幼儿园' , 'nurse' ] , [ '1 岁半上托育园' , '全日托,按月费算' , 'school' ] ] } ,
@@ -466,21 +448,36 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
/* ================= 费用表( 单位: 元, 2025~ 2026 国内常见公开行情;基准 = 新一线及省会) =================
/* ================= 费用表( 单位: 元, 2025~ 2026 国内常见公开行情;基准 = 新一线及省会) =================
I(名称, [量力低,高], [从容低,高], [富养低,高], 城市系数, 二胎复用系数)。名称可以是 [量力名, 从容名, 富养名];某档 [0,0] 表示这档不花这笔。
I(名称, [量力低,高], [从容低,高], [富养低,高], 城市系数, 二胎复用系数)。名称可以是 [量力名, 从容名, 富养名];某档 [0,0] 表示这档不花这笔。
D(答案键, 名称或按答案的名称数组, [按答案的 [低,高]...], 城市系数):随答案变(上学路线 school / 课外班 extra) 。
D(答案键, 名称或按答案的名称数组, [按答案的 [低,高]...], 城市系数):随答案变(医院 hosp / 上学路线 school / 课外班 extra 等 )。
F(名称或 s=>名称, s=>[低,高], 城市系数, 二胎复用系数):要同时看几道题的项(分娩方式 × 医院、月子 × 档次、喂养 × 档次);名称为空或 [0,0] 不列。
城市系数: s 人工/服务/教育, g 吃穿用, m 医疗, 0 不随城市变。 */
城市系数: s 人工/服务/教育, g 吃穿用, m 医疗, 0 不随城市变。 */
var CF = { s : [ 1.45 , 1 , 0.72 , 0.55 ] , g : [ 1.1 , 1 , 0.9 , 0.82 ] , m : [ 1.25 , 1 , 0.8 , 0.65 ] , '0' : [ 1 , 1 , 1 , 1 ] } ;
var CF = { s : [ 1.45 , 1 , 0.72 , 0.55 ] , g : [ 1.1 , 1 , 0.9 , 0.82 ] , m : [ 1.25 , 1 , 0.8 , 0.65 ] , '0' : [ 1 , 1 , 1 , 1 ] } ;
function I ( n , a , b , c , k , r ) { return { n : n , v : [ a , b , c ] , k : k , r : r } ; }
function I ( n , a , b , c , k , r ) { return { n : n , v : [ a , b , c ] , k : k , r : r } ; }
function D ( g , n , vs , k ) { return { g : g , n : n , dv : vs , k : k } ; }
function D ( g , n , vs , k ) { return { g : g , n : n , dv : vs , k : k } ; }
function F ( n , fv , k , r ) { return { n : typeof n === 'function' ? n : function ( ) { return n ; } , fv : fv , k : k , r : r } ; }
function sc3 ( v , f ) { return [ v [ 0 ] * f , v [ 1 ] * f ] ; }
// 分娩主项 [医院][分娩方式:顺产/剖宫产/还不确定](不确定 ≈ 顺产 + 约三成剖宫产差价)
var DELIV = [
[ [ 3000 , 6000 ] , [ 8000 , 15000 ] , [ 4500 , 9000 ] ] ,
[ [ 6000 , 12000 ] , [ 15000 , 25000 ] , [ 8500 , 16000 ] ] ,
[ [ 25000 , 50000 ] , [ 45000 , 90000 ] , [ 31000 , 62000 ] ]
] ;
var YUEZI = [ // 月子主项 [月子打算][档次 T]
[ [ 2000 , 4000 ] , [ 2500 , 5000 ] , [ 3000 , 6000 ] ] ,
[ [ 8000 , 13000 ] , [ 12000 , 20000 ] , [ 18000 , 30000 ] ] ,
[ [ 25000 , 40000 ] , [ 35000 , 60000 ] , [ 50000 , 120000 ] ]
] ;
var MILK1 = [ [ 8000 , 14000 ] , [ 12000 , 20000 ] , [ 18000 , 28000 ] ] , MILK _F = [ 0.15 , 0.5 , 1 ] ; // 0~ 1 岁全奶粉喂养 [档次];按喂养方式乘系数
var SUB = [ 3600 , 9600 ] , NANNY = [ 60000 , 90000 ] , TUOBAN = [ 20000 , 45000 ] , DAYCARE = [ 27500 , 55000 ] ;
var SUB = [ 3600 , 9600 ] , NANNY = [ 60000 , 90000 ] , TUOBAN = [ 20000 , 45000 ] , DAYCARE = [ 27500 , 55000 ] ;
var COST = [
var COST = [
// ① 孕期产检
// ① 孕期产检
[
[
I ( [ '建档和常规产检(约 12 次)' , '特需门诊产检(约 12 次)' , '私立医院产检套餐' ] , [ 1500 , 3000 ] , [ 5000 , 10000 ] , [ 15000 , 30000 ] , 'm' ) ,
D ( 'hosp' , [ '建档和常规产检(约 12 次)' , '特需门诊产检(约 12 次)' , '私立医院产检套餐' ] , [ [ 1500 , 3000 ] , [ 5000 , 10000 ] , [ 15000 , 30000 ] ] , 'm' ) ,
I ( 'B 超( NT、大排畸、晚孕) ' , [ 800 , 1500 ] , [ 1500 , 3000 ] , [ 2000 , 4000 ] , 'm' ) ,
D ( 'hosp' , 'B 超( NT、大排畸、晚孕) ' , [ [ 800 , 1500 ] , [ 1500 , 3000 ] , [ 2000 , 4000 ] ] , 'm' ) ,
I ( [ '唐氏筛查' , '无创 DNA( NIPT) ' , '无创 DNA 加强版' ] , [ 200 , 400 ] , [ 1500 , 2500 ] , [ 2500 , 4000 ] , 'm' ) ,
I ( [ '唐氏筛查' , '无创 DNA( NIPT) ' , '无创 DNA 加强版' ] , [ 200 , 400 ] , [ 1500 , 2500 ] , [ 2500 , 4000 ] , 'm' ) ,
I ( '四维彩超' , [ 300 , 600 ] , [ 500 , 1000 ] , [ 800 , 2000 ] , 'm' ) ,
D ( 'hosp' , ' 四维彩超' , [ [ 300 , 600 ] , [ 500 , 1000 ] , [ 800 , 2000 ] ] , 'm' ) ,
I ( '糖耐量和血液检查' , [ 300 , 600 ] , [ 500 , 1000 ] , [ 800 , 1500 ] , 'm' ) ,
D ( 'hosp' , ' 糖耐量和血液检查' , [ [ 300 , 600 ] , [ 500 , 1000 ] , [ 800 , 1500 ] ] , 'm' ) ,
I ( '胎心监护' , [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'm' ) ,
D ( 'hosp' , ' 胎心监护' , [ [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] ] , 'm' ) ,
I ( '孕妇奶粉' , [ 0 , 600 ] , [ 1200 , 2400 ] , [ 2400 , 4800 ] , 'g' ) ,
I ( '孕妇奶粉' , [ 0 , 600 ] , [ 1200 , 2400 ] , [ 2400 , 4800 ] , 'g' ) ,
I ( '叶酸、DHA、钙铁维生素' , [ 500 , 1200 ] , [ 1500 , 3000 ] , [ 3000 , 6000 ] , 'g' ) ,
I ( '叶酸、DHA、钙铁维生素' , [ 500 , 1200 ] , [ 1500 , 3000 ] , [ 3000 , 6000 ] , 'g' ) ,
I ( '孕妇装和孕妇内衣' , [ 600 , 1500 ] , [ 1500 , 3500 ] , [ 4000 , 10000 ] , 'g' ) ,
I ( '孕妇装和孕妇内衣' , [ 600 , 1500 ] , [ 1500 , 3500 ] , [ 4000 , 10000 ] , 'g' ) ,
@@ -494,26 +491,30 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
] ,
] ,
// ② 分娩住院
// ② 分娩住院
[
[
I ( [ '公立普通病房分娩 ' , '公立特需分娩 ' , '私立医院分娩套餐 ' ] , [ 3000 , 8000 ] , [ 8000 , 18000 ] , [ 35000 , 80000 ] , 'm' ) ,
F ( function ( s ) { return [ '公立普通病房' , '公立特需' , '私立医院' ] [ s . hosp ] + [ '顺产' , '剖宫产' , '分娩(顺剖未定)' ] [ s . birth ] ; } ,
I ( [ '无痛分娩' , '无痛分娩和导乐' , '无痛和一对一助产' ] , [ 1000 , 2500 ] , [ 2000 , 4000 ] , [ 3000 , 8000 ] , 'm' ) ,
function ( s ) { return DELIV [ s . hosp ] [ s . birth ] ; } , 'm' ) ,
I ( [ '病房床位' , '单间升级' , 'VIP 套房升级' ] , [ 300 , 800 ] , [ 2000 , 5000 ] , [ 5000 , 15000 ] , 'm' ) ,
F ( function ( s ) { return s . birth === 1 ? '术后镇痛泵' : [ '无痛分娩' , '无痛分娩和导乐' , '无痛和一对一助产' ] [ s . hosp ] ; } ,
function ( s ) { return s . birth === 1 ? [ [ 500 , 1200 ] , [ 800 , 1500 ] , [ 1000 , 3000 ] ] [ s . hosp ] : [ [ 1000 , 2500 ] , [ 2000 , 4000 ] , [ 3000 , 8000 ] ] [ s . hosp ] ; } , 'm' ) ,
F ( function ( s ) { return [ '病房床位' , '单间升级' , 'VIP 套房升级' ] [ s . hosp ] + ( s . birth === 1 ? '(多住几天)' : '' ) ; } ,
function ( s ) { return sc3 ( [ [ 300 , 800 ] , [ 2000 , 5000 ] , [ 5000 , 15000 ] ] [ s . hosp ] , [ 1 , 1.6 , 1.2 ] [ s . birth ] ) ; } , 'm' ) ,
I ( '陪护床和护工' , [ 300 , 800 ] , [ 1000 , 2500 ] , [ 2000 , 5000 ] , 's' ) ,
I ( '陪护床和护工' , [ 300 , 800 ] , [ 1000 , 2500 ] , [ 2000 , 5000 ] , 's' ) ,
I ( '新生儿筛查(听力、足跟血)' , [ 300 , 800 ] , [ 500 , 1200 ] , [ 1500 , 3000 ] , 'm' ) ,
D ( 'hosp' , '新生儿筛查(听力、足跟血)' , [ [ 300 , 800 ] , [ 500 , 1200 ] , [ 1500 , 3000 ] ] , 'm' ) ,
I ( '新生儿尿片、衣服、包被' , [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( '新生儿尿片、衣服、包被' , [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( '产妇用品(产褥垫、收腹带)' , [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( '产妇用品(产褥垫、收腹带)' , [ 200 , 500 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( [ '住院餐' , '住院营养餐' , '院内营养月子餐' ] , [ 300 , 800 ] , [ 800 , 1500 ] , [ 2000 , 4000 ] , 's' ) ,
F ( function ( s ) { return [ '住院餐' , '住院营养餐' , '院内营养月子餐' ] [ s . hosp ] ; } , function ( s ) { return sc3 ( [ [ 300 , 800 ] , [ 800 , 1500 ] , [ 2000 , 4000 ] ] [ s . hosp ] , [ 1 , 1.6 , 1.2 ] [ s . birth ] ) ; } , 's' ) ,
I ( '脐带血存储' , [ 0 , 0 ] , [ 0 , 0 ] , [ 15000 , 25000 ] , '0' ) ,
I ( '脐带血存储' , [ 0 , 0 ] , [ 0 , 0 ] , [ 15000 , 25000 ] , '0' ) ,
I ( '报喜红包和喜糖' , [ 500 , 1500 ] , [ 1000 , 3000 ] , [ 3000 , 8000 ] , 'g' ) ,
I ( '报喜红包和喜糖' , [ 500 , 1500 ] , [ 1000 , 3000 ] , [ 3000 , 8000 ] , 'g' ) ,
I ( '家属交通和餐费' , [ 300 , 800 ] , [ 500 , 1500 ] , [ 1000 , 3000 ] , 's' ) ,
I ( '家属交通和餐费' , [ 300 , 800 ] , [ 500 , 1500 ] , [ 1000 , 3000 ] , 's' ) ,
I ( '生育保险报销(预估)' , [ - 5000 , - 2500 ] , [ - 4500 , - 2000 ] , [ - 2500 , - 500 ] , 'm' )
F ( '生育保险报销(预估)' , function ( s ) { return sc3 ( [ [ - 5000 , - 2500 ] , [ - 4500 , - 2000 ] , [ - 2500 , - 500 ] ] [ s . hosp ] , [ 1 , 1.4 , 1.1 ] [ s . birth ] ) ; } , 'm' )
] ,
] ,
// ③ 坐月子
// ③ 坐月子
[
[
I ( [ '月子餐食材(家人做)' , '月嫂 26 天' , '高端月子中心 28 天' ] , [ 2500 , 5000 ] , [ 12000 , 20000 ] , [ 50000 , 120000 ] , 's' ) ,
F ( function ( s ) { return [ '月子餐食材(家人做)' , '住家 月嫂 26 天' , s . T === 2 ? '高端月子中心 28 天' : '月子中心 28 天' ] [ s . yuezi ] ; } ,
I ( '月子餐食材和营养汤' , [ 0 , 0 ] , [ 2000 , 4000 ] , [ 0 , 0 ] , 'g ' ) ,
function ( s ) { return YUEZI [ s . yuezi ] [ s . T ] ; } , 's ' ) ,
I ( '催乳和通乳' , [ 0 , 5 00] , [ 8 00, 2 000] , [ 2 000, 5 000] , 's ' ) ,
F ( '月子餐食材和营养汤' , function ( s ) { return s . yuezi === 1 ? [ [ 150 0, 30 00] , [ 20 00, 4 000] , [ 3 000, 6 000] ] [ s . T ] : [ 0 , 0 ] ; } , 'g ' ) ,
I ( '吸奶器和储奶袋' , [ 30 0 , 8 00] , [ 800 , 2000 ] , [ 2000 , 4 000] , 'g' , 0.5 ) ,
F ( '催乳和通乳' , function ( s ) { return s . feed === 2 ? [ 0 , 0 ] : [ [ 0 , 5 00] , [ 800 , 2000 ] , [ 2000 , 5 000] ] [ s . T ] ; } , 's' ) ,
I ( '哺乳内衣和防溢乳垫' , [ 2 00 , 5 00] , [ 4 00, 9 00] , [ 8 00, 2 000] , 'g' ) ,
F ( '吸奶器和储奶袋' , function ( s ) { return s . feed === 2 ? [ 0 , 0 ] : [ [ 3 00 , 8 00] , [ 8 00, 20 00] , [ 2 000 , 4 000] ] [ s . T ] ; } , 'g' , 0.5 ) ,
F ( '哺乳内衣和防溢乳垫' , function ( s ) { return s . feed === 2 ? [ 0 , 0 ] : [ [ 200 , 500 ] , [ 400 , 900 ] , [ 800 , 2000 ] ] [ s . T ] ; } , 'g' ) ,
I ( '产妇卫生巾和月子服' , [ 300 , 700 ] , [ 500 , 1200 ] , [ 1000 , 2500 ] , 'g' ) ,
I ( '产妇卫生巾和月子服' , [ 300 , 700 ] , [ 500 , 1200 ] , [ 1000 , 2500 ] , 'g' ) ,
I ( [ '产后盆底康复(医院)' , '产后修复疗程' , '产后修复和私教塑形' ] , [ 500 , 1500 ] , [ 3000 , 6000 ] , [ 10000 , 25000 ] , 's' ) ,
I ( [ '产后盆底康复(医院)' , '产后修复疗程' , '产后修复和私教塑形' ] , [ 500 , 1500 ] , [ 3000 , 6000 ] , [ 10000 , 25000 ] , 's' ) ,
I ( '产后 42 天复查' , [ 200 , 500 ] , [ 400 , 1000 ] , [ 1000 , 3000 ] , 'm' ) ,
I ( '产后 42 天复查' , [ 200 , 500 ] , [ 400 , 1000 ] , [ 1000 , 3000 ] , 'm' ) ,
@@ -524,7 +525,8 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
] ,
] ,
// ④ 0~ 1 岁
// ④ 0~ 1 岁
[
[
I ( [ '国产奶粉(混合喂养) ' , '国产高端奶粉' , '进口有机奶粉' ] , [ 3000 , 6000 ] , [ 6000 , 10000 ] , [ 12000 , 20000 ] , 'g' ) ,
F ( function ( s ) { return [ '国产奶粉' , '国产高端奶粉' , '进口有机奶粉' ] [ s . T ] + [ '(偶尔补充)' , '(混合喂养)' , '(全奶粉喂养)' ] [ s . feed ] ; } ,
function ( s ) { return sc3 ( MILK1 [ s . T ] , MILK _F [ s . feed ] ) ; } , 'g' ) ,
I ( '米粉和辅食' , [ 800 , 1500 ] , [ 1500 , 3000 ] , [ 3000 , 6000 ] , 'g' ) ,
I ( '米粉和辅食' , [ 800 , 1500 ] , [ 1500 , 3000 ] , [ 3000 , 6000 ] , 'g' ) ,
I ( '奶瓶和奶嘴' , [ 200 , 400 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( '奶瓶和奶嘴' , [ 200 , 400 ] , [ 400 , 800 ] , [ 800 , 1500 ] , 'g' ) ,
I ( '温奶器、消毒器' , [ 200 , 400 ] , [ 400 , 900 ] , [ 1000 , 2500 ] , 'g' , 0.5 ) ,
I ( '温奶器、消毒器' , [ 200 , 400 ] , [ 400 , 900 ] , [ 1000 , 2500 ] , 'g' , 0.5 ) ,
@@ -552,7 +554,7 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
] ,
] ,
// ⑤ 1~ 3 岁( f1 = 属于 1~ 2 岁那一年的比例,用来算 2 岁累计)
// ⑤ 1~ 3 岁( f1 = 属于 1~ 2 岁那一年的比例,用来算 2 岁累计)
[
[
I ( [ '国产奶粉' , '国产高端奶粉' , '进口高端奶粉' ] , [ 3000 , 6000 ] , [ 6000 , 10000 ] , [ 12000 , 18000 ] , 'g' ) ,
F ( function ( s ) { return [ '国产奶粉' , '国产高端奶粉' , '进口高端奶粉' ] [ s . T ] ; } , function ( s ) { return sc3 ( [ [ 3000 , 6000 ] , [ 6000 , 10000 ] , [ 12000 , 18000 ] ] [ s . T ] , [ 0.7 , 0.85 , 1 ] [ s . feed ] ) ; } , 'g' ) ,
I ( '纸尿裤和拉拉裤' , [ 2000 , 3500 ] , [ 3000 , 5000 ] , [ 4500 , 7000 ] , 'g' ) ,
I ( '纸尿裤和拉拉裤' , [ 2000 , 3500 ] , [ 3000 , 5000 ] , [ 4500 , 7000 ] , 'g' ) ,
I ( '湿巾和洗护用品' , [ 600 , 1200 ] , [ 1000 , 2000 ] , [ 2000 , 4000 ] , 'g' ) ,
I ( '湿巾和洗护用品' , [ 600 , 1200 ] , [ 1000 , 2000 ] , [ 2000 , 4000 ] , 'g' ) ,
I ( '辅食、水果和零食' , [ 4000 , 8000 ] , [ 6000 , 12000 ] , [ 12000 , 24000 ] , 'g' ) ,
I ( '辅食、水果和零食' , [ 4000 , 8000 ] , [ 6000 , 12000 ] , [ 12000 , 24000 ] , 'g' ) ,
@@ -676,15 +678,17 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
var $ = function ( s ) { return document . querySelector ( s ) ; } ;
var $ = function ( s ) { return document . querySelector ( s ) ; } ;
var sc = $ ( '#scroll' ) ;
var sc = $ ( '#scroll' ) ;
var reduce = window . matchMedia && matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches ;
var reduce = window . matchMedia && matchMedia ( '(prefers-reduced-motion: reduce)' ) . matches ;
var route = - 1 , A = { } , cur = 0 , hasBill = false , msgI = 0 , bill = null , billNo = '' , billAt = '' ;
var route = - 1 , A = { } , cur = 0 , hasBill = false , bill = null , billNo = '' , billAt = '' ;
/* ================= 计算 ================= */
/* ================= 计算 ================= */
function r100 ( n ) { return Math . round ( n / 100 ) * 100 ; }
function r100 ( n ) { return Math . round ( n / 100 ) * 100 ; }
function sel ( ) { return A . st && A . st . length ? A . st : ALL ; }
function sel ( ) { return A . st && A . st . length ? A . st : ALL ; }
function ctx ( r , a ) {
function ctx ( r , a ) {
var d = ROUTES [ r ] . def ;
var d = ROUTES [ r ] . def ;
function g ( k ) { return a [ k ] != null ? a [ k ] : d [ k ] != null ? d [ k ] : QK [ k ] . d ; }
return { T : tierOf ( r ) , city : a . city == null ? 1 : a . city , kid : a . kid || 0 ,
return { T : tierOf ( r ) , city : a . city == null ? 1 : a . city , kid : a . kid || 0 ,
care : a . care == null ? d . care : a . care , school : a . school == null ? d . school : a . school , extra : a . extra == null ? d . extra : a . extra } ;
hosp : g ( 'hosp' ) , birth : g ( 'birth' ) , yuezi : g ( 'yuezi' ) , feed : g ( 'feed' ) ,
care : g ( 'care' ) , school : g ( 'school' ) , extra : g ( 'extra' ) } ;
}
}
function calc ( r , a , stages ) {
function calc ( r , a , stages ) {
var s = ctx ( r , a ) ;
var s = ctx ( r , a ) ;
@@ -773,7 +777,7 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
$ ( '#routes' ) . addEventListener ( 'click' , function ( e ) {
$ ( '#routes' ) . addEventListener ( 'click' , function ( e ) {
var b = e . target . closest ( '.rt' ) ; if ( ! b ) return ;
var b = e . target . closest ( '.rt' ) ; if ( ! b ) return ;
var r = + b . dataset . r ;
var r = + b . dataset . r ;
if ( r !== route ) { route = r ; delete A . care ; delete A . school ; delete A . extra ; } // 换路线:后几题回到新路线的默认
if ( r !== route ) { route = r ; Object . keys ( ROUTES [ r ] . def ) . forEach ( function ( k ) { delete A [ k ] ; } ) ; } // 换路线:后几题回到新路线的默认
markRoute ( ) ;
markRoute ( ) ;
} ) ;
} ) ;
$ ( '#goQ' ) . addEventListener ( 'click' , function ( ) { if ( route < 0 ) return ; cur = 0 ; renderQ ( ) ; } ) ;
$ ( '#goQ' ) . addEventListener ( 'click' , function ( ) { if ( route < 0 ) return ; cur = 0 ; renderQ ( ) ; } ) ;
@@ -781,7 +785,7 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
/* ================= 问题屏 ================= */
/* ================= 问题屏 ================= */
function flow ( ) { var st = sel ( ) ; return QS . filter ( function ( q ) { return ! q . if || q . if ( st ) ; } ) ; }
function flow ( ) { var st = sel ( ) ; return QS . filter ( function ( q ) { return ! q . if || q . if ( st ) ; } ) ; }
function val ( k ) { if ( A [ k ] != null ) return A [ k ] ; var d = ROUTES [ route ] . def ; return d [ k ] != null ? d [ k ] : null ; }
function val ( k ) { if ( A [ k ] != null ) return A [ k ] ; var d = ROUTES [ route ] . def ; return d [ k ] != null ? d [ k ] : QK [ k ] . d != null ? QK [ k ] . d : null ; }
var stTmp = null , incTmp = '' ;
var stTmp = null , incTmp = '' ;
function renderQ ( ) {
function renderQ ( ) {
var list = flow ( ) , q = list [ cur ] , R = ROUTES [ route ] , v = val ( q . k ) , last = cur === list . length - 1 ;
var list = flow ( ) , q = list [ cur ] , R = ROUTES [ route ] , v = val ( q . k ) , last = cur === list . length - 1 ;
@@ -809,14 +813,15 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
markInc ( ) ;
markInc ( ) ;
$ ( '#qtip' ) . textContent = '' ;
$ ( '#qtip' ) . textContent = '' ;
} else {
} else {
opts . className = 'opts' + ( q . two ? ' two' : '' ) ;
opts . className = 'opts' ;
var rd = ROUTES [ route ] . def [ q . k ] , dTag = rd != null ? '路线默认' : '默认' , dv = rd != null ? rd : q . d ;
opts . innerHTML = q . o . map ( function ( o , i ) {
opts . innerHTML = q . o . map ( function ( o , i ) {
var isDef = ROUTES [ route ] . def [ q . k ] === i ;
var isDef = dv === i ;
return '<button class="opt' + ( v === i ? ' on' : '' ) + '" data-v="' + i + '"><span class="oi"><svg class="ic"><use href="#o-' + o [ 2 ] + '" xlink:href="#o-' + o [ 2 ] + '"/></svg></span>' +
return '<button class="opt' + ( v === i ? ' on' : '' ) + '" data-v="' + i + '"><span class="oi"><svg class="ic"><use href="#o-' + o [ 2 ] + '" xlink:href="#o-' + o [ 2 ] + '"/></svg></span>' +
'<span class="ox"><b>' + o [ 0 ] + ( isDef ? '<em>路线默认 </em>' : '' ) + '</b><small>' + o [ 1 ] + '</small></span><span class="rd"></span></button>' ;
'<span class="ox"><b>' + o [ 0 ] + ( isDef ? '<em>' + dTag + ' </em>' : '' ) + '</b><small>' + o [ 1 ] + '</small></span><span class="rd"></span></button>' ;
} ) . join ( '' ) ;
} ) . join ( '' ) ;
keep . classList . toggle ( 'on' , v != null ) ;
keep . classList . toggle ( 'on' , v != null ) ;
$ ( '#keepT' ) . textContent = last ? '就这样,出账单' : ( A [ q . k ] == null && ROUTES [ route ] . def [ q . k ] != null ? '按路线默认,下一题' : '就这样,下一题' ) ;
$ ( '#keepT' ) . textContent = last ? '就这样,出账单' : ( A [ q . k ] == null && dv != null ? ( rd != null ? '按路线默认,下一题' : '按默认,下一题' ) : '就这样,下一题' ) ;
$ ( '#qtip' ) . textContent = '选完自动下一题' ;
$ ( '#qtip' ) . textContent = '选完自动下一题' ;
}
}
$ ( '#prevT' ) . textContent = cur > 0 ? '上一题' : '换路线' ;
$ ( '#prevT' ) . textContent = cur > 0 ? '上一题' : '换路线' ;
@@ -898,7 +903,7 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
var R = ROUTES [ route ] , st = sel ( ) , b = calc ( route , A , st ) , s = b . s , isAll = st . length === ALL . length ;
var R = ROUTES [ route ] , st = sel ( ) , b = calc ( route , A , st ) , s = b . s , isAll = st . length === ALL . length ;
var full = isAll ? b : calc ( route , A , ALL ) ;
var full = isAll ? b : calc ( route , A , ALL ) ;
bill = b ; bill . full = full ; bill . range = rangeName ( st ) ; bill . isAll = isAll ;
bill = b ; bill . full = full ; bill . range = rangeName ( st ) ; bill . isAll = isAll ;
var sexW = A . sex === 1 ? '准爸爸' : '准妈妈' , inc = incomeOf ( b ) ;
var inc = incomeOf ( b ) ;
$ ( '#rRoute' ) . textContent = R . who . replace ( '我是' , '' ) + ' · ' + R . how ;
$ ( '#rRoute' ) . textContent = R . who . replace ( '我是' , '' ) + ' · ' + R . how ;
$ ( '#rMeta' ) . textContent = CITY _S [ s . city ] + ( has ( st , [ 0 , 1 , 2 , 3 , 4 ] ) ? ' · ' + ( s . kid ? '二胎' : '头胎' ) : '' ) ;
$ ( '#rMeta' ) . textContent = CITY _S [ s . city ] + ( has ( st , [ 0 , 1 , 2 , 3 , 4 ] ) ? ' · ' + ( s . kid ? '二胎' : '头胎' ) : '' ) ;
$ ( '#rTitle' ) . innerHTML = isAll ? '养到 18 岁,大约 <em>' + w ( b . m ) + ' 万</em>' : esc ( bill . range ) + ',合计约 <em>' + w ( b . m ) + ' 万</em>' ;
$ ( '#rTitle' ) . innerHTML = isAll ? '养到 18 岁,大约 <em>' + w ( b . m ) + ' 万</em>' : esc ( bill . range ) + ',合计约 <em>' + w ( b . m ) + ' 万</em>' ;
@@ -949,15 +954,6 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
'<div class="rc-f"><b>谢谢惠顾</b>宝宝一经签收,不退不换<br>账单按行情中间值估算,仅供参考' + barcode ( + billNo . slice ( - 5 ) || 7 ) + '<div class="rc-no mono">' + billNo + '</div></div>' ;
'<div class="rc-f"><b>谢谢惠顾</b>宝宝一经签收,不退不换<br>账单按行情中间值估算,仅供参考' + barcode ( + billNo . slice ( - 5 ) || 7 ) + '<div class="rc-no mono">' + billNo + '</div></div>' ;
$ ( '#paper' ) . innerHTML = h ;
$ ( '#paper' ) . innerHTML = h ;
// 情感收尾
$ ( '#momH' ) . textContent = A . sex === 1 ? '你就要做爸爸了。' : '你就要做妈妈了。' ;
var p = isAll ? '你的妈妈在养你长大的路上,也花了这么多钱。放在今天,差不多也是这样一张 <em>' + w ( b . m ) + ' 万</em>的账单;'
: '光是' + esc ( bill . range ) + ',就要 <em>' + w ( b . m ) + ' 万</em>。你的妈妈把你从怀孕一路养到 18 岁,放在今天,差不多是一张 <em>' + w ( full . m ) + ' 万</em>的账单;' ;
var fi = incomeOf ( full ) ;
if ( fi ) p += '相当于你家现在 <em>' + fi . txt + '</em>的收入;' ;
p += '还有数不清的时间和心思,<b>没有一项写在账单上</b>。' ;
$ ( '#momP' ) . innerHTML = p ;
renderMsg ( ) ;
renderTools ( ) ;
renderTools ( ) ;
[ ] . forEach . call ( document . querySelectorAll ( '#sRes .fu' ) , function ( el ) { el . classList . remove ( 'in' ) ; } ) ;
[ ] . forEach . call ( document . querySelectorAll ( '#sRes .fu' ) , function ( el ) { el . classList . remove ( 'in' ) ; } ) ;
@@ -990,139 +986,25 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
} , dur + 60 ) ;
} , dur + 60 ) ;
}
}
/* ================= 给妈妈的话 ================= */
function msgs ( ) {
var who = A . sex === 1 ? '爸爸' : '妈妈' ;
return [
'妈,我今天算了算养一个孩子要花多少钱,才知道你当年有多不容易。辛苦了。' ,
'妈,我也快当' + who + '了。以前没好好说过,这些年辛苦你了,谢谢你把我养这么大。' ,
'妈,钱能算出来,你给我的时间和心思算不出来。辛苦了,周末回家吃饭。'
] ;
}
function renderMsg ( ) {
var L = msgs ( ) ;
msgI = msgI % L . length ;
$ ( '#msgQ' ) . textContent = L [ msgI ] ;
$ ( '#msgDt' ) . innerHTML = L . map ( function ( x , i ) { return '<i class="' + ( i === msgI ? 'on' : '' ) + '"></i>' ; } ) . join ( '' ) ;
}
$ ( '#msgSw' ) . addEventListener ( 'click' , function ( ) { msgI ++ ; renderMsg ( ) ; save ( ) ; } ) ;
var tt ;
var tt ;
function toast ( msg ) {
function toast ( msg ) {
var el = $ ( '#toast' ) ; el . textContent = msg ; el . classList . add ( 'on' ) ;
var el = $ ( '#toast' ) ; el . textContent = msg ; el . classList . add ( 'on' ) ;
clearTimeout ( tt ) ; tt = setTimeout ( function ( ) { el . classList . remove ( 'on' ) ; } , 2400 ) ;
clearTimeout ( tt ) ; tt = setTimeout ( function ( ) { el . classList . remove ( 'on' ) ; } , 2400 ) ;
}
}
function copy ( text ) {
function legacy ( ) { return new Promise ( function ( ok , no ) {
var ta = document . createElement ( 'textarea' ) ;
ta . value = text ; ta . setAttribute ( 'readonly' , '' ) ; ta . style . cssText = 'position:fixed;top:-999px;opacity:0' ;
document . body . appendChild ( ta ) ; ta . select ( ) ;
var r = false ; try { r = document . execCommand ( 'copy' ) ; } catch ( e ) { }
document . body . removeChild ( ta ) ;
r ? ok ( ) : no ( ) ;
} ) ; }
if ( navigator . clipboard && window . isSecureContext ) return navigator . clipboard . writeText ( text ) . catch ( legacy ) ;
return legacy ( ) ;
}
$ ( '#copyBtn' ) . addEventListener ( 'click' , function ( ) {
copy ( msgs ( ) [ msgI ] ) . then ( function ( ) { toast ( '已复制,去微信发给妈妈吧' ) ; } , function ( ) { toast ( '复制没成功,点「生成卡片」发图给她也很好' ) ; } ) ;
} ) ;
/* ================= 生成卡片: canvas → <img> 长按保存 ================= */
/* ================= canvas 小工具 ================= */
var FONT = '-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif' ;
var FONT = '-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif' ;
var MONO = '"SF Mono",Menlo,Consolas,"Roboto Mono","Courier New",monospace' ;
var MONO = '"SF Mono",Menlo,Consolas,"Roboto Mono","Courier New",monospace' ;
function rr ( c , x , y , w2 , h2 , r ) {
function rr ( c , x , y , w2 , h2 , r ) {
c . beginPath ( ) ; c . moveTo ( x + r , y ) ; c . arcTo ( x + w2 , y , x + w2 , y + h2 , r ) ; c . arcTo ( x + w2 , y + h2 , x , y + h2 , r ) ;
c . beginPath ( ) ; c . moveTo ( x + r , y ) ; c . arcTo ( x + w2 , y , x + w2 , y + h2 , r ) ; c . arcTo ( x + w2 , y + h2 , x , y + h2 , r ) ;
c . arcTo ( x , y + h2 , x , y , r ) ; c . arcTo ( x , y , x + w2 , y , r ) ; c . closePath ( ) ;
c . arcTo ( x , y + h2 , x , y , r ) ; c . arcTo ( x , y , x + w2 , y , r ) ; c . closePath ( ) ;
}
}
function wrap ( c , text , maxW ) {
var lines = [ ] , line = '' ;
text . split ( '' ) . forEach ( function ( ch ) {
if ( c . measureText ( line + ch ) . width > maxW && line ) { lines . push ( line ) ; line = ch ; } else line += ch ;
} ) ;
if ( line ) lines . push ( line ) ;
for ( var i = 1 ; i < lines . length ; i ++ ) if ( /^[,。、;:!?」]/ . test ( lines [ i ] ) ) { lines [ i - 1 ] += lines [ i ] [ 0 ] ; lines [ i ] = lines [ i ] . slice ( 1 ) ; }
return lines . filter ( function ( l ) { return l ; } ) ;
}
function fit ( c , text , maxW , size , weight , fam ) { // 字太长就缩小
do { c . font = weight + ' ' + size + 'px ' + fam ; size -= 2 ; } while ( c . measureText ( text ) . width > maxW && size > 16 ) ;
}
function drawCard ( ) {
var b = bill , R = ROUTES [ route ] , W = 750 , H = 1240 , inc = incomeOf ( b . full ) ;
var cv = document . createElement ( 'canvas' ) ; cv . width = W ; cv . height = H ;
var c = cv . getContext ( '2d' ) ;
var g = c . createLinearGradient ( 0 , 0 , 0 , H ) ;
g . addColorStop ( 0 , '#FFF3E6' ) ; g . addColorStop ( . 5 , '#FFFBF6' ) ; g . addColorStop ( 1 , '#EAF7F0' ) ;
c . fillStyle = g ; c . fillRect ( 0 , 0 , W , H ) ;
c . fillStyle = 'rgba(255,255,255,.6)' ; c . beginPath ( ) ; c . arc ( 660 , 70 , 200 , 0 , 7 ) ; c . fill ( ) ;
c . fillStyle = 'rgba(24,160,88,.06)' ; c . beginPath ( ) ; c . arc ( 40 , 1120 , 170 , 0 , 7 ) ; c . fill ( ) ;
c . textAlign = 'center' ; c . textBaseline = 'alphabetic' ;
c . font = '700 24px ' + FONT ;
var lb = '兜爸心选 · 养娃账单' , lw = c . measureText ( lb ) . width + 48 ;
c . fillStyle = '#fff' ; rr ( c , ( W - lw ) / 2 , 54 , lw , 48 , 24 ) ; c . fill ( ) ;
c . fillStyle = '#18A058' ; c . fillText ( lb , W / 2 , 86 ) ;
c . fillStyle = '#1F2329' ; c . font = '800 54px ' + FONT ;
c . fillText ( A . sex === 1 ? '你就要做爸爸了。' : '你就要做妈妈了。' , W / 2 , 190 ) ;
c . fillStyle = '#86909C' ; c . font = '400 25px ' + FONT ;
c . fillText ( R . who + ' · ' + R . how + ' · ' + CITY _S [ b . s . city ] , W / 2 , 238 ) ;
/* 小票:始终画「怀孕到 18 岁」的全程合计,和下面「你的妈妈也付过这样一张账单」对上 */
var f = b . full , px = 110 , py = 286 , pw = W - 220 , ph = inc ? 440 : 400 ;
c . save ( ) ; c . shadowColor = 'rgba(120,80,40,.14)' ; c . shadowBlur = 30 ; c . shadowOffsetY = 10 ;
c . fillStyle = '#fff' ; c . beginPath ( ) ; c . moveTo ( px , py ) ; c . lineTo ( px + pw , py ) ; c . lineTo ( px + pw , py + ph ) ;
var n = Math . floor ( pw / 20 ) ;
for ( var i = 0 ; i < n ; i ++ ) { var x0 = px + pw - i * ( pw / n ) ; c . lineTo ( x0 - pw / n / 2 , py + ph + 12 ) ; c . lineTo ( x0 - pw / n , py + ph ) ; }
c . closePath ( ) ; c . fill ( ) ; c . restore ( ) ;
c . fillStyle = '#86909C' ; c . font = '500 23px ' + FONT ; c . fillText ( '养一个孩子 · 怀孕到 18 岁 · 合计' , W / 2 , py + 62 ) ;
c . fillStyle = '#18A058' ; fit ( c , '¥' + money ( f . m ) , pw - 40 , 66 , '800' , MONO ) ; c . fillText ( '¥' + money ( f . m ) , W / 2 , py + 142 ) ;
c . fillStyle = '#4E5969' ; c . font = '400 23px ' + FONT ; c . fillText ( '约 ' + w ( f . m ) + ' 万 · 区间 ' + wr ( f . lo , f . hi ) , W / 2 , py + 186 ) ;
c . strokeStyle = '#C9CED4' ; c . lineWidth = 2 ; c . setLineDash ( [ 8 , 7 ] ) ;
c . beginPath ( ) ; c . moveTo ( px + 30 , py + 220 ) ; c . lineTo ( px + pw - 30 , py + 220 ) ; c . stroke ( ) ;
var cols = [ [ ' 1 岁' , f . n1 ] , [ ' 2 岁' , f . n2 ] , [ ' 3 岁' , f . n3 ] ] , cw = ( pw - 60 ) / 3 ;
cols . forEach ( function ( x , k ) {
var cx = px + 30 + cw * k + cw / 2 ;
c . fillStyle = '#86909C' ; c . font = '400 21px ' + FONT ; c . fillText ( '养到' + x [ 0 ] , cx , py + 264 ) ;
c . fillStyle = '#1F2329' ; c . font = '800 32px ' + MONO ; c . fillText ( w ( x [ 1 ] ) + '万' , cx , py + 306 ) ;
} ) ;
c . beginPath ( ) ; c . moveTo ( px + 30 , py + 336 ) ; c . lineTo ( px + pw - 30 , py + 336 ) ; c . stroke ( ) ; c . setLineDash ( [ ] ) ;
var yy = py + 376 ;
if ( inc ) {
c . textAlign = 'left' ; c . fillStyle = '#4E5969' ; c . font = '400 22px ' + FONT ; c . fillText ( '≈ 你家现在的收入' , px + 30 , yy ) ;
c . textAlign = 'right' ; c . fillStyle = '#18A058' ; c . font = '800 24px ' + FONT ; c . fillText ( inc . txt , px + pw - 30 , yy ) ;
yy += 42 ;
}
c . textAlign = 'left' ; c . fillStyle = '#B4733A' ; c . font = '700 23px ' + FONT ; c . fillText ( '时间、心思和拥抱' , px + 30 , yy ) ;
c . textAlign = 'right' ; c . fillText ( '无法计价' , px + pw - 30 , yy ) ;
c . textAlign = 'center' ;
var oy = inc ? 40 : 0 ;
c . fillStyle = '#5B5249' ; c . font = '400 28px ' + FONT ;
c . fillText ( '你的妈妈养你长大,' , W / 2 , 778 + oy ) ;
c . fillText ( '也付过这样一张账单。' , W / 2 , 822 + oy ) ;
c . font = '800 60px ' + FONT ;
var say = '妈,辛苦了。' , sw = c . measureText ( say ) . width ;
c . fillStyle = 'rgba(244,190,130,.45)' ; c . fillRect ( ( W - sw ) / 2 - 6 , 896 + oy , sw + 12 , 24 ) ;
c . fillStyle = '#1F2329' ; c . fillText ( say , W / 2 , 914 + oy ) ;
c . fillStyle = '#4E5969' ; c . font = '400 26px ' + FONT ;
var ls = wrap ( c , '「' + msgs ( ) [ msgI ] + '」' , W - 170 ) ;
ls . slice ( 0 , 3 ) . forEach ( function ( l , k ) { c . fillText ( l , W / 2 , 986 + oy + k * 40 ) ; } ) ;
c . strokeStyle = 'rgba(24,160,88,.25)' ; c . lineWidth = 2 ;
c . beginPath ( ) ; c . moveTo ( W / 2 - 150 , 1148 ) ; c . lineTo ( W / 2 + 150 , 1148 ) ; c . stroke ( ) ;
c . fillStyle = '#18A058' ; c . font = '700 25px ' + FONT ; c . fillText ( '兜爸心选' , W / 2 , 1188 ) ;
c . fillStyle = '#86909C' ; c . font = '400 20px ' + FONT ; c . fillText ( '孕期专题 · 生娃计算器 · 估算仅供参考' , W / 2 , 1218 ) ;
return cv . toDataURL ( 'image/png' ) ;
}
var isWx = /MicroMessenger/i . test ( navigator . userAgent ) ;
var isWx = /MicroMessenger/i . test ( navigator . userAgent ) ;
$ ( '#cardBtn' ) . addEventListener ( 'click' , function ( ) {
if ( ! bill ) return ;
try {
openMask ( drawCard ( ) , '给妈妈的卡片' , '给妈妈的卡片.png' , '长按图片,保存或发给妈妈' , false ) ;
} catch ( e ) { toast ( '生成失败,截个图保存也可以' ) ; }
} ) ;
/* ================= 保存账单图片:把整张小票原样画成长图(宽 750, 高按内容算) =================
/* ================= 保存账单图片:把整张小票原样画成长图(宽 750, 高按内容算) =================
iOS 单张 canvas 建议 ≤ 约 16000px 高 / 1600 万像素:先按标准行高量一遍,超了就压行高(最低 32) , 仍超就整体缩小。 */
iOS 单张 canvas 建议 ≤ 约 16000px 高 / 1600 万像素:先按标准行高量一遍,超了就压行高(最低 32) , 仍超就整体缩小。 */
var BILL _MAX _H = 15800 ;
var BILL _MAX _H = 15800 ;
function drawBill ( ) {
function drawBill ( ) {
var b = bill , R = ROUTES [ route ] , s = b . s , st = sel ( ) , inc = incomeOf ( b ) ;
var b = bill , R = ROUTES [ route ] , s = b . s , st = sel ( ) , inc = incomeOf ( b ) ;
var sexW = A . sex === 1 ? '准爸爸' : '准妈妈' ;
var nodes = [ ] ;
var nodes = [ ] ;
if ( b . n1 != null ) nodes . push ( [ '养到 1 岁累计' , b . n1 ] ) ;
if ( b . n1 != null ) nodes . push ( [ '养到 1 岁累计' , b . n1 ] ) ;
if ( b . n2 != null ) { nodes . push ( [ '养到 2 岁累计' , b . n2 ] ) ; nodes . push ( [ '养到 3 岁累计' , b . n3 ] ) ; }
if ( b . n2 != null ) { nodes . push ( [ '养到 2 岁累计' , b . n2 ] ) ; nodes . push ( [ '养到 3 岁累计' , b . n3 ] ) ; }
@@ -1358,7 +1240,7 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
/* ================= 存取( v5; 兼容读取 v4: 路线 + 6 题答案,阶段按全部、收入为空) ================= */
/* ================= 存取( v5; 兼容读取 v4: 路线 + 6 题答案,阶段按全部、收入为空) ================= */
function save ( ) {
function save ( ) {
try { localStorage . setItem ( KEY , JSON . stringify ( { route : route , a : A , done : hasBill , no : billNo , at : billAt , msg : msgI } ) ) ; } catch ( e ) { }
try { localStorage . setItem ( KEY , JSON . stringify ( { route : route , a : A , done : hasBill , no : billNo , at : billAt } ) ) ; } catch ( e ) { }
}
}
function load ( ) {
function load ( ) {
try {
try {
@@ -1369,11 +1251,10 @@ h1 .mk{background:linear-gradient(transparent 64%,rgba(24,160,88,.24) 0)}
QS . forEach ( function ( q ) { var v = a [ q . k ] ; if ( q . o && typeof v === 'number' && v >= 0 && v < q . o . length ) A [ q . k ] = v ; } ) ;
QS . forEach ( function ( q ) { var v = a [ q . k ] ; if ( q . o && typeof v === 'number' && v >= 0 && v < q . o . length ) A [ q . k ] = v ; } ) ;
if ( Array . isArray ( a . st ) ) { var st = a . st . filter ( function ( i ) { return ALL . indexOf ( i ) >= 0 ; } ) ; if ( st . length ) A . st = st . sort ( function ( x , y ) { return x - y ; } ) ; }
if ( Array . isArray ( a . st ) ) { var st = a . st . filter ( function ( i ) { return ALL . indexOf ( i ) >= 0 ; } ) ; if ( st . length ) A . st = st . sort ( function ( x , y ) { return x - y ; } ) ; }
if ( typeof a . inc === 'number' && a . inc >= 0 ) A . inc = a . inc ;
if ( typeof a . inc === 'number' && a . inc >= 0 ) A . inc = a . inc ;
msgI = + o . msg || 0 ;
billNo = o . no || '' ; billAt = o . at || '' ;
billNo = o . no || '' ; billAt = o . at || '' ;
if ( ! A . st ) A . st = ALL . slice ( ) ;
if ( ! A . st ) A . st = ALL . slice ( ) ;
var need = QS . filter ( function ( q ) { return q . o && ( ! q . if || q . if ( A . st ) ) ; } ) ;
var need = QS . filter ( function ( q ) { return q . o && ( ! q . if || q . if ( A . st ) ) ; } ) ;
var all = need . every ( function ( q ) { return A [ q . k ] != null ; } ) ;
var all = need . every ( function ( q ) { return val ( q . k ) != null ; } ) ; // 新加的题没答过就按默认(旧账单照样能看)
if ( all && ! billNo ) newBill ( ) ;
if ( all && ! billNo ) newBill ( ) ;
return ! ! o . done && all ;
return ! ! o . done && all ;
} catch ( e ) { return false ; }
} catch ( e ) { return false ; }