Files
jizhi/design/ux-prototype.html
2026-07-24 23:11:20 +08:00

1016 lines
69 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>喵记账 · 可交互 UX 原型</title>
<style>
:root{
--primary:#00B386;--primary-deep:#009973;--primary-bg:#E6F7F1;
--ai:#5B6BF5;--ai-bg:#EEF0FE;
--red:#F0642D;--orange:#F5A623;
--text:#191F26;--text2:#5E6772;--text3:#9AA3AD;
--bg:#F6F7F9;--line:#EEF0F3;
}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
body{
font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;
background:#F0F2F5;color:var(--text);min-height:100vh;
display:flex;flex-direction:column;align-items:center;justify-content:center;padding:30px 16px;gap:18px;
}
svg{display:block;}
.ic{stroke:currentColor;fill:none;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;}
.hint{color:#9AA3AD;font-size:13px;text-align:center;line-height:1.8;}
.hint b{color:#5E6772;}
/* ===== 手机壳 ===== */
.phone{
width:375px;height:790px;background:var(--bg);border-radius:44px;
box-shadow:0 0 0 10px #1c1f24,0 0 0 12px #3c4149,0 24px 60px rgba(20,30,40,.35);
overflow:hidden;position:relative;
}
.statusbar{
height:42px;display:flex;justify-content:space-between;align-items:center;
padding:0 26px;font-size:13px;font-weight:600;position:absolute;top:0;left:0;right:0;z-index:50;pointer-events:none;
}
.statusbar .notch{position:absolute;left:50%;top:0;transform:translateX(-50%);width:148px;height:25px;background:#1c1f24;border-radius:0 0 15px 15px;}
/* ===== 路由屏 ===== */
.scr{
position:absolute;inset:0;background:var(--bg);display:flex;flex-direction:column;
padding-top:42px;opacity:0;pointer-events:none;transform:translateX(24px);
transition:opacity .28s ease,transform .28s ease;z-index:1;
}
.scr.on{opacity:1;pointer-events:auto;transform:none;z-index:2;}
.scr.back-out{transform:translateX(-24px);}
/* tab 切换:屏幕瞬切,仅内容区动画,tabbar 保持静止 */
.scr.snap{transition:none;transform:none;}
@keyframes bodyIn{from{opacity:0;transform:translateX(16px);}to{opacity:1;transform:none;}}
.scr.body-anim > *:not(.tabbar){animation:bodyIn .25s ease;}
.navbar{height:46px;flex:none;display:flex;align-items:center;justify-content:center;font-size:16px;font-weight:600;position:relative;}
.navbar .nav-l{position:absolute;left:10px;padding:6px;cursor:pointer;color:var(--text);display:flex;}
.navbar .nav-r{position:absolute;right:14px;font-size:13px;color:var(--primary);font-weight:500;cursor:pointer;}
.body{flex:1;overflow-y:auto;overflow-x:hidden;padding:0 16px;scrollbar-width:none;}
.body::-webkit-scrollbar{display:none;}
.card{background:#fff;border-radius:14px;padding:16px;border:.5px solid var(--line);}
.btn{border-radius:14px;padding:14px;text-align:center;font-size:15px;font-weight:600;cursor:pointer;transition:transform .12s;}
.btn:active{transform:scale(.97);}
.btn.primary{background:var(--primary);color:#fff;box-shadow:0 6px 16px rgba(0,179,134,.25);}
.btn.ai{background:var(--ai);color:#fff;box-shadow:0 6px 16px rgba(91,107,245,.28);}
.btn.ghost{background:#fff;border:1px solid var(--line);}
/* ===== tabbar ===== */
.tabbar{flex:none;height:58px;background:#fff;border-top:.5px solid var(--line);display:flex;align-items:center;justify-content:space-around;padding-bottom:6px;}
.tab{display:flex;flex-direction:column;align-items:center;gap:3px;font-size:10px;color:var(--text3);width:56px;cursor:pointer;}
.tab.active{color:var(--primary);font-weight:600;}
.tab-fab{
width:46px;height:46px;border-radius:16px;margin-top:-22px;background:var(--primary);
display:flex;align-items:center;justify-content:center;color:#fff;cursor:pointer;
box-shadow:0 6px 14px rgba(0,179,134,.32);border:3px solid var(--bg);transition:transform .12s;
}
.tab-fab:active{transform:scale(.92);}
.homebar{position:absolute;bottom:6px;left:50%;transform:translateX(-50%);width:128px;height:5px;border-radius:3px;background:#1c1f24;opacity:.85;z-index:60;pointer-events:none;}
.ai-face{border-radius:50%;background:var(--ai-bg);display:flex;align-items:center;justify-content:center;color:var(--ai);flex:none;}
.ai-face.solid{background:var(--ai);color:#fff;}
/* ===== 引导 ===== */
.onb{flex:1;display:flex;flex-direction:column;padding:10px 26px 24px;overflow-y:auto;scrollbar-width:none;}
.splash-logo{width:88px;height:88px;border-radius:26px;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 14px 30px rgba(0,179,134,.3);margin:0 auto;}
.app-name{font-size:25px;font-weight:800;text-align:center;margin-top:16px;letter-spacing:1px;}
.app-slogan{font-size:12.5px;color:var(--text2);text-align:center;margin-top:7px;}
.onb-title{font-size:20px;font-weight:800;margin-top:8px;}
.onb-sub{font-size:12px;color:var(--text2);margin-top:5px;line-height:1.6;}
.step-dots{display:flex;gap:6px;padding:12px 0 4px;}
.step-dots i{width:18px;height:5px;border-radius:3px;background:#E3E6EA;transition:.25s;}
.step-dots i.on{background:var(--primary);width:28px;}
.mode-big{background:#fff;border:2px solid var(--line);border-radius:18px;padding:15px;position:relative;cursor:pointer;transition:border-color .2s;}
.mode-big.on{border-color:var(--primary);}
.mode-big .pick{position:absolute;top:13px;right:13px;width:20px;height:20px;border-radius:50%;border:1.5px solid #C9CEDA;display:flex;align-items:center;justify-content:center;color:#fff;transition:.2s;}
.mode-big.on .pick{background:var(--primary);border-color:var(--primary);}
.mode-big .mt{font-size:14.5px;font-weight:700;display:flex;align-items:center;gap:8px;}
.mode-big .md{font-size:10.5px;color:var(--text2);margin-top:4px;line-height:1.6;}
.mini-prev{margin-top:10px;border-radius:12px;padding:9px;display:flex;gap:7px;background:var(--bg);pointer-events:none;}
.mini-prev .blk{border-radius:7px;background:#fff;border:.5px solid var(--line);}
.mini-prev.chatty{flex-direction:column;background:linear-gradient(135deg,#EEF0FE,#E6F7F1);}
.mini-prev .lbub{align-self:flex-start;background:#fff;border-radius:2px 9px 9px 9px;padding:5px 9px;font-size:9px;color:var(--text2);}
.mini-prev .rbub{align-self:flex-end;background:var(--ai);color:#fff;border-radius:9px 2px 9px 9px;padding:5px 9px;font-size:9px;}
.avatar-pick{display:flex;justify-content:center;gap:22px;align-items:center;padding:14px 0 8px;height:96px;}
.avatar-pick .ap{display:flex;flex-direction:column;align-items:center;gap:6px;cursor:pointer;font-size:10px;color:var(--text3);}
.avatar-pick .ap .ai-face{
width:56px;height:56px;color:var(--text3);
transition:transform .22s cubic-bezier(.34,1.4,.64,1),background .22s,color .22s,box-shadow .22s;
transform:scale(.9);
}
.avatar-pick .ap.on{color:var(--ai);font-weight:600;}
.avatar-pick .ap.on .ai-face{background:var(--ai);color:#fff;box-shadow:0 10px 22px rgba(91,107,245,.3);transform:scale(1.18);}
.p-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px;}
.p-card{background:#fff;border-radius:14px;padding:12px;border:1.5px solid var(--line);position:relative;cursor:pointer;transition:border-color .2s;}
.p-card.on{border-color:var(--ai);background:#FBFBFF;}
.p-card .n{font-size:13px;font-weight:700;margin-top:8px;}
.p-card .d{font-size:10px;color:var(--text2);margin-top:3px;line-height:1.5;}
/* ===== 首页 ===== */
.home-top{display:flex;justify-content:space-between;align-items:center;padding:8px 0 14px;}
.home-top .book{display:flex;align-items:center;gap:6px;font-size:16px;font-weight:700;cursor:pointer;}
.hero{background:linear-gradient(135deg,var(--primary),#00C99A);border-radius:18px;padding:18px 20px;color:#fff;position:relative;overflow:hidden;}
.hero::after{content:"";position:absolute;right:-30px;top:-40px;width:150px;height:150px;border-radius:50%;background:rgba(255,255,255,.08);}
.hero .lb{font-size:11.5px;opacity:.85;}
.hero .num{font-size:30px;font-weight:700;margin:5px 0 14px;font-variant-numeric:tabular-nums;}
.hero .io{display:flex;font-size:11px;opacity:.95;position:relative;z-index:1;}
.hero .io>div{flex:1;}
.hero .io b{display:block;font-size:14px;margin-top:2px;font-variant-numeric:tabular-nums;}
.ai-entry{margin-top:12px;background:#fff;border:.5px solid var(--line);border-radius:14px;padding:11px 13px;display:flex;align-items:center;gap:11px;cursor:pointer;}
.ai-entry .t1{font-size:13px;font-weight:600;}
.ai-entry .t2{font-size:11px;color:var(--text2);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:190px;}
.ai-entry .go{margin-left:auto;color:var(--ai);font-size:11.5px;padding:6px 12px;border-radius:16px;font-weight:600;background:var(--ai-bg);flex:none;}
.sec-head{display:flex;justify-content:space-between;margin:15px 2px 9px;font-size:13.5px;font-weight:700;}
.day-group{background:#fff;border-radius:14px;padding:2px 14px;border:.5px solid var(--line);margin-bottom:10px;}
.day-head{display:flex;justify-content:space-between;font-size:10.5px;color:var(--text3);padding:9px 2px 6px;border-bottom:.5px solid var(--line);}
.titem{display:flex;align-items:center;gap:11px;padding:10px 2px;cursor:pointer;animation:pop .35s ease;}
@keyframes pop{from{opacity:0;transform:translateY(-6px);}to{opacity:1;}}
.titem+.titem{border-top:.5px solid var(--line);}
.cat-ic{width:36px;height:36px;border-radius:11px;display:flex;align-items:center;justify-content:center;flex:none;}
.titem .n{font-size:13px;font-weight:500;}
.titem .d{font-size:10px;color:var(--text3);margin-top:2px;display:flex;gap:5px;align-items:center;}
.ai-badge{font-size:9px;color:var(--ai);background:var(--ai-bg);padding:1.5px 6px;border-radius:6px;font-weight:600;}
.titem .amt{margin-left:auto;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;}
.amt.in{color:var(--primary);}
/* ===== 记一笔 ===== */
.seg{display:flex;background:#EBEDF0;border-radius:9px;padding:3px;margin:6px auto;width:216px;flex:none;}
.seg span{flex:1;text-align:center;font-size:13px;padding:6px 0;border-radius:7px;color:var(--text2);cursor:pointer;}
.seg span.on{background:#fff;color:var(--text);font-weight:600;box-shadow:0 1px 3px rgba(25,31,38,.08);}
.cat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:2px 0;padding:4px 2px;}
.cat{display:flex;flex-direction:column;align-items:center;gap:5px;padding:8px 0;font-size:10.5px;color:var(--text2);cursor:pointer;}
.cat .ci{width:42px;height:42px;border-radius:13px;background:#fff;border:.5px solid var(--line);display:flex;align-items:center;justify-content:center;color:var(--text2);transition:.15s;}
.cat.on{color:var(--primary);font-weight:600;}
.cat.on .ci{background:var(--primary);border-color:var(--primary);color:#fff;box-shadow:0 4px 10px rgba(0,179,134,.28);}
.amount-panel{background:#fff;border-top:.5px solid var(--line);padding:10px 16px 14px;flex:none;}
.amount-line{display:flex;align-items:center;justify-content:space-between;padding-bottom:8px;border-bottom:.5px solid var(--line);}
.amount-line .cm{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;}
.amount-line .num{font-size:28px;font-weight:700;font-variant-numeric:tabular-nums;}
.amount-line .num i{font-style:normal;display:inline-block;width:2px;height:24px;background:var(--primary);margin-left:2px;animation:blink 1s infinite;vertical-align:-2px;}
@keyframes blink{50%{opacity:0;}}
.keypad{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;padding-top:10px;}
.key{height:48px;background:#F4F5F7;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:600;cursor:pointer;transition:background .1s;}
.key:active{background:#E8EAEE;}
.key.fn{font-size:13px;color:var(--text2);}
.key.ok{grid-row:span 2;height:auto;background:var(--primary);color:#fff;font-size:15px;}
/* ===== 聊天 ===== */
.chat-nav{height:50px;flex:none;display:flex;align-items:center;gap:10px;padding:0 12px;background:#fff;border-bottom:.5px solid var(--line);}
.chat-nav .nb{padding:6px;cursor:pointer;display:flex;}
.chat-nav .meta .n{font-size:14px;font-weight:700;display:flex;align-items:center;gap:6px;}
.persona-chip{font-size:9px;background:var(--ai-bg);color:var(--ai);padding:2px 7px;border-radius:8px;font-weight:600;}
.chat-nav .meta .s{font-size:9.5px;color:var(--primary);margin-top:1px;}
.chat-nav .gear{margin-left:auto;color:var(--text2);cursor:pointer;padding:6px;}
.chat-body{flex:1;overflow-y:auto;padding:14px 14px 8px;display:flex;flex-direction:column;gap:11px;scrollbar-width:none;}
.chat-body::-webkit-scrollbar{display:none;}
.time-tag{align-self:center;font-size:10px;color:var(--text3);}
.msg{display:flex;gap:8px;max-width:88%;animation:mIn .3s ease;}
@keyframes mIn{from{opacity:0;transform:translateY(8px);}to{opacity:1;}}
.msg .av{width:32px;height:32px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;}
.msg.me{align-self:flex-end;flex-direction:row-reverse;}
.msg.me .av{background:#E2E6EB;color:var(--text2);}
.bubble{background:#fff;border-radius:3px 15px 15px 15px;padding:9px 13px;font-size:13px;line-height:1.55;border:.5px solid var(--line);}
.msg.me .bubble{background:var(--primary);color:#fff;border:none;border-radius:15px 3px 15px 15px;}
.aimode .msg.me .bubble{background:var(--ai);}
.sticker-card{width:100px;border-radius:14px;background:#fff;border:.5px solid var(--line);display:flex;flex-direction:column;align-items:center;gap:6px;padding:13px 8px 9px;}
.sticker-card .t{font-size:10px;color:var(--text2);font-weight:600;}
.bill-card{width:225px;background:#fff;border-radius:14px;overflow:hidden;border:.5px solid var(--line);}
.bill-card .bc-head{background:var(--ai);color:#fff;padding:7px 12px;font-size:10.5px;display:flex;align-items:center;gap:6px;font-weight:600;}
.bill-card .bc-body{padding:11px 12px;display:flex;align-items:center;gap:10px;}
.bill-card .bc-amt{font-size:18px;font-weight:700;font-variant-numeric:tabular-nums;}
.bill-card .bc-cat{font-size:10.5px;color:var(--text2);margin-top:2px;}
.bill-card .bc-foot{display:flex;border-top:.5px solid var(--line);font-size:11.5px;text-align:center;align-items:center;}
.bill-card .bc-foot .st{flex:1.4;padding:8px 0;color:var(--primary);font-weight:600;}
.bill-card .bc-foot span.op{flex:1;padding:8px 0;color:var(--text2);cursor:pointer;border-left:.5px solid var(--line);}
.bill-card.undone .bc-body,.bill-card.undone .bc-head{opacity:.45;filter:saturate(.3);}
.bill-card.undone .bc-foot{display:none;}
.bill-card .bc-undone-tip{display:none;padding:8px 0;text-align:center;font-size:11px;color:var(--text3);}
.bill-card.undone .bc-undone-tip{display:block;}
.typing-b .bubble{padding:12px 14px;}
.typing{display:flex;gap:4px;}
.typing i{width:6px;height:6px;border-radius:50%;background:#B9BFD9;animation:ty 1.2s infinite;}
.typing i:nth-child(2){animation-delay:.2s;}
.typing i:nth-child(3){animation-delay:.4s;}
@keyframes ty{0%,60%,100%{transform:translateY(0);opacity:.5;}30%{transform:translateY(-4px);opacity:1;}}
.quick-row{display:flex;gap:8px;padding:8px 12px 2px;background:#fff;flex:none;overflow-x:auto;scrollbar-width:none;}
.quick-row::-webkit-scrollbar{display:none;}
.quick{font-size:11px;color:var(--text2);background:#F2F3F5;padding:5px 12px;border-radius:13px;white-space:nowrap;cursor:pointer;flex:none;}
.quick:active{background:var(--ai-bg);color:var(--ai);}
.chat-input{flex:none;background:#fff;padding:8px 12px 10px;display:flex;align-items:center;gap:9px;color:var(--text2);}
.chat-input input{flex:1;background:#F2F3F5;border:none;outline:none;border-radius:18px;padding:10px 14px;font-size:13px;font-family:inherit;color:var(--text);}
.chat-input .cbtn{cursor:pointer;display:flex;padding:2px;}
.send-btn{background:var(--primary);color:#fff;border-radius:50%;width:34px;height:34px;display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none;}
.aimode .send-btn{background:var(--ai);}
.stk-panel{flex:none;background:#fff;border-top:.5px solid var(--line);padding:10px 14px 30px;display:none;}
.stk-panel.open{display:block;}
.stk-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;}
.stk{display:flex;flex-direction:column;align-items:center;gap:4px;font-size:9px;color:var(--text2);cursor:pointer;}
.stk .box{width:58px;height:58px;border-radius:12px;background:var(--bg);display:flex;align-items:center;justify-content:center;transition:.15s;}
.stk:active .box{background:var(--ai-bg);}
/* ===== 全AI模式 ===== */
.aimode{background:linear-gradient(165deg,#EEF0FE 0%,#F6F7F9 40%,#E6F7F1 100%);}
.aimode-head{flex:none;padding:6px 16px 10px;}
.aimode-head .top{display:flex;align-items:center;gap:10px;}
.aimode-head .n{font-size:15px;font-weight:700;display:flex;align-items:center;gap:6px;}
.aimode-head .s{font-size:10px;color:var(--text3);margin-top:1px;}
.aimode-head .sw{margin-left:auto;font-size:10.5px;color:var(--ai);border:1px solid rgba(91,107,245,.35);padding:5px 11px;border-radius:14px;cursor:pointer;background:rgba(255,255,255,.6);}
.mini-dash{margin-top:10px;display:flex;gap:8px;}
.mini-card{flex:1;background:rgba(255,255,255,.75);border:.5px solid rgba(255,255,255,.9);border-radius:12px;padding:8px 11px;}
.mini-card .t{font-size:9px;color:var(--text3);}
.mini-card .v{font-size:13.5px;font-weight:700;margin-top:2px;font-variant-numeric:tabular-nums;}
.aimode .bubble{background:rgba(255,255,255,.88);border:.5px solid rgba(255,255,255,.9);}
.aimode .quick-row,.aimode .chat-input{background:rgba(255,255,255,.8);}
.aimode .chat-input input{background:rgba(242,243,245,.9);}
/* ===== 我的 ===== */
.me-head{padding:12px 4px 16px;display:flex;align-items:center;gap:13px;}
.me-head .av{width:54px;height:54px;border-radius:50%;background:#fff;border:.5px solid var(--line);display:flex;align-items:center;justify-content:center;color:var(--text2);}
.me-head .n{font-size:16px;font-weight:700;}
.me-head .d{font-size:10.5px;color:var(--text3);margin-top:3px;}
.mode-opts{display:flex;gap:10px;}
.mode-opt{flex:1;border:1.5px solid var(--line);border-radius:12px;padding:11px;position:relative;cursor:pointer;transition:.2s;}
.mode-opt.on{border-color:var(--primary);background:#FAFFFD;}
.mode-opt .n{font-size:12px;font-weight:700;margin-top:7px;}
.mode-opt .d{font-size:9px;color:var(--text2);margin-top:3px;line-height:1.5;}
.mode-opt .radio{position:absolute;top:10px;right:10px;width:15px;height:15px;border-radius:50%;border:1.5px solid #C9CEDA;transition:.2s;}
.mode-opt.on .radio{border-color:var(--primary);background:var(--primary);box-shadow:inset 0 0 0 3px #fff;}
.list-group{margin-top:12px;background:#fff;border-radius:14px;overflow:hidden;border:.5px solid var(--line);}
.li-row{display:flex;align-items:center;gap:12px;padding:13px 15px;font-size:13px;cursor:pointer;}
.li-row:active{background:#FAFBFC;}
.li-row+.li-row{border-top:.5px solid var(--line);}
.li-row .lic{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex:none;}
.li-row .val{margin-left:auto;color:var(--text3);font-size:11px;display:flex;align-items:center;gap:4px;}
/* ===== 性格设置 ===== */
.slider-block .lb{display:flex;justify-content:space-between;font-size:12px;color:var(--text2);margin-bottom:8px;}
.slider-block .lb b{color:var(--text);}
.track{height:5px;border-radius:3px;background:#E8EAEF;position:relative;cursor:pointer;}
.track i{position:absolute;left:0;top:0;height:100%;border-radius:3px;background:var(--ai);}
.track .knob{position:absolute;top:50%;transform:translate(-50%,-50%);width:18px;height:18px;background:#fff;border-radius:50%;box-shadow:0 1px 6px rgba(0,0,0,.18);border:2px solid var(--ai);}
/* ===== 统计 ===== */
.donut{width:118px;height:118px;border-radius:50%;flex:none;position:relative;background:conic-gradient(#00B386 0 34%,#5B6BF5 34% 55%,#F5A623 55% 71%,#4DA6FF 71% 84%,#F0642D 84% 93%,#E3E6EA 93% 100%);}
.donut::after{content:"";position:absolute;inset:19px;background:#fff;border-radius:50%;}
.donut .c{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:1;}
.donut .c .t{font-size:9.5px;color:var(--text3);}
.donut .c .v{font-size:15px;font-weight:700;}
.legend{flex:1;display:flex;flex-direction:column;gap:7px;font-size:11px;}
.legend .li{display:flex;align-items:center;gap:7px;color:var(--text2);}
.legend .sw2{width:8px;height:8px;border-radius:2.5px;}
.legend .pct{margin-left:auto;font-weight:600;color:var(--text);}
.ai-insight{margin-top:10px;background:var(--ai-bg);border-radius:14px;padding:13px;font-size:11.5px;color:#4A5160;line-height:1.7;}
.ai-insight .h{display:flex;align-items:center;gap:6px;font-size:12px;font-weight:700;color:var(--ai);margin-bottom:5px;}
/* ===== toast ===== */
.toast{
position:absolute;left:50%;bottom:110px;transform:translateX(-50%) translateY(10px);
background:rgba(25,31,38,.88);color:#fff;font-size:12px;padding:9px 18px;border-radius:20px;
opacity:0;transition:.3s;z-index:99;pointer-events:none;white-space:nowrap;
}
.toast.show{opacity:1;transform:translateX(-50%);}
</style>
</head>
<body>
<svg width="0" height="0" style="position:absolute;">
<defs>
<symbol id="i-cat" viewBox="0 0 24 24"><path class="ic" d="M5.5 9.5 4 4.5l4.2 2.1a8 8 0 0 1 7.6 0L20 4.5l-1.5 5A8 8 0 0 1 20 13c0 4.4-3.6 7.5-8 7.5S4 17.4 4 13c0-1.3.6-2.5 1.5-3.5Z"/><circle cx="9" cy="12.5" r="1" fill="currentColor" stroke="none"/><circle cx="15" cy="12.5" r="1" fill="currentColor" stroke="none"/><path class="ic" d="M10.5 15.8c.9.9 2.1.9 3 0"/></symbol>
<symbol id="i-dog" viewBox="0 0 24 24"><path class="ic" d="M7 6.5C5 7.5 4 9.5 4 12c0 4.4 3.6 7.5 8 7.5s8-3.1 8-7.5c0-2.5-1-4.5-3-5.5"/><path class="ic" d="M7 6.5C6.5 4 7.5 2.5 9.5 3.5L11 5M17 6.5c.5-2.5-.5-4-2.5-3l-1.5 1.5"/><circle cx="9.5" cy="11.5" r="1" fill="currentColor" stroke="none"/><circle cx="14.5" cy="11.5" r="1" fill="currentColor" stroke="none"/><path class="ic" d="M12 14v1.5M12 15.5c-.8.8-1.7.8-2.5.2M12 15.5c.8.8 1.7.8 2.5.2"/></symbol>
<symbol id="i-robot" viewBox="0 0 24 24"><rect class="ic" x="5" y="8" width="14" height="11" rx="3.5"/><path class="ic" d="M12 8V4.5"/><circle class="ic" cx="12" cy="3.8" r="1"/><circle cx="9.5" cy="13" r="1.1" fill="currentColor" stroke="none"/><circle cx="14.5" cy="13" r="1.1" fill="currentColor" stroke="none"/><path class="ic" d="M10 16.2h4M3 12.5v2M21 12.5v2"/></symbol>
<symbol id="i-sparkle" viewBox="0 0 24 24"><path class="ic" d="M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9L12 3Z"/><path class="ic" d="M18.5 15.5l.9 2.1 2.1.9-2.1.9-.9 2.1-.9-2.1-2.1-.9 2.1-.9.9-2.1Z"/></symbol>
<symbol id="i-home" viewBox="0 0 24 24"><path class="ic" d="M4 11.5 12 4l8 7.5M6 10v9h12v-9"/><path class="ic" d="M10 19v-5h4v5"/></symbol>
<symbol id="i-chart" viewBox="0 0 24 24"><path class="ic" d="M4 20h16"/><path class="ic" d="M7 16v-4M12 16V7M17 16v-6"/></symbol>
<symbol id="i-chat" viewBox="0 0 24 24"><path class="ic" d="M20 12a8 8 0 0 1-11.6 7.1L4 20l1-4.1A8 8 0 1 1 20 12Z"/><path class="ic" d="M8.5 12h.01M12 12h.01M15.5 12h.01"/></symbol>
<symbol id="i-user" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="8.5" r="3.5"/><path class="ic" d="M5.5 19.5c1-3.3 3.5-5 6.5-5s5.5 1.7 6.5 5"/></symbol>
<symbol id="i-plus" viewBox="0 0 24 24"><path class="ic" d="M12 5v14M5 12h14"/></symbol>
<symbol id="i-chev-l" viewBox="0 0 24 24"><path class="ic" d="m14 7-5 5 5 5"/></symbol>
<symbol id="i-chev-r" viewBox="0 0 24 24"><path class="ic" d="m10 7 5 5-5 5"/></symbol>
<symbol id="i-chev-d" viewBox="0 0 24 24"><path class="ic" d="m7 10 5 5 5-5"/></symbol>
<symbol id="i-close" viewBox="0 0 24 24"><path class="ic" d="M6 6l12 12M18 6 6 18"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path class="ic" d="m5 12.5 4.5 4.5L19 7.5"/></symbol>
<symbol id="i-gear" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="12" r="3"/><path class="ic" d="M12 4.5v-2M12 21.5v-2M19.5 12h2M2.5 12h2M17.3 6.7l1.4-1.4M5.3 18.7l1.4-1.4M17.3 17.3l1.4 1.4M5.3 5.3l1.4 1.4"/></symbol>
<symbol id="i-mic" viewBox="0 0 24 24"><rect class="ic" x="9" y="3" width="6" height="11" rx="3"/><path class="ic" d="M5.5 11a6.5 6.5 0 0 0 13 0M12 17.5V21"/></symbol>
<symbol id="i-smile" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="12" r="8.5"/><path class="ic" d="M9 10h.01M15 10h.01M8.8 14.2c1.8 1.8 4.6 1.8 6.4 0"/></symbol>
<symbol id="i-send" viewBox="0 0 24 24"><path class="ic" d="M4 12 20 5l-3.5 14L11 14l-7-2ZM11 14l6-6"/></symbol>
<symbol id="i-food" viewBox="0 0 24 24"><path class="ic" d="M4 11h16a8 8 0 0 1-16 0Z"/><path class="ic" d="M7 8c2-1.5 8-1.5 10 0M12 6V4"/></symbol>
<symbol id="i-cup" viewBox="0 0 24 24"><path class="ic" d="M7 6h10l-1.2 13H8.2L7 6Z"/><path class="ic" d="M7.5 11h9M11 3l1.5 3"/></symbol>
<symbol id="i-cart" viewBox="0 0 24 24"><path class="ic" d="M4 5h2.5l1.8 9.5h9.4L20 8H7"/><circle class="ic" cx="9.5" cy="19" r="1.4"/><circle class="ic" cx="16.5" cy="19" r="1.4"/></symbol>
<symbol id="i-metro" viewBox="0 0 24 24"><rect class="ic" x="6" y="4" width="12" height="13" rx="3"/><path class="ic" d="M6 11h12M9.5 14.5h.01M14.5 14.5h.01M8.5 20l-1.5 1.5M15.5 20l1.5 1.5"/></symbol>
<symbol id="i-house" viewBox="0 0 24 24"><path class="ic" d="M4 11.5 12 4l8 7.5M6.5 9.7V19h11V9.7"/></symbol>
<symbol id="i-game" viewBox="0 0 24 24"><path class="ic" d="M7 8h10a4.5 4.5 0 0 1 4.4 5.4l-.6 3a3 3 0 0 1-5.2 1.4L14 16h-4l-1.6 1.8a3 3 0 0 1-5.2-1.4l-.6-3A4.5 4.5 0 0 1 7 8Z"/><path class="ic" d="M8.5 11v3M7 12.5h3M15.5 11.5h.01M17.5 13.5h.01"/></symbol>
<symbol id="i-money" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="12" r="8.5"/><path class="ic" d="M9 9.5 12 12l3-2.5M12 12v5M9.5 14.5h5"/></symbol>
<symbol id="i-wallet" viewBox="0 0 24 24"><path class="ic" d="M4 7.5A2.5 2.5 0 0 1 6.5 5H18v3"/><path class="ic" d="M4 7.5V18a2 2 0 0 0 2 2h14V8H6.5A2.5 2.5 0 0 1 4 7.5Z"/><path class="ic" d="M16 13.5h.01"/></symbol>
<symbol id="i-target" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="12" r="8.5"/><circle class="ic" cx="12" cy="12" r="4.5"/><circle cx="12" cy="12" r="1.2" fill="currentColor" stroke="none"/></symbol>
<symbol id="i-fire" viewBox="0 0 24 24"><path class="ic" d="M12 21c-3.9 0-6.5-2.4-6.5-6 0-3 2.3-5.4 3.5-7.5.6 1.3 1.3 2 2.3 2.7C11.5 8 12 5.5 14 3c.6 3 4.5 5.6 4.5 11 .1 4-2.6 7-6.5 7Z"/></symbol>
<symbol id="i-pleading" viewBox="0 0 24 24"><circle class="ic" cx="12" cy="12" r="8.5"/><circle class="ic" cx="9" cy="11" r="1.6"/><circle class="ic" cx="15" cy="11" r="1.6"/><circle cx="9.5" cy="10.5" r=".5" fill="currentColor" stroke="none"/><circle cx="15.5" cy="10.5" r=".5" fill="currentColor" stroke="none"/><path class="ic" d="M10.8 15.5c.8-.5 1.6-.5 2.4 0"/></symbol>
<symbol id="i-cat-angry" viewBox="0 0 24 24"><path class="ic" d="M5.5 9.5 4 4.5l4.2 2.1a8 8 0 0 1 7.6 0L20 4.5l-1.5 5A8 8 0 0 1 20 13c0 4.4-3.6 7.5-8 7.5S4 17.4 4 13c0-1.3.6-2.5 1.5-3.5Z"/><path class="ic" d="m8 11.5 2 .8M16 11.5l-2 .8M10.2 16.2c1.1-.8 2.5-.8 3.6 0"/></symbol>
<symbol id="i-cat-happy" viewBox="0 0 24 24"><path class="ic" d="M5.5 9.5 4 4.5l4.2 2.1a8 8 0 0 1 7.6 0L20 4.5l-1.5 5A8 8 0 0 1 20 13c0 4.4-3.6 7.5-8 7.5S4 17.4 4 13c0-1.3.6-2.5 1.5-3.5Z"/><path class="ic" d="M8 12.5c.6-.8 1.4-.8 2 0M14 12.5c.6-.8 1.4-.8 2 0M10 15.5c1.2 1.2 2.8 1.2 4 0"/></symbol>
<symbol id="i-swap" viewBox="0 0 24 24"><path class="ic" d="M7 9h11l-3-3M17 15H6l3 3"/></symbol>
<symbol id="i-camera" viewBox="0 0 24 24"><path class="ic" d="M4 8h3l1.5-2h7L17 8h3v11H4V8Z"/><circle class="ic" cx="12" cy="13" r="3.2"/></symbol>
<symbol id="i-book" viewBox="0 0 24 24"><path class="ic" d="M5 5.5A2.5 2.5 0 0 1 7.5 3H19v15.5H7.5A2.5 2.5 0 0 0 5 21V5.5Z"/><path class="ic" d="M5 18.5A2.5 2.5 0 0 1 7.5 16H19"/></symbol>
<symbol id="i-tag" viewBox="0 0 24 24"><path class="ic" d="m12 3 8 1 1 8-9.5 9.5-9-9L12 3Z"/><circle class="ic" cx="15.5" cy="8.5" r="1.3"/></symbol>
<symbol id="i-gift" viewBox="0 0 24 24"><rect class="ic" x="4" y="9" width="16" height="4"/><path class="ic" d="M6 13v7h12v-7M12 9v11M12 9C9 9 7.5 7.5 8 5.8 8.6 4 11 4.5 12 7c1-2.5 3.4-3 4-1.2.5 1.7-1 3.2-4 3.2Z"/></symbol>
</defs>
</svg>
<div class="phone" id="phone">
<div class="statusbar"><span>9:41</span><div class="notch"></div><span>●●●</span></div>
<!-- ========== S1 登录 ========== -->
<div class="scr on" id="s-login">
<div class="onb" style="justify-content:center;">
<div class="splash-logo"><svg width="52" height="52"><use href="#i-cat"/></svg></div>
<div class="app-name">喵记账</div>
<div class="app-slogan">会聊天的记账本 · 让 AI 帮你管钱</div>
<div style="height:60px;"></div>
<div class="btn primary" onclick="go('s-mode')">微信一键登录</div>
<div style="height:12px;"></div>
<div class="btn ghost" onclick="go('s-mode')">手机号登录</div>
<div style="height:16px;"></div>
<div style="text-align:center;font-size:12px;color:var(--text3);cursor:pointer;" onclick="go('s-mode')">先逛逛,游客模式 </div>
</div>
</div>
<!-- ========== S2 选模式 ========== -->
<div class="scr" id="s-mode">
<div class="onb">
<div class="step-dots"><i class="on"></i><i></i></div>
<div class="onb-title">你想怎么用它?</div>
<div class="onb-sub">两种完全不同的体验,之后随时可以切换</div>
<div style="height:14px;"></div>
<div class="mode-big on" id="mb-normal" onclick="pickMode('normal')">
<div class="pick"><svg width="12" height="12"><use href="#i-check"/></svg></div>
<div class="mt"><svg width="20" height="20" style="color:var(--primary);"><use href="#i-wallet"/></svg>普通记账模式</div>
<div class="md">经典账本界面,手动记账、报表统计一应俱全,AI 助手随叫随到</div>
<div class="mini-prev">
<div class="blk" style="flex:1.4;height:66px;background:linear-gradient(135deg,var(--primary),#00C99A);border:none;"></div>
<div style="flex:1;display:flex;flex-direction:column;gap:6px;">
<div class="blk" style="height:18px;"></div>
<div class="blk" style="height:18px;"></div>
<div class="blk" style="height:18px;"></div>
</div>
</div>
</div>
<div style="height:11px;"></div>
<div class="mode-big" id="mb-ai" onclick="pickMode('ai')">
<div class="pick"><svg width="12" height="12"><use href="#i-check"/></svg></div>
<div class="mt"><svg width="20" height="20" style="color:var(--ai);"><use href="#i-sparkle"/></svg>全 AI 模式</div>
<div class="md">没有复杂界面,打开就是和 AI 聊天,说句话就完成记账、查账、看报告</div>
<div class="mini-prev chatty">
<div class="lbub">今天花了多少呀?</div>
<div class="rbub">午饭 26,奶茶 18</div>
<div class="lbub">记好啦,共 ¥44 ✓</div>
</div>
</div>
<div style="flex:1;min-height:20px;"></div>
<div class="btn primary" onclick="go('s-persona')">继续</div>
</div>
</div>
<!-- ========== S3 选性格 ========== -->
<div class="scr" id="s-persona">
<div class="onb">
<div class="step-dots"><i></i><i class="on"></i></div>
<div class="onb-title">认识你的 AI 伙伴</div>
<div class="onb-sub">选形象、挑性格 —— 它就是你的专属记账搭子</div>
<div style="height:10px;"></div>
<div class="avatar-pick">
<div class="ap" data-a="dog" onclick="pickAvatar('dog',this)"><div class="ai-face"><svg width="55%" height="55%"><use href="#i-dog"/></svg></div>阿福汪</div>
<div class="ap on" data-a="cat" onclick="pickAvatar('cat',this)"><div class="ai-face"><svg width="55%" height="55%"><use href="#i-cat"/></svg></div>小账喵</div>
<div class="ap" data-a="robot" onclick="pickAvatar('robot',this)"><div class="ai-face"><svg width="55%" height="55%"><use href="#i-robot"/></svg></div>账小智</div>
</div>
<div class="p-grid">
<div class="p-card on" data-p="毒舌猫娘" onclick="pickPersona(this)"><svg width="24" height="24" style="color:var(--ai);"><use href="#i-cat-angry"/></svg><div class="n">毒舌猫娘</div><div class="d">乱花钱会被无情吐槽</div></div>
<div class="p-card" data-p="温柔小暖" onclick="pickPersona(this)"><svg width="24" height="24" style="color:#E05585;"><use href="#i-cat-happy"/></svg><div class="n">温柔小暖</div><div class="d">永远鼓励,温柔提醒</div></div>
<div class="p-card" data-p="严格管家" onclick="pickPersona(this)"><svg width="24" height="24" style="color:#3E82E0;"><use href="#i-target"/></svg><div class="n">严格管家</div><div class="d">理性专业,数据说话</div></div>
<div class="p-card" data-p="沙雕损友" onclick="pickPersona(this)"><svg width="24" height="24" style="color:#F5A623;"><use href="#i-smile"/></svg><div class="n">沙雕损友</div><div class="d">玩梗高手,快乐记账</div></div>
</div>
<div style="flex:1;min-height:20px;"></div>
<div class="btn ai" onclick="finishOnboard()">开始记账之旅</div>
</div>
</div>
<!-- ========== S4 首页 ========== -->
<div class="scr" id="s-home">
<div class="body">
<div class="home-top">
<div class="book" onclick="toast('账本切换(原型略)')">日常账本 <svg width="14" height="14"><use href="#i-chev-d"/></svg></div>
</div>
<div class="hero">
<div class="lb">7月结余</div>
<div class="num" id="h-balance">¥ 4,286.50</div>
<div class="io">
<div>收入<b id="h-in">¥ 12,800.00</b></div>
<div>支出<b id="h-out">¥ 8,513.50</b></div>
<div>预算剩余<b id="h-left">¥ 1,900.00</b></div>
</div>
</div>
<div class="ai-entry" onclick="go('s-chat')">
<div class="ai-face solid" style="width:38px;height:38px;"><svg width="22" height="22"><use href="#i-cat" id="entry-avatar"/></svg></div>
<div>
<div class="t1" id="entry-name">小账喵</div>
<div class="t2" id="entry-line">"今天的奶茶已入账,这周第 3 杯了,克制一点喵"</div>
</div>
<div class="go">去聊天</div>
</div>
<div class="sec-head"><span>最近账单</span></div>
<div class="day-group">
<div class="day-head"><span>今天 · 7月17日</span><span id="today-sum">支出 ¥86.50</span></div>
<div id="today-list">
<div class="titem" onclick="toast('账单详情(原型略)')">
<div class="cat-ic" style="background:#FFF3EC;color:#F0642D;"><svg width="18" height="18"><use href="#i-cup"/></svg></div>
<div><div class="n">一点点奶茶</div><div class="d">14:32 <span class="ai-badge">✦ AI</span></div></div>
<div class="amt">-18.00</div>
</div>
<div class="titem" onclick="toast('账单详情(原型略)')">
<div class="cat-ic" style="background:#FFF8E8;color:#D89614;"><svg width="18" height="18"><use href="#i-food"/></svg></div>
<div><div class="n">午餐 · 兰州拉面</div><div class="d">12:05 <span class="ai-badge">✦ AI</span></div></div>
<div class="amt">-26.00</div>
</div>
<div class="titem" onclick="toast('账单详情(原型略)')">
<div class="cat-ic" style="background:#EAF3FF;color:#3E82E0;"><svg width="18" height="18"><use href="#i-metro"/></svg></div>
<div><div class="n">地铁通勤</div><div class="d">08:47</div></div>
<div class="amt">-42.50</div>
</div>
</div>
</div>
<div class="day-group">
<div class="day-head"><span>昨天 · 7月16日</span><span>收 ¥500.00 · 支 ¥128.00</span></div>
<div class="titem"><div class="cat-ic" style="background:var(--primary-bg);color:var(--primary);"><svg width="18" height="18"><use href="#i-money"/></svg></div><div><div class="n">兼职收入</div><div class="d">20:14</div></div><div class="amt in">+500.00</div></div>
<div class="titem"><div class="cat-ic" style="background:#FDEFF4;color:#E05585;"><svg width="18" height="18"><use href="#i-cart"/></svg></div><div><div class="n">超市采购</div><div class="d">19:02</div></div><div class="amt">-128.00</div></div>
</div>
<div style="height:8px;"></div>
</div>
<div class="tabbar">
<div class="tab active" onclick="switchTab('s-home',this)"><svg width="21" height="21"><use href="#i-home"/></svg>明细</div>
<div class="tab" onclick="switchTab('s-stats',this)"><svg width="21" height="21"><use href="#i-chart"/></svg>统计</div>
<div class="tab-fab" onclick="go('s-add')"><svg width="22" height="22"><use href="#i-plus"/></svg></div>
<div class="tab" onclick="switchTab('s-chat',this)"><svg width="21" height="21"><use href="#i-chat"/></svg><span class="tab-ainame">小账喵</span></div>
<div class="tab" onclick="switchTab('s-me',this)"><svg width="21" height="21"><use href="#i-user"/></svg>我的</div>
</div>
</div>
<!-- ========== S5 统计 ========== -->
<div class="scr" id="s-stats">
<div class="navbar">统计</div>
<div class="body">
<div class="card" style="margin-top:6px;">
<div style="display:flex;align-items:center;gap:16px;">
<div class="donut"><div class="c"><span class="t">7月总支出</span><span class="v" id="st-total">¥8,513</span></div></div>
<div class="legend">
<div class="li"><span class="sw2" style="background:#00B386;"></span>餐饮<span class="pct">34%</span></div>
<div class="li"><span class="sw2" style="background:#5B6BF5;"></span>购物<span class="pct">21%</span></div>
<div class="li"><span class="sw2" style="background:#F5A623;"></span>住房<span class="pct">16%</span></div>
<div class="li"><span class="sw2" style="background:#4DA6FF;"></span>交通<span class="pct">13%</span></div>
<div class="li"><span class="sw2" style="background:#F0642D;"></span>娱乐<span class="pct">9%</span></div>
<div class="li"><span class="sw2" style="background:#E3E6EA;"></span>其他<span class="pct">7%</span></div>
</div>
</div>
</div>
<div class="ai-insight">
<div class="h"><svg width="14" height="14"><use href="#i-sparkle"/></svg><span class="tab-ainame">小账喵</span>的分析</div>
本月餐饮支出比上月<b style="color:var(--red);">高 23%</b>,主要是奶茶(12 杯 ¥216)。按当前节奏预算将在 <b>7月28日</b> 用完,建议每日控制在 ¥130 以内。
<div style="margin-top:8px;"><span style="color:var(--ai);font-weight:600;cursor:pointer;" onclick="go('s-chat');setTimeout(()=>aiSay('想细看哪部分?餐饮、购物还是整体趋势?我可以直接生成月报'),600);">和它聊聊 </span></div>
</div>
<div style="height:8px;"></div>
</div>
<div class="tabbar">
<div class="tab" onclick="switchTab('s-home',this)"><svg width="21" height="21"><use href="#i-home"/></svg>明细</div>
<div class="tab active"><svg width="21" height="21"><use href="#i-chart"/></svg>统计</div>
<div class="tab-fab" onclick="go('s-add')"><svg width="22" height="22"><use href="#i-plus"/></svg></div>
<div class="tab" onclick="switchTab('s-chat',this)"><svg width="21" height="21"><use href="#i-chat"/></svg><span class="tab-ainame">小账喵</span></div>
<div class="tab" onclick="switchTab('s-me',this)"><svg width="21" height="21"><use href="#i-user"/></svg>我的</div>
</div>
</div>
<!-- ========== S6 记一笔 ========== -->
<div class="scr" id="s-add">
<div class="navbar"><span class="nav-l" onclick="go('s-home')"><svg width="20" height="20"><use href="#i-close"/></svg></span>记一笔</div>
<div class="seg"><span class="on">支出</span><span onclick="toast('原型仅演示支出')">收入</span><span onclick="toast('原型仅演示支出')">转账</span></div>
<div class="body">
<div class="cat-grid" id="cat-grid">
<div class="cat on" data-c="餐饮" data-i="i-food"><div class="ci"><svg width="20" height="20"><use href="#i-food"/></svg></div>餐饮</div>
<div class="cat" data-c="饮品" data-i="i-cup"><div class="ci"><svg width="20" height="20"><use href="#i-cup"/></svg></div>饮品</div>
<div class="cat" data-c="购物" data-i="i-cart"><div class="ci"><svg width="20" height="20"><use href="#i-cart"/></svg></div>购物</div>
<div class="cat" data-c="交通" data-i="i-metro"><div class="ci"><svg width="20" height="20"><use href="#i-metro"/></svg></div>交通</div>
<div class="cat" data-c="住房" data-i="i-house"><div class="ci"><svg width="20" height="20"><use href="#i-house"/></svg></div>住房</div>
<div class="cat" data-c="娱乐" data-i="i-game"><div class="ci"><svg width="20" height="20"><use href="#i-game"/></svg></div>娱乐</div>
<div class="cat" data-c="人情" data-i="i-gift"><div class="ci"><svg width="20" height="20"><use href="#i-gift"/></svg></div>人情</div>
<div class="cat" data-c="学习" data-i="i-book"><div class="ci"><svg width="20" height="20"><use href="#i-book"/></svg></div>学习</div>
</div>
</div>
<div class="amount-panel">
<div class="amount-line">
<div class="cm"><span id="add-cat-name">餐饮</span></div>
<div class="num"><span id="add-num">0</span><i></i></div>
</div>
<div class="keypad">
<div class="key" onclick="kp('1')">1</div><div class="key" onclick="kp('2')">2</div><div class="key" onclick="kp('3')">3</div><div class="key fn" onclick="kp('del')"></div>
<div class="key" onclick="kp('4')">4</div><div class="key" onclick="kp('5')">5</div><div class="key" onclick="kp('6')">6</div><div class="key fn" onclick="toast('原型不支持加法')"></div>
<div class="key" onclick="kp('7')">7</div><div class="key" onclick="kp('8')">8</div><div class="key" onclick="kp('9')">9</div><div class="key ok" onclick="saveManual()">完成</div>
<div class="key fn" onclick="toast('再记(原型略)')">再记</div><div class="key" onclick="kp('0')">0</div><div class="key" onclick="kp('.')">.</div>
</div>
</div>
</div>
<!-- ========== S7 聊天 ========== -->
<div class="scr" id="s-chat">
<div class="chat-nav">
<span class="nb" onclick="go(state.mode==='ai'?'s-aihome':'s-home')"><svg width="20" height="20"><use href="#i-chev-l"/></svg></span>
<div class="ai-face solid" style="width:36px;height:36px;"><svg width="22" height="22"><use href="#i-cat" class="ava-use"/></svg></div>
<div class="meta">
<div class="n"><span class="tab-ainame">小账喵</span> <span class="persona-chip" id="chat-chip">毒舌猫娘</span></div>
<div class="s">● 在线 · 已陪你记账 128 天</div>
</div>
<span class="gear" onclick="go('s-setting')"><svg width="19" height="19"><use href="#i-gear"/></svg></span>
</div>
<div class="chat-body" id="chat-body">
<div class="time-tag">今天 14:31</div>
</div>
<div class="quick-row">
<span class="quick" onclick="userSay('刚买了杯一点点,18块')">💬 刚买了杯一点点,18块</span>
<span class="quick" onclick="userSay('昨晚烧烤人均68支付宝付的')">💬 昨晚烧烤人均68</span>
<span class="quick" onclick="userSay('这个月我花最多的是什么?')">📊 花最多的是什么</span>
<span class="quick" onclick="toast('拍小票(原型略)')">📷 拍小票</span>
</div>
<div class="chat-input">
<span class="cbtn" onclick="toast('长按说话(原型略)')"><svg width="21" height="21"><use href="#i-mic"/></svg></span>
<input id="chat-inp" placeholder="说句话记一笔,如:打车花了45" onkeydown="if(event.key==='Enter')sendInput()">
<span class="cbtn" onclick="toggleStk()"><svg width="21" height="21"><use href="#i-smile"/></svg></span>
<span class="send-btn" onclick="sendInput()"><svg width="16" height="16"><use href="#i-send"/></svg></span>
</div>
<div class="stk-panel" id="stk-panel">
<div class="stk-grid">
<div class="stk" onclick="sendSticker('i-money','发工资啦','#00B386')"><div class="box"><svg width="34" height="34" style="color:var(--primary);"><use href="#i-money"/></svg></div>发工资啦</div>
<div class="stk" onclick="sendSticker('i-pleading','求原谅…','#F5A623')"><div class="box"><svg width="34" height="34" style="color:#F5A623;"><use href="#i-pleading"/></svg></div>求原谅</div>
<div class="stk" onclick="sendSticker('i-fire','剁手警告','#F0642D')"><div class="box"><svg width="34" height="34" style="color:var(--red);"><use href="#i-fire"/></svg></div>剁手警告</div>
<div class="stk" onclick="sendSticker('i-wallet','钱包空空','#9AA3AD')"><div class="box"><svg width="34" height="34" style="color:var(--text3);"><use href="#i-wallet"/></svg></div>钱包空空</div>
</div>
</div>
</div>
<!-- ========== S8 我的 ========== -->
<div class="scr" id="s-me">
<div class="body">
<div class="me-head">
<div class="av"><svg width="26" height="26"><use href="#i-user"/></svg></div>
<div><div class="n">南巡</div><div class="d">已连续记账 128 天 · 超过 92% 的用户</div></div>
</div>
<div class="card">
<div style="font-size:13px;font-weight:700;margin-bottom:3px;">App 模式</div>
<div style="font-size:10.5px;color:var(--text3);margin-bottom:11px;">选择你喜欢的使用方式,可随时切换</div>
<div class="mode-opts">
<div class="mode-opt on" id="mo-normal" onclick="setMode('normal')">
<div class="radio"></div>
<svg width="20" height="20" style="color:var(--primary);"><use href="#i-wallet"/></svg>
<div class="n">普通记账模式</div><div class="d">经典账本界面</div>
</div>
<div class="mode-opt" id="mo-ai" onclick="setMode('ai')">
<div class="radio"></div>
<svg width="20" height="20" style="color:var(--ai);"><use href="#i-sparkle"/></svg>
<div class="n">全 AI 模式</div><div class="d">对话作为主界面</div>
</div>
</div>
</div>
<div class="list-group">
<div class="li-row" onclick="go('s-setting')"><div class="lic" style="background:var(--ai-bg);color:var(--ai);"><svg width="16" height="16"><use href="#i-cat"/></svg></div>AI 性格设置<span class="val" id="me-persona">毒舌猫娘 <svg width="13" height="13"><use href="#i-chev-r"/></svg></span></div>
<div class="li-row" onclick="toast('预算管理(原型略)')"><div class="lic" style="background:var(--primary-bg);color:var(--primary);"><svg width="16" height="16"><use href="#i-target"/></svg></div>预算管理<span class="val">¥5,000/月 <svg width="13" height="13"><use href="#i-chev-r"/></svg></span></div>
<div class="li-row" onclick="toast('账本管理(原型略)')"><div class="lic" style="background:#EAF3FF;color:#3E82E0;"><svg width="16" height="16"><use href="#i-book"/></svg></div>账本管理<span class="val">3 个账本 <svg width="13" height="13"><use href="#i-chev-r"/></svg></span></div>
<div class="li-row" onclick="toast('分类管理(原型略)')"><div class="lic" style="background:#FFF8E8;color:#D89614;"><svg width="16" height="16"><use href="#i-tag"/></svg></div>分类管理<span class="val"><svg width="13" height="13"><use href="#i-chev-r"/></svg></span></div>
</div>
</div>
<div class="tabbar">
<div class="tab" onclick="switchTab('s-home',this)"><svg width="21" height="21"><use href="#i-home"/></svg>明细</div>
<div class="tab" onclick="switchTab('s-stats',this)"><svg width="21" height="21"><use href="#i-chart"/></svg>统计</div>
<div class="tab-fab" onclick="go('s-add')"><svg width="22" height="22"><use href="#i-plus"/></svg></div>
<div class="tab" onclick="switchTab('s-chat',this)"><svg width="21" height="21"><use href="#i-chat"/></svg><span class="tab-ainame">小账喵</span></div>
<div class="tab active"><svg width="21" height="21"><use href="#i-user"/></svg>我的</div>
</div>
</div>
<!-- ========== S9 性格设置 ========== -->
<div class="scr" id="s-setting">
<div class="navbar"><span class="nav-l" onclick="goBack()"><svg width="20" height="20"><use href="#i-chev-l"/></svg></span>AI 性格设置</div>
<div class="body">
<div style="text-align:center;padding:14px 0 4px;">
<div class="ai-face solid" style="width:70px;height:70px;margin:0 auto;box-shadow:0 10px 22px rgba(91,107,245,.3);"><svg width="40" height="40"><use href="#i-cat" class="ava-use"/></svg></div>
<div style="font-size:15px;font-weight:700;margin-top:9px;" class="tab-ainame">小账喵</div>
</div>
<div class="p-grid" id="setting-grid">
<div class="p-card on" data-p="毒舌猫娘" onclick="pickPersona(this,true)"><svg width="24" height="24" style="color:var(--ai);"><use href="#i-cat-angry"/></svg><div class="n">毒舌猫娘</div><div class="d">乱花钱会被无情吐槽</div></div>
<div class="p-card" data-p="温柔小暖" onclick="pickPersona(this,true)"><svg width="24" height="24" style="color:#E05585;"><use href="#i-cat-happy"/></svg><div class="n">温柔小暖</div><div class="d">永远鼓励,温柔提醒</div></div>
<div class="p-card" data-p="严格管家" onclick="pickPersona(this,true)"><svg width="24" height="24" style="color:#3E82E0;"><use href="#i-target"/></svg><div class="n">严格管家</div><div class="d">理性专业,数据说话</div></div>
<div class="p-card" data-p="沙雕损友" onclick="pickPersona(this,true)"><svg width="24" height="24" style="color:#F5A623;"><use href="#i-smile"/></svg><div class="n">沙雕损友</div><div class="d">玩梗高手,快乐记账</div></div>
</div>
<div style="height:10px;"></div>
<div class="card slider-block">
<div class="lb"><span>吐槽力度</span><b>较犀利</b></div>
<div class="track" onclick="toast('拖动调节(原型略)')"><i style="width:72%;"></i><span class="knob" style="left:72%;"></span></div>
<div style="height:16px;"></div>
<div class="lb"><span>表情包频率</span><b>经常发</b></div>
<div class="track" onclick="toast('拖动调节(原型略)')"><i style="width:85%;"></i><span class="knob" style="left:85%;"></span></div>
</div>
<div style="height:12px;"></div>
<div class="btn ai" onclick="goBack();toast('已保存')">保存设置</div>
<div style="height:10px;"></div>
</div>
</div>
<!-- ========== S10 全AI模式主界面 ========== -->
<div class="scr aimode" id="s-aihome">
<div class="aimode-head">
<div class="top">
<div class="ai-face solid" style="width:42px;height:42px;box-shadow:0 6px 14px rgba(91,107,245,.35);"><svg width="25" height="25"><use href="#i-cat" class="ava-use"/></svg></div>
<div>
<div class="n"><span class="tab-ainame">小账喵</span> <span class="persona-chip" id="ai-chip">毒舌猫娘</span></div>
<div class="s">全 AI 模式 · 说句话就能记账</div>
</div>
<div class="sw" onclick="setMode('normal');go('s-home')"><svg width="11" height="11" style="display:inline;vertical-align:-1px;"><use href="#i-swap"/></svg> 切换模式</div>
</div>
<div class="mini-dash">
<div class="mini-card"><div class="t">今日支出</div><div class="v" style="color:var(--red);" id="ai-today">¥86.50</div></div>
<div class="mini-card"><div class="t">本月结余</div><div class="v" style="color:var(--primary);" id="ai-balance">¥4,286</div></div>
<div class="mini-card"><div class="t">预算剩余</div><div class="v" id="ai-left">62%</div></div>
</div>
</div>
<div class="chat-body" id="ai-chat-body">
<div class="time-tag">今天 19:02</div>
</div>
<div class="quick-row">
<span class="quick" onclick="userSay('晚饭和同事吃了火锅AA,人均88',true)">💬 火锅AA人均88</span>
<span class="quick" onclick="userSay('这个月我花最多的是什么?',true)">📊 花最多的是什么</span>
<span class="quick" onclick="toast('生成月报(原型略)')">📈 生成月报</span>
<span class="quick" onclick="toast('拍小票(原型略)')">📷 拍小票</span>
</div>
<div class="chat-input">
<span class="cbtn" onclick="toast('长按说话(原型略)')"><svg width="21" height="21"><use href="#i-mic"/></svg></span>
<input id="ai-chat-inp" placeholder="说句话,记一笔…" onkeydown="if(event.key==='Enter')sendInput(true)">
<span class="cbtn" onclick="toggleStk(true)"><svg width="21" height="21"><use href="#i-smile"/></svg></span>
<span class="send-btn" onclick="sendInput(true)"><svg width="16" height="16"><use href="#i-send"/></svg></span>
</div>
<div class="stk-panel" id="ai-stk-panel">
<div class="stk-grid">
<div class="stk" onclick="sendSticker('i-money','发工资啦','#00B386',true)"><div class="box"><svg width="34" height="34" style="color:var(--primary);"><use href="#i-money"/></svg></div>发工资啦</div>
<div class="stk" onclick="sendSticker('i-pleading','求原谅…','#F5A623',true)"><div class="box"><svg width="34" height="34" style="color:#F5A623;"><use href="#i-pleading"/></svg></div>求原谅</div>
<div class="stk" onclick="sendSticker('i-fire','剁手警告','#F0642D',true)"><div class="box"><svg width="34" height="34" style="color:var(--red);"><use href="#i-fire"/></svg></div>剁手警告</div>
<div class="stk" onclick="sendSticker('i-wallet','钱包空空','#9AA3AD',true)"><div class="box"><svg width="34" height="34" style="color:var(--text3);"><use href="#i-wallet"/></svg></div>钱包空空</div>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<div class="homebar"></div>
</div>
<p class="hint">
<b>可交互原型</b> · 从登录开始点一遍:登录 → 选模式 → 选 AI 伙伴 → 主界面<br>
试试:聊天里输入「打车花了45」→ AI 直接入账(首页数字立即变化),卡片上可「撤销」回滚<br>
换形象后口癖会变(猫=喵 / 狗=汪 / 机器人=无)· 表情按钮可互发表情包 · 「我的」里可切全 AI 模式
</p>
<script>
/* ================= 状态 ================= */
const state = {
mode:'normal', avatar:'cat', persona:'毒舌猫娘', aiName:'小账喵',
todayOut:86.50, monthOut:8513.50, monthIn:12800, budgetTotal:5000, budgetUsed:3100,
};
const AI_NAMES = {cat:'小账喵', dog:'阿福汪', robot:'账小智'};
let history = [];
let curScr = 's-login';
/* ================= 路由 ================= */
function initScreen(id){
if(id==='s-chat' && !chatStarted) startChat();
if(id==='s-aihome' && !aiChatStarted) startAiChat();
}
function go(id){
if(id===curScr) return;
history.push(curScr);
const from = document.getElementById(curScr);
const to = document.getElementById(id);
from.classList.remove('on');
to.classList.add('on');
curScr = id;
initScreen(id);
}
function goBack(){
const prev = history.pop() || (state.mode==='ai'?'s-aihome':'s-home');
const from = document.getElementById(curScr);
const to = document.getElementById(prev);
from.classList.remove('on');
to.classList.add('on');
curScr = prev;
}
function switchTab(id){
if(id===curScr) return;
const from = document.getElementById(curScr);
const to = document.getElementById(id);
from.classList.add('snap');
to.classList.add('snap','body-anim');
from.classList.remove('on');
to.classList.add('on');
history.push(curScr);
curScr = id;
setTimeout(()=>{
from.classList.remove('snap');
to.classList.remove('snap','body-anim');
}, 300);
initScreen(id);
}
/* ================= 引导 ================= */
function pickMode(m){
state.mode = m;
document.getElementById('mb-normal').classList.toggle('on', m==='normal');
document.getElementById('mb-ai').classList.toggle('on', m==='ai');
}
function pickAvatar(a, el){
state.avatar = a;
state.aiName = AI_NAMES[a];
document.querySelectorAll('.avatar-pick .ap').forEach(p=>p.classList.remove('on'));
el.classList.add('on');
applyIdentity();
}
function pickPersona(el, isSetting){
state.persona = el.dataset.p;
el.parentElement.querySelectorAll('.p-card').forEach(c=>c.classList.remove('on'));
el.classList.add('on');
applyIdentity();
if(isSetting) syncPersonaCards();
}
function syncPersonaCards(){
document.querySelectorAll('.p-grid .p-card').forEach(c=>c.classList.toggle('on', c.dataset.p===state.persona));
}
function applyIdentity(){
document.querySelectorAll('.tab-ainame').forEach(e=>e.textContent=state.aiName);
document.getElementById('entry-name').textContent = state.aiName;
document.getElementById('chat-chip').textContent = state.persona;
document.getElementById('ai-chip').textContent = state.persona;
document.getElementById('me-persona').firstChild && (document.getElementById('me-persona').childNodes[0].textContent = state.persona+' ');
document.querySelectorAll('.ava-use').forEach(u=>u.setAttribute('href','#i-'+state.avatar));
/* 决策20:首页 AI 入口的示例台词也跟随口癖 */
document.getElementById('entry-line').textContent = '"'+suffix('今天的奶茶已入账,这周第 3 杯了,克制一点')+'"';
}
function finishOnboard(){
applyIdentity(); syncPersonaCards();
if(state.mode==='ai'){ setModeUI(); go('s-aihome'); }
else{ setModeUI(); go('s-home'); }
toast(state.aiName+'已上线,'+(state.persona==='温柔小暖'?'请多关照呀':'开始盯紧你的钱包'));
}
/* ================= 模式切换 ================= */
function setMode(m){
state.mode = m; setModeUI();
if(m==='ai'){ go('s-aihome'); toast('已切换到全 AI 模式'); }
else { toast('已切换到普通记账模式'); }
}
function setModeUI(){
document.getElementById('mo-normal').classList.toggle('on', state.mode==='normal');
document.getElementById('mo-ai').classList.toggle('on', state.mode==='ai');
}
/* ================= 首页数字 ================= */
function fmt(n){ return n.toLocaleString('zh-CN',{minimumFractionDigits:2,maximumFractionDigits:2}); }
function refreshNums(){
document.getElementById('h-balance').textContent = '¥ '+fmt(state.monthIn-state.monthOut);
document.getElementById('h-out').textContent = '¥ '+fmt(state.monthOut);
document.getElementById('h-left').textContent = '¥ '+fmt(state.budgetTotal-state.budgetUsed);
document.getElementById('today-sum').textContent = '支出 ¥'+fmt(state.todayOut);
document.getElementById('ai-today').textContent = '¥'+fmt(state.todayOut);
document.getElementById('ai-balance').textContent = '¥'+Math.round(state.monthIn-state.monthOut).toLocaleString();
document.getElementById('ai-left').textContent = Math.round((1-state.budgetUsed/state.budgetTotal)*100)+'%';
document.getElementById('st-total').textContent = '¥'+Math.round(state.monthOut).toLocaleString();
}
/* ================= 记账核心 ================= */
const CAT_STYLE = {
'餐饮':{i:'i-food',bg:'#FFF8E8',c:'#D89614'},
'饮品':{i:'i-cup',bg:'#FFF3EC',c:'#F0642D'},
'购物':{i:'i-cart',bg:'#FDEFF4',c:'#E05585'},
'交通':{i:'i-metro',bg:'#EAF3FF',c:'#3E82E0'},
'住房':{i:'i-house',bg:'#EAF3FF',c:'#3E82E0'},
'娱乐':{i:'i-game',bg:'#EEF0FE',c:'#5B6BF5'},
'人情':{i:'i-gift',bg:'#FDEFF4',c:'#E05585'},
'学习':{i:'i-book',bg:'#EAF3FF',c:'#3E82E0'},
'其他':{i:'i-tag',bg:'#F2F3F5',c:'#5E6772'},
};
const recordStore = {};
function addRecord(cat, name, amount, viaAI){
state.todayOut += amount; state.monthOut += amount; state.budgetUsed += amount;
const s = CAT_STYLE[cat]||CAT_STYLE['其他'];
const now = new Date();
const hh = String(now.getHours()).padStart(2,'0')+':'+String(now.getMinutes()).padStart(2,'0');
const item = document.createElement('div');
item.className='titem';
item.innerHTML = `<div class="cat-ic" style="background:${s.bg};color:${s.c};"><svg width="18" height="18"><use href="#${s.i}"/></svg></div>
<div><div class="n">${name}</div><div class="d">${hh} ${viaAI?'<span class="ai-badge">✦ AI</span>':''}</div></div>
<div class="amt">-${fmt(amount)}</div>`;
const list = document.getElementById('today-list');
list.insertBefore(item, list.firstChild);
refreshNums();
const rid = 'r'+Date.now()+Math.floor(Math.random()*1e4);
recordStore[rid] = {el:item, amount};
return rid;
}
function removeRecord(rid){
const r = recordStore[rid]; if(!r) return;
state.todayOut -= r.amount; state.monthOut -= r.amount; state.budgetUsed -= r.amount;
r.el.remove(); delete recordStore[rid];
refreshNums();
}
/* ================= 手动记账 ================= */
let addNum = '0';
document.getElementById('cat-grid').addEventListener('click', e=>{
const c = e.target.closest('.cat'); if(!c) return;
document.querySelectorAll('#cat-grid .cat').forEach(x=>x.classList.remove('on'));
c.classList.add('on');
document.getElementById('add-cat-name').textContent = c.dataset.c;
});
function kp(k){
if(k==='del'){ addNum = addNum.length>1 ? addNum.slice(0,-1) : '0'; }
else if(k==='.'){ if(!addNum.includes('.')) addNum+='.'; }
else{ addNum = addNum==='0' ? k : addNum+k; if(addNum.length>8) addNum=addNum.slice(0,8); }
document.getElementById('add-num').textContent = addNum;
}
function saveManual(){
const v = parseFloat(addNum);
if(!v){ toast('请输入金额'); return; }
const cat = document.querySelector('#cat-grid .cat.on').dataset.c;
addRecord(cat, cat, v, false);
addNum='0'; document.getElementById('add-num').textContent='0';
go('s-home'); toast('已记一笔 ¥'+fmt(v));
}
/* ================= 聊天 ================= */
let chatStarted=false, aiChatStarted=false;
function chatEl(ai){ return document.getElementById(ai?'ai-chat-body':'chat-body'); }
function scrollBottom(ai){ const el=chatEl(ai); el.scrollTop=el.scrollHeight; }
function avatarHtml(){ return `<div class="av ai-face solid"><svg width="20" height="20"><use href="#i-${state.avatar}"/></svg></div>`; }
function pushMsg(html, me, ai){
const m = document.createElement('div');
m.className = 'msg'+(me?' me':' ai');
m.innerHTML = me
? `<div class="av"><svg width="17" height="17"><use href="#i-user"/></svg></div>${html}`
: `${avatarHtml()}${html}`;
chatEl(ai).appendChild(m);
scrollBottom(ai);
return m;
}
function aiSay(text, ai){
const t = pushMsg('<div class="bubble typing-b"><div class="typing"><i></i><i></i><i></i></div></div>', false, ai);
setTimeout(()=>{ t.querySelector('.bubble').outerHTML = `<div class="bubble">${text}</div>`; scrollBottom(ai); }, 700+Math.random()*400);
}
function aiSticker(icon, label, color, ai){
setTimeout(()=>{
pushMsg(`<div class="sticker-card"><svg width="48" height="48" style="color:${color};"><use href="#${icon}"/></svg><span class="t">${label}</span></div>`, false, ai);
}, 1300);
}
function aiBill(cat, name, amount, ai){
const s = CAT_STYLE[cat]||CAT_STYLE['其他'];
const id = 'bill-'+Date.now();
setTimeout(()=>{
/* 决策18:AI 解析后直接入账,卡片提供撤销 */
const rid = addRecord(cat, name, amount, true);
pushMsg(`<div class="bill-card" id="${id}">
<div class="bc-head"><svg width="11" height="11"><use href="#i-sparkle"/></svg>AI 已自动记账</div>
<div class="bc-body">
<div class="cat-ic" style="background:${s.bg};color:${s.c};"><svg width="18" height="18"><use href="#${s.i}"/></svg></div>
<div><div class="bc-amt">-¥${fmt(amount)}</div><div class="bc-cat">${cat} · ${name}</div></div>
</div>
<div class="bc-foot">
<span class="st">✓ 已入账</span>
<span class="op" onclick="toast('修改(原型略):也可以直接说「不对,是28块」')">修改</span>
<span class="op" onclick="undoBill('${id}','${rid}')">撤销</span>
</div>
<div class="bc-undone-tip">已撤销,这笔没记</div>
</div>`, false, ai);
}, 1200);
}
function undoBill(id, rid){
removeRecord(rid);
document.getElementById(id).classList.add('undone');
toast('已撤销');
aiSay(pers({
'毒舌猫娘':suffix('好吧,当我没看见这笔'),
'温柔小暖':suffix('撤销啦,没关系~'),
'严格管家':'已撤销该笔记录,账目已回滚。',
'沙雕损友':'当无事发生.jpg 已撤销',
}), document.getElementById(id).closest('.scr').id==='s-aihome');
}
/* ---- персона语气 ---- */
/* 决策20:口癖跟随 AI 形象 —— 猫=喵 / 狗=汪 / 机器人=无口癖 */
const TIC = {cat:'喵', dog:'汪', robot:''};
function suffix(text){
const t = TIC[state.avatar];
if(!t) return text;
return /[。!?!?~]$/.test(text) ? text.replace(/([。!?!?~]+)$/, t+'$1') : text+t;
}
function pers(map){ return map[state.persona]; }
function tone(key, ctx){
const t = {
'记账吐槽':{
'毒舌猫娘':suffix(`记好了!不过${ctx}……钱包在哭泣哦,这周克制点`),
'温柔小暖':suffix(`记好啦~${ctx},偶尔享受一下也没关系的,我帮你看好预算`),
'严格管家':`已记录。提示:${ctx},当前分类预算使用率已偏高,请注意控制。`,
'沙雕损友':`记上了记上了!${ctx},家人们谁懂啊 🤡 下次带我一个`,
},
'表情回':{
'毒舌猫娘':suffix('卖萌也没用!该省还得省'),
'温柔小暖':'哈哈收到~心情好最重要啦',
'严格管家':'已收到。请继续保持记账习惯。',
'沙雕损友':'哈哈哈哈这表情包我先存了',
},
'分析':{
'毒舌猫娘':suffix(`是<b>餐饮 ¥2,894</b>(占 34%)!其中奶茶就 ¥216……你不是在喝奶茶,是在给奶茶店打工`),
'温柔小暖':`这个月<b>餐饮</b>最多,¥2,89434%)~ 其中奶茶 ¥216,要不要我帮你定个小目标呀?`,
'严格管家':`本月最大支出分类:<b>餐饮 ¥2,894.50</b>,占总支出 34%。其中饮品子项 ¥216,环比上升 23%。建议设置分类预算。`,
'沙雕损友':`必须是<b>干饭 ¥2,894</b>!占了 34%,奶茶 ¥216——你这肚子是碎钞机吧 2333`,
}
};
return t[key][state.persona];
}
/* ---- 意图解析(原型级) ---- */
function parseIntent(text){
const amtMatch = text.match(/(\d+(?:\.\d+)?)\s*(?:块|元|r|R)?/);
const amount = amtMatch ? parseFloat(amtMatch[1]) : null;
if(/花最多|花了多少|分析|报告/.test(text)) return {type:'query'};
if(amount){
let cat='餐饮', name='消费';
if(/奶茶|咖啡|一点点|喜茶|饮/.test(text)){cat='饮品';name=/一点点/.test(text)?'一点点奶茶':'饮品';}
else if(/打车|地铁|公交|滴滴|车费/.test(text)){cat='交通';name=/打车|滴滴/.test(text)?'打车':'交通出行';}
else if(/超市|买|购物|淘宝|京东/.test(text)){cat='购物';name='购物';}
else if(/火锅|烧烤|饭|餐|外卖|吃/.test(text)){cat='餐饮';name=/火锅/.test(text)?'火锅聚餐':(/烧烤/.test(text)?'烧烤':'餐饮');}
else if(/电影|游戏|KTV/.test(text)){cat='娱乐';name='娱乐';}
return {type:'bill', cat, name, amount};
}
return {type:'chat'};
}
function userSay(text, ai){
pushMsg(`<div class="bubble">${text}</div>`, true, ai);
const intent = parseIntent(text);
if(intent.type==='bill'){
const ctxMap = {'饮品':'这是你这周第 3 杯奶茶了','餐饮':'今天餐饮已经花了不少','交通':'通勤成本又上去了','购物':'购物车又出手了','娱乐':'玩得开心就好'};
aiSay(tone('记账吐槽', ctxMap[intent.cat]||'又花钱了'), ai);
aiBill(intent.cat, intent.name, intent.amount, ai);
}else if(intent.type==='query'){
aiSay(tone('分析'), ai);
}else{
aiSay(state.persona==='温柔小暖' ? suffix('嗯嗯我在听~要记账直接说金额就行哦') : suffix('在听。想记账就直接说,比如「午饭 26」'), ai);
}
}
function sendInput(ai){
const inp = document.getElementById(ai?'ai-chat-inp':'chat-inp');
const v = inp.value.trim(); if(!v) return;
inp.value='';
userSay(v, ai);
}
function toggleStk(ai){
document.getElementById(ai?'ai-stk-panel':'stk-panel').classList.toggle('open');
}
function sendSticker(icon, label, color, ai){
toggleStk(ai);
pushMsg(`<div class="sticker-card"><svg width="48" height="48" style="color:${color};"><use href="#${icon}"/></svg><span class="t">${label}</span></div>`, true, ai);
if(icon==='i-money'){
aiSay(state.persona==='严格管家' ? '检测到收入信号。请报具体金额,我来记录。' : suffix('哦?发工资了?多少多少,快报数,我帮你记收入!'), ai);
}else{
aiSay(tone('表情回'), ai);
const happy = state.persona==='温柔小暖';
const stkIcon = state.avatar==='cat' ? ('i-cat-'+(happy?'happy':'angry')) : 'i-'+state.avatar;
aiSticker(stkIcon, happy?'没关系哒':'哼!', 'var(--ai)', ai);
}
}
/* ---- 开场白 ---- */
function startChat(){
chatStarted=true;
setTimeout(()=>aiSay(suffix('下午好!今天已经花了 ¥'+fmt(state.todayOut)+',有什么要记的直接说,或者点下面的快捷短语试试')),300);
}
function startAiChat(){
aiChatStarted=true;
setTimeout(()=>aiSay(suffix('晚上好~这里是全 AI 模式,记账、查账、看报告都在这个对话里完成。先试试下面的快捷短语?'),true),300);
}
/* ================= toast ================= */
let toastTimer;
function toast(t){
const el = document.getElementById('toast');
el.textContent = t; el.classList.add('show');
clearTimeout(toastTimer);
toastTimer = setTimeout(()=>el.classList.remove('show'), 1800);
}
refreshNums();
</script>
</body>
</html>