From 8ea6a7dd1fcdbd4e22c564ed63a5a8023510161a Mon Sep 17 00:00:00 2001
From: zjk <852185829@qq.com>
Date: 星期三, 14 十月 2026 08:56:45 +0800
Subject: [PATCH] feat: 新增实名认证、企业认证、我的邀请与头像上传功能

---
 hugray-user-miniapp/pages/profile/edit.vue |  104 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 93 insertions(+), 11 deletions(-)

diff --git a/hugray-user-miniapp/pages/profile/edit.vue b/hugray-user-miniapp/pages/profile/edit.vue
index 9cf013f..f6ae495 100644
--- a/hugray-user-miniapp/pages/profile/edit.vue
+++ b/hugray-user-miniapp/pages/profile/edit.vue
@@ -26,8 +26,8 @@
 
         <view class="body">
             <view class="list">
-                <!-- 头像:点击更换(本期占位) -->
-                <view class="row" @tap="handlePlaceholder('头像更换')">
+                <!-- 头像:点击更换 -->
+                <view class="row" @tap="handleAvatarChange">
                     <text class="row-label">头像</text>
                     <view class="row-right">
                         <view class="avatar">
@@ -45,7 +45,7 @@
                 </view>
 
                 <!-- 实名认证 -->
-                <view class="row" @tap="handlePlaceholder('实名认证')">
+                <view class="row" @tap="handleRealNameCertification">
                     <text class="row-label">实名认证</text>
                     <view class="row-right">
                         <view class="badge" :class="realNameBadge.cls">
@@ -56,7 +56,7 @@
                 </view>
 
                 <!-- 企业 / 个体户认证 -->
-                <view class="row" @tap="handlePlaceholder('企业/个体户认证')">
+                <view class="row" @tap="handleCompanyCertification">
                     <text class="row-label">企业/个体户认证</text>
                     <view class="row-right">
                         <view class="badge" :class="companyBadge.cls">
@@ -82,10 +82,13 @@
 import { computed, ref } from 'vue'
 import { onShow } from '@dcloudio/uni-app'
 import { clearToken, ensureLogin } from '@/utils/request.js'
-import { getMemberInfo, logout } from '@/api/index.js'
+import { getMemberInfo, logout, uploadAvatarFile, updateAvatar } from '@/api/index.js'
 
 /** 状态栏高度:自定义导航栏下用于顶部留白 */
 const statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 0
+
+/** 头像文件大小上限:5MB(选图后前置校验,超限直接拒绝,避免无效上传) */
+const AVATAR_MAX_SIZE = 5 * 1024 * 1024
 
 /** 用户头像:登录后由 getMemberInfo 下发,为空时回退相机占位 */
 const avatar = ref('')
@@ -94,8 +97,7 @@
 const phone = ref('')
 
 /**
- * 认证状态字典:key 为后端下发的状态枚举,值含徽标文案与样式类
- * 本期为原型,两处认证均取 none(未认证)占位,后端接入后直接替换 ref 初值即可
+ * 认证状态字典:key 为本地徽标状态,值含徽标文案与样式类
  */
 const AUTH_STATUS_MAP = {
     none: { text: '未认证', cls: 'badge--none' },
@@ -104,10 +106,21 @@
     done: { text: '已认证', cls: 'badge--done' }
 }
 
-/** 实名认证状态(本期占位) */
+/**
+ * 后端认证状态码 → 本地徽标状态(0未认证 1审核中 2已认证 3认证失败)
+ * 个人中心「实名认证」行据此回显真实状态
+ */
+const AUTH_STATUS_CODE_MAP = {
+    '0': 'none',
+    '1': 'ing',
+    '2': 'done',
+    '3': 'fail'
+}
+
+/** 实名认证状态:由会员信息接口下发的 authStatus 映射,缺省「未认证」 */
 const realNameStatus = ref('none')
 
-/** 企业 / 个体户认证状态(本期占位) */
+/** 企业 / 个体户认证状态:由会员信息接口下发的 companyAuthStatus 映射,缺省「未认证」 */
 const companyStatus = ref('none')
 
 /** 实名认证徽标:状态缺省兜底「未认证」 */
@@ -126,9 +139,72 @@
     uni.switchTab({ url: '/pages/profile/index' })
 }
 
-/** 占位交互:头像更换 / 实名认证 / 企业认证 / 注销 / 更多 / 帮助本期均不接后端 */
+/** 占位交互:注销 / 更多 / 帮助本期均不接后端 */
 const handlePlaceholder = (name) => {
     uni.showToast({ title: `${name}功能开发中`, icon: 'none' })
+}
+
+/** 跳转实名认证页(个人主体) */
+const handleRealNameCertification = () => {
+    uni.navigateTo({ url: '/pages/profile/certification' })
+}
+
+/** 跳转企业/个体认证向导页(企业 / 个体工商户主体) */
+const handleCompanyCertification = () => {
+    uni.navigateTo({ url: '/pages/profile/company-certification' })
+}
+
+/**
+ * 更换头像入口:先弹出选择方式(相册 / 拍照 / 取消)
+ * 说明:取消按钮由系统 ActionSheet 自带,用户取消时不触发 success,无需额外处理
+ */
+const handleAvatarChange = () => {
+    uni.showActionSheet({
+        itemList: ['从相册选择', '拍照上传'],
+        success: (res) => {
+            // tapIndex 0=相册 1=拍照
+            chooseAndUploadAvatar(res.tapIndex === 1 ? 'camera' : 'album')
+        }
+    })
+}
+
+/**
+ * 选图并上传:选图 -> 大小校验 -> 上传文件服务 -> 写回会员资料 -> 本地即时回显
+ * @param {String} sourceType 图片来源:'album' 相册 / 'camera' 拍照
+ */
+const chooseAndUploadAvatar = (sourceType) => {
+    uni.chooseImage({
+        count: 1,
+        sizeType: ['compressed'],
+        sourceType: [sourceType],
+        success: async (res) => {
+            const filePath = (res.tempFilePaths || [])[0]
+            const file = (res.tempFiles || [])[0]
+            if (!filePath) return
+            // 前置大小校验:超限直接提示,避免无效上传
+            if (file && file.size > AVATAR_MAX_SIZE) {
+                uni.showToast({ title: '图片不能超过5MB', icon: 'none' })
+                return
+            }
+            try {
+                // STEP 1: 上传文件到文件服务,拿到可访问 url
+                const uploadRes = await uploadAvatarFile(filePath)
+                const url = uploadRes.data && uploadRes.data.url
+                if (!url) {
+                    uni.showToast({ title: '上传失败,请重试', icon: 'none' })
+                    return
+                }
+                // STEP 2: 把 url 写回会员资料
+                await updateAvatar(url)
+                // STEP 3: 本地即时回显,无需再拉接口
+                avatar.value = url
+                uni.showToast({ title: '头像已更新', icon: 'success' })
+            } catch (error) {
+                console.error('[PROFILE_EDIT] 更新头像失败', error)
+                uni.showToast({ title: (error && error.message) || '更新头像失败', icon: 'none' })
+            }
+        }
+    })
 }
 
 /** 退出登录:二次确认后调用退出接口并清理本地登录态,回到个人中心 */
@@ -152,17 +228,23 @@
     })
 }
 
-/** 拉取当前会员信息(头像 / 脱敏手机号),失败时静默降级为空 */
+/** 拉取当前会员信息(头像 / 脱敏手机号 / 实名认证状态),失败时静默降级为空 */
 const loadMemberInfo = async () => {
     try {
         const res = await getMemberInfo()
         const data = res.data || {}
         avatar.value = data.avatar || ''
         phone.value = data.phone || ''
+        // 实名认证徽标据后端 authStatus 映射回显(审核通过/驳回后再次进入本页即刷新)
+        realNameStatus.value = AUTH_STATUS_CODE_MAP[data.authStatus] || 'none'
+        // 企业/个体户认证徽标据后端 companyAuthStatus 映射回显,与实名认证相互独立
+        companyStatus.value = AUTH_STATUS_CODE_MAP[data.companyAuthStatus] || 'none'
     } catch (error) {
         console.error('[PROFILE_EDIT] 拉取会员信息失败', error)
         avatar.value = ''
         phone.value = ''
+        realNameStatus.value = 'none'
+        companyStatus.value = 'none'
     }
 }
 

--
Gitblit v1.7.1