elevatorControl.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <template>
  2. <view>
  3. <view class="have-reservation" v-if="showCheckinInfo">
  4. <view class="info">
  5. <view class="title">
  6. <view class="hotel-name">
  7. <!-- <u-text :text="hotelStore.hotel.name" bold color="#333333" size="30rpx"></u-text> -->
  8. <text>{{hotelStore.hotel.name}}</text>
  9. </view>
  10. <view class="tips">
  11. <!-- <u-text text="入住信息" color="#666666" size="24rpx"></u-text> -->
  12. <text>入住信息</text>
  13. </view>
  14. </view>
  15. <view class="checkin-info">
  16. <view class="checkin-info--item">
  17. <view class="checkin-info--item--text">
  18. <!-- <u-text text="所在楼层: " color="#999999" size="26rpx"></u-text> -->
  19. <text>所在楼层:</text>
  20. </view>
  21. <view class="checkin-info--item--text">
  22. <!-- <u-text :text="checkinInfo.floor + '楼'" color="#999999" size="26rpx"></u-text> -->
  23. <text>{{`${checkinInfo.floor}楼`}}</text>
  24. </view>
  25. </view>
  26. <view class="checkin-info--item">
  27. <view class="checkin-info--item--text">
  28. <!-- <u-text text="房间信息 : " color="#999999" size="26rpx"></u-text> -->
  29. <text>房间信息:</text>
  30. </view>
  31. <view class="checkin-info--item--text">
  32. <!-- <u-text :text="checkinInfo.room" color="#999999" size="26rpx"></u-text> -->
  33. <text>{{checkinInfo.room}}</text>
  34. </view>
  35. </view>
  36. <view class="checkin-info--item">
  37. <view class="checkin-info--item--text">
  38. <!-- <u-text text="起始时间 : " color="#999999" size="26rpx"></u-text> -->
  39. <text>起始时间:</text>
  40. </view>
  41. <view class="checkin-info--item--text">
  42. <!-- <u-text :text="formatDateTime(checkinInfo.startTime)" color="#999999" size="26rpx"></u-text> -->
  43. <text>{{formatDateTime(checkinInfo.startTime)}}</text>
  44. </view>
  45. </view>
  46. <view class="checkin-info--item">
  47. <view class="checkin-info--item--text">
  48. <!-- <u-text text="结束时间 : " color="#999999" size="26rpx"></u-text> -->
  49. <text>结束时间:</text>
  50. </view>
  51. <view class="checkin-info--item--text">
  52. <!-- <u-text :text="formatDateTime(checkinInfo.endTime)" color="#999999" size="26rpx"></u-text> -->
  53. <text>{{formatDateTime(checkinInfo.endTime)}}</text>
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. <view class="qrcode" :style="{width: qrCodeWidth, height: qrCodeWidth, display: showQrCode ? '' : 'none'}">
  59. <img style="width: 100%; height: 100%;" :src="qrCodeDataUrl" />
  60. </view>
  61. <view class="prompt" :style="{width: diaplayWidth}">
  62. <view class="prompt--text" v-if="showPrompt">
  63. <text>
  64. 请将梯控二维码正对扫描框进行梯控识别
  65. </text>
  66. <text style="margin-top: 10rpx;">
  67. {{ `该二维码将在${waitTime}分钟后失效` }}
  68. </text>
  69. </view>
  70. <view v-if="!showPrompt">
  71. <button class="prompt--count-down__button" @click="rerenderQrCode">二维码失效,点击重新生成二维码</button>
  72. </view>
  73. </view>
  74. <view class="mobile-elevator">
  75. <button :loading="buttonLoading" @click="mobileElevator">
  76. 手机乘梯
  77. </button>
  78. </view>
  79. </view>
  80. <view v-else class="not-checkin">
  81. <view class="not-checkin-text">
  82. <text>您还未入住!</text>
  83. </view>
  84. <view class="not-checkin-text">
  85. <text>若已退房或房间到期,请至前台办理</text>
  86. </view>
  87. </view>
  88. </view>
  89. </template>
  90. <script setup>
  91. import {
  92. ref,
  93. computed
  94. } from "vue";
  95. import {
  96. getCheckinInfo,
  97. getElevatorQRCode,
  98. moveElevator
  99. } from "../../utils/api"
  100. import {
  101. useHotelStore
  102. } from '@/store/hotelStore.js'
  103. import {
  104. onLoad
  105. } from '@dcloudio/uni-app'
  106. import moment from "moment";
  107. import {
  108. useUserStore
  109. } from "../../store/userStore";
  110. import {
  111. IMG_BASE_URL
  112. } from "../../config";
  113. import {
  114. QRCodeSVG
  115. } from "../../utils/qrCode/qrcode.mjs"
  116. const hotelStore = useHotelStore()
  117. const userStore = useUserStore()
  118. const showCheckinInfo = ref(false)
  119. const checkinInfo = ref(null)
  120. const diaplayWidth = ref("")
  121. const qrCodeWidth = ref("")
  122. const qrCodeData = ref("")
  123. const qrCode = ref("")
  124. const showQrCode = ref(false)
  125. const waitTime = ref(10)
  126. const showPrompt = ref(false)
  127. const logoBase64 = ref("")
  128. const buttonLoading = ref(false)
  129. const timeCountDown = () => {
  130. const intervalId = setInterval(() => {
  131. waitTime.value--
  132. if (waitTime.value === 0) {
  133. showPrompt.value = false
  134. showQrCode.value = false
  135. clearInterval(intervalId)
  136. }
  137. }, 60000)
  138. }
  139. const qrCodeDataUrl = computed(() => {
  140. if (qrCodeData.value !== "" && logoBase64.value !== "") {
  141. const qrSvg = new QRCodeSVG(
  142. qrCodeData.value, {
  143. level: "H",
  144. image: {
  145. source: logoBase64.value,
  146. width: '25%',
  147. height: '25%',
  148. x: 'center',
  149. y: 'center',
  150. border: 1
  151. }
  152. }
  153. )
  154. qrCode.value = qrSvg.toString()
  155. const encoded = encodeURIComponent(qrCode.value)
  156. .replace(/'/g, '%27')
  157. .replace(/"/g, '%22')
  158. const header = 'data:image/svg+xml,'
  159. const dataUrl = header + encoded
  160. showQrCode.value = true
  161. showPrompt.value = true
  162. timeCountDown()
  163. return dataUrl
  164. }
  165. })
  166. const rerenderQrCode = async () => {
  167. const qrCodeMsg = await getElevatorQRCode({
  168. hotelId: hotelStore.hotel.hotelId,
  169. building: 1,
  170. floor: checkinInfo.value.floor,
  171. customerId: userStore.userInfo.idNumber,
  172. customerType: 1,
  173. status: 1,
  174. activeTime: moment().add(10, "m")
  175. })
  176. console.log("获取梯控二维码信息", qrCodeMsg);
  177. if (!qrCodeMsg.data || !qrCodeMsg.success) {
  178. return
  179. }
  180. qrCodeData.value = qrCodeMsg.data.data
  181. const qrSvg = new QRCodeSVG(
  182. qrCodeData.value, {
  183. level: "H",
  184. image: {
  185. source: logoBase64.value,
  186. width: '25%',
  187. height: '25%',
  188. x: 'center',
  189. y: 'center',
  190. border: 1
  191. }
  192. }
  193. )
  194. qrCode.value = qrSvg.toString()
  195. showQrCode.value = true
  196. showPrompt.value = true
  197. waitTime.value = 10
  198. timeCountDown()
  199. }
  200. const mobileElevator = async () => {
  201. const scan = await uni.scanCode({
  202. scanType: ['qrCode']
  203. })
  204. // console.log("二维码扫描结果", scan);
  205. const deviceSn = scan.result
  206. buttonLoading.value = true
  207. uni.showLoading({
  208. title: '联系电梯中...',
  209. mask: true
  210. })
  211. // const eleRes = await moveElevator(deviceSn, checkinInfo.floor)
  212. const eleRes = await moveElevator(deviceSn, 7)
  213. console.log("乘梯结果", eleRes);
  214. if (!eleRes.data || !eleRes.success) {
  215. uni.hideLoading()
  216. buttonLoading.value = false
  217. uni.showModal({
  218. content: '操控电梯失败,请稍后重试。',
  219. showCancel: true,
  220. })
  221. return
  222. }
  223. uni.hideLoading()
  224. buttonLoading.value = false
  225. uni.showModal({
  226. content: '操控电梯成功。',
  227. showCancel: true,
  228. })
  229. }
  230. onLoad(async (options) => {
  231. console.log("onLoad", options);
  232. try {
  233. const infoRes = await getCheckinInfo(hotelStore.hotel.hotelId)
  234. // console.log("获取入住记录结果", infoRes);
  235. if (!infoRes.data || !infoRes.success) {
  236. return
  237. }
  238. checkinInfo.value = infoRes.data
  239. showCheckinInfo.value = true
  240. const systemIfo = await uni.getSystemInfo()
  241. console.log("系统信息:", systemIfo);
  242. diaplayWidth.value = (systemIfo.screenWidth - 40).toFixed() + "px"
  243. qrCodeWidth.value = (systemIfo.screenWidth * 3 / 5).toFixed() + "px"
  244. } catch (err) {
  245. console.log("获取入住记录异常", err);
  246. return
  247. }
  248. try {
  249. const qrCodeMsg = await getElevatorQRCode({
  250. hotelId: hotelStore.hotel.hotelId,
  251. building: 1,
  252. floor: checkinInfo.value.floor,
  253. customerId: userStore.userInfo.idNumber,
  254. customerType: 1,
  255. status: 1,
  256. activeTime: moment().add(10, "m")
  257. })
  258. console.log("获取梯控二维码信息", qrCodeMsg);
  259. if (!qrCodeMsg.data || !qrCodeMsg.success) {
  260. return
  261. }
  262. qrCodeData.value = qrCodeMsg.data.data
  263. } catch (err) {
  264. console.log("获取梯控二维码信息异常", err);
  265. return
  266. }
  267. const pic = await uni.request({
  268. url: `${IMG_BASE_URL}/yun_xiang_zhu_square.png`,
  269. responseType: 'arraybuffer',
  270. })
  271. // console.log("云享住logo", pic.data);
  272. logoBase64.value = "data:image/png;base64," + uni.arrayBufferToBase64(pic.data);
  273. // console.log("字符串",uni.arrayBufferToBase64(pic.data));
  274. })
  275. const formatDateTime = (dateTime) => {
  276. return moment(dateTime).format("YYYY年MM月DD日HH时mm分")
  277. }
  278. </script>
  279. <style lang="scss">
  280. .have-reservation {
  281. .info {
  282. background: #F5F8FE;
  283. box-shadow: -6px 17px 21px 0px rgba(112, 152, 246, 0.14);
  284. margin-bottom: 80rpx;
  285. .title {
  286. display: flex;
  287. justify-content: space-between;
  288. padding: 0 40rpx;
  289. line-height: 80rpx;
  290. border-bottom: 2rpx solid #E0E8FB;
  291. }
  292. .checkin-info {
  293. margin: 20rpx auto;
  294. .checkin-info--item {
  295. display: flex;
  296. margin: 0 40rpx;
  297. .checkin-info--item--text {
  298. margin: 10rpx;
  299. margin-left: 0;
  300. }
  301. &:last-child {
  302. padding-bottom: 20rpx;
  303. }
  304. }
  305. }
  306. }
  307. .qrcode {
  308. display: flex;
  309. margin: 10rpx auto;
  310. padding: 10rpx 20rpx;
  311. background: #ffffff;
  312. border-radius: 10rpx;
  313. }
  314. .prompt {
  315. margin: 0 auto;
  316. display: flex;
  317. flex-direction: column;
  318. justify-content: center;
  319. align-items: center;
  320. .prompt--text {
  321. background-color: #fff;
  322. display: flex;
  323. flex-direction: column;
  324. justify-content: center;
  325. align-items: center;
  326. margin: 0 20rpx;
  327. padding: 10rpx 20rpx;
  328. border-radius: 10rpx;
  329. }
  330. .prompt--count-down__button {
  331. display: flex;
  332. align-items: center;
  333. justify-content: center;
  334. padding: 40rpx;
  335. }
  336. }
  337. .mobile-elevator {
  338. display: flex;
  339. flex-direction: column;
  340. justify-content: center;
  341. align-items: center;
  342. margin: 0 20rpx;
  343. padding: 10rpx 20rpx;
  344. border-radius: 10rpx;
  345. }
  346. }
  347. .not-checkin {
  348. margin-top: 40vh;
  349. .not-checkin-text {
  350. display: flex;
  351. justify-content: center;
  352. }
  353. }
  354. </style>