| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828 |
- <!doctype html>
- <html lang="zh-CN" data-accent="indigo">
- <head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <title>Fmode v2 · MVP Demo(双端 11 屏)</title>
- <style>
- /* ==========================================================================
- Fmode v2 · MVP Demo
- 令牌值取自 ui-kit src/styles.uikit.css + indigo accent(裁决 12 / ADR-002)
- 本文件仅供评审,不进生产包,不污染 src/
- ========================================================================== */
- /* ---------- 令牌 ---------- */
- :root{
- --canvas:#f6f7f9; --surface:#ffffff; --surface-2:#f1f3f6; --surface-hover:#f6f7f9; --surface-active:#eef1f5;
- --edge:#e4e7ec; --edge-strong:#cbd2da;
- --ink:#1f2733; --ink-2:#4a5568; --muted:#6b7280; --faint:#9aa1ac; --inverse:#ffffff;
- --primary:#5856D6; --primary-hover:#4442BE; --primary-active:#3836a3; --primary-subtle:#ECEBFC; --primary-ring:rgb(88 86 214 / .35);
- --success:#047857; --success-subtle:#e7f5ef;
- --danger:#b91c1c; --danger-subtle:#fdecec;
- --warning:#a04b08; --warning-subtle:#fdf1dc;
- --info:#0369a1; --info-subtle:#e6f2fa;
- --fs-11:11.5px; --fs-12:12px; --fs-13:13px; --fs-15:15px; --fs-17:17px; --fs-20:20px; --fs-26:26px; --fs-42:42px;
- --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-8:32px;
- --r-sm:11px; --r-md:14px; --r-lg:18px; --r-tag:999px;
- /* 桌面栏宽(《双端布局规范》§2.1,全部令牌化,禁止硬编码) */
- --dk-nav-w:56px; --dk-nav-w-expanded:236px;
- --dk-list-w:300px; --dk-list-w-narrow:280px;
- --dk-main-min-w:480px;
- --dk-aside-w:340px; --dk-aside-w-compact:300px;
- /* 移动关键尺寸(§3.1,硬约束) */
- --touch-min:44px;
- --hd-h:64px; /* 栏头统一高度:列表 / 主区 / 右栏三栏底部分隔线必须对齐 */
- --mb-navbar-h:56px; --mb-tabbar-h:56px;
- --mb-list-h-1:56px; --mb-list-h-2:64px; --mb-list-h-3:88px;
- --mb-avatar:44px; --mb-avatar-lg:64px;
- --mb-gutter:16px;
- --mb-safe-top:env(safe-area-inset-top); --mb-safe-bottom:env(safe-area-inset-bottom);
- --r-sheet:32px;
- /* z-index 阶梯(§七,禁魔数) */
- --z-affix:900; --z-float:950; --z-mask:980; --z-popover:1000; --z-modal:1100; --z-toast:1400;
- --shadow-soft:0 1px 2px rgb(15 23 42 / .04);
- --shadow-card:0 1px 3px rgb(15 23 42 / .06), 0 1px 2px rgb(15 23 42 / .04);
- --shadow-pop:0 4px 16px rgb(15 23 42 / .10);
- --shadow-overlay:0 12px 40px rgb(15 23 42 / .16);
- --scrim:rgb(15 23 42 / .35);
- --stage-bg:radial-gradient(rgb(15 23 42 / .07) 1px, transparent 1px) 0 0 / 22px 22px, var(--canvas);
- }
- html.dark{
- --canvas:#16181d; --surface:#1e2128; --surface-2:#272b33; --surface-hover:#272b33; --surface-active:#333842;
- --edge:#2e333c; --edge-strong:#454b56;
- --ink:#f2f4f7; --ink-2:#c9cfd8; --muted:#98a1ad; --faint:#6b727d; --inverse:#16181d;
- --primary:#7D7AFF; --primary-hover:#9B99FF; --primary-active:#5856D6; --primary-subtle:rgb(125 122 255 / .17); --primary-ring:rgb(125 122 255 / .4);
- --success:#34d399; --success-subtle:rgb(52 211 153 / .14);
- --danger:#f87171; --danger-subtle:rgb(248 113 113 / .14);
- --warning:#fbbf24; --warning-subtle:rgb(251 191 36 / .14);
- --info:#38bdf8; --info-subtle:rgb(56 189 248 / .14);
- --shadow-soft:0 1px 2px rgb(0 0 0 / .30);
- --shadow-card:0 1px 3px rgb(0 0 0 / .40), 0 1px 2px rgb(0 0 0 / .30);
- --shadow-pop:0 4px 16px rgb(0 0 0 / .50);
- --shadow-overlay:0 12px 40px rgb(0 0 0 / .60);
- --scrim:rgb(0 0 0 / .55);
- --stage-bg:radial-gradient(rgb(255 255 255 / .07) 1px, transparent 1px) 0 0 / 22px 22px, var(--canvas);
- }
- *{box-sizing:border-box;margin:0;padding:0}
- html,body{height:100%}
- body{
- background:var(--canvas); color:var(--ink);
- font:var(--fs-15)/1.6 system-ui,-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;
- -webkit-font-smoothing:antialiased;
- }
- button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
- input,textarea{font:inherit;color:inherit}
- ol,ul{list-style:none}
- /* ---------- 图标 ---------- */
- .ic{width:18px;height:18px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
- .ic-sm{width:15px;height:15px}
- .ic-lg{width:22px;height:22px}
- .ic-fill{fill:currentColor;stroke:none}
- /* ---------- 演示外壳 ---------- */
- .app{display:grid;grid-template-columns:236px 1fr;grid-template-rows:56px 1fr;height:100vh}
- .topbar{
- grid-column:1/-1;display:flex;align-items:center;gap:var(--sp-4);
- padding:0 var(--sp-5);background:var(--surface);border-bottom:1px solid var(--edge);z-index:var(--z-affix);
- }
- .brand{display:flex;align-items:center;gap:var(--sp-3);min-width:0}
- .brand-mark{width:30px;height:30px;border-radius:var(--r-sm);background:var(--primary);color:var(--inverse);display:grid;place-items:center;font-weight:800;font-size:var(--fs-15);flex-shrink:0}
- .brand-t{font-size:var(--fs-15);font-weight:700;letter-spacing:-.01em;white-space:nowrap}
- .brand-s{font-size:var(--fs-12);color:var(--muted);white-space:nowrap}
- .top-sp{flex:1}
- .tool{display:flex;align-items:center;gap:var(--sp-1);background:var(--surface-2);border-radius:var(--r-sm);padding:3px}
- .tool-i{padding:5px var(--sp-3);border-radius:8px;font-size:var(--fs-13);color:var(--muted);white-space:nowrap;transition:.15s}
- .tool-i.on{background:var(--surface);color:var(--ink);font-weight:600;box-shadow:var(--shadow-soft)}
- .tool-i:hover:not(.on){color:var(--ink-2)}
- .tbtn{width:34px;height:34px;border-radius:var(--r-sm);display:grid;place-items:center;color:var(--muted);border:1px solid var(--edge);background:var(--surface)}
- .tbtn:hover{color:var(--ink);border-color:var(--edge-strong)}
- .tbtn.on{color:var(--primary);border-color:var(--primary);background:var(--primary-subtle)}
- .sidenav{background:var(--surface);border-right:1px solid var(--edge);overflow-y:auto;padding:var(--sp-3) var(--sp-3) var(--sp-6)}
- .nav-group{font-size:var(--fs-11);font-weight:700;color:var(--faint);letter-spacing:.06em;text-transform:uppercase;padding:var(--sp-4) var(--sp-2) var(--sp-2)}
- .nav-i{
- width:100%;display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) var(--sp-3);
- border-radius:var(--r-sm);color:var(--ink-2);font-size:var(--fs-13);text-align:left;transition:.15s;
- }
- .nav-i:hover{background:var(--surface-hover)}
- .nav-i.on{background:var(--primary-subtle);color:var(--primary);font-weight:600}
- .nav-i .ic{color:currentColor;opacity:.85}
- .nav-idx{margin-left:auto;font-size:var(--fs-11);color:var(--faint);font-variant-numeric:tabular-nums}
- .nav-i.on .nav-idx{color:var(--primary)}
- .stage{overflow:auto;background:var(--stage-bg);padding:var(--sp-6)}
- .screen{display:none}
- .screen.is-on{display:block;animation:fadeIn .22s ease-out}
- @keyframes fadeIn{from{opacity:0;transform:translateY(var(--sp-1))}to{opacity:1;transform:none}}
- @media (prefers-reduced-motion:reduce){.screen.is-on{animation:none}}
- /* ---------- 视图容器:两端布局的地基 ----------
- 桌面 .dk 横排 [导航轨 56 | 视图],视图内再横排 [列表 300 | 主区 flex | 右栏 340]
- 移动 .mb 竖排 [状态栏 | 视图 | TabBar],视图内再竖排 [顶栏 56 | 内容 flex | 输入]
- 此前 .view 无任何规则 → 桌面各栏上下堆叠、移动内容区高度塌陷,两端骨架均不成立 */
- .dk>.view{flex:1;display:flex;flex-direction:row;min-width:0;height:100%}
- .mb>.view{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
- .view>.page,.view>.pane-list,.view>.pane-main,.view>.pane-aside{min-width:0}
- /* 设备外框 */
- .device{background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-lg);box-shadow:var(--shadow-pop);overflow:hidden;margin:0 auto}
- .device-cap{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);border-bottom:1px solid var(--edge);font-size:var(--fs-12);color:var(--muted)}
- .device-cap b{color:var(--ink);font-size:var(--fs-13);font-weight:650}
- .dk{width:1440px;height:900px;transform-origin:top left;display:flex;background:var(--canvas)}
- .device-dk{width:1440px;height:900px}
- /* 标注 */
- .notes{display:none;max-width:920px;margin:var(--sp-5) auto 0}
- body.show-notes .notes{display:block}
- .notes-h{display:flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-13);font-weight:700;color:var(--info);margin-bottom:var(--sp-3)}
- .note{background:var(--surface);border:1px solid var(--edge);border-left:3px solid var(--info);border-radius:0 var(--r-sm) var(--r-sm) 0;padding:var(--sp-3) var(--sp-4);font-size:var(--fs-13);color:var(--ink-2);line-height:1.8;margin-bottom:var(--sp-2)}
- .note b{color:var(--info)}
- .note.warn{border-left-color:var(--warning)} .note.warn b{color:var(--warning)}
- .note.ok{border-left-color:var(--success)} .note.ok b{color:var(--success)}
- .ref{display:inline-block;padding:1px 7px;border-radius:var(--r-tag);font-size:var(--fs-11);background:var(--surface-2);color:var(--muted);margin-right:var(--sp-1);white-space:nowrap}
- /* ---------- 通用件 ---------- */
- .badge{display:inline-flex;align-items:center;gap:3px;padding:1px 8px;border-radius:var(--r-tag);font-size:var(--fs-11);font-weight:600;line-height:1.7;white-space:nowrap}
- .badge-p{background:var(--primary-subtle);color:var(--primary)}
- .badge-d{background:var(--danger-subtle);color:var(--danger)}
- .badge-w{background:var(--warning-subtle);color:var(--warning)}
- .badge-s{background:var(--success-subtle);color:var(--success)}
- .badge-i{background:var(--info-subtle);color:var(--info)}
- .badge-n{background:var(--surface-2);color:var(--muted)}
- .dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;display:inline-block}
- .dot-success{background:var(--success)} .dot-warning{background:var(--warning)}
- .dot-danger{background:var(--danger)} .dot-info{background:var(--info)} .dot-muted{background:var(--faint)}
- .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
- /* 头像 */
- .av{width:40px;height:40px;border-radius:var(--r-sm);display:grid;place-items:center;font-weight:650;font-size:var(--fs-13);flex-shrink:0;position:relative;background:var(--primary-subtle);color:var(--primary)}
- .av-bot{background:var(--primary-subtle);color:var(--primary)}
- .av-user{background:var(--surface-2);color:var(--ink-2)}
- .av-file{background:var(--surface-2);color:var(--ink-2)}
- .av-sm{width:32px;height:32px;font-size:var(--fs-11);border-radius:var(--r-sm)}
- .av-lg{width:64px;height:64px;font-size:var(--fs-20);border-radius:var(--r-lg)}
- .av-round{border-radius:50%}
- .av-on::after,.av-idle::after,.av-off::after{content:"";position:absolute;right:-1px;bottom:-1px;width:11px;height:11px;border-radius:50%;border:2px solid var(--surface)}
- .av-on::after{background:var(--success)} .av-idle::after{background:var(--warning)} .av-off::after{background:var(--faint)}
- .av-danger{background:var(--danger-subtle);color:var(--danger)}
- /* 按钮 */
- .btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-2);height:36px;padding:0 var(--sp-4);border-radius:var(--r-sm);font-size:var(--fs-13);font-weight:600;transition:.15s;border:1px solid transparent}
- .btn-primary{background:var(--primary);color:var(--inverse)}
- .btn-primary:hover{background:var(--primary-hover)}
- .btn-ghost{border-color:var(--edge);color:var(--ink-2);background:var(--surface)}
- .btn-ghost:hover{border-color:var(--edge-strong);color:var(--ink)}
- .btn-danger{color:var(--danger);border-color:var(--danger-subtle);background:var(--danger-subtle)}
- .btn-block{width:100%;height:44px;font-size:var(--fs-15)}
- .icon-btn{width:32px;height:32px;border-radius:var(--r-sm);display:grid;place-items:center;color:var(--muted);flex-shrink:0}
- .icon-btn:hover{background:var(--surface-hover);color:var(--ink)}
- .icon-btn:focus-visible,.btn:focus-visible,.nav-i:focus-visible,.tool-i:focus-visible{outline:2px solid var(--primary);outline-offset:2px}
- .mini-btn{width:28px;height:28px;border-radius:8px;display:grid;place-items:center;color:var(--muted)}
- .mini-btn:hover{background:var(--surface-hover);color:var(--ink)}
- /* 分段器 */
- .seg{display:inline-flex;background:var(--surface-2);border-radius:var(--r-sm);padding:3px;gap:2px}
- .seg-i{padding:6px var(--sp-4);border-radius:8px;font-size:var(--fs-13);color:var(--muted)}
- .seg-i.on{background:var(--surface);color:var(--ink);font-weight:600;box-shadow:var(--shadow-soft)}
- /* 标签页 */
- .tabs{display:flex;gap:var(--sp-5);border-bottom:1px solid var(--edge)}
- .tab{padding:var(--sp-3) 0;font-size:var(--fs-15);color:var(--muted);border-bottom:2px solid transparent;margin-bottom:-1px}
- .tab.on{color:var(--primary);border-bottom-color:var(--primary);font-weight:650}
- /* 筛选胶囊 */
- .chips{display:flex;gap:var(--sp-2);flex-wrap:wrap}
- .chip{position:relative;display:inline-flex;align-items:center;gap:var(--sp-1);height:var(--sp-8);padding:0 var(--sp-3);border-radius:var(--r-tag);font-size:var(--fs-12);font-weight:600;background:var(--surface-2);color:var(--muted)}
- .chip::after{content:"";position:absolute;inset:calc((44px - 100%) / -2) 0}
- .chip.on{background:var(--primary-subtle);color:var(--primary)}
- .chip.on.chip-w{background:var(--warning-subtle);color:var(--warning)}
- .chip.on.chip-d{background:var(--danger-subtle);color:var(--danger)}
- /* 进度条(仅用于分母已知场景) */
- .bar{height:6px;background:var(--surface-2);border-radius:var(--r-tag);overflow:hidden;margin-top:var(--sp-1)}
- .bar>i{display:block;height:100%;background:var(--primary);border-radius:var(--r-tag)}
- .bar.success>i{background:var(--success)} .bar.warning>i{background:var(--warning)}
- /* ---------- 桌面:导航轨 ---------- */
- .rail{width:var(--dk-nav-w);background:var(--surface);border-right:1px solid var(--edge);display:flex;flex-direction:column;align-items:center;padding:var(--sp-3) 0;gap:var(--sp-1);flex-shrink:0}
- .rail-logo{width:34px;height:34px;border-radius:var(--r-sm);background:var(--primary);color:var(--inverse);display:grid;place-items:center;font-weight:800;font-size:var(--fs-15);margin-bottom:var(--sp-3)}
- .rail-i{width:40px;height:40px;border-radius:var(--r-sm);display:grid;place-items:center;color:var(--muted);position:relative}
- .rail-i:hover{background:var(--surface-hover);color:var(--ink-2)}
- .rail-i.on{background:var(--primary-subtle);color:var(--primary)}
- .rail-i.has-dot::after{content:"";position:absolute;top:8px;right:8px;width:7px;height:7px;border-radius:50%;background:var(--danger);border:1.5px solid var(--surface)}
- .rail-sp{flex:1}
- /* ---------- 桌面:三栏 ---------- */
- .pane{display:flex;flex-direction:column;min-width:0}
- .pane-list{width:var(--dk-list-w);background:var(--surface);border-right:1px solid var(--edge);flex-shrink:0}
- .pane-main{flex:1;background:var(--canvas)}
- .pane-aside{width:var(--dk-aside-w);background:var(--surface);border-left:1px solid var(--edge);flex-shrink:0}
- .pane-head{padding:var(--sp-3) var(--sp-4);min-height:var(--hd-h);border-bottom:1px solid var(--edge);display:flex;align-items:center;gap:var(--sp-3);flex-shrink:0}
- .pane-body{flex:1;overflow-y:auto}
- .pane-body::-webkit-scrollbar,.msgs::-webkit-scrollbar{width:8px}
- .pane-body::-webkit-scrollbar-thumb,.msgs::-webkit-scrollbar-thumb{background:var(--edge-strong);border-radius:4px}
- .search{flex:1;height:var(--sp-8);background:var(--surface-2);border-radius:var(--r-sm);display:flex;align-items:center;gap:var(--sp-2);padding:0 var(--sp-3);color:var(--muted)}
- .search input{flex:1;border:0;background:none;outline:none;font-size:16px;min-width:0}
- .search input::placeholder{color:var(--faint)}
- .group-label{padding:var(--sp-3) var(--sp-4) var(--sp-1);font-size:var(--fs-11);font-weight:700;color:var(--faint);letter-spacing:.05em}
- .row{width:100%;display:flex;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);align-items:center;text-align:left;border-left:3px solid transparent;transition:.12s}
- .row:hover{background:var(--surface-hover)}
- .row.on{background:var(--primary-subtle);border-left-color:var(--primary)}
- .row.row-warn{border-left-color:var(--warning)}
- .row.row-err{border-left-color:var(--danger)}
- .row-meta{flex:1;min-width:0}
- .row-name{font-size:var(--fs-15);font-weight:600;display:flex;align-items:center;gap:var(--sp-2);min-width:0}
- .row-name span.nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .row-prev{font-size:var(--fs-13);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:var(--sp-1)}
- .row-prev.is-danger{color:var(--danger)}
- .row-prev.is-warning{color:var(--warning)}
- .row-time{font-size:var(--fs-12);color:var(--faint);flex-shrink:0;align-self:flex-start;margin-top:var(--sp-1)}
- /* ---------- 桌面:会话主区 ---------- */
- .chat-head{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);min-height:var(--hd-h);background:var(--surface);border-bottom:1px solid var(--edge);flex-shrink:0}
- .chat-title{flex:1;min-width:0}
- .t-name{font-size:var(--fs-15);font-weight:650;line-height:1.35;display:flex;align-items:center;gap:var(--sp-2)}
- .t-sub{font-size:var(--fs-12);color:var(--muted);line-height:1.35;display:flex;align-items:center;gap:var(--sp-1)}
- .head-actions{display:flex;gap:2px}
- /* L2 状态条 —— 全页面唯一渲染「在干嘛」的地方 */
- .statusbar{margin:var(--sp-4) var(--sp-4) 0;background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);padding:var(--sp-3) var(--sp-4);display:flex;align-items:center;gap:var(--sp-3);box-shadow:var(--shadow-soft);flex-shrink:0}
- .statusbar.is-static{cursor:default}
- .pulse{width:8px;height:8px;border-radius:50%;background:var(--info);flex-shrink:0;animation:pulse 1.8s ease-in-out infinite}
- @keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
- @media (prefers-reduced-motion:reduce){.pulse{animation:none}}
- .sb-text{flex:1;min-width:0}
- .sb-text b{font-size:var(--fs-13);font-weight:650;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .sb-text span{font-size:var(--fs-12);color:var(--muted)}
- .sb-chev{color:var(--faint)}
- .steps{margin:var(--sp-2) var(--sp-4) 0;padding-left:var(--sp-4);border-left:2px solid var(--edge);display:flex;flex-direction:column;gap:var(--sp-2);flex-shrink:0}
- .step{display:flex;gap:var(--sp-2);align-items:flex-start;font-size:var(--fs-13);color:var(--muted)}
- .step.done{color:var(--ink-2)} .step.cur{color:var(--info);font-weight:650}
- .step-m{width:14px;flex-shrink:0;text-align:center;font-size:var(--fs-12)}
- .step-time{color:var(--faint);font-size:var(--fs-12);margin-left:var(--sp-1)}
- .msgs{flex:1;overflow-y:auto;padding:var(--sp-5) var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-4)}
- .sys-msg{align-self:center;font-size:var(--fs-12);color:var(--muted);background:var(--surface-2);padding:2px var(--sp-3);border-radius:var(--r-tag)}
- .msg{display:flex;gap:var(--sp-3);max-width:78%}
- .msg.is-me{align-self:flex-end;flex-direction:row-reverse}
- .bubble{background:var(--surface);border:1px solid var(--edge);padding:var(--sp-3) var(--sp-4);border-radius:var(--r-md) var(--r-lg) var(--r-lg) var(--r-lg);font-size:var(--fs-15);line-height:1.65;box-shadow:var(--shadow-soft);word-break:break-word}
- .msg.is-me .bubble{background:var(--primary);color:var(--inverse);border-color:var(--primary);border-radius:var(--r-lg) var(--r-md) var(--r-lg) var(--r-lg)}
- /* 工具调用走系统消息式弱化样式,默认折叠 */
- .tool-call{align-self:flex-start;max-width:78%;display:flex;align-items:center;gap:var(--sp-2);font-size:var(--fs-12);color:var(--muted);background:var(--surface-2);border:1px dashed var(--edge-strong);border-radius:var(--r-sm);padding:var(--sp-2) var(--sp-3)}
- .tool-call .ic{color:var(--faint)}
- .composer{display:flex;align-items:flex-end;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);background:var(--surface);border-top:1px solid var(--edge);flex-shrink:0}
- .composer .icon-btn{width:36px;height:36px}
- .composer-input{flex:1;min-height:38px;max-height:132px;background:var(--surface-2);border-radius:var(--r-lg);padding:var(--sp-2) var(--sp-4);font-size:16px;line-height:1.5;border:0;outline:none;resize:none;overflow-y:auto}
- .composer-input::placeholder{color:var(--faint)}
- .send-btn{width:36px;height:36px;border-radius:var(--r-sm);background:var(--primary);color:var(--inverse);display:grid;place-items:center;flex-shrink:0}
- .send-btn:hover{background:var(--primary-hover)}
- /* 右栏 */
- .aside-h{padding:var(--sp-3) var(--sp-4);min-height:var(--hd-h);border-bottom:1px solid var(--edge);display:flex;align-items:center;justify-content:space-between;flex-shrink:0}
- .aside-h b{font-size:var(--fs-13);font-weight:650}
- .aside-b{flex:1;overflow-y:auto;padding:var(--sp-4)}
- .sect-t{font-size:var(--fs-11);font-weight:700;color:var(--faint);letter-spacing:.05em;text-transform:uppercase;margin:0 0 var(--sp-3)}
- .sect-t+.sect-t{margin-top:var(--sp-5)}
- .metric{display:flex;justify-content:space-between;align-items:center;font-size:var(--fs-13);padding:var(--sp-1) 0}
- .metric+.metric{margin-top:var(--sp-3)}
- .metric-k{color:var(--muted);display:flex;align-items:center;gap:var(--sp-1)}
- .metric-v{font-weight:650;font-variant-numeric:tabular-nums}
- .divider{height:1px;background:var(--edge);margin:var(--sp-4) 0}
- .file-row{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) 0}
- .file-row .nm{font-size:var(--fs-13);font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .file-row .tm{font-size:var(--fs-12);color:var(--faint)}
- /* ---------- 桌面:工作台 ---------- */
- .page{flex:1;min-width:0;padding:var(--sp-4) var(--sp-5);overflow-y:auto}
- .page-h{display:flex;align-items:flex-start;gap:var(--sp-4);margin-bottom:var(--sp-5)}
- .page-t{flex:1}
- .page-t h2{font-size:var(--fs-20);font-weight:700;letter-spacing:-.01em}
- .page-t p{font-size:var(--fs-13);color:var(--muted);margin-top:var(--sp-1)}
- .stat-row{display:flex;gap:var(--sp-4);margin-bottom:var(--sp-5)}
- .stat{flex:1;background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);padding:var(--sp-4);box-shadow:var(--shadow-card)}
- .stat-k{font-size:var(--fs-12);color:var(--muted);display:flex;align-items:center;gap:var(--sp-1)}
- .stat-v{font-size:var(--fs-26);font-weight:750;letter-spacing:-.02em;margin-top:var(--sp-2);font-variant-numeric:tabular-nums}
- .stat-v small{font-size:var(--fs-13);font-weight:600;color:var(--muted);margin-left:3px}
- .card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(310px,1fr));gap:var(--sp-4)}
- .wcard{background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);padding:var(--sp-4);box-shadow:var(--shadow-card);transition:.16s;display:flex;flex-direction:column;gap:var(--sp-3)}
- .wcard:hover{box-shadow:var(--shadow-pop);transform:translateY(-2px)}
- .wcard.edge-warn{border-left:3px solid var(--warning)}
- .wcard.edge-err{border-left:3px solid var(--danger)}
- .wcard-h{display:flex;align-items:center;gap:var(--sp-3)}
- .wcard-h .nm{flex:1;min-width:0}
- .wcard-h .nm b{font-size:var(--fs-15);font-weight:650;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .wcard-h .nm span{font-size:var(--fs-12);color:var(--muted)}
- .wcard-task{background:var(--surface-2);border-radius:var(--r-sm);padding:var(--sp-3);font-size:var(--fs-13);color:var(--ink-2);line-height:1.6;display:flex;gap:var(--sp-2)}
- .wcard-task .ic{color:var(--info);margin-top:var(--sp-1)}
- .wcard-metrics{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3) var(--sp-4)}
- .wcard-f{display:flex;justify-content:space-between;align-items:baseline;font-size:var(--fs-12);color:var(--muted)}
- .wcard-f b{font-size:var(--fs-13);color:var(--ink);font-weight:650;font-variant-numeric:tabular-nums}
- .wcard-foot{display:flex;align-items:center;gap:var(--sp-3);padding-top:var(--sp-3);border-top:1px solid var(--edge);font-size:var(--fs-12);color:var(--muted)}
- .wcard-foot .link{color:var(--primary);font-weight:600;display:inline-flex;align-items:center;gap:3px}
- /* ---------- 桌面:任务看板 ---------- */
- .task{width:100%;display:flex;gap:var(--sp-3);padding:var(--sp-3) var(--sp-4);border-left:3px solid transparent;text-align:left;border-bottom:1px solid var(--edge);transition:.12s}
- .task:hover{background:var(--surface-hover)}
- .task.on{background:var(--surface-active)}
- .task.blocked{border-left-color:var(--warning)} .task.failed{border-left-color:var(--danger)}
- .task.done{border-left-color:var(--success)} .task.cur{border-left-color:var(--info)}
- .task-ico{font-size:var(--fs-15);flex-shrink:0;width:18px;text-align:center;line-height:1.4}
- .task-ico.w{color:var(--warning)} .task-ico.d{color:var(--danger)}
- .task-ico.s{color:var(--success)} .task-ico.i{color:var(--info)}
- .task-b{flex:1;min-width:0}
- .task-t{font-size:var(--fs-15);font-weight:600;line-height:1.45}
- .task-m{font-size:var(--fs-12);color:var(--muted);margin-top:var(--sp-1);display:flex;gap:var(--sp-3);flex-wrap:wrap;align-items:center}
- .task-alert{font-size:var(--fs-12);font-weight:650;margin-top:var(--sp-1);display:flex;align-items:center;gap:var(--sp-1)}
- .task-alert.w{color:var(--warning)} .task-alert.d{color:var(--danger)}
- .detail{padding:var(--sp-6);height:100%;overflow-y:auto}
- .detail h3{font-size:var(--fs-17);font-weight:700;line-height:1.45;letter-spacing:-.01em}
- .detail-id{font-size:var(--fs-12);color:var(--faint);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;display:inline-flex;align-items:center;gap:var(--sp-1)}
- .kv{display:grid;grid-template-columns:96px 1fr;gap:var(--sp-2) var(--sp-4);font-size:var(--fs-13)}
- .kv dt{color:var(--muted)}
- .kv dd{color:var(--ink-2);font-weight:500}
- .run{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-2) 0;font-size:var(--fs-13);border-bottom:1px solid var(--edge)}
- .run:last-child{border-bottom:0}
- .run-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--ink-2);font-weight:600}
- .run-t{color:var(--faint);font-size:var(--fs-12);margin-left:auto}
- blockquote{border-left:3px solid var(--edge);padding-left:var(--sp-4);color:var(--ink-2);font-size:var(--fs-13);line-height:1.75}
- /* ---------- 桌面:成果 ---------- */
- .seg-head{display:flex;align-items:center;gap:var(--sp-4);padding:var(--sp-3) var(--sp-5);min-height:var(--hd-h);border-bottom:1px solid var(--edge);background:var(--surface);flex-shrink:0}
- .item{border-bottom:1px solid var(--edge);padding:var(--sp-4) var(--sp-5)}
- .item-h{display:flex;align-items:center;gap:var(--sp-3);width:100%;text-align:left}
- .item-h .nm{flex:1;min-width:0}
- .item-h .nm b{font-size:var(--fs-15);font-weight:650;display:block}
- .item-h .nm span{font-size:var(--fs-12);color:var(--muted)}
- .item-files{display:flex;gap:var(--sp-3);flex-wrap:wrap;margin-top:var(--sp-3)}
- .thumb{width:96px;height:72px;border-radius:var(--r-sm);background:var(--surface-2);border:1px solid var(--edge);display:grid;place-items:center;color:var(--faint);position:relative;overflow:hidden}
- .thumb .cap{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(transparent,rgb(0 0 0/.55));color:#fff;font-size:var(--fs-11);padding:10px 6px 3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
- .tl{position:relative;padding-left:var(--sp-6)}
- .tl::before{content:"";position:absolute;left:7px;top:6px;bottom:6px;width:2px;background:var(--edge)}
- .tl-i{position:relative;padding-bottom:var(--sp-5)}
- .tl-i::before{content:"";position:absolute;left:calc(var(--sp-6) * -1 + 3px);top:5px;width:10px;height:10px;border-radius:50%;background:var(--surface);border:2px solid var(--primary)}
- .tl-d{font-size:var(--fs-12);color:var(--faint);margin-bottom:3px}
- /* ---------- 桌面:空态 / 骨架 ---------- */
- .empty{padding:var(--sp-8) var(--sp-4);text-align:center;color:var(--muted)}
- .empty .ic{width:40px;height:40px;color:var(--faint);margin-bottom:var(--sp-3)}
- .empty b{display:block;font-size:var(--fs-15);color:var(--ink-2);margin-bottom:var(--sp-1)}
- .empty p{font-size:var(--fs-13);max-width:320px;margin:0 auto}
- .skel{background:linear-gradient(90deg,var(--surface-2) 25%,var(--surface-hover) 37%,var(--surface-2) 63%);background-size:400% 100%;animation:shimmer 1.6s linear infinite;border-radius:var(--r-sm);height:12px}
- @keyframes shimmer{from{background-position:100% 0}to{background-position:0 0}}
- @media (prefers-reduced-motion:reduce){.skel{animation:none}}
- /* ==========================================================================
- 移动端
- ========================================================================== */
- .device-mb{width:390px}
- .mb{width:390px;height:844px;background:var(--canvas);display:flex;flex-direction:column;position:relative}
- .mb-status{height:38px;display:flex;align-items:center;justify-content:space-between;padding:0 var(--mb-gutter);font-size:var(--fs-12);color:var(--ink-2);background:var(--surface);font-weight:600}
- .mb-nav{min-height:var(--mb-navbar-h);background:var(--surface);border-bottom:1px solid var(--edge);display:flex;align-items:center;padding:var(--mb-safe-top) var(--sp-3) 0;gap:var(--sp-2);flex-shrink:0}
- .mb-nav-t{flex:1;font-size:var(--fs-17);font-weight:700;letter-spacing:-.01em;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .mb-icon-btn{width:var(--touch-min);height:var(--touch-min);display:grid;place-items:center;color:var(--ink-2);flex-shrink:0;border-radius:var(--r-sm)}
- .mb-icon-btn:active{background:var(--surface-hover)}
- .mb-body{flex:1;overflow-y:auto;overscroll-behavior:contain}
- .mb-body::-webkit-scrollbar{width:0}
- /* 会话为全屏详情(FR-04):该视图激活时收起 TabBar
- 注意 tabbar 是 .view 的兄弟节点,故用 :has() 选择器 */
- .mb:has(>.view[data-view="chat"]:not([hidden]))>.mb-tabbar{display:none}
- .mb-tabbar{min-height:var(--mb-tabbar-h);background:var(--surface);border-top:1px solid var(--edge);display:flex;flex-shrink:0;padding-bottom:var(--mb-safe-bottom)}
- .mb-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;font-size:var(--fs-11);color:var(--faint);min-height:var(--touch-min);position:relative}
- .mb-tab.on{color:var(--primary);font-weight:650}
- .mb-tab .ic{width:21px;height:21px}
- .mb-tab.has-dot::after{content:"";position:absolute;top:7px;right:calc(50% - 16px);width:7px;height:7px;border-radius:50%;background:var(--danger)}
- .mb-cell{display:flex;gap:var(--sp-3);padding:var(--sp-3) var(--mb-gutter);min-height:var(--mb-list-h-2);background:var(--surface);border-bottom:1px solid var(--edge);align-items:center;width:100%;text-align:left}
- .mb-cell:active{background:var(--surface-hover)}
- .mb-cell.warn{border-left:3px solid var(--warning)}
- .mb-cell.err{border-left:3px solid var(--danger)}
- .mb-cb{flex:1;min-width:0}
- .mb-ct{font-size:var(--fs-15);font-weight:600;display:flex;align-items:center;gap:var(--sp-2)}
- .mb-ct .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
- .mb-cd{font-size:var(--fs-13);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:var(--sp-1)}
- .mb-cr{font-size:var(--fs-12);color:var(--faint);align-self:flex-start;margin-top:var(--sp-1);flex-shrink:0}
- .mb-sect{display:flex;align-items:baseline;justify-content:space-between;padding:var(--sp-4) var(--mb-gutter) var(--sp-2)}
- .mb-sect b{font-size:var(--fs-15);font-weight:700}
- .mb-sect a{font-size:var(--fs-13);color:var(--primary);font-weight:600}
- .mb-gutter{padding:var(--mb-gutter)}
- .mb-banner{margin:var(--mb-gutter) var(--mb-gutter) 0;background:var(--warning-subtle);border:1px solid color-mix(in srgb,var(--warning) 35%,transparent);border-radius:var(--r-md);padding:var(--sp-3);display:flex;gap:var(--sp-3);align-items:center;width:auto;text-align:left}
- .mb-banner .ic{color:var(--warning)}
- .mb-banner b{font-size:var(--fs-13);color:var(--warning);display:block}
- .mb-banner span{font-size:var(--fs-12);color:var(--ink-2)}
- .mb-input{background:var(--surface);border-top:1px solid var(--edge);padding:var(--sp-3) var(--mb-gutter) calc(var(--sp-3) + var(--mb-safe-bottom));display:flex;gap:var(--sp-2);align-items:flex-end;flex-shrink:0}
- .mb-input-x{flex:1;background:var(--surface-2);border-radius:var(--r-lg);padding:var(--sp-3) var(--sp-4);font-size:16px;line-height:1.5;border:0;outline:none;resize:none;max-height:110px;min-height:44px;overflow-y:auto}
- .mb-input-x::placeholder{color:var(--faint)}
- .mb-send{width:44px;height:44px;border-radius:var(--r-sm);background:var(--primary);color:var(--inverse);display:grid;place-items:center;flex-shrink:0}
- /* 胶囊视觉 28px,触达区由 .chip::after 撑到 44px;行高须 ≥ 触达区,避免溢出压到列表 */
- .mb-tabs{display:flex;align-items:center;gap:var(--sp-2);min-height:calc(var(--touch-min) + var(--sp-2) * 2);padding:var(--sp-2) var(--mb-gutter);overflow-x:auto;background:var(--surface);border-bottom:1px solid var(--edge);flex-shrink:0}
- .mb-tabs::-webkit-scrollbar{height:0}
- .mb-list-h{font-size:var(--fs-12);font-weight:700;color:var(--faint);padding:var(--sp-3) var(--mb-gutter) var(--sp-2);letter-spacing:.04em}
- .mb-group{background:var(--surface);border-radius:var(--r-md);margin:0 var(--mb-gutter) var(--mb-gutter);overflow:hidden;border:1px solid var(--edge)}
- .mb-line{display:flex;align-items:center;gap:var(--sp-3);padding:var(--sp-3) var(--mb-gutter);min-height:var(--mb-list-h-1);font-size:var(--fs-15);width:100%;text-align:left;border-bottom:1px solid var(--edge)}
- .mb-line:last-child{border-bottom:0}
- .mb-line:active{background:var(--surface-hover)}
- .mb-line .k{flex:1;color:var(--ink)}
- .mb-line .v{color:var(--muted);font-size:var(--fs-13);display:flex;align-items:center;gap:var(--sp-2)}
- .mb-line.danger .k{color:var(--danger)}
- .mb-card{background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);padding:var(--sp-4);box-shadow:var(--shadow-card)}
- .mb-drawer{position:absolute;left:0;right:0;bottom:0;background:var(--surface);border-top:1px solid var(--edge);border-radius:var(--r-sheet) var(--r-sheet) 0 0;box-shadow:var(--shadow-overlay);transform:translateY(101%);transition:transform .26s cubic-bezier(.16,1,.3,1);max-height:74%;display:flex;flex-direction:column;z-index:var(--z-modal)}
- .mb-drawer.open{transform:none}
- @media (prefers-reduced-motion:reduce){.mb-drawer{transition:none}}
- .mb-drawer-h{padding:var(--sp-4) var(--sp-4) var(--sp-2);display:flex;align-items:center;gap:var(--sp-3);border-bottom:1px solid var(--edge)}
- .mb-drawer-h b{flex:1;font-size:var(--fs-17);font-weight:700}
- .mb-drawer-b{overflow-y:auto;padding:var(--sp-2) 0 var(--sp-4)}
- .mb-scrim{position:absolute;inset:0;background:var(--scrim);opacity:0;pointer-events:none;transition:opacity .26s;z-index:var(--z-mask)}
- .mb-scrim.on{opacity:1;pointer-events:auto}
- .mb-role{display:inline-flex;align-items:center;gap:var(--sp-1)}
- /* 移动端头像尺寸(§3.1:列表 44 / 详情 64;桌面 40 不在此覆盖) */
- .mb .av{width:var(--mb-avatar);height:var(--mb-avatar);font-size:var(--fs-15);border-radius:var(--r-md)}
- .mb .av-sm{width:36px;height:36px;font-size:var(--fs-12)}
- .mb .av-lg{width:var(--mb-avatar-lg);height:var(--mb-avatar-lg);font-size:var(--fs-26)}
- /* 抽屉底部含安全区 */
- .mb-drawer{padding-bottom:var(--mb-safe-bottom)}
- /* ---------- 登录 ---------- */
- .login-stage{display:flex;flex-direction:column;gap:var(--sp-8);align-items:center}
- .login-dk{width:100%;min-height:720px;background:var(--canvas);position:relative;display:flex;flex-wrap:wrap;overflow:hidden}
- .login-dk::before{content:"";position:absolute;inset:0;background:
- radial-gradient(680px 420px at 78% 12%, color-mix(in srgb,var(--primary) 16%,transparent), transparent 70%),
- radial-gradient(520px 420px at 12% 88%, color-mix(in srgb,var(--info) 12%,transparent), transparent 70%);}
- .login-brand{position:relative;flex:1 1 480px;min-width:0;padding:var(--sp-8);display:flex;flex-direction:column;justify-content:center;gap:var(--sp-4)}
- .login-brand .lg{display:flex;align-items:center;gap:var(--sp-3)}
- .login-brand .lg .brand-mark{width:44px;height:44px;font-size:var(--fs-20);border-radius:var(--r-md)}
- .login-brand h1{font-size:var(--fs-26);font-weight:750;letter-spacing:-.02em;line-height:1.3}
- .login-brand p{font-size:var(--fs-15);color:var(--ink-2);line-height:1.8;max-width:420px}
- .login-points{display:flex;flex-direction:column;gap:var(--sp-3);margin-top:var(--sp-4)}
- .login-point{display:flex;gap:var(--sp-3);align-items:center;font-size:var(--fs-13);color:var(--ink-2)}
- .login-point .ic{color:var(--primary)}
- .login-panel{position:relative;flex:1 1 360px;max-width:440px;background:var(--surface);border-left:1px solid var(--edge);display:flex;flex-direction:column;justify-content:center;padding:var(--sp-8);box-shadow:var(--shadow-overlay)}
- .login-panel h2{font-size:var(--fs-20);font-weight:700;letter-spacing:-.01em}
- .login-panel .sub{font-size:var(--fs-13);color:var(--muted);margin-top:var(--sp-1);margin-bottom:var(--sp-5)}
- .field{margin-bottom:var(--sp-4)}
- .field label{display:block;font-size:var(--fs-13);font-weight:600;color:var(--ink-2);margin-bottom:var(--sp-2)}
- .field .box{display:flex;align-items:center;gap:var(--sp-2);height:44px;border:1px solid var(--edge);border-radius:var(--r-sm);padding:0 var(--sp-3);background:var(--surface);transition:.15s}
- .field .box:focus-within{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-ring)}
- .field .box .ic{color:var(--faint)}
- .field input{flex:1;border:0;background:none;outline:none;font-size:16px;min-width:0}
- .field .code-btn{color:var(--primary);font-size:var(--fs-13);font-weight:650;white-space:nowrap;padding:0 var(--sp-1)}
- .field .code-btn:disabled{color:var(--faint);cursor:default}
- .field .err{font-size:var(--fs-12);color:var(--danger);margin-top:var(--sp-1);display:flex;align-items:center;gap:var(--sp-1)}
- .login-alt{margin-top:var(--sp-5);padding-top:var(--sp-4);border-top:1px solid var(--edge);font-size:var(--fs-12);color:var(--muted);line-height:1.9}
- .login-alt code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--surface-2);padding:1px 5px;border-radius:4px;color:var(--ink-2)}
- .mb-login{width:390px;height:844px;background:var(--surface);display:flex;flex-direction:column;padding:var(--sp-8) var(--mb-gutter) var(--sp-6)}
- .mb-login .lg{display:flex;align-items:center;gap:var(--sp-3);margin-bottom:var(--sp-8)}
- .mb-login h1{font-size:var(--fs-26);font-weight:750;letter-spacing:-.02em;line-height:1.3}
- .mb-login p.sub{font-size:var(--fs-13);color:var(--muted);margin-top:var(--sp-2);margin-bottom:var(--sp-6);line-height:1.7}
- .mb-login .sp{flex:1}
- .colorswatch{display:flex;gap:var(--sp-2);flex-wrap:wrap;margin-top:var(--sp-3)}
- .sw{width:44px;height:44px;border-radius:var(--r-sm);border:1px solid var(--edge);display:grid;place-items:end center;padding-bottom:var(--sp-1);font-size:var(--fs-11);color:var(--inverse);font-weight:700}
- /* ==========================================================================
- 兜底 + 演示外壳响应式
- ========================================================================== */
- /* hidden 必须压过上面的 display:flex —— UA 对 [hidden] 只有 display:none,
- 特异性(0,1,0)低于 .dk>.view(0,2,0),不兜底会导致"隐藏的视图仍占位" */
- [hidden]{display:none !important}
- /* 演示外壳窄窗:左侧清单收为底部横向条。
- 注意:设备画布内保持 1440×900 固定设备态(评审用),
- 真正的桌面降级阶梯(1280/1150/940/768)属真机实现,见《双端布局规范》§四 */
- @media (max-width:1180px){ .app{grid-template-columns:208px 1fr} }
- @media (max-width:920px){
- .app{display:flex;flex-direction:column;height:auto;min-height:100vh}
- .topbar{order:1}
- .stage{order:2;padding:var(--sp-4)}
- .sidenav{order:3;display:flex;gap:var(--sp-2);overflow-x:auto;padding:var(--sp-2) var(--sp-3);border-top:1px solid var(--edge);border-right:0}
- .sidenav::-webkit-scrollbar{height:0}
- .nav-group,.nav-idx{display:none}
- .nav-i{width:auto;white-space:nowrap;flex-shrink:0}
- }
- </style>
- </head>
- <body>
- <!-- ============ 图标精灵 ============ -->
- <svg width="0" height="0" style="position:absolute" aria-hidden="true">
- <symbol id="i-chat" viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></symbol>
- <symbol id="i-users" viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></symbol>
- <symbol id="i-folder" viewBox="0 0 24 24"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></symbol>
- <symbol id="i-bell" viewBox="0 0 24 24"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></symbol>
- <symbol id="i-grid" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/></symbol>
- <symbol id="i-task" viewBox="0 0 24 24"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></symbol>
- <symbol id="i-box" viewBox="0 0 24 24"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><path d="M3.27 6.96 12 12.01l8.73-5.05M12 22.08V12"/></symbol>
- <symbol id="i-user" viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></symbol>
- <symbol id="i-search" viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></symbol>
- <symbol id="i-send" viewBox="0 0 24 24"><path d="M22 2 11 13"/><path d="M22 2l-7 20-4-9-9-4z"/></symbol>
- <symbol id="i-plus" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></symbol>
- <symbol id="i-more" viewBox="0 0 24 24"><circle cx="5" cy="12" r="1.6" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1.6" fill="currentColor" stroke="none"/><circle cx="19" cy="12" r="1.6" fill="currentColor" stroke="none"/></symbol>
- <symbol id="i-chev-d" viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></symbol>
- <symbol id="i-chev-r" viewBox="0 0 24 24"><path d="M9 18l6-6-6-6"/></symbol>
- <symbol id="i-chev-l" viewBox="0 0 24 24"><path d="M15 18l-6-6 6-6"/></symbol>
- <symbol id="i-refresh" viewBox="0 0 24 24"><path d="M23 4v6h-6M1 20v-6h6"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></symbol>
- <symbol id="i-download" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5M12 15V3"/></symbol>
- <symbol id="i-alert" viewBox="0 0 24 24"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><path d="M12 9v4M12 17h.01"/></symbol>
- <symbol id="i-ban" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M4.93 4.93l14.14 14.14"/></symbol>
- <symbol id="i-check" viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></symbol>
- <symbol id="i-circle" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/></symbol>
- <symbol id="i-play" viewBox="0 0 24 24"><path d="M6 3l14 9-14 9z"/></symbol>
- <symbol id="i-external" viewBox="0 0 24 24"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><path d="M15 3h6v6M10 14 21 3"/></symbol>
- <symbol id="i-cpu" viewBox="0 0 24 24"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3"/></symbol>
- <symbol id="i-db" viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></symbol>
- <symbol id="i-wallet" viewBox="0 0 24 24"><path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h4v-4z"/></symbol>
- <symbol id="i-zap" viewBox="0 0 24 24"><path d="M13 2 3 14h9l-1 8 10-12h-9z"/></symbol>
- <symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></symbol>
- <symbol id="i-panel" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M15 3v18"/></symbol>
- <symbol id="i-moon" viewBox="0 0 24 24"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></symbol>
- <symbol id="i-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4.5"/><path d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/></symbol>
- <symbol id="i-eye" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></symbol>
- <symbol id="i-logout" viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><path d="M16 17l5-5-5-5M21 12H9"/></symbol>
- <symbol id="i-smartphone" viewBox="0 0 24 24"><rect x="5" y="2" width="14" height="20" rx="2.5"/><path d="M12 18h.01"/></symbol>
- <symbol id="i-monitor" viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></symbol>
- <symbol id="i-file" viewBox="0 0 24 24"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M13 2v7h7"/></symbol>
- <symbol id="i-image" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></symbol>
- <symbol id="i-shield" viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></symbol>
- <symbol id="i-filter" viewBox="0 0 24 24"><path d="M22 3H2l8 9.46V19l4 2v-8.54z"/></symbol>
- <symbol id="i-phone" viewBox="0 0 24 24"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.8 19.8 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.12 4.18 2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.9.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></symbol>
- <symbol id="i-key" viewBox="0 0 24 24"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3"/></symbol>
- <symbol id="i-download-box" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M7 10l5 5 5-5M12 15V3"/></symbol>
- <symbol id="i-timeline" viewBox="0 0 24 24"><path d="M3 6h13M3 12h10M3 18h7"/><circle cx="19" cy="6" r="2"/><circle cx="18" cy="12" r="2"/></symbol>
- </svg>
- <!-- ============ 顶部工具条(演示外壳,非产品 UI) ============ -->
- <div class="app">
- <header class="topbar">
- <div class="brand">
- <span class="brand-mark">F</span>
- <span class="brand-t">Fmode v2</span>
- <span class="brand-s">MVP Demo · 双端 11 屏</span>
- </div>
- <div class="top-sp"></div>
- <div class="tool" role="tablist" aria-label="端切换">
- <button class="tool-i on" data-end="login" role="tab">登录</button>
- <button class="tool-i" data-end="dk" role="tab">桌面端</button>
- <button class="tool-i" data-end="mb" role="tab">移动端</button>
- </div>
- <div class="top-sp"></div>
- <button class="tbtn" id="btnNotes" title="显示设计依据标注"><svg class="ic"><use href="#i-eye"/></svg></button>
- <button class="tbtn" id="btnTheme" title="切换明暗"><svg class="ic"><use href="#i-moon"/></svg></button>
- </header>
- <!-- ============ 左侧屏幕清单 ============ -->
- <nav class="sidenav" aria-label="屏幕清单">
- <div class="nav-group">通用</div>
- <button class="nav-i on" data-end="login" data-mod="login"><svg class="ic"><use href="#i-shield"/></svg><span>登录</span><span class="nav-idx">1</span></button>
- <div class="nav-group">桌面端 · 1440×900</div>
- <button class="nav-i" data-end="dk" data-mod="chat"><svg class="ic"><use href="#i-chat"/></svg><span>会话(四栏)</span><span class="nav-idx">2</span></button>
- <button class="nav-i" data-end="dk" data-mod="workbench"><svg class="ic"><use href="#i-grid"/></svg><span>工作台</span><span class="nav-idx">3</span></button>
- <button class="nav-i" data-end="dk" data-mod="tasks"><svg class="ic"><use href="#i-task"/></svg><span>任务看板</span><span class="nav-idx">4</span></button>
- <button class="nav-i" data-end="dk" data-mod="deliverables"><svg class="ic"><use href="#i-box"/></svg><span>成果</span><span class="nav-idx">5</span></button>
- <button class="nav-i" data-end="dk" data-mod="contacts"><svg class="ic"><use href="#i-users"/></svg><span>通讯录</span><span class="nav-idx">6</span></button>
- <div class="nav-group">移动端 · 390×844</div>
- <button class="nav-i" data-end="mb" data-mod="home"><svg class="ic"><use href="#i-grid"/></svg><span>聚合首页</span><span class="nav-idx">7</span></button>
- <button class="nav-i" data-end="mb" data-mod="chat"><svg class="ic"><use href="#i-chat"/></svg><span>会话</span><span class="nav-idx">8</span></button>
- <button class="nav-i" data-end="mb" data-mod="workbench"><svg class="ic"><use href="#i-grid"/></svg><span>工作台</span><span class="nav-idx">9</span></button>
- <button class="nav-i" data-end="mb" data-mod="contacts"><svg class="ic"><use href="#i-users"/></svg><span>通讯录</span><span class="nav-idx">10</span></button>
- <button class="nav-i" data-end="mb" data-mod="mine"><svg class="ic"><use href="#i-user"/></svg><span>我的</span><span class="nav-idx">11</span></button>
- </nav>
- <!-- ============ 舞台 ============ -->
- <main class="stage" id="stage">
- <!-- ==================== 通用 1 · 登录(双形态) ==================== -->
- <section class="screen is-on" data-end="login">
- <div class="login-stage">
- <!-- 桌面形态 -->
- <div class="device" style="width:100%;max-width:1200px">
- <div class="device-cap"><b>登录 · 桌面形态</b><span>同页双形态 · 验证码 / Token 直登</span><span class="badge badge-n" style="margin-left:auto">FR-02</span></div>
- <div class="login-dk">
- <div class="login-brand">
- <div class="lg"><span class="brand-mark">F</span><span style="font-size:var(--fs-20);font-weight:800;letter-spacing:-.02em">Fmode</span></div>
- <h1>人机共生 IM 中枢</h1>
- <p>通过会话协作数字生命,实时掌握它的运行状态与交付成果。</p>
- <div class="login-points">
- <div class="login-point"><svg class="ic"><use href="#i-chat"/></svg>与数字生命一对一会话,随时下达指令</div>
- <div class="login-point"><svg class="ic"><use href="#i-box"/></svg>交付成果独立归档,与聊天解耦、随时取用</div>
- <div class="login-point"><svg class="ic"><use href="#i-grid"/></svg>工作台与任务看板,一眼看清谁在忙、谁卡住</div>
- </div>
- </div>
- <div class="login-panel">
- <h2>登录</h2>
- <p class="sub">验证码登录,或使用 Token 直登</p>
- <div class="tabs login-tabs" style="margin-bottom:var(--sp-5)">
- <button class="tab on" data-method="code">验证码登录</button>
- <button class="tab" data-method="token">Token 直登</button>
- </div>
- <div data-login-method="code">
- <div class="field">
- <label for="lg-phone">手机号</label>
- <div class="box"><svg class="ic"><use href="#i-phone"/></svg><input id="lg-phone" value="138 0000 0000"></div>
- </div>
- <div class="field">
- <label for="lg-code">验证码</label>
- <div class="box" style="border-color:var(--danger)">
- <svg class="ic" style="color:var(--danger)"><use href="#i-key"/></svg>
- <input id="lg-code" value="4821" aria-invalid="true" aria-describedby="lg-code-err">
- <button class="code-btn">重新获取</button>
- </div>
- <div class="err" id="lg-code-err"><svg class="ic ic-sm"><use href="#i-alert"/></svg>验证码错误,请重新输入</div>
- </div>
- <button class="btn btn-primary btn-block">登 录</button>
- </div>
- <div data-login-method="token" hidden>
- <div class="field">
- <label for="lg-token">访问 Token</label>
- <div class="box"><svg class="ic"><use href="#i-key"/></svg><input id="lg-token" placeholder="粘贴 Token,回车直登"></div>
- </div>
- <button class="btn btn-primary btn-block">登 录</button>
- </div>
- <div class="login-alt">
- <b style="color:var(--ink-2)">错误文案必须明确(AC-02.6,不得静默失败)</b><br>
- 手机号格式不正确 · 验证码错误 · 验证码已过期 · <code>#token=</code> 无效或已失效<br>
- <span style="color:var(--faint)">含 <code>#token=</code> 自动登录时,成功后清空地址栏(AC-02.2)</span>
- </div>
- </div>
- </div>
- </div>
- <!-- 移动形态 -->
- <div class="device device-mb" style="height:auto">
- <div class="device-cap"><b>登录 · 移动形态</b><span class="badge badge-n" style="margin-left:auto">FR-02</span></div>
- <div class="mb-login">
- <div class="lg"><span class="brand-mark">F</span><span style="font-size:var(--fs-20);font-weight:800;letter-spacing:-.02em">Fmode</span></div>
- <h1>欢迎回来</h1>
- <p class="sub">使用手机号验证码登录,与你的数字生命继续协作。</p>
- <div class="field">
- <label for="mb-phone">手机号</label>
- <div class="box"><svg class="ic"><use href="#i-phone"/></svg><input id="mb-phone" value="138 0000 0000"></div>
- </div>
- <div class="field">
- <label for="mb-code">验证码</label>
- <div class="box"><svg class="ic"><use href="#i-key"/></svg><input id="mb-code" placeholder="6 位验证码"><button class="code-btn">获取验证码</button></div>
- </div>
- <button class="btn btn-primary btn-block">登 录</button>
- <div class="sp"></div>
- <p style="font-size:var(--fs-12);color:var(--faint);text-align:center;line-height:1.8">
- 登录即表示同意服务条款 · v2.0.0
- </p>
- </div>
- </div>
- </div>
- <div class="notes">
- <div class="notes-h"><svg class="ic"><use href="#i-eye"/></svg>设计依据与留痕</div>
- <div class="note">
- <span class="ref">FR-02</span><span class="ref">AC-02.1</span><span class="ref">AC-02.2</span><span class="ref">AC-02.6</span><span class="ref">AC-02.7</span><br>
- <b>同页双形态</b>:桌面左右分栏(品牌叙事 + 表单),移动全屏单列。两种登录方式(验证码 / Token)在桌面用 Tab 切换。<br>
- 错误态就地展示、文案明确(<b>验证码错误</b> 为示例),不静默失败;重复提交需防抖。
- </div>
- <div class="note ok">
- <b>无障碍</b>:输入控件实际字号 <b>≥16px</b>(iOS 聚焦不放大,见《双端布局规范》§3.4);错误字段带 <code>aria-invalid</code> + <code>aria-describedby</code>;所有按钮触达区 ≥44px。
- </div>
- </div>
- </section>
- <!-- ==================== 桌面端(5 屏) ==================== -->
- <section class="screen" data-end="dk">
- <div class="device" id="dkDevice" style="max-width:1464px">
- <div class="device-cap">
- <b>桌面端 · 1440 × 900</b>
- <span id="dkCapSub">四栏骨架:导航 56 / 列表 300 / 主区 flex ≥480 / 右栏 340</span>
- <span class="badge badge-n" style="margin-left:auto">双端双套 · ADR-004</span>
- </div>
- <div class="device-dk" id="dkBox">
- <div class="dk" id="dkShell">
- <!-- 导航轨(7 模块 + 我的,默认图标态 56px) -->
- <nav class="rail" aria-label="主导航">
- <div class="rail-logo" title="Fmode">F</div>
- <button class="rail-i on" data-mod="chat" title="会话"><svg class="ic"><use href="#i-chat"/></svg></button>
- <button class="rail-i" data-mod="contacts" title="通讯录"><svg class="ic"><use href="#i-users"/></svg></button>
- <button class="rail-i" data-mod="projects" title="项目"><svg class="ic"><use href="#i-folder"/></svg></button>
- <button class="rail-i has-dot" data-mod="events" title="事件(有新告警)"><svg class="ic"><use href="#i-bell"/></svg></button>
- <button class="rail-i" data-mod="workbench" title="工作台"><svg class="ic"><use href="#i-grid"/></svg></button>
- <button class="rail-i" data-mod="tasks" title="任务看板"><svg class="ic"><use href="#i-task"/></svg></button>
- <button class="rail-i" data-mod="deliverables" title="成果"><svg class="ic"><use href="#i-box"/></svg></button>
- <div class="rail-sp"></div>
- <button class="rail-i" data-mod="mine" title="我的"><svg class="ic"><use href="#i-user"/></svg></button>
- </nav>
- <!-- ===== 桌面屏 2 · 会话(四栏) ===== -->
- <div class="view" data-view="chat">
- <aside class="pane pane-list">
- <div class="pane-head"><label class="search"><svg class="ic ic-sm"><use href="#i-search"/></svg><input placeholder="搜索会话"></label></div>
- <div class="pane-body">
- <div class="group-label">数字生命</div>
- <button class="row on">
- <span class="av av-bot av-on">数</span>
- <span class="row-meta">
- <span class="row-name"><span class="nm">数据分析助手</span></span>
- <span class="row-prev">已完成 3 份报表,正在生成第 4 份</span>
- </span>
- <span class="row-time">10:24</span>
- </button>
- <button class="row row-err">
- <span class="av av-bot av-off av-danger">运</span>
- <span class="row-meta">
- <span class="row-name"><span class="nm">运维值守</span></span>
- <span class="row-prev is-danger">任务失败:依赖服务不可用</span>
- </span>
- <span class="row-time">09:51</span>
- </button>
- <button class="row">
- <span class="av av-bot av-idle">文</span>
- <span class="row-meta">
- <span class="row-name"><span class="nm">文案生成器</span></span>
- <span class="row-prev">空闲,等待新任务</span>
- </span>
- <span class="row-time">昨天</span>
- </button>
- <div class="group-label">同事</div>
- <button class="row">
- <span class="av av-user av-on">李</span>
- <span class="row-meta">
- <span class="row-name"><span class="nm">李工</span><span class="badge badge-n">同事</span></span>
- <span class="row-prev">名下 2 个数字生命</span>
- </span>
- <span class="row-time">昨天</span>
- </button>
- </div>
- </aside>
- <section class="pane pane-main">
- <header class="chat-head">
- <span class="av av-bot av-on av-sm">数</span>
- <div class="chat-title">
- <div class="t-name">数据分析助手</div>
- <div class="t-sub"><span class="dot dot-success"></span>运行中 · 最后活动 2 分钟前</div>
- </div>
- <div class="head-actions">
- <button class="icon-btn" title="搜索消息"><svg class="ic"><use href="#i-search"/></svg></button>
- <button class="icon-btn" title="更多"><svg class="ic"><use href="#i-more"/></svg></button>
- </div>
- </header>
- <!-- L2 · 状态条:全页面唯一渲染「在干嘛」的地方 -->
- <div class="statusbar" role="status">
- <span class="pulse"></span>
- <div class="sb-text">
- <b>正在生成第 4 份季度报表</b>
- <span>已用时 3 分 12 秒 · 点击查看步骤</span>
- </div>
- <svg class="ic sb-chev"><use href="#i-chev-d"/></svg>
- </div>
- <ol class="steps">
- <li class="step done"><span class="step-m">✓</span><span>拉取数据源<span class="step-time">1.2s</span></span></li>
- <li class="step done"><span class="step-m">✓</span><span>清洗与聚合<span class="step-time">8.4s</span></span></li>
- <li class="step cur"><span class="step-m">▸</span><span>渲染图表并导出 PDF</span></li>
- <li class="step"><span class="step-m">○</span><span>上传至成果库</span></li>
- </ol>
- <div class="msgs" id="dkChatMsgs">
- <div class="sys-msg">今天 10:20</div>
- <div class="msg">
- <span class="av av-bot av-sm">数</span>
- <div class="bubble">早上好,我已开始处理今天的报表任务。</div>
- </div>
- <div class="msg is-me">
- <div class="bubble">把第 3 季度的也一起做了</div>
- <span class="av av-user av-sm">胡</span>
- </div>
- <div class="msg">
- <span class="av av-bot av-sm">数</span>
- <div class="bubble">收到,第 3 季度已排入队列。当前正在处理第 4 份,预计还需数分钟。</div>
- </div>
- <div class="tool-call"><svg class="ic ic-sm"><use href="#i-play"/></svg>工具调用 · 读取 sales_q4.xlsx(1.2s)· 已折叠</div>
- <div class="sys-msg">工具调用结果走系统消息样式,不占主视觉</div>
- <div class="msg">
- <span class="av av-bot av-sm">数</span>
- <div class="bubble">第 4 份报表已进入「导出 PDF」阶段,完成后会自动归档到成果库。</div>
- </div>
- <div class="msg is-me">
- <div class="bubble">好,完成后发我一份</div>
- <span class="av av-user av-sm">胡</span>
- </div>
- </div>
- <div class="composer">
- <button class="icon-btn" title="发送文件"><svg class="ic"><use href="#i-plus"/></svg></button>
- <textarea class="composer-input" rows="1" placeholder="发消息…(Enter 发送 / Shift+Enter 换行)"></textarea>
- <button class="send-btn" title="发送"><svg class="ic"><use href="#i-send"/></svg></button>
- </div>
- </section>
- <aside class="pane pane-aside">
- <div class="aside-h"><b>实况</b><svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-panel"/></svg></div>
- <div class="aside-b">
- <div class="sect-t">运行指标</div>
- <div class="metric"><span class="metric-k"><svg class="ic ic-sm"><use href="#i-cpu"/></svg>CPU</span><span class="metric-v">12%</span></div>
- <div class="bar"><i style="width:12%"></i></div>
- <div class="metric"><span class="metric-k"><svg class="ic ic-sm"><use href="#i-db"/></svg>内存</span><span class="metric-v">34%</span></div>
- <div class="bar"><i style="width:34%"></i></div>
- <div class="metric"><span class="metric-k"><svg class="ic ic-sm"><use href="#i-wallet"/></svg>余额</span><span class="metric-v" style="color:var(--primary);display:inline-flex;align-items:center;gap:var(--sp-1)">¥128.50<svg class="ic ic-sm"><use href="#i-external"/></svg></span></div>
- <div class="metric"><span class="metric-k"><svg class="ic ic-sm"><use href="#i-zap"/></svg>通道</span><span class="metric-v" style="display:inline-flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-success"></span>已连接</span></div>
- <div class="divider"></div>
- <div class="sect-t">最近成果</div>
- <div class="file-row"><span class="av av-file av-sm">PDF</span><span style="flex:1;min-width:0"><span class="nm" style="display:block">Q2 季度报表.pdf</span><span class="tm">10:12 · 1.2 MB</span></span></div>
- <div class="file-row"><span class="av av-file av-sm">XLS</span><span style="flex:1;min-width:0"><span class="nm" style="display:block">销售趋势.xlsx</span><span class="tm">昨天 · 340 KB</span></span></div>
- <div class="divider"></div>
- <div class="sect-t">上下文用量</div>
- <div class="metric"><span class="metric-k">窗口占用</span><span class="metric-v">62%</span></div>
- <div class="bar"><i style="width:62%"></i></div>
- <div class="sect-t" style="margin-top:var(--sp-5)">可用工具</div>
- <div style="display:flex;flex-wrap:wrap;gap:var(--sp-1)">
- <span class="badge badge-n">读取文件</span>
- <span class="badge badge-n">执行代码</span>
- <span class="badge badge-n">联网检索</span>
- </div>
- </div>
- </aside>
- </div>
- <!-- ===== 桌面屏 3 · 工作台 ===== -->
- <div class="view" data-view="workbench" hidden>
- <div class="page">
- <div class="page-h">
- <div class="page-t">
- <h2>工作台</h2>
- <p>名下 4 个数字生命的实时状态 · 双端同一实况服务,口径一致(含 token 用量)</p>
- </div>
- <button class="btn btn-ghost"><svg class="ic ic-sm"><use href="#i-refresh"/></svg>刷新</button>
- </div>
- <div class="stat-row">
- <div class="stat"><div class="stat-k">数字生命</div><div class="stat-v">4<small>个</small></div></div>
- <div class="stat"><div class="stat-k"><span class="dot dot-success"></span>运行中</div><div class="stat-v">2</div></div>
- <div class="stat"><div class="stat-k"><span class="dot dot-warning"></span>空闲</div><div class="stat-v">1</div></div>
- <div class="stat"><div class="stat-k"><span class="dot dot-danger"></span>异常</div><div class="stat-v" style="color:var(--danger)">1</div></div>
- <div class="stat"><div class="stat-k">今日 token</div><div class="stat-v">128<small>k</small></div></div>
- </div>
- <div class="card-grid">
- <!-- 卡片 1 运行中 -->
- <article class="wcard">
- <div class="wcard-h">
- <span class="av av-bot av-on">数</span>
- <span class="nm"><b>数据分析助手</b><span>数据分析 · 3 个成果</span></span>
- <span class="badge badge-s">运行中</span>
- </div>
- <div class="wcard-task"><svg class="ic ic-sm"><use href="#i-play"/></svg>正在生成第 4 份季度报表(3:12)</div>
- <div class="wcard-metrics">
- <div><div class="wcard-f"><span>CPU</span><b>12%</b></div><div class="bar"><i style="width:12%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>34%</b></div><div class="bar"><i style="width:34%"></i></div></div>
- </div>
- <div class="wcard-foot">
- <span style="flex:1">余额 ¥128.50</span>
- <span style="display:inline-flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-success"></span>通道正常</span>
- </div>
- </article>
- <!-- 卡片 2 异常 -->
- <article class="wcard edge-err">
- <div class="wcard-h">
- <span class="av av-bot av-off av-danger">运</span>
- <span class="nm"><b>运维值守</b><span>运维 · 1 个成果</span></span>
- <span class="badge badge-d">异常</span>
- </div>
- <div class="wcard-task" style="color:var(--danger)"><svg class="ic ic-sm" style="color:var(--danger)"><use href="#i-alert"/></svg>任务失败:依赖服务不可用,连续失败 41 次</div>
- <div class="wcard-metrics">
- <div><div class="wcard-f"><span>CPU</span><b>88%</b></div><div class="bar warning"><i style="width:88%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>71%</b></div><div class="bar"><i style="width:71%"></i></div></div>
- </div>
- <div class="wcard-foot">
- <span style="flex:1">余额 ¥12.00</span>
- <span style="color:var(--danger);display:inline-flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-danger"></span>通道异常</span>
- </div>
- </article>
- <!-- 卡片 3 空闲 -->
- <article class="wcard edge-warn">
- <div class="wcard-h">
- <span class="av av-bot av-idle">文</span>
- <span class="nm"><b>文案生成器</b><span>内容 · 0 个成果</span></span>
- <span class="badge badge-w">空闲</span>
- </div>
- <div class="wcard-task"><svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-clock"/></svg>暂无任务,等待派发(请到会话页下达指令)</div>
- <div class="wcard-metrics">
- <div><div class="wcard-f"><span>CPU</span><b>2%</b></div><div class="bar"><i style="width:2%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>18%</b></div><div class="bar"><i style="width:18%"></i></div></div>
- </div>
- <div class="wcard-foot">
- <span style="flex:1">余额 ¥56.20</span>
- <span style="display:inline-flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-success"></span>通道正常</span>
- </div>
- </article>
- <!-- 卡片 4 运行中 -->
- <article class="wcard">
- <div class="wcard-h">
- <span class="av av-bot av-on">研</span>
- <span class="nm"><b>行业研究员</b><span>研究 · 5 个成果</span></span>
- <span class="badge badge-s">运行中</span>
- </div>
- <div class="wcard-task"><svg class="ic ic-sm"><use href="#i-play"/></svg>汇总本周行业动态(12:40)</div>
- <div class="wcard-metrics">
- <div><div class="wcard-f"><span>CPU</span><b>27%</b></div><div class="bar"><i style="width:27%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>45%</b></div><div class="bar"><i style="width:45%"></i></div></div>
- </div>
- <div class="wcard-foot">
- <span style="flex:1">余额 ¥302.10</span>
- <span style="display:inline-flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-success"></span>通道正常</span>
- </div>
- </article>
- </div>
- </div>
- </div>
- <!-- ===== 桌面屏 4 · 任务看板 ===== -->
- <div class="view" data-view="tasks" data-filter-scope hidden>
- <aside class="pane pane-list">
- <div class="pane-head"><label class="search"><svg class="ic ic-sm"><use href="#i-search"/></svg><input placeholder="搜索任务"></label></div>
- <div style="padding:var(--sp-3) var(--sp-3) var(--sp-2);border-bottom:1px solid var(--edge)">
- <div class="chips">
- <button class="chip on" data-cat="all">全部 21</button>
- <button class="chip" data-cat="running">进行中 2</button>
- <button class="chip chip-w" data-cat="blocked">阻塞 1</button>
- <button class="chip chip-d" data-cat="failed">失败 1</button>
- <button class="chip" data-cat="todo">待办 3</button>
- <button class="chip" data-cat="done">已完成 14</button>
- </div>
- </div>
- <div class="pane-body">
- <button class="task blocked on" data-cat="blocked">
- <span class="task-ico w">⚠</span>
- <span class="task-b">
- <span class="task-t">用户身份对齐 — 手机号登录复用已有超管账号</span>
- <span class="task-m"><span>@fullstack</span><span>未开始</span></span>
- <span class="task-alert w">已阻塞 436 小时 · 等待外部条件</span>
- </span>
- </button>
- <button class="task failed" data-cat="failed">
- <span class="task-ico d">⛔</span>
- <span class="task-b">
- <span class="task-t">定时同步脚本修复</span>
- <span class="task-m"><span>@ops</span><span>09:51</span></span>
- <span class="task-alert d">连续失败 41 次 · 脚本路径不存在</span>
- </span>
- </button>
- <button class="task cur" data-cat="running">
- <span class="task-ico i">▸</span>
- <span class="task-b">
- <span class="task-t">《进化工程》16 章改稿</span>
- <span class="task-m"><span>@writer</span><span>已用时 1h 24m</span></span>
- </span>
- </button>
- <button class="task cur" data-cat="running">
- <span class="task-ico i">▸</span>
- <span class="task-b">
- <span class="task-t">用户画像矩阵校准</span>
- <span class="task-m"><span>@analyst</span><span>已用时 12m</span></span>
- </span>
- </button>
- <button class="task" data-cat="todo">
- <span class="task-ico">○</span>
- <span class="task-b">
- <span class="task-t">双端布局降级阶梯实现</span>
- <span class="task-m"><span>@frontend</span><span>已排期</span></span>
- </span>
- </button>
- <button class="task" data-cat="todo">
- <span class="task-ico">○</span>
- <span class="task-b">
- <span class="task-t">ER 图字段核对</span>
- <span class="task-m"><span>@backend</span><span>待办</span></span>
- </span>
- </button>
- <button class="task done" data-cat="done">
- <span class="task-ico s">✓</span>
- <span class="task-b">
- <span class="task-t">魔镜形象分析系统 V2.0 重写</span>
- <span class="task-m"><span>@fullstack</span><span>昨天完成</span></span>
- </span>
- </button>
- <button class="task done" data-cat="done">
- <span class="task-ico s">✓</span>
- <span class="task-b">
- <span class="task-t">设计令牌收敛为单轨</span>
- <span class="task-m"><span>@design</span><span>10-12 完成</span></span>
- </span>
- </button>
- </div>
- </aside>
- <section class="pane pane-main" style="overflow-y:auto">
- <div class="detail" style="max-width:860px">
- <div class="detail-id">FMODE-318 <svg class="ic ic-sm"><use href="#i-external"/></svg></div>
- <h3 style="margin-top:var(--sp-2)">用户身份对齐 — 手机号登录复用已有超管账号</h3>
- <div style="display:flex;gap:var(--sp-2);margin:var(--sp-3) 0 var(--sp-5);flex-wrap:wrap">
- <span class="badge badge-w"><svg class="ic ic-sm"><use href="#i-alert"/></svg>阻塞</span>
- <span class="badge badge-n">@fullstack</span>
- <span class="badge badge-n">优先级 P2</span>
- <span class="badge badge-n">分支 fix/identity-align</span>
- </div>
- <div class="note warn" style="margin:0 0 var(--sp-5)">
- <b>⚠ 已阻塞 436 小时(约 18 天)</b><br>
- 阻塞类型:等待外部条件 · 连续失败 0 次<br>
- <span style="color:var(--muted)">原因:代码修复已就绪,线上云函数未部署,等待运维窗口</span>
- </div>
- <div class="sect-t">时间三件套</div>
- <dl class="kv" style="margin-bottom:var(--sp-5)">
- <dt>创建</dt><dd>2026-09-24 09:12</dd>
- <dt>开始</dt><dd>2026-09-24 09:40</dd>
- <dt>最后活动</dt><dd>2026-09-26 05:15</dd>
- <dt>所属数字生命</dt><dd style="display:flex;align-items:center;gap:var(--sp-2)"><span class="av av-bot av-sm" style="width:20px;height:20px;font-size:var(--fs-11)">研</span>行业研究员</dd>
- </dl>
- <div class="sect-t">运行流水</div>
- <div style="margin-bottom:var(--sp-5)">
- <div class="run"><span class="run-id">run #16</span><span class="badge badge-w">blocked</span><span class="run-t">gave_up · 09-26 05:15</span></div>
- <div class="run"><span class="run-id">run #15</span><span class="badge badge-s">done</span><span class="run-t">completed · 09-25 22:03</span></div>
- <div class="run"><span class="run-id">run #14</span><span class="badge badge-d">failed</span><span class="run-t">timeout · 09-25 21:40</span></div>
- </div>
- <div class="sect-t">评论(1)</div>
- <blockquote style="margin-bottom:var(--sp-5)">
- <b style="color:var(--ink)">fullstack</b> <span style="color:var(--faint);font-size:var(--fs-12)">09-26 05:15</span><br>
- 本轮(run 16)结论:代码修复已就绪,线上未生效。需等待云函数部署窗口,不再重试。
- </blockquote>
- <div class="note">
- <b>一期只读</b>:本页不提供派发 / 评论 / 改状态入口(AC-07b.6)。要下新任务请回<b>会话页</b>发指令。<br>
- <span class="ref">FR-07b</span><span class="ref">AC-07b.2</span><span class="ref">AC-07b.3</span><span class="ref">AC-07b.6</span>
- </div>
- </div>
- </section>
- </div>
- <!-- ===== 桌面屏 5 · 成果 ===== -->
- <div class="view" data-view="deliverables" data-seg-scope hidden>
- <aside class="pane pane-list">
- <div class="pane-head"><label class="search"><svg class="ic ic-sm"><use href="#i-search"/></svg><input placeholder="搜索成果"></label></div>
- <div class="pane-body">
- <div class="group-label">按项目分组</div>
- <button class="row on">
- <span class="av av-file av-sm"><svg class="ic ic-sm"><use href="#i-folder"/></svg></span>
- <span class="row-meta"><span class="row-name"><span class="nm">季度经营分析</span></span><span class="row-prev">8 个成果</span></span>
- </button>
- <button class="row">
- <span class="av av-file av-sm"><svg class="ic ic-sm"><use href="#i-folder"/></svg></span>
- <span class="row-meta"><span class="row-name"><span class="nm">进化工程</span></span><span class="row-prev">5 个成果</span></span>
- </button>
- <button class="row">
- <span class="av av-file av-sm"><svg class="ic ic-sm"><use href="#i-folder"/></svg></span>
- <span class="row-meta"><span class="row-name"><span class="nm">魔镜形象分析</span></span><span class="row-prev">3 个成果</span></span>
- </button>
- <button class="row">
- <span class="av av-file av-sm"><svg class="ic ic-sm"><use href="#i-folder"/></svg></span>
- <span class="row-meta"><span class="row-name"><span class="nm">未归组</span></span><span class="row-prev">2 个成果</span></span>
- </button>
- </div>
- </aside>
- <section class="pane pane-main">
- <div class="seg-head">
- <span style="flex:1;font-size:var(--fs-15);font-weight:650">季度经营分析 · 8 个成果</span>
- <div class="seg">
- <button class="seg-i on" data-panel="byproject">按项目</button>
- <button class="seg-i" data-panel="timeline">按时间线</button>
- </div>
- <button class="btn btn-ghost"><svg class="ic ic-sm"><use href="#i-download"/></svg>批量下载</button>
- </div>
- <div class="pane-body">
- <div data-panel-name="byproject">
- <div class="item">
- <div class="item-h">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="nm"><b>Q2 季度报表.pdf</b><span>数据分析助手 · 1.2 MB · 10:12</span></span>
- <span class="badge badge-s">已交付</span>
- <button class="icon-btn" title="下载"><svg class="ic"><use href="#i-download"/></svg></button>
- </div>
- </div>
- <div class="item">
- <div class="item-h">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="nm"><b>销售趋势分析.xlsx</b><span>数据分析助手 · 340 KB · 昨天</span></span>
- <span class="badge badge-s">已交付</span>
- <button class="icon-btn" title="下载"><svg class="ic"><use href="#i-download"/></svg></button>
- </div>
- </div>
- <div class="item">
- <div class="item-h">
- <span class="av av-file"><svg class="ic"><use href="#i-image"/></svg></span>
- <span class="nm"><b>渠道转化漏斗图(4 张)</b><span>数据分析助手 · 图片组 · 昨天</span></span>
- <span class="badge badge-n">可预览</span>
- <button class="icon-btn" title="全屏预览"><svg class="ic"><use href="#i-eye"/></svg></button>
- </div>
- <div class="item-files">
- <div class="thumb"><svg class="ic ic-lg"><use href="#i-image"/></svg><span class="cap">漏斗-总览.png</span></div>
- <div class="thumb"><svg class="ic ic-lg"><use href="#i-image"/></svg><span class="cap">漏斗-分渠道.png</span></div>
- <div class="thumb"><svg class="ic ic-lg"><use href="#i-image"/></svg><span class="cap">漏斗-趋势.png</span></div>
- <div class="thumb"><svg class="ic ic-lg"><use href="#i-image"/></svg><span class="cap">漏斗-对比.png</span></div>
- </div>
- </div>
- </div>
- <div data-panel-name="timeline" hidden>
- <div style="padding:var(--sp-5) var(--sp-5) var(--sp-6)">
- <div class="tl">
- <div class="tl-i">
- <div class="tl-d">今天 · 10:12</div>
- <div style="font-size:var(--fs-15);font-weight:650">Q2 季度报表.pdf</div>
- <div style="font-size:var(--fs-12);color:var(--muted)">季度经营分析 · 数据分析助手</div>
- </div>
- <div class="tl-i">
- <div class="tl-d">昨天 · 18:30</div>
- <div style="font-size:var(--fs-15);font-weight:650">渠道转化漏斗图(4 张)</div>
- <div style="font-size:var(--fs-12);color:var(--muted)">季度经营分析 · 数据分析助手</div>
- </div>
- <div class="tl-i">
- <div class="tl-d">昨天 · 09:05</div>
- <div style="font-size:var(--fs-15);font-weight:650">销售趋势分析.xlsx</div>
- <div style="font-size:var(--fs-12);color:var(--muted)">季度经营分析 · 数据分析助手</div>
- </div>
- <div class="tl-i">
- <div class="tl-d">10-11 · 16:20</div>
- <div style="font-size:var(--fs-15);font-weight:650">《进化工程》第 15 章改稿.docx</div>
- <div style="font-size:var(--fs-12);color:var(--muted)">进化工程 · 文案生成器</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
- </div>
- <!-- ===== 桌面屏 6 · 通讯录 ===== -->
- <div class="view" data-view="contacts" data-tab-scope hidden>
- <div class="page">
- <div class="page-h" style="max-width:1040px;margin:0 auto var(--sp-4)">
- <div class="page-t">
- <h2>通讯录</h2>
- <p>全部 · AI 数字生命 · 同事 | 点数字生命行进会话,未接入的进详情页(R2 服务层单点判定)</p>
- </div>
- <label class="search" style="max-width:280px"><svg class="ic ic-sm"><use href="#i-search"/></svg><input placeholder="搜索名称"></label>
- </div>
- <div style="max-width:1040px;margin:0 auto">
- <div class="tabs">
- <button class="tab on" data-panel="all">全部 7</button>
- <button class="tab" data-panel="bots">AI 数字生命 4</button>
- <button class="tab" data-panel="colleagues">同事 3</button>
- </div>
- <div data-panel-name="all" style="padding-top:var(--sp-5)">
- <div class="sect-t">AI 数字生命</div>
- <div class="card-grid" style="margin-bottom:var(--sp-6)">
- <button class="wcard" style="text-align:left">
- <div class="wcard-h"><span class="av av-bot av-on">数</span><span class="nm"><b>数据分析助手</b><span>运行中 · 已接入 FMODE</span></span></div>
- <div class="wcard-foot"><span style="flex:1">最近成果 Q2 季度报表</span><svg class="ic ic-sm"><use href="#i-chev-r"/></svg></div>
- </button>
- <button class="wcard" style="text-align:left">
- <div class="wcard-h"><span class="av av-bot av-off av-danger">运</span><span class="nm"><b>运维值守</b><span>异常 · 已接入 FMODE</span></span></div>
- <div class="wcard-foot"><span style="flex:1">任务失败:依赖服务不可用</span><svg class="ic ic-sm"><use href="#i-chev-r"/></svg></div>
- </button>
- <button class="wcard" style="text-align:left">
- <div class="wcard-h"><span class="av av-bot av-idle">文</span><span class="nm"><b>文案生成器</b><span>空闲 · 已接入 FMODE</span></span></div>
- <div class="wcard-foot"><span style="flex:1">等待新任务</span><svg class="ic ic-sm"><use href="#i-chev-r"/></svg></div>
- </button>
- <button class="wcard" style="text-align:left">
- <div class="wcard-h"><span class="av av-file av-sm" style="width:40px;height:40px"><svg class="ic"><use href="#i-user"/></svg></span><span class="nm"><b>行业研究员</b><span>未接入 FMODE</span></span><span class="badge badge-n">详情</span></div>
- <div class="wcard-foot"><span style="flex:1">点行进「数字生命详情」</span><svg class="ic ic-sm"><use href="#i-chev-r"/></svg></div>
- </button>
- </div>
- <div class="sect-t">同事</div>
- <div style="background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);overflow:hidden">
- <button class="row" data-expand="ex-li" aria-expanded="false" style="border-bottom:1px solid var(--edge)">
- <span class="av av-user av-on">李</span>
- <span class="row-meta"><span class="row-name"><span class="nm">李工</span><span class="badge badge-n">2 个数字生命</span></span><span class="row-prev">产品经理 · 在线</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <div id="ex-li" hidden style="background:var(--surface-2);border-bottom:1px solid var(--edge)">
- <button class="row" style="padding-left:64px"><span class="av av-bot av-on av-sm">数</span><span class="row-meta"><span class="row-name"><span class="nm">数据分析助手</span></span><span class="row-prev">运行中</span></span></button>
- <button class="row" style="padding-left:64px"><span class="av av-bot av-idle av-sm">文</span><span class="row-meta"><span class="row-name"><span class="nm">文案生成器</span></span><span class="row-prev">空闲</span></span></button>
- </div>
- <button class="row" data-expand="ex-zhang" aria-expanded="false" style="border-bottom:1px solid var(--edge)">
- <span class="av av-user">张</span>
- <span class="row-meta"><span class="row-name"><span class="nm">张敏</span><span class="badge badge-n">1 个数字生命</span></span><span class="row-prev">运营 · 离线</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <div id="ex-zhang" hidden style="background:var(--surface-2)">
- <button class="row" style="padding-left:64px"><span class="av av-bot av-off av-sm">运</span><span class="row-meta"><span class="row-name"><span class="nm">运维值守</span></span><span class="row-prev">异常</span></span></button>
- </div>
- </div>
- </div>
- <div data-panel-name="bots" hidden style="padding-top:var(--sp-5)">
- <div class="empty"><svg class="ic" style="width:40px;height:40px"><use href="#i-users"/></svg><b>AI 数字生命(4)</b><p>此为 Tab 切换后的独立面板,与「全部」Tab 互斥显示(AC-03.1)。同一份网格卡在此完整呈现。</p></div>
- </div>
- <div data-panel-name="colleagues" hidden style="padding-top:var(--sp-5)">
- <div class="empty"><svg class="ic" style="width:40px;height:40px"><use href="#i-users"/></svg><b>同事(3)</b><p>同事行可展开其名下数字生命(AC-03.1)。展开态见「全部」 Tab 中的李工一行。</p></div>
- </div>
- </div>
- </div>
- </div>
- <!-- ===== 未覆盖模块占位(导航 7 项齐全,不砍功能) ===== -->
- <div class="view" data-view="stub" hidden>
- <div class="page" style="display:grid;place-items:center">
- <div class="empty">
- <svg class="ic" style="width:44px;height:44px;color:var(--faint)"><use href="#i-folder"/></svg>
- <b id="stubTitle">该模块</b>
- <p>本 MVP demo 聚焦 11 个关键屏;此模块 SPEC 中已有 FR 定义(非砍功能),将在阶段②B 组件规范细化时补齐。</p>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="notes">
- <div class="notes-h"><svg class="ic"><use href="#i-eye"/></svg>桌面端设计依据</div>
- <div class="note">
- <span class="ref">FR-04</span><span class="ref">AC-04.1</span><span class="ref">AC-04.6</span><span class="ref">约束 C5</span><br>
- <b>会话页四栏</b> 56 / 300 / flex(≥480) / 340。<b>「正在处理…」状态条是全页面唯一渲染「在干嘛」的地方</b> —— 存量在标题栏、TaskStrip、LiveConsole 三处重复渲染,这里收敛成一条(AC-04.6)。
- </div>
- <div class="note ok">
- <span class="ref">规则 2</span><b>不造假进度</b>:AI 任务耗时不可预测,用步骤清单(✓/▸/○)+ 已用时;进度条只用于分母已知的场景(CPU / 内存 / 上传)。
- </div>
- <div class="note warn">
- <span class="ref">FR-07</span><span class="ref">AC-07.3</span><b>工作台</b>:加载失败必须显示错误态,禁止伪装成空态或"权限问题"(存量痛点)。双端同一实况服务,口径一致含 token 用量(FR-07 AC-07.2 / FR-17)。
- </div>
- <div class="note">
- <span class="ref">FR-07b</span><span class="ref">AC-07b.3</span><b>任务看板</b>:阻塞 / 失败用<b>左色条 3px + 图标 + 文字 + 阻塞时长</b>,不用整行红底。列表内直接显示「已阻塞 436h」—— 这是 P2 的核心价值。一期只读。
- </div>
- <div class="note">
- <span class="ref">FR-08</span><span class="ref">AC-08.1</span><b>成果</b>:按项目 / 按时间线<b>双视图分段器</b>;条目可展开看文件,图片支持全屏预览。成果独立于消息气泡,P1 核心场景。
- </div>
- <div class="note ok">
- <span class="ref">规范</span><b>布局校验(本轮修正)</b>:① 四栏宽度全部令牌化(56 / 300 / flex ≥480 / 340),修复视图包裹层缺失导致的「各栏上下堆叠」;② 三栏头统一 <code>--hd-h</code> 64px,分隔线实测对齐;③ 任务看板列表栏由硬编码 340 归位 <code>--dk-list-w</code> 300;④ 右栏「当前任务」与 L2 状态条重复渲染已移除(约束 C5)。
- </div>
- </div>
- </section>
- <!-- ==================== 移动端(5 屏) ==================== -->
- <section class="screen" data-end="mb">
- <div class="device device-mb">
- <div class="device-cap">
- <b>移动端 · 390 × 844</b>
- <span>单列高可达 · 触达区 ≥44 · 输入 ≥16px</span>
- </div>
- <div class="mb" id="mbShell">
- <div class="mb-status"><span>9:41</span><span style="display:flex;align-items:center;gap:var(--sp-1)">中国移动 5G<svg class="ic ic-sm"><use href="#i-zap"/></svg></span></div>
- <!-- ===== 移动屏 7 · 聚合首页 ===== -->
- <div class="view" data-view="home">
- <header class="mb-nav">
- <span class="mb-nav-t">首页</span>
- <button class="mb-icon-btn" title="搜索"><svg class="ic"><use href="#i-search"/></svg></button>
- </header>
- <div class="mb-body">
- <button class="mb-banner">
- <svg class="ic"><use href="#i-alert"/></svg>
- <span style="flex:1"><b>有 2 项需要关注</b><span>1 个任务阻塞 · 1 个执行失败</span></span>
- <svg class="ic ic-sm" style="color:var(--warning)"><use href="#i-chev-r"/></svg>
- </button>
- <div class="mb-sect"><b>最近会话</b><a>全部 3 ›</a></div>
- <button class="mb-cell">
- <span class="av av-bot av-on">数</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">数据分析助手</span></span><span class="mb-cd">已完成 3 份报表,正在生成第 4 份</span></span>
- <span class="mb-cr">10:24</span>
- </button>
- <button class="mb-cell warn">
- <span class="av av-bot av-off av-danger">运</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">运维值守</span></span><span class="mb-cd" style="color:var(--danger)">任务失败:依赖服务不可用</span></span>
- <span class="mb-cr">09:51</span>
- </button>
- <button class="mb-cell">
- <span class="av av-bot av-idle">文</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">文案生成器</span></span><span class="mb-cd">空闲,等待新任务</span></span>
- <span class="mb-cr">昨天</span>
- </button>
- <div class="mb-sect"><b>最新成果</b><a>全部 3 ›</a></div>
- <button class="mb-cell">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">Q2 季度报表.pdf</span></span><span class="mb-cd">数据分析助手 · 1.2 MB</span></span>
- <span class="mb-cr">10:12</span>
- </button>
- <button class="mb-cell">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">销售趋势分析.xlsx</span></span><span class="mb-cd">数据分析助手 · 340 KB</span></span>
- <span class="mb-cr">昨天</span>
- </button>
- <button class="mb-cell">
- <span class="av av-file"><svg class="ic"><use href="#i-image"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">渠道转化漏斗图(4 张)</span></span><span class="mb-cd">数据分析助手 · 图片组</span></span>
- <span class="mb-cr">昨天</span>
- </button>
- <div style="height:var(--sp-4)"></div>
- </div>
- </div>
- <!-- ===== 移动屏 8 · 会话 ===== -->
- <div class="view" data-view="chat" hidden>
- <header class="mb-nav">
- <button class="mb-icon-btn" title="返回"><svg class="ic"><use href="#i-chev-l"/></svg></button>
- <span class="av av-bot av-on av-sm">数</span>
- <span style="flex:1;min-width:0">
- <span style="display:block;font-size:var(--fs-15);font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">数据分析助手</span>
- <span style="font-size:var(--fs-11);color:var(--muted);display:flex;align-items:center;gap:var(--sp-1)"><span class="dot dot-success"></span>运行中</span>
- </span>
- <button class="mb-icon-btn" data-drawer="open" title="查看成果"><svg class="ic"><use href="#i-box"/></svg></button>
- </header>
- <div class="statusbar is-static" style="margin:var(--sp-3) var(--sp-4) 0;padding:var(--sp-2) var(--sp-3)">
- <span class="pulse"></span>
- <span class="sb-text"><b style="font-size:var(--fs-12)">生成第 4 份报表</b></span>
- <span style="font-size:var(--fs-12);color:var(--faint);display:inline-flex;align-items:center;gap:var(--sp-1)">3:12<svg class="ic ic-sm"><use href="#i-chev-d"/></svg></span>
- </div>
- <div class="mb-body" id="mbChatMsgs" style="display:flex;flex-direction:column;gap:var(--sp-3);padding:var(--sp-4)">
- <div class="msg" style="max-width:88%"><span class="av av-bot av-sm">数</span><div class="bubble" style="font-size:var(--fs-15)">早上好,我已开始处理今天的报表任务。</div></div>
- <div class="msg is-me" style="max-width:88%"><div class="bubble" style="font-size:var(--fs-15)">把第 3 季度的也一起做了</div><span class="av av-user av-sm">胡</span></div>
- <div class="msg" style="max-width:88%"><span class="av av-bot av-sm">数</span><div class="bubble" style="font-size:var(--fs-15)">收到,已排入队列,正在处理第 4 份。</div></div>
- <div class="msg is-me" style="max-width:88%"><div class="bubble" style="font-size:var(--fs-15)">完成后发我一份</div><span class="av av-user av-sm">胡</span></div>
- </div>
- <div class="mb-input">
- <button class="mb-icon-btn" title="发送文件"><svg class="ic"><use href="#i-plus"/></svg></button>
- <textarea class="mb-input-x" rows="1" placeholder="发消息…"></textarea>
- <button class="mb-send" title="发送"><svg class="ic"><use href="#i-send"/></svg></button>
- </div>
- </div>
- <!-- ===== 移动屏 9 · 工作台 ===== -->
- <div class="view" data-view="workbench" hidden>
- <header class="mb-nav">
- <span class="mb-nav-t">工作台</span>
- <button class="mb-icon-btn" title="刷新"><svg class="ic"><use href="#i-refresh"/></svg></button>
- </header>
- <div class="mb-body" style="padding-top:var(--sp-4)">
- <div style="padding:0 var(--sp-4) var(--sp-4);display:grid;grid-template-columns:1fr 1fr 1fr;gap:var(--sp-3)">
- <div class="mb-card" style="text-align:center;padding:var(--sp-3)"><div style="font-size:var(--fs-12);color:var(--muted)">运行中</div><div style="font-size:var(--fs-20);font-weight:750;color:var(--success)">2</div></div>
- <div class="mb-card" style="text-align:center;padding:var(--sp-3)"><div style="font-size:var(--fs-12);color:var(--muted)">空闲</div><div style="font-size:var(--fs-20);font-weight:750;color:var(--warning)">1</div></div>
- <div class="mb-card" style="text-align:center;padding:var(--sp-3)"><div style="font-size:var(--fs-12);color:var(--muted)">异常</div><div style="font-size:var(--fs-20);font-weight:750;color:var(--danger)">1</div></div>
- </div>
- <div style="padding:0 var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)">
- <article class="mb-card" style="border-left:3px solid var(--danger)">
- <div style="display:flex;align-items:center;gap:var(--sp-3)">
- <span class="av av-bot av-off av-danger">运</span>
- <span style="flex:1;min-width:0"><b style="display:block;font-size:var(--fs-15)">运维值守</b><span style="font-size:var(--fs-12);color:var(--muted)">运维 · 通道异常</span></span>
- <span class="badge badge-d">异常</span>
- </div>
- <div style="margin-top:var(--sp-3);font-size:var(--fs-13);color:var(--danger);display:flex;gap:var(--sp-2)"><svg class="ic ic-sm" style="color:var(--danger)"><use href="#i-alert"/></svg>任务失败:依赖服务不可用,连续失败 41 次</div>
- <div style="margin-top:var(--sp-3);display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)">
- <div><div class="wcard-f"><span>CPU</span><b>88%</b></div><div class="bar warning"><i style="width:88%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>71%</b></div><div class="bar"><i style="width:71%"></i></div></div>
- </div>
- </article>
- <article class="mb-card">
- <div style="display:flex;align-items:center;gap:var(--sp-3)">
- <span class="av av-bot av-on">数</span>
- <span style="flex:1;min-width:0"><b style="display:block;font-size:var(--fs-15)">数据分析助手</b><span style="font-size:var(--fs-12);color:var(--muted)">数据分析 · 通道正常</span></span>
- <span class="badge badge-s">运行中</span>
- </div>
- <div style="margin-top:var(--sp-3);font-size:var(--fs-13);color:var(--ink-2);display:flex;gap:var(--sp-2)"><svg class="ic ic-sm" style="color:var(--info)"><use href="#i-play"/></svg>正在生成第 4 份季度报表(3:12)</div>
- <div style="margin-top:var(--sp-3);display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)">
- <div><div class="wcard-f"><span>CPU</span><b>12%</b></div><div class="bar"><i style="width:12%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>34%</b></div><div class="bar"><i style="width:34%"></i></div></div>
- </div>
- </article>
- <article class="mb-card">
- <div style="display:flex;align-items:center;gap:var(--sp-3)">
- <span class="av av-bot av-on">研</span>
- <span style="flex:1;min-width:0"><b style="display:block;font-size:var(--fs-15)">行业研究员</b><span style="font-size:var(--fs-12);color:var(--muted)">研究 · 通道正常</span></span>
- <span class="badge badge-s">运行中</span>
- </div>
- <div style="margin-top:var(--sp-3);font-size:var(--fs-13);color:var(--ink-2);display:flex;gap:var(--sp-2)"><svg class="ic ic-sm" style="color:var(--info)"><use href="#i-play"/></svg>汇总本周行业动态(12:40)</div>
- <div style="margin-top:var(--sp-3);display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3)">
- <div><div class="wcard-f"><span>CPU</span><b>27%</b></div><div class="bar"><i style="width:27%"></i></div></div>
- <div><div class="wcard-f"><span>内存</span><b>45%</b></div><div class="bar"><i style="width:45%"></i></div></div>
- </div>
- </article>
- </div>
- <div style="height:var(--sp-4)"></div>
- </div>
- </div>
- <!-- ===== 移动屏 10 · 通讯录 ===== -->
- <div class="view" data-view="contacts" hidden data-tab-scope>
- <header class="mb-nav"><span class="mb-nav-t">通讯录</span></header>
- <div style="padding:var(--sp-3) var(--sp-4);background:var(--surface)">
- <label class="search" style="height:var(--touch-min)"><svg class="ic ic-sm"><use href="#i-search"/></svg><input placeholder="搜索数字生命 / 同事"></label>
- </div>
- <div class="mb-tabs">
- <button class="chip on" data-panel="mall">全部 7</button>
- <button class="chip" data-panel="mbots">数字生命 4</button>
- <button class="chip" data-panel="mcol">同事 3</button>
- </div>
- <div class="mb-body" data-panel-name="mall">
- <div class="mb-list-h">AI 数字生命</div>
- <button class="mb-cell">
- <span class="av av-bot av-on">数</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">数据分析助手</span></span><span class="mb-cd">运行中 · 已接入</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <button class="mb-cell warn">
- <span class="av av-bot av-off av-danger">运</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">运维值守</span></span><span class="mb-cd" style="color:var(--danger)">异常 · 已接入</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <button class="mb-cell">
- <span class="av av-bot av-idle">文</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">文案生成器</span></span><span class="mb-cd">空闲 · 已接入</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <button class="mb-cell">
- <span class="av av-file"><svg class="ic"><use href="#i-user"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">行业研究员</span></span><span class="mb-cd">未接入 FMODE · 进详情页</span></span>
- <span class="badge badge-n">详情</span>
- </button>
- <div class="mb-list-h">同事</div>
- <button class="mb-cell" data-expand="mex-li" aria-expanded="false">
- <span class="av av-user av-on">李</span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">李工</span><span class="badge badge-n">2</span></span><span class="mb-cd">产品经理 · 在线</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg>
- </button>
- <div id="mex-li" hidden style="background:var(--surface-2)">
- <button class="mb-cell" style="padding-left:64px"><span class="av av-bot av-on av-sm">数</span><span class="mb-cb"><span class="mb-ct"><span class="nm">数据分析助手</span></span><span class="mb-cd">运行中</span></span></button>
- <button class="mb-cell" style="padding-left:64px"><span class="av av-bot av-idle av-sm">文</span><span class="mb-cb"><span class="mb-ct"><span class="nm">文案生成器</span></span><span class="mb-cd">空闲</span></span></button>
- </div>
- <div style="height:var(--sp-4)"></div>
- </div>
- <div class="mb-body" data-panel-name="mbots" hidden>
- <div class="empty" style="padding:var(--sp-8) var(--sp-6)"><svg class="ic" style="width:40px;height:40px;color:var(--faint)"><use href="#i-users"/></svg><b>数字生命(4)</b><p>Tab 切换后的独立面板(AC-03.1)。同一份数据在此完整呈现。</p></div>
- </div>
- <div class="mb-body" data-panel-name="mcol" hidden>
- <div class="empty" style="padding:var(--sp-8) var(--sp-6)"><svg class="ic" style="width:40px;height:40px;color:var(--faint)"><use href="#i-users"/></svg><b>同事(3)</b><p>同事行可展开其名下数字生命(AC-03.1)。展开态见「全部」Tab 的李工一行。</p></div>
- </div>
- </div>
- <!-- ===== 移动屏 11 · 我的 ===== -->
- <div class="view" data-view="mine" hidden>
- <header class="mb-nav"><span class="mb-nav-t">我的</span></header>
- <div class="mb-body">
- <div class="mb-gutter">
- <div class="mb-card" style="display:flex;align-items:center;gap:var(--sp-4)">
- <span class="av av-user av-round av-on av-lg">胡</span>
- <span style="flex:1;min-width:0">
- <b style="font-size:var(--fs-17);display:block">胡文博</b>
- <span style="font-size:var(--fs-13);color:var(--muted)">138 0000 0000</span><br>
- <span class="badge badge-p" style="margin-top:var(--sp-1)"><svg class="ic ic-sm"><use href="#i-shield"/></svg>超管</span>
- </span>
- </div>
- </div>
- <div class="mb-list-h">账号</div>
- <div class="mb-group">
- <div class="mb-line"><svg class="ic" style="color:var(--muted)"><use href="#i-user"/></svg><span class="k">手机号</span><span class="v">138 0000 0000</span></div>
- <div class="mb-line"><svg class="ic" style="color:var(--muted)"><use href="#i-db"/></svg><span class="k">归属公司</span><span class="v">Fmode 科技</span></div>
- <div class="mb-line"><svg class="ic" style="color:var(--muted)"><use href="#i-key"/></svg><span class="k">修复 Token</span><svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-chev-r"/></svg></div>
- </div>
- <div class="mb-list-h">使用形态</div>
- <div class="mb-group" style="padding:var(--sp-3) var(--sp-4)">
- <div class="seg" style="width:100%">
- <button class="seg-i on" style="flex:1;text-align:center">自动识别</button>
- <button class="seg-i" style="flex:1;text-align:center">桌面端</button>
- <button class="seg-i" style="flex:1;text-align:center">移动端</button>
- </div>
- <p style="font-size:var(--fs-12);color:var(--muted);margin-top:var(--sp-3);line-height:1.7">当前:移动端(UA + 视口判定)。端切换为一次性判定,缩放窗口不改变端(R1)。</p>
- </div>
- <div class="mb-gutter">
- <button class="btn btn-danger btn-block"><svg class="ic ic-sm"><use href="#i-logout"/></svg>退出登录</button>
- <p style="font-size:var(--fs-12);color:var(--faint);text-align:center;margin-top:var(--sp-3)">退出需二次确认(AC-10.2)</p>
- </div>
- <p style="font-size:var(--fs-12);color:var(--faint);text-align:center;padding-bottom:var(--sp-5)">版本 v2.0.0 · 构建注入(AC-10.3)</p>
- </div>
- </div>
- <!-- 未覆盖模块占位 -->
- <div class="view" data-view="stub" hidden>
- <header class="mb-nav"><span class="mb-nav-t" id="mbStubTitle">该模块</span></header>
- <div class="mb-body">
- <div class="empty" style="padding:var(--sp-8) var(--sp-6)"><svg class="ic" style="width:44px;height:44px;color:var(--faint)"><use href="#i-folder"/></svg><b>本 demo 未覆盖</b><p>SPEC 中已有 FR 定义(非砍功能),阶段②B 补齐。</p></div>
- </div>
- </div>
- <!-- 底部 TabBar(5 Tab · 老项目一致) -->
- <nav class="mb-tabbar">
- <button class="mb-tab on" data-mod="home"><svg class="ic"><use href="#i-grid"/></svg><span>首页</span></button>
- <button class="mb-tab" data-mod="contacts"><svg class="ic"><use href="#i-users"/></svg><span>通讯录</span></button>
- <button class="mb-tab" data-mod="projects"><svg class="ic"><use href="#i-folder"/></svg><span>项目</span></button>
- <button class="mb-tab has-dot" data-mod="workbench"><svg class="ic"><use href="#i-grid"/></svg><span>工作台</span></button>
- <button class="mb-tab" data-mod="mine"><svg class="ic"><use href="#i-user"/></svg><span>我的</span></button>
- </nav>
- <div class="mb-scrim" id="mbScrim" data-drawer="close"></div>
- <!-- 成果抽屉(AC-04.1 移动全屏 + 成果抽屉) -->
- <aside class="mb-drawer" id="mbDrawer" aria-label="会话成果">
- <div class="mb-drawer-h">
- <b>本会话成果</b>
- <span class="badge badge-n">3</span>
- <button class="mb-icon-btn" data-drawer="close" title="关闭"><svg class="ic"><use href="#i-chev-d"/></svg></button>
- </div>
- <div class="mb-drawer-b">
- <button class="mb-cell" style="border-bottom:1px solid var(--edge)">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">Q2 季度报表.pdf</span></span><span class="mb-cd">1.2 MB · 10:12</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-download"/></svg>
- </button>
- <button class="mb-cell" style="border-bottom:1px solid var(--edge)">
- <span class="av av-file"><svg class="ic"><use href="#i-file"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">销售趋势分析.xlsx</span></span><span class="mb-cd">340 KB · 昨天</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-download"/></svg>
- </button>
- <button class="mb-cell">
- <span class="av av-file"><svg class="ic"><use href="#i-image"/></svg></span>
- <span class="mb-cb"><span class="mb-ct"><span class="nm">渠道转化漏斗图(4 张)</span></span><span class="mb-cd">图片组 · 昨天</span></span>
- <svg class="ic ic-sm" style="color:var(--faint)"><use href="#i-eye"/></svg>
- </button>
- </div>
- </aside>
- </div>
- </div>
- <div class="notes">
- <div class="notes-h"><svg class="ic"><use href="#i-eye"/></svg>移动端设计依据</div>
- <div class="note">
- <span class="ref">FR-19</span><span class="ref">AC-19.1</span><span class="ref">AC-19.3</span><b>聚合首页</b>:事件提醒条 + 最近会话 + 最新成果,各带「全部」入口;<b>区块计数与列表条数一致</b>(修正存量"显示 20 却只有 6 行");每个区块独立三态;搜索框字号 ≥16px(iOS 不缩放)。
- </div>
- <div class="note ok">
- <span class="ref">FR-04</span><span class="ref">AC-04.1</span><b>会话</b>:全屏 + 成果抽屉(点右上角 📦 打开)。L2 状态条压缩成一行,仍是<b>唯一</b>渲染「在干嘛」的地方。
- </div>
- <div class="note">
- <span class="ref">FR-13</span><span class="ref">AC-13.3</span><b>无障碍</b>:所有交互元素 ≥44×44(Tab / 图标按钮 / 列表行);列表行高 64px(双行)• 头像 44px;顶栏 56px + 底栏 56px + 安全区。
- </div>
- <div class="note ok">
- <span class="ref">规范</span><b>移动端布局校验(本轮修正)</b>:修复设备外框被硬编码 844px 高、把底部 TabBar 连同内容一并裁掉的问题;列表头像按要求提到 44px;单行行高归位 56px(<code>--mb-list-h-1</code>);页面左右边距统一走 <code>--mb-gutter</code> 16px;会话为全屏详情,该视图激活时收起 TabBar。
- </div>
- <div class="note warn">
- <span class="ref">FR-10</span><span class="ref">AC-10.2</span><span class="ref">AC-10.3</span><b>我的</b>:端切换(自动 / 桌面 / 移动)+ 修复 Token + 退出(需二次确认);版本号从构建注入,禁止硬编码。
- </div>
- </div>
- </section>
- </main>
- </div>
- <script>
- (function(){
- var root = document.documentElement;
- var stage = document.getElementById('stage');
- var DK_LABEL = { chat:'会话', contacts:'通讯录', projects:'项目', events:'事件',
- workbench:'工作台', tasks:'任务看板', deliverables:'成果', mine:'我的' };
- var MB_LABEL = { home:'首页', chat:'会话', contacts:'通讯录', projects:'项目',
- workbench:'工作台', mine:'我的' };
- var screens = {};
- document.querySelectorAll('.screen').forEach(function(s){ screens[s.dataset.end] = s; });
- /* 在指定壳内切换视图;模块未实现时落到占位屏 */
- function showView(shellSel, mod, label){
- var shell = document.querySelector(shellSel);
- if(!shell) return;
- var found = false;
- shell.querySelectorAll('.view').forEach(function(v){
- if(v.dataset.view === 'stub') return;
- var hit = v.dataset.view === mod;
- if(hit) found = true;
- v.hidden = !hit;
- });
- var stub = shell.querySelector('.view[data-view="stub"]');
- if(stub){
- stub.hidden = found;
- if(!found){
- var t = stub.querySelector('b, .mb-nav-t, #stubTitle, #mbStubTitle');
- if(t) t.textContent = label || '该模块';
- }
- }
- }
- /* 桌面端 1440×900 自适应装进舞台 */
- function fitDk(){
- var dev = document.getElementById('dkDevice');
- var box = document.getElementById('dkBox');
- var dk = document.getElementById('dkShell');
- if(!dev || !box || !dk) return;
- var availW = stage.clientWidth - 48;
- var availH = stage.clientHeight - 48;
- var scale = Math.max(.3, Math.min(1, availW / 1440, availH / 900));
- dk.style.transform = 'scale(' + scale + ')';
- box.style.width = (1440 * scale) + 'px';
- box.style.height = (900 * scale) + 'px';
- dev.style.width = (1440 * scale + 2) + 'px';
- dev.style.maxWidth = 'none';
- }
- /* 总切换:端 + 模块 */
- function activate(end, mod){
- Object.keys(screens).forEach(function(k){
- if(screens[k]) screens[k].classList.toggle('is-on', k === end);
- });
- document.querySelectorAll('.tool-i').forEach(function(b){ b.classList.toggle('on', b.dataset.end === end); });
- document.querySelectorAll('.nav-i').forEach(function(b){
- b.classList.toggle('on', b.dataset.end === end && (end === 'login' || b.dataset.mod === mod));
- });
- if(end === 'dk'){
- showView('#dkShell', mod, DK_LABEL[mod]);
- document.querySelectorAll('#dkShell .rail-i').forEach(function(b){
- b.classList.toggle('on', b.dataset.mod === mod);
- });
- fitDk();
- }
- if(end === 'mb'){
- showView('#mbShell', mod, MB_LABEL[mod]);
- document.querySelectorAll('#mbShell .mb-tab').forEach(function(b){
- b.classList.toggle('on', b.dataset.mod === mod);
- });
- }
- stage.scrollTop = 0;
- }
- window.addEventListener('resize', fitDk);
- /* 左侧清单 + 顶栏端点 */
- document.querySelectorAll('.nav-i, .tool-i').forEach(function(b){
- b.addEventListener('click', function(){ activate(b.dataset.end, b.dataset.mod || 'chat'); });
- });
- /* 桌面导航轨(7 模块 + 我的) */
- document.querySelectorAll('#dkShell .rail-i').forEach(function(b){
- b.addEventListener('click', function(){ activate('dk', b.dataset.mod); });
- });
- /* 移动 TabBar */
- document.querySelectorAll('#mbShell .mb-tab').forEach(function(b){
- b.addEventListener('click', function(){ activate('mb', b.dataset.mod); });
- });
- /* 列表行选中 */
- document.querySelectorAll('.pane-list .row, .mb-cell').forEach(function(r){
- r.addEventListener('click', function(){
- if(r.hasAttribute('data-drawer')) return;
- var box = r.parentNode;
- box.querySelectorAll(':scope > .on').forEach(function(x){ x.classList.remove('on'); });
- r.classList.add('on');
- });
- });
- document.querySelectorAll('.task').forEach(function(t){
- t.addEventListener('click', function(){
- document.querySelectorAll('.task').forEach(function(x){ x.classList.remove('on'); });
- t.classList.add('on');
- });
- });
- /* 分段器 */
- document.querySelectorAll('.seg').forEach(function(seg){
- seg.querySelectorAll('.seg-i').forEach(function(i){
- i.addEventListener('click', function(){
- seg.querySelectorAll('.seg-i').forEach(function(x){ x.classList.remove('on'); });
- i.classList.add('on');
- if(!i.dataset.panel) return;
- var scope = seg.closest('[data-seg-scope]') || document;
- scope.querySelectorAll('[data-panel-name]').forEach(function(p){
- p.hidden = p.dataset.panelName !== i.dataset.panel;
- });
- });
- });
- });
- /* 标签页(桌面) */
- document.querySelectorAll('.tabs').forEach(function(tb){
- tb.querySelectorAll('.tab').forEach(function(t){
- t.addEventListener('click', function(){
- tb.querySelectorAll('.tab').forEach(function(x){ x.classList.remove('on'); });
- t.classList.add('on');
- if(!t.dataset.panel) return;
- var scope = tb.closest('[data-tab-scope]') || document;
- scope.querySelectorAll('[data-panel-name]').forEach(function(p){
- p.hidden = p.dataset.panelName !== t.dataset.panel;
- });
- });
- });
- });
- /* 移动筛选 Tab */
- document.querySelectorAll('.mb-tabs').forEach(function(tb){
- tb.querySelectorAll('.chip').forEach(function(c){
- c.addEventListener('click', function(){
- tb.querySelectorAll('.chip').forEach(function(x){ x.classList.remove('on'); });
- c.classList.add('on');
- var scope = tb.closest('[data-tab-scope]') || document;
- scope.querySelectorAll('[data-panel-name]').forEach(function(p){
- p.hidden = p.dataset.panelName !== c.dataset.panel;
- });
- });
- });
- });
- /* 状态筛选胶囊(任务看板) */
- document.querySelectorAll('.chips').forEach(function(box){
- box.querySelectorAll('.chip').forEach(function(c){
- c.addEventListener('click', function(){
- box.querySelectorAll('.chip').forEach(function(x){ x.classList.remove('on'); });
- c.classList.add('on');
- var cat = c.dataset.cat;
- var scope = box.closest('[data-filter-scope]') || document;
- scope.querySelectorAll('[data-cat]').forEach(function(item){
- if(item.classList.contains('chip')) return;
- item.hidden = (cat !== 'all' && item.dataset.cat !== cat);
- });
- });
- });
- });
- /* 发送消息(Enter 发送 / Shift+Enter 换行 / 真实自增高) */
- function bindComposer(inSel, listSel, withAvatar){
- document.querySelectorAll(inSel).forEach(function(input){
- var list = document.querySelector(listSel);
- if(!list) return;
- input.addEventListener('keydown', function(e){
- if(e.key !== 'Enter' || e.shiftKey) return;
- e.preventDefault();
- var v = input.value.trim(); if(!v) return;
- var el = document.createElement('div');
- el.className = 'msg is-me';
- el.style.maxWidth = '88%';
- el.innerHTML = '<div class="bubble" style="font-size:var(--fs-15)"></div>' + (withAvatar ? '<span class="av av-user av-sm">胡</span>' : '<span class="av av-user av-sm">胡</span>');
- el.querySelector('.bubble').textContent = v;
- list.appendChild(el);
- input.value = ''; input.style.height = '';
- list.scrollTop = list.scrollHeight;
- });
- input.addEventListener('input', function(){
- input.style.height = 'auto';
- input.style.height = Math.min(input.scrollHeight, 132) + 'px';
- });
- });
- }
- bindComposer('.composer-input', '#dkChatMsgs', false);
- bindComposer('.mb-input-x', '#mbChatMsgs', true);
- /* 移动成果抽屉 */
- var drawer = document.getElementById('mbDrawer');
- var scrim = document.getElementById('mbScrim');
- function setDrawer(open){
- if(!drawer) return;
- drawer.classList.toggle('open', open);
- if(scrim) scrim.classList.toggle('on', open);
- }
- document.querySelectorAll('[data-drawer="open"]').forEach(function(b){
- b.addEventListener('click', function(e){ e.stopPropagation(); setDrawer(true); });
- });
- document.querySelectorAll('[data-drawer="close"]').forEach(function(b){
- b.addEventListener('click', function(){ setDrawer(false); });
- });
- /* 同事展开名下数字生命 */
- document.querySelectorAll('[data-expand]').forEach(function(b){
- b.addEventListener('click', function(e){
- e.stopPropagation();
- var t = document.getElementById(b.dataset.expand);
- if(!t) return;
- var open = t.hidden;
- t.hidden = !open;
- b.setAttribute('aria-expanded', String(open));
- var chev = b.querySelector('svg.ic');
- if(chev && chev !== b.querySelector('span .ic')) chev.style.transform = open ? 'rotate(90deg)' : '';
- });
- });
- /* 登录方式切换 */
- document.querySelectorAll('.login-tabs .tab').forEach(function(t){
- t.addEventListener('click', function(){
- document.querySelectorAll('[data-login-method]').forEach(function(p){
- p.hidden = p.dataset.loginMethod !== t.dataset.method;
- });
- });
- });
- /* 明暗 / 标注 */
- document.getElementById('btnTheme').addEventListener('click', function(){
- root.classList.toggle('dark');
- this.querySelector('use').setAttribute('href', root.classList.contains('dark') ? '#i-sun' : '#i-moon');
- });
- document.getElementById('btnNotes').addEventListener('click', function(){
- document.body.classList.toggle('show-notes');
- this.classList.toggle('on');
- });
- /* 路由:支持 #<端>/<模块> 直达(评审截图与分享定位用) */
- function fromHash(){
- var h = (location.hash || '').replace(/^#/, '');
- if(!h) return null;
- var p = h.split('/');
- if(!screens[p[0]]) return null;
- return { end: p[0], mod: p[1] || (p[0] === 'login' ? 'login' : 'chat') };
- }
- window.addEventListener('hashchange', function(){
- var t = fromHash(); if(t) activate(t.end, t.mod);
- });
- /* 启动 */
- var t0 = fromHash();
- activate(t0 ? t0.end : 'login', t0 ? t0.mod : 'login');
- })();
- </script>
- </body>
- </html>
|