Parcourir la source

修改小程序bug问题

ext.liuqiwen3 il y a 1 mois
Parent
commit
a48dec983b

+ 17 - 0
api/faceVerify.js

@@ -0,0 +1,17 @@
+import request from "@/utils/request.js";
+
+/**
+ * 发起认证
+ * 
+ */
+export function init(data) {
+  return request.post('faceVerify/init', data);
+}
+
+/**
+ * 获取认证结果
+ * 
+ */
+export function query(data) {
+  return request.get('faceVerify/query', data);
+}

+ 14 - 0
api/user.js

@@ -198,3 +198,17 @@ export function withdrawToCard(data) {
 export function getCustomerServiceList(data) {
   return request.get("customer-service/list", data);
 }
+
+/**
+ * 实名认证
+ */
+export function faceVerify(data) {
+  return request.post(`faceVerify/hminit`, data);
+}
+
+/**
+ * 获取实名认证状态
+ */
+export function getFaceVerify(data) {
+  return request.post(`faceVerify/list`, data);
+}

+ 15 - 0
pages.json

@@ -236,6 +236,21 @@
             "enablePullDownRefresh": false
           }
         },
+        {
+          "path": "face_detect/index",
+          "style": {
+            "navigationBarTitleText": "实名认证",
+            "navigationBarBackgroundColor": "#FFFFFF",
+            "navigationBarTextStyle": "black",
+            "app-plus": {
+              // #ifdef APP-PLUS
+              "titleNView": {
+                "type": "default"
+              }
+              // #endif
+            }
+          }
+        },
         {
           "path": "goods_return/index",
           "style": {

+ 141 - 101
pages/order_addcart/order_addcart.vue

@@ -438,32 +438,59 @@ onShow(() => {
   
   canShow.value = false;
   if (isLogin.value) {
-    hotPage.value = 1;
-    hostProduct.value = [];
-    hotScroll.value = false;
-    loadend.value = false;
-    page.value = 1;
-    cartList.valid = [];
-    getCartListFn();
-    loadendInvalid.value = false;
-    pageInvalid.value = 1;
-    cartList.invalid = [];
-    getInvalidList();
-    footerswitch.value = true;
-    hotScroll.value = false;
-    hotPage.value = 1;
-    hotLimit.value = 10;
-    cartList.valid = [];
-    cartList.invalid = [];
-    // 不要重置选中状态
-    // isAllSelect.value = false;
-    // selectValue.value = [];
-    // selectCountPrice.value = 0.0;
-    cartCount.value = 0;
-    isShowAuth.value = false;
+    // 重置所有状态
+    resetAllState();
+
+    // 设置加载状态
+    // uni.showLoading({
+    //   title: '加载中...',
+    //   mask: true
+    // });
+
+    // 使用 Promise.allSettled 避免单个失败影响整体
+    Promise.allSettled([
+      getCartListFn(),
+      getInvalidList(),
+      getHostProduct()
+    ]).finally(() => {
+      // 添加一个短暂延迟,确保 DOM 更新完成
+      setTimeout(() => {
+        canShow.value = true;
+        uni.hideLoading();
+      }, 50);
+    });
   }
 });
+function resetAllState() {
+  footerswitch.value = true;
+  goodsHidden.value = false;
+  hotScroll.value = false;
+  hotPage.value = 1;
+  page.value = 1;
+  pageInvalid.value = 1;
+
+  // 不直接清空数组,而是先保留引用
+  // 避免立即触发响应式更新
+  isAllSelect.value = false;
+  selectValue.value = [];
+  selectCountPrice.value = 0.0;
+  shopCheckbox.value = [];
+  loading.value = false;
+  loadend.value = false;
+  loadendInvalid.value = false;
+  loadingInvalid.value = false;
+  loadTitleInvalid.value = "加载更多";
+
+  // 先重置购物车数据
+  // 使用 Object.assign 保持响应式
+  Object.assign(cartList, {
+    valid: [],
+    invalid: [],
+  });
 
+  // 清空推荐商品
+  hostProduct.value = [];
+}
 onReachBottom(() => {
   if (loadend.value) {
     getInvalidList();
@@ -599,10 +626,10 @@ function reElection(item) {
 
 function getGoodsDetails(item) {
   console.log("item", item);
-  uni.showLoading({
-    title: "加载中",
-    mask: true,
-  });
+  // uni.showLoading({
+  //   title: "加载中",
+  //   mask: true,
+  // });
   cartId.value = item.id;
   product_id.value = item.productId;
   getProductDetail(item.productId)
@@ -1073,103 +1100,116 @@ function getCartData(data) {
 }
 
 async function getCartListFn() {
-  uni.showLoading({
-    title: "加载中",
-    mask: true,
-  });
-  let data = {
-    page: page.value,
-    limit: limit.value,
-    isValid: true,
-  };
-  getCartCounts(true, "sum").then(async (c) => {
-    // 获取购物车商品数量
+  if (loading.value) return;
+  loading.value = true;
+  try {
+    let data = {
+      page: page.value,
+      limit: limit.value,
+      isValid: true,
+    };
+
+    const c = await getCartCounts(true, "sum");
     cartCount.value = c.data.count;
+
     // 当没有商品时,获取推荐商品
-    if (c.data.count === 0) getHostProduct();
+    if (c.data.count === 0) {
+      await getHostProduct();
+    }
+
+    // 收集所有有效的商品
+    const allValidItems = [];
+
     for (let i = 0; i < Math.ceil(cartCount.value / limit.value); i++) {
       let cartListData = await getCartData(data);
       let valid = cartListData.list;
-      let validList = [...cartList.valid, ...valid];
-      let selectValueArr = [];
 
-      if (validList.length > 0) {
-        for (let index in validList) {
+      // 处理商品数据
+      if (valid.length > 0) {
+        for (let index in valid) {
           // 购物车加减状态
-          if (validList[index].cartNum == 1) {
-            validList[index].numSub = true;
+          if (valid[index].cartNum == 1) {
+            valid[index].numSub = true;
           } else {
-            validList[index].numSub = false;
+            valid[index].numSub = false;
           }
-          // 库存
-          let stock = validList[index].stock ? validList[index].stock : 0;
-
-          // 当购物车数量大于库存时,设置购物车数量为库存
-          if (validList[index].cartNum == stock) {
-            validList[index].numAdd = true;
-          } else if (validList[index].cartNum == validList[index].stock) {
-            validList[index].numAdd = true;
+
+          let stock = valid[index].stock ? valid[index].stock : 0;
+
+          if (valid[index].cartNum == stock) {
+            valid[index].numAdd = true;
+          } else if (valid[index].cartNum == valid[index].stock) {
+            valid[index].numAdd = true;
           } else {
-            validList[index].numAdd = false;
+            valid[index].numAdd = false;
           }
 
-          // attrStatus 判断商品是否有效
-          if (validList[index].attrStatus) {
-            // 关键修改:根据 selectValue 中的ID来设置选中状态
-            if (selectValue.value.includes(validList[index].id)) {
-              validList[index].checked = true;
-              selectValueArr.push(validList[index].id);
-            } else {
-              validList[index].checked = false;
-            }
+          if (valid[index].attrStatus) {
+            valid[index].checked = true;
           } else {
-            validList[index].checked = false;
+            valid[index].checked = false;
           }
         }
+        allValidItems.push(...valid);
       }
-      cartList.valid = validList;
-      data.page += 1;
-      // 不要重置 selectValue,保持原来的选中状态
-      // selectValue.value = selectValueArr;
 
-      let newArr = validList.filter((item) => item.attrStatus);
-      // 全选状态
-      isAllSelect.value = newArr.length > 0 && selectValue.value.length === newArr.length;
-      switchSelect();
+      data.page += 1;
     }
+
+    // 一次性更新数组,避免多次响应式更新
+    cartList.valid = allValidItems;
+
+    // 更新选中状态
+    const selectValueArr = allValidItems
+        .filter(item => item.attrStatus && item.checked)
+        .map(item => item.id);
+
+    selectValue.value = selectValueArr;
+
+    let newArr = allValidItems.filter((item) => item.attrStatus);
+    isAllSelect.value = newArr.length == selectValueArr.length && newArr.length;
+    switchSelect();
+
+  } catch (error) {
+    Toast({
+      title: error.message || '加载失败',
+    });
+  } finally {
     loading.value = false;
-    canShow.value = true;
-    uni.hideLoading();
-  }).catch(err=>{
-	  uni.hideLoading()
-  })
+  }
 }
 
-function getInvalidList() {
+async function getInvalidList() {
   if (loadendInvalid.value) return false;
   if (loadingInvalid.value) return false;
-  let data = {
-    page: pageInvalid.value,
-    limit: limitInvalid.value,
-    isValid: false,
-  };
-  getCartList(data)
-    .then((res) => {
-      let invalid = res.data.list,
-        loadendInvalidFlag = invalid.length < limitInvalid.value;
-
-      cartList.invalid = [...invalid, ...cartList.invalid];
-      loadendInvalid.value = loadendInvalidFlag;
-      loadTitleInvalid.value = loadendInvalidFlag
-        ? "我也是有底线的"
-        : "加载更多";
-      pageInvalid.value = pageInvalid.value + 1;
-      loadingInvalid.value = false;
-    })
-    .catch((res) => {
-      loadingInvalid.value = false;
-      loadTitleInvalid.value = "加载更多";
-    });
+
+  loadingInvalid.value = true;
+
+  try {
+    let data = {
+      page: pageInvalid.value,
+      limit: limitInvalid.value,
+      isValid: false,
+    };
+
+    const res = await getCartList(data);
+    let invalid = res.data.list;
+    let loadendInvalidFlag = invalid.length < limitInvalid.value;
+
+    // 一次性更新数组
+    cartList.invalid = [...cartList.invalid, ...invalid];
+
+    loadendInvalid.value = loadendInvalidFlag;
+    loadTitleInvalid.value = loadendInvalidFlag ?
+        "我也是有底线的" :
+        "加载更多";
+    pageInvalid.value = pageInvalid.value + 1;
+
+  } catch (res) {
+    console.error('获取失效商品失败:', res);
+  } finally {
+    loadingInvalid.value = false;
+  }
 }
 
 function getHostProduct() {

+ 67 - 10
pages/user/index.vue

@@ -12,7 +12,7 @@
       </template>
     </up-navbar>
     <!-- 顶部用户信息 -->
-    <view class="user-header">
+    <view class="user-header jianbianBG">
       <view class="user-info">
         <view class="user-main">
           <view>
@@ -37,8 +37,19 @@
             <text class="vip-expire" v-if="appStore.$userInfo?.svip"
               >到期时间:{{ appStore.$userInfo?.svipExpireTime }}</text
             >
+            <view class="intro">
+              <view class="item" @click="handleFaceDetect">
+                {{ appStore.$userInfo?.realNameVerified ? "已实名" : "未实名" }}
+              </view>
+              <view class="item" v-if="userInfoAddres !== ''">IP:
+                {{ userInfoAddres }}
+              </view>
+
+              <view class="item" v-if="appStore.$userInfo?.sex !== 0">{{ sexMap[appStore.$userInfo?.sex] }}·{{ appStore.$userInfo?.age }}岁</view>
+            </view>
           </view>
         </view>
+
         <view class="btn-content" @click="handleEdit()">
           <image
             class="setting"
@@ -49,6 +60,7 @@
         </view>
       </view>
 
+
       <!-- 会员开通提示 v-if="!userInfo.isVip"-->
       <view class="vip-promote" v-if="!(appStore?.$wxConfig?.auditModeEnabled)">
         <image class="vipBG" :src="HTTP_REQUEST_URL_IMG+'vipBG.png'" mode="scaleToFill"></image>
@@ -372,6 +384,18 @@ const params = ref({
   page: 1,
   limit: 10,
 });
+const sexMap = {
+  0: "未知",
+  1: "男",
+  2: "女",
+  3: "保密",
+};
+
+const userInfoAddres = computed(() => {
+  let address = appStore.userInfo?.addres || "";
+  const list = address.split("-");
+  return list[0] || "";
+});
 
 // 页面加载
 onShow(async () => {
@@ -414,6 +438,7 @@ onPageScroll((e) => {
 const wxConfig = ref({});
 const tradeList = ref([]);
 const useList = ref([]);
+const isOwner = ref(true);
 watch(
   () => appStore.wxConfig,
   (newVal) => {
@@ -648,6 +673,16 @@ const getHistoryList = async () => {
   const { data } = await footprintList(params.value);
   recentStores.value = data.records;
 };
+//人脸识别
+function handleFaceDetect() {
+  // #ifndef APP-PLUS
+  if (appStore.userInfo.realNameVerified || !isOwner.value) return;
+  uni.navigateTo({
+    url: "/pages/users/face_detect/index"
+  });
+  // #endif
+
+}
 </script>
 
 <style scoped lang="scss">
@@ -660,7 +695,7 @@ const getHistoryList = async () => {
 /* 顶部用户信息 */
 .user-header {
   height: 600rpx;
-  background-image: linear-gradient(200deg, #fcd965 0%, #ffffff 90%) !important;
+  //background-image: linear-gradient(200deg, #fcd965 0%, #ffffff 90%) !important;
   background-size: 100% 100%;
   padding: 150rpx 20rpx 20rpx;
   color: #fff;
@@ -672,17 +707,21 @@ const getHistoryList = async () => {
   display: flex;
   justify-content: space-between;
   align-items: center;
-  margin-bottom: 30rpx;
+  margin-bottom: 20rpx;
+}
+.user-detail{
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
 }
-
 .user-main {
   display: flex;
   align-items: center;
 }
 
 .avatar {
-  width: 120rpx;
-  height: 120rpx;
+  width: 140rpx;
+  height: 140rpx;
   border-radius: 50%;
   background-color: #fff;
   margin-right: 30rpx;
@@ -691,7 +730,7 @@ const getHistoryList = async () => {
 .name-vip {
   display: flex;
   align-items: center;
-  margin-bottom: 16rpx;
+  margin-bottom: 14rpx;
 }
 
 .name {
@@ -704,10 +743,10 @@ const getHistoryList = async () => {
   margin-left: 16rpx;
 }
 
-.vip-expire,
-.login-tip {
+.vip-expire{
   font-size: 28rpx;
   color: #666;
+  margin-bottom: 14rpx;
 }
 
 .btn-content {
@@ -790,7 +829,7 @@ const getHistoryList = async () => {
 /* 钱包余额 */
 .wallet-section {
   background: #fff;
-  margin: -190rpx 20rpx 20rpx;
+  margin: -176rpx 20rpx 20rpx;
   border-radius: 24rpx;
   padding: 30rpx;
 }
@@ -1035,4 +1074,22 @@ const getHistoryList = async () => {
     }
   }
 }
+.intro {
+  display: flex;
+  align-items: center;
+
+  .item {
+    color: #333;
+    font-size: 24rpx;
+    padding: 0 16rpx;
+    line-height: 40rpx;
+    margin-right: 16rpx;
+    background: #FEF8E6;
+    border-radius: 8rpx;
+
+    &:last-child {
+      margin-right: 0;
+    }
+  }
+}
 </style>

+ 631 - 0
pages/users/face_detect/index.vue

@@ -0,0 +1,631 @@
+<template>
+	<view class="container">
+		<!-- <up-notify type="success" ref="uNotifyRef" duration="0" :show="true" message="Hi uview-plus"
+			:safeAreaInsetTop="true">审核中</up-notify> -->
+		
+		<view class="upload-section">
+			<!-- 状态展示 -->
+			<view v-if="verifyInfo" class="verify-status">
+				<view>认证状态:{{ statusText }}</view>
+			</view>
+			<!-- 身份证正面上传 -->
+			<view class="upload-box">
+				<view class="upload-title">上传身份证</view>
+				<view class="upload-box-list">
+					<up-upload width="335rpx" height="208rpx" :fileList="frontImageList" @afterRead="afterReadFront"
+						@delete="deletePicFront" :deletable="deletable" :previewImage="true" imageMode="aspectFill" name="front"
+						:maxCount="1">
+						<template #trigger>
+							<view class="upload-block">
+								<image mode="" v-if="frontImageList.length === 0" src="/static/img/IDFront.png" class="IDFront" />
+
+							</view>
+						</template>
+					</up-upload>
+					<up-upload width="335rpx" height="208rpx" :fileList="backImageList" @afterRead="afterReadBack"
+						@delete="deletePicBack" :previewImage="true" :deletable="deletable" imageMode="aspectFill" name="back"
+						:maxCount="1">
+						<template #trigger>
+							<view class="upload-block">
+								<image mode="aspectFill" v-if="backImageList.length === 0" src="/static/img/IDReverse.png"
+									class="IDBack" />
+							</view>
+						</template>
+					</up-upload>
+				</view>
+			</view>
+			<!-- 身份信息输入 -->
+			<view class="info-section">
+
+				<view class="info-title">身份信息</view>
+				<view class="info-form">
+					<view class="form-item">
+						<up-input v-model="realName" placeholder="请输入真实姓名" border="surround" clearable :customStyle="inputStyle"
+							:disabled="isReadonly" inputAlign="right">
+							<template #prefix>
+								<view class="">姓名</view>
+							</template>
+						</up-input>
+					</view>
+					<view class="form-item">
+						<up-input v-model="idCardNumber" placeholder="请输入身份证号码" border="surround" clearable
+							:customStyle="inputStyle" type="idcard" @change="onIdCardChange" maxlength="18" :disabled="isReadonly"
+							inputAlign="right">
+							<template #prefix>
+								<view class="">身份证号</view>
+							</template>
+						</up-input>
+					</view>
+				</view>
+			</view>
+			<view class="info-tips">
+				<image src="/static/img/tips@2x.png" mode=""></image>
+				<view class="">
+					<view class="">上传说明:</view>
+					<view class="">1.请确保身份证信息清晰可见</view>
+					<view class="">2.请上传真实的身份证照片</view>
+					<view class="">3.请确保光线充足,避免反光</view>
+					<view class="">4.请确保姓名和身份证号与身份证照片一致</view>
+				</view>
+			</view>
+		</view>
+		<view class="kong"></view>
+		<view class="footer">
+			<up-button class="btn" @click="submitDetect" :disabled="!canSubmit || isProcessing || isReadonly">
+				{{
+          isProcessing ? "认证中..." : isRejected ? "重新提交认证" : "提交认证"
+        }}
+			</up-button>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		computed
+	} from "vue";
+	import {
+		onLoad
+	} from "@dcloudio/uni-app";
+	import {
+		init,
+		query
+	} from "@/api/faceVerify.js";
+	import {
+		useToast
+	} from "@/hooks/useToast";
+	import {
+		useImageUpload
+	} from "@/hooks/useImageUpload";
+	import {
+		faceVerify,
+		getFaceVerify
+	} from "@/api/user";
+	import {
+		useAppStore
+	} from "@/stores/app";
+
+	const {
+		Toast
+	} = useToast();
+	const appStore = useAppStore();
+	const idCardPicUrl = ref("");
+	const isProcessing = ref(false);
+	const realName = ref("");
+	const idCardNumber = ref("");
+	const emit = defineEmits(["fetchUserInfo"]);
+	const verifyInfo = ref(null);
+	const deletable = ref(true);
+
+	// #ifdef APP
+	const aliyunVerify = uni.requireNativePlugin("AP-FaceDetectModule");
+	// #endif
+
+
+
+	const certifyId = ref("");
+	const metaInfo = ref("");
+
+	// 正面上传
+	const {
+		imageList: frontImageList,
+		afterRead: afterReadFront,
+		deletePic: deletePicFront,
+	} = useImageUpload({
+		pid: 7,
+		model: "user",
+	});
+	console.log("frontImageList", frontImageList.value);
+	// 反面上传
+	const {
+		imageList: backImageList,
+		afterRead: afterReadBack,
+		deletePic: deletePicBack,
+	} = useImageUpload({
+		pid: 5,
+		model: "user",
+	});
+
+	// 输入框样式
+	const inputStyle = {
+		backgroundColor: "#F9F7F0",
+		borderRadius: "16rpx",
+		padding: "28rpx 16rpx",
+		fontSize: "28rpx",
+		border: 'none'
+	};
+
+	const isReadonly = computed(() => {
+		return (
+			verifyInfo.value &&
+			(verifyInfo.value.status === 0 || verifyInfo.value.status === 1)
+		);
+	});
+	const showUploadImg = computed(() => {
+		// 如果是被拒绝状态,不显示已上传的图片,允许重新上传
+		if (isRejected.value) {
+			return false;
+		}
+		return verifyInfo.value || frontImageList.value[0]?.info?.url;
+	});
+	const isRejected = computed(() => {
+		return verifyInfo.value && verifyInfo.value.status === 2;
+	});
+	const statusText = computed(() => {
+		if (!verifyInfo.value) return "";
+		switch (verifyInfo.value.status) {
+			case 0:
+				return "审核中";
+			case 1:
+				return "已通过";
+			case 2:
+				return verifyInfo.value?.approveMsg || "认证被拒绝,请重新提交";
+			default:
+				return "";
+		}
+	});
+
+	// 计算是否可以提交(基础校验)
+	const canSubmit = computed(() => {
+		return (
+			frontImageList.value.length > 0 &&
+			backImageList.value.length > 0 &&
+			realName.value.trim() &&
+			idCardNumber.value.trim()
+		);
+	});
+
+	onLoad(() => {
+		fetchFaceVerify();
+	});
+
+	// 获取实名状态
+	async function fetchFaceVerify() {
+		try {
+			const {
+				data
+			} = await getFaceVerify({
+				uid: appStore.uid
+			});
+			if (data?.list.length > 0) {
+				verifyInfo.value = data.list[0];
+				realName.value = verifyInfo.value.realName || "";
+				idCardNumber.value = verifyInfo.value.cardId || "";
+				frontImageList.value[0] = {
+					url: verifyInfo.value.idCardFront,
+				};
+				backImageList.value[0] = {
+					url: verifyInfo.value.idCardBack,
+				};
+				if (verifyInfo.value.status === 0 || verifyInfo.value.status === 1) {
+					deletable.value = false;
+				}
+				// 如果是被拒绝状态,清空上传列表,允许重新上传
+				// if (verifyInfo.value.status === 2) {
+				//   frontImageList.value = [];
+				//   backImageList.value = [];
+				// }
+			} else {
+				verifyInfo.value = null;
+				realName.value = "";
+				idCardNumber.value = "";
+				frontImageList.value = [];
+				backImageList.value = [];
+			}
+		} catch (error) {
+			console.error("getFaceVerify", error);
+		}
+	}
+
+	function submitDetect() {
+		if (isReadonly.value) {
+			Toast({
+				title: "当前状态不可提交"
+			});
+			return;
+		}
+		if (!frontImageList.value.length || !backImageList.value.length) {
+			Toast({
+				title: "请先上传身份证正反面照片"
+			});
+			return;
+		} else if (!realName.value.trim()) {
+			Toast({
+				title: "请输入真实姓名"
+			});
+			return;
+		} else if (!idCardNumber.value.trim()) {
+			Toast({
+				title: "请输入身份证号码"
+			});
+			return;
+		} else if (!validateIdCard(idCardNumber.value.trim())) {
+			Toast({
+				title: "请输入正确的身份证号码"
+			});
+			return;
+		}
+		// 检查图片上传状态
+		const frontImage = frontImageList.value[0];
+		const backImage = backImageList.value[0];
+		console.log(frontImage, backImage);
+		if (!frontImage || !backImage) {
+			Toast({
+				title: "请先上传身份证正反面照片"
+			});
+			return;
+		}
+		if (frontImage?.status === "failed" || backImage?.status === "failed") {
+			Toast({
+				title: "有图片上传失败,请重新上传"
+			});
+			return;
+		}
+		if (frontImage?.status === "uploading" || backImage?.status === "uploading") {
+			Toast({
+				title: "图片正在上传中,请稍候"
+			});
+			return;
+		}
+		try {
+			isProcessing.value = true;
+			uni.showLoading({
+				title: "开始认证"
+			});
+			console.log("frontImage?.info", frontImage?.info);
+			const frontImageUrl = frontImage.info?.url || frontImage.url;
+			const backImageUrl = backImage.info?.url || backImage.url;
+			if (!frontImageUrl || !backImageUrl) {
+				Toast({
+					title: "图片上传失败,请重新上传"
+				});
+				uni.hideLoading();
+				isProcessing.value = false;
+				return;
+			}
+			const params = {
+				uid: appStore.uid,
+				idCardFront: frontImageUrl,
+				idCardBack: backImageUrl,
+				realName: realName.value.trim(),
+				cardId: idCardNumber.value.trim(),
+			};
+			faceVerify(params)
+				.then((res) => {
+					uni.hideLoading();
+					Toast({
+						title: "认证已提交,正在审核..."
+					});
+					emit("fetchUserInfo");
+					// 认证成功后清空所有数据
+					frontImageList.value = [];
+					backImageList.value = [];
+					realName.value = "";
+					idCardNumber.value = "";
+					isProcessing.value = false;
+					fetchFaceVerify(); // 重新拉取状态
+				})
+				.catch((err) => {
+					console.log("submitDetect-err", err);
+					uni.hideLoading();
+					isProcessing.value = false;
+					Toast({
+						title: err?.msg || "认证失败,请重试"
+					});
+				});
+		} catch (err) {
+			console.log("submitDetect-err", err);
+			uni.hideLoading();
+			isProcessing.value = false;
+			Toast({
+				title: "认证失败,请重试"
+			});
+		}
+	}
+
+	// 身份证号码验证
+	function validateIdCard(idCard) {
+		const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
+		return reg.test(idCard);
+	}
+	// 身份证号码输入处理
+	function onIdCardChange(value) {
+		if (value) {
+			idCardNumber.value = value.toUpperCase();
+		}
+	}
+	// 重试上传
+	function retryUpload(type) {
+		if (type === "front") {
+			frontImageList.value = [];
+		} else if (type === "back") {
+			backImageList.value = [];
+		}
+	}
+
+	// 重新上传(清空后重新选择)
+	function reUpload(type) {
+		if (type === "front") {
+			frontImageList.value = [];
+		} else if (type === "back") {
+			backImageList.value = [];
+		}
+	}
+
+	//调用getMetaInfo获取MetaInfo数据
+	function startVerify() {
+		try {
+			console.log("aliyunVerify", aliyunVerify);
+			metaInfo.value = aliyunVerify.getMetaInfo();
+			let p = uni.getSystemInfoSync().platform;
+			if (p === "ios") {
+				metaInfo.value = JSON.stringify(metaInfo);
+			}
+			console.log("metaInfo", metaInfo.value);
+			initFn();
+		} catch (error) {
+			console.log("startVerify-error", error);
+		}
+	}
+
+	function initFn() {
+		console.log("initFn-start");
+		try {
+			uni.showLoading({
+				title: "开始认证"
+			});
+			init({
+					idCardPicUrl: idCardPicUrl.value,
+					metaInfo: metaInfo.value,
+				})
+				.then((res) => {
+					console.log("initFn-----", res);
+					certifyId.value = res.data.certifyId || "";
+					uni.hideLoading();
+					aliyunVerify.verify({
+							certifyId: certifyId.value,
+							extParams: {},
+						},
+						function(response) {
+							console.log("aliyunVerify", response, response?.code);
+							if (response?.code == 1000) {
+								queryFn();
+							}
+						}
+					);
+				})
+				.catch((err) => {
+					console.log("initFn-err", err);
+					certifyId.value = "";
+				});
+		} catch (err) {
+			console.log("initFn-err", err);
+		}
+	}
+
+	function queryFn() {
+		console.log("initFn-start");
+		query({
+				certifyId: certifyId.value,
+			})
+			.then((res) => {
+				const passed = res.data && res.data.passed;
+				if (passed == "T") {
+					Toast({
+						title: "认证成功"
+					});
+					emit("fetchUserInfo");
+				} else {
+					Toast({
+						title: "认证失败,请确认身份证和人脸信息是否一致?"
+					});
+				}
+				console.log("queryFn", res);
+			})
+			.catch((err) => {
+				console.log("queryFn-err", err);
+			});
+	}
+
+	defineExpose({
+		startVerify,
+	});
+</script>
+
+<style lang="scss" scoped>
+	page {
+		background-color: #F9F7F0;
+	}
+
+	.upload-section {
+		padding: 16rpx;
+	}
+
+	.upload-box {
+		padding: 16rpx;
+		border-radius: 16rpx;
+		background: #FFFFFF;
+
+		&:last-child {
+			margin-bottom: 0;
+		}
+
+		::v-deep .u-upload__wrap {
+			// width: 100%;
+
+			.u-upload__wrap__preview {
+				// width: 100%;
+				margin: 0;
+
+				.u-upload__wrap__preview__image {
+					// width: 100% !important;
+				}
+			}
+
+			view:last-child {
+				flex: 1;
+			}
+		}
+	}
+
+	.upload-title {
+		font-size: 32rpx;
+		font-weight: 600;
+		color: #333;
+		margin-bottom: 16rpx;
+	}
+
+	.upload-box-list {
+		display: flex;
+	}
+
+	.upload-block {
+		width: 335rpx;
+
+	}
+
+	.IDFront,
+	.IDBack {
+		width: 100%;
+		height: 206rpx;
+		object-fit: cover;
+		border-radius: 8rpx;
+	}
+
+
+	.status-text {
+		font-size: 22rpx;
+		font-weight: 500;
+
+		&.uploading {
+			color: #fa8013;
+		}
+
+		&.failed {
+			color: #ff4444;
+		}
+
+		&.success {
+			color: #52c41a;
+		}
+	}
+
+	.retry-btn {
+		color: #fa8013;
+		text-decoration: underline;
+		margin-left: 10rpx;
+		font-size: 20rpx;
+	}
+
+	.upload-show {
+		padding: 15rpx;
+		background-color: #f8f9fa;
+		border-radius: 12rpx;
+	}
+
+	.info-section {
+		margin: 16rpx 0;
+		background-color: #fff;
+		border-radius: 16rpx;
+		padding: 16rpx;
+	}
+
+	.info-tips {
+		padding: 10rpx 16rpx;
+		display: flex;
+		background: #FEF2CE;
+		border-radius: 16rpx;
+		border: 1rpx solid #F8C008;
+
+		image {
+			top: 4rpx;
+			width: 32rpx;
+			height: 32rpx;
+			margin-right: 8rpx;
+		}
+
+		view {
+			flex: 1;
+			color: #333333;
+			font-size: 24rpx;
+			line-height: 40rpx;
+		}
+	}
+
+	.info-title {
+		font-size: 32rpx;
+		font-weight: 600;
+		color: #333;
+		margin-bottom: 16rpx;
+	}
+
+	.info-form {
+		.form-item {
+			margin-bottom: 16rpx;
+
+			&:last-child {
+				margin-bottom: 0;
+			}
+		}
+	}
+
+	.verify-status {
+		background-color: #fff;
+		border-radius: 16rpx;
+		padding: 16rpx;
+		font-size: 28rpx;
+		font-weight: 600;
+		color: #F8C008;
+		margin-bottom: 16rpx;
+	}
+
+	
+.kong {
+		height: calc(132rpx + constant(safe-area-inset-bottom));
+		height: calc(132rpx + env(safe-area-inset-bottom));
+	}
+	.footer {
+		width: 100%;
+		background: #FFFFFF;
+		box-shadow: inset 0rpx 1rpx 0rpx 0rpx #F1F3F8;
+		padding: 22rpx 32rpx calc(22rpx + constant(safe-area-inset-bottom));
+		padding: 22rpx 32rpx calc(22rpx + env(safe-area-inset-bottom));position: fixed;
+		bottom: 0;
+
+		.btn {
+			font-size: 32rpx;
+			color: #333333;
+			font-weight: bold;
+			background-color: #F8C008;
+			border-radius: 16rpx;
+			text-align: center;
+			line-height: 88rpx;
+
+			&:disabled {
+				background-image: linear-gradient(to right, #ccc 0%, #ccc 100%);
+				color: #999;
+			}
+		}
+	}
+</style>

BIN
static/img/IDFront.png


BIN
static/img/IDReverse.png


BIN
static/img/tips@2x.png