parking.html 19 KB

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