register.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. <template>
  2. <view>
  3. <uni-card>
  4. <uni-section title="基本信息" type="line">
  5. <lzcOCR class="lzcOCR" :src="zjcaijianSrc" @end="idcardEnd"></lzcOCR>
  6. <uni-forms ref="baseForm" :modelValue="baseFormData" :rules="rules"
  7. style="margin-top: 3vh;margin-left: 3vw;">
  8. <uni-forms-item label="姓名" required name="lrXm">
  9. <uni-easyinput ref="xm" type="text" v-model="baseFormData.lrXm" placeholder="请输入姓名"
  10. :inputBorder="true"></uni-easyinput>
  11. </uni-forms-item>
  12. <uni-forms-item label="手机号" required name="lrCydh">
  13. <uni-easyinput type="text" v-model="baseFormData.lrCydh" placeholder="请输入手机号"
  14. :inputBorder="true"></uni-easyinput>
  15. </uni-forms-item>
  16. <uni-forms-item label="市区" required name="lrHjdz">
  17. <uni-data-picker :localdata="items" popup-title="请选择市区" @change="onchange" placeholder="请选择市区"
  18. @nodeclick="onnodeclick"></uni-data-picker>
  19. </uni-forms-item>
  20. <uni-forms-item label="住址" required name="lrHjbcxx">
  21. <uni-easyinput type="text" v-model="baseFormData.lrHjbcxx" placeholder="请输入住址"
  22. :inputBorder="true"></uni-easyinput>
  23. </uni-forms-item>
  24. <uni-forms-item label="人像" required>
  25. <image :src="src" @click="takePhoto" mode="widthFix" style="width: 25vw;"></image>
  26. </uni-forms-item>
  27. <view v-if="show">
  28. <uni-forms-item label="直接上传">
  29. <uni-data-checkbox v-model="radio" :localdata="radioData"></uni-data-checkbox>
  30. </uni-forms-item>
  31. <text>注意:由于人脸比对不成功可以直接上传人工审核!</text>
  32. </view>
  33. <view>
  34. <button cursor-spacing="22px" class="buttonClass" @click="save()">注册</button>
  35. </view>
  36. </uni-forms>
  37. </uni-section>
  38. </uni-card>
  39. </view>
  40. </template>
  41. <script>
  42. import lzcOCR from '@/components/lzc-OCR/lzc-OCR.vue';
  43. let jl = require('../../static/jl.json')
  44. import {
  45. decryptRowData_ECB,
  46. decryptData_ECB
  47. } from '@/common/sm4.js'
  48. import {
  49. showConfirm,
  50. getDictInfo,
  51. toast,
  52. toBase64
  53. } from '@/common/common.js'
  54. import {
  55. UploadOne
  56. } from '@/api/upload.js'
  57. import {
  58. Register
  59. } from '@/api/login.js'
  60. import {
  61. getUser
  62. } from '@/common/auth.js'
  63. import CryptoJS from 'crypto-js';
  64. import config from '@/config.js';
  65. import idCardNoUtil from '@/common/idcard.js'
  66. import {
  67. translate,
  68. base64ToUrl
  69. } from '@/common/image.js'
  70. import {
  71. setToken,
  72. setOpenid,
  73. getOpenid,
  74. setUser
  75. } from '@/common/auth.js'
  76. import {
  77. updateKhjbxx,
  78. infoKhjbxx,
  79. GetLrByZjhm,
  80. SaveKhjbxx
  81. } from '@/api/kh.js'
  82. export default {
  83. components: {
  84. lzcOCR
  85. },
  86. data() {
  87. return {
  88. items: [],
  89. show: false,
  90. radio: 0,
  91. radioData: [{
  92. text: '否',
  93. value: 0
  94. }, {
  95. text: '是',
  96. value: 1
  97. }],
  98. // 字典
  99. dicts: {
  100. // 民族
  101. C0009: [],
  102. // 性别
  103. C0007: [],
  104. },
  105. // 百度云access_token
  106. token: '',
  107. client_id: config.face_client_id,
  108. client_secret: config.face_client_secret,
  109. // 人像地址
  110. src: "/static/images/head.png",
  111. // 身份拍摄地址
  112. zjSrc: "",
  113. // 身份证裁剪地址
  114. zjcaijianSrc: '/static/images/sfsb.png',
  115. showSrc: "",
  116. // 人员信息
  117. userInfo: {},
  118. // 组
  119. groupId: '',
  120. // 身份证号加密
  121. idcardMD5: '',
  122. // 人像base64
  123. face: '',
  124. // 身份证base64
  125. idcardFace: '',
  126. idcardFaceUrl: '',
  127. // 对比份数
  128. score: 0,
  129. // ocrXm
  130. ocrXm: '',
  131. isSearch: false,
  132. baseFormData: {
  133. lrXm: '',
  134. lrZjhm: '',
  135. lrHjbcxx: '',
  136. lrCydh: '',
  137. code: '',
  138. },
  139. rules: {
  140. lrHjbcxx: {
  141. rules: [{
  142. required: true,
  143. errorMessage: '住址不能为空'
  144. }]
  145. },
  146. lrXm: {
  147. rules: [{
  148. required: true,
  149. errorMessage: '姓名不能为空'
  150. }]
  151. },
  152. photo: {
  153. rules: [{
  154. required: true,
  155. errorMessage: '请上传人像'
  156. }]
  157. },
  158. lrCydh: {
  159. rules: [{
  160. required: true,
  161. errorMessage: '手机号不能为空'
  162. },
  163. {
  164. format: 'number',
  165. errorMessage: '请输入正确的手机号',
  166. },
  167. {
  168. pattern: '^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1}))+\\d{8})$',
  169. errorMessage: '请输入正确的手机号',
  170. }
  171. ]
  172. }
  173. },
  174. }
  175. },
  176. created() {},
  177. onLoad(o) {
  178. this.getDictList(Object.keys(this.dicts), this.dicts)
  179. this.baseFormData.code = getOpenid()
  180. this.zuzhuang()
  181. // this.userInfo = getUser()
  182. // this.groupId = this.userInfo.dept.locationCode.substring(0, 6)
  183. // let info = JSON.parse(o.info)
  184. // this.baseFormData = info
  185. // this.zjcaijianSrc = config.baseUrl + info.lrZjz
  186. // this.src = config.baseUrl + info.lrTx
  187. },
  188. methods: {
  189. zuzhuang() {
  190. let array = jl.RECORDS
  191. let shi = []
  192. jl.RECORDS.forEach(e => {
  193. if (e.level == 2) {
  194. shi.push({
  195. value: e.code,
  196. text: e.name,
  197. id: e.id,
  198. children: []
  199. })
  200. } else {
  201. shi[shi.length - 1].children.push({
  202. value: e.code,
  203. text: e.name,
  204. id: e.id,
  205. })
  206. }
  207. })
  208. this.items = shi
  209. },
  210. onchange(e) {
  211. const value = e.detail.value
  212. console.log("onchange", value);
  213. },
  214. onnodeclick(node) {
  215. console.log("fas", node);
  216. this.groupId = node.value.substring(0, 6)
  217. this.baseFormData.lrHjdz = this.groupId + '000000'
  218. },
  219. getAccessToken() {
  220. uni.request({
  221. url: '/baiduApi/oauth/2.0/token',
  222. data: {
  223. grant_type: 'client_credentials',
  224. client_id: this.client_id,
  225. client_secret: this.client_secret
  226. },
  227. method: 'POST',
  228. header: {
  229. 'Content-Type': 'application/x-www-form-urlencoded'
  230. },
  231. success: (res) => {
  232. if (res.statusCode == 200) {
  233. this.token = res.data.access_token
  234. this.match()
  235. }
  236. },
  237. error: (err) => {
  238. uni.hideLoading()
  239. }
  240. })
  241. },
  242. // 人脸对比
  243. match() {
  244. let face = this.face
  245. let idcardFace = this.idcardFace
  246. let data = [{
  247. image: face,
  248. image_type: 'BASE64',
  249. liveness_control: 'NORMAL',
  250. }, {
  251. image: idcardFace,
  252. image_type: 'BASE64'
  253. }]
  254. console.log("人脸对比:", data)
  255. uni.request({
  256. url: '/baiduApi/rest/2.0/face/v3/match?access_token=' + this.token,
  257. data: data,
  258. method: 'POST',
  259. header: {
  260. 'Content-Type': 'application/json'
  261. },
  262. success: (res) => {
  263. console.log('对比', res);
  264. if (res.data.error_msg == 'SUCCESS') {
  265. this.score = res.data.result.score;
  266. this.baseFormData.lrTxdb = JSON.stringify({
  267. "lrJmzjhm": this.idcardMD5,
  268. "xsfs": this.score
  269. })
  270. if (this.score >= config.score) {
  271. this.show = false
  272. this.baseFormData.lzzt = 3
  273. this.baseFormData.lrSpyj = '同意'
  274. this.baseFormData.prelrZjz = this.idcardFaceUrl
  275. this.faceSearch()
  276. } else {
  277. // 低于80选项是否人工审核,是的话进记录表
  278. // 身份证头像保存后端
  279. // 人脸库注册人脸、身份证md5
  280. // 修改的时候去人脸库搜索,搜索不到不允许修改
  281. // 修改成功替换原始人脸库照片
  282. // 首次修改搜索身份证
  283. // 后端没入库,人脸库相应删除
  284. // ocr失败身份证原版入库,ocr成功人脸入库
  285. // showConfirm('人像与身份证不符,请重新上传')
  286. this.baseFormData.lzzt = 1
  287. this.baseFormData.lrSpyj = ''
  288. this.show = true
  289. this.baseFormData.prelrZjz = this.zjcaijianSrc
  290. this.faceSearch()
  291. }
  292. } else {
  293. showConfirm(res.data.error_msg)
  294. uni.hideLoading()
  295. }
  296. },
  297. error: (err) => {
  298. console.log("对比失败,", err);
  299. uni.hideLoading()
  300. }
  301. })
  302. },
  303. createGroup() {
  304. uni.request({
  305. url: '/baiduApi/rest/2.0/face/v3/faceset/group/add?access_token=' + this.token,
  306. data: {
  307. group_id: this.groupId,
  308. },
  309. method: 'POST',
  310. header: {
  311. 'Content-Type': 'application/x-www-form-urlencoded'
  312. },
  313. success: (res) => {
  314. if (res.statusCode == 200) {
  315. this.faceAdd()
  316. }
  317. },
  318. error: (err) => {
  319. uni.hideLoading()
  320. }
  321. })
  322. },
  323. // 人脸注册
  324. faceAdd() {
  325. // https://cloud.baidu.com/doc/FACE/s/Gk37c1uzc#%E4%BA%BA%E8%84%B8%E6%B3%A8%E5%86%8C
  326. let face = this.face
  327. let data = {
  328. image: face,
  329. image_type: 'BASE64',
  330. group_id: this.groupId,
  331. user_id: this.idcardMD5,
  332. action_type: 'REPLACE', // 操作方式 APPEND: 当user_id在库中已经存在时,对此user_id重复注册时,新注册的图片默认会追加到该user_id下 REPLACE : 当对此user_id重复注册时,则会用新图替换库中该user_id下所有图片 默认使用APPEND
  333. }
  334. console.log("人脸注册:", data)
  335. uni.request({
  336. url: '/baiduApi/rest/2.0/face/v3/faceset/user/add?access_token=' + this.token,
  337. data: data,
  338. method: 'POST',
  339. header: {
  340. 'Content-Type': 'application/json'
  341. },
  342. success: (res) => {
  343. console.log("人脸注册:", res);
  344. uni.hideLoading()
  345. if (res.data.error_msg != 'SUCCESS') {
  346. showConfirm(res.data.error_msg)
  347. }
  348. },
  349. error: (err) => {
  350. uni.hideLoading()
  351. }
  352. })
  353. },
  354. // 人脸搜索
  355. faceSearch() {
  356. let face = this.face
  357. let data = {
  358. image: face,
  359. image_type: 'BASE64',
  360. group_id_list: this.groupId,
  361. match_threshold: config.score,
  362. max_user_num: 50
  363. }
  364. console.log("人脸搜索:", data)
  365. uni.request({
  366. url: '/baiduApi/rest/2.0/face/v3/search?access_token=' + this.token,
  367. data: data,
  368. method: 'POST',
  369. header: {
  370. 'Content-Type': 'application/json'
  371. },
  372. success: (res) => {
  373. console.log("人脸搜索:", res)
  374. if (res.data.error_msg == 'SUCCESS') {
  375. if (res.data.result.user_list.length < 1) {
  376. console.log("人脸不存在");
  377. this.createGroup()
  378. } else {
  379. if (res.data.result.user_list[0].score >= config.score) {
  380. let xs = []
  381. res.data.result.user_list.forEach(e => {
  382. if (e.user_id != this.idcardMD5) {
  383. xs.push({
  384. "lrJmzjhm": e.user_id,
  385. "xsfs": e.score
  386. })
  387. this.baseFormData.lzzt = 2
  388. this.baseFormData.lrSpyj = ''
  389. }
  390. })
  391. this.baseFormData.xslrZjhm = JSON.stringify(xs)
  392. }
  393. // this.faceAdd()
  394. uni.hideLoading()
  395. }
  396. } else {
  397. // uni.hideLoading()
  398. this.faceAdd()
  399. }
  400. },
  401. error: (err) => {
  402. uni.hideLoading()
  403. }
  404. })
  405. },
  406. save() {
  407. if (this.src == '/static/images/head.png') {
  408. showConfirm('请上传人像')
  409. return
  410. } else {
  411. if (this.ocrXm != this.baseFormData.lrXm) {
  412. showConfirm('姓名与真实姓名不符,请重新上传身份证')
  413. return
  414. }
  415. // if (!this.isSearch) {
  416. // showConfirm('当前区县暂未开放,请联系相关人员')
  417. // return
  418. // }
  419. if ((this.score >= config.score) || (this.score < config.score && this.radio == '1')) {
  420. uni.showLoading({
  421. title: '正在保存中...'
  422. })
  423. this.$refs['baseForm'].validate().then(res => {
  424. UploadOne(this.baseFormData.prelrZjz, {}).then(re => {
  425. console.log("re", re)
  426. this.baseFormData.lrZjz = re.data.url
  427. UploadOne(this.src, {}).then(re => {
  428. console.log("re", re)
  429. this.baseFormData.lrTx = re.data.url
  430. this.baseFormData.id = this.userInfo.userId
  431. Register(this.baseFormData).then(r => {
  432. console.log("r:", r)
  433. uni.hideLoading()
  434. if (r.code == 200) {
  435. toast('注册成功')
  436. // setOpenid(r.data.openId)
  437. setUser(r.data.sysUser)
  438. setToken(r.data.token.access_token)
  439. setTimeout(function() {
  440. uni.switchTab({
  441. url: '/pages/index/index'
  442. })
  443. }, 1000)
  444. }
  445. })
  446. })
  447. })
  448. }).catch(err => {
  449. uni.hideLoading()
  450. console.log(err);
  451. })
  452. } else {
  453. showConfirm('请重新上传人像')
  454. return
  455. }
  456. }
  457. },
  458. takePhoto() {
  459. if (!this.zjSrc) {
  460. showConfirm('请先上传身份证人像面')
  461. return
  462. }
  463. if (!this.groupId) {
  464. showConfirm('请先选择市区')
  465. return
  466. }
  467. uni.chooseImage({
  468. count: 1,
  469. mediaType: ['image'],
  470. sizeType: ['compressed'],
  471. sourceType: ['camera'],
  472. success: (res) => {
  473. uni.showLoading({
  474. title: '正在上传中...'
  475. })
  476. let size = res.tempFiles[0].size
  477. let scale = 1
  478. if (size / 1024 / 1024 > 0.9) scale = 0.6
  479. translate(res.tempFilePaths[0], scale, 'blob', this.setSrc)
  480. }
  481. })
  482. },
  483. setSrc(e, blobUrl) {
  484. this.src = blobUrl
  485. uni.getFileInfo({
  486. filePath: blobUrl,
  487. success: (res) => {
  488. console.log(res);
  489. let size = res.size
  490. let scale = 1
  491. if (size / 1024 / 1024 > 0.9) {
  492. scale = 0.6
  493. translate(this.src, scale, 'blob', this.setSrc)
  494. } else {
  495. e = e.replace('data:image/jpeg;base64,', "");
  496. this.face = e
  497. this.getAccessToken()
  498. }
  499. },
  500. fail: (err) => {
  501. console.log("err:", err);
  502. }
  503. })
  504. },
  505. // 身份证识别
  506. idcardEnd(words, src) {
  507. if (words.image_status == "other_type_card") {
  508. showConfirm('请上传正确的身份证人像面')
  509. return
  510. }
  511. // 身份证号校验 性别 出生日期
  512. // 修改之后的姓名和ocr返回校验,重新ocr
  513. let id = words.words_result['公民身份号码'].words
  514. let csrq = words.words_result['出生'].words
  515. let sex = words.words_result['性别'].words
  516. let info = idCardNoUtil.getIdCardInfo(id)
  517. if (!idCardNoUtil.checkIdCardNo(id)) {
  518. showConfirm('身份证号识别有误,请重新上传')
  519. return
  520. }
  521. if (info.birthday != csrq) {
  522. showConfirm('身份证出生日期识别有误,请重新上传')
  523. return
  524. }
  525. if (info.gender != sex) {
  526. showConfirm('身份证性别识别有误,请重新上传')
  527. return
  528. }
  529. if (words.image_status == "reversed_side") {
  530. showConfirm('请上传身份证人像面')
  531. return
  532. }
  533. if (words.risk_type != "normal") {
  534. // normal-正常身份证;copy-复印件;temporary-临时身份证;screen-翻拍;unknown-其他未知情况
  535. showConfirm('请上传正确的身份证人像面')
  536. return
  537. }
  538. this.baseFormData.lrXb = getDictInfo(this.dicts.C0007, words.words_result['性别'].words)[0].value
  539. this.baseFormData.lrMz = getDictInfo(this.dicts.C0009, words.words_result['民族'].words)[0].value
  540. this.idcardFace = words.photo
  541. this.idcardFaceUrl = base64ToUrl(words.photo);
  542. this.baseFormData.lrZjhm = id
  543. this.baseFormData.lrCsrq = csrq
  544. this.idcardMD5 = CryptoJS.MD5(this.baseFormData.lrZjhm).toString()
  545. this.baseFormData.lrXm = words.words_result['姓名'].words
  546. this.ocrXm = words.words_result['姓名'].words
  547. this.zjSrc = src
  548. this.zjcaijianSrc = base64ToUrl(words.card_image);
  549. if (id) {
  550. GetLrByZjhm({
  551. lrJmzjhm: this.idcardMD5
  552. }).then(res => {
  553. console.log(res);
  554. if (res.data) {
  555. showConfirm('该账号已存在,请登录').then(res => {
  556. if (res.confirm == true) {
  557. uni.reLaunch({
  558. url: '/pages/login/index'
  559. })
  560. }
  561. })
  562. }
  563. })
  564. }
  565. },
  566. }
  567. }
  568. </script>
  569. <style>
  570. .lzcOCR {
  571. width: 90%;
  572. display: flex;
  573. justify-content: center;
  574. }
  575. .buttonClass {
  576. margin-top: 4vh;
  577. margin-left: 4vw;
  578. width: 68vw;
  579. /* height: 5vh; */
  580. border-radius: 16px;
  581. border: 1px solid rgba(176, 179, 199, 1);
  582. background: #7948EA;
  583. }
  584. </style>