index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. <template>
  2. <ay-container>
  3. <div class="chunk">
  4. <div class="center justify-between top">
  5. <div class="center" @click="methods.goPerson">
  6. <image
  7. class="personal"
  8. v-if="store.user.userInfo.head_url"
  9. :src="store.user.userInfo.head_url"
  10. mode="scaleToFill"
  11. />
  12. <image
  13. class="personal"
  14. v-else
  15. src="@img/icons/turnk_number_head.png"
  16. mode="scaleToFill"
  17. />
  18. <!-- <uni-icons type="contact" size="50" class="personal"></uni-icons> -->
  19. <div>
  20. <div>{{ store.user.userInfo.user_name }}</div>
  21. <div class="mobile">{{ store.user.userInfo.mobile }}</div>
  22. </div>
  23. </div>
  24. <uni-icons
  25. type="scan"
  26. color=""
  27. class="p-color"
  28. size="40"
  29. @click="methods.scanCode"
  30. ></uni-icons>
  31. </div>
  32. <div class="center">
  33. <ay-flowLine class="mt-spac mb-spac">
  34. <div class="qrcode">
  35. <image
  36. src="@img/qr@3x.png"
  37. class="image"
  38. mode="aspectFit"
  39. v-if="data.qrcode.expire"
  40. @click="methods.getQrcode"
  41. />
  42. <image :src="data.qrcode.img" class="image" mode="aspectFit" v-else />
  43. </div>
  44. </ay-flowLine>
  45. </div>
  46. <div class="center">
  47. <template v-if="data.qrcode.expire">
  48. 二维码已失效
  49. <div class="center p-color" @click="methods.getQrcode">
  50. <uni-icons type="refresh" color="" size="24"></uni-icons>
  51. 刷新
  52. </div>
  53. </template>
  54. <template v-else>有效时间:{{ data.qrcode.countdown }}</template>
  55. </div>
  56. </div>
  57. <div class="flex">
  58. <div class="chunk flex-1 s-fz mr-spac account" @click="methods.goAccount">
  59. <div class="mb-spacd4">可用余额</div>
  60. <div class="">
  61. <span class="font-bold b-fz">{{ data.accountInfo.showBalance.balance }}</span>
  62. <span class="font-bold">{{ data.accountInfo.showBalance.suffix }}</span>
  63. <span class="unit">{{ data.accountInfo.unit }}</span>
  64. </div>
  65. </div>
  66. <div class="chunk flex-1 center justify-start s-fz cars" @click="">
  67. <div class="p-color" v-if="false">添加车辆</div>
  68. <div v-else>
  69. <div class="mb-spacd4">车辆管理</div>
  70. <div>
  71. <span class="font-bold b-fz">1</span>
  72. </div>
  73. </div>
  74. </div>
  75. </div>
  76. <div class="center justify-around mt-spac">
  77. <div
  78. class="text-center menu"
  79. v-for="(m, i) in data.menus"
  80. :key="i"
  81. @click="methods.goPage(m)"
  82. >
  83. <img class="icon" :src="m.icon" />
  84. <div>{{ m.name }}</div>
  85. </div>
  86. </div>
  87. <div class="chuck list-app">
  88. <div class="center justify-between mb-spac">
  89. <div class="title">附近加气站</div>
  90. <div v-if="data.userLocation" @click="methods.drawerOpen">
  91. {{ data.station.curCity }}
  92. <uni-icons type="down" size="12" />
  93. </div>
  94. </div>
  95. <template v-if="data.userLocation">
  96. <ayb-station
  97. v-for="(la, i) in data.station.listApp"
  98. :key="i"
  99. :stationInfo="la"
  100. ></ayb-station>
  101. </template>
  102. <div class="center p-color" v-else @click="methods.getListApp({ first: true })">
  103. 查看附近加气站
  104. </div>
  105. </div>
  106. <uni-drawer ref="drawer" mode="right" :maskClick="true" :width="320">
  107. <uni-indexed-list
  108. :options="data.station.cityList"
  109. :show-select="false"
  110. @click="methods.bindClick"
  111. v-if="data.station.showIndexedList"
  112. />
  113. </uni-drawer>
  114. </ay-container>
  115. </template>
  116. <script lang="ts" setup>
  117. import stompSocket from '@/utils/api/socket/stomp'
  118. import perpay from '@img/icons/perpay.png'
  119. import payhistory from '@img/icons/payhistory.png'
  120. import firm from '@img/icons/firm.png'
  121. import card from '@img/icons/card.png'
  122. const drawer = ref()
  123. const staticData = {
  124. client: null,
  125. entranceArgs: null as AyContainerEntryArgs,
  126. location: { longitude: '', latitude: '' } as any,
  127. }
  128. const data = reactive({
  129. accountInfo: { showBalance: { balance: '', suffix: '' } } as IAccountInfo,
  130. /** 用户已授权定位 */
  131. userLocation: false,
  132. /** 二维码相关 */
  133. qrcode: {
  134. /** 二维码过期倒计时 */
  135. countdown: '',
  136. /** 二维码 */
  137. img: null,
  138. /** 已过期 */
  139. expire: false,
  140. },
  141. /** 菜单列表 */
  142. menus: [
  143. {
  144. id: 0,
  145. icon: perpay,
  146. name: '待支付订单',
  147. },
  148. {
  149. id: 1,
  150. name: '加气订单',
  151. icon: payhistory,
  152. },
  153. {
  154. id: 2,
  155. name: '所属物流',
  156. icon: firm,
  157. },
  158. {
  159. id: 3,
  160. name: '优惠卡/券',
  161. icon: card,
  162. },
  163. ],
  164. station: {
  165. /** 首次呈现,解决索引滑动失效问题 */
  166. showIndexedList: false,
  167. cityList: [] /** 附近加气站列表 */,
  168. curCity: '全部',
  169. listApp: [],
  170. },
  171. })
  172. const methods = ay.initMethods(
  173. {
  174. goPerson() {
  175. ay.goPage(config.pages.personCenter_index)
  176. },
  177. goPage(menu) {
  178. const maps = {
  179. 0() {
  180. methods.goPrePay()
  181. },
  182. 1() {
  183. ay.goPage(config.pages.orderList_index)
  184. },
  185. }
  186. maps[menu.id]()
  187. },
  188. drawerOpen() {
  189. drawer.value.open()
  190. data.station.showIndexedList = true
  191. },
  192. bindClick(args) {
  193. drawer.value.close()
  194. data.station.curCity = args.item.name
  195. methods.getListApp()
  196. },
  197. goAccount() {
  198. ay.goPage(config.pages.account_index)
  199. },
  200. /** 初始化ws */
  201. initWS() {
  202. stompSocket
  203. .init(
  204. 'wss://dwx.auyen.com/websocket/sockjs',
  205. // 传参
  206. {
  207. access_token: store.user.userInfo.token,
  208. identifier: store.user.userInfo.Identifier,
  209. },
  210. // ws断开回调
  211. () => {
  212. methods.initWS()
  213. },
  214. )
  215. .then((client) => {
  216. staticData.client = client
  217. // 订阅
  218. const subscription = client.subscribe(
  219. // 路径
  220. '/user/' + store.user.userInfo.user_id + '/msg',
  221. // 接收到的数据
  222. (res) => {
  223. const body = JSON.parse(res.body)
  224. if (body.type === 1) {
  225. ay.goPage(config.pages.prePay_index, { params: JSON.parse(body.content) })
  226. } else if (body.type === 0) {
  227. const content = JSON.parse(body.content)
  228. uni
  229. .showModal({
  230. title: content.data,
  231. message: content.message,
  232. })
  233. .then(() => {})
  234. }
  235. },
  236. )
  237. })
  238. },
  239. // 直接调用发送即可
  240. send() {
  241. staticData.client.send(
  242. // 路径
  243. '/user/' + store.user.userInfo.user_id + '/msg',
  244. {},
  245. // 发送文本
  246. JSON.stringify({ content: '1212' }),
  247. )
  248. },
  249. async goPrePay() {
  250. const nopayfordriver = await webapi.pay.find_unpayfordriver()
  251. if (nopayfordriver) {
  252. // 跳未支付
  253. ay.goPage(config.pages.prePay_index, { params: { orderId: nopayfordriver.orderId } })
  254. return true
  255. } else {
  256. func.native.showToast('暂无待支付订单!')
  257. return false
  258. }
  259. },
  260. async scanCode() {
  261. if (await methods.goPrePay()) {
  262. return
  263. }
  264. const reqStr = await uni
  265. .scanCode({
  266. scanType: ['qrcode'],
  267. })
  268. .catch((err) => {
  269. func.native.showToast('二维码无效')
  270. return Promise.reject(err)
  271. })
  272. let ret = { gasstationId: '', cashierId: '' }
  273. try {
  274. ret = JSON.parse(reqStr.result)
  275. } catch {
  276. func.native.showToast('二维码无效')
  277. return
  278. }
  279. // const ret = {
  280. // cashierId: '710613333157822464',
  281. // gasstationId: '710613333157822464',
  282. // }
  283. const user = await webapi.user.find_6({ userId: ret.cashierId })
  284. if (ret.gasstationId === user.user.orgId) {
  285. const price = await webapi.strategy.find_price({
  286. gasstationId: ret.gasstationId,
  287. driverId: user.user.userId,
  288. })
  289. if (
  290. ((price.qrcode === 0 || price.qrcode === 1) && ret.gasstationId !== ret.cashierId) || // 设置的加气站收款码
  291. (price.qrcode === 2 && ret.gasstationId === ret.cashierId) // 设置的收银员
  292. ) {
  293. func.native.showModal({
  294. title: '错误提示',
  295. content: '加气站收款码已禁用,请选择收银员收款码扫码。',
  296. })
  297. } else {
  298. const gasJudge = await webapi.strategy.driver_gas_judge({
  299. driverId: user.user.userId,
  300. gasstationId: ret.gasstationId,
  301. })
  302. if (gasJudge === 1) {
  303. // 创建订单
  304. ay.goPage(config.pages.createOrder_index, { params: ret })
  305. } else if (gasJudge === 2) {
  306. func.native.showModal({
  307. title: '错误提示',
  308. content:
  309. '该加气站未及时补充平台气源,已无法通过大象平台为您提供优质气源,给您带来的不便深感其歉意,如有疑问可以与加气站沟通,亦可拨打大象加气平台客服电话:"400-0165388"',
  310. })
  311. }
  312. }
  313. } else {
  314. func.native.showModal({
  315. title: '错误提示',
  316. content: '当前收银员所属企业和二维码对应的企业不一致,请联系加气站管理员。',
  317. })
  318. }
  319. },
  320. sdfsdf() {
  321. webapi.strategy.get_truck_info().then((res) => {})
  322. },
  323. getCityList() {
  324. webapi.strategy.city_list().then((res) => {
  325. res.unshift({ text: '全部', children: [{ text: '全部' }] })
  326. data.station.cityList = res.map((m) => {
  327. return {
  328. letter: m.text,
  329. data: m.children.map((cm) => cm.text),
  330. }
  331. })
  332. })
  333. },
  334. async getListApp({ cras = config.common.defAyContainerRefreshArgs, first = false } = {}) {
  335. // 非首次 && 未授权
  336. if (!first && !data.userLocation) {
  337. // 取消加载中效果
  338. ay.containerLoaded({
  339. reqState: enums.ReqState.cancel,
  340. })
  341. return
  342. }
  343. let location = staticData.location
  344. // 上拉不重新获取位置
  345. if (!cras.isAdd) {
  346. location = await uni.getLocation()
  347. staticData.location = location
  348. }
  349. data.userLocation = true
  350. webapi.strategy
  351. .list_mini(
  352. {
  353. page: cras.page,
  354. size: cras.size,
  355. param: {
  356. city: data.station.curCity === '全部' ? '' : data.station.curCity,
  357. longitude: location.longitude.toString(),
  358. latitude: location.latitude.toString(),
  359. },
  360. },
  361. { showLoading: first || !cras.isAdd },
  362. )
  363. .then((res) => {
  364. if (cras.isAdd) {
  365. data.station.listApp.push(...res.records)
  366. } else {
  367. data.station.listApp = res.records
  368. }
  369. })
  370. },
  371. /** 时长处理 */
  372. duration(times) {
  373. if (times) {
  374. let m: number | string = Math.floor(Number(times) / 60)
  375. let s: number | string = Math.floor(Number(times) % 60)
  376. if (s < 10) {
  377. s = `0${s}`
  378. }
  379. if (m < 10) {
  380. m = `0${m}`
  381. }
  382. return `${m}:${s}`
  383. }
  384. },
  385. getQrcode() {
  386. return webapi.strategy.get_user_qrcode().then(async (res) => {
  387. // await func.awaiter()
  388. data.qrcode.img = res
  389. data.qrcode.expire = false
  390. func.timer({
  391. seconds: 300,
  392. ticker(tick) {
  393. data.qrcode.countdown = methods.duration(tick)
  394. },
  395. ender() {
  396. data.qrcode.expire = true
  397. },
  398. })
  399. })
  400. },
  401. },
  402. {
  403. scanCode: { showLoading: true },
  404. },
  405. )
  406. ay.entrance(
  407. (args) => {
  408. staticData.entranceArgs = args
  409. // webapi.strategy.getCarNumber<null, { truckId: string }>().then((res) => {
  410. // webapi.strategy.getQrcode({}, { appendUrl: '/' + res.truckId }).then((resq) => {
  411. // data.qrcode = resq
  412. // })
  413. // })
  414. const init = async () => {
  415. // #ifdef MP
  416. await uni
  417. .getSetting()
  418. .then((res) => {
  419. if (res.authSetting['scope.userLocation']) {
  420. data.userLocation = true
  421. }
  422. })
  423. .catch()
  424. // #endif
  425. methods.getListApp({ cras: args.cras })
  426. webapi.strategy.get_driver_balance().then((res) => {
  427. data.accountInfo = {
  428. ...res,
  429. ...aop.request.AR.getAccountInfo(res),
  430. }
  431. })
  432. }
  433. if (args.loadType === enums.LoadType.onLoad) {
  434. methods.initWS()
  435. methods.getQrcode()
  436. methods.getCityList()
  437. init()
  438. }
  439. if (args.loadType === enums.LoadType.refresh) {
  440. if (args.cras.isAdd) {
  441. methods.getListApp({ cras: args.cras })
  442. } else {
  443. init()
  444. }
  445. }
  446. },
  447. {
  448. // addLoadTypes: [enums.LoadType.onLoad],
  449. },
  450. )
  451. </script>
  452. <style lang="scss">
  453. .top {
  454. padding-bottom: $p-spac;
  455. border-bottom: 1px dashed;
  456. .personal {
  457. width: 100rpx;
  458. height: 100rpx;
  459. margin-right: $p-spac;
  460. border-radius: $p-spac;
  461. }
  462. .mobile {
  463. margin-top: $p-spacd2;
  464. font-size: $s-fz;
  465. }
  466. }
  467. .qrcode {
  468. width: 400rpx;
  469. height: 400rpx;
  470. overflow: hidden;
  471. border-radius: $p-spacd2;
  472. .image {
  473. width: 480rpx;
  474. height: 480rpx;
  475. margin: -40rpx;
  476. }
  477. }
  478. .truck {
  479. width: 152rpx;
  480. height: 116rpx;
  481. }
  482. .unit {
  483. margin: 0 $p-spacd2;
  484. }
  485. $bgc: rgba($p-color, 0.4);
  486. .account {
  487. background-color: rgba($p-price-color, 0.1);
  488. }
  489. .cars {
  490. position: relative;
  491. overflow: hidden;
  492. &::after {
  493. position: absolute;
  494. top: 0;
  495. left: 0;
  496. width: 100%;
  497. height: 100%;
  498. content: '';
  499. background-image: linear-gradient($bgc, $bgc), url('@img/truck.svg');
  500. background-repeat: no-repeat;
  501. background-position: right;
  502. background-size: contain;
  503. opacity: 0.2;
  504. }
  505. }
  506. .menu {
  507. font-size: $s-fz;
  508. .icon {
  509. width: 80rpx;
  510. height: 80rpx;
  511. margin-bottom: $p-spacd2;
  512. border-radius: 50%;
  513. }
  514. }
  515. .list-app {
  516. margin-top: $p-spac * 2;
  517. .title {
  518. font-size: $p-fz * 1.2;
  519. font-weight: bold;
  520. }
  521. }
  522. // 为了让左侧索引中文竖排
  523. ::v-deep .uni-indexed-list__menu-item {
  524. width: 20px;
  525. }
  526. </style>