parking.html 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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, maximum-scale=1.0, user-scalable=no">
  6. <title>停车减免查询 - YesWash</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=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
  10. <style>
  11. :root {
  12. --color-primary: #9B0415;
  13. --color-primary-light: #c0051a;
  14. --color-primary-lighter: #fef0f0;
  15. --color-primary-bg: #fff5f5;
  16. --color-success: #67C23A;
  17. --color-success-bg: #f0f9eb;
  18. --color-warning: #E6A23C;
  19. --color-warning-bg: #fdf6ec;
  20. --color-danger: #F56C6C;
  21. --color-danger-bg: #fef0f0;
  22. --color-info: #909399;
  23. --color-info-bg: #f4f4f5;
  24. --bg-color: #f8f8f8;
  25. --bg-white: #ffffff;
  26. --text-primary: #303133;
  27. --text-regular: #606266;
  28. --text-secondary: #909399;
  29. --text-placeholder: #c0c4cc;
  30. --border-color: #dcdfe6;
  31. --border-color-light: #e4e7ed;
  32. --border-color-lighter: #ebeef5;
  33. --border-radius: 4px;
  34. --border-radius-lg: 8px;
  35. --border-radius-round: 20px;
  36. --shadow-card: 0 1px 4px rgba(0, 0, 0, 0.04);
  37. --shadow-card-hover: 0 2px 12px rgba(0, 0, 0, 0.08);
  38. --font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "SimSun", sans-serif;
  39. --font-brand: "Nunito", "PingFang SC", "Helvetica Neue", sans-serif;
  40. --transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  41. }
  42. * {
  43. margin: 0;
  44. padding: 0;
  45. box-sizing: border-box;
  46. }
  47. body {
  48. font-family: var(--font-family);
  49. font-size: 14px;
  50. color: var(--text-primary);
  51. background-color: var(--bg-color);
  52. min-height: 100vh;
  53. display: flex;
  54. flex-direction: column;
  55. align-items: center;
  56. -webkit-font-smoothing: antialiased;
  57. -moz-osx-font-smoothing: grayscale;
  58. }
  59. /* Header */
  60. .brand-header {
  61. width: 100%;
  62. background: #9B0415;
  63. padding: 32px 20px 40px;
  64. text-align: center;
  65. color: #fff;
  66. position: relative;
  67. overflow: hidden;
  68. }
  69. .brand-header::before {
  70. content: '';
  71. position: absolute;
  72. top: -50%;
  73. left: -50%;
  74. width: 200%;
  75. height: 200%;
  76. background: radial-gradient(ellipse at 30% 50%, rgba(255,255,255,0.08) 0%, transparent 60%);
  77. pointer-events: none;
  78. }
  79. .brand-logo {
  80. font-family: var(--font-brand);
  81. font-size: 16px;
  82. font-weight: 700;
  83. letter-spacing: 3px;
  84. opacity: 0.85;
  85. margin-bottom: 8px;
  86. position: relative;
  87. }
  88. .brand-title {
  89. font-size: 28px;
  90. font-weight: 600;
  91. letter-spacing: 1px;
  92. margin-bottom: 6px;
  93. position: relative;
  94. }
  95. .brand-subtitle {
  96. font-size: 14px;
  97. opacity: 0.75;
  98. font-weight: 300;
  99. position: relative;
  100. }
  101. /* Main Content */
  102. .page-wrapper {
  103. width: 100%;
  104. max-width: 420px;
  105. padding: 0 16px;
  106. margin-top: -16px;
  107. position: relative;
  108. z-index: 1;
  109. }
  110. .main-card {
  111. background: var(--bg-white);
  112. border-radius: var(--border-radius-lg);
  113. box-shadow: var(--shadow-card);
  114. padding: 28px 24px;
  115. margin-bottom: 20px;
  116. }
  117. /* Form */
  118. .form-group {
  119. margin-bottom: 0;
  120. }
  121. .field-label {
  122. display: block;
  123. font-size: 13px;
  124. font-weight: 500;
  125. color: var(--text-regular);
  126. margin-bottom: 8px;
  127. }
  128. .input-wrapper {
  129. position: relative;
  130. display: flex;
  131. align-items: center;
  132. }
  133. .input-prefix {
  134. position: absolute;
  135. left: 14px;
  136. z-index: 1;
  137. display: flex;
  138. align-items: center;
  139. }
  140. .input-prefix svg {
  141. width: 18px;
  142. height: 18px;
  143. color: var(--text-secondary);
  144. }
  145. .phone-input {
  146. width: 100%;
  147. height: 44px;
  148. padding: 0 14px 0 42px;
  149. border: 1px solid var(--border-color);
  150. border-radius: var(--border-radius);
  151. font-size: 15px;
  152. font-family: var(--font-family);
  153. color: var(--text-primary);
  154. background: var(--bg-white);
  155. transition: border-color var(--transition), box-shadow var(--transition);
  156. outline: none;
  157. -webkit-appearance: none;
  158. }
  159. .phone-input::placeholder {
  160. color: var(--text-placeholder);
  161. }
  162. .phone-input:focus {
  163. border-color: var(--color-primary);
  164. box-shadow: 0 0 0 2px rgba(155, 4, 21, 0.12);
  165. }
  166. .phone-input.error {
  167. border-color: var(--color-danger);
  168. }
  169. .field-error {
  170. color: var(--color-danger);
  171. font-size: 12px;
  172. margin-top: 6px;
  173. display: none;
  174. align-items: center;
  175. gap: 4px;
  176. }
  177. .field-error.show {
  178. display: flex;
  179. }
  180. /* Buttons */
  181. .btn {
  182. display: inline-flex;
  183. align-items: center;
  184. justify-content: center;
  185. width: 100%;
  186. height: 44px;
  187. padding: 0 20px;
  188. font-size: 15px;
  189. font-weight: 500;
  190. font-family: var(--font-family);
  191. border: none;
  192. border-radius: var(--border-radius-round);
  193. cursor: pointer;
  194. transition: all var(--transition);
  195. outline: none;
  196. letter-spacing: 1px;
  197. margin-top: 20px;
  198. }
  199. .btn-primary {
  200. background: var(--color-primary);
  201. color: #fff;
  202. }
  203. .btn-primary:hover:not(:disabled) {
  204. background: var(--color-primary-light);
  205. box-shadow: 0 2px 8px rgba(155, 4, 21, 0.25);
  206. transform: translateY(-1px);
  207. }
  208. .btn-primary:active:not(:disabled) {
  209. transform: translateY(0);
  210. box-shadow: none;
  211. }
  212. .btn-primary:disabled {
  213. opacity: 0.55;
  214. cursor: not-allowed;
  215. }
  216. .btn-claim {
  217. background: var(--color-primary);
  218. color: #fff;
  219. margin-top: 16px;
  220. animation: fadeInUp 0.4s ease;
  221. }
  222. .btn-claim:hover:not(:disabled) {
  223. background: var(--color-primary-light);
  224. box-shadow: 0 2px 8px rgba(155, 4, 21, 0.25);
  225. }
  226. /* Loading */
  227. .loading-area {
  228. display: none;
  229. text-align: center;
  230. padding: 32px 20px;
  231. }
  232. .loading-area.active {
  233. display: block;
  234. animation: fadeIn 0.25s ease;
  235. }
  236. .spinner {
  237. display: inline-block;
  238. width: 32px;
  239. height: 32px;
  240. border: 3px solid var(--border-color-lighter);
  241. border-top-color: var(--color-primary);
  242. border-radius: 50%;
  243. animation: spin 0.8s linear infinite;
  244. }
  245. .loading-text {
  246. margin-top: 14px;
  247. font-size: 13px;
  248. color: var(--text-secondary);
  249. }
  250. /* Result Card */
  251. .result-card {
  252. display: none;
  253. padding: 20px;
  254. border-radius: var(--border-radius);
  255. margin-top: 20px;
  256. animation: fadeInUp 0.35s ease;
  257. }
  258. .result-card.show {
  259. display: block;
  260. }
  261. .result-card.success {
  262. background: var(--color-success-bg);
  263. border-left: 3px solid var(--color-success);
  264. }
  265. .result-card.warning {
  266. background: var(--color-warning-bg);
  267. border-left: 3px solid var(--color-warning);
  268. }
  269. .result-card.error {
  270. background: var(--color-danger-bg);
  271. border-left: 3px solid var(--color-danger);
  272. }
  273. .result-icon {
  274. width: 40px;
  275. height: 40px;
  276. border-radius: 50%;
  277. display: flex;
  278. align-items: center;
  279. justify-content: center;
  280. margin-bottom: 12px;
  281. }
  282. .result-icon.success {
  283. background: var(--color-success);
  284. color: #fff;
  285. }
  286. .result-icon.warning {
  287. background: var(--color-warning);
  288. color: #fff;
  289. }
  290. .result-icon.error {
  291. background: var(--color-danger);
  292. color: #fff;
  293. }
  294. .result-icon svg {
  295. width: 20px;
  296. height: 20px;
  297. }
  298. .result-title {
  299. font-size: 16px;
  300. font-weight: 600;
  301. margin-bottom: 6px;
  302. color: var(--text-primary);
  303. }
  304. .result-desc {
  305. font-size: 13px;
  306. color: var(--text-regular);
  307. line-height: 1.6;
  308. }
  309. /* Hint */
  310. .hint-text {
  311. display: flex;
  312. align-items: center;
  313. justify-content: center;
  314. gap: 6px;
  315. margin-top: 18px;
  316. font-size: 12px;
  317. color: var(--text-placeholder);
  318. }
  319. .hint-text svg {
  320. width: 14px;
  321. height: 14px;
  322. flex-shrink: 0;
  323. }
  324. /* Footer */
  325. .page-footer {
  326. text-align: center;
  327. padding: 16px 20px 28px;
  328. font-size: 12px;
  329. font-family: var(--font-brand);
  330. font-weight: 600;
  331. color: var(--text-secondary);
  332. letter-spacing: 1px;
  333. }
  334. /* Keyframes */
  335. @keyframes spin {
  336. from { transform: rotate(0deg); }
  337. to { transform: rotate(360deg); }
  338. }
  339. @keyframes fadeIn {
  340. from { opacity: 0; }
  341. to { opacity: 1; }
  342. }
  343. @keyframes fadeInUp {
  344. from { opacity: 0; transform: translateY(10px); }
  345. to { opacity: 1; transform: translateY(0); }
  346. }
  347. /* Mobile tweaks */
  348. @media (max-width: 440px) {
  349. .brand-header {
  350. padding: 24px 16px 32px;
  351. }
  352. .brand-title {
  353. font-size: 24px;
  354. }
  355. .page-wrapper {
  356. padding: 0 10px;
  357. margin-top: -12px;
  358. }
  359. .main-card {
  360. padding: 22px 18px;
  361. }
  362. }
  363. </style>
  364. </head>
  365. <body>
  366. <header class="brand-header">
  367. <div class="brand-logo">YESWASH</div>
  368. <h1 class="brand-title">停车减免查询</h1>
  369. <p class="brand-subtitle">查询是否符合停车费用减免条件</p>
  370. </header>
  371. <div class="page-wrapper">
  372. <div class="main-card">
  373. <form id="queryForm" novalidate>
  374. <div class="form-group">
  375. <label class="field-label" for="phoneNumber">手机号码</label>
  376. <div class="input-wrapper">
  377. <span class="input-prefix">
  378. <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  379. <rect x="5" y="2" width="14" height="20" rx="2" ry="2"/>
  380. <line x1="12" y1="18" x2="12.01" y2="18"/>
  381. </svg>
  382. </span>
  383. <input
  384. type="tel"
  385. id="phoneNumber"
  386. class="phone-input"
  387. placeholder="请输入注册时使用的手机号"
  388. maxlength="11"
  389. autocomplete="tel"
  390. inputmode="numeric"
  391. >
  392. </div>
  393. <div id="fieldError" class="field-error">
  394. <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  395. <circle cx="12" cy="12" r="10"/>
  396. <line x1="15" y1="9" x2="9" y2="15"/>
  397. <line x1="9" y1="9" x2="15" y2="15"/>
  398. </svg>
  399. <span></span>
  400. </div>
  401. </div>
  402. <button type="submit" class="btn btn-primary" id="submitBtn">查 询</button>
  403. </form>
  404. <div class="hint-text">
  405. <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  406. <circle cx="12" cy="12" r="10"/>
  407. <line x1="12" y1="16" x2="12" y2="12"/>
  408. <line x1="12" y1="8" x2="12.01" y2="8"/>
  409. </svg>
  410. <span>领取后请尽快出场,避免产生二次费用</span>
  411. </div>
  412. </div>
  413. <div class="loading-area" id="loadingArea">
  414. <div class="spinner"></div>
  415. <p class="loading-text">查询中,请稍候...</p>
  416. </div>
  417. <div id="resultCard" class="result-card">
  418. <div id="resultIcon" class="result-icon"></div>
  419. <h2 id="resultTitle" class="result-title"></h2>
  420. <p id="resultDesc" class="result-desc"></p>
  421. <button id="collectBtn" class="btn btn-claim" style="display:none;">领取停车券</button>
  422. </div>
  423. </div>
  424. <footer class="page-footer">
  425. YesWash 超级进化车生活
  426. </footer>
  427. <script>
  428. (function() {
  429. var phoneInput = document.getElementById('phoneNumber');
  430. var submitBtn = document.getElementById('submitBtn');
  431. var fieldError = document.getElementById('fieldError');
  432. var loadingArea = document.getElementById('loadingArea');
  433. var resultCard = document.getElementById('resultCard');
  434. var resultIcon = document.getElementById('resultIcon');
  435. var resultTitle = document.getElementById('resultTitle');
  436. var resultDesc = document.getElementById('resultDesc');
  437. var collectBtn = document.getElementById('collectBtn');
  438. var mainCard = document.querySelector('.main-card');
  439. var redirectUrl = null;
  440. var querying = false;
  441. var phoneRegex = /^1[3-9]\d{9}$/;
  442. function showFieldError(msg) {
  443. fieldError.querySelector('span').textContent = msg;
  444. fieldError.classList.add('show');
  445. phoneInput.classList.add('error');
  446. }
  447. function clearFieldError() {
  448. fieldError.classList.remove('show');
  449. phoneInput.classList.remove('error');
  450. }
  451. function setLoading(loading) {
  452. querying = loading;
  453. if (loading) {
  454. loadingArea.classList.add('active');
  455. mainCard.style.opacity = '0.6';
  456. mainCard.style.pointerEvents = 'none';
  457. submitBtn.disabled = true;
  458. resultCard.classList.remove('show');
  459. resultCard.className = 'result-card';
  460. collectBtn.style.display = 'none';
  461. } else {
  462. loadingArea.classList.remove('active');
  463. mainCard.style.opacity = '';
  464. mainCard.style.pointerEvents = '';
  465. submitBtn.disabled = false;
  466. }
  467. }
  468. function showResult(type, title, desc, showClaimBtn) {
  469. resultCard.className = 'result-card ' + type + ' show';
  470. resultIcon.className = 'result-icon ' + type;
  471. var iconSvg = '';
  472. if (type === 'success') {
  473. iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
  474. } else if (type === 'warning') {
  475. iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>';
  476. } else {
  477. iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
  478. }
  479. resultIcon.innerHTML = iconSvg;
  480. resultTitle.textContent = title;
  481. resultDesc.textContent = desc;
  482. if (showClaimBtn) {
  483. collectBtn.style.display = 'inline-flex';
  484. } else {
  485. collectBtn.style.display = 'none';
  486. }
  487. resultCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
  488. }
  489. document.getElementById('queryForm').addEventListener('submit', function(e) {
  490. e.preventDefault();
  491. if (querying) return;
  492. var phone = phoneInput.value.replace(/\D/g, '');
  493. clearFieldError();
  494. if (!phoneRegex.test(phone)) {
  495. showFieldError('请输入正确的11位手机号码');
  496. phoneInput.focus();
  497. return;
  498. }
  499. setLoading(true);
  500. fetch('https://api.yeswash.cn/api/parking-coupon/checkParkingCoupon?mobilePhone=' + encodeURIComponent(phone))
  501. .then(function(res) {
  502. if (!res.ok) {
  503. throw new Error('服务繁忙,请稍后重试');
  504. }
  505. return res.json();
  506. })
  507. .then(function(data) {
  508. setLoading(false);
  509. if (data.code === 200) {
  510. redirectUrl = data.data;
  511. showResult('success',
  512. '符合减免条件',
  513. '您的手机号符合停车费用减免资格,点击下方按钮领取停车优惠券。',
  514. true
  515. );
  516. } else {
  517. showResult('warning',
  518. '暂不符合条件',
  519. data.message || '暂不符合停车减免条件,如有疑问请联系客服。',
  520. false
  521. );
  522. }
  523. })
  524. .catch(function(err) {
  525. setLoading(false);
  526. showResult('error',
  527. '网络异常',
  528. err.message || '网络连接失败,请检查网络后重试。',
  529. false
  530. );
  531. });
  532. });
  533. collectBtn.addEventListener('click', function() {
  534. if (redirectUrl && !querying) {
  535. setLoading(true);
  536. location.href = redirectUrl;
  537. }
  538. });
  539. phoneInput.addEventListener('input', function() {
  540. this.value = this.value.replace(/\D/g, '');
  541. if (this.value.length >= 11) {
  542. clearFieldError();
  543. }
  544. });
  545. phoneInput.focus();
  546. })();
  547. </script>
  548. </body>
  549. </html>