zkxw-mobile-oa-manage-search-icon-demo.html 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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, maximum-scale=1" />
  6. <title>OA 列表 · 搜索后方管理 Icon 选型</title>
  7. <style>
  8. :root {
  9. --brand: #0a9f6d;
  10. --brand-dark: #087f57;
  11. --brand-soft: #e9f9f2;
  12. --nav-bg: #ecfdf5;
  13. --page-bg: #f5f8f7;
  14. --text: #1f2a26;
  15. --text-muted: #6b7b74;
  16. --border: #e8eaed;
  17. --capsule-w: 87px;
  18. --capsule-h: 32px;
  19. --capsule-right: 7px;
  20. }
  21. * { box-sizing: border-box; }
  22. body {
  23. margin: 0;
  24. font-family: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", -apple-system, system-ui, sans-serif;
  25. color: var(--text);
  26. background:
  27. radial-gradient(900px 420px at 8% -8%, rgba(10, 159, 109, 0.12), transparent 55%),
  28. linear-gradient(180deg, #f8fffc 0%, #f4f7fb 50%, #f7f8fa 100%);
  29. line-height: 1.45;
  30. }
  31. .stage { max-width: 1280px; margin: 0 auto; padding: 28px 16px 64px; }
  32. .hero h1 { margin: 0 0 8px; font-size: 22px; font-weight: 720; }
  33. .hero p { margin: 0; color: #64748b; font-size: 14px; max-width: 900px; }
  34. .rec {
  35. margin: 16px 0 0;
  36. padding: 14px 16px;
  37. border-radius: 14px;
  38. background: var(--brand-soft);
  39. border: 1px solid #b7ebd4;
  40. font-size: 13px;
  41. color: #166534;
  42. line-height: 1.55;
  43. }
  44. .rec b { color: var(--brand-dark); }
  45. .mode-tabs {
  46. display: flex; flex-wrap: wrap; gap: 10px;
  47. margin: 20px 0 8px;
  48. }
  49. .mode-tab {
  50. appearance: none; border: 1px solid #e2e8f0; background: #fff;
  51. border-radius: 999px; padding: 10px 16px; font-size: 13px;
  52. font-weight: 600; color: #475569; cursor: pointer;
  53. }
  54. .mode-tab.is-active {
  55. color: var(--brand-dark); border-color: var(--brand);
  56. background: var(--brand-soft);
  57. box-shadow: 0 0 0 3px rgba(10, 159, 109, 0.16);
  58. }
  59. .hint {
  60. margin: 0 0 16px;
  61. font-size: 13px;
  62. color: #64748b;
  63. }
  64. .gallery {
  65. display: grid;
  66. grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  67. gap: 18px;
  68. }
  69. .option {
  70. background: rgba(255,255,255,.94);
  71. border: 2px solid #e2e8f0;
  72. border-radius: 18px;
  73. padding: 12px;
  74. cursor: pointer;
  75. transition: border-color .15s, box-shadow .15s;
  76. }
  77. .option:hover { border-color: #a7f3d0; }
  78. .option.is-selected {
  79. border-color: var(--brand);
  80. box-shadow: 0 0 0 4px rgba(10, 159, 109, 0.18);
  81. background: #f0fdf7;
  82. }
  83. .option__head {
  84. display: flex; align-items: center; justify-content: space-between;
  85. gap: 8px; margin-bottom: 10px; padding: 0 4px;
  86. }
  87. .option__name { font-size: 14px; font-weight: 700; color: #0f291e; }
  88. .option__tag {
  89. font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  90. background: #f1f5f9; color: #64748b;
  91. }
  92. .option.is-selected .option__tag {
  93. background: #d1fae5; color: #047857;
  94. }
  95. .option__desc {
  96. margin: 0 0 10px; padding: 0 4px;
  97. font-size: 12px; color: #64748b;
  98. }
  99. .phone {
  100. width: 100%; max-width: 320px; margin: 0 auto;
  101. background: #fff; border-radius: 22px; overflow: hidden;
  102. box-shadow: 0 0 0 1px rgb(15 23 42 / 6%), 0 12px 28px rgb(15 23 42 / 10%);
  103. position: relative;
  104. pointer-events: none;
  105. }
  106. .sys-bar {
  107. height: 36px; background: var(--nav-bg);
  108. display: flex; align-items: flex-end; justify-content: space-between;
  109. padding: 0 14px 4px; font-size: 11px; font-weight: 650; color: #0f291e;
  110. }
  111. .nav-wrap {
  112. background: var(--nav-bg);
  113. border-bottom: 1px solid #d8f3e5;
  114. position: relative;
  115. }
  116. .nav {
  117. height: 40px; display: flex; align-items: center;
  118. padding: 0 8px 0 4px; position: relative;
  119. }
  120. .nav-back {
  121. width: 32px; height: 32px; display: flex; align-items: center; justify-content: center;
  122. }
  123. .nav-back::before {
  124. content: ""; width: 9px; height: 9px;
  125. border-left: 2px solid #0f291e; border-bottom: 2px solid #0f291e;
  126. transform: rotate(45deg); margin-left: 4px;
  127. }
  128. .nav-title {
  129. position: absolute; left: 50%; transform: translateX(-50%);
  130. font-size: 15px; font-weight: 650; color: #0f291e;
  131. }
  132. .wx-capsule {
  133. position: absolute; top: 4px; right: 6px;
  134. width: 74px; height: 28px;
  135. border-radius: 14px; background: rgba(255,255,255,.92);
  136. border: 1px solid rgba(0,0,0,.12);
  137. display: flex; align-items: center; z-index: 50;
  138. }
  139. .wx-capsule__dots, .wx-capsule__close {
  140. flex: 1; height: 100%; display: flex; align-items: center; justify-content: center;
  141. color: #111; font-size: 11px; font-weight: 700;
  142. }
  143. .wx-capsule__dots { gap: 2px; }
  144. .wx-capsule__dots span {
  145. width: 3px; height: 3px; border-radius: 50%; background: #111;
  146. }
  147. .wx-capsule__divider { width: 1px; height: 14px; background: rgba(0,0,0,.12); }
  148. .toolbar {
  149. background: #fff; padding: 8px 10px;
  150. border-bottom: 1px solid var(--border);
  151. }
  152. .toolbar-row { display: flex; align-items: center; gap: 8px; }
  153. .search {
  154. flex: 1; min-width: 0; height: 34px; border-radius: 9px;
  155. border: 1px solid #e8eaed; background: #fafafa;
  156. display: flex; align-items: center; padding: 0 10px; gap: 6px;
  157. color: #94a3b8; font-size: 12px;
  158. }
  159. .search::before {
  160. content: ""; width: 12px; height: 12px; flex-shrink: 0;
  161. border: 2px solid #94a3b8; border-radius: 50%; box-sizing: border-box;
  162. }
  163. .manage-ico-btn {
  164. flex-shrink: 0;
  165. width: 34px; height: 34px;
  166. border-radius: 9px;
  167. border: 1px solid #c6f0dc;
  168. background: #ecfdf5;
  169. color: #166534;
  170. display: inline-flex;
  171. align-items: center;
  172. justify-content: center;
  173. outline: 2px solid rgba(10, 159, 109, 0.45);
  174. outline-offset: 1px;
  175. }
  176. .manage-ico-btn.is-done {
  177. border-color: #e2e8f0;
  178. background: #f8fafc;
  179. color: #64748b;
  180. outline-color: rgba(100, 116, 139, 0.35);
  181. }
  182. .manage-ico-btn svg { width: 17px; height: 17px; display: block; }
  183. .pair {
  184. display: grid;
  185. grid-template-columns: 1fr 1fr;
  186. gap: 8px;
  187. margin-top: 8px;
  188. }
  189. .pair__label {
  190. text-align: center;
  191. font-size: 11px;
  192. font-weight: 650;
  193. color: #64748b;
  194. margin-bottom: 4px;
  195. }
  196. .mini-phone {
  197. background: #fff;
  198. border: 1px solid #e8eeeb;
  199. border-radius: 12px;
  200. overflow: hidden;
  201. }
  202. .mini-bar {
  203. background: var(--nav-bg);
  204. height: 18px;
  205. border-bottom: 1px solid #d8f3e5;
  206. }
  207. .mini-tool {
  208. display: flex; align-items: center; gap: 6px;
  209. padding: 6px;
  210. background: #fff;
  211. }
  212. .mini-search {
  213. flex: 1; height: 26px; border-radius: 7px;
  214. border: 1px solid #e8eaed; background: #fafafa;
  215. }
  216. .mini-ico {
  217. width: 26px; height: 26px; border-radius: 7px;
  218. border: 1px solid #c6f0dc; background: #ecfdf5; color: #166534;
  219. display: inline-flex; align-items: center; justify-content: center;
  220. }
  221. .mini-ico.is-done {
  222. border-color: #e2e8f0; background: #f8fafc; color: #64748b;
  223. }
  224. .mini-ico svg { width: 14px; height: 14px; }
  225. .mini-list { background: var(--page-bg); padding: 6px; min-height: 52px; }
  226. .mini-card {
  227. height: 18px; border-radius: 6px; background: #fff;
  228. border: 1px solid #eef2f0; margin-bottom: 4px;
  229. }
  230. .footer-pick {
  231. position: sticky;
  232. bottom: 12px;
  233. margin-top: 20px;
  234. padding: 12px 14px;
  235. border-radius: 14px;
  236. background: rgba(15, 41, 30, 0.92);
  237. color: #ecfdf5;
  238. font-size: 13px;
  239. display: flex;
  240. align-items: center;
  241. justify-content: space-between;
  242. gap: 12px;
  243. box-shadow: 0 10px 28px rgba(15,23,42,.18);
  244. }
  245. .footer-pick strong { color: #6ee7b7; }
  246. .footer-pick .muted { color: #94a3b8; font-size: 12px; }
  247. </style>
  248. </head>
  249. <body>
  250. <div class="stage">
  251. <div class="hero">
  252. <h1>搜索框后方 · 管理 Icon 选型</h1>
  253. <p>
  254. 布局已定:顶栏不放「管理」;搜索框右侧放 36×36 icon。
  255. 下面每种 icon 都画出<strong>普通态 / 管理态(完成)</strong>对照,点选卡片即可选定。
  256. </p>
  257. <div class="rec">
  258. <b>已选定:</b>搜索行 <code>[搜索框] [三点菜单 icon]</code>;
  259. 普通态 = 三点;管理态 = 勾选。已落地到草稿箱 / 待办 / 抄送三页。
  260. </div>
  261. </div>
  262. <div class="mode-tabs">
  263. <button type="button" class="mode-tab is-active" disabled>每种方案均含:普通态 + 管理态</button>
  264. </div>
  265. <p class="hint">绿框为当前可点区域示意;右上角仍保留微信胶囊,确认不会挡到 icon。</p>
  266. <div class="gallery" id="gallery"></div>
  267. <div class="footer-pick" id="footerPick">
  268. <div>
  269. 当前选中:<strong id="pickedName">—</strong>
  270. <div class="muted" id="pickedDesc">点击上方卡片选择 icon</div>
  271. </div>
  272. <div class="muted">点选后回复方案名即可落地</div>
  273. </div>
  274. </div>
  275. <script>
  276. var CHECK =
  277. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">' +
  278. '<path d="M5 12.5l4.2 4.2L19 7"/></svg>'
  279. var OPTIONS = [
  280. {
  281. id: "more",
  282. name: "三点菜单",
  283. tag: "已落地",
  284. desc: "入口克制;真机用三个圆点,兼容性好。完成态换勾。",
  285. normal:
  286. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">' +
  287. '<circle cx="6" cy="12" r="1.4" fill="currentColor" stroke="none"/>' +
  288. '<circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"/>' +
  289. '<circle cx="18" cy="12" r="1.4" fill="currentColor" stroke="none"/>' +
  290. '</svg>'
  291. },
  292. {
  293. id: "gear",
  294. name: "齿轮设置",
  295. tag: "备选",
  296. desc: "真机 CSS 齿轮不稳定,已弃用。",
  297. normal:
  298. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  299. '<circle cx="12" cy="12" r="3"/>' +
  300. '<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"/>' +
  301. '</svg>'
  302. },
  303. {
  304. id: "sliders",
  305. name: "调参条",
  306. tag: "偏整理",
  307. desc: "「整理/批量操作」感;完成态换勾。",
  308. normal:
  309. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  310. '<path d="M4 7h10M16 7h4M4 17h4M10 17h10M14 4v6M8 14v6"/>' +
  311. '</svg>'
  312. },
  313. {
  314. id: "layers",
  315. name: "多层卡片",
  316. tag: "偏批量",
  317. desc: "暗示对多条记录操作;完成态换勾。",
  318. normal:
  319. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  320. '<path d="M12 2l9 4.5-9 4.5L3 6.5 12 2z"/>' +
  321. '<path d="M3 12.5l9 4.5 9-4.5"/>' +
  322. '<path d="M3 17.5l9 4.5 9-4.5"/>' +
  323. '</svg>'
  324. },
  325. {
  326. id: "checklist",
  327. name: "清单勾选",
  328. tag: "偏多选",
  329. desc: "直接表达「进入多选管理」;完成态换勾。",
  330. normal:
  331. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  332. '<path d="M9 6h11M9 12h11M9 18h11"/>' +
  333. '<path d="M4.5 6.5l1.2 1.2L7.8 5.5M4.5 12.5l1.2 1.2L7.8 11.5M4.5 18.5l1.2 1.2L7.8 17.5"/>' +
  334. '</svg>'
  335. },
  336. {
  337. id: "edit",
  338. name: "铅笔编辑",
  339. tag: "偏编辑",
  340. desc: "草稿箱场景很贴切;待办/抄送也说得通。完成态换勾。",
  341. normal:
  342. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  343. '<path d="M12 20h9"/>' +
  344. '<path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"/>' +
  345. '</svg>'
  346. },
  347. {
  348. id: "square-check",
  349. name: "方框勾选",
  350. tag: "偏选择",
  351. desc: "一眼是「可勾选」;管理态用实心勾强调完成。",
  352. normal:
  353. '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
  354. '<rect x="4" y="4" width="16" height="16" rx="3"/>' +
  355. '<path d="M8 12l2.8 2.8L16.5 9"/>' +
  356. '</svg>'
  357. }
  358. ]
  359. var selected = "more"
  360. function miniPair(opt) {
  361. return (
  362. '<div class="pair">' +
  363. '<div>' +
  364. '<div class="pair__label">普通态 · 管理</div>' +
  365. '<div class="mini-phone">' +
  366. '<div class="mini-bar"></div>' +
  367. '<div class="mini-tool">' +
  368. '<div class="mini-search"></div>' +
  369. '<div class="mini-ico">' + opt.normal + '</div>' +
  370. '</div>' +
  371. '<div class="mini-list"><div class="mini-card"></div><div class="mini-card"></div></div>' +
  372. '</div>' +
  373. '</div>' +
  374. '<div>' +
  375. '<div class="pair__label">管理态 · 完成</div>' +
  376. '<div class="mini-phone">' +
  377. '<div class="mini-bar"></div>' +
  378. '<div class="mini-tool">' +
  379. '<div class="mini-search"></div>' +
  380. '<div class="mini-ico is-done">' + CHECK + '</div>' +
  381. '</div>' +
  382. '<div class="mini-list"><div class="mini-card"></div><div class="mini-card"></div></div>' +
  383. '</div>' +
  384. '</div>' +
  385. '</div>'
  386. )
  387. }
  388. function fullPhone(opt, manage) {
  389. var svg = manage ? CHECK : opt.normal
  390. var cls = "manage-ico-btn" + (manage ? " is-done" : "")
  391. return (
  392. '<div class="phone">' +
  393. '<div class="sys-bar"><span>9:41</span><span>▮▮</span></div>' +
  394. '<div class="nav-wrap">' +
  395. '<div class="nav"><div class="nav-back"></div><div class="nav-title">待办中心</div></div>' +
  396. '<div class="wx-capsule" aria-hidden="true">' +
  397. '<div class="wx-capsule__dots"><span></span><span></span><span></span></div>' +
  398. '<div class="wx-capsule__divider"></div>' +
  399. '<div class="wx-capsule__close">✕</div>' +
  400. '</div>' +
  401. '</div>' +
  402. '<div class="toolbar"><div class="toolbar-row">' +
  403. '<div class="search">搜索流程名称、申请人</div>' +
  404. '<div class="' + cls + '">' + svg + '</div>' +
  405. '</div></div>' +
  406. '</div>'
  407. )
  408. }
  409. function render() {
  410. var root = document.getElementById("gallery")
  411. root.innerHTML = OPTIONS.map(function (opt) {
  412. var on = opt.id === selected ? " is-selected" : ""
  413. var tag = opt.id === selected ? "已选" : opt.tag
  414. return (
  415. '<div class="option' + on + '" data-id="' + opt.id + '">' +
  416. '<div class="option__head">' +
  417. '<div class="option__name">' + opt.name + '</div>' +
  418. '<div class="option__tag">' + tag + '</div>' +
  419. '</div>' +
  420. '<p class="option__desc">' + opt.desc + '</p>' +
  421. fullPhone(opt, false) +
  422. miniPair(opt) +
  423. '</div>'
  424. )
  425. }).join("")
  426. var cur = OPTIONS.find(function (o) { return o.id === selected })
  427. document.getElementById("pickedName").textContent = cur ? cur.name : "—"
  428. document.getElementById("pickedDesc").textContent = cur ? cur.desc : ""
  429. }
  430. document.getElementById("gallery").addEventListener("click", function (e) {
  431. var card = e.target.closest(".option")
  432. if (!card) return
  433. selected = card.getAttribute("data-id")
  434. render()
  435. })
  436. render()
  437. </script>
  438. </body>
  439. </html>