authFace.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <template>
  2. <view class="container">
  3. <image class="face_auth_bg" :src="iconUrl.face_auth_bg" />
  4. <!-- 演示线因没有人脸审核模块,可能会导致审核失败,可以注释代码提交审核,但是不要把注释代码上传到git上 -->
  5. <view class="main_box">
  6. <view class="cont displayFlexCol">
  7. <text>为保障账户安全</text>
  8. <text class="cont_text">当前业务需要采集您的人脸信息以核实身份</text>
  9. <image class="cont_img" :src="iconUrl.face_auth_icon"></image>
  10. </view>
  11. <view class="input_box padding_30upx">
  12. <view class="input_list" v-if="!changeMobile">
  13. <view class="input_item border_bottom">
  14. <view class="input_tit">姓名</view>
  15. <view class="input_con">{{ memberName }}</view>
  16. </view>
  17. <view class="input_item">
  18. <view class="input_tit">身份证号</view>
  19. <input class="input_con" placeholder="请输入就诊人身份证号" v-model="idCardNo" type='idcard'
  20. placeholder-style="color:#999"></input>
  21. </view>
  22. </view>
  23. <view class="input_list" v-if="changeMobile">
  24. <view class="input_item">
  25. <view class="input_tit">新手机号</view>
  26. <input class="input_con" placeholder="请输入新手机号" v-model="newMobile" type='number'
  27. placeholder-style="color:#999"></input>
  28. </view>
  29. <view class="input_item">
  30. <input class="input_con" placeholder="请输入验证码" v-model="code" type='number'
  31. placeholder-style="color:#999"></input>
  32. <view v-if="seconds <= 0" class="code_con_txt colorCustom" @click="getCode">获取验证码</view>
  33. <view v-if="seconds > 0" class="code_con_txt colorCustom">{{ seconds }}秒后重新获取</view>
  34. </view>
  35. </view>
  36. </view>
  37. <view class="public_btn_con bg_white">
  38. <view v-if="!changeMobile" class="public_btn backgroundCustom displayFlexRow" @click="startCertification">开始人脸识别
  39. </view>
  40. <view v-if="changeMobile" class="public_btn backgroundCustom displayFlexRow" @click="hisUpdateMobileByCard">
  41. 修改手机号</view>
  42. </view>
  43. </view>
  44. </view>
  45. </template>
  46. <script lang="ts" setup>
  47. import { ref } from 'vue';
  48. import { useStore } from 'vuex';
  49. import { useOnLoad, usePreserMember } from '@/hook';
  50. import { addUserLevelL2_V3, sendVerificationCode_V3, checkVerificationCode_V3, setHisMobile, queryBaseMemberList_V3 } from '@/pagesPersonal/service/patientManagement';
  51. import { common } from '@/utils';
  52. import icon from '@/utils/icon.js';
  53. const app = getApp();
  54. const store = useStore();
  55. const iconUrl = ref(icon);
  56. const currentUser = ref<any>({});
  57. const checkUserInfo = ref<any>({});
  58. const memberName = ref("");
  59. const idCardNo = ref("");
  60. const changeMobile = ref(false);
  61. const newMobile = ref("");
  62. const timer = ref<any>(null);
  63. const seconds = ref(0);
  64. const cardNo = ref("");
  65. const memberId = ref("");
  66. const pcid = ref("");
  67. const pageType = ref("");
  68. const code = ref("");
  69. useOnLoad((options) => {
  70. console.log("authFace=========",options);
  71. if (options && options.params) {
  72. try {
  73. let params = JSON.parse(options.params);
  74. console.log("params=========",params);
  75. let pType = options.pageType;
  76. if (params) {
  77. cardNo.value = params.CardNo;
  78. memberName.value = params.MemberName;
  79. idCardNo.value = params.IdCardNo;
  80. memberId.value = params.MemberId;
  81. pageType.value = pType;
  82. app.globalData.currentUser = {
  83. memberId: params.MemberId
  84. };
  85. }
  86. } catch (e) {
  87. console.error('参数解析失败', e);
  88. }
  89. }
  90. currentUser.value = app.globalData.currentUser;
  91. main();
  92. });
  93. const main = async () => {
  94. let checkUser = {};
  95. let querData = {
  96. isEncrypt: true,
  97. isTokenSecret: true,
  98. hosId: app.globalData.districtId || app.globalData.hosId,
  99. memberId: currentUser.value.memberId
  100. };
  101. // Service returns resp array
  102. let { resData: resp } = await queryBaseMemberList_V3(querData);
  103. if (resp && resp.length > 0) {
  104. let keyStr = resp[0].baseMemberEncryptionStore;
  105. let key = uni.getStorageSync("token");
  106. checkUser = JSON.parse(await common.desDecrypt(keyStr, key, 'hex'));
  107. }
  108. checkUserInfo.value = checkUser;
  109. memberName.value = checkUser.memberName;
  110. };
  111. const startCertification = async () => {
  112. let mName = memberName.value;
  113. let iCardNo = idCardNo.value;
  114. if (common.isEmpty(mName)) {
  115. common.showToast('请输入就诊人姓名');
  116. return;
  117. }
  118. if (common.isEmpty(iCardNo)) {
  119. common.showToast('请输入身份证号码');
  120. return;
  121. }
  122. if (iCardNo != checkUserInfo.value.idCardNo) {
  123. common.showToast('当前输入身份证号与实际授权用户信息不一致');
  124. return;
  125. }
  126. // uni.startFacialRecognitionVerify
  127. // #ifdef MP-WEIXIN
  128. uni.startFacialRecognitionVerify({
  129. checkAliveType: 1,
  130. name: mName,
  131. idCardNumber: iCardNo,
  132. success: async function (res) {
  133. let cUser = currentUser.value;
  134. if (!!pageType.value && pageType.value == "changeMobile") {
  135. changeMobile.value = true;
  136. } else {
  137. // 认证成功
  138. let queryData = {
  139. openId: uni.getStorageSync('openid'),
  140. memberId: cUser.memberId,
  141. store: {
  142. cardEncryptionStore: cUser.encryptionStore || '',
  143. baseMemberEncryptionStore: cUser.baseMemberEncryptionStore
  144. }
  145. };
  146. let { resData: resLevel } = await addUserLevelL2_V3(queryData);
  147. if (resLevel) {
  148. app.globalData.currentUser = cUser;
  149. common.navigateBack(1);
  150. }
  151. }
  152. },
  153. fail: (err) => {
  154. console.error('人脸识别失败', err);
  155. common.showToast('人脸识别失败');
  156. }
  157. });
  158. // #endif
  159. // #ifndef MP-WEIXIN
  160. common.showToast('当前平台不支持人脸识别');
  161. // #endif
  162. };
  163. const getCode = async () => {
  164. if (newMobile.value == "") {
  165. common.showToast("手机号不能为空");
  166. return;
  167. }
  168. let queryData = {
  169. OpenId: store.state.openId,
  170. HosId: app.globalData.hosId,
  171. Mobile: newMobile.value
  172. };
  173. let { resData: resp } = await sendVerificationCode_V3(queryData);
  174. if (!common.isEmpty(resp)) {
  175. pcid.value = resp[0].pcId;
  176. common.showModal('发送成功!');
  177. // Custom countdown logic
  178. seconds.value = 60;
  179. if (timer.value) clearInterval(timer.value);
  180. timer.value = setInterval(() => {
  181. seconds.value--;
  182. if (seconds.value <= 0) {
  183. clearInterval(timer.value);
  184. }
  185. }, 1000);
  186. }
  187. };
  188. const checkVerificationCode = async (queryData: any) => {
  189. return new Promise(async (resolve, reject) => {
  190. if (common.isEmpty(queryData.pcId)) {
  191. common.showModal('请先获取验证码');
  192. } else {
  193. let reqData = {
  194. pcId: queryData.pcId || '',
  195. verificationCode: queryData.verificationCode,
  196. };
  197. try {
  198. let { resData } = await checkVerificationCode_V3(reqData);
  199. if (resData && resData.RespCode == '10000') {
  200. resolve(false); // Valid
  201. } else {
  202. resolve(true); // Invalid
  203. }
  204. } catch (e) {
  205. resolve(true); // Invalid
  206. }
  207. }
  208. });
  209. };
  210. const hisUpdateMobileByCard = async () => {
  211. if (common.isEmpty(newMobile.value)) {
  212. common.showToast("请输入手机号");
  213. return;
  214. }
  215. if (common.isEmpty(pcid.value)) {
  216. common.showToast("请获取验证码");
  217. return;
  218. }
  219. if (common.isEmpty(code.value)) {
  220. common.showToast("请输入验证码");
  221. return;
  222. }
  223. // 校验验证码是否正确
  224. let reqData = {
  225. pcId: pcid.value || '',
  226. verificationCode: code.value,
  227. };
  228. if (await checkVerificationCode(reqData)) return;
  229. let data = {
  230. CardNo: cardNo.value,
  231. Mobile: newMobile.value,
  232. MemberName: memberName.value,
  233. MemberId: memberId.value
  234. };
  235. // setHisMobile returns resp
  236. let { resData: resp } = await setHisMobile(data);
  237. if (resp) {
  238. common.showModal("您的手机号码已修改成功", () => {
  239. common.navigateBack(1);
  240. });
  241. }
  242. };
  243. </script>
  244. <style lang="scss" scoped>
  245. .container {
  246. background: white;
  247. }
  248. .padding_30upx {
  249. padding: 0 30upx;
  250. box-sizing: border-box;
  251. }
  252. .face_auth_bg {
  253. width: 100%;
  254. height: 790upx;
  255. position: relative;
  256. z-index: 1;
  257. }
  258. .main_box {
  259. width: 100%;
  260. height: 100%;
  261. position: absolute;
  262. top: 0;
  263. left: 0;
  264. z-index: 2;
  265. }
  266. .cont {
  267. padding: 56upx 74upx;
  268. box-sizing: border-box;
  269. }
  270. .cont text:nth-child(1) {
  271. font-size: 48upx;
  272. font-weight: bold;
  273. color: white;
  274. padding-bottom: 20upx;
  275. }
  276. .cont_img {
  277. width: 395upx;
  278. height: 395upx;
  279. margin-top: 55upx;
  280. }
  281. .cont_text {
  282. font-size: 32upx;
  283. color: white;
  284. }
  285. .input_list {
  286. display: inline-block;
  287. width: 100%;
  288. padding: 0 30upx;
  289. box-shadow: 0px 2px 20px 0px #ddd;
  290. border-radius: 20upx;
  291. background: white;
  292. }
  293. .input_item {
  294. height: 120upx;
  295. display: flex;
  296. align-items: center;
  297. position: relative;
  298. margin-bottom: -2px;
  299. }
  300. .input_tit {
  301. font-size: 32upx;
  302. font-weight: bold;
  303. color: #222326;
  304. width: 180upx;
  305. flex-shrink: 0;
  306. }
  307. .input_con {
  308. font-size: 32upx;
  309. }
  310. .public_btn {
  311. font-size: 34upx;
  312. }
  313. .code_con_txt {
  314. width: 30%;
  315. }
  316. </style>