【PT.SCC实名制管理系统】24.10.01 -30天,考勤打卡小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

419 lines
9.2 KiB

6 months ago
  1. <template>
  2. <view class="page-content">
  3. <view class="containerV">
  4. <view class="headerV">
  5. <view class="top-tips1">
  6. <view>请将正对手机头部匹配摄像区域</view>
  7. </view>
  8. <view class="top-tips2">
  9. 为了捍卫你的不要脸请拍摄本人头像
  10. </view>
  11. </view>
  12. <view class="contentV">
  13. <view class="mark"></view>
  14. <image v-if="tempImg" mode="widthFix" :src="tempImg" />
  15. <camera v-if='isAuthCamera' :device-position="devicePosition ?'front': 'back'" class="camera"
  16. flash="off" resolution='high' />
  17. <view v-show="!tempImg && tipsText" class="tipV">{{ tipsText }}</view>
  18. </view>
  19. <view class="footerV">
  20. <view style="width: 100%;">
  21. <view v-if="!tempImg" style="width: 100%;">
  22. <view class="privacyV">
  23. <view class="icon"></view>
  24. <view class="text">
  25. 照片隐私<text @click="handleJumpSecurityClick">安全保障</text>
  26. </view>
  27. </view>
  28. <view class="bottom-tips-2">该照片作为你不要脸的铁证</view>
  29. <view class="take-photo-bgV">
  30. <!-- 图片上传 -->
  31. <view v-show="true" class="btn-change-upload" @click="handleChooseImage" />
  32. <!--拍照-->
  33. <view class="btn-take-photo" @click="handleTakePhotoClick" />
  34. <!-- 切换镜头 -->
  35. <view class="btn-change-camera" @click="handleChangeCameraClick" />
  36. </view>
  37. </view>
  38. <view class="confirmV" v-else>
  39. <view class="btn-cancel" @click="handleCancelClick">
  40. 取消
  41. </view>
  42. <view class="btn-ok" @click="handleOkClick">
  43. 确定
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </template>
  51. <script>
  52. export default {
  53. name: 'index',
  54. components: {
  55. },
  56. data() {
  57. return {
  58. tipsText: '', // 错误文案提示
  59. tempImg: '', // 本地图片路径
  60. cameraEngine: null, // 相机引擎
  61. devicePosition: true, // 摄像头朝向
  62. isAuthCamera: true, // 是否拥有相机权限
  63. }
  64. },
  65. onLoad(options) {
  66. this.initData()
  67. },
  68. methods: {
  69. // 初始化相机引擎
  70. initData() {
  71. // #ifdef MP-WEIXIN
  72. // 1、初始化人脸识别
  73. wx.initFaceDetect()
  74. // 2、创建 camera 上下文 CameraContext 对象
  75. this.cameraEngine = wx.createCameraContext()
  76. // 3、获取 Camera 实时帧数据
  77. const listener = this.cameraEngine.onCameraFrame((frame) => {
  78. if (this.tempImg) {
  79. return;
  80. }
  81. // 4、人脸识别,使用前需要通过 wx.initFaceDetect 进行一次初始化,推荐使用相机接口返回的帧数据
  82. wx.faceDetect({
  83. frameBuffer: frame.data,
  84. width: frame.width,
  85. height: frame.height,
  86. enablePoint: true,
  87. enableConf: true,
  88. enableAngle: true,
  89. enableMultiFace: true,
  90. success: (faceData) => {
  91. let face = faceData.faceInfo[0]
  92. if (faceData.x == -1 || faceData.y == -1) {
  93. this.tipsText = '检测不到人'
  94. }
  95. if (faceData.faceInfo.length > 1) {
  96. this.tipsText = '请保证只有一个人'
  97. } else {
  98. const {
  99. pitch,
  100. roll,
  101. yaw
  102. } = face.angleArray;
  103. const standard = 0.5
  104. if (Math.abs(pitch) >= standard || Math.abs(roll) >= standard ||
  105. Math.abs(yaw) >= standard) {
  106. this.tipsText = '请平视摄像头'
  107. } else if (face.confArray.global <= 0.8 || face.confArray.leftEye <=
  108. 0.8 || face.confArray.mouth <= 0.8 || face.confArray.nose <= 0.8 ||
  109. face.confArray.rightEye <= 0.8) {
  110. this.tipsText = '请勿遮挡五官'
  111. } else {
  112. this.tipsText = '请拍照'
  113. // 这里可以写自己的逻辑了
  114. }
  115. }
  116. },
  117. fail: (err) => {
  118. if (err.x == -1 || err.y == -1) {
  119. this.tipsText = '检测不到人'
  120. } else {
  121. this.tipsText = err.errMsg || '网络错误,请退出页面重试'
  122. }
  123. },
  124. })
  125. })
  126. // 5、开始监听帧数据
  127. listener.start()
  128. // #endif
  129. },
  130. // 切换设备镜头
  131. handleChangeCameraClick() {
  132. this.devicePosition = !this.devicePosition;
  133. },
  134. // 图片上传
  135. handleChooseImage() {
  136. uni.chooseImage({
  137. count: 1,
  138. sizeType: ['original', 'compressed'],
  139. sourceType: ['album'],
  140. success: (res) => {
  141. if (res.errMsg === 'chooseImage:ok') {
  142. uni.showLoading({
  143. title: '照片上传中...'
  144. })
  145. console.log("===========:", res.tempFilePaths[0])
  146. this.handleOkClick()
  147. }
  148. },
  149. fail: (res) => {
  150. },
  151. });
  152. },
  153. // 拍照点击
  154. handleTakePhotoClick() {
  155. if (this.tipsText != "" && this.tipsText != "请拍照") {
  156. return;
  157. }
  158. uni.getSetting({
  159. success: (res) => {
  160. if (!res.authSetting['scope.camera']) {
  161. this.isAuthCamera = false
  162. uni.openSetting({
  163. success: (res) => {
  164. if (res.authSetting['scope.camera']) {
  165. this.isAuthCamera = true;
  166. }
  167. }
  168. })
  169. }
  170. }
  171. })
  172. this.cameraEngine.takePhoto({
  173. quality: "high",
  174. success: ({
  175. tempImagePath
  176. }) => {
  177. this.tempImg = tempImagePath
  178. console.log("=======tempImg:", this.tempImg)
  179. }
  180. })
  181. },
  182. // 点击确定上传
  183. handleOkClick() {
  184. uni.showLoading({
  185. mask: true,
  186. title: '校验中...'
  187. })
  188. // 更新人脸识别图片请求协议:传七牛图片链接
  189. setTimeout(function() {
  190. uni.hideLoading()
  191. uni.showToast({
  192. icon: "none",
  193. title: "假装图片上传成功",
  194. duration: 2000,
  195. })
  196. }, 3000);
  197. },
  198. // 点击 - 取消上传
  199. handleCancelClick() {
  200. this.tempImg = ''
  201. },
  202. // 点击 - 人脸安全保障按钮
  203. handleJumpSecurityClick() {
  204. uni.showToast({
  205. icon: "none",
  206. title: "假装跳转人脸安全保障",
  207. duration: 2000,
  208. })
  209. },
  210. }
  211. }
  212. </script>
  213. <style lang="scss" scoped>
  214. .page-content {
  215. width: 100%;
  216. height: 100%;
  217. .containerV {
  218. width: 100%;
  219. height: 100%;
  220. .headerV {
  221. .top-tips1 {
  222. margin-top: 60rpx;
  223. color: #1C1C1C;
  224. font-size: 36rpx;
  225. text-align: center;
  226. }
  227. .top-tips2 {
  228. margin-top: 20rpx;
  229. color: #00AAFF;
  230. font-size: 28rpx;
  231. text-align: center;
  232. }
  233. }
  234. .contentV {
  235. position: relative;
  236. display: flex;
  237. flex-direction: column;
  238. align-items: center;
  239. justify-content: center;
  240. height: 661rpx;
  241. margin-top: 30rpx;
  242. .tipV {
  243. bottom: 30rpx;
  244. position: absolute;
  245. line-height: 90rpx;
  246. padding-left: 24rpx;
  247. padding-right: 24rpx;
  248. max-width: calc(100vw - 50rpx * 2);
  249. text-align: center;
  250. font-size: 30rpx;
  251. background: #000000;
  252. opacity: 0.75;
  253. color: #FFFFFF;
  254. border-radius: 16rpx;
  255. overflow: hidden;
  256. white-space: nowrap;
  257. text-overflow: ellipsis;
  258. z-index: 5;
  259. }
  260. .camera {
  261. width: 100%;
  262. height: 100%;
  263. }
  264. .mark {
  265. position: absolute;
  266. left: 0;
  267. top: 0;
  268. z-index: 2;
  269. width: 750rpx;
  270. height: 100%;
  271. // background: url("@/static/face/view_face_background.png") no-repeat center bottom;
  272. background-size: 750rpx 661rpx;
  273. }
  274. image {
  275. position: absolute;
  276. width: 100%;
  277. height: 100%;
  278. z-index: 3;
  279. }
  280. }
  281. .footerV {
  282. width: 100%;
  283. display: flex;
  284. flex-direction: row;
  285. align-items: center;
  286. justify-content: center;
  287. .privacyV {
  288. padding-top: 30rpx;
  289. display: flex;
  290. flex-direction: row;
  291. align-items: center;
  292. justify-content: center;
  293. .text {
  294. font-size: 30rpx;
  295. color: #1C1C1C;
  296. text-align: center;
  297. line-height: 42rpx;
  298. margin-left: 15rpx;
  299. text {
  300. font-size: 30rpx;
  301. color: #00AAFF;
  302. text-align: center;
  303. line-height: 42rpx;
  304. }
  305. }
  306. .icon {
  307. width: 40rpx;
  308. height: 47rpx;
  309. // background: url("@/static/face/icon_face_security.png") no-repeat;
  310. background-size: 100% auto;
  311. }
  312. }
  313. .bottom-tips-2 {
  314. margin-top: 20rpx;
  315. color: #999999;
  316. text-align: center;
  317. font-size: 26rpx;
  318. }
  319. .take-photo-bgV {
  320. width: 100%;
  321. margin-top: 30rpx;
  322. display: flex;
  323. flex-direction: row;
  324. align-items: center;
  325. justify-content: center;
  326. .btn-take-photo {
  327. // 由于左边没有按钮,所以左边要便宜更大,以便是拍照按钮居中
  328. margin: 0rpx 80rpx 0rpx 80rpx;
  329. width: 196rpx;
  330. height: 196rpx;
  331. // background: url("https://pro-file-qn.ztjy61.com/1003020211103145058685NNR9vlTm.png") no-repeat;
  332. background-size: 100% auto;
  333. }
  334. .btn-change-upload {
  335. left: 130rpx;
  336. width: 80rpx;
  337. height: 80rpx;
  338. // background: url("@/static/face/icon_face_upload_picture.png") no-repeat;
  339. background-size: 100% auto;
  340. }
  341. .btn-change-camera {
  342. right: 130rpx;
  343. width: 80rpx;
  344. height: 80rpx;
  345. // background: url("@/static/face/icon_face_switch_cameras.png") no-repeat;
  346. background-size: 100% auto;
  347. }
  348. }
  349. .confirmV {
  350. margin: 200rpx 100rpx 0rpx 100rpx;
  351. display: flex;
  352. flex-direction: row;
  353. align-items: center;
  354. justify-content: space-between;
  355. .btn-cancel {
  356. font-size: 32rpx;
  357. color: #1C1C1C;
  358. }
  359. .btn-ok {
  360. font-size: 32rpx;
  361. color: #00AAFF;
  362. }
  363. }
  364. }
  365. }
  366. }
  367. </style>