pay.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. <template>
  2. <view class="pay-container">
  3. <!-- 支付金额区域 -->
  4. <view class="amount-section">
  5. <view class="amount-label">支付金额</view>
  6. <view class="amount-display">
  7. <text class="currency">¥</text>
  8. <text class="amount">{{ displayAmount }}</text>
  9. </view>
  10. <button class="clear-amount-btn" @click="changeAmount(0)">清空金额</button>
  11. </view>
  12. <!-- 客户信息卡片 -->
  13. <view class="customer-info-card">
  14. <view class="card-header">
  15. <view class="customer-avatar">
  16. <text class="avatar-text">{{ customInfo.name ? customInfo.name.charAt(0) : '客' }}</text>
  17. </view>
  18. <view class="customer-details">
  19. <text class="customer-name">{{ customInfo.name || '客户' }}</text>
  20. <text class="customer-status has-debt" @click="goGathering">
  21. 查看待结订单
  22. </text>
  23. </view>
  24. </view>
  25. <view class="debt-info" v-if="Number(customInfo.remainDebtAmount) > 0">
  26. <view class="debt-amount" @click="changeAmount(customInfo.remainDebtAmount)">
  27. <text class="debt-label">待结金额</text>
  28. <text class="debt-value">¥{{ customInfo.remainDebtAmount }}</text>
  29. </view>
  30. </view>
  31. </view>
  32. <!-- 数字键盘 - 使用直接事件绑定,确保兼容性 -->
  33. <view class="keyboard-section">
  34. <view class="keyboard">
  35. <view class="keyboard-row" v-for="(row, rowIndex) in keyboardKeys" :key="rowIndex">
  36. <view
  37. class="key-item"
  38. v-for="(key, keyIndex) in row"
  39. :key="`${rowIndex}-${keyIndex}`"
  40. :class="{
  41. 'key-number': key.type === 'number',
  42. 'key-delete': key.type === 'delete',
  43. 'key-dot': key.type === 'dot',
  44. 'key-confirm': key.type === 'confirm'
  45. }"
  46. @click="handleKeyPress(key)"
  47. @touchstart="handleTouchStart"
  48. @touchend="handleTouchEnd"
  49. >
  50. <text v-if="key.type === 'delete'" class="iconfont icon-delete"></text>
  51. <text v-else-if="key.type === 'confirm'">确认</text>
  52. <text v-else>{{ key.value }}</text>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. <!-- 支付按钮 -->
  58. <view class="pay-button-section">
  59. <button
  60. class="pay-button"
  61. :class="{ disabled: !canPay }"
  62. :disabled="!canPay"
  63. @click="handlePay"
  64. >
  65. <text class="button-text">支付宝支付</text>
  66. </button>
  67. </view>
  68. </view>
  69. </template>
  70. <script>
  71. import { getGhsData } from '@/api/ghs';
  72. import { rechargeFn } from '@/api/custom-recharge'
  73. // 优化:使用常量避免重复创建
  74. const KEY_TYPES = {
  75. NUMBER: 'number',
  76. DELETE: 'delete',
  77. DOT: 'dot',
  78. CONFIRM: 'confirm'
  79. };
  80. const MAX_INTEGER_LENGTH = 8;
  81. const MAX_DECIMAL_LENGTH = 2;
  82. export default {
  83. name: 'pay',
  84. data() {
  85. return {
  86. currentAmount: '0',
  87. displayAmount: '0',
  88. // 优化:使用静态数据,避免重复创建
  89. keyboardKeys: [
  90. [
  91. { type: KEY_TYPES.NUMBER, value: '1' },
  92. { type: KEY_TYPES.NUMBER, value: '2' },
  93. { type: KEY_TYPES.NUMBER, value: '3' }
  94. ],
  95. [
  96. { type: KEY_TYPES.NUMBER, value: '4' },
  97. { type: KEY_TYPES.NUMBER, value: '5' },
  98. { type: KEY_TYPES.NUMBER, value: '6' }
  99. ],
  100. [
  101. { type: KEY_TYPES.NUMBER, value: '7' },
  102. { type: KEY_TYPES.NUMBER, value: '8' },
  103. { type: KEY_TYPES.NUMBER, value: '9' }
  104. ],
  105. [
  106. { type: KEY_TYPES.DOT, value: '.' },
  107. { type: KEY_TYPES.NUMBER, value: '0' },
  108. { type: KEY_TYPES.DELETE, value: '' }
  109. ]
  110. ],
  111. // 优化:使用更高效的状态管理
  112. amountBuffer: '0',
  113. updateScheduled: false,
  114. updateTimer: null,
  115. id:0,
  116. salt:'',
  117. ghsInfo:[],
  118. customInfo:{},
  119. payWay:1
  120. }
  121. },
  122. computed: {
  123. // 简化支付按钮判断逻辑:只要大于0就能支付
  124. canPay() {
  125. const amount = parseFloat(this.currentAmount);
  126. return amount > 0;
  127. }
  128. },
  129. onLoad(options) {
  130. if (options.id) {
  131. this.id = options.id;
  132. }
  133. if (options.salt) {
  134. this.salt = options.salt;
  135. }
  136. let that = this
  137. if (this.id && this.salt) {
  138. getGhsData({id:this.id,salt:this.salt}).then(res => {
  139. if (res.data && res.data.ghs){
  140. that.ghsInfo = res.data.ghs
  141. that.customInfo = res.data.custom?res.data.custom:[]
  142. if(that.customInfo.remainDebtAmount && Number(that.customInfo.remainDebtAmount)>0){
  143. that.currentAmount = parseFloat(that.customInfo.remainDebtAmount).toString()
  144. that.updateDisplay()
  145. }
  146. }
  147. })
  148. }
  149. },
  150. methods: {
  151. changeAmount(amount){
  152. this.currentAmount = amount
  153. this.updateDisplay()
  154. },
  155. // 优化:添加触摸反馈
  156. handleTouchStart(e) {
  157. const target = e.currentTarget;
  158. if (target && target.style) {
  159. target.style.transform = 'scale(0.95)';
  160. }
  161. },
  162. handleTouchEnd(e) {
  163. const target = e.currentTarget;
  164. if (target && target.style) {
  165. setTimeout(() => {
  166. target.style.transform = 'scale(1)';
  167. }, 100);
  168. }
  169. },
  170. // 优化:简化的键盘处理逻辑
  171. handleKeyPress(key) {
  172. // 防抖处理
  173. if (this.updateTimer) {
  174. clearTimeout(this.updateTimer);
  175. }
  176. if (key.type === KEY_TYPES.NUMBER) {
  177. this.addNumber(key.value);
  178. } else if (key.type === KEY_TYPES.DELETE) {
  179. this.deleteNumber();
  180. } else if (key.type === KEY_TYPES.DOT) {
  181. this.addDecimal();
  182. }
  183. // 使用 requestAnimationFrame 优化更新
  184. this.scheduleUpdate();
  185. },
  186. // 优化:使用 requestAnimationFrame 调度更新
  187. scheduleUpdate() {
  188. if (!this.updateScheduled) {
  189. this.updateScheduled = true;
  190. requestAnimationFrame(() => {
  191. this.updateDisplay();
  192. this.updateScheduled = false;
  193. });
  194. }
  195. },
  196. // 优化:更高效的数字添加逻辑
  197. addNumber(num) {
  198. const buffer = this.amountBuffer;
  199. // 快速路径:如果当前是0且输入的不是小数点,直接替换
  200. if (buffer === '0' && num !== '.') {
  201. this.amountBuffer = num;
  202. this.currentAmount = num;
  203. return;
  204. }
  205. // 检查长度限制
  206. const parts = buffer.split('.');
  207. const integerPart = parts[0];
  208. const decimalPart = parts[1];
  209. // 整数部分限制
  210. if (!decimalPart && integerPart.length >= MAX_INTEGER_LENGTH) {
  211. uni.showToast({
  212. title: '金额不能超过8位数',
  213. icon: 'none',
  214. duration: 1500
  215. })
  216. return;
  217. }
  218. // 小数部分限制
  219. if (decimalPart && decimalPart.length >= MAX_DECIMAL_LENGTH) {
  220. uni.showToast({
  221. title: '最多支持2位小数',
  222. icon: 'none',
  223. duration: 1500
  224. })
  225. return;
  226. }
  227. // 添加数字
  228. this.amountBuffer = buffer + num;
  229. this.currentAmount = this.amountBuffer;
  230. },
  231. // 优化:更高效的小数点添加逻辑
  232. addDecimal() {
  233. if (!this.amountBuffer.includes('.')) {
  234. this.amountBuffer += '.';
  235. this.currentAmount = this.amountBuffer;
  236. }
  237. },
  238. // 优化:更高效的删除逻辑
  239. deleteNumber() {
  240. const buffer = this.amountBuffer;
  241. if (buffer.length > 1) {
  242. this.amountBuffer = buffer.slice(0, -1);
  243. } else {
  244. this.amountBuffer = '0';
  245. }
  246. this.currentAmount = this.amountBuffer;
  247. },
  248. // 优化:更高效的显示更新逻辑
  249. updateDisplay() {
  250. let amount = this.currentAmount;
  251. // 确保 amount 是字符串类型
  252. if (typeof amount !== 'string') {
  253. amount = amount.toString();
  254. }
  255. // 快速路径:如果是0,直接显示
  256. if (amount === '0') {
  257. this.displayAmount = '0';
  258. return;
  259. }
  260. // 检查是否包含小数点
  261. if (amount.includes('.')) {
  262. const numAmount = parseFloat(amount) || 0;
  263. this.displayAmount = numAmount.toFixed(2);
  264. } else {
  265. // 整数显示
  266. this.displayAmount = amount;
  267. }
  268. },
  269. // 优化:更高效的金额设置
  270. setAmount(amount) {
  271. const numAmount = parseFloat(amount);
  272. if (!isNaN(numAmount) && numAmount > 0) {
  273. const amountStr = numAmount.toString();
  274. this.amountBuffer = amountStr;
  275. this.currentAmount = amountStr;
  276. this.updateDisplay();
  277. }
  278. },
  279. // 处理支付
  280. handlePay() {
  281. if (!this.canPay) return;
  282. const amount = parseFloat(this.currentAmount);
  283. // 简化验证:只要大于0就能支付
  284. if (amount <= 0) {
  285. uni.showToast({
  286. title: '请输入金额!',
  287. icon: 'none',
  288. duration: 2000
  289. })
  290. return false
  291. }
  292. let params = {}
  293. params = {
  294. actPrice: amount,
  295. payWay: this.payWay,
  296. }
  297. params.ghsId = this.id
  298. params.salt = this.salt
  299. rechargeFn(params).then(res => {
  300. //错误返回判断
  301. if(res.code == 0){
  302. uni.hideLoading()
  303. uni.showToast({
  304. title: res.msg,
  305. icon: 'none',
  306. duration: 2000
  307. })
  308. return false
  309. }
  310. // 隐藏加载提示
  311. uni.hideLoading()
  312. // 显示成功提示
  313. uni.showToast({
  314. title: '正在跳转支付...',
  315. icon: 'success',
  316. duration: 1500
  317. })
  318. // 延迟跳转到支付页面
  319. setTimeout(() => {
  320. window.location.href = res.data.url;
  321. }, 300)
  322. }).catch(err => {
  323. // 隐藏加载提示
  324. uni.hideLoading()
  325. // 显示错误提示
  326. uni.showToast({
  327. title: '请求失败,请重试',
  328. icon: 'none',
  329. duration: 2000
  330. })
  331. })
  332. },
  333. // 返回上一页
  334. goBack() {
  335. uni.navigateBack({
  336. delta: 1
  337. });
  338. },
  339. // 跳转到待结订单页面
  340. goGathering() {
  341. if (!this.id) {
  342. uni.showToast({
  343. title: '供货商信息加载中,请稍后再试',
  344. icon: 'none'
  345. });
  346. return;
  347. }
  348. uni.navigateTo({
  349. url: `/pagesPurchase/gathering?id=${this.id}&salt=${this.salt}`
  350. });
  351. },
  352. }
  353. }
  354. </script>
  355. <style lang="scss" scoped>
  356. .pay-container {
  357. min-height: 100vh;
  358. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  359. position: relative;
  360. }
  361. .nav-bar {
  362. display: flex;
  363. align-items: center;
  364. justify-content: center; /* Changed to center the title */
  365. padding: 20upx 30upx;
  366. background: rgba(255, 255, 255, 0.1);
  367. backdrop-filter: blur(10px);
  368. .nav-back {
  369. width: 80upx;
  370. height: 80upx;
  371. display: flex;
  372. align-items: center;
  373. justify-content: center;
  374. border-radius: 50%;
  375. background: rgba(255, 255, 255, 0.2);
  376. cursor: pointer;
  377. transition: all 0.2s ease;
  378. &:active {
  379. background: rgba(255, 255, 255, 0.3);
  380. transform: scale(0.9);
  381. }
  382. .iconfont {
  383. font-size: 40upx;
  384. color: #fff;
  385. font-weight: bold;
  386. }
  387. }
  388. .nav-title {
  389. color: #fff;
  390. font-size: 36upx;
  391. font-weight: 600;
  392. }
  393. .nav-placeholder {
  394. width: 80upx; /* Placeholder for back button */
  395. }
  396. }
  397. .amount-section {
  398. padding: 60upx 40upx;
  399. text-align: center;
  400. .amount-label {
  401. color: rgba(255, 255, 255, 0.8);
  402. font-size: 34upx;
  403. margin-bottom: 20upx;
  404. }
  405. .amount-display {
  406. display: flex;
  407. align-items: baseline;
  408. justify-content: center;
  409. margin-bottom: 20upx;
  410. .currency {
  411. color: #fff;
  412. font-size: 48upx;
  413. font-weight: 600;
  414. margin-right: 10upx;
  415. }
  416. .amount {
  417. color: #fff;
  418. font-size: 80upx;
  419. font-weight: 700;
  420. font-family: 'Arial', sans-serif;
  421. }
  422. }
  423. .clear-amount-btn {
  424. color: rgb(226, 219, 219);
  425. font-size: 22upx;
  426. margin-top: 20upx;
  427. background: transparent;
  428. border: 1upx solid rgb(226, 219, 219);
  429. border-radius: 12upx;
  430. padding: 6upx 12upx;
  431. transition: all 0.3s ease;
  432. cursor: pointer;
  433. width: auto;
  434. display: inline-block;
  435. }
  436. }
  437. .customer-info-card {
  438. background: #fff; /* Changed to white */
  439. margin: 0 30upx 20upx;
  440. border-radius: 20upx;
  441. padding: 30upx;
  442. box-shadow: 0 8upx 30upx rgba(0, 0, 0, 0.08);
  443. position: relative;
  444. overflow: hidden;
  445. &::before {
  446. content: '';
  447. position: absolute;
  448. top: 0;
  449. left: 0;
  450. right: 0;
  451. height: 8upx;
  452. background: #fff; /* Changed to white */
  453. box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.1);
  454. }
  455. .card-header {
  456. display: flex;
  457. align-items: center;
  458. margin-bottom: 20upx;
  459. margin-top: 8upx;
  460. .customer-avatar {
  461. width: 90upx;
  462. height: 90upx;
  463. border-radius: 50%;
  464. background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%);
  465. display: flex;
  466. align-items: center;
  467. justify-content: center;
  468. margin-right: 25upx;
  469. box-shadow: 0 6upx 20upx rgba(22, 119, 255, 0.3);
  470. position: relative;
  471. &::after {
  472. content: '';
  473. position: absolute;
  474. top: -2upx;
  475. left: -2upx;
  476. right: -2upx;
  477. bottom: -2upx;
  478. border-radius: 50%;
  479. background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%);
  480. z-index: -1;
  481. opacity: 0.3;
  482. }
  483. .avatar-text {
  484. color: #fff;
  485. font-size: 44upx;
  486. font-weight: 600;
  487. }
  488. }
  489. .customer-details {
  490. flex: 1;
  491. display: flex;
  492. align-items: center;
  493. justify-content: space-between;
  494. .customer-name {
  495. display: block;
  496. font-size: 34upx;
  497. font-weight: 600;
  498. color: #333;
  499. }
  500. .customer-status {
  501. display: flex;
  502. align-items: center;
  503. justify-content: center;
  504. font-size: 24upx;
  505. color: #999;
  506. padding: 0 24upx;
  507. height: 70upx;
  508. line-height: 70upx;
  509. border-radius: 36upx;
  510. background: #f8f9fa;
  511. border: 1upx solid #e9ecef;
  512. box-sizing: border-box;
  513. &.has-debt {
  514. color: #fff;
  515. background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
  516. border-color: #ff6b6b;
  517. box-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.3);
  518. }
  519. }
  520. }
  521. }
  522. .debt-info {
  523. background: linear-gradient(135deg, #fff5f5 0%, #fef2f2 100%);
  524. border-radius: 15upx;
  525. padding: 20upx 25upx;
  526. margin-top: 20upx;
  527. border: 1upx solid rgba(255, 107, 107, 0.2);
  528. position: relative;
  529. &::before {
  530. content: '';
  531. position: absolute;
  532. top: 0;
  533. left: 0;
  534. right: 0;
  535. bottom: 0;
  536. background: linear-gradient(135deg, rgba(255, 107, 107, 0.05) 0%, rgba(255, 107, 107, 0.02) 100%);
  537. border-radius: 15upx;
  538. }
  539. .debt-amount {
  540. display: flex;
  541. align-items: baseline;
  542. justify-content: space-between;
  543. margin-bottom: 10upx;
  544. position: relative;
  545. z-index: 1;
  546. .debt-label {
  547. font-size: 28upx;
  548. color: #666;
  549. font-weight: 500;
  550. }
  551. .debt-value {
  552. font-size: 40upx;
  553. font-weight: 700;
  554. color: #ff6b6b;
  555. font-family: 'Arial', sans-serif;
  556. text-shadow: 0 2upx 10upx rgba(255, 107, 107, 0.2);
  557. }
  558. }
  559. .debt-tip {
  560. font-size: 22upx;
  561. color: #999;
  562. text-align: right;
  563. position: relative;
  564. z-index: 1;
  565. font-style: italic;
  566. }
  567. }
  568. }
  569. .keyboard-section {
  570. position: fixed;
  571. bottom: 160upx;
  572. left: 0;
  573. right: 0;
  574. background: rgba(255, 255, 255, 0.98);
  575. backdrop-filter: blur(20px);
  576. padding: 30upx;
  577. border-top: 1upx solid rgba(0, 0, 0, 0.05);
  578. .keyboard {
  579. .keyboard-row {
  580. display: flex;
  581. margin-bottom: 20upx;
  582. &:last-child {
  583. margin-bottom: 0;
  584. }
  585. .key-item {
  586. flex: 1;
  587. height: 120upx;
  588. margin: 0 10upx;
  589. border-radius: 20upx;
  590. display: flex;
  591. align-items: center;
  592. justify-content: center;
  593. font-size: 40upx;
  594. font-weight: 600;
  595. transition: all 0.15s ease;
  596. user-select: none;
  597. -webkit-user-select: none;
  598. cursor: pointer;
  599. will-change: transform;
  600. position: relative;
  601. overflow: hidden;
  602. &::before {
  603. content: '';
  604. position: absolute;
  605. top: 0;
  606. left: 0;
  607. right: 0;
  608. bottom: 0;
  609. background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  610. opacity: 0;
  611. transition: opacity 0.15s ease;
  612. }
  613. &:active::before {
  614. opacity: 1;
  615. }
  616. &.key-number {
  617. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  618. color: #333;
  619. box-shadow: 0 4upx 20upx rgba(0, 0, 0, 0.08);
  620. border: 1upx solid rgba(0, 0, 0, 0.05);
  621. }
  622. &.key-delete {
  623. background: linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%);
  624. color: #fff;
  625. box-shadow: 0 4upx 20upx rgba(255, 107, 107, 0.3);
  626. }
  627. &.key-dot {
  628. background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
  629. color: #333;
  630. box-shadow: 0 4upx 20upx rgba(0, 0, 0, 0.08);
  631. border: 1upx solid rgba(0, 0, 0, 0.05);
  632. }
  633. &.key-confirm {
  634. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  635. color: #fff;
  636. box-shadow: 0 4upx 20upx rgba(102, 126, 234, 0.3);
  637. }
  638. }
  639. }
  640. }
  641. }
  642. .pay-button-section {
  643. position: fixed;
  644. bottom: 0;
  645. left: 0;
  646. right: 0;
  647. padding: 30upx;
  648. background: rgba(255, 255, 255, 0.98);
  649. backdrop-filter: blur(20px);
  650. border-top: 1upx solid rgba(0, 0, 0, 0.05);
  651. .pay-button {
  652. width: 100%;
  653. height: 100upx;
  654. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  655. color: #fff;
  656. font-size: 36upx;
  657. font-weight: 600;
  658. border-radius: 50upx;
  659. border: none;
  660. transition: all 0.3s ease;
  661. position: relative;
  662. overflow: hidden;
  663. &::before {
  664. content: '';
  665. position: absolute;
  666. top: 0;
  667. left: 0;
  668. right: 0;
  669. bottom: 0;
  670. background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
  671. opacity: 0;
  672. transition: opacity 0.3s ease;
  673. }
  674. &:active::before {
  675. opacity: 1;
  676. }
  677. &.disabled {
  678. background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);
  679. color: #adb5bd;
  680. box-shadow: none;
  681. }
  682. &:not(.disabled):active {
  683. transform: scale(0.98);
  684. }
  685. .button-text {
  686. position: absolute;
  687. left: 50%;
  688. transform: translateX(-50%);
  689. font-size: 36upx;
  690. font-weight: 600;
  691. color: #fff;
  692. }
  693. .button-amount {
  694. position: absolute;
  695. right: 30upx;
  696. font-size: 36upx;
  697. font-weight: 700;
  698. color: #fff;
  699. font-family: 'Arial', sans-serif;
  700. }
  701. }
  702. }
  703. </style>