zkxw-mobile-oa-protocol-form-beautify-demo.html 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  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>协议单 · 新增/编辑表单美化 Demo(销售专员 / 地区经理)</title>
  7. <style>
  8. :root {
  9. --brand: #0a9f6d;
  10. --brand-dark: #087f57;
  11. --brand-soft: #e9f9f2;
  12. --brand-mid: #b8ebd4;
  13. --barley: #d6a343;
  14. --barley-soft: #fff7e8;
  15. --text: #1f2a26;
  16. --text-muted: #6b7b74;
  17. --border: #dcebe4;
  18. --page-bg: #f5f8f7;
  19. --surface: #ffffff;
  20. --danger: #d14343;
  21. --warn: #cf8a19;
  22. --shadow: 0 8px 28px rgba(15, 42, 34, 0.06);
  23. --radius-card: 16px;
  24. --radius-ctl: 12px;
  25. }
  26. * { box-sizing: border-box; }
  27. body {
  28. margin: 0;
  29. min-height: 100vh;
  30. font-family: "PingFang SC", "Hiragino Sans GB", "Noto Sans SC", -apple-system, system-ui, sans-serif;
  31. color: var(--text);
  32. background:
  33. radial-gradient(900px 420px at 8% -8%, rgba(10, 159, 109, 0.14), transparent 55%),
  34. radial-gradient(700px 380px at 92% 0%, rgba(214, 163, 67, 0.1), transparent 50%),
  35. linear-gradient(180deg, #f8fffc 0%, #f4f7fb 45%, #f7f8fa 100%);
  36. line-height: 1.45;
  37. }
  38. .stage { max-width: 1280px; margin: 0 auto; padding: 28px 16px 72px; }
  39. .hero h1 { margin: 0 0 8px; font-size: 24px; font-weight: 720; letter-spacing: -0.02em; }
  40. .hero p { margin: 0; max-width: 860px; color: #64748b; font-size: 14px; }
  41. .hero .meta {
  42. margin-top: 12px; display: flex; flex-wrap: wrap; gap: 8px;
  43. }
  44. .hero .chip {
  45. display: inline-flex; align-items: center; gap: 6px;
  46. padding: 6px 12px; border-radius: 999px; font-size: 12px; font-weight: 600;
  47. background: #fff; border: 1px solid #e2e8f0; color: #475569;
  48. }
  49. .hero .chip strong { color: var(--brand-dark); }
  50. .pain {
  51. margin: 18px 0 0;
  52. display: grid;
  53. grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  54. gap: 10px;
  55. }
  56. .pain-item {
  57. background: #fff;
  58. border: 1px solid #fecaca;
  59. border-radius: 12px;
  60. padding: 10px 12px;
  61. font-size: 12px;
  62. color: #7f1d1d;
  63. }
  64. .pain-item b { color: #b91c1c; }
  65. .tabs {
  66. display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 18px;
  67. }
  68. .tab {
  69. appearance: none; border: 1px solid #e2e8f0; background: #fff;
  70. border-radius: 999px; padding: 10px 16px; font-size: 13px;
  71. font-weight: 600; color: #475569; cursor: pointer;
  72. transition: .15s border-color, .15s box-shadow, .15s color, .15s background;
  73. }
  74. .tab:hover { border-color: #94a3b8; }
  75. .tab.is-active {
  76. color: var(--brand-dark); border-color: var(--brand);
  77. background: var(--brand-soft);
  78. box-shadow: 0 0 0 3px rgba(10, 159, 109, 0.18);
  79. }
  80. .layout {
  81. display: grid;
  82. grid-template-columns: minmax(280px, 360px) 1fr;
  83. gap: 22px;
  84. align-items: start;
  85. }
  86. @media (max-width: 960px) {
  87. .layout { grid-template-columns: 1fr; }
  88. }
  89. .panel {
  90. background: rgba(255,255,255,.92);
  91. border: 1px solid #e2e8f0;
  92. border-radius: 18px;
  93. padding: 18px;
  94. box-shadow: 0 10px 30px rgba(15, 23, 42, 0.05);
  95. position: sticky;
  96. top: 16px;
  97. }
  98. .panel h2 { margin: 0 0 4px; font-size: 16px; }
  99. .panel .sub { margin: 0 0 14px; font-size: 12px; color: #64748b; }
  100. .panel ol { margin: 0; padding-left: 18px; font-size: 13px; color: #475569; }
  101. .panel li { margin: 0 0 8px; }
  102. .panel li strong { color: var(--brand-dark); }
  103. .legend {
  104. margin-top: 16px; padding-top: 14px; border-top: 1px dashed #e2e8f0;
  105. display: grid; gap: 8px; font-size: 12px; color: #64748b;
  106. }
  107. .legend span {
  108. display: flex; align-items: center; gap: 8px;
  109. }
  110. .swatch {
  111. width: 14px; height: 14px; border-radius: 4px; flex: none;
  112. }
  113. .phones {
  114. display: grid;
  115. grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  116. gap: 20px;
  117. }
  118. .phone-wrap { display: flex; flex-direction: column; gap: 10px; }
  119. .phone-label {
  120. display: flex; align-items: center; justify-content: space-between;
  121. padding: 0 4px;
  122. }
  123. .phone-label h3 { margin: 0; font-size: 15px; font-weight: 700; }
  124. .phone-label .tag {
  125. font-size: 11px; font-weight: 700; padding: 4px 8px; border-radius: 999px;
  126. }
  127. .tag-old { background: #f1f5f9; color: #64748b; }
  128. .tag-new { background: var(--brand-soft); color: var(--brand-dark); }
  129. .phone {
  130. width: 100%;
  131. max-width: 390px;
  132. margin: 0 auto;
  133. height: 780px;
  134. border-radius: 36px;
  135. border: 10px solid #0f172a;
  136. background: var(--page-bg);
  137. box-shadow: 0 24px 60px rgba(15, 23, 42, 0.18);
  138. overflow: hidden;
  139. position: relative;
  140. display: flex;
  141. flex-direction: column;
  142. }
  143. .phone::before {
  144. content: "";
  145. position: absolute;
  146. top: 8px; left: 50%; transform: translateX(-50%);
  147. width: 108px; height: 22px; border-radius: 12px;
  148. background: #0f172a; z-index: 5;
  149. }
  150. /* ========== 当前样式(对照) ========== */
  151. .old-page {
  152. flex: 1; overflow: auto; padding: 44px 12px 88px;
  153. background: #f5f8f7;
  154. }
  155. .old-nav {
  156. position: sticky; top: 0; z-index: 2;
  157. margin: -44px -12px 12px; padding: 40px 14px 10px;
  158. background: #fff; border-bottom: 1px solid var(--border);
  159. text-align: center; font-size: 16px; font-weight: 650;
  160. }
  161. .old-section {
  162. margin-bottom: 12px; padding: 16px;
  163. border: 1px solid var(--border); border-radius: 16px; background: #fff;
  164. }
  165. .old-section h4 {
  166. margin: 0 0 14px; padding-left: 10px;
  167. border-left: 3px solid var(--brand); font-size: 15px; font-weight: 650;
  168. }
  169. .old-field { display: grid; gap: 7px; margin-bottom: 14px; color: var(--text-muted); font-size: 13px; }
  170. .old-field .ctl {
  171. min-height: 44px; border: 1px solid var(--border); border-radius: 10px;
  172. background: #fff; padding: 0 12px; display: flex; align-items: center;
  173. color: #94a3b8; font-size: 14px;
  174. }
  175. .old-field .ctl.has-val { color: var(--text); }
  176. .old-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  177. .old-tabs button {
  178. min-height: 44px; border: 1px solid var(--border); border-radius: 10px;
  179. background: #fff; color: var(--text); font-size: 14px;
  180. }
  181. .old-tabs button.on {
  182. border-color: var(--brand); background: var(--brand-soft);
  183. color: var(--brand-dark); font-weight: 600;
  184. }
  185. .old-bottom {
  186. position: absolute; left: 0; right: 0; bottom: 0;
  187. display: flex; gap: 10px; justify-content: center;
  188. padding: 10px 14px 18px;
  189. border-top: 1px solid var(--border); background: rgb(255 255 255 / 96%);
  190. }
  191. .old-bottom .btn {
  192. min-height: 44px; min-width: 120px; max-width: 168px; flex: 0 1 168px;
  193. border-radius: 999px; font-size: 15px; font-weight: 600; border: 1px solid var(--border);
  194. background: #fff; color: var(--text);
  195. }
  196. .old-bottom .btn.primary {
  197. border-color: var(--brand); background: var(--brand); color: #fff;
  198. }
  199. /* ========== 美化方案 ========== */
  200. .new-page {
  201. flex: 1; overflow: auto;
  202. padding: 0 0 96px;
  203. background:
  204. linear-gradient(180deg, #e9f9f2 0%, #f5f8f7 120px, #f5f8f7 100%);
  205. }
  206. .new-nav {
  207. position: sticky; top: 0; z-index: 3;
  208. padding: 36px 14px 0;
  209. background: linear-gradient(180deg, #d8f5e8 0%, #e9f9f2 70%, rgba(233,249,242,0.92) 100%);
  210. backdrop-filter: blur(8px);
  211. }
  212. .new-nav__bar {
  213. display: grid; grid-template-columns: 40px 1fr 40px;
  214. align-items: center; margin-bottom: 10px;
  215. }
  216. .new-nav__back {
  217. width: 36px; height: 36px; border-radius: 12px;
  218. display: grid; place-items: center;
  219. background: rgba(255,255,255,.72); border: 1px solid rgba(10,159,109,.18);
  220. color: var(--brand-dark); font-size: 22px; line-height: 1;
  221. }
  222. .new-nav__title { text-align: center; font-size: 17px; font-weight: 720; color: var(--text); }
  223. .new-nav__mode {
  224. justify-self: end;
  225. font-size: 11px; font-weight: 700; padding: 4px 8px; border-radius: 999px;
  226. background: #fff; color: var(--brand-dark); border: 1px solid var(--brand-mid);
  227. }
  228. .new-steps {
  229. display: flex; gap: 6px; overflow-x: auto; padding: 0 0 12px;
  230. scrollbar-width: none;
  231. }
  232. .new-steps::-webkit-scrollbar { display: none; }
  233. .step-chip {
  234. flex: none; display: inline-flex; align-items: center; gap: 6px;
  235. padding: 7px 12px; border-radius: 999px;
  236. font-size: 12px; font-weight: 650; white-space: nowrap;
  237. background: rgba(255,255,255,.65); color: var(--text-muted);
  238. border: 1px solid transparent;
  239. }
  240. .step-chip .n {
  241. width: 18px; height: 18px; border-radius: 50%;
  242. display: grid; place-items: center; font-size: 10px; font-weight: 800;
  243. background: #e2e8f0; color: #64748b;
  244. }
  245. .step-chip.is-active {
  246. background: #fff; color: var(--brand-dark);
  247. border-color: var(--brand-mid);
  248. box-shadow: 0 2px 8px rgba(10,159,109,.12);
  249. }
  250. .step-chip.is-active .n {
  251. background: var(--brand); color: #fff;
  252. }
  253. .step-chip.is-done .n {
  254. background: var(--brand-mid); color: var(--brand-dark);
  255. }
  256. .new-body { padding: 4px 12px 12px; display: grid; gap: 12px; }
  257. .card {
  258. background: var(--surface);
  259. border-radius: var(--radius-card);
  260. box-shadow: var(--shadow);
  261. border: 1px solid rgba(220, 235, 228, 0.85);
  262. overflow: hidden;
  263. }
  264. .card__head {
  265. display: flex; align-items: center; gap: 10px;
  266. padding: 14px 14px 0;
  267. }
  268. .card__badge {
  269. width: 28px; height: 28px; border-radius: 10px;
  270. display: grid; place-items: center;
  271. font-size: 12px; font-weight: 800; color: #fff;
  272. background: linear-gradient(145deg, #12b981, #087f57);
  273. box-shadow: 0 4px 10px rgba(10,159,109,.28);
  274. }
  275. .card__title {
  276. flex: 1; margin: 0; font-size: 15px; font-weight: 720;
  277. }
  278. .card__hint {
  279. margin: 4px 14px 0; font-size: 11px; color: var(--text-muted);
  280. }
  281. .card__body { padding: 12px 14px 14px; display: grid; gap: 12px; }
  282. .field { display: grid; gap: 6px; }
  283. .field.is-span2 { grid-column: 1 / -1; }
  284. .field__label {
  285. display: flex; align-items: center; gap: 4px;
  286. font-size: 12px; font-weight: 650; color: #3d524a;
  287. }
  288. .field__label .req { color: var(--danger); font-weight: 800; }
  289. .field__label .tip {
  290. margin-left: 4px; font-size: 11px; font-weight: 500; color: var(--text-muted);
  291. }
  292. .field__ctl {
  293. min-height: 46px;
  294. border-radius: var(--radius-ctl);
  295. border: 1px solid transparent;
  296. background: #f4faf7;
  297. padding: 0 14px;
  298. display: flex; align-items: center; justify-content: space-between;
  299. gap: 8px;
  300. font-size: 14px; color: #94a3b8;
  301. transition: border-color .15s, background .15s, box-shadow .15s;
  302. }
  303. .field__ctl.has-val { color: var(--text); background: #f7fbf9; border-color: #e3f0ea; }
  304. .field__ctl:focus-within,
  305. .field__ctl.is-focus {
  306. background: #fff;
  307. border-color: var(--brand);
  308. box-shadow: 0 0 0 3px rgba(10, 159, 109, 0.15);
  309. color: var(--text);
  310. }
  311. .field__ctl .chev { color: #9cb0a7; font-size: 16px; }
  312. .field__ctl.textarea {
  313. min-height: 84px; align-items: flex-start; padding: 12px 14px;
  314. color: var(--text);
  315. }
  316. .field-grid {
  317. display: grid;
  318. grid-template-columns: 1fr 1fr;
  319. gap: 12px;
  320. }
  321. .seg {
  322. display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  323. padding: 4px; border-radius: 14px; background: #eef6f2;
  324. }
  325. .seg button {
  326. min-height: 40px; border: 0; border-radius: 11px;
  327. background: transparent; color: var(--text-muted);
  328. font-size: 13px; font-weight: 650; cursor: pointer;
  329. }
  330. .seg button.on {
  331. background: #fff; color: var(--brand-dark);
  332. box-shadow: 0 2px 8px rgba(15, 42, 34, 0.08);
  333. }
  334. .subgroup {
  335. margin-top: 2px;
  336. padding: 12px;
  337. border-radius: 14px;
  338. background: linear-gradient(180deg, #f8fffc 0%, #f4faf7 100%);
  339. border: 1px solid #e3f0ea;
  340. display: grid; gap: 12px;
  341. }
  342. .subgroup__title {
  343. display: flex; align-items: center; gap: 8px;
  344. font-size: 12px; font-weight: 750; color: var(--brand-dark);
  345. }
  346. .subgroup__title::before {
  347. content: "";
  348. width: 6px; height: 6px; border-radius: 50%;
  349. background: var(--brand);
  350. box-shadow: 0 0 0 3px var(--brand-soft);
  351. }
  352. .money-sync {
  353. display: flex; align-items: center; justify-content: space-between;
  354. gap: 10px; padding: 10px 12px; border-radius: 12px;
  355. background: var(--barley-soft); border: 1px solid #f0e0bc;
  356. font-size: 12px; color: #8a6419;
  357. }
  358. .money-sync strong { color: #92400e; font-size: 14px; }
  359. .sample-card {
  360. padding: 12px; border-radius: 14px;
  361. border: 1px solid #e3f0ea; background: #fff;
  362. display: grid; gap: 8px;
  363. }
  364. .sample-card__head {
  365. display: flex; align-items: center; justify-content: space-between; gap: 8px;
  366. }
  367. .sample-card__head strong { font-size: 14px; }
  368. .tag-status {
  369. font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  370. background: var(--brand-soft); color: var(--brand-dark);
  371. }
  372. .sample-card__meta {
  373. display: flex; flex-wrap: wrap; gap: 6px 10px;
  374. font-size: 12px; color: var(--text-muted);
  375. }
  376. .sample-card__actions { display: flex; gap: 8px; }
  377. .mini-btn {
  378. min-height: 26px; padding: 0 10px; border-radius: 999px;
  379. border: 0; background: #5f8f7d;
  380. font-size: 11px; font-weight: 700; color: #fff;
  381. box-shadow: 0 2px 5px rgba(15,42,34,.12);
  382. }
  383. .mini-btn.danger {
  384. background: linear-gradient(135deg, #e35d5d, #d14343);
  385. box-shadow: 0 2px 5px rgba(209,67,67,.2);
  386. }
  387. .mini-btn.primary {
  388. background: linear-gradient(135deg, #12b981, #087f57);
  389. box-shadow: 0 2px 6px rgba(10,159,109,.28);
  390. }
  391. .mini-btn.warn {
  392. background: linear-gradient(135deg, #e5a63a, #cf8a19);
  393. box-shadow: 0 2px 5px rgba(207,138,25,.22);
  394. }
  395. .toolbar-row {
  396. display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px;
  397. }
  398. .upload-row {
  399. display: flex; flex-wrap: wrap; gap: 10px;
  400. }
  401. .upload-card {
  402. width: 96px; height: 72px; border-radius: 12px;
  403. border: 1.5px dashed #a7f3d0;
  404. background: #f7fffb;
  405. display: grid; place-items: center; text-align: center;
  406. font-size: 11px; color: var(--brand-dark); font-weight: 650;
  407. gap: 2px;
  408. }
  409. .upload-card .plus { font-size: 20px; line-height: 1; color: var(--brand); }
  410. .upload-file {
  411. width: 96px; height: 72px; border-radius: 12px;
  412. border: 1px solid var(--border); background: #fff;
  413. padding: 8px; display: grid; align-content: space-between;
  414. font-size: 11px; color: var(--text);
  415. }
  416. .upload-file .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  417. .upload-file .rm { color: var(--danger); font-weight: 650; }
  418. .confirm-row {
  419. display: flex; align-items: flex-start; gap: 10px;
  420. padding: 12px; border-radius: 14px;
  421. background: var(--brand-soft); border: 1px solid var(--brand-mid);
  422. font-size: 13px; color: var(--text); font-weight: 600;
  423. }
  424. .confirm-row .box {
  425. width: 20px; height: 20px; border-radius: 6px; flex: none; margin-top: 1px;
  426. border: 2px solid var(--brand); background: var(--brand);
  427. color: #fff; display: grid; place-items: center; font-size: 12px;
  428. }
  429. .new-bottom {
  430. position: absolute; left: 0; right: 0; bottom: 0; z-index: 4;
  431. display: flex; gap: 10px;
  432. padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 8px));
  433. background: linear-gradient(180deg, rgba(245,248,247,0), #fff 28%);
  434. }
  435. .new-bottom::before {
  436. content: "";
  437. position: absolute; inset: 0 0 auto 0; height: 1px;
  438. background: linear-gradient(90deg, transparent, rgba(10,159,109,.18), transparent);
  439. }
  440. .new-bottom .btn {
  441. position: relative;
  442. min-height: 40px; flex: 1; border-radius: 12px;
  443. font-size: 14px; font-weight: 700; border: 0; cursor: pointer;
  444. color: #fff;
  445. }
  446. .new-bottom .btn.ghost {
  447. background: #5f8f7d;
  448. box-shadow: 0 3px 8px rgba(15, 42, 34, 0.14);
  449. }
  450. .new-bottom .btn.primary {
  451. background: linear-gradient(135deg, #12b981 0%, #087f57 100%);
  452. box-shadow: 0 6px 16px rgba(10, 159, 109, 0.3);
  453. }
  454. .variant-b .card__head {
  455. padding: 12px 14px;
  456. background: linear-gradient(90deg, #ecfdf5, #fff 60%);
  457. border-bottom: 1px solid #eef6f2;
  458. }
  459. .variant-b .card__body { padding-top: 14px; }
  460. .variant-b .field__ctl {
  461. background: #fff;
  462. border: 1px solid #e3f0ea;
  463. }
  464. .variant-b .field__ctl.has-val { background: #fff; }
  465. .variant-b .seg { background: #f0f7f4; }
  466. .note-bar {
  467. margin-top: 18px;
  468. padding: 14px 16px;
  469. border-radius: 14px;
  470. background: #fff;
  471. border: 1px solid #e2e8f0;
  472. font-size: 13px;
  473. color: #475569;
  474. }
  475. .note-bar code {
  476. font-size: 12px; padding: 2px 6px; border-radius: 6px;
  477. background: #f1f5f9; color: #0f766e;
  478. }
  479. </style>
  480. </head>
  481. <body>
  482. <div class="stage">
  483. <header class="hero">
  484. <h1>协议单 · 新增 / 编辑表单美化</h1>
  485. <p>
  486. 面向 <strong>销售专员 / 地区经理</strong>(mobile-oa-h5 市场模块)。
  487. 字段与分区顺序:协议信息 → 采集信息 → 客户信息 → 样本及运输 → 缴费 → 附件 → <strong>提交确认(最后)</strong>。
  488. Token 使用三墙绿 <code style="font-size:12px;background:#e9f9f2;padding:2px 6px;border-radius:6px;">#0a9f6d</code>,不混用管理端薄荷主色。
  489. </p>
  490. <div class="meta">
  491. <span class="chip"><strong>工程</strong> mobile-oa-h5</span>
  492. <span class="chip"><strong>入口</strong> 市场 · 协议单</span>
  493. <span class="chip"><strong>模式</strong> 新增 / 编辑</span>
  494. </div>
  495. <div class="pain">
  496. <div class="pain-item"><b>现状问题</b>:白卡片 + 细描边扁平,长表单缺乏节奏</div>
  497. <div class="pain-item"><b>现状问题</b>:label 灰色过淡,字段堆叠一列,滚动过长</div>
  498. <div class="pain-item"><b>现状问题</b>:客户区母亲/父亲/新生儿无分组,扫读成本高</div>
  499. <div class="pain-item"><b>现状问题</b>:底栏与内容粘连感弱,主按钮不够醒目</div>
  500. </div>
  501. </header>
  502. <div class="tabs" role="tablist">
  503. <button type="button" class="tab is-active" data-tab="compare">对照:现状 vs 方案 A</button>
  504. <button type="button" class="tab" data-tab="a">方案 A · 软填充(推荐)</button>
  505. <button type="button" class="tab" data-tab="b">方案 B · 白底描边</button>
  506. </div>
  507. <div class="layout">
  508. <aside class="panel" id="side-panel">
  509. <h2>方案 A · 设计要点</h2>
  510. <p class="sub">推荐落地;与现有 Vant 组件可渐进替换样式</p>
  511. <ol>
  512. <li><strong>顶区进度芯片</strong>:长表单可横向跳读分区</li>
  513. <li><strong>编号卡片头</strong>:分区层级一眼可辨</li>
  514. <li><strong>软填充控件</strong>:#f4faf7 底 + 聚焦描边,减少「框框墙」</li>
  515. <li><strong>客户三分组</strong>:母亲 / 父亲 / 新生儿独立浅底块</li>
  516. <li><strong>短字段双列</strong>:金额、性别、胎次、评分等降滚动</li>
  517. <li><strong>实心小按钮</strong>:表单内操作统一实心,尺寸偏小;底栏取消/保存亦为实心</li>
  518. </ol>
  519. <div class="legend">
  520. <span><i class="swatch" style="background:#0a9f6d"></i> 主色 / 进度 / 主按钮</span>
  521. <span><i class="swatch" style="background:#e9f9f2"></i> 软底 / 选中态</span>
  522. <span><i class="swatch" style="background:#fff7e8"></i> 金额同步提示</span>
  523. <span><i class="swatch" style="background:#f4faf7;border:1px solid #dcebe4"></i> 输入控件默认底</span>
  524. </div>
  525. </aside>
  526. <div class="phones" id="phone-stage">
  527. <!-- 对照:现状 -->
  528. <div class="phone-wrap" data-view="compare">
  529. <div class="phone-label">
  530. <h3>当前样式</h3>
  531. <span class="tag tag-old">AS-IS</span>
  532. </div>
  533. <div class="phone">
  534. <div class="old-page">
  535. <div class="old-nav">新增协议单</div>
  536. <section class="old-section">
  537. <h4>协议信息</h4>
  538. <div class="old-field">
  539. <span>业务来源*</span>
  540. <div class="old-tabs">
  541. <button type="button" class="on">细胞存储</button>
  542. <button type="button">科研捐赠</button>
  543. </div>
  544. </div>
  545. <div class="old-field"><span>协议编号</span><div class="ctl">请输入</div></div>
  546. <div class="old-field"><span>登记日期</span><div class="ctl">请选择</div></div>
  547. <div class="old-field"><span>采集专员</span><div class="ctl">请选择</div></div>
  548. <div class="old-field"><span>协议总金额</span><div class="ctl">请输入</div></div>
  549. <div class="old-field"><span>备注</span><div class="ctl">请输入</div></div>
  550. </section>
  551. <section class="old-section">
  552. <h4>采集信息</h4>
  553. <div class="old-field"><span>市场专员</span><div class="ctl has-val">张专员</div></div>
  554. <div class="old-field"><span>采集地区</span><div class="ctl">请选择</div></div>
  555. <div class="old-field"><span>采集医院</span><div class="ctl">请选择</div></div>
  556. </section>
  557. <section class="old-section">
  558. <h4>客户信息</h4>
  559. <div class="old-field"><span>母亲姓名*</span><div class="ctl has-val">王女士</div></div>
  560. <div class="old-field"><span>联系电话</span><div class="ctl">请输入</div></div>
  561. <div class="old-field"><span>父亲姓名</span><div class="ctl">请输入</div></div>
  562. <div class="old-field"><span>新生儿姓名</span><div class="ctl">请输入</div></div>
  563. </section>
  564. </div>
  565. <div class="old-bottom">
  566. <button type="button" class="btn">取消</button>
  567. <button type="button" class="btn primary">保存</button>
  568. </div>
  569. </div>
  570. </div>
  571. <!-- 方案 A -->
  572. <div class="phone-wrap" data-view="compare a">
  573. <div class="phone-label">
  574. <h3>方案 A · 软填充</h3>
  575. <span class="tag tag-new">推荐</span>
  576. </div>
  577. <div class="phone" id="phone-a">
  578. <div class="new-page">
  579. <header class="new-nav">
  580. <div class="new-nav__bar">
  581. <div class="new-nav__back">‹</div>
  582. <div class="new-nav__title">新增协议单</div>
  583. <span class="new-nav__mode">专员</span>
  584. </div>
  585. <div class="new-steps">
  586. <span class="step-chip is-active"><span class="n">1</span>协议</span>
  587. <span class="step-chip"><span class="n">2</span>采集</span>
  588. <span class="step-chip"><span class="n">3</span>客户</span>
  589. <span class="step-chip"><span class="n">4</span>样本</span>
  590. <span class="step-chip"><span class="n">5</span>缴费</span>
  591. <span class="step-chip"><span class="n">6</span>附件</span>
  592. <span class="step-chip"><span class="n">7</span>确认</span>
  593. </div>
  594. </header>
  595. <div class="new-body">
  596. <!-- 1 协议 -->
  597. <section class="card" id="sec-protocol">
  598. <div class="card__head">
  599. <span class="card__badge">1</span>
  600. <h4 class="card__title">协议信息</h4>
  601. </div>
  602. <div class="card__body">
  603. <div class="field">
  604. <div class="field__label">业务来源<span class="req">*</span></div>
  605. <div class="seg">
  606. <button type="button" class="on">细胞存储</button>
  607. <button type="button">科研捐赠</button>
  608. </div>
  609. </div>
  610. <div class="field-grid">
  611. <div class="field">
  612. <div class="field__label">协议编号</div>
  613. <div class="field__ctl">选填 / 可自动</div>
  614. </div>
  615. <div class="field">
  616. <div class="field__label">登记日期</div>
  617. <div class="field__ctl has-val">2026-10-15 <span class="chev">›</span></div>
  618. </div>
  619. </div>
  620. <div class="field">
  621. <div class="field__label">采集专员</div>
  622. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  623. </div>
  624. <div class="field">
  625. <div class="field__label">协议总金额<span class="tip">元</span></div>
  626. <div class="field__ctl has-val is-focus">128000.00</div>
  627. </div>
  628. <div class="field">
  629. <div class="field__label">备注</div>
  630. <div class="field__ctl textarea">客户要求加急入库说明…</div>
  631. </div>
  632. </div>
  633. </section>
  634. <!-- 2 采集 -->
  635. <section class="card">
  636. <div class="card__head">
  637. <span class="card__badge">2</span>
  638. <h4 class="card__title">采集信息</h4>
  639. </div>
  640. <div class="card__body">
  641. <div class="field">
  642. <div class="field__label">市场专员</div>
  643. <div class="field__ctl has-val">张专员 <span class="chev">›</span></div>
  644. </div>
  645. <div class="field-grid">
  646. <div class="field">
  647. <div class="field__label">采集地区</div>
  648. <div class="field__ctl has-val">合肥 <span class="chev">›</span></div>
  649. </div>
  650. <div class="field">
  651. <div class="field__label">采集医院</div>
  652. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  653. </div>
  654. </div>
  655. <div class="field">
  656. <div class="field__label">地区经理</div>
  657. <div class="field__ctl has-val">李经理 <span class="chev">›</span></div>
  658. </div>
  659. <div class="field-grid">
  660. <div class="field">
  661. <div class="field__label">样本采集时间</div>
  662. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  663. </div>
  664. <div class="field">
  665. <div class="field__label">母血采集时间</div>
  666. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  667. </div>
  668. </div>
  669. </div>
  670. </section>
  671. <!-- 3 客户 -->
  672. <section class="card">
  673. <div class="card__head">
  674. <span class="card__badge">3</span>
  675. <h4 class="card__title">客户信息</h4>
  676. </div>
  677. <p class="card__hint">可搜索客户档案回填;身份证可自动推算出生年月</p>
  678. <div class="card__body">
  679. <div class="subgroup">
  680. <div class="subgroup__title">母亲</div>
  681. <div class="field">
  682. <div class="field__label">母亲姓名<span class="req">*</span></div>
  683. <div class="field__ctl has-val">王女士 🔍</div>
  684. </div>
  685. <div class="field-grid">
  686. <div class="field">
  687. <div class="field__label">联系电话</div>
  688. <div class="field__ctl has-val">138****8899</div>
  689. </div>
  690. <div class="field">
  691. <div class="field__label">出生年月</div>
  692. <div class="field__ctl has-val">1992-06</div>
  693. </div>
  694. </div>
  695. <div class="field">
  696. <div class="field__label">母亲身份证号</div>
  697. <div class="field__ctl has-val">3401**********1234</div>
  698. </div>
  699. <div class="field">
  700. <div class="field__label">家庭住址</div>
  701. <div class="field__ctl textarea" style="min-height:64px">合肥市蜀山区××路××号</div>
  702. </div>
  703. </div>
  704. <div class="subgroup">
  705. <div class="subgroup__title">父亲</div>
  706. <div class="field-grid">
  707. <div class="field">
  708. <div class="field__label">父亲姓名</div>
  709. <div class="field__ctl">搜索档案 🔍</div>
  710. </div>
  711. <div class="field">
  712. <div class="field__label">父亲电话</div>
  713. <div class="field__ctl">请输入</div>
  714. </div>
  715. </div>
  716. </div>
  717. <div class="subgroup">
  718. <div class="subgroup__title">新生儿</div>
  719. <div class="field-grid">
  720. <div class="field">
  721. <div class="field__label">新生儿姓名</div>
  722. <div class="field__ctl">请输入</div>
  723. </div>
  724. <div class="field">
  725. <div class="field__label">性别</div>
  726. <div class="seg">
  727. <button type="button" class="on">男</button>
  728. <button type="button">女</button>
  729. </div>
  730. </div>
  731. </div>
  732. <div class="field-grid">
  733. <div class="field">
  734. <div class="field__label">预产期</div>
  735. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  736. </div>
  737. <div class="field">
  738. <div class="field__label">分娩方式</div>
  739. <div class="field__ctl">请选择 <span class="chev">›</span></div>
  740. </div>
  741. </div>
  742. <div class="field-grid">
  743. <div class="field">
  744. <div class="field__label">胎次</div>
  745. <div class="field__ctl">请输入</div>
  746. </div>
  747. <div class="field">
  748. <div class="field__label">体重(克)</div>
  749. <div class="field__ctl">请输入</div>
  750. </div>
  751. </div>
  752. <div class="field-grid">
  753. <div class="field">
  754. <div class="field__label">评分 1分钟</div>
  755. <div class="field__ctl">请输入</div>
  756. </div>
  757. <div class="field">
  758. <div class="field__label">评分 5分钟</div>
  759. <div class="field__ctl">请输入</div>
  760. </div>
  761. </div>
  762. </div>
  763. </div>
  764. </section>
  765. <!-- 4 样本 -->
  766. <section class="card">
  767. <div class="card__head">
  768. <span class="card__badge">4</span>
  769. <h4 class="card__title">样本及运输</h4>
  770. </div>
  771. <p class="card__hint">规则与管理端一致</p>
  772. <div class="card__body">
  773. <div class="toolbar-row">
  774. <button type="button" class="mini-btn primary">+ 添加样本</button>
  775. <button type="button" class="mini-btn">配置运费</button>
  776. <button type="button" class="mini-btn warn">取消运费</button>
  777. </div>
  778. <article class="sample-card">
  779. <div class="sample-card__head">
  780. <strong>☐ YB20261015001</strong>
  781. <span class="tag-status">已采集</span>
  782. </div>
  783. <div class="sample-card__meta">
  784. <span>脐带血</span>
  785. <span>优惠价 ¥68,000</span>
  786. <span>顺丰 · ¥120</span>
  787. <span>ETA 10-18</span>
  788. </div>
  789. <div class="sample-card__actions">
  790. <button type="button" class="mini-btn">编辑</button>
  791. <button type="button" class="mini-btn danger">删除</button>
  792. </div>
  793. </article>
  794. </div>
  795. </section>
  796. <!-- 5 缴费 -->
  797. <section class="card">
  798. <div class="card__head">
  799. <span class="card__badge">5</span>
  800. <h4 class="card__title">缴费信息</h4>
  801. </div>
  802. <div class="card__body">
  803. <div class="money-sync">
  804. <span>样本合同合计</span>
  805. <strong>¥68,000.00</strong>
  806. </div>
  807. <article class="sample-card">
  808. <div class="sample-card__head">
  809. <strong>YB20261015001 · 脐带血</strong>
  810. <span class="tag-status">分期</span>
  811. </div>
  812. <div class="field">
  813. <div class="field__label">样本合同金额</div>
  814. <div class="field__ctl has-val">68000</div>
  815. </div>
  816. <div class="field-grid">
  817. <div class="field">
  818. <div class="field__label">期数</div>
  819. <div class="field__ctl has-val">3</div>
  820. </div>
  821. <div class="field">
  822. <div class="field__label">间隔(月)</div>
  823. <div class="field__ctl has-val">3</div>
  824. </div>
  825. </div>
  826. </article>
  827. </div>
  828. </section>
  829. <!-- 6 附件 -->
  830. <section class="card">
  831. <div class="card__head">
  832. <span class="card__badge">6</span>
  833. <h4 class="card__title">附件</h4>
  834. </div>
  835. <div class="card__body">
  836. <div class="field">
  837. <div class="field__label">协议附件</div>
  838. <div class="upload-row">
  839. <div class="upload-card"><span class="plus">+</span>上传</div>
  840. <div class="upload-file">
  841. <span class="name">协议扫描.pdf</span>
  842. <span class="rm">删除</span>
  843. </div>
  844. </div>
  845. </div>
  846. <div class="field">
  847. <div class="field__label">知情同意书</div>
  848. <div class="upload-row">
  849. <div class="upload-card"><span class="plus">+</span>上传</div>
  850. </div>
  851. </div>
  852. <div class="field">
  853. <div class="field__label">健康调查表</div>
  854. <div class="upload-row">
  855. <div class="upload-card"><span class="plus">+</span>上传</div>
  856. </div>
  857. </div>
  858. </div>
  859. </section>
  860. <!-- 7 提交确认(始终最后) -->
  861. <section class="card">
  862. <div class="card__head">
  863. <span class="card__badge">7</span>
  864. <h4 class="card__title">提交确认</h4>
  865. </div>
  866. <p class="card__hint">请核对协议、样本、缴费与附件后再勾选</p>
  867. <div class="card__body">
  868. <div class="confirm-row">
  869. <span class="box">✓</span>
  870. <span>我已核对以上信息,确认无误后保存</span>
  871. </div>
  872. </div>
  873. </section>
  874. </div>
  875. </div>
  876. <div class="new-bottom">
  877. <button type="button" class="btn ghost">取消</button>
  878. <button type="button" class="btn primary">保存协议单</button>
  879. </div>
  880. </div>
  881. </div>
  882. <!-- 方案 B(单独 tab 时显示) -->
  883. <div class="phone-wrap" data-view="b" hidden>
  884. <div class="phone-label">
  885. <h3>方案 B · 白底描边</h3>
  886. <span class="tag tag-new">备选</span>
  887. </div>
  888. <div class="phone variant-b">
  889. <div class="new-page">
  890. <header class="new-nav">
  891. <div class="new-nav__bar">
  892. <div class="new-nav__back">‹</div>
  893. <div class="new-nav__title">编辑协议单</div>
  894. <span class="new-nav__mode">经理</span>
  895. </div>
  896. <div class="new-steps">
  897. <span class="step-chip is-done"><span class="n">✓</span>协议</span>
  898. <span class="step-chip is-active"><span class="n">2</span>采集</span>
  899. <span class="step-chip"><span class="n">3</span>客户</span>
  900. <span class="step-chip"><span class="n">4</span>样本</span>
  901. </div>
  902. </header>
  903. <div class="new-body">
  904. <section class="card">
  905. <div class="card__head">
  906. <span class="card__badge">2</span>
  907. <h4 class="card__title">采集信息</h4>
  908. </div>
  909. <div class="card__body">
  910. <div class="field">
  911. <div class="field__label">市场专员</div>
  912. <div class="field__ctl has-val">张专员 <span class="chev">›</span></div>
  913. </div>
  914. <div class="field-grid">
  915. <div class="field">
  916. <div class="field__label">采集地区</div>
  917. <div class="field__ctl has-val">合肥 <span class="chev">›</span></div>
  918. </div>
  919. <div class="field">
  920. <div class="field__label">采集医院</div>
  921. <div class="field__ctl has-val">安徽省立医院 <span class="chev">›</span></div>
  922. </div>
  923. </div>
  924. <div class="field">
  925. <div class="field__label">地区经理</div>
  926. <div class="field__ctl has-val">李经理 <span class="chev">›</span></div>
  927. </div>
  928. <div class="seg">
  929. <button type="button" class="on">细胞存储</button>
  930. <button type="button">科研捐赠</button>
  931. </div>
  932. </div>
  933. </section>
  934. <section class="card">
  935. <div class="card__head">
  936. <span class="card__badge">3</span>
  937. <h4 class="card__title">客户信息 · 母亲</h4>
  938. </div>
  939. <div class="card__body">
  940. <div class="field">
  941. <div class="field__label">母亲姓名<span class="req">*</span></div>
  942. <div class="field__ctl has-val">王女士</div>
  943. </div>
  944. <div class="field-grid">
  945. <div class="field">
  946. <div class="field__label">联系电话</div>
  947. <div class="field__ctl has-val">138****8899</div>
  948. </div>
  949. <div class="field">
  950. <div class="field__label">民族</div>
  951. <div class="field__ctl has-val">汉族 <span class="chev">›</span></div>
  952. </div>
  953. </div>
  954. </div>
  955. </section>
  956. </div>
  957. </div>
  958. <div class="new-bottom">
  959. <button type="button" class="btn ghost">取消</button>
  960. <button type="button" class="btn primary">保存修改</button>
  961. </div>
  962. </div>
  963. </div>
  964. </div>
  965. </div>
  966. <div class="note-bar">
  967. 文件路径:<code>mobile-ui/zkxw-mobile-oa-protocol-form-beautify-demo.html</code>
  968. · 浏览器直接打开即可预览。确认方案后,可再落到
  969. <code>mobile-oa-h5/src/styles/market.css</code> 与协议相关 Panel 组件。
  970. 业务字段不改,仅样式与信息层级。
  971. <br />样本运输 / 缴费明细专项深化:
  972. <code>mobile-ui/zkxw-mobile-oa-protocol-sample-pay-beautify-demo.html</code>
  973. </div>
  974. </div>
  975. <script>
  976. const tabs = document.querySelectorAll('.tab')
  977. const wraps = document.querySelectorAll('.phone-wrap')
  978. const panel = document.getElementById('side-panel')
  979. const copy = {
  980. compare: {
  981. title: '对照说明',
  982. sub: '左侧现状、右侧方案 A;结构字段不变,只改视觉层级',
  983. html: `<ol>
  984. <li><strong>左侧</strong>:当前 market-form-section 扁平卡片</li>
  985. <li><strong>右侧</strong>:推荐软填充 + 进度芯片 + 客户分组</li>
  986. <li><strong>不改</strong>:校验规则、接口字段、专员/经理权限</li>
  987. <li><strong>可改</strong>:CSS Token、卡片头、双列栅格、底栏</li>
  988. </ol>`
  989. },
  990. a: {
  991. title: '方案 A · 软填充(推荐)',
  992. sub: '与现有 Vant 组件可渐进替换样式',
  993. html: `<ol>
  994. <li><strong>顶区进度芯片</strong>:长表单可横向跳读分区</li>
  995. <li><strong>编号卡片头</strong>:分区层级一眼可辨</li>
  996. <li><strong>软填充控件</strong>:#f4faf7 底 + 聚焦描边</li>
  997. <li><strong>客户三分组</strong>:母亲 / 父亲 / 新生儿</li>
  998. <li><strong>短字段双列</strong>:降滚动长度</li>
  999. <li><strong>实心小按钮</strong>:表单内操作统一实心偏小</li>
  1000. </ol>`
  1001. },
  1002. b: {
  1003. title: '方案 B · 白底描边',
  1004. sub: '卡片头浅绿条 + 白底输入,更接近「表单纸」质感',
  1005. html: `<ol>
  1006. <li><strong>白底描边控件</strong>:更传统、对比更强</li>
  1007. <li><strong>卡片头色带</strong>:分区识别靠顶条而非填充输入</li>
  1008. <li><strong>适合</strong>:更偏好「清晰边框」的团队</li>
  1009. <li><strong>相对 A</strong>:长列表时框线略密,建议少用双线叠加</li>
  1010. </ol>`
  1011. }
  1012. }
  1013. function show(tab) {
  1014. tabs.forEach((t) => t.classList.toggle('is-active', t.dataset.tab === tab))
  1015. wraps.forEach((w) => {
  1016. const views = (w.dataset.view || '').split(/\s+/)
  1017. w.hidden = !views.includes(tab)
  1018. })
  1019. const c = copy[tab] || copy.a
  1020. panel.querySelector('h2').textContent = c.title
  1021. panel.querySelector('.sub').textContent = c.sub
  1022. const ol = panel.querySelector('ol')
  1023. ol.outerHTML = c.html
  1024. }
  1025. tabs.forEach((t) => t.addEventListener('click', () => show(t.dataset.tab)))
  1026. </script>
  1027. </body>
  1028. </html>