1016 lines
69 KiB
HTML
1016 lines
69 KiB
HTML
<!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,894(34%)~ 其中奶茶 ¥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>
|