zkxw-mobile-bright-theme-demos.html 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  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" />
  6. <title>mobile-h5 · 明亮清爽配色 Demo</title>
  7. <style>
  8. * { box-sizing: border-box; }
  9. html, body { margin: 0; min-height: 100%; }
  10. body {
  11. font-family: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", -apple-system, system-ui, sans-serif;
  12. color: #1e293b;
  13. background:
  14. radial-gradient(900px 420px at 8% -8%, rgba(52, 211, 153, 0.18), transparent 55%),
  15. radial-gradient(700px 380px at 92% 0%, rgba(125, 211, 252, 0.16), transparent 50%),
  16. linear-gradient(180deg, #f8fffc 0%, #f4f7fb 45%, #f7f8fa 100%);
  17. line-height: 1.45;
  18. }
  19. .page {
  20. max-width: 1180px;
  21. margin: 0 auto;
  22. padding: 28px 18px 64px;
  23. }
  24. .hero h1 {
  25. margin: 0 0 8px;
  26. font-size: 24px;
  27. letter-spacing: -0.02em;
  28. font-weight: 720;
  29. }
  30. .hero p {
  31. margin: 0;
  32. max-width: 720px;
  33. color: #64748b;
  34. font-size: 14px;
  35. }
  36. .hero .note {
  37. margin-top: 12px;
  38. display: inline-block;
  39. padding: 8px 12px;
  40. border-radius: 10px;
  41. background: #fff;
  42. border: 1px solid #e2e8f0;
  43. font-size: 12px;
  44. color: #64748b;
  45. }
  46. .hero .note strong { color: #0f766e; }
  47. .theme-tabs {
  48. display: flex;
  49. flex-wrap: wrap;
  50. gap: 10px;
  51. margin: 22px 0 20px;
  52. }
  53. .theme-tab {
  54. appearance: none;
  55. border: 1px solid #e2e8f0;
  56. background: #fff;
  57. border-radius: 999px;
  58. padding: 10px 16px;
  59. font-size: 13px;
  60. font-weight: 600;
  61. color: #475569;
  62. cursor: pointer;
  63. display: inline-flex;
  64. align-items: center;
  65. gap: 8px;
  66. transition: border-color .15s, box-shadow .15s, color .15s;
  67. }
  68. .theme-tab:hover { border-color: #94a3b8; }
  69. .theme-tab.is-active {
  70. color: var(--t-brand-dark);
  71. border-color: var(--t-brand);
  72. box-shadow: 0 0 0 3px color-mix(in srgb, var(--t-brand) 22%, transparent);
  73. background: var(--t-brand-soft);
  74. }
  75. .theme-tab .dot {
  76. width: 10px; height: 10px; border-radius: 50%;
  77. background: var(--swatch, #22c55e);
  78. }
  79. .theme-tab .badge {
  80. font-size: 10px;
  81. font-weight: 700;
  82. padding: 2px 6px;
  83. border-radius: 999px;
  84. background: #ecfdf5;
  85. color: #047857;
  86. }
  87. .theme-tab.is-current .badge {
  88. background: #f1f5f9;
  89. color: #64748b;
  90. }
  91. .layout {
  92. display: grid;
  93. grid-template-columns: minmax(280px, 360px) 1fr;
  94. gap: 22px;
  95. align-items: start;
  96. }
  97. @media (max-width: 900px) {
  98. .layout { grid-template-columns: 1fr; }
  99. }
  100. .panel {
  101. background: rgba(255,255,255,.92);
  102. border: 1px solid #e2e8f0;
  103. border-radius: 18px;
  104. padding: 18px;
  105. box-shadow: 0 10px 30px rgba(15, 23, 42, 0.05);
  106. }
  107. .panel h2 {
  108. margin: 0 0 4px;
  109. font-size: 16px;
  110. }
  111. .panel .sub {
  112. margin: 0 0 14px;
  113. font-size: 12px;
  114. color: #64748b;
  115. }
  116. .token-grid {
  117. display: grid;
  118. gap: 8px;
  119. }
  120. .token {
  121. display: grid;
  122. grid-template-columns: 36px 1fr auto;
  123. gap: 10px;
  124. align-items: center;
  125. padding: 8px 10px;
  126. border-radius: 12px;
  127. border: 1px solid #eef2f7;
  128. background: #fafbfc;
  129. }
  130. .token i {
  131. width: 36px; height: 36px;
  132. border-radius: 10px;
  133. border: 1px solid rgba(15,23,42,.06);
  134. display: block;
  135. }
  136. .token .name {
  137. font-size: 12px;
  138. font-weight: 650;
  139. color: #334155;
  140. }
  141. .token .desc {
  142. font-size: 11px;
  143. color: #94a3b8;
  144. }
  145. .token code {
  146. font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  147. font-size: 11px;
  148. color: #0f766e;
  149. background: #f0fdfa;
  150. padding: 3px 6px;
  151. border-radius: 6px;
  152. }
  153. .stage {
  154. display: flex;
  155. flex-direction: column;
  156. align-items: center;
  157. gap: 14px;
  158. }
  159. .stage-caption {
  160. width: 100%;
  161. max-width: 390px;
  162. font-size: 13px;
  163. color: #64748b;
  164. text-align: center;
  165. }
  166. .stage-caption strong { color: #0f172a; }
  167. .phone {
  168. width: 390px;
  169. height: 780px;
  170. background: #0f172a;
  171. border-radius: 40px;
  172. padding: 10px;
  173. box-shadow:
  174. 0 28px 60px rgba(15, 23, 42, 0.18),
  175. inset 0 0 0 1px rgba(255,255,255,.08);
  176. position: relative;
  177. }
  178. .phone::before {
  179. content: "";
  180. position: absolute;
  181. top: 16px; left: 50%;
  182. transform: translateX(-50%);
  183. width: 108px; height: 24px;
  184. background: #020617;
  185. border-radius: 16px;
  186. z-index: 6;
  187. }
  188. .phone-screen {
  189. height: 100%;
  190. border-radius: 32px;
  191. overflow: hidden;
  192. background: var(--t-bg);
  193. color: var(--t-text);
  194. display: flex;
  195. flex-direction: column;
  196. }
  197. .screen-scroll {
  198. flex: 1;
  199. overflow-y: auto;
  200. -webkit-overflow-scrolling: touch;
  201. }
  202. /* —— 完整工作台界面 —— */
  203. .home-header {
  204. padding: 52px 16px 22px;
  205. position: relative;
  206. overflow: hidden;
  207. border-radius: 0 0 22px 22px;
  208. background: var(--t-header-bg);
  209. color: var(--t-header-fg);
  210. }
  211. .home-header::after {
  212. content: "";
  213. position: absolute;
  214. right: -36px; top: -28px;
  215. width: 140px; height: 140px;
  216. border-radius: 50%;
  217. background: var(--t-header-glow);
  218. pointer-events: none;
  219. }
  220. .home-header .brand {
  221. font-size: 12px;
  222. opacity: .78;
  223. letter-spacing: .04em;
  224. margin-bottom: 8px;
  225. position: relative;
  226. z-index: 1;
  227. }
  228. .home-header .row {
  229. display: flex;
  230. justify-content: space-between;
  231. align-items: flex-start;
  232. gap: 12px;
  233. position: relative;
  234. z-index: 1;
  235. }
  236. .home-header h3 {
  237. margin: 0;
  238. font-size: 22px;
  239. font-weight: 720;
  240. letter-spacing: -.01em;
  241. }
  242. .home-header .logout {
  243. font-size: 12px;
  244. opacity: .85;
  245. padding: 4px 0;
  246. white-space: nowrap;
  247. }
  248. .home-header .meta {
  249. margin-top: 10px;
  250. display: flex;
  251. align-items: center;
  252. gap: 8px;
  253. font-size: 12px;
  254. opacity: .82;
  255. position: relative;
  256. z-index: 1;
  257. }
  258. .home-header .meta .dot {
  259. width: 4px; height: 4px; border-radius: 50%;
  260. background: currentColor; opacity: .55;
  261. }
  262. .home-body { padding: 12px 12px 20px; }
  263. .banner {
  264. height: 132px;
  265. border-radius: 16px;
  266. overflow: hidden;
  267. margin-bottom: 12px;
  268. border: 1px solid var(--t-border);
  269. background:
  270. linear-gradient(135deg, var(--t-banner-a), var(--t-banner-b)),
  271. var(--t-brand-soft);
  272. position: relative;
  273. display: flex;
  274. align-items: flex-end;
  275. padding: 14px;
  276. color: var(--t-banner-fg);
  277. }
  278. .banner::before {
  279. content: "";
  280. position: absolute;
  281. inset: 0;
  282. background:
  283. radial-gradient(180px 100px at 85% 20%, rgba(255,255,255,.45), transparent 60%),
  284. radial-gradient(120px 80px at 10% 80%, rgba(255,255,255,.2), transparent 55%);
  285. }
  286. .banner .txt { position: relative; z-index: 1; }
  287. .banner .kicker { font-size: 11px; opacity: .85; margin-bottom: 4px; }
  288. .banner .title { font-size: 16px; font-weight: 700; }
  289. .card {
  290. background: var(--t-surface);
  291. border: 1px solid var(--t-border);
  292. border-radius: 16px;
  293. box-shadow: var(--t-shadow);
  294. padding: 14px 12px;
  295. margin-bottom: 12px;
  296. }
  297. .card-hd {
  298. display: flex;
  299. align-items: center;
  300. justify-content: space-between;
  301. margin-bottom: 12px;
  302. padding: 0 4px;
  303. }
  304. .card-hd h4 {
  305. margin: 0;
  306. font-size: 15px;
  307. font-weight: 680;
  308. color: var(--t-text);
  309. }
  310. .card-hd .hint {
  311. font-size: 11px;
  312. color: var(--t-muted);
  313. }
  314. .menu-grid {
  315. display: grid;
  316. grid-template-columns: repeat(4, 1fr);
  317. gap: 8px 4px;
  318. }
  319. .menu-item {
  320. display: flex;
  321. flex-direction: column;
  322. align-items: center;
  323. gap: 8px;
  324. padding: 8px 4px 6px;
  325. border-radius: 12px;
  326. }
  327. .menu-icon {
  328. width: 44px; height: 44px;
  329. border-radius: 14px;
  330. display: grid;
  331. place-items: center;
  332. font-size: 18px;
  333. font-weight: 700;
  334. }
  335. .menu-item span {
  336. font-size: 11px;
  337. color: var(--t-text);
  338. text-align: center;
  339. line-height: 1.25;
  340. }
  341. .todo {
  342. display: flex;
  343. gap: 10px;
  344. padding: 12px;
  345. border-radius: 14px;
  346. border: 1px solid var(--t-border);
  347. background: var(--t-todo-bg);
  348. margin-bottom: 8px;
  349. }
  350. .todo:last-child { margin-bottom: 0; }
  351. .todo .bar {
  352. width: 4px;
  353. border-radius: 4px;
  354. background: var(--todo-accent, var(--t-brand));
  355. flex-shrink: 0;
  356. }
  357. .todo .body { flex: 1; min-width: 0; }
  358. .todo .top {
  359. display: flex;
  360. justify-content: space-between;
  361. gap: 8px;
  362. margin-bottom: 4px;
  363. }
  364. .todo .name {
  365. font-size: 13px;
  366. font-weight: 650;
  367. color: var(--t-text);
  368. }
  369. .tag {
  370. font-size: 10px;
  371. font-weight: 650;
  372. padding: 2px 7px;
  373. border-radius: 999px;
  374. white-space: nowrap;
  375. }
  376. .tag.warn {
  377. background: color-mix(in srgb, var(--t-warning) 14%, #fff);
  378. color: var(--t-warning);
  379. }
  380. .tag.ok {
  381. background: color-mix(in srgb, var(--t-success) 14%, #fff);
  382. color: var(--t-success);
  383. }
  384. .todo .meta {
  385. font-size: 11px;
  386. color: var(--t-muted);
  387. }
  388. .cta-row {
  389. display: flex;
  390. gap: 8px;
  391. margin-top: 4px;
  392. }
  393. .btn {
  394. flex: 1;
  395. height: 40px;
  396. border-radius: 12px;
  397. border: 1px solid var(--t-border);
  398. background: #fff;
  399. color: var(--t-text);
  400. font-size: 13px;
  401. font-weight: 650;
  402. display: grid;
  403. place-items: center;
  404. }
  405. .btn.primary {
  406. background: var(--t-brand);
  407. border-color: var(--t-brand);
  408. color: #fff;
  409. box-shadow: 0 6px 16px color-mix(in srgb, var(--t-brand) 28%, transparent);
  410. }
  411. .compare {
  412. margin-top: 28px;
  413. display: grid;
  414. grid-template-columns: 1fr 1fr;
  415. gap: 14px;
  416. }
  417. @media (max-width: 720px) {
  418. .compare { grid-template-columns: 1fr; }
  419. }
  420. .compare .mini {
  421. border-radius: 16px;
  422. overflow: hidden;
  423. border: 1px solid #e2e8f0;
  424. background: #fff;
  425. }
  426. .compare .mini-hd {
  427. padding: 10px 12px;
  428. font-size: 12px;
  429. font-weight: 650;
  430. border-bottom: 1px solid #eef2f7;
  431. color: #475569;
  432. }
  433. .compare .mini-body { height: 88px; }
  434. </style>
  435. </head>
  436. <body>
  437. <div class="page">
  438. <div class="hero">
  439. <h1>mobile-h5 · 明亮清爽配色方案</h1>
  440. <p>
  441. 针对「整体偏暗、顶栏沉重」的问题:去掉深绿顶栏(#14532d),改用浅色头图 + 通透背景。
  442. 下方可切换方案,左侧是完整 Token,右侧是工作台完整界面预览。
  443. </p>
  444. <div class="note">点选方案后,在对话里告诉我选哪套(或组合喜好)。文件也可本地打开:<strong>mobile-ui/zkxw-mobile-bright-theme-demos.html</strong></div>
  445. </div>
  446. <div class="theme-tabs" id="tabs"></div>
  447. <div class="layout">
  448. <aside class="panel">
  449. <h2 id="themeTitle">—</h2>
  450. <p class="sub" id="themeDesc">—</p>
  451. <div class="token-grid" id="tokens"></div>
  452. </aside>
  453. <section class="stage">
  454. <div class="stage-caption">完整界面预览 · <strong id="previewName">—</strong></div>
  455. <div class="phone" id="phone">
  456. <div class="phone-screen">
  457. <div class="screen-scroll">
  458. <header class="home-header">
  459. <div class="brand">中科兴皖 · 移动工作台</div>
  460. <div class="row">
  461. <h3>您好,张明</h3>
  462. <div class="logout">退出登录</div>
  463. </div>
  464. <div class="meta">
  465. <span>产品经理</span>
  466. <span class="dot"></span>
  467. <span>细胞存储事业部</span>
  468. </div>
  469. </header>
  470. <div class="home-body">
  471. <div class="banner">
  472. <div class="txt">
  473. <div class="kicker">今日提醒</div>
  474. <div class="title">有 3 条待办审批待处理</div>
  475. </div>
  476. </div>
  477. <div class="card">
  478. <div class="card-hd">
  479. <h4>功能菜单</h4>
  480. <span class="hint">共 8 项</span>
  481. </div>
  482. <div class="menu-grid" id="menus"></div>
  483. </div>
  484. <div class="card">
  485. <div class="card-hd">
  486. <h4>我的待办</h4>
  487. <span class="hint">最近更新</span>
  488. </div>
  489. <div class="todo" style="--todo-accent: var(--t-warning)">
  490. <div class="bar"></div>
  491. <div class="body">
  492. <div class="top">
  493. <div class="name">采集协议审批</div>
  494. <span class="tag warn">待处理</span>
  495. </div>
  496. <div class="meta">申请人 李华 · 今天 09:18</div>
  497. </div>
  498. </div>
  499. <div class="todo" style="--todo-accent: var(--t-brand)">
  500. <div class="bar"></div>
  501. <div class="body">
  502. <div class="top">
  503. <div class="name">样本入库确认</div>
  504. <span class="tag ok">进行中</span>
  505. </div>
  506. <div class="meta">库位 A-12 · 今天 08:42</div>
  507. </div>
  508. </div>
  509. <div class="cta-row">
  510. <div class="btn">查看全部</div>
  511. <div class="btn primary">发起审批</div>
  512. </div>
  513. </div>
  514. </div>
  515. </div>
  516. </div>
  517. </div>
  518. </section>
  519. </div>
  520. <div class="compare">
  521. <div class="mini">
  522. <div class="mini-hd">现状顶栏(偏沉)</div>
  523. <div class="mini-body" style="background:linear-gradient(155deg,#14532d,#16a34a,#22c55e)"></div>
  524. </div>
  525. <div class="mini">
  526. <div class="mini-hd">目标顶栏(明亮)</div>
  527. <div class="mini-body" id="targetHeader" style="background:linear-gradient(160deg,#ecfdf5,#d1fae5)"></div>
  528. </div>
  529. </div>
  530. </div>
  531. <script>
  532. const THEMES = {
  533. mint: {
  534. id: 'mint',
  535. name: 'A · 薄荷微风',
  536. badge: '推荐',
  537. swatch: '#22c55e',
  538. desc: '保留绿色品牌,但顶栏改为浅绿渐变 + 深色字,页面通透。改造成本最低,最贴近现有业务。',
  539. tokens: [
  540. ['brand', '#22c55e', '主色 / 按钮'],
  541. ['brandDark', '#16a34a', '主色深 / 强调文字'],
  542. ['brandSoft', '#ecfdf5', '主色浅底'],
  543. ['headerBg', 'linear-gradient(160deg, #f0fdf4 0%, #d1fae5 58%, #a7f3d0 100%)', '顶栏背景'],
  544. ['headerFg', '#065f46', '顶栏文字'],
  545. ['bg', '#f7fffb', '页面背景'],
  546. ['surface', '#ffffff', '卡片表面'],
  547. ['text', '#0f291e', '主文字'],
  548. ['muted', '#5f7a6d', '次要文字'],
  549. ['border', '#d8f3e5', '边框'],
  550. ['accent', '#fbbf24', '辅助强调(大麦黄提亮)'],
  551. ['warning', '#d97706', '警告'],
  552. ['danger', '#ef4444', '危险'],
  553. ['success', '#10b981', '成功']
  554. ],
  555. css: {
  556. '--t-brand': '#22c55e',
  557. '--t-brand-dark': '#16a34a',
  558. '--t-brand-soft': '#ecfdf5',
  559. '--t-header-bg': 'linear-gradient(160deg, #f0fdf4 0%, #d1fae5 58%, #a7f3d0 100%)',
  560. '--t-header-fg': '#065f46',
  561. '--t-header-glow': 'rgba(255,255,255,.55)',
  562. '--t-bg': '#f7fffb',
  563. '--t-surface': '#ffffff',
  564. '--t-text': '#0f291e',
  565. '--t-muted': '#5f7a6d',
  566. '--t-border': '#d8f3e5',
  567. '--t-shadow': '0 8px 24px rgba(22, 163, 74, 0.07)',
  568. '--t-banner-a': '#bbf7d0',
  569. '--t-banner-b': '#86efac',
  570. '--t-banner-fg': '#14532d',
  571. '--t-todo-bg': 'linear-gradient(180deg, #f6fffa 0%, #ffffff 70%)',
  572. '--t-warning': '#d97706',
  573. '--t-success': '#059669'
  574. },
  575. menus: [
  576. ['审', '#ffe4e6', '#e11d48', '发起审批'],
  577. ['待', '#ecfdf5', '#16a34a', '我的待办'],
  578. ['协', '#e0f2fe', '#0284c7', '协议管理'],
  579. ['样', '#fef3c7', '#d97706', '样本查询'],
  580. ['质', '#ede9fe', '#7c3aed', '质检工单'],
  581. ['库', '#dcfce7', '#15803d', '入库登记'],
  582. ['报', '#f1f5f9', '#475569', '统计报表'],
  583. ['设', '#f8fafc', '#64748b', '个人设置']
  584. ]
  585. },
  586. sky: {
  587. id: 'sky',
  588. name: 'B · 晴空青',
  589. swatch: '#0ea5e9',
  590. desc: '顶栏用极浅天蓝,主操作偏青蓝,绿色作成功/进行态点缀。整体更「透气、白天感」。',
  591. tokens: [
  592. ['brand', '#0ea5e9', '主色 / 按钮'],
  593. ['brandDark', '#0284c7', '主色深'],
  594. ['brandSoft', '#e0f2fe', '主色浅底'],
  595. ['headerBg', 'linear-gradient(165deg, #f0f9ff 0%, #e0f2fe 55%, #bae6fd 100%)', '顶栏背景'],
  596. ['headerFg', '#0c4a6e', '顶栏文字'],
  597. ['bg', '#f8fbff', '页面背景'],
  598. ['surface', '#ffffff', '卡片表面'],
  599. ['text', '#0f172a', '主文字'],
  600. ['muted', '#64748b', '次要文字'],
  601. ['border', '#dbeafe', '边框'],
  602. ['accent', '#22c55e', '绿色点缀'],
  603. ['warning', '#d97706', '警告'],
  604. ['danger', '#ef4444', '危险'],
  605. ['success', '#22c55e', '成功']
  606. ],
  607. css: {
  608. '--t-brand': '#0ea5e9',
  609. '--t-brand-dark': '#0284c7',
  610. '--t-brand-soft': '#e0f2fe',
  611. '--t-header-bg': 'linear-gradient(165deg, #f0f9ff 0%, #e0f2fe 55%, #bae6fd 100%)',
  612. '--t-header-fg': '#0c4a6e',
  613. '--t-header-glow': 'rgba(255,255,255,.6)',
  614. '--t-bg': '#f8fbff',
  615. '--t-surface': '#ffffff',
  616. '--t-text': '#0f172a',
  617. '--t-muted': '#64748b',
  618. '--t-border': '#dbeafe',
  619. '--t-shadow': '0 8px 24px rgba(14, 165, 233, 0.08)',
  620. '--t-banner-a': '#bae6fd',
  621. '--t-banner-b': '#7dd3fc',
  622. '--t-banner-fg': '#0c4a6e',
  623. '--t-todo-bg': 'linear-gradient(180deg, #f0f9ff 0%, #ffffff 70%)',
  624. '--t-warning': '#d97706',
  625. '--t-success': '#16a34a'
  626. },
  627. menus: [
  628. ['审', '#ffe4e6', '#e11d48', '发起审批'],
  629. ['待', '#e0f2fe', '#0284c7', '我的待办'],
  630. ['协', '#ecfdf5', '#16a34a', '协议管理'],
  631. ['样', '#fef3c7', '#d97706', '样本查询'],
  632. ['质', '#ede9fe', '#7c3aed', '质检工单'],
  633. ['库', '#cffafe', '#0891b2', '入库登记'],
  634. ['报', '#f1f5f9', '#475569', '统计报表'],
  635. ['设', '#f8fafc', '#64748b', '个人设置']
  636. ]
  637. },
  638. teal: {
  639. id: 'teal',
  640. name: 'C · 青瓷医疗',
  641. swatch: '#14b8a6',
  642. desc: '偏医疗 / 实验室气质的青绿(teal),白瓷感背景,干净专业,不压抑。',
  643. tokens: [
  644. ['brand', '#14b8a6', '主色 / 按钮'],
  645. ['brandDark', '#0f766e', '主色深'],
  646. ['brandSoft', '#f0fdfa', '主色浅底'],
  647. ['headerBg', 'linear-gradient(160deg, #f0fdfa 0%, #ccfbf1 60%, #99f6e4 100%)', '顶栏背景'],
  648. ['headerFg', '#115e59', '顶栏文字'],
  649. ['bg', '#f7fffe', '页面背景'],
  650. ['surface', '#ffffff', '卡片表面'],
  651. ['text', '#134e4a', '主文字'],
  652. ['muted', '#5f7c78', '次要文字'],
  653. ['border', '#ccfbf1', '边框'],
  654. ['accent', '#f59e0b', '辅助强调'],
  655. ['warning', '#d97706', '警告'],
  656. ['danger', '#ef4444', '危险'],
  657. ['success', '#0d9488', '成功']
  658. ],
  659. css: {
  660. '--t-brand': '#14b8a6',
  661. '--t-brand-dark': '#0f766e',
  662. '--t-brand-soft': '#f0fdfa',
  663. '--t-header-bg': 'linear-gradient(160deg, #f0fdfa 0%, #ccfbf1 60%, #99f6e4 100%)',
  664. '--t-header-fg': '#115e59',
  665. '--t-header-glow': 'rgba(255,255,255,.55)',
  666. '--t-bg': '#f7fffe',
  667. '--t-surface': '#ffffff',
  668. '--t-text': '#134e4a',
  669. '--t-muted': '#5f7c78',
  670. '--t-border': '#ccfbf1',
  671. '--t-shadow': '0 8px 24px rgba(13, 148, 136, 0.08)',
  672. '--t-banner-a': '#99f6e4',
  673. '--t-banner-b': '#5eead4',
  674. '--t-banner-fg': '#115e59',
  675. '--t-todo-bg': 'linear-gradient(180deg, #f0fdfa 0%, #ffffff 70%)',
  676. '--t-warning': '#d97706',
  677. '--t-success': '#0d9488'
  678. },
  679. menus: [
  680. ['审', '#ffe4e6', '#e11d48', '发起审批'],
  681. ['待', '#f0fdfa', '#0f766e', '我的待办'],
  682. ['协', '#e0f2fe', '#0284c7', '协议管理'],
  683. ['样', '#fef3c7', '#d97706', '样本查询'],
  684. ['质', '#ede9fe', '#7c3aed', '质检工单'],
  685. ['库', '#ccfbf1', '#0f766e', '入库登记'],
  686. ['报', '#f1f5f9', '#475569', '统计报表'],
  687. ['设', '#f8fafc', '#64748b', '个人设置']
  688. ]
  689. },
  690. dawn: {
  691. id: 'dawn',
  692. name: 'D · 暖晨光',
  693. swatch: '#84cc16',
  694. desc: '浅暖米背景 + 柔和嫩绿顶栏,带一点大麦黄,像早晨阳光,亲和不沉重。',
  695. tokens: [
  696. ['brand', '#65a30d', '主色 / 按钮'],
  697. ['brandDark', '#4d7c0f', '主色深'],
  698. ['brandSoft', '#f7fee7', '主色浅底'],
  699. ['headerBg', 'linear-gradient(160deg, #fffbeb 0%, #fef9c3 45%, #d9f99d 100%)', '顶栏背景'],
  700. ['headerFg', '#3f6212', '顶栏文字'],
  701. ['bg', '#fffcf5', '页面背景'],
  702. ['surface', '#ffffff', '卡片表面'],
  703. ['text', '#1c1917', '主文字'],
  704. ['muted', '#78716c', '次要文字'],
  705. ['border', '#f5e6c8', '边框'],
  706. ['accent', '#eab308', '大麦黄'],
  707. ['warning', '#d97706', '警告'],
  708. ['danger', '#ef4444', '危险'],
  709. ['success', '#65a30d', '成功']
  710. ],
  711. css: {
  712. '--t-brand': '#65a30d',
  713. '--t-brand-dark': '#4d7c0f',
  714. '--t-brand-soft': '#f7fee7',
  715. '--t-header-bg': 'linear-gradient(160deg, #fffbeb 0%, #fef9c3 45%, #d9f99d 100%)',
  716. '--t-header-fg': '#3f6212',
  717. '--t-header-glow': 'rgba(255,255,255,.5)',
  718. '--t-bg': '#fffcf5',
  719. '--t-surface': '#ffffff',
  720. '--t-text': '#1c1917',
  721. '--t-muted': '#78716c',
  722. '--t-border': '#f5e6c8',
  723. '--t-shadow': '0 8px 24px rgba(101, 163, 13, 0.08)',
  724. '--t-banner-a': '#fde68a',
  725. '--t-banner-b': '#bef264',
  726. '--t-banner-fg': '#3f6212',
  727. '--t-todo-bg': 'linear-gradient(180deg, #fffbeb 0%, #ffffff 70%)',
  728. '--t-warning': '#d97706',
  729. '--t-success': '#65a30d'
  730. },
  731. menus: [
  732. ['审', '#ffe4e6', '#e11d48', '发起审批'],
  733. ['待', '#f7fee7', '#4d7c0f', '我的待办'],
  734. ['协', '#e0f2fe', '#0284c7', '协议管理'],
  735. ['样', '#fef3c7', '#d97706', '样本查询'],
  736. ['质', '#ede9fe', '#7c3aed', '质检工单'],
  737. ['库', '#ecfccb', '#4d7c0f', '入库登记'],
  738. ['报', '#f5f5f4', '#57534e', '统计报表'],
  739. ['设', '#fafaf9', '#78716c', '个人设置']
  740. ]
  741. }
  742. }
  743. const order = ['mint', 'sky', 'teal', 'dawn']
  744. let active = 'mint'
  745. const tabsEl = document.getElementById('tabs')
  746. const tokensEl = document.getElementById('tokens')
  747. const menusEl = document.getElementById('menus')
  748. const phoneEl = document.getElementById('phone')
  749. const root = document.documentElement
  750. function renderTabs() {
  751. tabsEl.innerHTML = order.map((id) => {
  752. const t = THEMES[id]
  753. const rec = id === 'mint' ? '<span class="badge">推荐</span>' : ''
  754. return `<button class="theme-tab ${id === active ? 'is-active' : ''}" data-id="${id}" style="--swatch:${t.swatch};--t-brand:${t.css['--t-brand']};--t-brand-dark:${t.css['--t-brand-dark']};--t-brand-soft:${t.css['--t-brand-soft']}">
  755. <span class="dot"></span>${t.name}${rec}
  756. </button>`
  757. }).join('')
  758. tabsEl.querySelectorAll('.theme-tab').forEach((btn) => {
  759. btn.addEventListener('click', () => {
  760. active = btn.dataset.id
  761. applyTheme()
  762. // for visual companion selection
  763. if (typeof toggleSelect === 'function') {
  764. const fake = { dataset: { choice: active }, classList: { add() {}, remove() {}, contains() { return false } } }
  765. }
  766. window.parent && window.parent.postMessage
  767. document.dispatchEvent(new CustomEvent('theme-selected', { detail: active }))
  768. try {
  769. const payload = { type: 'click', choice: active, text: THEMES[active].name, timestamp: Math.floor(Date.now() / 1000) }
  770. // companion helper may listen to option clicks; also expose for agent
  771. window.__selectedTheme = active
  772. } catch (e) {}
  773. })
  774. })
  775. }
  776. function applyTheme() {
  777. const t = THEMES[active]
  778. Object.entries(t.css).forEach(([k, v]) => phoneEl.style.setProperty(k, v))
  779. // also set on page for tab active colors
  780. Object.entries(t.css).forEach(([k, v]) => root.style.setProperty(k, v))
  781. document.getElementById('themeTitle').textContent = t.name
  782. document.getElementById('themeDesc').textContent = t.desc
  783. document.getElementById('previewName').textContent = t.name
  784. document.getElementById('targetHeader').style.background = t.css['--t-header-bg']
  785. tokensEl.innerHTML = t.tokens.map(([name, hex, desc]) => {
  786. const isGrad = String(hex).includes('gradient')
  787. const swatch = isGrad
  788. ? `<i style="background:${hex}"></i>`
  789. : `<i style="background:${hex}"></i>`
  790. return `<div class="token">${swatch}<div><div class="name">${name}</div><div class="desc">${desc}</div></div><code>${hex}</code></div>`
  791. }).join('')
  792. menusEl.innerHTML = t.menus.map(([ch, bg, fg, label]) =>
  793. `<div class="menu-item"><div class="menu-icon" style="background:${bg};color:${fg}">${ch}</div><span>${label}</span></div>`
  794. ).join('')
  795. renderTabs()
  796. }
  797. // companion-friendly selectable cards at bottom via data-choice hooks
  798. function injectCompanionHooks() {
  799. // Add invisible option markers for companion selection if wrapped
  800. order.forEach((id) => {
  801. const el = document.createElement('div')
  802. el.className = 'option'
  803. el.dataset.choice = id
  804. el.style.display = 'none'
  805. el.onclick = () => {}
  806. document.body.appendChild(el)
  807. })
  808. }
  809. applyTheme()
  810. injectCompanionHooks()
  811. </script>
  812. <!-- companion selectable options -->
  813. <div class="options" style="max-width:1180px;margin:0 auto;padding:0 18px 40px;display:grid;gap:10px">
  814. <p style="margin:0 0 4px;font-size:13px;color:#64748b">选择偏好方案(可点击下方卡片,也可在上方 Tab 预览):</p>
  815. <div class="option" data-choice="mint" onclick="toggleSelect && toggleSelect(this); document.querySelector('[data-id=mint]')?.click()" style="display:flex;gap:12px;align-items:center;padding:12px 14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer">
  816. <div class="letter" style="width:28px;height:28px;border-radius:8px;background:#ecfdf5;color:#065f46;display:grid;place-items:center;font-weight:700">A</div>
  817. <div class="content"><h3 style="margin:0;font-size:14px">薄荷微风(推荐)</h3><p style="margin:2px 0 0;font-size:12px;color:#64748b">浅绿顶栏 + 品牌绿,最稳妥</p></div>
  818. </div>
  819. <div class="option" data-choice="sky" onclick="toggleSelect && toggleSelect(this); document.querySelector('[data-id=sky]')?.click()" style="display:flex;gap:12px;align-items:center;padding:12px 14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer">
  820. <div class="letter" style="width:28px;height:28px;border-radius:8px;background:#e0f2fe;color:#0c4a6e;display:grid;place-items:center;font-weight:700">B</div>
  821. <div class="content"><h3 style="margin:0;font-size:14px">晴空青</h3><p style="margin:2px 0 0;font-size:12px;color:#64748b">天蓝顶栏,更透气</p></div>
  822. </div>
  823. <div class="option" data-choice="teal" onclick="toggleSelect && toggleSelect(this); document.querySelector('[data-id=teal]')?.click()" style="display:flex;gap:12px;align-items:center;padding:12px 14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer">
  824. <div class="letter" style="width:28px;height:28px;border-radius:8px;background:#f0fdfa;color:#115e59;display:grid;place-items:center;font-weight:700">C</div>
  825. <div class="content"><h3 style="margin:0;font-size:14px">青瓷医疗</h3><p style="margin:2px 0 0;font-size:12px;color:#64748b">teal 专业、干净</p></div>
  826. </div>
  827. <div class="option" data-choice="dawn" onclick="toggleSelect && toggleSelect(this); document.querySelector('[data-id=dawn]')?.click()" style="display:flex;gap:12px;align-items:center;padding:12px 14px;border:1px solid #e2e8f0;border-radius:14px;background:#fff;cursor:pointer">
  828. <div class="letter" style="width:28px;height:28px;border-radius:8px;background:#f7fee7;color:#3f6212;display:grid;place-items:center;font-weight:700">D</div>
  829. <div class="content"><h3 style="margin:0;font-size:14px">暖晨光</h3><p style="margin:2px 0 0;font-size:12px;color:#64748b">暖米 + 嫩绿,亲和</p></div>
  830. </div>
  831. </div>
  832. </body>
  833. </html>