index.html 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. <!doctype html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>菜单布局方案对比 · 横向导航 Demo</title>
  7. <link rel="preconnect" href="https://fonts.googleapis.com" />
  8. <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
  9. <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
  10. <style>
  11. :root {
  12. --primary: #10b981;
  13. --primary-dark: #059669;
  14. --primary-bg: #ecfdf5;
  15. --portal-green: #1ca851;
  16. --text: #1e293b;
  17. --text-muted: #64748b;
  18. --border: #d9e8e2;
  19. --bg-page: #f8fafc;
  20. --surface: #ffffff;
  21. --table-head: #f8fafc;
  22. --row-alt: #fafafa;
  23. --shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  24. --radius: 10px;
  25. --content-padding: 24px;
  26. }
  27. * { box-sizing: border-box; }
  28. body {
  29. margin: 0;
  30. min-height: 100vh;
  31. font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  32. font-size: 14px;
  33. line-height: 1.5;
  34. color: var(--text);
  35. background: #eef2f0;
  36. }
  37. /* —— 选择器壳 —— */
  38. .picker {
  39. position: sticky;
  40. top: 0;
  41. z-index: 100;
  42. background: #0f172a;
  43. color: #e2e8f0;
  44. border-bottom: 1px solid #1e293b;
  45. padding: 12px 20px 14px;
  46. }
  47. .picker-head {
  48. display: flex;
  49. flex-wrap: wrap;
  50. align-items: baseline;
  51. justify-content: space-between;
  52. gap: 8px 16px;
  53. margin-bottom: 10px;
  54. }
  55. .picker-head h1 {
  56. margin: 0;
  57. font-size: 15px;
  58. font-weight: 600;
  59. color: #f8fafc;
  60. }
  61. .picker-head p {
  62. margin: 0;
  63. font-size: 12px;
  64. color: #94a3b8;
  65. }
  66. .picker-tabs {
  67. display: flex;
  68. flex-wrap: wrap;
  69. gap: 8px;
  70. }
  71. .picker-tab {
  72. appearance: none;
  73. border: 1px solid #334155;
  74. background: #1e293b;
  75. color: #cbd5e1;
  76. border-radius: 8px;
  77. padding: 8px 12px;
  78. font-size: 12px;
  79. font-weight: 500;
  80. cursor: pointer;
  81. text-align: left;
  82. max-width: 220px;
  83. }
  84. .picker-tab:hover { border-color: #64748b; color: #f1f5f9; }
  85. .picker-tab.is-active {
  86. background: var(--primary);
  87. border-color: var(--primary);
  88. color: #fff;
  89. }
  90. .picker-tab strong {
  91. display: block;
  92. font-size: 12px;
  93. margin-bottom: 2px;
  94. }
  95. .picker-tab span {
  96. display: block;
  97. font-size: 11px;
  98. opacity: 0.85;
  99. font-weight: 400;
  100. line-height: 1.35;
  101. }
  102. .picker-note {
  103. margin: 10px 0 0;
  104. font-size: 12px;
  105. color: #94a3b8;
  106. max-width: 960px;
  107. }
  108. .picker-note b { color: #e2e8f0; font-weight: 600; }
  109. .stage {
  110. padding: 16px;
  111. max-width: 1280px;
  112. margin: 0 auto;
  113. }
  114. .frame {
  115. background: var(--bg-page);
  116. border: 1px solid var(--border);
  117. border-radius: 12px;
  118. overflow: hidden;
  119. box-shadow: var(--shadow);
  120. min-height: 620px;
  121. display: none;
  122. }
  123. .frame.is-active { display: flex; flex-direction: column; }
  124. /* 共用 mock UI */
  125. .mock-content { flex: 1; padding: var(--content-padding); min-width: 0; }
  126. .mock-panel {
  127. background: var(--surface);
  128. border: 1px solid var(--border);
  129. border-radius: var(--radius);
  130. overflow: hidden;
  131. }
  132. .mock-panel-top {
  133. display: flex;
  134. align-items: center;
  135. justify-content: space-between;
  136. padding: 14px 16px;
  137. border-bottom: 1px solid var(--border);
  138. }
  139. .mock-panel-top h2 {
  140. margin: 0;
  141. font-size: 15px;
  142. font-weight: 600;
  143. display: flex;
  144. align-items: center;
  145. gap: 8px;
  146. }
  147. .mock-panel-top h2::before {
  148. content: "";
  149. width: 3px;
  150. height: 14px;
  151. border-radius: 2px;
  152. background: var(--primary);
  153. }
  154. .mock-toolbar {
  155. display: flex;
  156. align-items: center;
  157. gap: 8px;
  158. padding: 12px 16px;
  159. border-bottom: 1px solid var(--border);
  160. font-size: 13px;
  161. color: var(--text-muted);
  162. }
  163. .btn {
  164. appearance: none;
  165. border: 1px solid var(--border);
  166. background: var(--surface);
  167. color: var(--text);
  168. border-radius: 8px;
  169. height: 32px;
  170. padding: 0 12px;
  171. font-size: 13px;
  172. cursor: default;
  173. }
  174. .btn-main {
  175. background: var(--primary);
  176. border-color: var(--primary);
  177. color: #fff;
  178. font-weight: 600;
  179. }
  180. .mock-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  181. .mock-table th {
  182. text-align: left;
  183. background: var(--table-head);
  184. color: var(--text-muted);
  185. font-weight: 600;
  186. padding: 10px 14px;
  187. border-bottom: 1px solid var(--border);
  188. }
  189. .mock-table td {
  190. padding: 10px 14px;
  191. border-bottom: 1px solid var(--border);
  192. color: var(--text);
  193. }
  194. .mock-table tr:nth-child(even) td { background: var(--row-alt); }
  195. .tag {
  196. display: inline-block;
  197. padding: 2px 8px;
  198. border-radius: 999px;
  199. font-size: 12px;
  200. background: var(--primary-bg);
  201. color: var(--primary-dark);
  202. font-weight: 600;
  203. }
  204. .space-badge {
  205. display: inline-flex;
  206. align-items: center;
  207. gap: 6px;
  208. font-size: 11px;
  209. color: var(--text-muted);
  210. background: #fff7ed;
  211. border: 1px solid #fed7aa;
  212. border-radius: 6px;
  213. padding: 4px 8px;
  214. }
  215. .space-badge em {
  216. font-style: normal;
  217. font-weight: 700;
  218. color: #c2410c;
  219. }
  220. .user-chip {
  221. display: flex;
  222. align-items: center;
  223. gap: 8px;
  224. color: inherit;
  225. font-size: 13px;
  226. white-space: nowrap;
  227. }
  228. .avatar {
  229. width: 28px;
  230. height: 28px;
  231. border-radius: 50%;
  232. background: rgba(255,255,255,0.25);
  233. border: 1px solid rgba(255,255,255,0.35);
  234. }
  235. .avatar.dark {
  236. background: var(--primary-bg);
  237. border-color: var(--border);
  238. }
  239. /* ========== A: 现状门户 ========== */
  240. .a-header {
  241. height: 56px;
  242. background: var(--portal-green);
  243. color: #fff;
  244. display: flex;
  245. align-items: center;
  246. justify-content: space-between;
  247. padding: 0 20px;
  248. gap: 12px;
  249. }
  250. .a-brand {
  251. display: flex;
  252. align-items: center;
  253. gap: 10px;
  254. font-weight: 700;
  255. font-size: 15px;
  256. flex-shrink: 0;
  257. }
  258. .a-logo {
  259. width: 32px;
  260. height: 32px;
  261. border-radius: 8px;
  262. background: rgba(255,255,255,0.2);
  263. display: grid;
  264. place-items: center;
  265. font-size: 12px;
  266. font-weight: 800;
  267. }
  268. .a-modules {
  269. display: flex;
  270. gap: 6px;
  271. flex: 1;
  272. min-width: 0;
  273. overflow: hidden;
  274. }
  275. .a-mod {
  276. appearance: none;
  277. border: 1px solid rgba(255,255,255,0.25);
  278. background: rgba(255,255,255,0.12);
  279. color: #fff;
  280. border-radius: 8px;
  281. padding: 6px 12px;
  282. font-size: 13px;
  283. white-space: nowrap;
  284. cursor: pointer;
  285. }
  286. .a-mod.is-active {
  287. background: #fff;
  288. color: var(--portal-green);
  289. border-color: #fff;
  290. font-weight: 600;
  291. }
  292. .a-body { display: flex; flex: 1; min-height: 0; }
  293. .a-side {
  294. width: 220px;
  295. flex-shrink: 0;
  296. background: var(--surface);
  297. border-right: 1px solid var(--border);
  298. padding: 16px 12px;
  299. }
  300. .a-side .group-title {
  301. font-size: 12px;
  302. font-weight: 700;
  303. color: var(--text-muted);
  304. padding: 8px 12px;
  305. letter-spacing: 0.02em;
  306. }
  307. .a-side a {
  308. display: block;
  309. padding: 8px 12px;
  310. margin: 2px 0;
  311. border-radius: 8px;
  312. color: var(--text-muted);
  313. text-decoration: none;
  314. font-size: 13px;
  315. font-weight: 500;
  316. }
  317. .a-side a:hover { background: var(--row-alt); color: var(--text); }
  318. .a-side a.active {
  319. background: var(--primary-bg);
  320. color: var(--primary-dark);
  321. font-weight: 600;
  322. }
  323. .width-callout {
  324. margin: 12px;
  325. padding: 8px 10px;
  326. border-radius: 8px;
  327. border: 1px dashed #fdba74;
  328. background: #fffbeb;
  329. font-size: 11px;
  330. color: #9a3412;
  331. line-height: 1.4;
  332. }
  333. /* ========== B: 纯顶栏横向 + 下拉 ========== */
  334. .b-top {
  335. height: 56px;
  336. background: var(--surface);
  337. border-bottom: 1px solid var(--border);
  338. display: flex;
  339. align-items: center;
  340. padding: 0 20px;
  341. gap: 16px;
  342. }
  343. .b-brand {
  344. display: flex;
  345. align-items: center;
  346. gap: 8px;
  347. font-weight: 700;
  348. font-size: 15px;
  349. flex-shrink: 0;
  350. color: var(--text);
  351. }
  352. .b-brand span { color: var(--primary); }
  353. .b-nav {
  354. display: flex;
  355. align-items: stretch;
  356. gap: 2px;
  357. flex: 1;
  358. min-width: 0;
  359. height: 100%;
  360. }
  361. .b-item {
  362. position: relative;
  363. display: flex;
  364. align-items: center;
  365. height: 100%;
  366. }
  367. .b-link {
  368. appearance: none;
  369. border: 0;
  370. background: transparent;
  371. padding: 0 14px;
  372. height: 100%;
  373. font-size: 13px;
  374. font-weight: 500;
  375. color: var(--text-muted);
  376. cursor: pointer;
  377. display: flex;
  378. align-items: center;
  379. gap: 4px;
  380. border-bottom: 2px solid transparent;
  381. }
  382. .b-link:hover { color: var(--text); background: var(--row-alt); }
  383. .b-item.is-active > .b-link {
  384. color: var(--primary-dark);
  385. font-weight: 600;
  386. border-bottom-color: var(--primary);
  387. }
  388. .b-drop {
  389. display: none;
  390. position: absolute;
  391. top: calc(100% - 2px);
  392. left: 0;
  393. min-width: 180px;
  394. background: var(--surface);
  395. border: 1px solid var(--border);
  396. border-radius: 10px;
  397. box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
  398. padding: 6px;
  399. z-index: 20;
  400. }
  401. .b-item:hover .b-drop,
  402. .b-item:focus-within .b-drop { display: block; }
  403. .b-drop a {
  404. display: block;
  405. padding: 8px 12px;
  406. border-radius: 8px;
  407. color: var(--text-muted);
  408. text-decoration: none;
  409. font-size: 13px;
  410. }
  411. .b-drop a:hover,
  412. .b-drop a.active {
  413. background: var(--primary-bg);
  414. color: var(--primary-dark);
  415. }
  416. .b-actions {
  417. display: flex;
  418. align-items: center;
  419. gap: 12px;
  420. flex-shrink: 0;
  421. color: var(--text);
  422. }
  423. /* ========== C: 双层顶栏 ========== */
  424. .c-l1 {
  425. height: 48px;
  426. background: var(--portal-green);
  427. color: #fff;
  428. display: flex;
  429. align-items: center;
  430. padding: 0 20px;
  431. gap: 16px;
  432. }
  433. .c-l1 .b-brand { color: #fff; }
  434. .c-l1 .b-brand span { color: #d1fae5; }
  435. .c-l1-nav { display: flex; gap: 4px; flex: 1; min-width: 0; }
  436. .c-l1-btn {
  437. appearance: none;
  438. border: 0;
  439. background: transparent;
  440. color: rgba(255,255,255,0.85);
  441. padding: 6px 12px;
  442. border-radius: 8px;
  443. font-size: 13px;
  444. cursor: pointer;
  445. }
  446. .c-l1-btn.is-active,
  447. .c-l1-btn:hover {
  448. background: rgba(255,255,255,0.18);
  449. color: #fff;
  450. font-weight: 600;
  451. }
  452. .c-l2 {
  453. height: 44px;
  454. background: var(--surface);
  455. border-bottom: 1px solid var(--border);
  456. display: flex;
  457. align-items: center;
  458. padding: 0 20px;
  459. gap: 4px;
  460. overflow-x: auto;
  461. }
  462. .c-l2 a {
  463. text-decoration: none;
  464. color: var(--text-muted);
  465. font-size: 13px;
  466. padding: 6px 12px;
  467. border-radius: 8px;
  468. white-space: nowrap;
  469. font-weight: 500;
  470. }
  471. .c-l2 a:hover { background: var(--row-alt); color: var(--text); }
  472. .c-l2 a.active {
  473. background: var(--primary-bg);
  474. color: var(--primary-dark);
  475. font-weight: 600;
  476. }
  477. /* ========== D: Mega Menu ========== */
  478. .d-mega {
  479. display: none;
  480. position: absolute;
  481. top: 100%;
  482. left: 50%;
  483. transform: translateX(-50%);
  484. width: min(720px, calc(100vw - 48px));
  485. background: var(--surface);
  486. border: 1px solid var(--border);
  487. border-radius: 12px;
  488. box-shadow: 0 12px 32px rgba(15, 23, 42, 0.1);
  489. padding: 16px;
  490. z-index: 30;
  491. grid-template-columns: repeat(3, 1fr);
  492. gap: 12px 20px;
  493. }
  494. .d-item { position: relative; height: 100%; display: flex; align-items: center; }
  495. .d-item:hover .d-mega,
  496. .d-item:focus-within .d-mega { display: grid; }
  497. .d-col h4 {
  498. margin: 0 0 8px;
  499. font-size: 12px;
  500. color: var(--text-muted);
  501. font-weight: 700;
  502. letter-spacing: 0.02em;
  503. }
  504. .d-col a {
  505. display: block;
  506. padding: 6px 8px;
  507. margin: 0 -8px;
  508. border-radius: 6px;
  509. color: var(--text);
  510. text-decoration: none;
  511. font-size: 13px;
  512. }
  513. .d-col a:hover { background: var(--primary-bg); color: var(--primary-dark); }
  514. .d-col a.active {
  515. background: var(--primary-bg);
  516. color: var(--primary-dark);
  517. font-weight: 600;
  518. }
  519. /* ========== E: 顶栏一级 + 窄侧栏二级 ========== */
  520. .e-body { display: flex; flex: 1; min-height: 0; }
  521. .e-side {
  522. width: 160px;
  523. flex-shrink: 0;
  524. background: var(--surface);
  525. border-right: 1px solid var(--border);
  526. padding: 12px 8px;
  527. }
  528. .e-side a {
  529. display: block;
  530. padding: 8px 10px;
  531. margin: 2px 0;
  532. border-radius: 8px;
  533. color: var(--text-muted);
  534. text-decoration: none;
  535. font-size: 13px;
  536. }
  537. .e-side a:hover { background: var(--row-alt); color: var(--text); }
  538. .e-side a.active {
  539. background: var(--primary-bg);
  540. color: var(--primary-dark);
  541. font-weight: 600;
  542. }
  543. .gain-bar {
  544. display: flex;
  545. flex-wrap: wrap;
  546. gap: 8px;
  547. margin-bottom: 12px;
  548. }
  549. .gain-pill {
  550. font-size: 11px;
  551. padding: 4px 8px;
  552. border-radius: 6px;
  553. background: var(--primary-bg);
  554. color: var(--primary-dark);
  555. font-weight: 600;
  556. border: 1px solid #a7f3d0;
  557. }
  558. .gain-pill.warn {
  559. background: #fff7ed;
  560. color: #c2410c;
  561. border-color: #fed7aa;
  562. }
  563. </style>
  564. </head>
  565. <body>
  566. <div class="picker">
  567. <div class="picker-head">
  568. <h1>web-admin 菜单布局方案对比</h1>
  569. <p>Fresh Mint Token · 仅 Demo,未改产品代码 · 点击下方切换</p>
  570. </div>
  571. <div class="picker-tabs" role="tablist">
  572. <button type="button" class="picker-tab is-active" data-demo="a" role="tab">
  573. <strong>A · 现状(门户)</strong>
  574. <span>顶栏模块卡 + 左侧 220px 子菜单</span>
  575. </button>
  576. <button type="button" class="picker-tab" data-demo="b" role="tab">
  577. <strong>B · 纯顶栏下拉</strong>
  578. <span>一级横排,二级 Hover 下拉</span>
  579. </button>
  580. <button type="button" class="picker-tab" data-demo="c" role="tab">
  581. <strong>C · 双层顶栏</strong>
  582. <span>一级绿条 + 二级白条,无侧栏</span>
  583. </button>
  584. <button type="button" class="picker-tab" data-demo="d" role="tab">
  585. <strong>D · Mega 面板</strong>
  586. <span>一级横排 + 大面板分组二级</span>
  587. </button>
  588. <button type="button" class="picker-tab" data-demo="e" role="tab">
  589. <strong>E · 顶栏+窄侧栏</strong>
  590. <span>一级上移,侧栏缩至 160px</span>
  591. </button>
  592. </div>
  593. <p class="picker-note" id="demoNote">
  594. <b>A 现状:</b>客户感知「左侧占空间」主要来自当前 PORTAL 布局的固定侧栏(约 220–270px)。内容区被横向压缩,宽表/操作列更容易出现横向滚动。
  595. </p>
  596. </div>
  597. <div class="stage">
  598. <!-- A -->
  599. <div class="frame is-active" id="demo-a" data-label="A">
  600. <header class="a-header">
  601. <div class="a-brand"><div class="a-logo">SX</div>山峡一体化门户</div>
  602. <div class="a-modules">
  603. <button type="button" class="a-mod is-active">CRM</button>
  604. <button type="button" class="a-mod">细胞存储</button>
  605. <button type="button" class="a-mod">报销</button>
  606. <button type="button" class="a-mod">系统管理</button>
  607. <button type="button" class="a-mod">Demo</button>
  608. </div>
  609. <div class="user-chip"><div class="avatar"></div>管理员</div>
  610. </header>
  611. <div class="a-body">
  612. <aside class="a-side">
  613. <div class="group-title">客户与商机</div>
  614. <a href="#" class="active">客户管理</a>
  615. <a href="#">商机跟进</a>
  616. <a href="#">合同管理</a>
  617. <div class="group-title">商品</div>
  618. <a href="#">商品列表</a>
  619. <a href="#">分类管理</a>
  620. <div class="width-callout">侧栏常宽 ≈ 220–270px<br />宽屏列表少约 1/6~1/5 可用宽度</div>
  621. </aside>
  622. <div class="mock-content">
  623. <div class="gain-bar">
  624. <span class="gain-pill warn">内容区最窄 · 基线对照</span>
  625. <span class="space-badge">侧栏占用 <em>≈220px</em> 固定宽度</span>
  626. </div>
  627. <div class="mock-panel">
  628. <div class="mock-panel-top"><h2>客户列表</h2></div>
  629. <div class="mock-toolbar">
  630. <span>已选 0 项</span>
  631. <button type="button" class="btn btn-main">新增</button>
  632. <button type="button" class="btn">导出</button>
  633. </div>
  634. <table class="mock-table">
  635. <thead><tr><th>客户名称</th><th>区域</th><th>状态</th><th>更新时间</th></tr></thead>
  636. <tbody>
  637. <tr><td>华东生物科技</td><td>上海 / 浦东</td><td><span class="tag">合作中</span></td><td>2026-07-18</td></tr>
  638. <tr><td>三峡医械</td><td>湖北 / 宜昌</td><td><span class="tag">合作中</span></td><td>2026-07-17</td></tr>
  639. <tr><td>绿源检测</td><td>江苏 / 苏州</td><td><span class="tag">跟进中</span></td><td>2026-07-16</td></tr>
  640. </tbody>
  641. </table>
  642. </div>
  643. </div>
  644. </div>
  645. </div>
  646. <!-- B -->
  647. <div class="frame" id="demo-b" data-label="B">
  648. <header class="b-top">
  649. <div class="b-brand">山峡<span>门户</span></div>
  650. <nav class="b-nav" aria-label="主导航">
  651. <div class="b-item is-active">
  652. <button type="button" class="b-link">CRM ▾</button>
  653. <div class="b-drop">
  654. <a href="#" class="active">客户管理</a>
  655. <a href="#">商机跟进</a>
  656. <a href="#">合同管理</a>
  657. <a href="#">商品列表</a>
  658. <a href="#">分类管理</a>
  659. </div>
  660. </div>
  661. <div class="b-item">
  662. <button type="button" class="b-link">细胞存储 ▾</button>
  663. <div class="b-drop">
  664. <a href="#">样本接收</a>
  665. <a href="#">质检工单</a>
  666. <a href="#">协议管理</a>
  667. </div>
  668. </div>
  669. <div class="b-item">
  670. <button type="button" class="b-link">报销 ▾</button>
  671. <div class="b-drop">
  672. <a href="#">我的报销</a>
  673. <a href="#">待审批</a>
  674. <a href="#">借款申请</a>
  675. </div>
  676. </div>
  677. <div class="b-item">
  678. <button type="button" class="b-link">系统管理 ▾</button>
  679. <div class="b-drop">
  680. <a href="#">用户</a>
  681. <a href="#">角色</a>
  682. <a href="#">菜单</a>
  683. <a href="#">租户</a>
  684. </div>
  685. </div>
  686. <div class="b-item">
  687. <button type="button" class="b-link">Demo ▾</button>
  688. <div class="b-drop">
  689. <a href="#">工作台</a>
  690. <a href="#">标准列表</a>
  691. <a href="#">订单列表</a>
  692. </div>
  693. </div>
  694. </nav>
  695. <div class="b-actions">
  696. <div class="user-chip"><div class="avatar dark"></div>管理员</div>
  697. </div>
  698. </header>
  699. <div class="mock-content">
  700. <div class="gain-bar">
  701. <span class="gain-pill">释放全部侧栏宽度 · 内容区最宽</span>
  702. <span class="space-badge">侧栏占用 <em>0px</em></span>
  703. </div>
  704. <div class="mock-panel">
  705. <div class="mock-panel-top"><h2>客户列表</h2></div>
  706. <div class="mock-toolbar">
  707. <span>已选 0 项</span>
  708. <button type="button" class="btn btn-main">新增</button>
  709. <button type="button" class="btn">导出</button>
  710. </div>
  711. <table class="mock-table">
  712. <thead><tr><th>客户名称</th><th>区域</th><th>联系人</th><th>状态</th><th>更新时间</th></tr></thead>
  713. <tbody>
  714. <tr><td>华东生物科技</td><td>上海 / 浦东</td><td>王敏</td><td><span class="tag">合作中</span></td><td>2026-07-18</td></tr>
  715. <tr><td>三峡医械</td><td>湖北 / 宜昌</td><td>李强</td><td><span class="tag">合作中</span></td><td>2026-07-17</td></tr>
  716. <tr><td>绿源检测</td><td>江苏 / 苏州</td><td>陈洁</td><td><span class="tag">跟进中</span></td><td>2026-07-16</td></tr>
  717. </tbody>
  718. </table>
  719. </div>
  720. </div>
  721. </div>
  722. <!-- C -->
  723. <div class="frame" id="demo-c" data-label="C">
  724. <header class="c-l1">
  725. <div class="b-brand">山峡<span>门户</span></div>
  726. <nav class="c-l1-nav">
  727. <button type="button" class="c-l1-btn is-active">CRM</button>
  728. <button type="button" class="c-l1-btn">细胞存储</button>
  729. <button type="button" class="c-l1-btn">报销</button>
  730. <button type="button" class="c-l1-btn">系统管理</button>
  731. <button type="button" class="c-l1-btn">Demo</button>
  732. </nav>
  733. <div class="user-chip"><div class="avatar"></div>管理员</div>
  734. </header>
  735. <nav class="c-l2" aria-label="二级导航">
  736. <a href="#" class="active">客户管理</a>
  737. <a href="#">商机跟进</a>
  738. <a href="#">合同管理</a>
  739. <a href="#">商品列表</a>
  740. <a href="#">分类管理</a>
  741. </nav>
  742. <div class="mock-content">
  743. <div class="gain-bar">
  744. <span class="gain-pill">无侧栏 · 二级始终可见(无需 Hover)</span>
  745. <span class="space-badge">额外顶栏高度 <em>+44px</em>,宽度全释放</span>
  746. </div>
  747. <div class="mock-panel">
  748. <div class="mock-panel-top"><h2>客户列表</h2></div>
  749. <div class="mock-toolbar">
  750. <span>已选 0 项</span>
  751. <button type="button" class="btn btn-main">新增</button>
  752. <button type="button" class="btn">导出</button>
  753. </div>
  754. <table class="mock-table">
  755. <thead><tr><th>客户名称</th><th>区域</th><th>联系人</th><th>状态</th><th>更新时间</th></tr></thead>
  756. <tbody>
  757. <tr><td>华东生物科技</td><td>上海 / 浦东</td><td>王敏</td><td><span class="tag">合作中</span></td><td>2026-07-18</td></tr>
  758. <tr><td>三峡医械</td><td>湖北 / 宜昌</td><td>李强</td><td><span class="tag">合作中</span></td><td>2026-07-17</td></tr>
  759. <tr><td>绿源检测</td><td>江苏 / 苏州</td><td>陈洁</td><td><span class="tag">跟进中</span></td><td>2026-07-16</td></tr>
  760. </tbody>
  761. </table>
  762. </div>
  763. </div>
  764. </div>
  765. <!-- D -->
  766. <div class="frame" id="demo-d" data-label="D">
  767. <header class="b-top">
  768. <div class="b-brand">山峡<span>门户</span></div>
  769. <nav class="b-nav">
  770. <div class="d-item">
  771. <button type="button" class="b-link" style="border-bottom-color:var(--primary);color:var(--primary-dark);font-weight:600">CRM ▾</button>
  772. <div class="d-mega">
  773. <div class="d-col">
  774. <h4>客户与商机</h4>
  775. <a href="#" class="active">客户管理</a>
  776. <a href="#">商机跟进</a>
  777. <a href="#">合同管理</a>
  778. </div>
  779. <div class="d-col">
  780. <h4>商品主数据</h4>
  781. <a href="#">商品列表</a>
  782. <a href="#">分类管理</a>
  783. <a href="#">单位管理</a>
  784. </div>
  785. <div class="d-col">
  786. <h4>分析</h4>
  787. <a href="#">销售看板</a>
  788. <a href="#">区域报表</a>
  789. </div>
  790. </div>
  791. </div>
  792. <div class="d-item">
  793. <button type="button" class="b-link">细胞存储 ▾</button>
  794. <div class="d-mega">
  795. <div class="d-col">
  796. <h4>样本</h4>
  797. <a href="#">样本接收</a>
  798. <a href="#">质检工单</a>
  799. </div>
  800. <div class="d-col">
  801. <h4>协议</h4>
  802. <a href="#">协议管理</a>
  803. <a href="#">归档查询</a>
  804. </div>
  805. <div class="d-col">
  806. <h4>其他</h4>
  807. <a href="#">库存概览</a>
  808. </div>
  809. </div>
  810. </div>
  811. <div class="d-item"><button type="button" class="b-link">报销 ▾</button></div>
  812. <div class="d-item"><button type="button" class="b-link">系统管理 ▾</button></div>
  813. <div class="d-item"><button type="button" class="b-link">Demo ▾</button></div>
  814. </nav>
  815. <div class="b-actions">
  816. <div class="user-chip"><div class="avatar dark"></div>管理员</div>
  817. </div>
  818. </header>
  819. <div class="mock-content">
  820. <div class="gain-bar">
  821. <span class="gain-pill">适合二级很多、需分组浏览的模块</span>
  822. <span class="space-badge">侧栏 <em>0px</em> · Hover「CRM」查看大面板</span>
  823. </div>
  824. <div class="mock-panel">
  825. <div class="mock-panel-top"><h2>客户列表</h2></div>
  826. <div class="mock-toolbar">
  827. <span>已选 0 项</span>
  828. <button type="button" class="btn btn-main">新增</button>
  829. <button type="button" class="btn">导出</button>
  830. </div>
  831. <table class="mock-table">
  832. <thead><tr><th>客户名称</th><th>区域</th><th>联系人</th><th>状态</th><th>更新时间</th></tr></thead>
  833. <tbody>
  834. <tr><td>华东生物科技</td><td>上海 / 浦东</td><td>王敏</td><td><span class="tag">合作中</span></td><td>2026-07-18</td></tr>
  835. <tr><td>三峡医械</td><td>湖北 / 宜昌</td><td>李强</td><td><span class="tag">合作中</span></td><td>2026-07-17</td></tr>
  836. <tr><td>绿源检测</td><td>江苏 / 苏州</td><td>陈洁</td><td><span class="tag">跟进中</span></td><td>2026-07-16</td></tr>
  837. </tbody>
  838. </table>
  839. </div>
  840. </div>
  841. </div>
  842. <!-- E -->
  843. <div class="frame" id="demo-e" data-label="E">
  844. <header class="c-l1">
  845. <div class="b-brand">山峡<span>门户</span></div>
  846. <nav class="c-l1-nav">
  847. <button type="button" class="c-l1-btn is-active">CRM</button>
  848. <button type="button" class="c-l1-btn">细胞存储</button>
  849. <button type="button" class="c-l1-btn">报销</button>
  850. <button type="button" class="c-l1-btn">系统管理</button>
  851. <button type="button" class="c-l1-btn">Demo</button>
  852. </nav>
  853. <div class="user-chip"><div class="avatar"></div>管理员</div>
  854. </header>
  855. <div class="e-body">
  856. <aside class="e-side">
  857. <a href="#" class="active">客户管理</a>
  858. <a href="#">商机跟进</a>
  859. <a href="#">合同管理</a>
  860. <a href="#">商品列表</a>
  861. <a href="#">分类管理</a>
  862. <div class="width-callout" style="margin:10px 4px">窄侧栏 160px<br />比现状约省 60–110px</div>
  863. </aside>
  864. <div class="mock-content">
  865. <div class="gain-bar">
  866. <span class="gain-pill">折中:一级上移,二级仍常驻可见</span>
  867. <span class="space-badge">侧栏 <em>160px</em>(可再折叠)</span>
  868. </div>
  869. <div class="mock-panel">
  870. <div class="mock-panel-top"><h2>客户列表</h2></div>
  871. <div class="mock-toolbar">
  872. <span>已选 0 项</span>
  873. <button type="button" class="btn btn-main">新增</button>
  874. <button type="button" class="btn">导出</button>
  875. </div>
  876. <table class="mock-table">
  877. <thead><tr><th>客户名称</th><th>区域</th><th>状态</th><th>更新时间</th></tr></thead>
  878. <tbody>
  879. <tr><td>华东生物科技</td><td>上海 / 浦东</td><td><span class="tag">合作中</span></td><td>2026-07-18</td></tr>
  880. <tr><td>三峡医械</td><td>湖北 / 宜昌</td><td><span class="tag">合作中</span></td><td>2026-07-17</td></tr>
  881. <tr><td>绿源检测</td><td>江苏 / 苏州</td><td><span class="tag">跟进中</span></td><td>2026-07-16</td></tr>
  882. </tbody>
  883. </table>
  884. </div>
  885. </div>
  886. </div>
  887. </div>
  888. </div>
  889. <script>
  890. const notes = {
  891. a: '<b>A 现状(PORTAL):</b>顶栏选模块 + 左侧展示该模块子菜单。与当前 web-admin 默认布局最接近。客户说的「占空间」主要指这条固定侧栏。',
  892. b: '<b>B 纯顶栏下拉:</b>内容区最宽,实现成本相对低(工程里已有 ArtHorizontalMenu / MenuTypeEnum.TOP)。风险:二级依赖 Hover,触控/键盘可达性与「同模块内频繁切换」体验偏弱;一级过多时会挤到省略号。',
  893. c: '<b>C 双层顶栏:</b>推荐优先给客户看。无侧栏占宽,二级始终可见、单击即达,适合 B 端「在同一模块内反复切页面」。代价是垂直方向多约 44px。',
  894. d: '<b>D Mega 面板:</b>适合二级菜单很多、需要分组的模块。信息密度高,但交互更重,移动端/窄屏要另做适配。',
  895. e: '<b>E 顶栏 + 窄侧栏:</b>接近现状 PORTAL / TOP_LEFT 思路,只是把一级从侧栏挪到顶栏并收窄。改动小、风险低,但空间收益有限。'
  896. };
  897. const tabs = document.querySelectorAll('.picker-tab');
  898. const frames = document.querySelectorAll('.frame');
  899. const noteEl = document.getElementById('demoNote');
  900. tabs.forEach((tab) => {
  901. tab.addEventListener('click', () => {
  902. const id = tab.getAttribute('data-demo');
  903. tabs.forEach((t) => t.classList.toggle('is-active', t === tab));
  904. frames.forEach((f) => f.classList.toggle('is-active', f.id === 'demo-' + id));
  905. noteEl.innerHTML = notes[id] || '';
  906. });
  907. });
  908. </script>
  909. </body>
  910. </html>