realname-verify.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. <template>
  2. <view>
  3. <template v-if="isCertify">
  4. <uni-list>
  5. <uni-list-item class="item" title="姓名" :rightText="userInfo.realNameAuth.realName"></uni-list-item>
  6. <uni-list-item class="item" title="身份证号码" :rightText="userInfo.realNameAuth.identity"></uni-list-item>
  7. </uni-list>
  8. </template>
  9. <template v-else>
  10. <view class="uni-content">
  11. <template v-if="verifyFail">
  12. <view class="face-icon">
  13. <image src="./face-verify-icon.svg" class="face-icon-image" />
  14. </view>
  15. <view class="error-title">{{verifyFailTitle}}</view>
  16. <view class="error-description">{{verifyFailContent}}</view>
  17. <button type="primary" @click="retry" v-if="verifyFailCode !== 10013">重新开始验证</button>
  18. <button type="primary" @click="retry" v-else>返回</button>
  19. <view class="dev-tip" v-if="isDev">请在控制台查看详细错误(此提示仅在开发环境展示)</view>
  20. </template>
  21. <template v-else>
  22. <text class="title">实名认证</text>
  23. <uni-forms>
  24. <uni-forms-item name="realName">
  25. <uni-easyinput placeholder="姓名" class="input-box" v-model="realName" :clearable="false">
  26. </uni-easyinput>
  27. </uni-forms-item>
  28. <uni-forms-item name="idCard">
  29. <uni-easyinput placeholder="身份证号码" class="input-box" v-model="idCard" :clearable="false">
  30. </uni-easyinput>
  31. </uni-forms-item>
  32. </uni-forms>
  33. <uni-id-pages-agreements scope="realNameVerify" ref="agreements" style="margin-bottom: 20px;">
  34. </uni-id-pages-agreements>
  35. <button type="primary" :disabled="!certifyIdNext" @click="getCertifyId">确定</button>
  36. </template>
  37. </view>
  38. </template>
  39. </view>
  40. </template>
  41. <script>
  42. import checkIdCard from '@/uni_modules/uni-id-pages/common/check-id-card.js'
  43. import mixin from '@/uni_modules/uni-id-pages/common/login-page.mixin.js';
  44. import {
  45. store,
  46. mutations
  47. } from '@/uni_modules/uni-id-pages/common/store.js'
  48. const uniIdCo = uniCloud.importObject('uni-id-co')
  49. const tempFrvInfoKey = 'uni-id-pages-temp-frv'
  50. export default {
  51. mixins: [mixin],
  52. data() {
  53. return {
  54. realName: '',
  55. idCard: '',
  56. certifyId: '',
  57. verifyFail: false,
  58. verifyFailCode: 0,
  59. verifyFailTitle: '',
  60. verifyFailContent: ''
  61. }
  62. },
  63. computed: {
  64. userInfo() {
  65. return store.userInfo
  66. },
  67. certifyIdNext() {
  68. return Boolean(this.realName) && Boolean(this.idCard) && (this.needAgreements && this.agree)
  69. },
  70. isCertify() {
  71. return this.userInfo.realNameAuth && this.userInfo.realNameAuth.authStatus === 2
  72. },
  73. isDev() {
  74. return process.env.NODE_ENV === 'development'
  75. }
  76. },
  77. onLoad() {
  78. const tempFrvInfo = uni.getStorageSync(tempFrvInfoKey);
  79. if (tempFrvInfo) {
  80. this.realName = tempFrvInfo.realName
  81. this.idCard = tempFrvInfo.idCard
  82. }
  83. },
  84. methods: {
  85. async getCertifyId() {
  86. if (!this.certifyIdNext) return
  87. // #ifndef APP
  88. return uni.showModal({
  89. content: "暂不支持实名认证",
  90. showCancel: false
  91. })
  92. // #endif
  93. if (!checkIdCard(this.idCard)) {
  94. uni.showToast({
  95. title: "身份证不合法",
  96. icon: "none"
  97. })
  98. return
  99. }
  100. if (
  101. typeof this.realName !== 'string' ||
  102. this.realName.length < 2 ||
  103. !/^[\u4e00-\u9fa5]{1,10}(·?[\u4e00-\u9fa5]{1,10}){0,5}$/.test(this.realName)
  104. ) {
  105. uni.showToast({
  106. title: "姓名只能是汉字",
  107. icon: "none"
  108. })
  109. return
  110. }
  111. uni.setStorage({
  112. key: tempFrvInfoKey,
  113. data: {
  114. realName: this.realName,
  115. idCard: this.idCard
  116. }
  117. });
  118. const metaInfo = uni.getFacialRecognitionMetaInfo()
  119. const res = await uniIdCo.getFrvCertifyId({
  120. realName: this.realName,
  121. idCard: this.idCard,
  122. metaInfo
  123. })
  124. this.certifyId = res.certifyId
  125. this.startFacialRecognitionVerify()
  126. },
  127. startFacialRecognitionVerify() {
  128. // #ifdef APP
  129. uni.startFacialRecognitionVerify({
  130. certifyId: this.certifyId,
  131. progressBarColor: "#2979ff",
  132. success: () => {
  133. this.verifyFail = false
  134. this.getFrvAuthResult()
  135. },
  136. fail: (e) => {
  137. let title = "验证失败"
  138. let content
  139. console.log(
  140. `[frv-debug] certifyId auth error: certifyId -> ${this.certifyId}, error -> ${JSON.stringify(e, null, 4)}`
  141. )
  142. switch (e.errCode) {
  143. case 10001:
  144. content = '认证ID为空'
  145. break
  146. case 10010:
  147. title = '刷脸异常'
  148. content = e.cause.message || '错误代码: 10010'
  149. break
  150. case 10011:
  151. title = '验证中断'
  152. content = e.cause.message || '错误代码: 10011'
  153. break
  154. case 10012:
  155. content = '网络异常'
  156. break
  157. case 10013:
  158. this.verifyFailCode = e.errCode
  159. this.verifyFailContent = e.cause.message || '错误代码: 10013'
  160. this.getFrvAuthResult()
  161. console.log(
  162. `[frv-debug] 刷脸失败, certifyId -> ${this.certifyId}, 如在开发环境请检查用户的姓名、身份证号与刷脸用户是否为同一用户。如遇到认证ID已使用请检查opendb-frv-logs表中certifyId状态`
  163. )
  164. return
  165. case 10020:
  166. content = '设备设置时间异常'
  167. break
  168. default:
  169. title = ''
  170. content = `验证未知错误 (${e.errCode})`
  171. break
  172. }
  173. this.verifyFail = true
  174. this.verifyFailCode = e.errCode
  175. this.verifyFailTitle = title
  176. this.verifyFailContent = content
  177. }
  178. })
  179. // #endif
  180. },
  181. async getFrvAuthResult() {
  182. const uniIdCo = uniCloud.importObject('uni-id-co', {
  183. customUI: true
  184. })
  185. try {
  186. uni.showLoading({
  187. title: "验证中...",
  188. mask: false
  189. })
  190. const res = await uniIdCo.getFrvAuthResult({
  191. certifyId: this.certifyId
  192. })
  193. const {
  194. errCode,
  195. ...rest
  196. } = res
  197. if (this.verifyFailContent) {
  198. console.log(`[frv-debug] 客户端刷脸失败,由实人认证服务查询具体原因,原因:${this.verifyFailContent}`)
  199. }
  200. uni.showModal({
  201. content: "实名认证成功",
  202. showCancel: false,
  203. success: () => {
  204. mutations.setUserInfo({
  205. realNameAuth: rest
  206. })
  207. this.verifyFail = false
  208. }
  209. })
  210. uni.removeStorage({
  211. key: tempFrvInfoKey
  212. })
  213. } catch (e) {
  214. this.verifyFail = true
  215. this.verifyFailTitle = e.errMsg
  216. console.error(JSON.stringify(e));
  217. } finally {
  218. uni.hideLoading()
  219. }
  220. },
  221. retry() {
  222. if (this.verifyFailCode !== 10013) {
  223. this.getCertifyId()
  224. } else {
  225. this.verifyFail = false
  226. }
  227. }
  228. }
  229. }
  230. </script>
  231. <style lang="scss">
  232. @import "@/uni_modules/uni-id-pages/common/login-page.scss";
  233. .checkbox-box,
  234. .uni-label-pointer {
  235. align-items: center;
  236. display: flex;
  237. flex-direction: row;
  238. }
  239. .item {
  240. flex-direction: row;
  241. }
  242. .text {
  243. line-height: 26px;
  244. }
  245. .checkbox-box ::v-deep .uni-checkbox-input {
  246. border-radius: 100%;
  247. }
  248. .checkbox-box ::v-deep .uni-checkbox-input.uni-checkbox-input-checked {
  249. border-color: $uni-color-primary;
  250. color: #FFFFFF !important;
  251. background-color: $uni-color-primary;
  252. }
  253. .agreements {
  254. margin-bottom: 20px;
  255. }
  256. .face-icon {
  257. width: 100px;
  258. height: 100px;
  259. margin: 50px auto 30px;
  260. }
  261. .face-icon-image {
  262. width: 100%;
  263. height: 100%;
  264. display: block;
  265. }
  266. .error-title {
  267. font-size: 18px;
  268. text-align: center;
  269. font-weight: bold;
  270. }
  271. .error-description {
  272. font-size: 13px;
  273. color: #999999;
  274. margin: 10px 0 20px;
  275. text-align: center;
  276. }
  277. .dev-tip {
  278. margin-top: 20px;
  279. font-size: 13px;
  280. color: #999;
  281. text-align: center;
  282. }
  283. </style>