alipayCheckPic.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <template>
  2. <view>
  3. <view class="top">
  4. <NavigateBar title="身份核验" bgcolor="#a09cc4"></NavigateBar>
  5. </view>
  6. <view class="face-area">
  7. <view class="face-area--tips">
  8. <view class="face-area--tips--title">
  9. <u-text text="身份核验" color="#333333" bold size="34rpx"></u-text>
  10. </view>
  11. <view class="face-area--tips--context">
  12. <u-text text="请根据页面提示进行操作" color="#CBCBCB" size="28rpx"></u-text>
  13. </view>
  14. </view>
  15. <view class="face-area--line"></view>
  16. <view class="camera-container">
  17. <camera id="check-pic--cam__cam" flash="off" device-position="front" @ready="cameraContext"
  18. :style="[cameraStyle]"/>
  19. <cover-image src="../../static/cover.png" :style="[coverImageStyle]"></cover-image>
  20. </view>
  21. <view v-if="!showTips" class="check-pic-result">
  22. {{ result }}
  23. </view>
  24. </view>
  25. <view class="precautions">
  26. <view class="precautions--tips">
  27. <view class="precautions--tips--title">
  28. <u-text text="注意事项" color="#333333" bold size="34rpx"></u-text>
  29. </view>
  30. <view class="precautions--tips--context">
  31. <u-text text="请遵守需注意事项" color="#CBCBCB" size="28rpx"></u-text>
  32. </view>
  33. </view>
  34. <view class="precautions--line"></view>
  35. <view class="precautions--context">
  36. <u-text :text="'确认'+name+'本人操作;保持正脸在取景框中根据屏幕指示完成'" color="#666666" size="24rpx"></u-text>
  37. </view>
  38. <view class="img-list">
  39. <view class="img-list--item" v-for="img in imgList">
  40. <view class="img">
  41. <u-image :src="img.src" :height="img.height" :width="img.width"></u-image>
  42. </view>
  43. <view class="tips">
  44. <u-text :text="img.tips" color="#666666" size="20rpx"></u-text>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. <view class="btn">
  50. <u-button text="同意并开始验证" @click="takePhoto" :disabled="isCheckingFace" color="#9e97c3"></u-button>
  51. </view>
  52. </view>
  53. </template>
  54. <script>
  55. import {
  56. mapState,
  57. mapMutations
  58. } from "vuex";
  59. import NavigateBar from "../../components/navigateBar/navigate-bar.vue";
  60. export default {
  61. components: {
  62. NavigateBar
  63. },
  64. data() {
  65. return {
  66. name: '',
  67. idNumber: '',
  68. camContext: null,
  69. result: "身份核验中....",
  70. photoBase64: null,
  71. fs: null,
  72. checkFaceRes: false,
  73. showTips: true,
  74. isCheckingFace: false,
  75. imgList: [{
  76. src: '/static/check-face-phone.png',
  77. width: '48rpx',
  78. height: '70rpx',
  79. tips: '正对手机'
  80. },
  81. {
  82. src: '/static/check-face-light.png',
  83. width: '78rpx',
  84. height: '70rpx',
  85. tips: '光线充足'
  86. },
  87. {
  88. src: '/static/check-face-face.png',
  89. width: '80rpx',
  90. height: '80rpx',
  91. tips: '脸部无遮挡'
  92. }
  93. ],
  94. faceAreaTipsHeight: 0,
  95. faceAreaLineHeight: 0,
  96. menuButtonTop: 0,
  97. menuButtonHeight: 0,
  98. menuButtonBottom: 0,
  99. width: 0,
  100. phone: ""
  101. }
  102. },
  103. computed: {
  104. ...mapState('m_user', ['userInfo']),
  105. ...mapState('m_business', ['currentHotel', 'checkinInfo']),
  106. cameraStyle() {
  107. let style = {}
  108. // 设置相机显示区域左右边框距屏幕左右边框为20px
  109. let camWidth = this.width === 0 ? 0 : this.width - 20 * 2
  110. style.width = camWidth + 'px'
  111. style.height = camWidth + 'px'
  112. return style
  113. },
  114. coverImageStyle() {
  115. let style = {}
  116. // 设置相机遮罩图片的左右边框距屏幕左右边框为16px
  117. let imgWidth = this.width === 0 ? 0 : this.width - 16 * 2
  118. style.width = imgWidth + 'px'
  119. style.height = imgWidth + 'px'
  120. style.left = "16px"
  121. let top = 0
  122. if (this.faceAreaTipsHeight && this.faceAreaLineHeight && this.menuButtonTop
  123. && this.menuButtonHeight && this.menuButtonBottom
  124. ) {
  125. top = this.faceAreaTipsHeight + this.faceAreaLineHeight + this.menuButtonTop
  126. + this.menuButtonHeight + this.menuButtonBottom + 2
  127. // console.log("顶部距离", top);
  128. }
  129. // console.log("computed");
  130. style.top = top + "px"
  131. return style
  132. }
  133. },
  134. methods: {
  135. ...mapMutations('m_business', ['updateCheckinInfo']),
  136. async cameraContext() {
  137. this.camContext = my.createCameraContext('check-pic--cam__cam');
  138. },
  139. async takePhoto() {
  140. const userSetting = await uni.getSetting()
  141. // console.log("userSetting", userSetting);
  142. let camAuth = userSetting[1].authSetting['camera'] ? userSetting[1].authSetting['camera'] : false
  143. while (!camAuth) {
  144. await new Promise(async (resolve, reject) => {
  145. await uni.showModal({
  146. title: "温馨提示",
  147. content: "身份核验功能需要使用您的相机,请授权后重新点击核验。",
  148. success: async (res) => {
  149. if (res.confirm) {
  150. await uni.openSetting().then(res => {
  151. console.log("openSetting", res);
  152. camAuth = res[1].authSetting['camera'] ? res[1]
  153. .authSetting['camera'] : false
  154. resolve()
  155. })
  156. }
  157. }
  158. })
  159. })
  160. setTimeout(() => {}, 200)
  161. }
  162. // console.log("进行了相机授权操作");
  163. this.result = "身份核验中...."
  164. this.showTips = false
  165. this.isCheckingFace = true
  166. // console.log("this.camContext",this.camContext);
  167. while (!this.checkFaceRes) {
  168. // console.log("开始takePhoto进行人脸检测");
  169. let photo = await this.camContext.takePhoto({
  170. quality: 'normal',
  171. })
  172. // console.log("完成takePhoto", this.photo.tempImagePath);
  173. this.photoBase64 = await this.fs.readFile({
  174. filePath: photo.tempImagePath,
  175. encoding: "base64"
  176. })
  177. // console.log("photoBase64", photoBase64);
  178. let checkPicRes = await uni.$http.post("/faceVerification/checkPic", {
  179. hotelId: this.currentHotel.hotelId,
  180. faceData: this.photoBase64.data,
  181. })
  182. // console.log("checkPicRes", checkPicRes);
  183. if (!checkPicRes.data.success) {
  184. // console.log("checkPicRes.data", checkPicRes.data.msg.split("原因:")[1]);
  185. this.result = checkPicRes.data.msg.split("原因:")[1] + "请将面部完整放入拍摄区域。"
  186. } else {
  187. this.checkFaceRes = checkPicRes.data.success
  188. }
  189. setTimeout(() => {}, 100)
  190. }
  191. // 进行云极人证比对
  192. await this.afterSuccessCheckPic()
  193. },
  194. async afterSuccessCheckPic() {
  195. if (this.userInfo.skipIdMatching === true) {
  196. this.result = "身份核验成功,将跳转确认订单页面"
  197. let guestInfo={
  198. name:this.name,
  199. idNumber:this.idNumber,
  200. faceData: this.photoBase64.data,
  201. phone: this.phone,
  202. }
  203. this.checkinInfo.push(guestInfo)
  204. this.updateCheckinInfo(this.checkinInfo)
  205. setTimeout(() => {
  206. uni.reLaunch({
  207. url: '/subpkg_checkin/confirmOrder/confirmOrder'
  208. })
  209. }, 500)
  210. } else {
  211. let yunjiFaceCheckInfo = {
  212. idNo: this.idNumber,
  213. name: this.name,
  214. image: this.photoBase64.data,
  215. }
  216. uni.showLoading({
  217. title: "正在身份核验,请稍后",
  218. });
  219. let res = await uni.$http.post(
  220. "/faceVerification/yunjiVerification",
  221. yunjiFaceCheckInfo
  222. );
  223. if (res.data.success === true) {
  224. uni.hideLoading();
  225. this.result = "身份核验成功,将跳转确认订单页面"
  226. this.checkinInfo.push({
  227. name:this.name,
  228. idNumber:this.idNumber,
  229. faceData: this.photoBase64.data,
  230. phone: this.phone,
  231. })
  232. this.updateCheckinInfo(this.checkinInfo)
  233. setTimeout(() => {
  234. this.isCheckingFace = false
  235. uni.reLaunch({
  236. url: '/subpkg_checkin/confirmOrder/confirmOrder'
  237. })
  238. }, 500)
  239. } else {
  240. uni.hideLoading();
  241. this.isCheckingFace = false
  242. this.result = "身份核验失败,请重新进行"
  243. }
  244. }
  245. }
  246. },
  247. async onLoad(options) {
  248. this.name=options.name
  249. this.idNumber=options.idNumber
  250. this.phone = options.phone
  251. this.fs = my.getFileSystemManager();
  252. let alipaySystemInfo = await uni.getSystemInfo()
  253. this.width = alipaySystemInfo[1].screen.width
  254. const menuButton = uni.getMenuButtonBoundingClientRect()
  255. this.menuButtonTop = menuButton.top
  256. this.menuButtonHeight = menuButton.height
  257. this.menuButtonBottom = 8
  258. },
  259. onShow() {
  260. this.result = "身份核验中...."
  261. this.showTips = true
  262. this.isCheckingFace = false
  263. },
  264. async beforeMount() {
  265. let faceAreaTipsSize = await uni.$u.getRect('.face-area--tips')
  266. // console.log("faceAreaTipsSize", faceAreaTipsSize);
  267. this.faceAreaTipsHeight = faceAreaTipsSize.height
  268. let faceAreaLineSize = await uni.$u.getRect('.face-area--line')
  269. this.faceAreaLineHeight = faceAreaLineSize.height
  270. // console.log("faceAreaLineSize", faceAreaLineSize);
  271. }
  272. }
  273. </script>
  274. <style lang="scss">
  275. page {
  276. background-color: #EFEFF4;
  277. .top {
  278. position: sticky;
  279. background-color: #fff;
  280. width: 100%;
  281. top: 0;
  282. z-index: 999;
  283. }
  284. .face-area {
  285. display: flex;
  286. flex-direction: column;
  287. background-color: #FFFFFF;
  288. border-radius: 50rpx;
  289. overflow: hidden;
  290. .face-area--tips {
  291. display: flex;
  292. padding: 10rpx 20rpx;
  293. height: 60rpx;
  294. align-items: flex-end;
  295. .face-area--tips--title {
  296. margin: 10rpx;
  297. }
  298. .face-area--tips--context {
  299. margin: 10rpx;
  300. }
  301. }
  302. .face-area--line {
  303. margin-left: 40rpx;
  304. width: 30rpx;
  305. height: 6rpx;
  306. margin-bottom: 4rpx;
  307. background-color: #9e97c3;
  308. }
  309. .camera-container {
  310. width: 100%;
  311. display: flex;
  312. align-items: center;
  313. justify-content: center;
  314. padding-bottom: 30rpx;
  315. cover-image {
  316. margin: 0;
  317. padding: 0;
  318. position: absolute;
  319. }
  320. }
  321. .check-pic-result {
  322. width: 100%;
  323. padding: 10rpx 20rpx;
  324. display: flex;
  325. justify-content: center;
  326. box-sizing: border-box;
  327. color: red;
  328. }
  329. }
  330. .precautions {
  331. overflow: hidden;
  332. .precautions--tips {
  333. display: flex;
  334. padding: 10rpx 20rpx;
  335. align-items: flex-end;
  336. .precautions--tips--title {
  337. margin: 10rpx;
  338. }
  339. .precautions--tips--context {
  340. margin: 10rpx;
  341. }
  342. }
  343. .precautions--line {
  344. margin-left: 40rpx;
  345. width: 30rpx;
  346. height: 6rpx;
  347. margin-bottom: 4rpx;
  348. background-color: #9e97c3;
  349. }
  350. .precautions--context {
  351. margin: 0 20rpx;
  352. margin-bottom: 20rpx;
  353. }
  354. .img-list {
  355. display: flex;
  356. justify-content: space-around;
  357. .img-list--item {
  358. display: flex;
  359. flex-direction: column;
  360. align-items: center;
  361. width: 20%;
  362. .img {
  363. display: flex;
  364. flex-direction: row;
  365. border-radius: 20rpx;
  366. background-color: #dcdce9;
  367. width: 100%;
  368. height: 140rpx;
  369. justify-content: center;
  370. align-items: center;
  371. }
  372. }
  373. }
  374. }
  375. .btn {
  376. margin: 20rpx;
  377. }
  378. }
  379. </style>