index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. <template>
  2. <ay-container v-show="store.user.isLogined" :title="data.title">
  3. <div class="chunk">
  4. <div class="center justify-between top">
  5. <div class="center" @click="methods.goPerson">
  6. <image class="personal" :src="store.user.userInfo.head_url" mode="scaleToFill" />
  7. <div>
  8. <div>{{ store.user.userInfo.user_name }}</div>
  9. <div class="mobile">{{ store.user.userInfo.mobileDes }}</div>
  10. </div>
  11. </div>
  12. <uni-icons
  13. type="scan"
  14. color=""
  15. class="p-color"
  16. size="40"
  17. @click="methods.scanCode"
  18. ></uni-icons>
  19. </div>
  20. <div class="center">
  21. <ay-flowLine
  22. class="mt-spac mb-spac"
  23. :lineWidth="4"
  24. :loading="store.webapi.strategy.get_user_qrcode.ing"
  25. >
  26. <div class="qrcode">
  27. <image
  28. src="@img/qr@3x.png"
  29. class="image"
  30. mode="aspectFit"
  31. v-if="data.hasnopayfordriver || data.qrcode.expire"
  32. @click="methods.getQrcode"
  33. />
  34. <image :src="data.qrcode.img" class="image" mode="aspectFit" v-else />
  35. </div>
  36. </ay-flowLine>
  37. </div>
  38. <div class="center qrcode-text">
  39. <template v-if="!data.firstUnload">
  40. <template v-if="data.hasnopayfordriver">存在未支付完成订单</template>
  41. <template v-else-if="data.qrcode.expire">
  42. 二维码已失效
  43. <ay-refresh
  44. :iconSize="36"
  45. :loading="store.webapi.strategy.get_user_qrcode.ing"
  46. @refresh="methods.getQrcode"
  47. ></ay-refresh>
  48. </template>
  49. <template v-else>
  50. 有效时间:
  51. <ay-countdown :seconds="data.qrcode.seconds" @ender="data.qrcode.expire = true" />
  52. </template>
  53. </template>
  54. </div>
  55. </div>
  56. <div class="flex">
  57. <ay-flowLine class="flex-1 mr-spac" :loading="store.webapi.strategy.get_driver_balance.ing">
  58. <div class="chunk m0 h-100% s-fz money-bg" @click="methods.goAccount">
  59. <div class="mb-spacd4">
  60. 可用余额
  61. <div class="inline yellow-color ss-fz ml-spacd4" v-if="data.accountInfo.flag === 0">
  62. [余额不足]
  63. </div>
  64. </div>
  65. <ay-numer :value="data.accountInfo.showBalance" :unit="data.accountInfo.unit" />
  66. </div>
  67. </ay-flowLine>
  68. <ay-flowLine class="flex-1" :loading="store.webapi.strategy.get_truck_info.ing">
  69. <div class="chunk m0 h-100% s-fz cars" @click="methods.truckManage">
  70. <div>
  71. <div class="mb-spacd4" v-show="showcm">车辆管理</div>
  72. <div v-show="store.webapi.strategy.get_truck_info.firstSuccess">
  73. <div class="p-color mt-spac" v-if="data.truckInfo.length === 0">添加车辆</div>
  74. <div v-else>
  75. <span class="font-bold b-fz">{{ data.truckInfo.length }}</span>
  76. </div>
  77. </div>
  78. </div>
  79. </div>
  80. </ay-flowLine>
  81. </div>
  82. <div class="center justify-around mt-spacm2">
  83. <div
  84. class="text-center menu"
  85. v-for="(m, i) in data.menus"
  86. :key="i"
  87. @click="methods.goPage(m)"
  88. >
  89. <img class="icon" :src="m.icon" />
  90. <div>{{ m.name }}</div>
  91. </div>
  92. </div>
  93. <div class="chuck list-app">
  94. <ay-sticky :top="topHeightPX" relativeTo="#stations" targetSelector="#stationTop">
  95. <div
  96. class="center justify-between sticky"
  97. id="stationTop"
  98. :class="{ stickyed: data.station.stickyed }"
  99. @click="methods.hiddenDoora"
  100. >
  101. <div class="title" @click.stop="methods.hiddenDoorb">附近加气站</div>
  102. <div v-if="data.userLocation" @click="methods.drawerOpen">
  103. {{ data.station.curCity }}
  104. <uni-icons type="down" size="12" />
  105. </div>
  106. </div>
  107. </ay-sticky>
  108. <div v-show="data.userLocation" id="stations">
  109. <ay-flowLine :minLoadTime="400" :loading="store.webapi.strategy.list_mini.ing">
  110. <div style="height: 2rpx"></div>
  111. </ay-flowLine>
  112. <ayb-station
  113. v-for="(la, i) in data.station.listApp"
  114. :key="i"
  115. :stationInfo="la"
  116. ></ayb-station>
  117. </div>
  118. <div
  119. class="center p-color"
  120. v-show="!data.firstUnload && !data.userLocation"
  121. @click="methods.getListApp({ activation: true })"
  122. >
  123. 查看附近加气站
  124. </div>
  125. </div>
  126. <uni-popup ref="inputDialog" type="dialog">
  127. <uni-popup-dialog
  128. mode="input"
  129. title="邀请通知"
  130. confirmText="加入"
  131. cancelText="拒绝"
  132. :beforeClose="true"
  133. @confirm="methods.agree"
  134. @close="methods.disagree"
  135. >
  136. <div class="text-center w-100%">
  137. <div class="mb-spacd2 text-center">
  138. 【{{ data.invite?.org?.orgName }}】邀请您加入成为其司机
  139. <span class="p-color" @click="methods.phone(data.invite?.org?.mobile)">
  140. <uni-icons type="phone" color="" class="mr-spacd4" size="none"></uni-icons>
  141. <span>{{ data.invite?.org?.mobile }}</span>
  142. </span>
  143. </div>
  144. </div>
  145. </uni-popup-dialog>
  146. </uni-popup>
  147. <ay-drawer
  148. ref="drawer"
  149. mode="right"
  150. :maskClick="true"
  151. :width="320"
  152. :top="topHeightPX"
  153. @change="methods.drawerChange"
  154. >
  155. <uni-indexed-list
  156. :options="data.station.cityList"
  157. :show-select="false"
  158. @click="methods.changeCity"
  159. ref="indexedList"
  160. v-if="data.station.indexedListShow"
  161. />
  162. </ay-drawer>
  163. <ayb-carNumber ref="carNumber" />
  164. </ay-container>
  165. </template>
  166. <script lang="ts" setup>
  167. import stompSocket from '@/utils/api/socket/stomp'
  168. import perpay from '@img/icons/perpay.png'
  169. import payhistory from '@img/icons/payhistory.png'
  170. import firm from '@img/icons/firm.png'
  171. import card from '@img/icons/card.png'
  172. const drawer = ref()
  173. const indexedList = ref()
  174. const carNumber = ref()
  175. const inputDialog = ref()
  176. const staticData = {
  177. /** 选择的城市 缓存key名 */
  178. cctkn: 'chooseCity',
  179. /** 默认选择城市 */
  180. defCity: '全部',
  181. /** websocket 实例 */
  182. client: null,
  183. // entranceArgs: null as AyContainerEntryArgs,
  184. /** 临时记录位置信息 */
  185. location: { longitude: '', latitude: '' } as any,
  186. indexedListShowed: false,
  187. /** 索引组件数据监听器 */
  188. indexedListWatcher: null,
  189. /** 页面滚动距离 */
  190. scrollTop: 0,
  191. }
  192. const data = ay.initData({
  193. /** 未load */
  194. firstUnload: true,
  195. /** 存在未支付完成订单 */
  196. hasnopayfordriver: true,
  197. invite: {} as 预添加司机详情,
  198. truckInfo: [] as PersonDriver对象[],
  199. accountInfo: {} as IAccountInfo,
  200. /** 用户已授权定位 */
  201. userLocation: false,
  202. /** 二维码相关 */
  203. qrcode: {
  204. /** 有效时长 m */
  205. seconds: 300,
  206. /** 二维码 */
  207. img: null,
  208. /** 已过期 */
  209. expire: true,
  210. },
  211. /** 菜单列表 */
  212. menus: [
  213. {
  214. id: 0,
  215. icon: perpay,
  216. name: '待支付订单',
  217. },
  218. {
  219. id: 1,
  220. name: '加气订单',
  221. icon: payhistory,
  222. },
  223. {
  224. id: 2,
  225. name: '所属物流',
  226. icon: firm,
  227. },
  228. {
  229. id: 3,
  230. name: '优惠卡/券',
  231. icon: card,
  232. },
  233. ],
  234. station: {
  235. /** 头部已吸顶 */
  236. stickyed: false,
  237. cityList: [] /** 附近加气站列表 */,
  238. curCity: staticData.defCity,
  239. listApp: [],
  240. indexedListShow: false,
  241. },
  242. hiddenDoor: [],
  243. })
  244. const topHeight = computed(() => config.common.SystemInfo.safeArea.top + 44)
  245. const topHeightPX = computed(() => `${topHeight.value}px`)
  246. const showcm = computed(() => {
  247. return (
  248. !store.webapi.strategy.get_truck_info.firstSuccess ||
  249. (store.webapi.strategy.get_truck_info.firstSuccess && data.truckInfo.length)
  250. )
  251. })
  252. const methods = ay.initMethods(
  253. {
  254. hiddenDoorb() {
  255. data.hiddenDoor[data.hiddenDoor.length - 1]++
  256. },
  257. hiddenDoora() {
  258. if (
  259. data.hiddenDoor[0] === 3 &&
  260. data.hiddenDoor[1] === 1 &&
  261. data.hiddenDoor[2] === 2 &&
  262. data.hiddenDoor[3] === 4
  263. ) {
  264. data.hiddenDoor = []
  265. uni.setClipboardData({
  266. data: JSON.stringify({ userInfo: store.user.userInfo }),
  267. })
  268. } else {
  269. data.hiddenDoor.push(0)
  270. }
  271. },
  272. phone(num) {
  273. uni.makePhoneCall({
  274. phoneNumber: num,
  275. })
  276. },
  277. getTruckInfo() {
  278. webapi.strategy.get_truck_info({}).then((res) => {
  279. data.truckInfo = aop.request.AR.truckInfo(res)
  280. })
  281. },
  282. truckManage() {
  283. if (data.truckInfo.length) {
  284. ay.goPage(config.pages.truckInfo_index)
  285. } else {
  286. carNumber.value.open().then((cn) => {
  287. if (store.webapi.strategy.bind_person_truck.ing) {
  288. return
  289. }
  290. webapi.strategy
  291. .bind_person_truck<{ userId: string }>({
  292. userId: store.user.userInfo.user_id,
  293. newCarNumber: cn,
  294. })
  295. .then((res) => {
  296. if (res) {
  297. func.native.showToast('添加成功')
  298. methods.getTruckInfo()
  299. }
  300. })
  301. })
  302. }
  303. },
  304. goPerson() {
  305. ay.goPage(config.pages.personCenter_index)
  306. },
  307. goPage(menu) {
  308. const maps = {
  309. 0() {
  310. methods.checkNopayfordriver(1)
  311. },
  312. 1() {
  313. ay.goPage(config.pages.order_index)
  314. },
  315. 2() {
  316. ay.goPage(config.pages.org_index)
  317. },
  318. 3() {
  319. ay.goPage(config.pages.cards_index)
  320. },
  321. }
  322. maps[menu.id]()
  323. },
  324. drawerOpen() {
  325. drawer.value.open()
  326. data.station.indexedListShow = true
  327. // 解决uni-indexed-list 组件滑动失效问题
  328. // 问题原因: 因为嵌套于uni-drawer内,造成uni-indexed-list的winOffsetY值获取有误
  329. // 解决方法:通过阅读组件源码发现uni-indexed-list在初始化时会设置winOffsetY,再给他设置正确的值。
  330. // 小程序于h5环境设置时机不同;
  331. // 组件内部:小程序仅首次渲染完毕会设置winOffsetY,h5环境每次打开组件都会重新设置winOffsetY
  332. // 通过监听$data.loaded的变化,重新设置winOffsetY为页面滚动距离,以及小程序环境-每次呈现组件后重新设置winOffsetY
  333. nextTick(() => {
  334. // 小程序环境-每次呈现组件后重新设置winOffsetY
  335. // #ifdef MP
  336. if (indexedList.value) {
  337. indexedList.value.$data.winOffsetY = staticData.scrollTop + topHeight.value
  338. }
  339. // #endif
  340. if (!staticData.indexedListWatcher) {
  341. staticData.indexedListWatcher = watch(
  342. () => indexedList.value?.$data.loaded,
  343. (nv) => {
  344. // 小程序环境仅首次呈现监听到, h5环境每次呈现都会监听到
  345. if (indexedList.value) {
  346. indexedList.value.$data.winOffsetY = staticData.scrollTop + topHeight.value
  347. }
  348. },
  349. {
  350. // deep: true,
  351. },
  352. )
  353. // 调用可释放监听
  354. // staticData.indexedListWatcher()
  355. }
  356. })
  357. },
  358. drawerChange(isopen) {},
  359. changeCity(args) {
  360. drawer.value.close()
  361. data.station.curCity = args.item.name
  362. uni.setStorageSync(staticData.cctkn, args.item.name)
  363. methods.getListApp()
  364. },
  365. goAccount() {
  366. ay.goPage(config.pages.account_index)
  367. },
  368. /** 初始化ws */
  369. initWS() {
  370. stompSocket
  371. .init(
  372. ay.getWebsocketUrl('websocket/sockjs'),
  373. // 传参
  374. {
  375. access_token: store.user.userInfo.token,
  376. identifier: store.user.userInfo.Identifier,
  377. },
  378. // ws断开回调
  379. () => {
  380. methods.initWS()
  381. },
  382. )
  383. .then((client) => {
  384. staticData.client = client
  385. // 订阅
  386. const subscription = client.subscribe(
  387. // 路径
  388. '/user/' + store.user.userInfo.user_id + '/msg',
  389. // 接收到的数据
  390. (res) => {
  391. const body = JSON.parse(res.body)
  392. if (body.type === 1) {
  393. ay.goPage(config.pages.order_prePay, { params: JSON.parse(body.content) })
  394. } else if (body.type === 0) {
  395. const content = JSON.parse(body.content)
  396. uni
  397. .showModal({
  398. title: content.data,
  399. message: content.message,
  400. })
  401. .then(() => {})
  402. }
  403. },
  404. )
  405. })
  406. },
  407. // 直接调用发送即可
  408. send() {
  409. staticData.client.send(
  410. // 路径
  411. '/user/' + store.user.userInfo.user_id + '/msg',
  412. {},
  413. // 发送文本
  414. JSON.stringify({ content: '1212' }),
  415. )
  416. },
  417. /** 检查未支付
  418. * type 0:仅检查 1:点击待支付订单 2:点击扫码
  419. * */
  420. async checkNopayfordriver(type: 0 | 1 | 2 = 0) {
  421. const nopayfordriver = await webapi.pay.find_unpayfordriver()
  422. // 存在 未支付(待支付、支付中、支付异常)
  423. if (nopayfordriver) {
  424. if (type === 1) {
  425. if (nopayfordriver.settleStatus === 1) {
  426. // 跳未支付
  427. ay.goPage(config.pages.order_prePay, { params: { orderId: nopayfordriver.orderId } })
  428. }
  429. }
  430. if (type === 2) {
  431. func.native
  432. .showModal({
  433. title: '温馨提示',
  434. content: '存在未支付完成订单',
  435. showCancel: true,
  436. })
  437. .then((res) => {
  438. if (res.confirm) {
  439. if (nopayfordriver.settleStatus === 1) {
  440. ay.goPage(config.pages.order_prePay, {
  441. params: { orderId: nopayfordriver.orderId },
  442. })
  443. } else {
  444. ay.goPage(config.pages.order_orderDetail, {
  445. params: { orderId: nopayfordriver.orderId },
  446. })
  447. }
  448. }
  449. })
  450. }
  451. return true
  452. } else {
  453. if (type === 1) {
  454. func.native.showToast('暂无待支付订单!')
  455. }
  456. return false
  457. }
  458. },
  459. async scanCode() {
  460. if (await methods.checkNopayfordriver(2)) {
  461. return
  462. }
  463. const ret: { gasstationId?: string; cashierId?: string } = await func.native.scan()
  464. if (!(ret.gasstationId && ret.cashierId)) {
  465. func.native.showToast('二维码无效')
  466. return
  467. }
  468. const user = await webapi.user.find_6({ userId: ret.cashierId })
  469. if (ret.gasstationId === user.user.orgId) {
  470. const price = await webapi.strategy.find_price({
  471. gasstationId: ret.gasstationId,
  472. driverId: user.user.userId,
  473. })
  474. if (
  475. ((price.qrcode === 0 || price.qrcode === 1) && ret.gasstationId !== ret.cashierId) || // 设置的加气站收款码
  476. (price.qrcode === 2 && ret.gasstationId === ret.cashierId) // 设置的收银员
  477. ) {
  478. func.native.showModal({
  479. title: '错误提示',
  480. content: '加气站收款码已禁用,请选择收银员收款码扫码。',
  481. })
  482. } else {
  483. const gasJudge = await webapi.strategy.driver_gas_judge({
  484. driverId: user.user.userId,
  485. gasstationId: ret.gasstationId,
  486. })
  487. if (gasJudge === 1) {
  488. // 创建订单
  489. ay.goPage(config.pages.order_createOrder, { params: ret })
  490. } else if (gasJudge === 2) {
  491. func.native.showModal({
  492. title: '错误提示',
  493. content: `该加气站未及时补充平台气源,已无法通过大象平台为您提供优质气源,给您带来的不便深感其歉意,如有疑问可以与加气站沟通,亦可拨打大象加气平台客服电话:"${store.common.data.phone}"`,
  494. })
  495. }
  496. }
  497. } else {
  498. func.native.showModal({
  499. title: '错误提示',
  500. content: '当前收银员所属企业和二维码对应的企业不一致,请联系加气站管理员。',
  501. })
  502. }
  503. },
  504. /** 同意加入 */
  505. agree() {
  506. webapi.user.agree({ id: data.invite.driverWhiteList.id }).then((res) => {
  507. if (res) {
  508. func.native.showToast('加入成功,请重新登录').then(() => {})
  509. inputDialog.value.close()
  510. }
  511. })
  512. },
  513. /** 拒绝加入 */
  514. disagree() {
  515. webapi.user.disagree({ id: data.invite.driverWhiteList.id }).then((res) => {
  516. if (res) {
  517. func.native.showToast('已拒绝')
  518. inputDialog.value.close()
  519. }
  520. })
  521. },
  522. /** 获取邀请信息 */
  523. getInvite() {
  524. webapi.user
  525. .find_by_driver_mobile({ driverMobile: store.user.userInfo.mobile })
  526. .then((res) => {
  527. if (res.driverWhiteList && res.org) {
  528. data.invite = res
  529. inputDialog.value.open()
  530. }
  531. })
  532. },
  533. getCityList() {
  534. webapi.strategy.city_list().then((res) => {
  535. res.unshift({ text: staticData.defCity, children: [{ text: staticData.defCity }] })
  536. data.station.cityList = res.map((m) => {
  537. return {
  538. letter: m.text,
  539. data: m.children.map((cm) => cm.text),
  540. }
  541. })
  542. })
  543. },
  544. async getListApp({
  545. cras = config.common.defAyContainerRefreshArgs,
  546. activation = false,
  547. checkScope = false,
  548. } = {}) {
  549. if (checkScope) {
  550. }
  551. // 非激活 && 未授权
  552. if (!activation && !data.userLocation) {
  553. // 取消加载中效果
  554. ay.containerLoaded({
  555. reqState: enums.ReqState.cancel,
  556. })
  557. return
  558. }
  559. let location = staticData.location
  560. // 上拉不重新获取位置
  561. if (!cras.isAdd) {
  562. location = await func.native.getLocation(false)
  563. if (!location) return
  564. staticData.location = location
  565. }
  566. data.userLocation = true
  567. webapi.strategy
  568. .list_mini(
  569. {
  570. page: cras.page,
  571. size: cras.size,
  572. param: {
  573. city: data.station.curCity === staticData.defCity ? '' : data.station.curCity,
  574. longitude: location.longitude.toString(),
  575. latitude: location.latitude.toString(),
  576. },
  577. },
  578. { showLoading: activation }, // || !cras.isAdd },
  579. )
  580. .then((res) => {
  581. if (cras.isAdd) {
  582. data.station.listApp.push(...res.records)
  583. } else {
  584. data.station.listApp = res.records
  585. }
  586. })
  587. },
  588. getQrcode() {
  589. if (data.hasnopayfordriver || store.webapi.strategy.get_user_qrcode.ing) {
  590. return
  591. }
  592. return webapi.strategy.get_user_qrcode({}, { minRTime: 1e3 }).then(async (res) => {
  593. data.qrcode.img = res
  594. data.qrcode.expire = false
  595. })
  596. },
  597. },
  598. {
  599. scanCode: { showLoading: true },
  600. },
  601. )
  602. ay.entrance(
  603. async (args) => {
  604. // staticData.entranceArgs = args
  605. const init = async () => {
  606. webapi.strategy.get_driver_balance({}).then((res) => {
  607. data.accountInfo = {
  608. ...res,
  609. ...aop.request.AR.getAccountInfo(res),
  610. }
  611. })
  612. data.hasnopayfordriver = await methods.checkNopayfordriver()
  613. methods.getTruckInfo()
  614. }
  615. if (args.loadType === enums.LoadType.onLoad) {
  616. // data.title = store.curPage?.pageConfig?.title
  617. // #ifdef MP
  618. // 用户是否授权了获取地理位置
  619. await uni
  620. .getSetting()
  621. .then((res) => {
  622. if (res.authSetting['scope.userLocation']) {
  623. data.userLocation = true
  624. }
  625. })
  626. .catch()
  627. // #endif
  628. methods.initWS()
  629. methods.getCityList()
  630. data.station.curCity = uni.getStorageSync(staticData.cctkn) || staticData.defCity
  631. methods.getListApp({ cras: args.cras, checkScope: true })
  632. await init()
  633. // 无未支付订单
  634. if (!data.hasnopayfordriver) {
  635. await methods.getQrcode()
  636. }
  637. data.firstUnload = false
  638. // 小程序环境:时机过早会inputDialog.value为null
  639. // h5环境:当页面data内的值改变时,弹框会消失
  640. // 所有先放这里吧
  641. methods.getInvite()
  642. }
  643. if (args.loadType === enums.LoadType.refresh) {
  644. methods.getListApp({ cras: args.cras })
  645. // if (!args.cras.isAdd) {
  646. // init()
  647. // }
  648. }
  649. if (args.loadType === enums.LoadType.onShow) {
  650. init()
  651. }
  652. },
  653. {
  654. addLoadTypes: [enums.LoadType.onShow],
  655. },
  656. )
  657. onPageScroll((res) => {
  658. staticData.scrollTop = res.scrollTop
  659. })
  660. </script>
  661. <style lang="scss" scoped>
  662. .center-item {
  663. min-height: 136rpx;
  664. }
  665. .top {
  666. padding-bottom: $p-spac;
  667. border-bottom: 1px dashed;
  668. .personal {
  669. width: 100rpx;
  670. height: 100rpx;
  671. margin-right: $p-spac;
  672. border-radius: $p-spac;
  673. }
  674. .mobile {
  675. margin-top: $p-spacd2;
  676. font-size: $s-fz;
  677. }
  678. }
  679. .qrcode {
  680. width: 400rpx;
  681. height: 400rpx;
  682. overflow: hidden;
  683. border-radius: $p-spacd2;
  684. .image {
  685. width: 480rpx;
  686. height: 480rpx;
  687. margin: -40rpx;
  688. }
  689. }
  690. .qrcode-text {
  691. height: $p-fz;
  692. }
  693. .truck {
  694. width: 152rpx;
  695. height: 116rpx;
  696. }
  697. #stationTop {
  698. padding: $p-spac 0;
  699. }
  700. .unit {
  701. margin: 0 $p-spacd2;
  702. }
  703. $bgc: rgba($p-color, 0.4);
  704. .cars {
  705. position: relative;
  706. overflow: hidden;
  707. &::after {
  708. position: absolute;
  709. top: 0;
  710. left: 0;
  711. width: 100%;
  712. height: 100%;
  713. content: '';
  714. background-image: linear-gradient($bgc, $bgc), url('@img/truck.svg');
  715. background-repeat: no-repeat;
  716. background-position: right;
  717. background-size: contain;
  718. opacity: 0.2;
  719. }
  720. }
  721. .menu {
  722. font-size: $s-fz;
  723. .icon {
  724. width: 80rpx;
  725. height: 80rpx;
  726. margin-bottom: $p-spacd2;
  727. border-radius: 50%;
  728. }
  729. }
  730. .list-app {
  731. margin-top: $p-spac;
  732. .title {
  733. font-size: $p-fz * 1.2;
  734. font-weight: bold;
  735. }
  736. }
  737. // 为了让左侧索引中文竖排
  738. ::v-deep .uni-indexed-list__menu-item {
  739. width: 20px;
  740. }
  741. ::v-deep .uni-popup__info {
  742. @apply: font-bold;
  743. font-size: $bs-fz;
  744. color: unset;
  745. }
  746. </style>